My thanks to Matt Taylor and Kevin Holman, Ralph Kyttle, and John Kavanagh for their guidance!
Updated 24 Jun 2022
Read on if these apply
Trying to start, update, or end SCOM MM
Get alerts when MM is updated
PowerShell only in your shop!
SCORCH in play but need to convert runbooks to straight PowerShell
Ran into issues using Set-SCOMMaintenanceMode, as the cmdlet doesn’t put ALL the recursive classes under Windows Computer
Background
Set-SCOMMaintenanceMode cmdlet is actually “by design.” ☹
Start-SCOMMaintenanceMode assumes you want recursive action when you start maintenance mode….
Pick a Windows Computer and it places the Windows Computer object (AND all contained objects) into MM.
Computer in MM
All contained objects in MM
However, the problem is that Set-SCOMMaintenancemode does not have an understanding of recursiveness.
Command changes the MM entry for the Windows Computer, but NOT all the contained objects. So they retain the original setting.
Health explorer looks like this, resulting in unwanted alerts
Details
NOTE these $Time and DateTime Method are dependent on the delay between running the commands
If you start MM, and wait 5 minutes, then update, the total MM duration will be ~20 minutes
Maintenance Mode options and examples
# Setup variables for MM
# Example 1 Windows Computer
$server = “Servername.FQDN”
$instance = (get-scomclass -DisplayName “Windows Computer” |Get-SCOMClassInstance | where { $_.DisplayName -eq $server } )
# Set time for 6 minutes
$Time = (Get-Date).addMinutes(6)
Start-SCOMMaintenanceMode -Instance $Instance -EndTime $Time -Comment “Starting Maintenance Mode.” -Reason “PlannedOther”
# Example 2
# Business needs require Windows Operating System monitoring to occur while Application is in maintenance
# My Example is Defender, could be SQL, MSMQ, Lync, Skype, or your custom class created for your application
$Class = (get-scomclass)
$Class | ? { $_.Name -like “*Defender*” } | fl DisplayName,Name
$Class | ? { $_.Name -like “*Defender*” } | fl DisplayName,Name
DisplayName : Protected Endpoint
Name : Microsoft.WindowsDefender.ProtectedServer
DisplayName : Protected Candidate
Name : Microsoft.WindowsDefender.ProtectedServerCandidate
DisplayName : Unprotected Endpoint
Name : Microsoft.WindowsDefender.UnprotectedServer
DisplayName : Microsoft Windows Defender Class
Name : Microsoft.Windows.Defender.Class
# Choose the class needed
$server = “Servername.FQDN”
$instance = ( $Class | ? { $_.Name -like “Microsoft.Windows.Defender*” } |Get-SCOMClassInstance | ? { $_.DisplayName -eq $server } )
# Verify Instance variable
$instance
PS C:\Users\scomadmin> $instance
HealthState InMaintenanceMode DisplayName
———– —————– ———–
Success False WFM.testlab.net
# Don’t forget to add time variable
$Time = (Get-Date).addMinutes(6)
# Start maintenance mode
Start-SCOMMaintenanceMode -Instance $Instance -EndTime $Time -Comment “Starting Maintenance Mode.” -Reason “PlannedOther”
Start, Update, End and Verify Maintenance mode syntax
# Start MM via PoSH cmdlet
Start-SCOMMaintenanceMode -Instance $Instance -EndTime $Time -Comment “Starting Maintenance Mode.” -Reason “PlannedOther”
# Start MM using method vs. PowerShell cmdlet
Note Recursive in $WCobj.ScheduleMaintenanceMode
$windowsComment=”PlannedOther”
$windowReason=”PlannedOther”
$windowsComment=”Testing Maintenance Mode”
$windowDuration=15
$server= “wfm.testlab.net”
$instance = (get-scomclass -DisplayName “Windows Computer” |Get-SCOMClassInstance | ? { $_.DisplayName -eq $server } )
$instance.ScheduleMaintenanceMode([datetime]::Now.touniversaltime(),([datetime]::Now).addminutes($windowDuration).touniversaltime(), “$windowReason”, “$windowsComment” , “Recursive”)
# Drop Recursive if you don’t want it (but can’t imagine why you would!)
# Update MM
# Make sure you’ve put object in MM
$server= “wfm.testlab.net”
$instance = (get-scomclass -DisplayName “Windows Computer” |Get-SCOMClassInstance | ? { $_.DisplayName -eq $server } )
# 15 minutes in the future
$instance.UpdateMaintenanceMode([System.datetime]::Now.touniversaltime().addminutes(15),[Microsoft.EnterpriseManagement.Monitoring.MaintenanceModeReason]::PlannedOther,[System.string]::”Adding 15 minutes to the end time.”,[Microsoft.EnterpriseManagement.Common.TraversalDepth]::Recursive);
# Stop MM
# Make sure you’ve put object in MM
# Immediate
$instance.StopMaintenanceMode([System.DateTime]::Now.ToUniversalTime());
My thanks to Jan Nevaril
$server.StopMaintenanceMode([System.DateTime]::Now.ToUniversalTime(),“Recursive”)
Verification steps
# Verify MM
get-scommaintenancemode -ComputerName $instance.Name|fl MonitoringObjectId,StartTime,ScheduledEndTime
NOTE This will error if you’ve stopped maintenance
Example
PS C:\Users\scomadmin> get-scommaintenancemode -ComputerName $instance.Name
get-scommaintenancemode : The Data Access service is either not running or not yet initialized. Check the event log
for more information.
At line:1 char:1
+ get-scommaintenancemode -ComputerName $instance.Name
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Microsoft.Syste…anceModeCommand:GetSCMaintenanceModeCommand) [Get-S
COMMaintenanceMode], ServiceNotRunningException
+ FullyQualifiedErrorId : ExecutionError,Microsoft.SystemCenter.OperationsManagerV10.Commands.GetSCMaintenanceMode
Command
# Validate MM through Operations Manager Event ID’s 1215 and 1216 logged
get-eventlog -LogName “Operations Manager” | ? { $_.EventID -eq 1215 -OR $_.EventID -eq 1216 } |fl EventID,TimeGenerated,Message
# Alternate command to check latest 100 events
get-eventlog -LogName “Operations Manager” -newest 100 | ? { $_.EventID -eq 1215 -OR $_.EventID -eq 1216 } |fl EventID,TimeGenerated,Message
# Error if object NOT in MM
Cannot find an overload for “UpdateMaintenanceMode” and the argument count: “1”.
At line:1 char:1
+ $WCobj.UpdateMaintenanceMode(([System.datetime]::Now).addminutes(15). …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
PS C:\Windows\system32>
Testing System datetime
PS C:\Windows\system32> [System.datetime]::Now.addminutes(15)
Thursday, August 24, 2017 9:18:04 AM
PS C:\Windows\system32> ([System.datetime]::Now.addminutes(15)).touniversaltime()
Thursday, August 24, 2017 2:18:16 PM
References
2012 PowerShell cmdlets https://docs.microsoft.com/en-us/previous-versions/system-center/hh920227(v=sc.20)
2016 PowerShell cmdlets https://docs.microsoft.com/en-us/powershell/module/operationsmanager/?view=systemcenter-ps-2016
2019 PowerShell cmdlets https://docs.microsoft.com/en-us/powershell/module/operationsmanager/?view=systemcenter-ps-2019
SDK
Ralph Kyttle Blog https://blogs.technet.microsoft.com/ralphkyttle/2014/11/10/scom-2012-r2-use-powershell-to-end-an-active-maintenance-mode/
DateTime Methods https://docs.microsoft.com/en-us/dotnet/api/system.datetime
SCOM 2019 Maintenance Mode
https://docs.microsoft.com/en-us/system-center/scom/manage-maintenance-mode-overview?view=sc-om-2019
MSDN MaintenanceModeReason Method https://docs.microsoft.com/en-us/previous-versions/system-center/developer/bb465591(v=msdn.10)
MSDN StopMaintenanceMode Method
UpdateMaintenanceMode Method https://docs.microsoft.com/en-us/previous-versions/system-center/developer/bb424495(v=msdn.10)
MM deluxe custom script https://gist.github.com/stegenfeldt/b3f044aa77894ed80d82f8849a48035b
To stop MM recursively, use $server.StopMaintenanceMode([System.DateTime]::Now.ToUniversalTime(),“Recursive”)
with the recursive option
How can we put iis of perticular server in maintenance mode using powershell
Here’s a way –
See what instances and classes you want into maintenance with Get-SCOMClass, and pipe your output to format-list -property * to see all properties of the class.
# IIS 10 web server example
get-scomclass -DisplayName “IIS 10 Web Server”
get-scomclass -DisplayName “IIS 10 Web Server” | fl -property *
Example outputs
PS C:\Users\scomadmin> get-scomclass -DisplayName “IIS 10 Web Server”
DisplayName Name ManagementPackName Id
———– —- —————— —
IIS 10 Web Server Microsoft.Windows.InternetI… Microsoft.Windows.InternetI… c0ed2093-0af1-b6ae-4ee4…
PS C:\Users\scomadmin> get-scomclass -DisplayName “IIS 10 Web Server” | fl -property *
ManagementPackName : Microsoft.Windows.InternetInformationServices.2016
PropertyCollection : {}
Base : ManagementPackElementUniqueIdentifier=c2dbd9a8-c677-5ec7-735e-bc703e84b743
Hosted : True
Singleton : False
Extension : False
OptimizationCollection : {}
FullTextSearchable :
XmlTag : ClassType
Abstract : False
Accessibility : Public
ManagementGroup : SCOM2016
ManagementGroupId : e39f5f53-9fbb-9d7f-4bfe-5f0324630ae5
Identifier : 1|Microsoft.Windows.InternetInformationServices.2016/31bf3856ad364e35|1.0.0.0|Microsoft.Window
s.InternetInformationServices.10.0.WebServer||
Name : Microsoft.Windows.InternetInformationServices.10.0.WebServer
Id : c0ed2093-0af1-b6ae-4ee4-07624efe25d6
DisplayName : IIS 10 Web Server
Description : IIS 10 Web Server
LanguageCode : ENU
Comment :
Status : Unchanged
LastModified : 10/29/2020 1:42:00 PM
TimeAdded : 1/31/2017 7:23:18 PM
InstanceName :
NOTE: Windows computer is the top level class putting the server in maintenance for patching, where Windows Computer uses DisplayName for one property for the server name.
Adjust the $instance variable based on the class and property name to what object(s) you want in maintenance.
# Substitute the IIS pieces you want for the underlined fields from the Windows Computer blog example
$instance = (get-scomclass -DisplayName “Windows Computer” |Get-SCOMClassInstance | where { $_.DisplayName -eq $server } )