Check that driver file versions match on all your cluster nodes via Powershell
This is more of a proof of concept, but I've used it with success internally. Take it and do with it what you want. Many thx to Brandon who did the "heavy lifting" when I got stuck!
Overview:
Ever run into cluster issues and wanted to see if the driver file versions matched on all the nodes of the cluster to rule out a mismatch on a driver level? Well I did! The basic gist is that you can show all the file versions for each node by just running the script against a node name. If you want to see only the drivers that don’t match then you’d use the pipeline with where-object (?).
Typical output:
When All drivers match:
PS C:\Debuggers> Test-MSCluster.ps1 ServerSQL11 | ?{!$_.IsSame}
Getting Nodes via WMI
Getting the drivers on: ServerSQL11
Getting the file versions for the drivers on: ServerSQL11
Getting the drivers on: ServerSQL12
Getting the file versions for the drivers on: ServerSQL12
PS C:\Debuggers>
One Mismatch:
PS C:\Debuggers> Test-MSCluster.ps1 ServerAX | ?{!$_.IsSame}
Getting Nodes via WMI
Getting the drivers on: ServerAX
Getting the file versions for the drivers on: ServerAX
Getting the drivers on: ServerBX
Getting the file versions for the drivers on: ServerBX
FileName ServerAX ServerBX
-------- ---------- ----------
rmcast.sys 6.0.6001.18000 6.0.6001.18069
Many nodes, many mismatches:
PS C:\Debuggers> Test-MSCluster.ps1 Server-Clus--11 | ?{!$_.IsSame}
Getting Nodes via WMI
Getting the drivers on: Server-Clus--10
Getting the file versions for the drivers on: Server-Clus--10
Getting the drivers on: Server-Clus--11
Getting the file versions for the drivers on: Server-Clus--11
Getting the drivers on: Server-Clus--15
Getting the file versions for the drivers on: Server-Clus--15
Getting the drivers on: Server-Clus--16
Getting the file versions for the drivers on: Server-Clus--16
Getting the drivers on: Server-Clus--13
Getting the file versions for the drivers on: Server-Clus--13
Getting the drivers on: Server-Clus--12
Getting the file versions for the drivers on: Server-Clus--12
FileName : Dbgv.sys
Server-Clus--10 : 4.60
Server-Clus--11 : FileMissing
Server-Clus--15 : FileMissing
Server-Clus--16 : FileMissing
Server-Clus--13 : FileMissing
Server-Clus--12 : FileMissing
IsSame : False
FileName : HpCISSs2.sys
Server-Clus--10 : FileMissing
Server-Clus--11 : FileMissing
Server-Clus--15 : FileMissing
Server-Clus--16 : 6.8.0.64 Build 9 (x86-64)
Server-Clus--13 : 6.8.0.64 Build 9 (x86-64)
Server-Clus--12 : 6.8.0.64 Build 9 (x86-64)
IsSame : False
FileName : USBSTOR.SYS
Server-Clus--10 : FileMissing
Server-Clus--11 : FileMissing
Server-Clus--15 : FileMissing
Server-Clus--16 : FileMissing
Server-Clus--13 : 6.0.6001.18000
Server-Clus--12 : 6.0.6001.18000
IsSame : False
FileName : mrxsmb10.sys
Server-Clus--10 : 6.0.6001.18000
Server-Clus--11 : 6.0.6001.18000
Server-Clus--15 : 6.0.6001.18000
Server-Clus--16 : 6.0.6001.18068
Server-Clus--13 : 6.0.6001.18000
Server-Clus--12 : 6.0.6001.18000
IsSame : False
FileName : nm3.sys
Server-Clus--10 : 03.02.0764.0001
Server-Clus--11 : FileMissing
Server-Clus--15 : FileMissing
Server-Clus--16 : FileMissing
Server-Clus--13 : FileMissing
Server-Clus--12 : FileMissing
IsSame : False
Code:
######################################################################
#Test-MSCluster.ps1
Param($ClusterNode)
# I am using this hashtable to store a unique list of file names.
$Files = @{}
# I am using this array to store my custom objects we create later.
$FileObjects = @()
Write-Host "Getting Nodes via WMI"
$nodes = gwmi -q "Select name from MSCluster_Node" -namespace root\mscluster -computername $ClusterNode -Authentication PacketPrivacy | %{$_.Name}
# Here we process each node and get all the drivers from the node and add it to our $Files HashTable to be processed
foreach ( $node in $nodes )
{
Write-Host "Getting the drivers on:" $node
# Here we are getting a list of the .sys files. Notice I am only getting the names
$filelistFinal = get-childitem "\\$node\admin$\system32\drivers" *.sys | %{$_.name}
Write-Host "Getting the file versions for the drivers on:" $node
foreach($file in $filelistFinal)
{
# foreach file found we add it to the hasttable, but hashtables can only have a key once
# so we need check if the key already exist. I do this because it is possible you could have
# unique drivers per node.
if(!$Files.$file)
{
$Files.Add($file,"added")
}
}
}
# Ok... now we have all our files time to process the hashtable and create our custom objects
foreach($FileName in $Files.Keys)
{
# This is how I create an object for each file
$myFileObj = New-Object System.Object
# This is how we add a property. In this case the FileName property. For these scenarios I chose add-member
# because you can dynamically add properties (i.e. NodeName with value of File version)
$myFileobj | add-Member -MemberType NoteProperty -Name FileName -Value $FileName
# Now we need to add properties for each node.
foreach($node in $nodes)
{
# Making sure the file exist on the node
if(Test-Path \\$node\admin$\system32\drivers\$FileName)
{
# Getting ProductVersion Info to use as the value for the Node Property
$fileInfo = [system.diagnostics.fileversioninfo]::getversioninfo("\\$node\admin$\system32\drivers\$FileName")
$myFileobj | add-Member -MemberType NoteProperty -Name $node -Value $FileInfo.ProductVersion
}
else
{
# File not found using FileMissing as the value for the Node Property
$myFileobj | add-Member -MemberType NoteProperty -Name $node -Value "FileMissing"
}
}
# Outputting Object
$FileObjects += $myFileObj
}
foreach($result in $FileObjects)
{
$isSame = $true
# Getting Server Name from Properties of the custom object
$servers = $result | Get-Member -MemberType Noteproperty | ?{$_.Name -ne "FileName"} | %{$_.Name}
# Checking the value of each server vs the other servers
foreach($server in $servers)
{
foreach($srv in $servers)
{
if($srv -ne $server)
{
# If the the value is different we set $isSame to $false
if($result."$srv" -ne $result."$server"){$isSame = $false}
}
}
}
# add the isSame property to the object
$result | add-Member -MemberType NoteProperty -Name IsSame -value $isSame
# output object
$result
}
######################################################################
***Note: This script is not fast, as it is getting the file versions for every driver (*.sys) on each system, I'd highly suggest not running this over the WAN...
Comments
Anonymous
January 01, 2003
Hey elate: The -Authentication was put into v2 to help with this issue. You cannot use get-wmiobject in POSH v1 to connect to namespaces that require packet privacy (see my earlier post on this subject). You'd need to use [wmisearcher] or the .NET framework and then set the authentication in there. Sorry. It CAN be done though, just a bit more work.Anonymous
January 01, 2003
PingBack from http://diggwow.info/tags/109/200812/file-server.htmlAnonymous
January 01, 2003
Hey eltate, you need to be running Powershell v2.Anonymous
December 10, 2008
Nice one. Will be covering on the next PowerScripting Podcast.Anonymous
January 27, 2009
I get this error on Exchange 2007 64bits cluster [PS] D:Scripts>.Test-MSCluster.ps1 SCC1 | ?{!$_.IsSame} Getting Nodes via WMI Get-WmiObject : A parameter cannot be found that matches parameter name 'Authentication'. At D:ScriptsTest-MSCluster.ps1:11 char:120
- $nodes = gwmi -q "Select name from MSCluster_Node" -namespace rootmscluster -computername $ClusterNode -Authenticati on <<<< PacketPrivacy | %{$_.Name} Getting the drivers on: Get-ChildItem : Cannot find path '\admin$system32drivers' because it does not exist. At D:ScriptsTest-MSCluster.ps1:18 char:35
- $filelistFinal = get-childitem <<<< "$nodeadmin$system32drivers" *.sys | %{$_.name} Getting the file versions for the drivers on: Exception calling "Add" with "2" argument(s): "Key cannot be null. Parameter name: key" At D:ScriptsTest-MSCluster.ps1:28 char:23
- $Files.Add( <<<< $file,"added")