Orchestrator 2012: Check SCCM maintenance window and set SCOM maintenance mode

Everyone who uses System Center Configuration Manager 2012 and System Center Operations Manager 2012 knows the problem of setting the server into maintenance mode when patching or software deployment needs to take place.

With System Center Orchestrator 2012 you get the integration packs for both systems and the option to create a workflow for this task. My intetion for this was to use the maintenance windows which are defined on the collections. During this timeframe software updates and deployments can be performed on the servers incl. reboots. So it would be good to set the servers into maintenance mode in SCOM. I only focussed on general maintenance mode windows not OSD ones and non recurring windows.

Here is the summary of the workflow I have created:
The workflow runs every 2 minutes. It reads a text file on the runbook server with all collection ids it should check, then checks if the collection has a maintenance window defined, that will start within the next 10-15 minutes. If yes, then it gets the collection members in SCCM, gets the FQDN for the server and starts the maintenance mode in SCOM. If successful it writes a log file otherwise it tries again to set the maintenance mode with the Netbios name.

Diagram:

set sccm maintenance window

Most of the parts are standard activities, so I only describe the “Get Maintenance Window” activity, which runs a PowerShell script on the Runbook server. This activity needs to run with a user that has SCCM permissions, otherwise it will provide no result. It only will have output data, if the maintenance window will occur within the next 10-15 minutes. So the link to the Get Collection Members activity should have the following include entry: Pure Output from Get Maintenance Window matches pattern .+

Here is the command line for the Get Maintenance Window activity:

cmd.exe /c | c:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe –c “function WMI-DateStringToDate($time) {  [System.Management.ManagementDateTimeconverter]::ToDateTime($time);};$collsettings = ([WMIClass] ‘\\SCCM Server FQDN\root\SMS\site_SCCMSiteCode:SMS_CollectionSettings’).CreateInstance();if($collsettings -is [Object]){$collsettings.CollectionID = ‘Link to Line Text of previous activity’;$collsettings.get();$windows=$collsettings.ServiceWindows;if ($windows -is [Object]){$now=Get-Date;Foreach ($window in $windows){$Time=WMI-DateStringToDate($window.StartTime);if (($window.IsEnabled -eq $True) -and ($window.ServiceWindowType -eq ‘1’) -and ($window.RecurrenceType -eq ‘1’)){if (($now.AddMinutes(15).compareto($Time) -eq ‘1’) -and ($now.AddMinutes(10).compareto($Time) -eq ‘-1’)){$Duration=$window.Duration+15;write-host ($Time.ToString(),$Duration) -separator ‘;’}}}}};”

Attention! The command line should not have line breaks! Otherwise it will not work within this activity.
For better readability I post the script here also with line breaks and comments:

param($SMSSiteCode, $SMSManagementServer, $COLLECTION_ID)
# convert WMI date to DateTime format
function WMI-DateStringToDate($time)
{ [System.Management.ManagementDateTimeconverter]::ToDateTime($time)}
# get collection settings (incl. Maintenance Windows)
$collsettings= ([WMIClass] \\$SMSManagementServer\root\SMS\site_$($SmsSiteCode):SMS_CollectionSettings).CreateInstance()
if($collsettings -is [Object])
{
$collsettings.CollectionID =$COLLECTION_ID
$collsettings.get()
$windows=$collsettings.ServiceWindows
if ($windows -is [Object])
{
$now=Get-Date
Foreach ($window in $windows)
{
$Time=WMI-DateStringToDate($window.StartTime)
# only check general maintenance and non recurring windows
if (($window.IsEnabled -eq$True) -and ($window.ServiceWindowType -eq‘1’) -and ($window.RecurrenceType -eq‘1’))
{
# check if starttime is within the next 10-15 min.
if (($now.AddMinutes(15).compareto($Time) -eq‘1’) -and ($now.AddMinutes(10).compareto($Time) -eq‘-1’))
{
# add 15 min to duration as buffer
$duration=$window.Duration+15;
write-host ($Time.ToString(),$Duration) -Separator ‘;’
}
}
}
}
}

