PowerShell: Speeding up SCOM script

已答覆 PowerShell: Speeding up SCOM script

  • Tuesday, March 05, 2013 8:39 PM
     
      Has Code

    We've got SCOM 2007R2 and I'm working on a script to get the MM status of a list of servers. The script takes a long time to run and I wonder if anyone can see any way to optimize it. Here is the code:

    <# 
    .Synopsis
        Checks the Maintenance Mode history of a single server, or a group of servers.    
    .DESCRIPTION 
        When run, this script will check the Maintenance Mode history of either a user-provided, comma-separated list of servers or of the members of a user-provided SCOM group. When history data is available, the script returns the computer name, MM start time, MM end time, username, and comment
    .NOTES 
        Author: Mike
        V1 date: 5 Mar 13
    .PARAMETER RootMS
        This parameter is be the SCOM root management server. The default value is "rms01"
    .PARAMETER GroupName
    	This parameter is the SCOM group for which to gather history data.
    .PARAMETER ComputerNames
        This parameter can be a single computer name, or a comma-separated list of computer names
    .PARAMETER SearchType
        This parameter specifies whether the script should search for a group or single computers. Valid selections are "Computer" and "Group". The default value is "Computer".
    .EXAMPLE
        .\getSCOMMaintenanceMode-Parameterized.ps1 -SearchType Group -GroupName "Group1"
        This example gets the Maintenance Mode history for each computer in the "Group1" group.
    .EXAMPLE
        .\getSCOMMaintenanceMode-Parameterized.ps1 -SearchType Computer -ComputerNames server1,server2
        This exmaple gets the Maintenance Mode history for the computers server2 and server1
    #>
    [CmdletBinding()]           
    param(
        [string]$RootMS = "rms01",
        
        [string]$GroupName,
        
        [array]$ComputerNames,
        
        [ValidateSet("Computer","Group")]
        [string]$SearchType = "Computer"
    )            
    
    #Initialize variables
    $SCOMSnapinLoaded = $False
    $SCOMSnapin = "Microsoft.EnterpriseManagement.OperationsManager.Client"
    
    #Load snapins, then test for success
    Add-PSSnapin $SCOMSnapin –ErrorAction SilentlyContinue
    If ((Get-PSSnapin $SCOMSnapin -ErrorAction SilentlyContinue) –eq $null) {
    	# If snapin is not loaded, notify user with required details
    	Write-Host
    	Write-Host "This script requires the SCOM snapin: $SCOMSnapin. Please make sure you've got the correct tools installed." -ForegroundColor Red
        Break
    }
    Else{
    	# If it did load, Flag Status as "good"
    	$SCOMSnapinLoaded=$True
    }
    
    New-ManagementGroupConnection -ConnectionString:$RootMS | Out-Null            
    Push-Location -Path "OperationsManagerMonitoring::" -ErrorAction Stop
    
    If ($SCOMSnapinLoaded) { #If the SCOM snapin is loaded...
        If ($SearchType -eq "Group") {
            #Get references to the Group, Windows Computer, Health Service, and Health Service watcher classes
            $instanceGroupClass = Get-MonitoringClass -Name:System.Group
            $windowsComputerClass = Get-MonitoringClass -Name:Microsoft.Windows.Computer
    
            #Get a reference to the PrincipalName property as this will be needed soon
            $principalNameProp = Get-MonitoringClassProperty -monitoringClass:$windowsComputerClass | where {$_.Name -eq 'PrincipalName'}
    
            #Find the user-specified group
            $groupInstance = (Get-ManagementGroupConnection).ManagementGroup.GetPartialMonitoringObjects($instanceGroupClass) | where {$_.DisplayName -eq $GroupName}
    
            #Retrieve all the computers contained in the group. This will return both agent as well as agentless managed computers
            $ComputerNames = $groupInstance.GetRelatedMonitoringObjects($windowsComputerClass,[Microsoft.EnterpriseManagement.Common.TraversalDepth]::OneLevel)
        }
        
        Foreach ($computer in $ComputerNames) {      
            #This is here for debugging: Write-Host "Gathering data for"$computer
            $agent = Get-Agent | Where-Object {$_.displayname -match $computer}            
            $maintenanceObj = Get-MaintenanceWindow -MonitoringObject $agent.HostComputer -History -ErrorAction 0            
            
            If($maintenanceObj) {            
                $output = New-Object -Type PSObject -Property @{
                    ComputerName = $computer   
                    StartTime  = ($maintenanceObj.Starttime).tolocaltime()            
                    EndTime   = ($maintenanceObj.ScheduledEndTime).Tolocaltime()            
                    Username  = $maintenanceObj.User            
                    Comment   = $maintenanceObj.Comments            
                }            
        
                $output | select ComputerName, StartTime, EndTime, Username, Comment | ft -wrap
            }
            Else {
                Write-Host "No Maintenance Mode history data is available for $computer." -Foreground Yellow
                #This is here for debugging: Write-Error "Unable to get the status of $computer."
            }                       
        }
    }
    Pop-Location

    Thanks.

All Replies

  • Tuesday, March 05, 2013 9:49 PM
     
     Answered

    Implement detailed loggin with timestamps to find out what is taking. time.  COmputers that do not respond will take 60 seconds or longer to fail.  If you are scanning many systems this could take a very long time.


    ¯\_(ツ)_/¯

  • Wednesday, March 06, 2013 2:24 PM
     
     Answered Has Code

    Here's what I do when connecting to a number of remote computers:

    All I added to your code was a test-connection at the beginning and a little block at the end to let you know it was offline.

    Foreach ($computer in $ComputerNames) {   
        If (Test-Connection $computer -Count 2 -Quiet) 
            {  
            #This is here for debugging: Write-Host "Gathering data for"$computer
            $agent = Get-Agent | Where-Object {$_.displayname -match $computer}            
            $maintenanceObj = Get-MaintenanceWindow -MonitoringObject $agent.HostComputer -History -ErrorAction 0            
            
            If($maintenanceObj) {            
                $output = New-Object -Type PSObject -Property @{
                    ComputerName = $computer   
                    StartTime  = ($maintenanceObj.Starttime).tolocaltime()            
                    EndTime   = ($maintenanceObj.ScheduledEndTime).Tolocaltime()            
                    Username  = $maintenanceObj.User            
                    Comment   = $maintenanceObj.Comments            
                }            
        
                $output | select ComputerName, StartTime, EndTime, Username, Comment | ft -wrap
            }
            Else {
                Write-Host "No Maintenance Mode history data is available for $computer." -Foreground Yellow
                #This is here for debugging: Write-Error "Unable to get the status of $computer."
            }
            }
        Else {"$Computer is not online"}