Showing posts with label Monitoring. Show all posts
Showing posts with label Monitoring. Show all posts

Friday, September 20, 2024

SCOM Maintenance Mode using Hashtable

Hi All,

In this post, we'll explore one of the most frequently used features in SCOM—placing servers into Maintenance Mode. As a SCOM admin, you've likely performed this task countless times, either via the SCOM Console or by using PowerShell scripts.

While the SCOM Console offers a simple way to put a server into Maintenance Mode, it has a limitation when dealing with multiple servers, as there's no built-in feature for bulk maintenance mode operations.

To address this, many turn to PowerShell scripts. However, if you've tried this approach, you may have noticed it works well for smaller numbers, like 10 or 20 servers. But what happens when you need to place 500 servers into Maintenance Mode?

Running the command Get-ScomClass | ?{$_.Name -eq 'Microsoft.Windows.Computer'} | Get-ScomClassInstance | ?{$_.DisplayName -eq 'ServerName'} for each of the 500 servers can be extremely time-consuming and may not even succeed as expected.

Fortunately, this challenge can be solved by using Hashtables in PowerShell. In the script below, we create a Hashtable of all WindowsComputer class instances and then efficiently match our list of servers against it, placing each one into Maintenance Mode.

This might not be the only solution to place bulk servers into Maintenance Mode, however it is one of the few solutions which I have been using and found to be pretty reliable with very less hassle.

Please check the Script Below.



#======== Script for Bulk Maintenance Mode ==============#
# Script Created By: Apoorv Katiyar
# Description: This script places multiple servers into maintenance mode in SCOM.
# The list of servers is read from a text file, and the user can specify the duration of maintenance mode.
#============== Starting Script =========================#

