Patch_ppv.ps1
param([parameter(Mandatory=$true, parameterSetName="C")][parameter(Mandatory=$true, parameterSetName="V")][string]$Target, `
[parameter(Mandatory=$true, parameterSetName="C")][switch]$Check, `
[parameter(Mandatory=$true, parameterSetName="V")][switch]$Validate, `
[parameter(parameterSetName="V")][switch]$NoDelete, `
[parameter(parameterSetName="V")][switch]$FixService, `
[parameter(Mandatory=$true, parameterSetName="H")][switch]$Help)
<#
#>
$USAGE = @"
#################################################################
#
# Pre-Validates Servers BEFORE patching.
# v2.1
#
# Collects HDD/Service/Share information from either a single machine or list
# of machines And Writes to a file. Later, a switch can be used to
# validate the information is the same.
#
#
# USAGE:
#
# .\PATCH_PPV.ps1 -Target <"FileName or ServerName"> -Check
# .\PATCH_PPV.ps1 -Target <"FileName or ServerName"> -Validate [-NoDelete] [-FixService]
# .\PATCH_PPV.ps1 -Help
#
#
# Options:
# -Target "FileName or ServerName" List of servers, or server name to preform operations against.
# -Check Step 1, Collect information about -Target.
# -Validate Step 2, Validate the target condition is the same as when you ran -Check.
#
# -NoDelete Optional, If you DONT want to delete the files after successfully validating.
# -FixService Optional, Attempt to start a failed service on Validation.
# -Help Show this usage message.
#
##::CHANGELOG @ EOF.
#
#################################################################
"@
if ($Help)
{
Write-Host $USAGE -ForegroundColor Yellow
exit
}
function pingSvr($ipAddress)
{
$alive_system = gwmi Win32_PingStatus -Filter "Address='$ipAddress'"
$Ping_status = $alive_system.statusCode
return $Ping_Status
}
Function CCLocalFldr([string]$Fldr)
{
$coFolder_Check = test-path "$Fldr"
#if the local collection folder doesnt exist, create it.
if (!$coFolder_Check)
{
$QUIET = new-item "$Fldr" -itemType Directory -force
}
}
Function GetHDD($Server)
{
$HDInfo = gwmi -Class "Win32_Volume" -Namespace "ROOT\CIMV2" -computerName $server | ? { $_.DriveType -eq 3 } | select-object Caption, Capacity
Return $HDInfo
}
Function GetSVC($Server)
{
$SVInfo = gwmi -computerName $server "Win32_Service" | ? { $_.State -eq "Running" -AND $_.StartMode -eq "Auto" } | select-object Name
return $SVInfo
}
Function GetShare ($Server)
{
$SHInfo = gwmi -Class "Win32_Share" -ComputerName $Server
return $SHInfo
}
Function WriteXMLDriveInfo($DriveList, $XO)
{
Add-Content $XO -Value ""
foreach ($HDD in $DriveList)
{
$HDD_Label = $HDD.Caption
$HDD_Size = $HDD.Capacity
Add-Content $XO -Value "$HDD_Size"
}
Add-Content $XO -Value ""
}
function WriteXMLServices($SVCList, $XO)
{
Add-Content $XO -Value ""
foreach ($SVC in $SVCList)
{
$SVCName = $SVC.Name
Add-Content $XO -Value "$SVCName"
}
Add-Content $XO -Value ""
}
function WriteXMLShare ($ShareList, $XO)
{
Add-Content $XO -Value ""
foreach ($Share in $ShareList)
{
$ShName = $Share.Name
$ShPath = $Share.Path
Add-Content $XO -Value "$ShPath"
}
Add-Content $XO -Value ""
}
#Local Folder where collection files are stored.
$Collection_Folder = "C:\Temp\PrePostValidate\"
#set up variables for write-progress
$current = 1
$first_Check = test-path $Target
if ($first_Check)
{
$targets = gc $target
$tot = $targets.Length #Variable for Write-Progress
}
else
{
$targets = $target
$tot = 1 #Variable for Write-Progress
}
foreach ($Server in $Targets)
{
if ($Server -ne "")
{
$pct = ($current * 100) / $tot #Variable for Write-Progress
$serv_File = join-path "$Collection_Folder" "$server"
#$serv_File = $serv_File + ".txt"
if ($Check)
{
CCLocalFldr "$Collection_Folder"
#if the file currently exists, remove it before progressing.
if (Test-Path $serv_File)
{
$null = rm "$serv_File" -Force
}
if ((pingSvr $Server) -eq 0)
{
Add-Content $serv_File -Value ""
write-progress "Taking a Pre-Reboot snapshot" "Collecting information on $server" -percent $pct
$drives = GetHDD $Server
WriteXMLDriveInfo $drives $serv_File
$services = GetSVC $Server
WriteXMLServices $services $serv_File
$NetShares = GetShare $Server
WriteXMLShare $NetShares $serv_File
Add-Content $serv_File -Value ""
}
}
# Files are in the proper location. Validate after a reboot.
if ($Validate)
{
$Problem_Flag = $null
write-progress "Taking a Post-Reboot Check" "Validating information on $server" -percent $pct
if (Test-Path $serv_File)
{
[xml]$OldFile = gc $serv_File
##
# Drive Stuff
#
##
#Read in Pre-Reboot Drive values
$ODrives = $OldFile.Server.Drives.Drive
#Post-Reboot Drive Info
$NDrives = GetHDD $Server
#Compare Drive info
foreach ($Dr in $ODrives)
{
$dLBL = $Dr.Label
$dTXT = $dr."#text"
if ($NDrives | ? {$_.Caption -eq "$dLBL"})
{
$NDSize = (($NDrives | ? {$_.Caption -eq "$dLBL"}).Capacity)
#Drive Found Success. Need to add a provision in here that checks for both drive letter and drive size.
if (!($NDSize -eq $dTXT))
{
Write-Host "[DRIVES]:: $server $dLBL Drive Size Mismatch." -ForegroundColor Yellow
$Problem_Flag = 1
}
}
else
{
Write-Host "[DRIVES]:: $server $dLBL Drive not mounted." -ForegroundColor Yellow
$Problem_Flag = 1
#Drive not found error.
}
}
##
# Services Stuff
#
##
#Service List from File
$OServices = $OldFile.Server.Services.Service
#Post-Reboot running services
$NServices = getSVC $Server
foreach ($OSVC in $OServices)
{
if (!($NServices | Select-String "$OSVC"))
{
#In Testing, I was running into issues with the service "MSSQL$MICROSOFT##SSEE", so I had to
#add the below extra test.
if ($OSVC -notlike '*SQL*')
{
$Problem_Flag = 1
Write-Host "[Services]:: $server - $OSVC service is not currently running." -ForegroundColor Yellow
#Service failed to start. Failure
}
else
{
if (!(gwmi -ComputerName $Server Win32_Service | ? {($_.Name -eq "$OSVC") -and ($_.state -eq "Running")}))
{
$Problem_Flag = 1
Write-Host "[Services]:: $server - $OSVC service is not currently running." -ForegroundColor Yellow
}
}
if ($FixService) {
Write-Host "[Services]:: Attempting to start $OSVC on $Server..." -ForegroundColor Magenta -BackgroundColor White
if (((gwmi -ComputerName $Server Win32_Service | ? {$_.Name -eq "$OSVC"}).StartService()).ReturnValue -eq 0) {
Write-Host "[Services]:: $server - $OSVC service has been properly started." -ForegroundColor Green
} else {
Write-Host "[Services]:: $server - $OSVC service FAILED to start properly!!!" -ForegroundColor Red
}
}
}
}
##
# Shares Stuff
#
##
#Pre-Reboot Shares List
$OShares = $OldFile.Server.Shares.Share
#Post-Reboot Shares
$NShares = GetShare $Server
foreach ($OldShare in $OShares)
{
$OldShareName = $OldShare.Name
$OldSharePath = $OldShare."#text"
if (!($NShares | ? {($_.Name -eq "$OldShareName") -and ($_.Path -eq "$OldSharePath")}))
{
#Share offline. Failure
$Problem_Flag = 1
Write-Host "[NetShares]:: $server - $OldShareName share is not online." -ForegroundColor Yellow
}
}
##
# Post-work Cleanup (Any new additions should be done above this section)
#
##
if (!$Problem_Flag)
{
#Everything was good.
write-host "[$server]:: Ok." -foregroundColor Green
if (!$NoDelete)
{
$QUIET = rm $serv_File -force
}
}
else
{
#Oh Noes! there was a problem. Alert the user with RED.
Write-host "[SUMMARY]:: There is a problem with $Server" -ForegroundColor Red
}
}
else
{
#File not found error.
Write-Host "[GENERAL]:: $server - Validation file not found. Please run this with -Check first." -ForegroundColor Red
}
}
$current++
}
}
#::CHANGELOG###############################################################
#
# v1.0 - Initial production script. -SS 8/28/09
# v1.1 - Functionalized writing to a file -SS 11/16/09
# v2.0 - Reworked entire script to use an XML file as output during check
# - Added proper parameters section
# - Added new check for Net Shares -SS 2/28/11
# v2.01 - Made minor change to how a SQL service was identified during a validate. -SS 3/3/11
# v2.03 - Changed the drive check and validation to check for mount points instead of logical drives. -SS 3/3/11
# v2.1 - Added new functionality for attempting to start a failed service using [-FixService] switch. -SS 9/1/11
#
#
###########################################################################