SCOM Powershell Examples

Generic PowerShell Snippets

Connecting to OpsMgr

Example commands to connect to SCOM Servers. All the scripts listed here requires a connection to a SCOM Management Server:

Import SCOM Management Modules:

Import-Module OperationsManager
New-SCOMManagementGroupConnection -ComputerName SERVERNAME

Same thing by pulling the location of the Module from the registry

$moduleDir = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\System Center Operations Manager\12\Setup\Powershell\V2').InstallDirectory
$modulePath = Join-Path -Path $moduleDir -ChildPath '\OperationsManager\OperationsManager.psm1'
Import-Module $modulePath
New-SCOMManagementGroupConnection -ComputerName SERVERNAME

Enable Agent Proxy

Get-SCOMAgent | where-object {$_.ProxyingEnabled –match "false"} | Enable-SCOMAgentProxy

Remove Disabled Classes

Run this to remove old discovered class instances/objects that are no longer installed, also to remove class instances where the discovery has been manually disabled.


Add a Windows Server to SCOM

Run this to remotely add a Windows Server to SCOM, the Primary Management Server is the SCOM server the newly installed Agent will communicate with:

$PrimaryMgmtServer = Get-SCOMManagementserver -Name
Install-SCOMAgent -Name servername.DOMAIN.COM -PrimaryManagementServer $PrimaryMgmtServer

Forceably Remove a Windows Server

In rare circumstances, it is impossible to remove an Agent Managed Server from SCOM. Use the below script that utilizes the SDK connection to SCOM to remove the server

$Servername = "SERVNAME_TO_REMOVE"
$administration = (Get-SCOMManagementGroup).GetAdministration();
$agentManagedComputerType = [Microsoft.EnterpriseManagement.Administration.AgentManagedComputer];
$genericListType = [System.Collections.Generic.List``1]
$genericList = $genericListType.MakeGenericType($agentManagedComputerType)
$agentList = new-object $genericList.FullName
$agent = Get-SCOMAgent *$Servername*
$genericReadOnlyCollectionType = [System.Collections.ObjectModel.ReadOnlyCollection``1]
$genericReadOnlyCollection = $genericReadOnlyCollectionType.MakeGenericType($agentManagedComputerType)
$agentReadOnlyCollection = new-object $genericReadOnlyCollection.FullName @(,$agentList);    

Backup and Compress Management Packs

It is HIGHLY Recommended to backup your custom Management Packs at least once a day. The below script will backup and compress your unsealed Management Packs:

# This script backs up all the unsealed SCOM Mangement Packs
$tempdir = "$env:TEMP"
$backup_dir = $tempdir + "\SCOM\"
New-Item -ItemType directory -Path $backup_dir -Force
$CurrentDate = Get-Date
$FormattedDate = $CurrentDate.ToString("yyMMdd")
$fullpath = "$backup_dir" + "$FormattedDate"
$finaldir = "\\servername\BackupMPs\PROD\"
New-Item -ItemType directory -Path $fullpath
New-Item -ItemType directory -Path $fullpath\UnSealed
Import-Module OperationsManager 
New-SCOMManagementGroupConnection -ComputerName $SCOMServer
Get-SCOMManagementPack | where {$_.Sealed -eq $false} | export-SCOMmanagementpack -path $fullpath\UnSealed
Add-Type -AssemblyName System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::CreateFromDirectory($fullpath, ($fullpath + ".$archivetype"))
Remove-Item $fullpath -Force -Recurse
Move-Item ($fullpath + ".$archivetype") $finaldir

Get-SCOMGroup Alternatives

The PowerShell SCOM Modules includes a cmdlet to pull the SCOM Groups in a Management Group. Unfortunately the process behind this cmdlet creates very long SQL Queries when there are many groups in the Management Group, around 900+ groups. Many times, the SQL Server will choke on the query with a "could not produce a query plan" error.

Below are some examples of how to work around this issue, as well as speed up process of pulling data as these processes are normally faster than the Get-SCOMGroup cmdlet. These alternatives heavily use SCOM Classes, an easy way to get the names of classes to use run this command to get a CSV file for reference:

Get-SCOMClass | select Name, DisplayName, Description, ManagementPackName | Export-Csv classes.csv

Pull the Windows Servers and Linux Servers in a SCOM Group

$groupnameclass = Get-SCOMClass | Where-Object {$_.Displayname -eq "Server Group Name"}
$groupname = Get-SCOMClassInstance -Class $groupnameclass
$winserverclass = Get-SCOMClass -Name "Microsoft.Windows.Computer"
$winservers = $groupname.GetRelatedMonitoringObjects($winserverclass,"Recursive")
$linserverclass = Get-SCOMClass -Name  "Microsoft.Unix.Computer"
$linservers = $groupname.GetRelatedMonitoringObjects($linserverclass,"Recursive")

Pull Subgroups under a main group

