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
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 ( http://blogs.msdn.com/b/tysonpaul/ )
# Date: 7/22/2014
#
# 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")
#NOTE: The 'here' string terminators < "@ > below must be completely left justified or a script error will occur upon execution of the script.
$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"] = "$($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