Powershell: How to find out which running services aren't part of OS and non-MS Powershell: How to find out which running services aren't part of OS and non-MS powershell powershell

Powershell: How to find out which running services aren't part of OS and non-MS


You can't do with it Get-Service alone, because even though the service-info objects it outputs have a .BinaryPathName property, that property is available in PowerShell Core only and it is not necessarily the true service binary, which is often a DLL hosted by the generic svchost.exe service host.

To find the binary file path in all cases, you must (also) query the service definitions in the registry. Once you have the file path, you can use Get-Item and the .VersionInfo property of the file-info objects returned to extract information such as the product and company name.

The Get-ServiceFileInfo function at the bottom does just that; it allows you to run commands such as:

# Return information about all services that aren't part of Windows.# (May still include Microsoft services).Get-ServiceFileInfo | Where ProductName -ne 'Microsoft® Windows® Operating System'

Get-ServiceFileInfo source code (PSv5+, but could be adapted to work with lower versions):

# Note: While it is possible to run without elevated privileges,#       not all file information is retrievable then.#requires -runAsAdministratorfunction Get-ServiceFileInfo {  Set-StrictMode -Version 1  Get-Service | ForEach-Object {    # PowerShell Core only:    # Get the service binary path, which may or may not be the true service     # executable.    $binaryPath = $_.BinaryPathName        # Windows PowerShell:    # We fall back on trying to obtain the "ImagePath" value from the registry.    # Note: Even in PowerShell Core there appear to be services that Get-Service fails     #       to query even when running as admin, such as "SshdBroker"    #       (a non-terminating error is issued).    #       Reading from the registry is needed in that case too,     #       but, only succeeds when running as admin.    if (-not $binaryPath) {      $binaryPath = try { Get-ItemPropertyValue -EA Ignore "HKLM:\SYSTEM\CurrentControlSet\Services\$($_.Name)" ImagePath } catch { }    }        # Test for svchost.exe, which indicates the need to look for the service-specific DLL path elsewhere.    if ($binaryPath -like '*\svchost.exe *') {      # Get the actual binary (DLL) from the registry, subkey "Parameters", value "ServiceDLL"      # NOTE: Some services exist in *2* (multiple?) incarnations, as "<name>"" and "<name>_<num>"      #       Only the "<name>" incarnation has the "ServiceDLL" value, so we fall back on that.      foreach ($keyName in $_.Name, ($_.Name -split '_')[0]) {        # NOTE: Most DLL-based services store the "ServiceDLL" value in the "Parameters" subkey, but        #       some have it in the service's root key itself.        foreach ($subKeyName in "$keyName\Parameters", $keyName) {          $binaryPath = try { Get-ItemPropertyValue -EA Ignore "HKLM:\SYSTEM\CurrentControlSet\Services\$subKeyName" ServiceDLL } catch { }          if ($binaryPath) { break }        }      }    }        # Sanitize the path:    # * Some values have enclosing "...", so we strip them,     # * others have arguments, so we only take the first token.    $binaryPath = if ($binaryPath.StartsWith('"')) {      ($binaryPath -split '"')[1]    } else {      # The path / command line isn't or doesn't start with a double-quoted token, which      # can mean one of two things:      #  * It is a command line based on an unquoted executable, possibly with arguments.      #  * It is a service DLL path - possibly with spaces in the (expanded) path.      if (Test-Path -LiteralPath $binaryPath -Type Leaf) {        $binaryPath # Value as a whole is a file path      } else {        (-split $binaryPath)[0] # Value is a command line, extract executable      }    }    $FileVersionInfo = if ($binaryPath) { (Get-Item -LiteralPath $binaryPath).VersionInfo }    # Construct the output object.            [pscustomobject] @{      Name = $_.Name      BinaryPath = if ($binaryPath) { $binaryPath } else { '(n/a)'; Write-Error "Failed to determine binary path for service '$($_.Name)'. Try running as admin." }      ProductName = $FileVersionInfo.ProductName      FileDescription = $FileVersionInfo.FileDescription      CompanyName = $FileVersionInfo.CompanyName    }      }}