Tuesday, May 2, 2017

Putting SCOM agents in maintenance mode during Configmgr SCCM patching using a management pack.

A while ago I was tasked to suppress the alerts from SCOM for servers which were being patched and rebooted. There is a checkbox in SCCM which allows you to suppress the SCOM alerts but it did not work in my case and we got bombarded with alerts during a patching window.

This management pack in your environment should help in catching those alerts and suppressing your servers when there is a reboot for patching. Copy the code below and create your own xml file.
Name it Contoso.Patching.Maintenance.xml before you import it or you can rename it to the company or organization you work for.
But make sure that you replace Contoso everywhere.

This management pack will monitor the agents for an event 1074. Which is the Configmgr initiated reboot.
Then run a power shell script which will put those agents in maintenance mode.


<?xml version="1.0" encoding="utf-8"?><ManagementPack ContentReadable="true" SchemaVersion="2.0" OriginalSchemaVersion="1.1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <Manifest>
    <Identity>
      <ID>Contoso.Patching.Maintenance</ID>
      <Version>1.0.0.0</Version>
    </Identity>
    <Name>Contoso Patching Maintenance</Name>
    <References>
      <Reference Alias="MicrosoftWindowsLibrary7585010">
        <ID>Microsoft.Windows.Library</ID>
        <Version>7.5.8501.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="SystemLibrary7585010">
        <ID>System.Library</ID>
        <Version>7.5.8501.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="SystemCenter">
        <ID>Microsoft.SystemCenter.Library</ID>
        <Version>7.0.8433.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Health">
        <ID>System.Health.Library</ID>
        <Version>7.0.8433.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
    </References>
  </Manifest>
  <Monitoring>
    <Rules>
      <Rule ID="Contoso.ConfigmgrInitiated.Reboot.Alert.Rule" Enabled="true" Target="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Server.Computer" ConfirmDelivery="true" Remotable="true" Priority="Normal" DiscardLevel="100">
        <Category>Alert</Category>
        <DataSources>
          <DataSource ID="DS" TypeID="MicrosoftWindowsLibrary7585010!Microsoft.Windows.EventProvider">
            <ComputerName>$Target/Property[Type="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Computer"]/NetworkName$</ComputerName>
            <LogName>System</LogName>
            <Expression>
              <And>
                <Expression>
                  <SimpleExpression>
                    <ValueExpression>
                      <XPathQuery Type="UnsignedInteger">EventDisplayNumber</XPathQuery>
                    </ValueExpression>
                    <Operator>Equal</Operator>
                    <ValueExpression>
                      <Value Type="UnsignedInteger">1074</Value>
                    </ValueExpression>
                  </SimpleExpression>
                </Expression>
                <Expression>
                  <SimpleExpression>
                    <ValueExpression>
                      <XPathQuery Type="String">PublisherName</XPathQuery>
                    </ValueExpression>
                    <Operator>Equal</Operator>
                    <ValueExpression>
                      <Value Type="String">User32</Value>
                    </ValueExpression>
                  </SimpleExpression>
                </Expression>
                <Expression>
                  <RegExExpression>
                    <ValueExpression>
                      <XPathQuery Type="String">EventDescription</XPathQuery>
                    </ValueExpression>
                    <Operator>ContainsSubstring</Operator>
                    <Pattern>The process C:\Windows\CCM\Ccmexec.exe</Pattern>
                  </RegExExpression>
                </Expression>
                <Expression>
                  <RegExExpression>
                    <ValueExpression>
                      <XPathQuery Type="String">EventDescription</XPathQuery>
                    </ValueExpression>
                    <Operator>ContainsSubstring</Operator>
                    <Pattern>has initiated the restart of computer</Pattern>
                  </RegExExpression>
                </Expression>
              </And>
            </Expression>
          </DataSource>
        </DataSources>
        <WriteActions>
          <WriteAction ID="Alert" TypeID="Health!System.Health.GenerateAlert">
            <Priority>1</Priority>
            <Severity>0</Severity>
            <AlertName />
            <AlertDescription />
            <AlertOwner />
            <AlertMessageId>$MPElement[Name="Contoso.ConfigmgrInitiated.Reboot.Alert.Rule.AlertMessage"]$</AlertMessageId>
            <AlertParameters>
              <AlertParameter1>$Data/LoggingComputer$</AlertParameter1>
              <AlertParameter2>$Data/EventSourceName$</AlertParameter2>
              <AlertParameter3>$Data/EventNumber$</AlertParameter3>
              <AlertParameter4>$Data[Default='']/EventDescription$</AlertParameter4>
            </AlertParameters>
            <Suppression />
            <Custom1 />
            <Custom2 />
            <Custom3 />
            <Custom4 />
            <Custom5 />
            <Custom6 />
            <Custom7 />
            <Custom8 />
            <Custom9 />
            <Custom10 />
          </WriteAction>
        </WriteActions>
      </Rule>
      <Rule ID="Contoso.ConfigMgrInitiated.Reboot.Script.Rule" Enabled="true" Target="SystemCenter!Microsoft.SystemCenter.AllManagementServersPool" ConfirmDelivery="false" Remotable="true" Priority="Normal" DiscardLevel="100">
        <Category>Custom</Category>
        <DataSources>
          <DataSource ID="Scheduler" TypeID="SystemLibrary7585010!System.Scheduler">
            <Scheduler>
              <SimpleReccuringSchedule>
                <Interval Unit="Minutes">2</Interval>
              </SimpleReccuringSchedule>
              <ExcludeDates />
            </Scheduler>
          </DataSource>
        </DataSources>
        <WriteActions>
          <WriteAction ID="ExecuteScript" TypeID="MicrosoftWindowsLibrary7585010!Microsoft.Windows.PowerShellWriteAction">
            <ScriptName>SuppressPatchedServers.ps1</ScriptName>
            <ScriptBody>
            ## This script will suppress the patched servers
 Add-PSSnapin "Microsoft.EnterpriseManagement.OperationsManager.Client" -ErrorVariable errSnapin;
 Function WriteEvent ($Messages,$ID) {
 $Messages = $Messages + "`t" + $(get-date).ToString()
 Write-EventLog -LogName Application -Source PatchingSuppress -EventId $ID -Message $Messages
 }


