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
#
#
###########################################################################