Articles in the "Reboot script for Exchange environment" series
- Patch and reboot script for an entire Exchange environment, Part 1
- Patch and reboot script for an entire Exchange environment, Part 2
- Patch and reboot script for an entire Exchange environment, Part 3
- Patch and reboot script for an entire Exchange environment, Part 4 [This article]
- Patch and reboot script updated to version 2.1
- Patch and reboot script updated to v2.4
After enabling transcript logging, loading the Exchange snap-in, and connecting to SCOM, the server processing begins. This is grouped by server role and production vs. DR.
1 2 3 4 5 6 7 |
ProcessServerGroup $HTCAS 'HTCAS' ProcessServerGroup $UM 'UM' ProcessServerGroup $MB 'MB' BalanceDB ProcessServerGroup $DRHTCAS 'HTCAS' ProcessServerGroup $DRUM 'UM' ProcessServerGroup $DRMB 'MB' |
Based on my environment’s configuration where hub transport and client access server are colocated, the production HT/CAS servers are processed, then the UM servers, and then mailbox servers. When the production mailbox servers are complete, the databases are re-balanced according to activation preference. Then the DR servers are processed.
Let’s go through the ProcessServerGroup function.
1 2 3 4 5 6 7 8 9 10 |
function ProcessServerGroup($serverGroup,$groupType) { foreach ($server in $serverGroup) { Write-Host "*******************Beginning processing of $server.*******************" $Host.UI.RawUI.WindowTitle = "Processing $server" if ($bSendStatusUpdates) { SendStatus "Processing beginning" $server } |
The function is called by passing the array that contains the server names, along with the role they serve. Looping through each server in the array, the display reflects the status. If status updates are enabled, line 9 calls a function with the status and the server name; here is the SendStatus function:
1 2 3 4 5 6 7 |
function SendStatus($details,$server) { $mailSubject = "$server status update" $mailBody = "$server: $details" $smtp = New-Object Net.Mail.SmtpClient($mailServer) $smtp.Send($mailSender,$statusRecipients,$mailSubject,$mailBody) } |
The only noteworthy thing about the previous function is the use of the SmtpClient .NET class instead of the Send-MailMessage cmdlet. This is because of the different encoding used between them. When sending to a mobile device via SMS, the cmdlet’s encoding causes non-printable characters to be displayed in the SMS body. Using the .NET class avoids this.
The next section of the ProcessServerGroup function is for SCOM. If SCOM updates are enabled and the remote PowerShell session to the RMS is established, a function to start maintenance mode is called:
1 2 3 4 |
if ($bUpdateSCOM -and $global:bSCOMSessionOpen) { StartSCOMMaintenance $server } |
And here is that function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function StartSCOMMaintenance($nodeName) { WriteTime;Write-Host 'Putting server into maintenance mode in SCOM...' $ErrorActionPreference = 'Stop' try { Invoke-Command -ScriptBlock {param($nodeName) $serverCrit = "DisplayName like '$nodeName%'"} -ArgumentList $nodeName -Session $global:scomSession Invoke-Command -ScriptBlock {$monObj = Get-MonitoringObject -MonitoringClass $monClass -Criteria $serverCrit} -Session $global:scomSession Invoke-Command -ScriptBlock {param($duration) $now = Get-Date;$maintStartTime = $now.ToUniversalTime();$maintEndTime = $now.AddMinutes($duration).ToUniversalTime()} -ArgumentList $maintModeDuration -Session $global:scomSession Invoke-Command -ScriptBlock {New-MaintenanceWindow -MonitoringObject $monObj -StartTime $maintStartTime -EndTime $maintEndTime -Reason PlannedApplicationMaintenance -Comment 'Patch and reboot'} -Session $global:scomSession WriteTime;Write-Host 'Server successfully put into maintenance mode in SCOM.' $script:bMaintModeActive = $true } catch { WriteTime;Write-Host 'Warning: Server could not be put into maintenance mode in SCOM.' -ForegroundColor Yellow $script:bMaintModeActive = $false } $ErrorActionPreference = 'Continue' } |
Lines 7-10 send commands to the remote session. It took some time to figure out how to do this because it isn’t well documented. The gist is that the SCOM object for a server has to be found, then a new maintenance window created. You can’t have an open-ended window, so the duration is set to the variable defined earlier. If the server is successfully put into maintenance mode, Line 12 sets a variable with this state. If any of the previous steps fail, a warning is output to the screen. I don’t treat this as a fatal error, so the patching will continue.
The next post in the series will continue with the ProcessServerGroup function and moving active database copies if a server with the mailbox role is being processed.
Download the complete script:
Reboot-ExchangeServers.zip (7.5 KiB)
Hi,
Nice work! very good, just what I was searching for. only thing is when I run it I get the following notice:
“Loading the Exchange 2010 Management Snap-in…” then it errors with: “The script can only be run on a system with the Exchange 2010 management tools installed”. This is in red and on an Exchange server with the tools installed. Can you explain it, am I missing something?
thanx
Harald
I have corrected the function that loads the snap-in and updated the copy of the script on the site.