From af78c3cbfd1c0390bbcab489d42c270a0c38e66a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Fri, 9 Oct 2026 15:31:17 +0200 Subject: [PATCH] terminal_services: detect Connection Broker via service control manager (#2628) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Opus 5.5 Signed-off-by: Jan-Otto Kröpke --- docs/collector.terminal_services.md | 2 +- .../terminal_services/terminal_services.go | 39 +++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/docs/collector.terminal_services.md b/docs/collector.terminal_services.md index ea8c6f7c..662b3850 100644 --- a/docs/collector.terminal_services.md +++ b/docs/collector.terminal_services.md @@ -7,7 +7,7 @@ The terminal_services collector exposes terminal services (Remote Desktop Servic | __Metric name prefix__ | `terminal_services` | | __Data source__ | Perflib/WMI, Win32 | | __Classes__ | [`Win32_PerfRawData_LocalSessionManager_TerminalServices`](https://wutils.com/wmi/root/cimv2/win32_perfrawdata_localsessionmanager_terminalservices/), [`Win32_PerfRawData_TermService_TerminalServicesSession`](https://docs.microsoft.com/en-us/previous-versions/aa394344(v%3Dvs.85)), [`Win32_PerfRawData_RemoteDesktopConnectionBrokerPerformanceCounterProvider_RemoteDesktopConnectionBrokerCounterset`](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/mt729067(v%3Dws.11)) | -| __Win32 API__ | [WTSEnumerateSessionsEx](https://learn.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtsenumeratesessionsexw) | +| __Win32 API__ | [WTSEnumerateSessionsEx](https://learn.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtsenumeratesessionsexw), [OpenService](https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-openservicew) | | __Enabled by default?__ | No | ## Flags diff --git a/internal/collector/terminal_services/terminal_services.go b/internal/collector/terminal_services/terminal_services.go index 29829663..3f5f658c 100644 --- a/internal/collector/terminal_services/terminal_services.go +++ b/internal/collector/terminal_services/terminal_services.go @@ -30,14 +30,16 @@ import ( "github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/pdh" "github.com/prometheus-community/windows_exporter/internal/types" - "github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus/client_golang/prometheus" "golang.org/x/sys/windows" ) const ( - Name = "terminal_services" - ConnectionBrokerFeatureID uint32 = 133 + Name = "terminal_services" + + // connectionBrokerServiceName is the "Remote Desktop Connection Broker" + // service, installed by the RDS-Connection-Broker role. + connectionBrokerServiceName = "Tssdis" ) type Config struct{} @@ -45,23 +47,24 @@ type Config struct{} //nolint:gochecknoglobals var ConfigDefaults = Config{} -type Win32_ServerFeature struct { - ID uint32 -} - -func isConnectionBrokerServer(miSession *mi.Session) bool { - var dst []Win32_ServerFeature - if err := miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_ServerFeature")), 0); err != nil { +// isConnectionBrokerServer reports whether the Remote Desktop Connection Broker +// role is installed by looking up its service in the service control manager. +func isConnectionBrokerServer() bool { + scm, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_CONNECT) + if err != nil { return false } - for _, d := range dst { - if d.ID == ConnectionBrokerFeatureID { - return true - } + defer windows.CloseServiceHandle(scm) //nolint:errcheck + + service, err := windows.OpenService(scm, windows.StringToUTF16Ptr(connectionBrokerServiceName), windows.SERVICE_QUERY_STATUS) + if err != nil { + return false } - return false + _ = windows.CloseServiceHandle(service) + + return true } // A Collector is a Prometheus Collector for WMI @@ -233,13 +236,9 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error { nil, ) - if miSession == nil { - return errors.New("miSession is nil") - } - var err error - c.connectionBrokerEnabled = isConnectionBrokerServer(miSession) + c.connectionBrokerEnabled = isConnectionBrokerServer() if c.connectionBrokerEnabled { c.perfDataCollectorBroker, err = pdh.NewCollector[perfDataCounterValuesBroker](c.logger, pdh.CounterTypeRaw, "Remote Desktop Connection Broker Counterset", pdh.InstancesAll)