Showing posts with label PowerShell. Show all posts
Showing posts with label PowerShell. Show all posts

Saturday, October 5, 2024

SCOM Service Monitoring using WildCard

 

A while back I got a request from one of my Application Team to monitor multiple services on a set of servers. Usually the standard way of completing this request would be to create a group of servers on which the service is monitoring and create individual service monitor for each service, however this request was a little unique.

All the services that were given me to monitor had a similar prefix "Hyper-V" and then the service name for eg "Hyper-VService1", "Hyper-VService2" etc.


Hence, I thought if there is way to monitor multiple services using  WildCard which would greatly reduce the time to create the monitoring configuration and SCOM Admins their time back.


Let's dive right into it.

  • The First step would be same as always create a group of servers for which monitoring needs to be enabled.
  • If you already have a group where these services needs to be monitored create the service in the same Management Pack.
  • For this blog I will be creating a New Group and saving the config in a New Management Pack.
                                                      
  • Add the servers explicitly or dynamically as per your requirement and save the group.
  • Now create a test service that needs to be monitored on this server, you may use any service as we will be changing the config from the Management Pack. I am using Spooler.
                                                                            


  • Now comes the fun part. Open Wbemtest on one of the server where service needs to be monitored.
  • Connect to root\cimv2 and Select Query.
                                                            
  • Write the following Query "select * from win32_service where (DisplayName like '%Hyper-V%')"
  • This query will return the list of services Running with DisplayName Hyper-V.
                                                                                


  • What we did here is used WildCard to identify list of services that are running with the DisplayName Hyper-V and the same will be applied in our Management Pack.

MP Authoring Section.

  • Now to the MP Part to SCOM Administration > Management Packs > Select the Management pack where the service monitor was created > Export Management Pack.
  • Open the Management Pack in any editor for your choice and look for the following highlighted section.
=========================================================================  
  <Discoveries>
      <Discovery ID="UINameSpacea93b21e7cf554ddd91465e5f8d7a93fc.Group.DiscoveryRule" Enabled="true" Target="UINameSpacea93b21e7cf554ddd91465e5f8d7a93fc.Group" ConfirmDelivery="false" Remotable="true" Priority="Normal">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryRelationship TypeID="MicrosoftSystemCenterInstanceGroupLibrary7585010!Microsoft.SystemCenter.InstanceGroupContainsEntities" />
        </DiscoveryTypes>
        <DataSource ID="GroupPopulationDataSource" TypeID="SystemCenter!Microsoft.SystemCenter.GroupPopulator">
          <RuleId>$MPElement$</RuleId>
          <GroupInstanceId>$MPElement[Name="UINameSpacea93b21e7cf554ddd91465e5f8d7a93fc.Group"]$</GroupInstanceId>
          <MembershipRules>
            <MembershipRule>
              <MonitoringClass>$MPElement[Name="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Server.Computer"]$</MonitoringClass>
              <RelationshipClass>$MPElement[Name="MicrosoftSystemCenterInstanceGroupLibrary7585010!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$</RelationshipClass>
              <IncludeList>
                <MonitoringObjectId>09057974-5012-07b5-54a5-89183a595c8e</MonitoringObjectId>
              </IncludeList>
            </MembershipRule>
          </MembershipRules>
        </DataSource>
      </Discovery>
      <Discovery ID="ServiceStateProbePage_fcd1ed2a65c844d1bd0f7537a7919737.DiscoveryRule" Enabled="false" Target="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Computer" ConfirmDelivery="false" Remotable="true" Priority="Normal">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryClass TypeID="ServiceStateProbePage_fcd1ed2a65c844d1bd0f7537a7919737" />
        </DiscoveryTypes>
        <DataSource ID="DS" TypeID="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Win32ServiceInformationProviderWithClassSnapshotDataMapper">
          <ComputerName>$Target/Property[Type="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Computer"]/NetworkName$</ComputerName>
          <ServiceName>Spooler</ServiceName>
          <Frequency>60</Frequency>
          <ClassId>$MPElement[Name="ServiceStateProbePage_fcd1ed2a65c844d1bd0f7537a7919737"]$</ClassId>
          <InstanceSettings>
            <Settings>
              <Setting>
                <Name>$MPElement[Name="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Computer"]/PrincipalName$</Name>
                <Value>$Target/Property[Type="MicrosoftWindowsLibrary7585010!Microsoft.Windows.Computer"]/PrincipalName$</Value>
              </Setting>
              <Setting>
                <Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/ServiceName$</Name>
                <Value>$Data/Property[@Name='Name']$</Value>
              </Setting>
              <Setting>
                <Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/ServiceProcessName$</Name>
                <Value>$Data/Property[@Name='BinaryPathName']$</Value>
              </Setting>
              <Setting>
                <Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/DisplayName$</Name>
                <Value>$Data/Property[@Name='DisplayName']$</Value>
              </Setting>
              <Setting>
                <Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/Description$</Name>
                <Value>$Data/Property[@Name='Description']$</Value>
              </Setting>
              <Setting>
                <Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name>
                <Value>SCOM Wildcard Service</Value>
              </Setting>
            </Settings>
          </InstanceSettings>
        </DataSource>
      </Discovery>
    </Discoveries>

=========================================================================

  • Now update the first section highlighted in Yellow.

        <DataSource ID="DS" TypeID="MicrosoftWindowsLibrary7585010!Microsoft.Windows.WmiProviderWithClassSnapshotDataMapper">

          <NameSpace>root\cimv2</NameSpace>

          <Query>select * from win32_service where (DisplayName like '%Hyper-V%')</Query>

          <Frequency>60</Frequency>

          <ClassId>$MPElement[Name="ServiceStateProbePage_fcd1ed2a65c844d1bd0f7537a7919737"]$</ClassId>

  • Change ComputerName to NameSpace and Frequency to Query.
  • Now change the Purple highlighted section from BinaryPathName to PathName
  • Next update the Green Highligted Section to the following value - $Data/Property[@Name=’Name’]$
  • Now save the updates and change the Management Pack Version to an updated version from 1.0.0.0 to 1.0.0.1.
                                                            
  • Import the updated Management Pack.
  • Now move to Discovered inventory and you would start seeing the Hyper-V Services coming up.
                            


  • This way with just one monitor we are monitoring a set of services, AMAZING AIN'T IT.
  • You might see sometime before the config is applied and monitors are populated.


Please let me know your thoughts over this blog.




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.