# Read the list of servers from the text file
[array]$File = Get-Content -Path "C:\path\ServerList.txt"
$StartTime = Get-Date
Write-Host "Initializing Script"
Write-Host "Please Ensure that FQDN (Fully Qualified Domain Name) are used to place servers into Maintenance Mode"
# Prompt user to proceed
$Input = Read-Host "Press.......1 to Continue"
# Check if the user input is 1
if ($Input -eq "1") {
    
    # Check if the file is not empty
    if (!($File)) {
        Write-Host "File is Empty"
        EXIT
    } else {
        # Get the number of servers in the list
        $Count = $File.count
        Write-Host "Found $Count Servers to be placed into Maintenance Mode"
        # Ask the user for the maintenance mode duration and comments
        $ETime = Read-Host "Please enter the time in minutes for which the servers need to be placed into Maintenance Mode."
        $Comment = Read-Host "Please enter Comments for Maintenance Mode"
        $Message = $Comment
        # Calculate the end time for maintenance mode
        $SCOMMMEND = (Get-Date).AddMinutes($ETime)
        # Retrieve all Windows Computer objects in SCOM
        [array]$WindowsObj = Get-SCOMClass -Name "Microsoft.Windows.Computer" | Get-SCOMClassInstance
        
        # Check if the Windows Computer objects were retrieved successfully
        if (!($WindowsObj)) {
            Write-Host "Status:"
            Write-Host "Unable to fetch all Windows Computer Objects"
        } else {
            $WindowsObjCount = $WindowsObj.count
            Write-Host `n"Found ($WindowsObjCount) Windows Computer objects in the Management Group"
            
            # Create a hash table to store the SCOM instances
            $HashTable = @{}
            foreach ($Object in $WindowsObj) {
                $HashTable.Add("$($Object.DisplayName)", $Object)
            }
            Write-Output "Starting Maintenance Mode Script"
            # Loop through each server in the file
            foreach ($Server in $File) {
                $Instance = $HashTable.($Server)
                
                # Check if the server exists in SCOM
                if (!($Instance)) {
                    Write-Host `n"Warning: $Server was not found as a Windows Computer object in SCOM. Skipping..."`n
                    $DeletedServer += $Server
                } else {
                    $SName = $Instance.DisplayName.ToString()
                    
                    # Check if the server is already in maintenance mode
                    if ($Instance.InMaintenanceMode) {
                        Write-Host "Status: "
                        Write-Host "$SName is already in Maintenance Mode"
                    } else {
                        try {
                            # Start maintenance mode for the server
                            Start-SCOMMaintenanceMode -Instance $SName -EndTime $SCOMMMEND -Comment $Message
                            Write-Host "Status: "
                            Write-Host "Enabled Maintenance Mode for $Instance till $SCOMMMEND (Pacific Time)"
                        } catch {
                            # Handle any errors
                            $ErrorMessage = $_.Exception.Message
                            Write-Host $ErrorMessage
                            Write-Host "Status: "
                            Write-Host "$ErrorMessage"
                        }
                    }
                }
            }
        }
    }
}

#======== End Of Script ==============#

Sunday, September 15, 2024

Export Monitors and Rules from SCOM Notification Subscription.

 

Recently I got into a requirement to fetch a list of all Rules and Monitors that are part of a SCOM Notification Subscriptions or all Subscriptions.

This task would usually be not possible from the SCOM UI Console but can be easily achieved using some PowerShell.

Here is the Script.

$SubScriptionName = (Get-SCOMNotificationSubscription |?{$_.Enabled -eq "True"}|Select DisplayName -expandproperty DisplayName)

$ArrayOut = @()

Foreach($SubScription in $SubscriptionName)

{

Write-host "$Subscription"

$Id = ((Get-SCOMNotificationSubscription -DisplayName $SubScription).Configuration).Criteria|Select-XML -XPath "//Value"|ForEach-Object {$_.Node.InnerXML}

#Write-host "$Id"

$Output = @(foreach($RuleId in $Id)

{

if($RuleID -match "\S{8}\W\S{4}\W\S{4}\W\S{4}\W\S{12}")

{


$MonitoringObject = Get-ScomRule -Id $RuleId

#Get-ScomMonitor -Id $RuleId | Select DisplayName,XMLTag

if($MonitoringObject)

{

$MonitoringObject|Select-Object @{n='MetricName';e={$MonitoringObject.DisplayName}},@{n='Type';e={$MonitoringObject.XMLTag}},@{n='SubscriptionName'; e={$SubScription}}

}

elseif((Get-SCOMMonitor -Id $RuleId) -ne $NULL)

{

$MonitoringObject = Get-SCOMMonitor -Id $RuleId

$MonitoringObject|Select-Object @{n='MetricName';e={$MonitoringObject.DisplayName}},@{n='Type';e={$MonitoringObject.XMLTag}},@{n='SubscriptionName'; e={$SubScription}}

}

else 

{

$MonitoringObject = "NotFound"

$MonitoringObject|Select-Object @{n='MetricName';e={"No Value"}},@{n='Type';e={"No Value"}},@{n='SubscriptionName'; e={$SubScription}}

}


}

})

Clear-Variable -Name "MonitoringObject"

$ArrayOut+= $Output 

}

$ArrayOut|Export-Csv -path "C:\Temp\FileName.csv"


Here is the breakup of the Script.

  • The first line is the standard SCOM commandlet to fetch list of all SCOM Subscriptions which are enabled
  • Next, we just create an array to store the output.
  • Now we iterate over each subscription using a for loop.
  • Now this is where the things get interesting, we call the configuration method for the subscription in the iteration which gives the XML output for the Subscription configuration as below.
  • (Get-SCOMNotificationSubscription -DisplayName $SubScription).Configuration).Criteria|Select-XML -XPath "//Value"|ForEach-Object {$_.Node.InnerXML}

  • At first the output is not very understandable as it a fragment from the notification Management Pack, where Rules and Monitors are listed with their ID's rather than names.
  • Now we fetch the ID's from the Inner XML and use the basic SCOM Commandlets to get the Rule or the Monitor Name.
  • Please note it could be possible you might have other Instances like Web URL Monitor which this script might not return, but you can single that subscription out and use the Get-SCOMClassInstance command against the ID's
  • We use Regex \S{8}\W\S{4}\W\S{4}\W\S{4}\W\S{12} to get the ID's and fetch the Monitor \ Rule Name.
  • Later the Output is exported to a CSV File and there you have it all Rules and Monitors that are part of the notification subscription.

There might be other ways to fetch this data out, this is one of the solution, I use to get the data out quicky and not much hassle.

Friday, September 13, 2024

Targeting Rules\Monitor to Groups based other Groups

 In SCOM usually we have a lot of requirements to create a windows computer groups of various application or custom applications like SQL, Clusters, SharePoint servers to perform actions like Maintenance Mode, Notification or Dashboards for state or performance view or might create a custom monitoring configuration like enabling Service or Process to servers that belong to this application.

Now achieving this feat from console is not easy or might I say is not possible, but can be done with a very little XML magic.

Let's look at one such scenario.

  1. Create a group of Windows computers objects that host Windows Server 2016 and 1709+ Monitoring Cluster Service.
    • To achieve this create a New normal windows computer group give it a dynamic condition like below and save it in a New Management Pack, it doesn't matter what condition you give as it will be replaced later.


    • Now export this management pack and open it in a text editor.
    • The next step would be to find the Group discovery rule for the one that we just created and make some changes to it. This is how the Group discovery rule would look like.

    • If we take a look at the rule it states that Principal name = Test, how about if we change this to Windows Computer class contained in Cluster Application, might sound wired let's try it.
    • Remove the entire code in the Simple Expression.

    • And the following lines of code.
    • This is just essentially telling it to create a group of windows computer which Contains Cluster Class, the word Contains is very important here. There meaning an usage is something I will be sharing in next blog.


    • Now before saving this MP , you need to ensure that proper referencing is made to the cluster class as it is a part of a Sealed Management Pack, if you are using any other class which is not a part of a Sealed management pack this MP shall be created in the same management pack as of the referred class.
    • To do to referencing go to the Manifest section of the Management Pack and add the required alias as below.

    • If you have trouble finding the Alias of a sealed MP, locate the MP's Management Pack for example here are using the class Windows Server 2016 and 1709+ Monitoring Cluster Service, Locate the MP that contains this Class export it using the SCOM Powershell commandlets.
Get-SCOMManagementPack|?{$_.Name -eq 'Microsoft.Windows.2016.Cluster.Management.Monitoring'}|Export-SCOMManagementPack -Path "C:\temp"
    • Go to the path where the Management Pack is exported open it and copy the alias from there to your New Management Pack.
    • Now the change the version of your New Management Pack, say from 1.0.0.0 to 1.0.0.1 and save it.
    • Now Import this MP from the MP Wizard.
    • Go to authoring locate the New Group that we created and voila you would see computer objects populating the group in some time.
Now you can use this same method to create groups of not just windows computer but also other object like Health Service watcher or any other object.

In my next post we will be creating a group of Health Service Watcher objects that would be based on a Custom Windows Computer Group.