Skip to content

Instantly share code, notes, and snippets.

@talatham
Created June 13, 2013 15:00
Show Gist options
  • Save talatham/5774395 to your computer and use it in GitHub Desktop.
Save talatham/5774395 to your computer and use it in GitHub Desktop.
Check machines for specific hotfix.
# Check for a specific patch on remote PCs v1.2
# Tom Latham 04/02/2010
#
# Added v1.1: Error messaages
# Added v1.2: GUI Inputs
# Function to open file dialog box and select a file
Function Get-FileName($initialDirectory)
{
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = "Text Files (*.txt)| *.txt" # Set the file types visible to dialog
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
}
# Function to prompt user for kb number
Function Get-Input
{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Enter KB Number"
$objForm.Size = New-Object System.Drawing.Size(300,200)
$objForm.StartPosition = "CenterScreen"
$objForm.KeyPreview = $True
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
{$x=$objTextBox.Text;$objForm.Close()}})
$objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
{$objForm.Close()}})
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = "OK"
$OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close()})
$objForm.Controls.Add($OKButton)
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$objForm.Close()})
$objForm.Controls.Add($CancelButton)
$objLabel = New-Object System.Windows.Forms.Label
$objLabel.Location = New-Object System.Drawing.Size(10,20)
$objLabel.Size = New-Object System.Drawing.Size(280,20)
$objLabel.Text = "Please enter the KB number below (kbxxxxxx):"
$objForm.Controls.Add($objLabel)
$objTextBox = New-Object System.Windows.Forms.TextBox
$objTextBox.Location = New-Object System.Drawing.Size(10,40)
$objTextBox.Size = New-Object System.Drawing.Size(260,20)
$objForm.Controls.Add($objTextBox)
$objForm.Topmost = $True
$objForm.Add_Shown({$objForm.Activate()})
[void] $objForm.ShowDialog()
$x
}
# Main Program --------------------------------------
# Do not display errors
$erroractionpreference = "SilentlyContinue"
# Clear screen
clear-host
# Store user credentials
$cred = get-credential
# Supply text file of all PCs to be checked and KB number to search for
# Run Open File Dialog
$filename = Get-FileName -initialDirectory "c:"
# Get path of file to be used in storing results
$path = split-path $filename
# If kbresults.txt exists, delete it
if (test-path $path\kbresults.txt)
{ remove-item $path\kbresults.txt }
# Get kb number
$kb = Get-Input
# Extract content from filename object
$computernames = get-content $filename
# For each computer in list
foreach ($computer in $computernames)
{
# Set query string to query ping status
$strQuery = "select * from win32_pingstatus where address = '" + $computer + "'"
# Get WMI object using query
$wmi = gwmi -query $strquery
# If machine pings (status = 0)
if ($wmi.statuscode -eq 0)
{
# Get WMI object on computer where hotfixid equals our kb number
# Use stored user credentials
$checkkb = gwmi win32_QuickFixEngineering -computer $computer -credential $cred | where {$_.hotfixid -eq $kb} | select-object hotfixid, description
switch -regex ($Error[ 0 ].Exception)
{
"The RPC server is unavailable"
{
write-host -f blue $computer "`t" "RPC Unavailable on $computer" "`r"
"$computer `t RPC Unavailable." | out-file $path\kbresults.txt -append
continue
}
"Access denied"
{
write-host -f blue $computer "`t" "Access Denied" "`r"
"$computer `t Access Denied." | out-file $path\kbresults.txt -append
continue
}
"Access is denied"
{
write-host -f blue $computer "`t" "Access Denied" "`r"
"$computer `t Access Denied." | out-file $path\kbresults.txt -append
continue
}
# No error -> record our info!
$null
{
# If kb numbers match
if ($checkkb.hotfixid -eq $kb)
{
# Patch is installed. Test reboot status.
# Connect to remote registry hive (HKLM)
$regHive = [Microsoft.Win32.RegistryHive]"LocalMachine";
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($regHive,$computer);
# Set subkey to 'UpdateExeVolatile', the existence of which show reboot pending status
$subKey = $regKey.OpenSubKey("SOFTWARE\Microsoft\Updates\UpdateExeVolatile");
# If subkey is not found
if (!$subKey)
{
# Patch is installed
write-host -f green $computer "`t" $checkkb.description "`r"
"$computer `t Installed." | out-file $path\kbresults.txt -append
}
else
{
# Patch installed. Reboot required.
write-host -f green $computer "`t" $checkkb.description "`r"
"$computer `t Reboot Required" | out-file $path\kbresults.txt -append
}
}
else
{
# Patch is not installed.
write-host -f red $computer "`t" "Not Found" "`r"
"$computer `t Not Installed." | out-file $path\kbresults.txt -append
}
}
}
$Error.clear()
}
else
{
# Machine doesn't ping. Write to screen and append to results file.
write-host $computer "`t" "Cannot ping." "`r"
"$computer `t Ping failed." | out-file $path\kbresults.txt -append
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment