Balance SCOM servers with SMA

So after I’ve written the first Balance Runbook I felt that I was on a roll so I wrote another. This one is used to balance SCOM management servers.

The runbook is based on this script by Tao Yang : Link to script

So in this case I thought that it would be nice to use the Operations Manager Connection asset in SMA so I created one with my SCOM server name and the SCOM Action Account.

SMA_ConnectionBalanceSCOM

So for the runbook I created two parameters, one for the name of the connection asset and another for a SCOM Resource Pool.

So why a Resource Pool?
If you have a big environment and have dedicated management servers for network monitoring you do not want to get server agents assigned to them.
The SCOM Resource Pool parameter is optional, so if you want to get all your servers balanced just run without the Resource Pool parameter.

So here is the runbook:

Link to the script at the bottom of the post

###################################################################
#    Writen by Mattias Lehmus, TrueSec
#    Twitter: @onelehmus
#    Blog: onelehmus.com
#
#    Original Script: http://blog.tyang.org/2010/08/11/balancing-number-of-scom-agent-per-management-server-using-powershell/
#
#    THIS CODE IS PROVIDED *AS IS*
###################################################################

workflow Maintenance-SCOM-BalanceServers
{
Param(
[Parameter(Mandatory=$true)]
[string]$SCOMConnectionAssetName,[Parameter(Mandatory=$false)]
[string]$SCOMResourcePoolName
)
# Connection to access SCOM server
$SCOMConnection = Get-AutomationConnection -Name “$SCOMConnectionAssetName”
$SCOMServerName = $SCOMConnection.ComputerName

#Create PS Credentials
$SecurePassword = ConvertTo-SecureString -AsPlainText -String $SCOMConnection.Password -Force
$SCOMCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList  $SCOMConnection.Username, $SecurePassword

InlineScript{
#Import OperationsManager module
Import-Module Operationsmanager

#Load Functions
Function Get-FailoverMS ($PrimaryMS){
$FailOverMSs = $SCOMManagmentServers
$FailOverMSs = $FailOverMSs | ?{$_.Name -ne $PrimaryMS}
Return $FailOverMSs
}

#Get Variables
$SCOMManagementGroup = Get-SCOMManagementGroup -ComputerName $Using:SCOMServerName
$SCOMRMSEmulator = Get-SCOMRMSEmulator -ComputerName $Using:SCOMServerName
$SCOMRMSEmulatorDisplayName = $SCOMRMSEmulator.DisplayName

Write-Output “Balancing SCOM Management Group $SCOMManagementGroup on RMS server $SCOMRMSEmulatorDisplayName”

#Get SCOM Managmentservers
IF($Using:SCOMResourcePoolName -ne $null){
$SCOMManagmentServers = @()
$SCOMManagmentServersNoGroup = Get-SCOMManagementServer -ComputerName $SCOMRMSEmulatorDisplayName
ForEach($SCOMManagmentServerNoGroup in $SCOMManagmentServersNoGroup){
$MemberOfGroup = Get-SCOMResourcePool -Member $SCOMManagmentServerNoGroup | Where-Object{$_.DisplayName -eq $Using:SCOMResourcePoolName}
IF($MemberOfGroup -ne $null){
$SCOMManagmentServers += $SCOMManagmentServerNoGroup
}
}
}
Else{
$SCOMManagmentServers = Get-SCOMManagementServer -ComputerName $SCOMRMSEmulatorDisplayName
}Write-Output “The following managment servers will be balanced” $SCOMManagmentServers.DisplayName

#Get SCOM Agents
$SCOMAgents = @()
ForEach($SCOMManagmentServer in $SCOMManagmentServers){
$SCOMAgents += Get-SCOMAgent -ManagementServer $SCOMManagmentServer
}
$NumberOfSCOMAgents = $SCOMAgents.count

Write-Output “There are $NumberOfSCOMAgents agents in Management Group $SCOMManagementGroup”

#Calculate how many agents eache server should have
$AveragePerMS = [System.Math]::Round($NumberOfSCOMAgents / $SCOMManagmentServers.count)
Write-Output “In average, approx. $AveragePerMS agents should be assigned to each Management server”

#Get how Managment Servers should be balanced
$SCOMMSLowerThanAverage = New-Object System.Collections.ArrayList
$SCOMMSHigherThanAverage = New-Object System.Collections.ArrayList
Foreach ($SCOMManagmentServer in $SCOMManagmentServers){
$SCOMAgentCount = (Get-SCOMAgent -ManagementServer $SCOMManagmentServer ).count
if($SCOMAgentCount -lt ($AveragePerMS -1)){
$SCOMMSLowerThanAverage.add($SCOMManagmentServer) | Out-Null
}
elseif($SCOMAgentCount -gt ($AveragePerMS +1)){
$SCOMMSHigherThanAverage.add($SCOMManagmentServer) | Out-Null
}
}
Write-Output “Hosts with higer than avrage number of agents:” $SCOMMSHigherThanAverage.DisplayName
Write-Output “Hosts with lower than avrage number of agents:” $SCOMMSLowerThanAverage.DisplayName

#Balance SCOM Servers

#adding SCOM PSSnapin
if((Get-PSSnapin | where-Object { $_.Name -eq ‘Microsoft.EnterpriseManagement.OperationsManager.Client’ }) -eq $null){
Add-PSSnapin Microsoft.EnterpriseManagement.OperationsManager.Client -ErrorAction SilentlyContinue -ErrorVariable Err
}
if((Get-PSDrive | where-Object { $_.Name -eq ‘Monitoring’ }) -eq $null){
New-PSDrive -Name:Monitoring -PSProvider:OperationsManagerMonitoring -Root:\ -ErrorAction SilentlyContinue -ErrorVariable Err | Out-Null
}

#Connect to RMS
Set-Location “OperationsManagerMonitoring::”
new-managementGroupConnection -ConnectionString:$SCOMRMSEmulatorDisplayName | Out-Null
Set-Location Monitoring:\$SCOMRMSEmulatorDisplayName#Balance
Foreach ($SCOMManagmentServer in $SCOMMSHigherThanAverage){
$iDifference = (Get-SCOMAgent -ManagementServer $SCOMManagmentServer).count – ($AveragePerMS +1)
$Temp = @()
$Temp += Get-SCOMAgent -ManagementServer $SCOMManagmentServer
For ($i=0; $i -lt $iDifference; $i++){
$TargetMS = Get-Random -InputObject $SCOMMSLowerThanAverage
$FailOverMSs = Get-failoverMS $TargetMS
$AgentName = $Temp[$i].Name
$FailOverMS = $null
Foreach($SCOMManagmentServer in $FailOverMSs){
$FailOverMS = $FailOverMS + $SCOMManagmentServer.name + ‘; ‘}
Set-ManagementServer -AgentManagedComputer $Temp[$i] -PrimaryManagementServer $TargetMS -FailoverServer $FailOverMSs | Out-Null
if(!(($TargetMS | Get-Agent).count -lt ($AveragePerMS -1))) {$SCOMMSLowerThanAverage.Remove($TargetMS)}
Remove-Variable FailOverMSs
}
For($i = $iDifference; $i -le ($Temp.count -1); $i ++){
$FailOverMSs = Get-failoverMS $SCOMManagmentServer
$AgentName = $Temp[$i].Name
$TargetMS = $TargetMS.Name
$FailOverMS = $null
Foreach ($SCOMManagmentServer in $FailOverMSs){ $FailOverMS = $FailOverMS + $SCOMManagmentServer.name + ‘; ‘}
Set-ManagementServer -AgentManagedComputer $Temp[$i] -PrimaryManagementServer $SCOMManagmentServer -FailoverServer $FailOverMSs | Out-Null
}
Remove-Variable Temp
}
Write-Output “Management Group $SCOMManagementGroup is now balanced”
}-PSComputerName $SCOMServerName -PSCredential $SCOMCredential
}

So when you run this script you get an output that looks like this:

SMA_DashboardBalanceSCOM

This can then be configured to run on a schedule so that you have a balanced SCOM environment.

Script can be downloaded here: http://1drv.ms/1jx6pAX

//Mattias
The scripts in the blog post are AS IS, test before using in production
This entry was posted in Operations Manager and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s