Another thing to mention: Please add an exclude to the link between “Get Collection Member” and “Get FQDN” for your Management Servers: Member Name from Get Collection Member equals SCOMMGServerName.
Then they will not be set into maintenance mode if they are members of the checked collections.

Update

I found some problems with the daylight saving settings on the runbook server. We use UTC maintenance windows in SCCM. With daylight saving the local time of the runbook server gets adjusted but the maintenance window stays in standard UTC. The script compares the local time with the maintenance window. With the old version it sets the maintenance window at the wrong time when daylight saving is enabled.

Therefore I had to adjust the script. Here is the new version. The italic entries are new.

cmd.exe /c | c:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe –c “function WMI-DateStringToDate($time) {  [System.Management.ManagementDateTimeconverter]::ToDateTime($time);};$collsettings = ([WMIClass] ‘\\SCCM Server FQDN\root\SMS\site_SCCMSiteCode:SMS_CollectionSettings’).CreateInstance();if($collsettings -is [Object]){$collsettings.CollectionID = ‘Link to Line Text of previous activity’;$collsettings.get();$windows=$collsettings.ServiceWindows;if ($windows -is [Object]){$now=Get-Date;$universal=$now.ToUniversalTime().AddHours(([System.TimeZoneInfo]::Local).baseutcoffset.hours);$diff=($now.subtract($universal)).Hours;Foreach ($window in $windows){$Time=WMI-DateStringToDate($window.StartTime);if (($window.IsEnabled -eq $True) -and ($window.ServiceWindowType -eq ‘1’) -and ($window.RecurrenceType -eq ‘1’)){if (($now.AddMinutes(15).compareto($Time.AddHours($diff)) -eq ‘1’) -and ($now.AddMinutes(10).compareto($Time.AddHours($diff)) -eq ‘-1’)){$Duration=$window.Duration+15;write-host ($Time.ToString(),$Duration) -separator ‘;’}}}}}”

Here is the link to the runbook.

Advertisements
Post a comment or leave a trackback: Trackback URL.

