Skip Ribbon Commands
Skip to main content

Ondrej Sevecek's English Pages


Engineering and troubleshooting by Directory Master!
MCM: Directory

Quick Launch

Ondrej Sevecek's English Pages > Posts > Sample SCOM (OpsMgr) PowerShell discovery script template
March 19
Sample SCOM (OpsMgr) PowerShell discovery script template

Again just a very fast publishing of my PowerShell discovery template for SCOM (System Center Operations Manager, OpsMgr) 2007 and newer. The script can be run from PowerShell command window (for which it generates the target instance ID and the target class ID randomly). It automatically detects if it is running customized from HealthService or from the command line in debug mode and contains debug/error output functionality which can either write into the Operations Manager event log or just to the console if you use the -dbg switch.

The script is explicitly developed to support even PowerShell 2.0 which is a common requirements with my customers.

I usually discover two additional properties for every object - the LastRunTime and ScriptError - which are easy for operational stability monitoring.

Any additional questions, send me an email.

  [string] $targetClassId = [Guid]::NewGuid().ToString('b'), # Note: replace with $MPElement$
  [string] $targetInstId = [Guid]::NewGuid().ToString('b'), # Note: replace with $Target/Id$

  [string] $computerName = ('{0}.{1}' -f (gwmi Win32_ComputerSystem).DnsHostName, (gwmi Win32_ComputerSystem).Domain)

$errorActionPreference = 'Stop'

# Note: if the caller does not supply the $targetClassId we assume 
#       it must be run from command line in a debug session. Note
#       that the parameter name is case-sensitive
# Note: PowerShell 2.0 does not have .Contains() method on [string[]] type
[bool] $fromCmd = -not ([Collections.ArrayList] $PSBoundParameters.Keys).Contains('targetClassId')

[__ComObject] $scom = New-Object -Com MOM.ScriptAPI
[__ComObject] $discoData = $scom.CreateDiscoveryData(0, $targetClassId, $targetInstId)

[bool] $ok = (-not [object]::Equals($scom, $null)) -and (-not [object]::Equals($discoData, $null))
if (-not $ok) { throw 'SEVECEK: An error occured during the very script initialization' }

function MSG (
    [string] $message,
    [ValidateRange(10001,19999)] [int] $id = 10001,
    [ValidateSet('info', 'warn', 'err')] [string] $type = 'info',
    [switch] $dbg
  [int] $evType = 0

  # Note: cannot use host's colors here because the script is not running
  #       with a console and the colors are $null in HealthService
  [string] $color = 'Yellow'

  switch ($type) {

    'info' { $evType = 0 ; $color = 'Yellow' }
    'warn' { $evType = 1 ; $color = 'Magenta' }
    'err' { $evType = 2 ; $color = 'Red' }

  if (-not $dbg) { $scom.LogScriptEvent('SEVECEK Script', $id, $evType, $message) }
  if ($fromCmd) { Write-Host ('{0,5}: {1,4}: {2}' -f $id, $type, $message) -Fore $color }

# Note: would not display if we are not running from cmd
MSG -dbg 'Running from cmd'


[Collections.ArrayList] $foundInstances = @()

try {

  for ($i = 1; $i -le 2; $i++) {

    [PSCustomObject] $newInstance = New-Object PSCustomObject
    Add-Member -Input $newInstance -MemberType NoteProperty -Name display -Value 'Sevecek test object 1'

    [void] $foundInstances.Add($newInstance)

} catch {

  $exp = $_.Exception
  [string] $expMsg = ''
  [string[]] $errorCodes = @()

  do {

    $expMsg = "{0}`r`n{1}" -f $expMsg, $exp.Message

    function ConvertTo-StringError($value)
       [string] $strValue = ''
       if (-not ([object]::Equals($value, $null))) {

          $strValue = '{0}' -f $value
          [string] $hexElement = ''
          try { $hexElement = '0x{0:X8}' -f $value } catch { }
          if ($hexElement -ne '') { $strValue = '{0} ({1})' -f $strValue, $hexElement }

       return $strValue.Trim()

    $errorCodes += ConvertTo-StringError $exp.HResult
    $errorCodes += ConvertTo-StringError $exp.ErrorCode
    $errorCodes += ConvertTo-StringError $exp.ErrorCode.value__

    $exp = $exp.InnerException

  } while (-not ([object]::Equals($exp, $null)))

  MSG ("SEVECEK: An error occured during script execution: {0}`r`nError codes: {1}" -f $expMsg, (($errorCodes | ? { $_ -ne '' }) -join ' | ')) 19999 err 
  $ok = $false

foreach ($oneFoundInstance in $foundInstances) {

  [__ComObject] $newInst = $discoData.CreateClassInstance('$MPElement[Name="Sevecek.Monitoring.SensitiveUser"]$')

  $newInst.AddProperty('$MPElement[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName$', $computerName)

  $newInst.AddProperty('$MPElement[Name="System!System.Entity"]/DisplayName$', $oneFoundInstance.display)
  $newInst.AddProperty('$MPElement[Name="Sevecek.Monitoring.Base"]/LastRunTime$', [DateTime]::Now)
  $newInst.AddProperty('$MPElement[Name="Sevecek.Monitoring.Base"]/ScriptError$', (-not $ok))



if ($fromCmd) {

  # Note: when running debug from command line we return the XML
  #       to take a look. The .Return() method does not have a return
  #       value, it writes the output XML into console (not stdout) directly
  Write-Host; MSG -dbg 'Finished.'

} else {

  # Note: when running from a module data source we return
  #       the pure object to be handled completelly by the caller
  return $discoData



There are no comments for this post.

Add Comment

Sorry comments are disable due to the constant load of spam *

This simple antispam field seems to work well. Just put here the number.


You do not need to provide any value this column. It will automatically fill with the name of the article itself.

Author *

Body *