#WriteEvent "Starting patching script in Contoso.Patching.Maintenance.xml mp" "1234"

$Date = Get-Date
$path = $date.Month.ToString() + $date.Day.ToString() + $date.Year.ToString() + ".log"
$minutes= 15
$comment= "Rebooted by Configuration Manager"
$reason="PlannedOther"
$startTime = [System.DateTime]::Now
$endTime = $startTime.AddMinutes($minutes)
$Agents = Get-SCOMAgent
$Alerts = Get-ScomAlert -Criteria {Name like 'Contoso Reboot Initiated Alert' and ResolutionState = 0}


foreach($Alert in $Alerts)
{
$agent = $Agents | Where-Object {$_.DisplayName -eq $alert.MonitoringObjectName}
if(($clusters = $agent.GetRemotelyManagedComputers()))
   {
      $clusterNodeClass = Get-MonitoringClass -Name Microsoft.Windows.Cluster.Node
       foreach($cluster in $clusters)
         {
           $clusterObj = Get-MonitoringClass -Name Microsoft.Windows.Cluster | Get-MonitoringObject -Criteria "Name='$($cluster.ComputerName)'"
            if($clusterObj)
             {
               $clusterObj.ScheduleMaintenanceMode($startTime,$endTime,$reason,$Comment,"Recursive")
               $nodes = $clusterObj.GetRelatedMonitoringObjects($clusterNodeClass)
                if($nodes)
                   {
                   foreach($node in $nodes)
                     {
                       $message = $node.ToString()
                       WriteEvent "Putting node $message into maintenance mode by patching script in Contoso.Patching.Maintenance.xml mp." "1235"
                       }
                   }
              }
              $message = $($cluster.Computer).ToString()
              WriteEvent "Putting cluster computer $message into maintenance mode by patching script in Contoso.Patching.Maintenance.xml mp." "1236"
              New-MaintenanceWindow -StartTime $startTime -EndTime $endTime -MonitoringObject $cluster.Computer -Reason $reason -Comment $comment
          }
    }
   
    else
   {
     $message = $($agent.HostComputer.DisplayName).ToString()
     WriteEvent "Putting server $message into maintenance mode by patching script in Contoso.Patching.Maintenance.xml mp." "1237"
     New-MaintenanceWindow -StartTime $startTime -EndTime $endTime -MonitoringObject $agent.HostComputer -Reason $reason -Comment $comment
   }

   $Alert | Set-SCOMAlert -ResolutionState 255 -CustomField8 "Patching maintenance completed"
 }
 #WriteEvent "Ending patching script in Contoso.Patching.Maintenance.xml mp" "1238"

            </ScriptBody>
            <TimeoutSeconds>60</TimeoutSeconds>
          </WriteAction>
        </WriteActions>
      </Rule>
    </Rules>
  </Monitoring>
  <Presentation>
    <Folders>
      <Folder ID="Folder_5e3e9391b6394ab288bd1c95f83e90cd" Accessibility="Public" ParentFolder="SystemCenter!Microsoft.SystemCenter.Monitoring.ViewFolder.Root" />
    </Folders>
    <StringResources>
      <StringResource ID="Contoso.ConfigmgrInitiated.Reboot.Alert.Rule.AlertMessage" />
    </StringResources>
  </Presentation>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="false">
      <DisplayStrings>
        <DisplayString ElementID="Contoso.Patching.Maintenance">
          <Name>Contoso Patching Maintenance</Name>
          <Description>Author: Parag Waghmare