Comments

  • astrally2000  On May 16, 2013 at 6:58 am

    Hi there,
    Thanks for this runbook, I have found the integration with SCCM useful, however we have a very large environment (several hundred servers within a specific collection) over several domains and as such the Get FQDN activity is taking a long time as it run remotely against each host. It also means that I can’t get the FQDN for computers within other domains (as there is no trust). I will explore simply appending our internal domain name to get the majority of the objects and when we have completed our SCCM deployment to external domains, will try and get the FQDN from SCCM.
    Another suggestion that I’ve looked at is replacing the read file activity with a SQL query so that should additional maintenance windows be created with the name maintenance in them they will be included automatically.

    SELECT COL.CollectionID 
    FROM dbo.v_Collection COL 
    WHERE COL.Name like ‘%maintenance%’

    Thanks for providing in the first instance,
    Cheers
    Andrew

    • opsmgrtipps  On June 17, 2013 at 6:48 am

      H Andrew,

      thanks for these great comments. You are right. It all depends on your environment, so I am glad for every idea to optimize the runbooks and adopt it to your needs.
      I like the SQL query and will add it to my own running workflow. Thanks!

      Kind regards
      Natascia Heil

  • Garion  On July 10, 2013 at 7:35 pm

    Would it be possible to publish the entire runbook? I see significant value in having this runbook but I’m having issues with the actual command portion (get current window). It seems to simply “hang” with no output or anything. Should I be able to run the command independently for a collection if there is a window and get output? Any help would be appreciated in regards to debugging this aspect. Thanks for the great blog btw..you have some good stuff here. Keep up the good work!

    • opsmgrtipps  On July 29, 2013 at 11:03 am

      Garion,

      thank you for your positive feedback. To follow up on your problem. It should be able to run the “get maintenance window” activity in a separated runbook. You only need to enter your servername, site code and the collection ID you would like to check. It should provide a pure output if a current maintenance window exists.
      Did you try the first or the updated script? You could also try the script directly in PowerShell to see if it generally works.

      Kind regards,

      Natascia

  • Waz  On August 7, 2013 at 4:15 am

    This is exactly what we were looking for! However, I have the same issue as Garion. Even when I run the script directly on the SCCM server command line, I dont get any errors, just a blank output. I’ve tried sending the output to a text file, but it is blank. All other activites in the runbook operate normally, but for the life of me I am unable to extract the maintenance window schedule from SCCM. When executed from the runbook, It just hangs on the Get Maintenacne Window activity; I guess waiting for an output. I’ve checked and double checked the maintenance window is current on the collection and even set it to run for 23 hours every day. Any ideas? Thanks again

    • opsmgrtipps  On August 12, 2013 at 7:33 am

      Hi Warwick,

      I have published the runbook on Dropbox. Here is the link:

      Please do not use it without adopting it to your environment (path to list, sccm servername and site code, scom connection, management server name etc).

      Kind regards,

      Natascia

  • Garion  On August 22, 2013 at 6:13 pm

    Natascia, thank you for publishing your RB, this is extremely helpful in debugging the issues I’m having but I’m still unable to get the ‘get maintenance window’ activity working. I created a test maintenance window and try running the command manually but receive this error;

    Exception calling “Get” with “0” argument(s): “Not found ”
    At line:1 char:305
    + … =
    `GarionTest’;$collsettings.get();$windows=$collsettings.ServiceWindows;if ($wi

    + ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    C:\>cmd.exe /c | c:\Windows\system32\WindowsPowerShell\v1.0\po
    wershell.exe -c “cls;function WMI-DateStringToDate($time){[System.Management.Man
    agementDateTimeconverter]::ToDateTime($time);};$collsettings = ([WMIClass] `\\\root\SMS\site_CCM:SMS_CollectionSettings’).CreateIns
    tance();if($collsettings -is [Object]){$collsettings.CollectionID = `GarionTest’
    ;$collsettings.get();$windows=$collsettings.ServiceWindows;if ($windows -is [Obj
    ect]){$now=Get-Date;$universal=$now.ToUniversalTime().AddHours(([System.TimeZone
    Info]::Local).baseutcoffset.hours);$diff=($now.subtract($universal)).Hours;Forea
    ch ($window in $windows){$Time=WMI-DateStringToDate($window.StartTime);if (($win
    dow.IsEnabled -eq $True) -and ($window.ServiceWindowType -eq ‘1’) -and ($window.
    RecurrenceType -eq ‘1’)){if (($now.AddMinutes(15).compareto($Time.AddHours($diff
    )) -eq ‘1’) -and ($now.AddMinutes(10).compareto($Time.AddHours($diff)) -eq ‘-1’)
    ){$Duration=$window.Duration+15;write-host ($Time.ToString(),$Duration) -separat
    or ‘;’}}}}}”

    I’m also wondering if this part of the WMI statement is correct if my site code is CCM??

    \\\root\SMS\site_CCM:SMS_CollectionSettings’

    • Garion  On August 22, 2013 at 8:28 pm

      Ok, so I figured out what was the issue with the command but now I have specified a test maint window within 10-15 mins and verified the window. The ‘get-maintenance window’ activity however, merely continues to run and never finishes. I separated the get-maintenance windows activity into it’s own runbook and it does the same thing…just runs with no output and never finishes?? Any ideas?

  • Stuart  On November 12, 2013 at 2:00 pm

    Great stuff. Another approach to scheduling, since Orchestrator clearly isn’t great at scheduling, is to use the Windows Task Scheduler to invoke runbooks. If your environment has a limited number of SUS patching windows defined, you’d only need a handful of scheduled tasks to invoke the runbooks to set maintenance mode. The benefit would be to only take up runbook server resources when really needed.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: