Nigel Boulton's Blog
7Feb/110

Checking whether a Hotfix is installed on Multiple Machines using PowerShell Remoting

In my last post, I said that I would post a way of verifying whether a particular hotfix had been installed on a number of machines, so here it is...

This approach uses good old PowerShell remoting again - as I have said before, this is an incredibly powerful way of executing PowerShell code on a number of machines, and well worth investing the time to set it up in your environment.

...So, I'd deployed the hotfix to all the servers in the farm, and I needed a quick way of verifying that it had been successfully installed on each of them. This was a variation on an approach I'd taken in the past (an enhancement kindly provided by Jeffrey Snover) - with one important difference: this time I was making good use of the PowerShell custom objects that the script returns. The script code is shown below:

$Servers = $(1..176 | foreach {"SERVER$_"})

Invoke-Command -ComputerName $Servers -ScriptBlock {
	$Result = Get-Hotfix | where {$_.hotfixid -eq 'KB2464876'}
	if ($Result) {
        New-Object PSObject -Property @{Host = hostname; Value = $true}
    } else {
		New-Object PSObject -Property @{Host = hostname; Value = $false}
    }
}

Running this script as shown below allowed me to get a quick indication of any servers that did not have the hotfix installed. This was achieved by querying for returned custom objects whose "Value" property was not equal to True:

./Check-Hotfix.ps1 | Where-Object {$_.Value -ne $True} | Select-Object Host

...and the result was:

Host
----

As I got no servers returned in the result (which of course is good), I wanted a confidence check, so I ran it this way to prove that the code was in fact running as expected:

./Check-Hotfix.ps1 | Where-Object {$_.Value -ne $False} | Select-Object Host

Host
----
SERVER1
SERVER2
SERVER3
SERVER4
.

As I mentioned in my last post, there are a number of ways you can build the list of servers. I used a numbered range, but by simply substituting the line which sets the $Servers variable, you can easily read a list of machine names from a text file (or a CSV file of course):

$Servers = Get-Content '\\Fileserver\Hotfixes\ServerList.txt'

Variations on the above approach can potentially allow you to do almost anything that you can do with PowerShell locally, across your entire server estate. For example, recently I used the same method to check which servers had a specific unwanted value in one of the Terminal Server "shadow" keys. This rogue value was being written into user profiles when users were directed to the servers in question and causing unexpected behaviour in subsequent sessions.

One of the best things about this is that, in most cases, you can develop and test the functional part of the code locally and then simply drop it into the scriptblock. Nice!