Reason: Created to suppress the servers during reboots initiated by patching</Description>
        </DisplayString>
        <DisplayString ElementID="Folder_5e3e9391b6394ab288bd1c95f83e90cd">
          <Name>Contoso Patching Maintenance</Name>
        </DisplayString>
        <DisplayString ElementID="Contoso.ConfigmgrInitiated.Reboot.Alert.Rule">
          <Name>Contoso Reboot Initiated Alert</Name>
          <Description />
        </DisplayString>
        <DisplayString ElementID="Contoso.ConfigmgrInitiated.Reboot.Alert.Rule.AlertMessage">
          <Name>Contoso Reboot Initiated Alert</Name>
          <Description>Computer:{0}
EventSource:{1}
EventID:{2}
Event Description: {3}
</Description>
        </DisplayString>
        <DisplayString ElementID="Contoso.ConfigmgrInitiated.Reboot.Alert.Rule" SubElementID="DS">
          <Name>DS</Name>
        </DisplayString>
        <DisplayString ElementID="Contoso.ConfigmgrInitiated.Reboot.Alert.Rule" SubElementID="Alert">
          <Name>Alert</Name>
        </DisplayString>
        <DisplayString ElementID="Contoso.ConfigMgrInitiated.Reboot.Script.Rule">
          <Name>Contoso suppress patching server script</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPack>

Friday, April 28, 2017

System Center management health service credentials not found Alert


The SCOM run as profiles is a collection of run as accounts and objects that they are targeted to.

You select to add a run as account and distribute it to either a Class, Group or Object.

This all works fine and well until you choose to make the distribution for the account more secure and do not select the computers where you want this account to be distributed.

I have seen customers choosing to distribute the account to all targeted objects and then not adding those in the distribution to the run as account.

This the runas profile configuration which you see when you click on the runas profiles.


This is the runas account distribution you see when you click on the run as accounts.


This particular alert will give you the account ssid which is causing the alerts.

If you do not want this account do be distributed you can close the alert and it wont appear until there is  restart for the health service on the agent.

But if you don't want this, use the following script to find the account and then add the computer to it for distribution.



$SSID = "Enter the ssid from the alert here"





Get-RunAsAccount | Sort Name | % {$string = $null;$_.SecureStorageId | % {   $string = $string + "{0:X2}" -f $_}



 $RunAsAccountName = $_.Name

 [string]$RunAsAccountSSID = $string

 if ($SSID -match $RunAsAccountSSID) {write-host "The Run As Account is .. $RunAsAccountName"}

 }




Thursday, April 27, 2017

Putting a SCOM agent (non clustered) in maintenance mode using powershell

## Putting scom agent in maintenance mode. This does not yet put agents which are part ## of a cluster in maintenance mode.




$rootMS = "rootms"

$agentName = "agentname"

$minutes= 10

$comment= "Planned Reboot"

$reason="PlannedOther"

$startTime = [System.DateTime]::Now

$endTime = $startTime.AddMinutes($minutes)

Add-PSSnapin "Microsoft.EnterpriseManagement.OperationsManager.Client" -ErrorVariable errSnapin;

New-ManagementGroupConnection -ConnectionString:$rootMS

set-location "OperationsManagerMonitoring::";

$agent = Get-Agent | ?{$_.computername -match $agentName}

$agent

New-MaintenanceWindow -StartTime $startTime -EndTime $endTime -MonitoringObject $agent.HostComputer -Reason PlannedOther -Comment $Comment