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 " " } function WriteXMLServices($SVCList, $XO) { Add-Content $XO -Value "$HDD_Size " } Add-Content $XO -Value "" foreach ($SVC in $SVCList) { $SVCName = $SVC.Name Add-Content $XO -Value " " } function WriteXMLShare ($ShareList, $XO) { Add-Content $XO -Value "$SVCName " } Add-Content $XO -Value "" foreach ($Share in $ShareList) { $ShName = $Share.Name $ShPath = $Share.Path 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 "$ShPath " } Add-Content $XO -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 # # ###########################################################################