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.
µ