Operations Manager 2012 R2 UR2 Powershell Grid Widget Effective Monitoring Configuration Dashboard

Have you ever wanted to simply click a server object and see all of the effective rule and monitor configuration settings in one view?  Now you can.

NOTES:

  • This dashboard isn’t perfect. I’ve seen some weird behavior on occasion. Sometimes the top right widget will update with content from other widgets that exist in other views in other folders. Perhaps the Powershell runspace is sharing scope with other dashboards?.  Let me know if you find ways to improve it.
  • If you select ONLY one computer object (top left), expect to see the entire list of configurations for ALL contained subitems appear in the bottom widget.
    This may take a minute to enumerate so be patient. If you select more than one computer you will only see output for the first computer, not multiple computers. This is by design.
  • Select a subitem (top right) and ONLY the configuration for THAT item will appear in the bottom widget.
  • If you are not seeing results in the bottom pane, you may have to increase your “PollingInterval” (refresh rate) for your console to give it time to populate the results before re-running the scripts. See here: http://www.bictt.com/blogs/bictt.php/2011/06/01/scom-trick-20-increase-console

Manual Creation Process

1) Create a new Management Pack from the Administration tab. Title it appropriately, something like:  “My Dashboards”

2) Once you create the MP, a new folder will appear under your Monitoring tab. Add a new Grid Layout view to the folder.

New -> Dashboard View -> Microsoft -> Grid Layout

Name it “Effective Configuration”

Next.

3 Cells (two on top, one below)

Add the code to each widget:

Top left widget: Windows Computers

Top right widget: Contained Items
Bottom widget: Effective config

WidgetTitleCode Snippet
Top LeftGroup Members: “Windows Computers” 

 

 ##################################################################################################
# ListWindowsComputers
# Author: Tyson Paul ( http://blogs.msdn.com/b/tysonpaul/ )
# Date: 7/22/2014
#
$class = Get-SCOMClass -Name Microsoft.Windows.Computer
$computers = Get-SCOMClassInstance -Class $class
$i=1
foreach ($computer in $computers)
{
$dataObject = $ScriptContext.CreateFromObject($computer, "Id=Id,HealthState=HealthState,DisplayName=DisplayName", $null)
$dataObject["Index"]=$($i).ToString("00000")
$ScriptContext.ReturnCollection.Add($dataObject)
$i++
}
 Top Right Contained Items of Selected Object 

 

# ContainedItemsOfSelectedItem

Param($globalSelectedItems)
foreach ($globalSelectedItem in $globalSelectedItems)
{
If ( ($globalSelectedItem["Id"].Length -ge 4 ) ) # Prevent scripts from fighting each other
{
$globalSelectedItemInstance = Get-SCOMClassInstance -Id $globalSelectedItem["Id"]
foreach ($relatedItem in $globalSelectedItemInstance.GetRelatedMonitoringObjects() )
{
$dataObject = $ScriptContext.CreateFromObject($relatedItem, "Id=Id,State=HealthState,DisplayName=DisplayName", $null)
$dataObject["ParentRelatedObject"] = $globalSelectedItemInstance.DisplayName
$ScriptContext.ReturnCollection.Add($dataObject)
}
}
}
 Bottom Effective Configuration of Selected Object  (Please wait patiently. This may take a minute…)  

 

###################################################################################################
# EffectiveMonitoringConfiguration
# Author: Tyson Paul ( )
# Date: 1/14/2015
#
# Will recursively find contained instances on a Windows Computer and ouput the effective monitoring configurations/settings to individual output files
# Will merge all resulting files into one .csv file, delimited by pipes '|'
###################################################################################################
Param($globalSelectedItems)

New-Variable -Name StartupVariables -Force -Value (Get-Variable -Scope Global | Select -ExpandProperty Name)

