Find an Application that runs as a Service in your Environment with PowerShell

I recently worked with a vendor to remove an old application that was no longer being used from a server in one of my customer's environments. While many applications may be left to die on the server long after they're needed, this particular one transmitted data to a partner company so it definitely needed to be removed.

The problem is the application was so old that no one knew which server of the hundreds of servers it was running on. The partner company was able to provide the display name of the service that the application runs as which made this problem fairly easy to resolve with PowerShell. For this scenario, I'll use "OpenSSH" as the display name of the service that I'm looking for.

First, you'll need a list of all the servers in your environment to query. While this can be obtained from Active Directory, I've found that it's easier to maintain a list of servers in a text file.

Get-Service has a ComputerName parameter, but I don't recommend using the ComputerName parameter on most cmdlets because they use older DCOM protocols that are typically blocked by firewalls and when querying multiple computers, they're queried serially instead of in parallel. If one is unreachable for some reason, it has to timeout before continuing to the next system which is slow and inefficient to say the least.

1Get-Service -ComputerName sql08, sql12, sql14, sql16, sql17 -DisplayName '*OpenSSH*'

Instead, I recommend using the one to many PowerShell remoting Invoke-Command cmdlet and run the Get-Service command within its ScriptBlock parameter.

1Invoke-Command -ComputerName sql08, sql12, sql14, sql16, sql17 {Get-Service -DisplayName '*OpenSSH*'}


By default, you'll need to be an admin on the remote systems, but you can provide alternate credentials if necessary.

1$Cred = Get-Credential


Then those credentials can be used along with the Credential parameter.

1Invoke-Command -ComputerName sql08, sql12, sql14, sql16, sql17 {Get-Service -DisplayName '*OpenSSH*'} -Credential $Cred


I've created a text file with the server names in it and I'll query the file with Get-Content.

1Get-Content -Path C:\tmp\myservers.txt


I'll combine those two techniques, placing Get-Content inside of parentheses so that portion of the command runs first and provides its results as the values for the ComputerName parameter of Invoke-Command.

1Invoke-Command -ComputerName (Get-Content -Path C:\tmp\myservers.txt) {Get-Service -DisplayName '*OpenSSH*'} -Credential $Cred


As I previously mentioned, you can also retrieve the computer names from Active Directory. All of the servers that I've been querying exist in a "SQL Servers" OU (Organizational Unit) so I can simply query Active Directory for all of the computer names in that particular OU. This does require the RSAT tools (Remote Server Administration Tools) to be installed on your workstation. As of Windows 10 version 1809, RSAT can be installed via Features on Demand.

1Invoke-Command -ComputerName (Get-ADComputer -Filter * -SearchBase 'OU=SQL Servers,OU=Test,DC=mikefrobbins,DC=com').Name {Get-Service -DisplayName '*OpenSSH*'} -Credential $Cred


Keep in mind that this is running on your workstation and querying all of the specified servers remotely. The results are returned as deserialized objects. By default, Invoke-Command will run in parallel on up to 32 remote systems at once and that number can be controlled with its ThrottleLimit parameter.