$groupnameclass = Get-SCOMClass | Where-Object {$_.Displayname -eq "Parent Group Name"}
$parentgroup = Get-SCOMClassInstance -Class $groupnameclass
$groupclass = Get-SCOMClass -Name "System.Group"
$subgroups = $parentgroup.GetRelatedMonitoringObjects($groupclass,”Recursive”)

Working with Alerts

Here are some PowerShell examples you can use to work with SCOM Alerts

Closing Rule Alerts by Age

Alerts coming from SCOM "Rules" will not resolve themselves even when the issue is resolved. Examples would be alerts from Windows System Logs, etc. To avoid filling the Alert views with old Rule Alerts that no one closes, use something similar to below to auto-close these alerts.

$AgeHours = 12
get-scomalert -criteria 'ResolutionState=''0'' AND IsMonitorAlert=''False''' | where {$_.TimeRaised -le (Get-Date).addhours(-$AgeHours)} | resolve-SCOMAlert -Comment 'Close old alerts generated by rules' -PassThru | Set-SCOMAlert -ResolutionState 255

Reset Monitor Alerts by Name

To quickly "Reset" monitors that have alerts triggered by Alert Name use something similar to below:

$alertname = "Unable to establish AD authorization"
$alerts = get-scomalert | where {($_.Name -eq $alertname) -And (!($_.ResolutionState -eq 255))}
foreach ($alert in $alerts)
  $ruleid = $alert.monitoringruleid
  $classid = $alert.monitoringclassid
  $objectid = $alert.monitoringobjectid
  $monitor = Get-SCOMMonitor | where {$ -eq $ruleid}
  $monitoringclass = Get-SCOMClass | where {$ -eq $classid}
  $monitoringobject = Get-SCOMMonitoringobject -class $monitoringclass | where {$ -eq $objectid}
  $monitoringobject | foreach{$_.ResetMonitoringState($monitor)}

Reset Monitor Alerts that were Manually Closed

With SCOM, Alerts triggered from actual "Monitors" should auto-resolve themselves once the issue has been resolved. In some cases, Users may incorrectly "Close" these alerts without fixing the issue. Use something similar to below to auto-reset monitors that weren't closed by "System":

$alerts = Get-SCOMAlert -Criteria "IsMonitorAlert=1 AND ResolutionState=255" | where-Object { $_.ResolvedBy -notlike "system" }
# SanityCheck
if ($alerts -is [object])
  foreach ($alert in $alerts)
    $monitoringobject = Get-SCOMClassinstance -id $alert.MonitoringObjectId
    # Reset Monitor if still in Error or Warning State
    If (($monitoringobject.HealthState -eq ‘Error’) -or ($monitoringobject.HealthState -eq ‘Warning’))

Reset Applog and Syslog based "Monitor" Alerts

Some of Microsoft's Management Packs have "Monitors" that are watching for Applog and Syslog entries. These should have been written as "Rules", but since they weren't this will allow you to auto-resolve them:

# This Script will reset any Alert older than X hours generated from a Monitor that is based on Application or System Log entries.
# These should have been created as "Rules" instead of Monitors.
Import-Module OperationsManager
New-SCOMManagementGroupConnection -ComputerName SCOMSERVERNAME
$alerttime = ((Get-Date).addhours(-18)).ToUniversalTime()
$tmpalerts = Get-SCOMAlert -Criteria "IsMonitorAlert=1 AND ResolutionState=0" | where {($_.TimeRaised -gt $alerttime) -And !($_.Severity -eq "Information")}
ForEach ($alert in $tmpalerts) {
    $monitor = Get-SCOMMonitor | where {$ -eq $alert.MonitoringRuleID}
    If ($monitor.typeid.Identifier.Path -like "*EventLog*") { 
        $monitoringobject = Get-SCOMClassinstance -id $alert.MonitoringObjectId
        # Reset Monitor if still in Error or Warning State
        If (($monitoringobject.HealthState -eq ‘Error’) -or ($monitoringobject.HealthState -eq ‘Warning’))

Resolving Health Service Alerts

Here is an example of pulling Health Service Alerts where the computer is still pinging. This is a basic stop/start the Health Service, expand as you need to clear the cache, etc.

$allalerts = Get-SCOMAlert | Where-Object {$_.ResolutionState -eq 0}
$offalerts = $allalerts | Where-Object { ($_.Name -eq 'Failed to Connect to Computer') -And ($_.ResolutionState -eq 0)}
ForEach ($alert in $offalerts) {
	$servername = $alert.MonitoringObjectDisplayName
	$offservers += $servername
$hsalerts = $allalerts | Where-Object { ($_.Name -eq 'Health Service Heartbeat Failure') -And ($_.ResolutionState -eq 0)}
ForEach ($alert in $hsalerts) {
	$servername = $alert.MonitoringObjectDisplayName
	$hsservers += $servername
ForEach ($hsserver in $hsservers) {
	if(!($offservers -Match $hsserver)){
		echo $hsserver
		Invoke-Command -ComputerName $hsserver {Stop-Service 'Microsoft Monitoring Agent'}
		Sleep 5
		Invoke-Command -ComputerName $hsserver {Start-Service 'Microsoft Monitoring Agent'}

Reset Agent Push Alerts

When SCOM Agent Updates and Installs fail, it generates an alert based on a "Monitor", this will reset these alerts:

# This script will reset the Agent Push Monitors that trigger when SCOM fails to push the Agent.
# These are Monitors, yet they will never auto-resolve on their own
Import-Module OperationsManager 
New-SCOMManagementGroupConnection -ComputerName SCOMSERVERNAME
$AgeHours = 4
$alert1 = "Failed Agent Push/Repair - Agent Installer service failed to start"
$alert2 = "Failed Agent Push/Repair - Agent Management task timed out"
$alert3 = "Failed Agent Push/Repair - Could not acquire exclusive access to remote registry"
$alert4 = "Failed Agent Push/Repair - Could not connect to Service Control Manager"
$alert5 = "Failed Agent Push/Repair - Could not remotely verify agent operating system version"
$alert6 = "Failed Agent Push/Repair - Management Server failed to perform an operation on a remote computer"
$alert7 = "Failed Agent Push/Repair - Remote Agent Management operation failed"
$alerts = get-scomalert | where {( ($_.Name -eq $alert1) -Or ($_.Name -eq $alert2) -Or ($_.Name -eq $alert3) -Or ($_.Name -eq $alert4) -Or ($_.Name -eq $alert5) -Or ($_.Name -eq $alert6) -Or ($_.Name -eq $alert7) ) -And (!($_.ResolutionState -eq 255)) -And ($_.TimeRaised -le ((Get-Date).addhours(-$AgeHours)).ToUniversalTime() )}
foreach ($alert in $alerts)
  $ruleid = $alert.monitoringruleid
  $classid = $alert.monitoringclassid
  $objectid = $alert.monitoringobjectid
  $monitor = Get-SCOMMonitor | where {$ -eq $ruleid}
  $monitoringclass = Get-SCOMClass | where {$ -eq $classid}
  $monitoringobject = Get-SCOMMonitoringobject -class $monitoringclass | where {$ -eq $objectid}
  $monitoringobject | foreach{$_.ResetMonitoringState($monitor)}

Reset Disk Fragmentation Alerts

This might be old since later URs disable this monitor by default, but here is one way to reset Disk Fragmentation Alerts:

#Win2003 monitor: Microsoft.Windows.Server.2003.LogicalDisk.DefragAnalysis
#Win2008 monitor: Microsoft.Windows.Server.2008.LogicalDisk.DefragAnalysis
#Win2012 monitor: Microsoft.Windows.Server.6.2.LogicalDisk.DefragAnalysis
 $maingroup = Get-SCOMGroup -Displayname "All Windows Computers"
 $monitor = Get-ScomMonitor | where {$_.Name -eq 'Microsoft.Windows.Server.2008.LogicalDisk.DefragAnalysis'}
 $monitorclass = Get-ScomClass -name Microsoft.Windows.Server.2008.LogicalDisk
 $groupsalerts = $maingroup.GetRelatedMonitoringObjects($monitorclass,”Recursive”)
 $fragdisks = $groupsalerts | where {$_.HealthState -eq 'Warning' -or $_.HealthState -eq 'Error'}
 $fragdisks | foreach {$_.ResetMonitoringState($monitor)}

Maintenance Mode with PowerShell

Even though SCOM 2016 brought with it a way to "Schedule" Maintenance Mode through the Console, there are still times when you need to put something in MM via a script. Here are some examples.

Putting a Single Server in MM

Here is an example of putting a single Server in MM.

$StartTime = ([DateTime]::Now).ToUniversalTime()
$EndTime = $StartTime.AddMinutes(30)
$Reason = "PlannedOther"
$Comments = "Performing some maintenance"
$servername = "blahSERVERNAMEblah"
$serveragent = Get-SCOMAgent -name $servername
$server = $serveragent.HostComputer
$server.ScheduleMaintenanceMode($StartTime, $EndTime, $Reason, $Comments)

Putting a SCOM Group in MM

Here is an example on how to put a SCOM Group in MM NOT using Get-SCOMGroup (see above)

$minutes = 30
$groupname = "My SCOM GroupName"
$StartTime = ([DateTime]::Now).ToUniversalTime()
$EndTime = $StartTime.AddMinutes($minutes)
$Reason = "PlannedOther"
$Comments = "PowerShell Group MM Example"
$groupnameclass = Get-SCOMClass | Where-Object {$_.Displayname -eq  $groupname}
$group = Get-SCOMClassInstance -Class $groupnameclass
$group.ScheduleMaintenanceMode($StartTime, $EndTime, "$Reason", "$Comments" , "Recursive")

Google Ad

© 2017 Mike Petersen - All Rights Reserved