Hello Everyone,
Being windows administrator it is necessary to patch the Servers till the latest and so its necessary to Reboot them after patching in order to see the effects the patches.
I have recently automated the Patch Management Process by integrating SCCM+SCO+ITSM tool and the complete Patching for a list of servers is taken care automatically on the respective schedule times.
The only pre-requisite is to maintain an inventory for all the servers with patching schedule details.
The PROBLEM BEGINS HERE, although patching is automated but reboot is suppressed throughout the deployment and now the task is "TO REBOOT THE LIST OF SERVERS THAT RECENTLY GOT PATCHED".
This is how the Inventory of patching schedule looks like :
File.csv(view is modified for legibility)
ComputerName Date StartTimeEnd Time vm-server1 12/22/2014 8:00 10:00 vm-server2 02/22/2015 6:00 8:00 vm-server3 12/22/2014 8:00 10:00 vm-server4 01/07/2015 14:00 16:00
When it comes to patching the till the deployment of patches everything works but the problem is in coding the script for rebooting the servers.
MAJOR POINTS ON REBOOT:
* The reboot should be completed within the Start Time and End Time ,but should start only after the systems are patched.
* The reboot script should keep on iterating on the list of servers and keep updating the reboot status and should stop 30 mins before end time.
All this points I have developed this powershell code with various assurance that systems are rebooted only when reboot is pending on system and once rebooted they are not rebooted again.
* Please suggest me if the below solution is OK for the purpose or How well can I optimize this code to work for me :
#import of Schedules
$csv=Import-Csv D:\file.csv
$StartTime=([datetime]$($csv.Time[0])).AddMinutes(30).ToString('HH:mm:ss')
$EndTime=([datetime]$($csv.'End Time'[0])).AddMinutes(-30).ToString('HH:mm:ss')
$Time2 =Get-Date-DisplayHintTime-Format("HH:mm:ss")
$TimeDiff1 =New-TimeSpan $Time2 $EndTime
#sleep time for iterations
$sleeptime_iterate=($TimeDiff1.Hours/6)*3600
Start-Sleep-Seconds3 #initial sleep time
$i=0
do
{
$CIReport=Import-Csv D:\final.csv
Foreach($Computer in $CIReport.ComputerName)
{
$PendFileRename,$Pending,$SCCM = $false,$false,$false
$CBSRebootPend = $null
# Making registry connection to the local/remote computer
$RegCon =[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"LocalMachine",$Computer)
# Query WUAU from the registry
$RegWUAU = $RegCon.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\")
$RegWUAURebootReq = $RegWUAU.GetSubKeyNames()
$WUAURebootReq = $RegWUAURebootReq -contains "RebootRequired"
# Query PendingFileRenameOperations from the registry
$RegSubKeySM = $RegCon.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\")
$RegValuePFRO = $RegSubKeySM.GetValue("PendingFileRenameOperations",$null)
# Closing registry connection
$RegCon.Close()
$lastPatched=$Computer |%{ gwmi win32_quickfixengineering -computer $_ |?{ $_.installedon }| sort @{e={[datetime]$_.InstalledOn}}|select-last1}
$date =Get-Date
if($date -eq $lastPatched)
{
$Datematched="True"
}
else
{
$Datematched="False"
}
# If PendingFileRenameOperations has a value set $RegValuePFRO variable to $true
If($RegValuePFRO)
{
$PendFileRename = $true
}#End If ($RegValuePFRO)
# Determine SCCM 2012 Client Reboot Pending Status
# To avoid nested 'if' statements and unneeded WMI calls to determine if the CCM_ClientUtilities class exist, setting EA = 0
$CCMClientSDK = $null
$CCMSplat =@{
NameSpace='ROOT\ccm\ClientSDK'
Class='CCM_ClientUtilities'
Name='DetermineIfRebootPending'
ComputerName=$Computer
ErrorAction='SilentlyContinue'
}
$CCMClientSDK =Invoke-WmiMethod@CCMSplat
If($CCMClientSDK)
{
If($CCMClientSDK.ReturnValue-ne 0)
{
Write-Warning"Error: DetermineIfRebootPending returned error code $($CCMClientSDK.ReturnValue)"
}#End If ($CCMClientSDK -and $CCMClientSDK.ReturnValue -ne 0)
If($CCMClientSDK.IsHardRebootPending-or $CCMClientSDK.RebootPending)
{
$SCCM = $true
}#End If ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending)
}#End If ($CCMClientSDK)
Else
{
$SCCM = $null
}
# If any of the variables are true, set $Pending variable to $true
If($CBSRebootPend -or $WUAURebootReq -or $SCCM )
{
$Pending = $true
}#End If ($CBS -or $WUAU -or $PendFileRename)
# Creating Custom PSObject and Select-Object Splat
$SelectSplat =@{
Property=('Computer','CBServicing','WindowsUpdate','CCMClientSDK','RebootPending','ScheduleMatch')
}
New-Object-TypeNamePSObject-Property@{
Computer=$Computer
CBServicing=$CBSRebootPend
WindowsUpdate=$WUAURebootReq
CCMClientSDK=$SCCM
RebootPending=$Pending
ScheduleMatch=$Datematched
}|Select-Object@SelectSplat|Export-Csv D:\Reboot\Status.csv -NoTypeInformation
#Reboot Module-if(Conditions are true)
if($WUAURebootReq -eq "True"-and $SCCM -and"True"-and $Pending -eq "True"-and $Datematched -eq "True")
{
Try
{
$LastBootUpTime =Get-WmiObjectWin32_OperatingSystem-Comp localhost |Select-ExpLastBootUpTime
$RebootTime=[System.Management.ManagementDateTimeConverter]::ToDateTime($LastBootUpTime)
if($RebootTime.Date-eq (Get-Date).Date)
{
$Timer0=Get-Date
$SelectSplat3 =@{
Property=('Computer','Status','TimeStamp')
}
New-Object-TypeNamePSObject-Property@{
Computer=$Computer
TimeStamp=$Timer0
Status="Already Rebooted"
}|Select-Object@SelectSplat3|Export-Csv D:\Reboot\Already_Rebooted.csv -NoTypeInformation-Append
}
else{
Restart-Computer-Computername $Computer -force -ErrorAction
}
}
catch
{
$Timer1=Get-Date
$SelectSplat1 =@{
Property=('Computer','Status','TimeStamp')
}
New-Object-TypeNamePSObject-Property@{
Computer=$Computer
Status="Not Rebooted"
TimeStamp=$Timer1
}|Select-Object@SelectSplat1|Export-Csv D:\Reboot\NotRebooted.csv -NoTypeInformation-Append
}
}#end of IF
Else
{
$Timer2=Get-Date
$SelectSplat1 =@{
Property=('Computer','Status','TimeStamp')
}
New-Object-TypeNamePSObject-Property@{
Computer=$Computer
Status="Not Rebooted"
TimeStamp=$Timer2
}|Select-Object@SelectSplat1|Export-Csv D:\Reboot\NotRebooted.csv -NoTypeInformation-Append}
}#End Foreach ($Computer in $ComputerName)
Start-Sleep-Seconds $sleeptime_iterate
$i++
$Time3 =Get-Date-DisplayHintTime-Format("HH:mm:ss")
$TimeDiff =New-TimeSpan $Time3 $EndTime
}while($TimeDiff.Hours-ge 0-and $TimeDiff.TotalMinutes-gt 30)