Invoke-magdevExchangeMW.ps1
<#PSScriptInfo
.DESCRIPTION Allows Interactive Patching of Exchange during maintenance windows (WSUS/SCCM) .VERSION 1.0 .GUID 6e52afd9-3a79-48ed-97a5-8c6a0a804eae .AUTHOR Ken Maglio @kenmaglio .TAGS 2013 .RELEASENOTES Intial Release. #> Add-PSSnapin *exchange* -ErrorAction SilentlyContinue $WhatIf = $false # you can set to $true and this will not take effect function Get-Answer { param( $caption = "Proceed?", $message = "Please see prior output to decide!", $option1 = "Proceed", $option2 = "Stop" ) $opt1 = new-Object System.Management.Automation.Host.ChoiceDescription "&$option1","$option1"; $opt2 = new-Object System.Management.Automation.Host.ChoiceDescription "&$option2","$option2"; $choices = [System.Management.Automation.Host.ChoiceDescription[]]($opt1,$opt2); $answer = $host.ui.PromptForChoice($caption,$message,$choices,0) switch ($answer){ 0 { return $true } 1 { return $false } default { return $false } } } function Get-MailStoreHealth { param ( $copyQueueLengthMax = 100 ) $allStores = Get-MailboxDatabaseCopyStatus * $healthy = 0 $mounted = 0 $other = 0 $copyQueueLengthCurrent = 0 $allStores | ForEach-Object { switch ($_.Status) { "Mounted" { $mounted++ } "Healthy" { $healthy++ } default { $other++ } } if ($_.CopyQueueLength -gt $copyQueueLengthCurrent) { $copyQueueLengthCurrent = $_.CopyQueueLength } } Write-Host "Current Status: " -ForegroundColor White Write-Host "Mounted: $mounted" -ForegroundColor Magenta Write-Host "Healthy: $healthy" -ForegroundColor Green Write-Host "Other: $other" -ForegroundColor Red Write-Host "" Write-Host "Max Copy Queue Length: $copyQueueLengthCurrent" -ForegroundColor Cyan if ($other -gt 0) { Write-Host "*********************************************" -ForegroundColor Red Write-Host "*********************************************" -ForegroundColor Red Write-Host "***** MailStores Not Healthy ******" -ForegroundColor Red Write-Host "*********************************************" -ForegroundColor Red Write-Host "*********************************************" -ForegroundColor Red return $false } elseif ($copyQueueLengthCurrent -gt $copyQueueLengthMax) { Write-Host "*********************************************" -ForegroundColor Red Write-Host "*********************************************" -ForegroundColor Red Write-Host "***** Copy Queue Length > $copyQueueLengthMax ******" -ForegroundColor Red Write-Host "*********************************************" -ForegroundColor Red Write-Host "*********************************************" -ForegroundColor Red return $false } else { return $true } } function Restart-ComputerAndWaitForExchange { param( $server, $WhatIf, $waitMinutes = 2 ) #reboot server if(Get-Answer -message "Do you want to reboot $($server)?" -option1 "Yes" -option2 "No") { Write-Host "Issuing Reboot to Server and Waiting for the reboot..." -ForegroundColor Yellow Restart-Computer $server -Force -Confirm:$false -Wait -WhatIf:$WhatIf #wait for exchange to be healthy Write-Host "Waiting $waitMinutes minutes for exchange health ..." if (-not($WhatIf) ) { $Time = [System.Diagnostics.Stopwatch]::StartNew() while($Time.Elapsed.Minutes -lt 5) { Write-Host "Elapsed: $($Time.Elapsed.Minutes)min." $success = Get-MailStoreHealth if ($success) { break; } Start-Sleep -Seconds 30 } $Time.Stop() if ($Time.Elapsed.Minutes -ge $waitMinutes) { Write-Host "Time Elapsed is > $($waitMinutes)min. and we still have bad Exchange Health" Write-Host "*********************************************" -ForegroundColor Red Write-Host "*********************************************" -ForegroundColor Red Write-Host "***** BAD EXCHANGE HEALTH ******" -ForegroundColor Red Write-Host "*********************************************" -ForegroundColor Red Write-Host "*********************************************" -ForegroundColor Red return $false } Write-Host "Server Reboot and Wait complete!" -ForegroundColor Green return $true } else { Write-Host "---WhatIf -- not waiting" return $true } } } ##################################################################################################################### ##################################################################################################################### ##################################################################################################################### ##################################################################################################################### Get-MailStoreHealth | Out-Null if (Get-Answer -message "Is Exchange Healthy Enough To Proceed?" -option1 "Yes" -option2 "NO! STOP THE PRESSES!") { $allExServers = Get-ExchangeServer ForEach($server in $allExServers) { Write-Host ("Server: $($server.Name)") $mountedStores = Get-MailboxDatabaseCopyStatus -Server $server.id | Where {$_.Status -eq 'Mounted'} $activationsDone = 0 if ($mountedStores.Count -gt 0) { if(Get-Answer -message "There are active copies on $($server.Name)... Proceed?" -option2 "Skip") { foreach($mountedStore in $mountedStores) { $mailStoreName = $mountedStore.Name.Split("\")[0] $mountedServer = $mountedStore.Name.Split("\")[1] Write-Host "Mailstore $mailStoreName is on $($server.Name)" -ForegroundColor Green $allCopies = Get-MailboxDatabaseCopyStatus $mailStoreName | Where {$_.Name -notlike "*$($mountedServer)"} $moveToServer = $allCopies[0].Name.Split("\")[1] Write-Host "Intent is to Activate on $moveToServer" -ForegroundColor Yellow if(Get-Answer -message "Activate $mailStoreName on $($moveToServer)?" -option2 "Skip") { Write-Host "Activating Mailstore..." try { Move-ActiveMailboxDatabase $mailStoreName -ActivateOnServer $moveToServer -WhatIf:$WhatIf -Confirm:$false Write-Host "Activating Mailstore Complete!!!" -ForegroundColor Green } catch { Write-Host "ERROR!!!" -ForegroundColor Red break; } $activationsDone++ } else { Write-Host " --- Not Moving cause you said not to..." } } Write-Host "Mounted Stores: $($mountedStores.Count) -- 'Move' Activations Completed: $activationsDone" $rebootAndHealthy = Restart-ComputerAndWaitForExchange -server $server -WhatIf $WhatIf if (-not($rebootAndHealthy)) { Write-Host "Stopping Script" break; } } else { Write-Host "Skipping $($server.Name)... " -ForegroundColor Yellow } } else { Write-Host "There are no mailstores active on $($server.Name)..." -ForegroundColor Yellow Restart-ComputerAndWaitForExchange -server $server -WhatIf $WhatIf } } if(Get-Answer -message "Rebalance?" -option1 "Yup! Do it!" -option2 "No - leave it alone") { $scriptPath = "C:\Program Files\Microsoft\Exchange Server\V15\Scripts\RedistributeActiveDatabases.ps1" $dag = Get-DatabaseAvailabilityGroup $argumentList = @() $argumentList += ("-DagName", "$($dag.Name)") $argumentList += ("-BalanceDbsByActivationPreference") $argumentList += ("-Confirm:`$false") $argumentList += ("-WhatIf:`$$($WhatIf.ToString().ToLower())") Write-Host "Attempting to invoke-expression with: `"$scriptPath`" $argumentList" Invoke-Expression "& `"$scriptPath`" $argumentList" } } |