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 (5)

  1. Anonymous says:

    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.

  2. Anonymous says:

    Hey eltate, you need to be running Powershell v2.

  3. Hal Rottenberg [MVP] says:

    Nice one.  Will be covering on the next PowerScripting Podcast.

  4. eltate says:

    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")