########################################################################################################
Function LogIt ([int]$EventID, [int]$Type=2, [string]$Message="No message specified." , [int]$proceed) {

$TimeStamp = (get-date -format "yyyyMMddHHmmssfff")
$output = @"
Message: $Message

"@

If ($proceed -gt 1) {
$output += @"

ThisScript: EffectiveMonitoringConfiguration.ps1
TimeStamp: $TimeStamp

Any Errors: $error

"@

}

If ($proceed) {
$oEvent = New-Object -comObject "MOM.ScriptAPI"
$oEvent.LogScriptEvent("$ThisScript",$EventID,$Type,$output)
}

} #endregion Function
#####################################################################################################
# Function MergeFiles
# Will find .csv files and merge them together.
Function MergeFiles{
Param(
[string]$strTargetFolderPath
)

$strOutputFile = Join-Path $Env:TEMP "MergedFile.csv"
If (Test-Path $strOutputFile) { Remove-Item -Path $strOutputFile }
If (Test-Path $strOutputFile) {
$Message = "Cannot remove $strOutputFile and therefore cannot generate merged output file. Remove this file first: $strOutputFile , Exiting. "
LogIt -EventID 9999 -Message $Message -Type $Critical -Proceed $WriteToEventLog
Exit
}
If (!($strTargetFolderPath)){
$Message = "No input file folder path specified ! Exiting. "
LogIt -EventID 9999 -Message $Message -Type $Critical -Proceed $WriteToEventLog
Exit
}

Get-ChildItem -Filter "*.csv" -Path $strTargetFolderPath | ForEach {
$intThisHeaderLength = (Get-Content $_.FullName)[0].Length
If ($intThisHeaderLength -gt $intLongestHeaderLength) {
$objLongestHeaderFile = $_
$intLongestHeaderLength = $intThisHeaderLength
}
}
Get-Content $objLongestHeaderFile.FullName | Set-Content -Path $strOutputFile -Force
Get-ChildItem -Path $strTargetFolderPath -Filter *.csv | ForEach {
If( ( $_.FullName -eq $objLongestHeaderFile.FullName ) -or ($_.FullName -eq $strOutputFile) ){
#Skip File
}
Else {
(Get-Content $_.FullName | Select -Skip 1).Replace("`0",'') | Out-File -FilePath $strOutputFile -Append -Encoding UTF8
$i++
}
}

Return $strOutputFile

} # EndFunction
###################################################################################################
Function Cleanup () {
$ErrorActionPreference = "SilentlyContinue" #Depending on when this is called, some variables may not be initialized and clearing could throw benign error. Supress.
#Cleanup
Get-Variable | Where-Object { $StartupVariables -notcontains $_.Name } | % { Remove-Variable -Name "$($_.Name)" -Force -Scope 1 }
}
########################################################################################################

# --------------------------------------------------------------------------------------------------------------------------------------------------------
$WriteToEventLog=0 #Set to 1 or 2 to start logging
[int]$info=0
[int]$critical=1
[int]$warning=2

$TempOutputFolder= Join-Path $Env:Temp "EffectiveConfig_$(Get-Random)"
Get-ChildItem $Env:Temp -Filter "EffectiveConfig_*" | Remove-Item -Recurse

$i=1
If (!(Test-Path $TempOutputFolder)) { new-item -ItemType Directory -Path $TempOutputFolder}
If (!(Test-Path $TempOutputFolder)) {
LogIt -EventID 9999 -Message $Message -Type $Critical -Proceed $WriteToEventLog
Exit
}

