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

 

Enjoy!  Download MP Here: My.Dashboards.xml

 

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:

Finish.

 

 

 
Widget Title Code Snippet
Top Left Group 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

 

 

 

 

 

 


Comments (5)

  1. RichardLeos says:

    Hi Tyson,

    This Rick from UC Davis from the other day, looks like I found your blog. This is a very great dashboard it really going to help our admins. To note I manually created dashboard with your code. The bottom cell for "Effective Monitoring Configuration" gave and error. It looks like the lines 17, 20 23 and 30 have a incorrect terminator. Below is the correction I used for those lines which got it to work.

    Thanks!

    Rick

    ########################################################################################################

    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

    @"

    }

  2. Tyson.Paul says:

    Hi Rick,

    .  Glad you like it. The error you experienced is most likely the result of a copy/paste anomaly. The "here" string terminator

    "@

    must be completely left justified in order to work; no preceding spaces, tabs or otherwise. If you open the MP and find that code section you may not be able to see what I mean because the dashboard coded sections are stored / formatted kindof wonky.

  3. Christian Haugan says:

    Hi Paul!

    Thanks for the dashboard!

    I see that you have an error in your script for the lower window:

    $dataObject["$Column"] = "$($arrRow[$c])"

    The dataObject must be an unique name. At the end of the csv-data, the headers "Parameter Name|Default Value|Effective Value" repeats itself and therefore overwrites the data into the same columns and you only get the data from the last column.

    I easily and dirty solved it by adding the $c counter to the column name:  

    $dataObject["$Column ($c)"] = "$($arrRow[$c])"

    We found this out because we wanted the info in the last columns (the override data) and we saw that maaaaany columns was missing.

  4. Tyson.Paul says:

    Excellent!  Thanks, Christian!  I've updated the script and code sample snippet above.

  5. Stelian Postea says:

    Great idea!!

    Just to complement and make things a bit better try using Powershell Grid Widget (Filtered) instead of just Powershell Grid Widget; you will enjoy the search filter…

    Powershell Grid Widget (Filtered) is provided by gallery.technet.microsoft.com/Powershell-Grid-Widget-919dc3d6.