SCOM 2016 – Error EventID 1199 GetOpsMgrDBWatcherDiscovery.ps1

For SCOM2016 testers, if you encountered EventID 1199 Health Service Script GetOpsMgrDBWatcherDiscovery.ps1 in Operations Manager log and you are missing Operations Manager Database and Data Warehouse Watchers (check the Management Group Health dashboard), then troubleshoot no more.

The GetOpsMgrDBWatcherDiscovery.ps1 script has a bug and I am sure that Microsoft will soon release a fix. But meanwhile you can import the following MP https://gallery.technet.microsoft.com/System-Center-Internal-2cf0614a that should fix the discovery and get you back on-track with your testing.

SCOM2016 compatibility of my MPs

Short updates for all users of the MPs that I published on TechNet Gallery (https://gallery.technet.microsoft.com/site/search?f%5B0%5D.Type=User&f%5B0%5D.Value=Stelian%20Postea)

– All MPs are working fine with SCOM2016 as well as SCOM2012 R2

– All MPs are still needed in SCOM2016, as none of the new features of SCOM2016 renders the additional functionality of my MPs ineffective or obsolete

– AddOn DFS Replication Management is now updated.
DFS-R: Backlog File Count (Monitor) allows now configuration of overrides for the checking interval (default 3600 sec) as well as for the backlog count threshold (default 0).
Please keep in mind that optimal overrides configuration would be using “For all objects of class: DFS-R Replication Connection” for cookdown considerations.

Lifting limitations for monitoring UNIX/Linux LogFiles using SCOM

If you landed on this article because you found the title appealing then you are already familiar with the limitations of monitoring UNIX/Linux LogFiles using SCOM.

Whatever method you followed (either by using monitoring templates or advanced MP Authoring) to create monitoring that involve Microsoft.Unix.SCXLog.VarPriv.DataSource, you most probably felt the pain of the following limitations:

  • It only works well with certain behavior of the log file
  • It only works with one log file
  • It doesn’t actually suppress alerts corresponding to entries logged during maintenance mode; the alerts come anyhow soon after maintenance window ends

My latest TechNet gallery contribution https://gallery.technet.microsoft.com/UNIXLinux-LogFile-Library-4133064b is a library Management Pack that allows you to create rules to monitor UNIX/Linux LogFiles with all the above limitations lifted:

  • works for any kind of log file, including circular
  • allows wildcard in specifying what log files you’d like to monitor
  • fully aware of maintenance mode

There is a catch – the prerequisites for using the MP:

There are good chances you already have all these ingredients.

To configure monitoring, please follow closely the instructions below, as the syntax is important to get things right.

First of all test your grep / egrep commands on your system(s) before attempting to configure monitoring.

Below is a walk through of creating a monitoring rule that uses grep under the hood.

Using Authoring pane in Operations Manager console go to Rules and select Create a new rule…; this will bring you to the screen below:

unix1

Please notice the new entries (grep and egrep) introduced by my library MP. Select the highlighted for grep.

unix2

Make your selections for the highlighted. I strongly suggest that you use your own Unix Local Application already discovered in your environment for the rule target. You can also go the route of targeting the UNIX/Linux Computer class but remember to disable the rule/monitor by default, and use an override to enable it for a group or instance (not elegant, not my favorite).

unix3

Select how often the log file check will be performed. Exercise caution in configuring it too often.

unix4

Actually it doesn’t matter what you type for Script, it will be ignored anyhow.

What matters are the Script Arguments! Here is the Script Arguments entry:

'ERROR' /log:'/tmp/*.log' /temp:/tmp

explained:
‘ERROR’ = the error pattern to be passed to grep; expression cannot contain spaces, please use . instead
/log:’/tmp/*.log’ = /log: followed by the logfiles path and name between single quotes
/temp:/tmp = /temp: followed by some temporary path that can be used to store some control files automatically handled by the datasource module; the account used in Run As profile must be able to write files in the path specified here!

Note. There is only one space in-between the arguments and single quotes are used.

unix5

Don’t bother with the alert description; regardless what you’ll configure there the alert description will be:
LogFile Error Entry below in format [LogFile]:[LineNumber]:[Entry]
{0}

That’s at least what the wizard template will deliver to you. If this is not satisfying then you’re welcomed to do some minor editing inside your unsealed MP after the rule is created.

If steps above are followed carefully then you should see something like this inside your Management Pack:

<Rule ID="MomUIGeneratedRulec7749c523f08444abd9ebc8dc5b409a3" Enabled="false" Target="MicrosoftUnixLibrary7510450!Microsoft.Unix.Computer" ConfirmDelivery="false" Remotable="true" Priority="Normal" DiscardLevel="100">
<Category>Alert</Category>
<DataSources>
  <DataSource ID="InvokeDS" TypeID="AddOnUnixLogFileLibrary!AddOn.GREPDIFF.DS">
	<TargetSystem>$Target/Property[Type="MicrosoftUnixLibrary7510450!Microsoft.Unix.Computer"]/NetworkName$</TargetSystem>
	<ErrorCode>'ERROR'</ErrorCode>
	<LogFilePattern>'/tmp/*.log'</LogFilePattern>
	<TempFolder>/tmp</TempFolder>
	<UserName>$RunAs[Name="MicrosoftUnixLibrary7510450!Microsoft.Unix.ActionAccount"]/UserName$</UserName>
	<Password>$RunAs[Name="MicrosoftUnixLibrary7510450!Microsoft.Unix.ActionAccount"]/Password$</Password>
	<Frequency>300</Frequency>
	<Timeout>30</Timeout>
  </DataSource>
</DataSources>
<WriteActions>
  <WriteAction ID="Alert" TypeID="Health!System.Health.GenerateAlert">
	<Priority>1</Priority>
	<Severity>0</Severity>
	<AlertName />
	<AlertDescription />
	<AlertOwner />
	<AlertMessageId>$MPElement[Name="MomUIGeneratedRulec7749c523f08444abd9ebc8dc5b409a3.AlertMessage"]$</AlertMessageId>
	<AlertParameters>
	  <AlertParameter1>$Data/Property[@Name='ErrorLogEntry']$</AlertParameter1>
	</AlertParameters>
  </WriteAction>
</WriteActions>
</Rule>

<DisplayString ElementID="MomUIGeneratedRulec7749c523f08444abd9ebc8dc5b409a3">
  <Name>Type a rule name here</Name>
</DisplayString>
<DisplayString ElementID="MomUIGeneratedRulec7749c523f08444abd9ebc8dc5b409a3.AlertMessage">
  <Name>Type an alert name here</Name>
  <Description>
		  LogFile Error Entry below in format [LogFile]:[LineNumber]:[Entry]

		  {0}
		</Description>
</DisplayString>

To configure the egrep version of the rule, please follow the same steps as for grep, except:

  • in Unix log Files Details screen type egrep in the Script (again it actually doesn’t matter, will be ignored)
  • enter something like this in Script Arguments:
'ERROR|^Job.status:.FATAL|EOD.Report$' /log:'/tmp/*.log' /temp:/tmp

Note. Remember: no spaces in the regular expression, use . instead! Also use single quotes.

'ERROR|^Job.status:.FATAL|EOD.Report$'

will match entries like the ones below:

2017-03-03T12:11:10.000Z ERROR [TEST] – file in use
Job status: FATAL FAILURE – file not found
2017-03-03T12:11:10.000Z Critical error in EOD Report

Hope this helps your SCOM Cross-Platform monitoring. Feedback is welcomed.

Automated SCOM Maintenance Mode according to SCCM Maintenance Windows

The SCCM option “Disable Operations Manager alerts while software updates run” in package / application / software update deployments is not triggering SCOM Maintenance Mode.

With this option checked SCCM client will only pause the SCOM agent during deployment, and this is not the equivalent to SCOM Maintenance Mode.
This has been already explained nicely in article http://blog.tyang.org/2014/04/24/use-disable-operations-manager-alerts-option-configmgr/, and maybe in a few others.

I have developed a solution to address this issue.
It is as compact as a SCOM 2012 Management Pack, for SCOM 2012.
Once imported, the MP workflows will take care of all the automation to place in Maintenance Mode monitored Windows servers exactly as per Maintenance Windows associated with SCCM collections.

There is absolutely no need for any other tools (like Orchestrator) or services outside SCOM. Nor any user intervention. Patching weekends will go by alert free.

If interested, please contact me https://stelianposteablog.wordpress.com/contact-me/.

SCOM Events Dashboard

Dashboard visualization for Operations Manager does not include an Event Widget. But this does not mean that displaying events in a dashboard is off-limits.

My suggested usage example makes use of Powershell Grid Widget with Filter (https://gallery.technet.microsoft.com/Powershell-Grid-Widget-919dc3d6).

I would design the Events dashboard as a 2 cell grid layout: the above cell called Event Collection Rule and the one below just Events. Both cells will use the Powershell Grid Widget with Filter template.

And here are the scripts that I would use to configure them.

Event Collection Rule cell:

$rules = Get-SCOMRule | Where {$_.Category -eq "EventCollection"}
foreach ($rule in $rules)
{
    $dataObject = $ScriptContext.CreateInstance("xsd://rules")
    $dataObject["Id"]=$rule.Id.Guid.ToString()
    $dataObject["RuleName"]=$rule.Name
    $dataObject["RuleDisplayName"]=$rule.DisplayName
    $ScriptContext.ReturnCollection.Add($dataObject)
}

Events cell:

Param($globalSelectedItems)
foreach ($globalSelectedItem in $globalSelectedItems)
{
    $rule = Get-SCOMRule -Id $globalSelectedItem["Id"]
    $events = Get-SCOMEvent -rule $rule
    foreach ($event in $events) {
                $dataObject = $ScriptContext.CreateInstance("xsd://events")
                $dataObject["Id"]=[string]$event.Id.Guid
                $dataObject["TimeAdded"]=[string]$event.TimeAdded
                $dataObject["LoggingComputer"]=[string]$event.LoggingComputer
                $dataObject["Description"]=[string]$event.Description
                $ScriptContext.ReturnCollection.Add($dataObject)
     }
}

The end result is an easy searchable grid for rules that classify as EventCollection category, and the corresponding events collected by the selected rule. Note that even multiple rules selection will work.

Events can also be filtered, just make sure that you click on one of the columns of the grid first.

Script Generated Event Collection – the proper way to use

I want to share my experience on using the Microsoft.Windows.TimedScript.EventProvider data source module type (https://msdn.microsoft.com/en-us/library/jj130481.aspx).

I will suggest here a simplification of the sample provided in the online documentation, just to quickly illustrate the symptom.

Here is the code for a rule that should start collecting script generated events capturing in the Description the current date and time.

<Rule ID="TestingScriptGeneratedEventCollection" Enabled="true" Target="SC!Microsoft.SystemCenter.RootManagementServer" ConfirmDelivery="false" Remotable="true" Priority="Normal" DiscardLevel="100">
        <Category>EventCollection</Category>
        <DataSources>
          <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedScript.EventProvider">
            <IntervalSeconds>300</IntervalSeconds>
            <SyncTime />
            <ScriptName>TestingScriptGeneratedEventCollection.vbs</ScriptName>
            <Arguments />
            <ScriptBody>
              <![CDATA[ Dim oAPI, oBag Set oAPI = CreateObject("MOM.ScriptAPI") Set oBag = oAPI.CreatePropertyBag() Call oBag.AddValue("Description",CStr(Now())) Call oAPI.Return(oBag) ]]>
            </ScriptBody>
            <TimeoutSeconds>10</TimeoutSeconds>
            <EventOriginId>$MPElement$</EventOriginId>
            <PublisherId>$MPElement$</PublisherId>
            <PublisherName>TimedScript.EventProvider</PublisherName>
            <Channel></Channel>
            <LoggingComputer>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</LoggingComputer>
            <EventNumber>1001</EventNumber>
            <EventCategory>1</EventCategory>
            <EventLevel>2</EventLevel>
            <UserName />
            <Description>$Data/Property[@Name="Description"]$</Description>
            <Params></Params>
          </DataSource>
        </DataSources>
        <WriteActions>
          <WriteAction ID="WriteToDB" TypeID="SC!Microsoft.SystemCenter.CollectEvent" />
          <!--<WriteAction ID="WriteToDW" TypeID="SCDW!Microsoft.SystemCenter.DataWarehouse.PublishEventData" />-->
        </WriteActions>
</Rule>

As you can see the Description property bag value goes directly into Description of the Event.

The result of this configuration is weird: either using an Event View in the OpsMgr console or by querying events using OM PowerShell you will notice that all the events have same description, despite the fact that Event Data is correct.

More precisely the Description will be the value for the last execution, updated for all events!

ev1

So here is the proper way to use this module:

<Rule ID="TestingScriptGeneratedEventCollection" Enabled="true" Target="SC!Microsoft.SystemCenter.RootManagementServer" ConfirmDelivery="false" Remotable="true" Priority="Normal" DiscardLevel="100">
        <Category>EventCollection</Category>
        <DataSources>
          <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedScript.EventProvider">
            <IntervalSeconds>300</IntervalSeconds>
            <SyncTime />
            <ScriptName>TestingScriptGeneratedEventCollection.vbs</ScriptName>
            <Arguments />
            <ScriptBody>
              <![CDATA[ Dim oAPI, oBag Set oAPI = CreateObject("MOM.ScriptAPI") Set oBag = oAPI.CreatePropertyBag() Call oBag.AddValue("Description",CStr(Now())) Call oAPI.Return(oBag) ]]>
            </ScriptBody>
            <TimeoutSeconds>10</TimeoutSeconds>
            <EventOriginId>$MPElement$</EventOriginId>
            <PublisherId>$MPElement$</PublisherId>
            <PublisherName>TimedScript.EventProvider</PublisherName>
            <Channel></Channel>
            <LoggingComputer>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</LoggingComputer>
            <EventNumber>1001</EventNumber>
            <EventCategory>1</EventCategory>
            <EventLevel>2</EventLevel>
            <UserName />
            <Description>%1</Description>
            <Params>
              <Param>$Data/Property[@Name="Description"]$</Param>
            </Params>
          </DataSource>
        </DataSources>
        <WriteActions>
          <WriteAction ID="WriteToDB" TypeID="SC!Microsoft.SystemCenter.CollectEvent" />
          <WriteAction ID="WriteToDW" TypeID="SCDW!Microsoft.SystemCenter.DataWarehouse.PublishEventData" />
        </WriteActions>
</Rule>

Please note making use of Parameters and then inserting Param into Description.

With the changes above everything looks back to normal.

ev2

The State View vs State Widget

SCOM Widgets are in almost all situations equivalent to or superior to the corresponding Views. State Widget falls in the category that justifies the almost exception.

Here it is why I continue to use State Views:
– Superior group filtering (more details on this below)
– Contextual Maintenance Mode
– Ability to perform Copy & Paste data from the view
In favor of the State Widget I can only mark the fact that it is faster.

Whenever I need to show/report inventory of a specific class, my preferred method is to use a State View. Of course such task can be performed in OM PowerShell, but creating a State View it’s easy and graphical. The experience is similar to SQL Query Designer. And the best part of it is that allows you to apply an umbrella group filter (group members hosting or containing the class of interest).

Here is a use case example that will show why State View continues to be one of my favorites: show me all the instances of SQL Server 2008 Reporting Services installed on Windows Server 2012 R2 servers; and I’d like to know the following properties: Version, Service Pack Version and Install Path.

Here is what needs to be configured:

state1

Please note the highlighted: Show data related to: _ Show data contained in a specific group: _ (that is precisely what I am looking for).

And screen below for selecting only the class properties of interest.

state2

The results are Copy & Paste exportable (Ctrl+A, Ctrl+C, Ctrl+V).

state3

And I did not care to use in this example further, graphical filtering on properties matching some criteria, definitely useful.

The corresponding State Widget configuration looks somewhat similar:

state4

Please note the highlighted: Select a class to scope the members of the specified groups – far from what I need and questionably useful.

Indeed, with such configuration the widget does not provide any results. And no matter what else you would try to configure for the widget (I tried not only the UI, but also using Component Overrides in MP XML), you cannot get the results the State View is providing.
It might be because of the way Microsoft.SystemCenter.Visualization.GetManagedEntitiesDataSource is implemented, the fact that RecursionTypeNames is set to System.Library!System.Group (I am still researching this).

I will therefore conclude that, to my taste at least, the View implemented in the Microsoft.Mom.Ui.Components assembly is better than the State Widget.

AddOn DFS Replication Management Pack (part #1 – configuration)

This article is to serve as documentation for my recent MP addition to TechNet gallery: https://gallery.technet.microsoft.com/AddOn-DFS-Replication-33d233a8.
I split the documentation into part #1 (configuration) and part #2 (featured monitoring).

The AddOn Distributed File System (DFS) Replication Management Pack for System Center Operations Manager 2012 monitors the health of DFS Replication by complementing the monitoring provided by Microsoft Management Packs:
– System Center 2012 Management Pack for Microsoft Windows Server File & iSCSI Services 2012 R2 (https://www.microsoft.com/en-us/download/details.aspx?id=42066)
– System Center 2012 Management Pack for Microsoft Windows Server File & iSCSI Services 2012 (https://www.microsoft.com/en-ca/download/details.aspx?id=34970)

Here are the Management Packs that you need to have imported in the first place:

pic1

Plus the following MP, specifically for the presentation MP (visualization):

pic2

Get this MP from:
https://gallery.technet.microsoft.com/Powershell-Grid-Widget-919dc3d6

All agents need to have the Agent Proxy setting enabled (Allow this agent to act as a proxy and discover managed objects on other computers).
Make sure that Firewalls are not blocking WMI remote connections – a lot of workflows in the DFS MPs are using WMI queries (local and remote).

Add a Windows Account with appropriate permissions on DFS. Configure this account for More Secure distribution (no selected computers, for the moment).

pic3

The AddOn.DFSReplication MP has configured a group called “Agents On Windows FileServer DFS-R”; members of this group are HealthServices on all Windows FileServer DFS-R role computers. You can use this group to have the “DFR-R Monitoring Account” distributed; just execute the following from Operations Manager Shell:

PS C:\> $distagents = Get-SCOMGroup -DisplayName “Agents On Windows FileServer DFS-R” | Get-SCOMClassInstance
PS C:\> Get-SCOMRunAsAccount -Name “DFS-R Monitoring Account” | Set-SCOMRunAsDistribution -MoreSecure -SecureDistribution $distagents

Note. Please update the commands above for whatever name you provided to the DFS-R monitoring account; in case you used exactly same name as in the screenshot, then you can use (cut and paste) the commands as they are provided.

Verification:

pic4

Last step is to associate the Profile with the RunAs account just created.

pic5

In part #2 I will detail what additional monitoring is provided by this Management Pack.

AddOn DFS Replication Management Pack (part #2 – featured monitoring)

This is second part of the documentation for my recent MP addition to TechNet Gallery: https://gallery.technet.microsoft.com/AddOn-DFS-Replication-33d233a8.

Discoveries

The AddOn.DFSReplication MP introduces a new class “DFS-R Replication Connection”. It is very similar to the “Replication Connection” defined by the Microsoft Windows Server DFS Replication MP, the only difference is that it doesn’t have the BacklogCount property – instead being a property it would be more appropriate to be a monitored counter.

AddOn.DFSReplication MP discovers by default instances of this new class.
Check the “DFS-R Replication Connection” instances discovered in the “DFS-R Replication Connections” dashboard.

Note. “Replication Connection” class instances are not discovered by default by Microsoft Windows Server DFS Replication MP; even enabled, in some cases, it fails to discover all the DFS-R replication connections.

Monitors

Three new monitors are added by AddOn.DFSReplication MP:
DFS-R: Backlog File Count (Monitor) – periodically (every 1h) checks the backlog file count and triggers warning alert in case its value is not zero.
DFSRDIAG Error Check (Monitor) – periodically (every 1h) checks that DFSRDIAG executes without encountering errors; in case errors are found it triggers warning alert.

pic6

DFS-R: Replication Service stopped replication on Volume – looks after event id 2213 in DFS Replication log; this event id is missed by the Microsoft DFS Replication MPs and actually a good indication of issues with replication.

pic7

Sample generated alerts:

pic8

Tasks

The following tasks are added by AddOn.DFSReplication MP:
“Resume Replication” for “Replication Volume”
“BackLof File Count (dfsrdiag)” for “DFS-R Replication Connection”
“DFSRDIAG SyncNow” for “DFS-R Replication Connection”
“DFSRDIAG PollAD” for “DFS Replication Service”

All tasks are executed in the “DFS Replication Monitoring Account” security context and are returning verbose output of the actions performed. All parameters are filled in contextually, from target properties.

Examples below:

pic9

pic10

pic11

pic12

pic13

Dashboards

All DFS active monitoring is performed by monitors and not rules. This means it is safe to assume that detected issues are reflected in state changes.

Here are the screenshots for the dashboards that are configured in the AddOn.DFSRReplication.Presentation MP:

pic14

pic15

References

http://blogs.technet.com/b/askds/archive/2010/11/01/common-dfsr-configuration-mistakes-and-oversights.aspx
http://www.mysysadmintips.com/windows/servers/499-dfs-replication-stops-after-unexpected-server-shutdown
http://www.mysysadmintips.com/windows/servers/500-error-while-checking-dfs-replication-backlog-2147217406-0x80041002
https://stelianposteablog.wordpress.com/2015/10/10/powershell-grid-widget-with-filter/

SCOM Maintenance Mode Scheduling Solution (Optimized and Free)

When it comes to scheduling maintenance mode in SCOM you can probably find quite a few solutions posted on Internet. This blogpost is presenting yet another (free) solution. Who knows, perhaps you’ll appreciate the simplicity of it…

My solution is leveraging only basic SCOM features: Computer Groups, System.Scheduler data source module type and VSAE snippets. In a few minutes you will be able to create your own Management Pack that will do the Maintenance Mode scheduling for you. From then on, you’ll just have to maintain this Management Pack in a very convenient way, as easy as (re)importing a csv file. Plus you’ll have to author some Computer Groups and you’re done.

Here are the steps:

1/ Using Visual Studio create a new Project (Operations Manager 2012 R2 Management Pack): call it MaintModeScheduling

2/ You will need a custom Write Action Module Type so create a MP Fragment for that like the one presented below:

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <ModuleTypes>
      <WriteActionModuleType ID="MaintModeScheduling.StartMMForGroup.WA" Accessibility="Public" >
        <Configuration>
          <xsd:element name="ComputerGroupDisplayName" type="xsd:string" minOccurs="1" maxOccurs="1"/>
          <xsd:element name="ForHowLongInMin" type="xsd:integer" minOccurs="1" maxOccurs="1"/>
          <xsd:element name="Comment" type="xsd:string" minOccurs="1" maxOccurs="1"/>
        </Configuration>
        <OverrideableParameters>
        </OverrideableParameters>
        <ModuleImplementation>
          <Composite>
            <MemberModules>
              <WriteAction ID="WA" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagWriteAction" >
                <ScriptName>Start-SCOMMaintModeForGroup.ps1</ScriptName>
                <ScriptBody>$IncludeFileContent/Scripts/Start-GroupMaintMode.ps1$</ScriptBody>
                <SnapIns>
                </SnapIns>
                <Parameters>
                  <Parameter>
                    <Name>ComputerGroupDisplayName</Name>
                    <Value>$Config/ComputerGroupDisplayName$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>ForHowLongInMin</Name>
                    <Value>$Config/ForHowLongInMin$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>Comment</Name>
                    <Value>$Config/Comment$</Value>
                  </Parameter>
                </Parameters>
                <TimeoutSeconds>300</TimeoutSeconds>
              </WriteAction>
            </MemberModules>
            <Composition>
              <Node ID="WA"/>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <InputType>System!System.BaseData</InputType>
      </WriteActionModuleType>
    </ModuleTypes>
  </TypeDefinitions>
</ManagementPackFragment>

3/ Add a new folder to the solution called Scripts; then add a PowerShell script file resource to this folder, name the script “Start-GroupMaintMode.ps1” and copy the following content to the file

<#  .SYNOPSIS Places all members of a SCOM Computer Group in maintenance mode. .DESCRIPTION Places all members of a SCOM Computer Group in maintenance mode. .EXAMPLE  Start-GroupMaintMode.ps1 -ComputerGroupDisplayName "GroupA" -ForHowLongInMin 10 -Comment "Testing Maintenance Mode" -Verbose  Puts all Members of the "GroupA" Group in Maintenance Mode for 10 minutes with Comment "Testing Maintenance Mode". Adding Verbose information. .PARAMETER ComputerGroupDisplayName = The SCOM Computer Group name for which members you want to put in Maintenance Mode.  .PARAMETER ForHowLongInMin = The Maintenance Mode Interval .PARAMETER Comment = The Maintenance Mode Comment #>            

[CmdletBinding(SupportsShouldProcess=$true)]

param([string[]]$ComputerGroupDisplayName,[int]$ForHowLongInMin,[string]$Comment)

$Reason = "PlannedApplicationMaintenance"

$MS = gc env:computername
$ScriptName = "Start-GroupMaintMode.ps1"
$LogEventID = 509

$evt = New-Object System.Diagnostics.EventLog("Operations Manager")
$evt.Source = "MMScheduling"
$infoevent  = [System.Diagnostics.EventLogEntryType]::Information
$warnevent  = [System.Diagnostics.EventLogEntryType]::Warning
$errorevent = [System.Diagnostics.EventLogEntryType]::Error

Write-Verbose "Script $ScriptName started on $MS"
$evt.WriteEntry("Script $ScriptName started on $MS",$infoevent,$LogEventID)

$ModuleImportError = $false
Try
{
	$setupKey = Get-Item -Path "HKLM:\Software\Microsoft\Microsoft Operations Manager\3.0\Setup"
	$installDirectory = $setupKey.GetValue("InstallDirectory") | Split-Path
	$psmPath = $installdirectory + ‘\Powershell\OperationsManager\OperationsManager.psm1’

	Import-Module $psmPath

	$conn = (New-SCOMManagementGroupConnection –ComputerName $MS)
}
Catch [system.exception]
{
	Write-Verbose "Errors detected while importing module OperationsManager on $MS; $error"
	$evt.WriteEntry("Errors detected while importing module OperationsManager on $MS; $error",$errorevent,$LogEventID)
	$ModuleImportError = $true
}

If (!$ModuleImportError)
{
	$Groups = Get-SCOMGroup -DisplayName $ComputerGroupDisplayName

	if($Groups -ne $null)
	{
		foreach ($Group in $Groups)
		{
			If ($Group.InMaintenanceMode -eq $false)
			{
				Write-Verbose "Starting Maintenance Mode for $Group.DisplayName"
				$evt.WriteEntry("Starting Maintenance Mode for $Group.DisplayName",$infoevent,$LogEventID)
				$Group.ScheduleMaintenanceMode([datetime]::Now.touniversaltime(), ([datetime]::Now).addminutes($ForHowLongInMin).touniversaltime(), "$Reason", "$Comment" , "Recursive")
			}
		}
	}
}

4/ Add a snippet template to the solution (Right click on solution, Add / New Item/ Management Pack / Code / Snippet Template); name it StartMMForGroup.templatesnippet; copy/paste the following MP fragment to this snippet template:

<ManagementPackFragment SchemaVersion="2.0">
  <Monitoring>
    <Rules>
      <Rule ID="#text('Rule Id')#" Target="SC!Microsoft.SystemCenter.RootManagementServer" Enabled="#text('Enabled')#" ConfirmDelivery="false" Remotable="true" Priority="Normal" DiscardLevel="100">
        <Category>Operations</Category>
        <DataSources>
          <DataSource ID="DS" TypeID="System!System.Scheduler">
            <Scheduler>
              <WeeklySchedule>
                <Windows>
                  <Daily>
                    <Start>#text('StartTime')#</Start>
                    <End>#text('StartTime')#</End>
                    <DaysOfWeekMask>#text('DaysOfWeekMask')#</DaysOfWeekMask>
                  </Daily>
                </Windows>
              </WeeklySchedule>
              <ExcludeDates />
            </Scheduler>
          </DataSource>
        </DataSources>
        <WriteActions>
          <WriteAction ID="WA" TypeID="MaintModeScheduling.StartMMForGroup.WA">
            <ComputerGroupDisplayName>#text('ComputerGroupDisplayName')#</ComputerGroupDisplayName>
            <ForHowLongInMin>#text('ForHowLongInMin')#</ForHowLongInMin>
            <Comment>#text('Comment')#</Comment>
          </WriteAction>
        </WriteActions>
      </Rule>
    </Rules>
  </Monitoring>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="#text('Rule Id')#">
          <Name>#text('Rule Id')#</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

5/ Add snippet data to the solution (Right click on solution, Add / New Item / Management Pack / Templates / Snippet Data); call it StartMMForGroup.mpsd; then press the “Select snippet type” button and you’ll have the only option “StartMMForGroup”.

Add few items according to your needs. I think the parameter names are self-explanatory. In case in doubt what to enter for DaysOfWeekMask please refer to the PublicSchedulerType complex data type (https://msdn.microsoft.com/en-us/library/ee692976.aspx). If it’s more convenient you can Import from CSV file the data at this step.

Note that Visual Studio will perform syntax checking at this step for the data that you enter.

6/ Build your solution and import the MP. The rules in the MP will take care of the Maintenance Mode Scheduling exactly as you wrote the instructions in the snippet data. Maintain the snippet data to reflect the needs of Maintenance Mode Scheduling in your organization (and don’t forget to combine this with accurate Computer Groups membership definitions)

Enjoy…