#ForEach ($globalSelectedItem in $globalSelectedItems)
#{
$globalSelectedItem = $globalSelectedItems | Select -First 1
$globalSelectedItemInstance = Get-SCOMClassInstance -Id $globalSelectedItem["Id"]
If ($globalSelectedItemInstance.Fullname -like "Microsoft.Windows.Computer:*") {
$RelatedObjects = $globalSelectedItemInstance.GetRelatedMonitoringObjects()
}
Else {
$RelatedObjects = $globalSelectedItemInstance
}
$RelatedObjects | ForEach `
{
$DN = (($($_.DisplayName).Replace(':','_')).Replace('/','_')).Replace('\','_')
$path= (Join-Path $TempOutputFolder "($($_.Path))_$($DN).csv" )
Export-SCOMEffectiveMonitoringConfiguration -Instance $_ -Path $path
$i++
}
#}

$strMergedFilePath = MergeFiles -strTargetFolderPath $TempOutputFolder
$Headers = @()
$Headers= (Get-Content $strMergedFilePath | Select -First 1).Split('|')
$FileContents = (Get-Content $strMergedFilePath | Select -Skip 1 ).Replace("`0",'')
$r=1
ForEach ($Row in $FileContents) {
If ($Row.Length -le 1) { Continue; }
$c=0
$arrRow = @()
$arrRow = $Row.Split('|')
$dataObject = $ScriptContext.CreateInstance("xsd://foo!bar/baz")
$dataObject["Id"] = $r.ToString("0000")
$dataObject["Row"] = $r.ToString("0000")
ForEach ($Column in $Headers) {
If ( ($arrRow[$c] -eq '') -or ($arrRow[$c] -eq ' ') ) { $arrRow[$c] = 'N/A' }
$dataObject["$Column ($c)"] = "$($arrRow[$c])"
$c++
}
$r++
$ScriptContext.ReturnCollection.Add($dataObject)
}

LogIt -EventID 9998 -Message "Errors: $Error" -Type $Warning -Proceed $WriteToEventLog
Remove-Item $TempOutputFolder -Force -Recurse #Cleanup temp folder/files
Cleanup

Page History:

2015.1.14: Updated script (EffectiveMonitoringConfiguration) to make Column names unique

5 Replies to “Operations Manager 2012 R2 UR2 Powershell Grid Widget Effective Monitoring Configuration Dashboard”

  1. Hello Tyson,

    I have been trying for weeks to create a very similar SCOM custom dashboard view to display current CPU%, RAM%, Network%, C drive %, D drive % in one single view. SCOM has the limitation to display only the “Top 20” resource utilization but in my case I have more than 60+ server and all of them needs to be displayed. I was suggested that this could be possible using a PowerShell widget dashboard and I have done too many research to find a script which could help me based on my requirement but unfortunately could not find any blogs or post which is relevant to my need. Could you please help me out with a PowerShell script to meet my requirements?

    1. Are you talking about a single table with 60+ rows (one for each of the ~60 computers), each row would include a column for each of the metrics you listed?

      Like this:
      Name CPU% MEM_USED% ETH% C_Used% D_Used%
      Srv1 23 50 2 40 10
      Srv2 ….
      Srv60 ….

  2. Hi Tyson, Thank you for responding. Yes, that could be more useful if there is a possibility to get all the resources in one single table or having a separate grid created for each of the resources will also meet my requirement.

    1. Zid,
      What you are requesting is certainly possible and I have something that is really close, but not exactly what you want. I don’t have time to tweak it. Not this week anyway. Although this would potentially make a neat blog post.
      Don’t hold your breath for me though. I think you can do this on your own with a little help.

      I wrote a ‘Disk Helper’ management pack a long, long time ago that included a pretty cool PowerShell grid widget for disks. It contains a timed rule (PowerShell script) that would query the DW to harvest disk information, then write the disk stats to a CSV file. The dashboard (Posh grid widget) was very fast because it would pull data from the CSV file, which is very inexpensive. The only drawback is that because this was written so long ago it references the older OS MPs and classes (Server 2003, 2008, 2012/R2) so it won’t be suitable to import if you don’t have those older MPs. No big deal, you can cannibalize it to create your own timed rule then plug in the dashboard code into a grid widget.

      This is a really good example of how to build a fast PowerShell Grid Widget with lots of columns of data.
      Create timed rules to cache whatever data to a local file (in this case a simple CSV).
      Create a Posh grid widget to present the data. FAST.
      Windows Disk Stats MP Dashboard

      Windows Disk Helper

  3. Thanks for the suggestion. Will check the possibilities to create the dashboard with the references you have attached. But also it would be great if you can consider my request and create a new blog post. I am quite sure it would be of really great help for many to have such dashboards which could monitor all the major resources at one view.

Leave a Reply

Your email address will not be published. Required fields are marked *