Public/system/Get-ServiceHealth.ps1
|
#Requires -Version 5.1 function Get-ServiceHealth { <# .SYNOPSIS Retrieves service health status from local or remote computers .DESCRIPTION Queries Win32_Service via CIM to report on Windows services state and health. By default returns only auto-start services that are not running (degraded), making it ideal for monitoring. Use -IncludeAll to see every service. Use -Name to filter by service name with wildcard support. .PARAMETER ComputerName One or more computer names to query. Defaults to the local computer. Accepts pipeline input by value and by property name. .PARAMETER ServiceName Optional wildcard filter on the service name. Uses -like matching. For example, 'sql*' returns all SQL-related services. .PARAMETER IncludeAll When specified, returns all services regardless of start mode or state. By default, only auto-start services that are not running are returned. .PARAMETER Credential Optional PSCredential for authenticating to remote computers. Not used for local queries. .EXAMPLE Get-ServiceHealth Returns auto-start services that are not running on the local computer. .EXAMPLE Get-ServiceHealth -ComputerName 'SRV01' -ServiceName 'sql*' -IncludeAll Returns all SQL-related services from SRV01 regardless of state. .EXAMPLE 'SRV01', 'SRV02' | Get-ServiceHealth Checks service health on multiple servers via pipeline. .OUTPUTS PSWinOps.ServiceHealth Returns objects with service name, display name, state, start mode, account, process ID, and a health status indicator. .NOTES Author: Franck SALLET Version: 1.0.0 Last Modified: 2026-03-25 Requires: PowerShell 5.1+ / Windows only .LINK https://github.com/k9fr4n/PSWinOps .LINK https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-service #> [CmdletBinding()] [OutputType('PSWinOps.ServiceHealth')] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [Alias('CN', 'Name', 'DNSHostName')] [string[]]$ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$ServiceName, [Parameter(Mandatory = $false)] [switch]$IncludeAll, [Parameter(Mandatory = $false)] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty ) begin { Write-Verbose -Message "[$($MyInvocation.MyCommand)] Starting" $localNames = @($env:COMPUTERNAME, 'localhost', '.') } process { foreach ($machine in $ComputerName) { $cimSession = $null try { $isLocal = $localNames -contains $machine $cimParams = @{ ErrorAction = 'Stop' } if (-not $isLocal) { $sessionParams = @{ ComputerName = $machine ErrorAction = 'Stop' } if ($Credential -ne [System.Management.Automation.PSCredential]::Empty) { $sessionParams['Credential'] = $Credential } $cimSession = New-CimSession @sessionParams $cimParams['CimSession'] = $cimSession Write-Verbose -Message "[$($MyInvocation.MyCommand)] CimSession established to '$machine'" } Write-Verbose -Message "[$($MyInvocation.MyCommand)] Querying Win32_Service on '$machine'" $services = @(Get-CimInstance -ClassName 'Win32_Service' @cimParams) $displayName = if ($isLocal) { $env:COMPUTERNAME } else { $machine } foreach ($svc in $services) { # Apply name filter if specified if ($PSBoundParameters.ContainsKey('ServiceName') -and ($svc.Name -notlike $ServiceName)) { continue } # Determine health status $status = switch ($true) { ($svc.State -eq 'Running') { 'Healthy' break } ($svc.StartMode -eq 'Auto' -and $svc.State -ne 'Running') { 'Degraded' break } ($svc.StartMode -eq 'Disabled') { 'Disabled' break } default { 'Stopped' } } # Default mode: only show degraded (auto-start not running) if (-not $IncludeAll -and $status -ne 'Degraded') { continue } [PSCustomObject]@{ PSTypeName = 'PSWinOps.ServiceHealth' ComputerName = $displayName ServiceName = $svc.Name DisplayName = $svc.DisplayName State = $svc.State StartMode = $svc.StartMode Account = $svc.StartName ProcessId = $svc.ProcessId Status = $status Timestamp = Get-Date -Format 'o' } } } catch { Write-Error -Message "[$($MyInvocation.MyCommand)] Failed on '${machine}': $_" continue } finally { if ($cimSession) { Remove-CimSession -CimSession $cimSession -ErrorAction SilentlyContinue } } } } end { Write-Verbose -Message "[$($MyInvocation.MyCommand)] Completed" } } |