I have a lot of Windows Services on my Windows 11 laptop, mainly from Microsoft itself or third-party, but Microsoft signed are safe(r). In this blog post, I will show you how you can scan your system for non-Microsoft signed Windows Services and create a report on those.
What are Microsoft signed Windows Services?
A Window Service is a task/process that runs automatically or manually on your system as a background process. Most Windows Services are built-in, but other software can add Windows Services to your system. Inside the properties of a Windows Service, you will find the executable being started. C:\WINDOWS\system32\svchost.exe, for example, is the one that Windows Services uses to start the built-in/required services.
Inside the properties of the executable, there is a Digital Signatures tab with a signature list containing the name of the signer(s). Microsoft Services are signed by a certificate that has been issued to Microsoft Corporation:

What does the script do?
The script checks all the Windows Services on your (or a remote) system and reports which ones are not signed by Microsoft by using the Get-AuthenticodeSignature cmdlet. These Windows Services are third-party and could potentially be dangerous. It is worth checking, in my opinion. Some third-party Windows Services are signed by, for example, Lenovo but also by Microsoft. These will not be reported, for example:

I had some ‘fun’ with RegEx in the script, too. I must master that skill in the future. 🙁
Running the script
Scanning one system
You can start the script without any parameter, and it will then connect to your local system and show the results in an Out-GridView pane. It will show you how many services it will scan and a progress bar. For example:
.\Get-Non_Microsoft_Signed_Services.ps1


If there are no results found, it will report that on your screen:

Scanning multiple systems
You can also run the script with the -ComputerName parameter to specify multiple systems separated by a comma. In the example below, I ran it on my test Domain Controller to scan that server and the w2k22member server. The W2K22DC server had no results, and the W2K22Member server did for Google Chrome.
.\Get-Non_Microsoft_Signed_Services.ps1 -ComputerName w2k22dc, w2k22member Retrieving information for 228 services on w2k22dc Retrieving information for 196 services on w2k22member

Note: Your account must have permissions on the remote system. It will not prompt you for it.
Saving the results to an Excel file
To get the results in a Microsoft Excel file, you can use the -Filename parameter. Results will not be shown in an Out-GridView pane anymore but will be saved in the specified Excel file. If the specified Excel file exists, it will add a Services tab to the file with a time stamp and insert the results there.
Note: The Excel filename must end with .xlsx, and the path must be accessible. The script will check for that and install the ImportExcel PowerShell module if it is not already present on your system.
For example:
.\Get-Non_Microsoft_Signed_Services.ps1' -Filename C:\Data\Services.xlsx Specified C:\Data\Services.xlsx filename is correct, and the path is accessible, continuing... The ImportExcel module was found on the system, continuing... Retrieving information for 310 services on NEXXT-592 Exported Non-Microsoft Signed Services to C:\Data\Services.xlsx
The Services.xlsx Excel File will look like this:

The script
Below are the contents of the script. Save it to c:\scripts\Get-Non_Microsoft_Signed_Services.ps1, for example.
[CmdletBinding()] param ( [Parameter(Mandatory = $false)][String[]]$ComputerName = $env:COMPUTERNAME, [parameter(Mandatory = $false)][string]$Filename ) #Validate output $filename if ($Filename) { if (-not ($Filename.EndsWith('.xlsx'))) { Write-Warning ("Specified {0} filename does not end with .xlsx, exiting..." -f $Filename) return } #Check access to the path, and if the file already exists, append if it does or test the creation of a new one if (-not (Test-Path -Path $Filename)) { try { New-Item -Path $Filename -ItemType File -Force:$true -Confirm:$false -ErrorAction Stop | Out-Null Remove-Item -Path $Filename -Force:$true -Confirm:$false | Out-Null Write-Host ("Specified {0} filename is correct, and the path is accessible, continuing..." -f $Filename) -ForegroundColor Green } catch { Write-Warning ("Path to specified {0} filename is not accessible, correct or file is in use, exiting..." -f $Filename) return } } else { Write-Warning ("Specified file {0} already exists, appending data to it..." -f $Filename) } #Check if the ImportExcel module is installed. Install it if not if (-not (Get-Module -ListAvailable -Name ImportExcel)) { Write-Warning ("The ImportExcel module was not found on the system, installing now...") try { Install-Module -Name ImportExcel -SkipPublisherCheck -Force:$true -Confirm:$false -Scope CurrentUser -ErrorAction Stop Import-Module -Name ImportExcel -Scope Local -ErrorAction Stop Write-Host ("Successfully installed the ImportExcel module, continuing..") -ForegroundColor Green } catch { Write-Warning ("Could not install the ImportExcel module, exiting...") return } } else { Write-Host ("The ImportExcel module was found on the system, continuing...") -ForegroundColor Green } } #Set $total to $null for when running script multiple times in one session $total = $null #Retrieve services on system and check if they are signed using a Microsoft signature (Trusted) $total = foreach ($Computer in $ComputerName) { try { $count = 0 $services = Get-WmiObject -Class Win32_Service -ComputerName $Computer -ErrorAction Stop | Select-Object Displayname, Name, PathName, State, StartName, StartMode | Sort-Object DisplayName Write-Host ("Retrieving information for {0} services on {1}" -f $services.count, $($Computer)) -ForegroundColor Green foreach ($service in $services) { $count++ Write-Progress ("Checking service {0} on {1}" -f $service.Displayname, $($Computer)) -PercentComplete (($count * 100) / $services.count) -Status "$(([math]::Round((($count)/$services.count * 100),0))) %" if ($null -ne $service.PathName) { $servicepath = $service.PathName -replace '^(?:"(.+?)"|([^ ]+)).*', '$1$2' $servicepath = "\\$($computer)\$($servicepath.Substring(0,1))$" + "$($servicepath.Substring(2))" if (Test-Path -Path $servicepath) { if (-not ((Get-AuthenticodeSignature $($servicepath)).SignerCertificate.Subject -match 'O=Microsoft Corporation')) { [PSCustomObject]@{ ComputerName = $Computer DisplayName = $service.DisplayName Name = $service.Name 'Log on as' = $service.StartName StartMode = $service.StartMode State = $service.State Path = $service.PathName } } } } } } catch { Write-Warning ("Error connecting {0}, skipping..." -f $Computer) } } #Output to GridView or Excel is results were found if ($Total.Count -gt 0) { if (-not $Filename) { $Total | Sort-Object ComputerName, DisplayName | Out-GridView -Title 'Non-Microsoft Signed Services' } else { $Date = Get-Date -Format 'dd-MM-yyyy HH-mm' $Total | Export-Excel -Path $Filename -WorksheetName "Services_$($Date)" -AutoFilter -AutoSize -Append Write-Host ("Exported Non-Microsoft Signed Services to {0}" -f $Filename) -ForegroundColor Green } } else { Write-Host ("No Non-Microsoft Signed Services found on {0}..." -f $ComputerName) }
Download the script(s) from GitHub here