Monthly Archives: September 2012

Bug Fixes for SCOM Enhanced Email Notification Script V2

Written by Tao Yang

Since I released the version 2 of the SCOM Enhanced Email Notification Script last month, I’ve been made aware there are few bugs in the script.

First of all, apologies for not responding to these bugs sooner. I’ve been extremely busy at work and went away for a week attending Australia TechEd in Gold Coast. On top of all work related stuff, my 3-months old daughter occupies most of my spare time…

So, here are the 2 bugs that people in the community has found so far:

  1. agent name is not displayed in the email subject
    • This is a bug in the script, the script has now been updated.
  2. web console link in the email is displayed incorrectly (http://blogs.msdn.com/b/steverac/archive/2008/10/19/opsmgr-2007-command-line-notifications-and-alert-id.aspx)
    • Looks like it’s a known issue. The command channel needs to be updated.

Thanks for Jon Tiffin and François LEFEBVRE for not only identified the bugs but also provided the fixes before I even had time to take a look.

The first bug is in the script itself and the second bug is related to the command line parameter for the command channel setup. I have updated the script and the command channel setup instruction. the updated package can be found here.

As always, if you’ve found any other issues, please let me know either via email or leave comments in my blog posts.

PowerShell Script To Enable SCOM Agent Proxy in a More Efficient Way

Written by Tao Yang

if you search on how to enable SCOM agent proxy for all your SCOM agents using PowerShell, you’ll get lots of posts and scripts that shows you how to do it in SCOM 2007 or 2012. In fact, I have written few back in the days.

However, no matter if the script uses SCOM 2007 PowerShell Snap-in, or SCOM 2012 PowerShell module, or even SCOM SDK, there is one limitation: the “ProxyingEnabled” property of the agent class is not one of the search criteria that you can use when retrieving the agent:

image

If you use the SCOM SDK, there are only 4 property names that can be used in the search criteria expression:

  • Id
  • Name
  • LastModified
  • DisplayName

ref: http://msdn.microsoft.com/en-us/library/microsoft.enterprisemanagement.administration.agentmanagedcomputercriteria.aspx

So in order to retrieve the agents that are not ProxyingEnabled, we can only client-side filtering, which retrieves ALL agents in the management group and then filter-out the ones that ProxyingEnabled is set to False.

i.e.

Using SCOM 2007 PowerShell Snap-in:

Get-agent | where-object {$_.ProxyingEnabled -match "false"}| foreach {$_.ProxyingEnabled = $true; $_.applyChanges()}

Using SCOM 2012 PowerShell Module:

Get-SCOMAgent | where-object {$_.ProxyingEnabled –match “false”} | Enable-SCOMAgentProxy

Using SCOM SDK in PowerShell:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager") | Out-Null

$RMS = “RMS SERVER NAME”

$MGConnSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings(RMS )
$MG = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MGConnSetting)

#Get MG Admin
$Admin = $MG.GetAdministration()

#Search agents
$Agents = $Admin.GetAllAgentManagedComputers()
Foreach ($Agent in $Agents)
{
If (!($Agent.ProxyingEnabled.Value))
{
Write-Host "Enabling Agent Proxy for $($Agent.Name)`..."
$Agent.ProxyingEnabled = $true
$Agent.ApplyChanges()

}
}

Imagine in a large management group with few thousands agents or more and there are only couple of agents that don’t have Agent Proxy enabled. the script / cmdlet will take a long time and a lot of system resources to run because it needs to retrieve information of ALL agents first!

So I wrote a PowerShell script to perform this task a bit differently:

  1. Firstly run a SQL query against SCOM operational database to retrieve a list of agents that do not have agent proxy enabled
  2. connect to SCOM SDK and for each agent retrieved from the database, turn on agent proxy.

This is much more efficient as it only retrieves agents that do not have agent proxy enabled, not the whole lot!

The script uses SCOM SDK, it works on both 2007 and 2012 environments.

Syntax:

To run it on a SCOM management server, no other parameters need to be specified.

image

To run it on a SCOM agent, you will need to specify a management server in the management group that you wish to connect to (does not have to be RMS or RMSE)

image

Additionally, the default SQL query timeout is set to 120 seconds, you can specify a different value by using the –SQLQueryTimeout parameter

image

DOWNLOAD Enable-AgentProxy.ps1

By the way, I also tried to run below SQL command to directly change the ProxyingEnabled attribute in the database (similar to Kevin Holman’s query to change all agents to remote manageable):

Update MT_HealthService Set ProxyingEnabled = 1 where ProxyingEnabled = 0

After I ran this SQL command, the agent proxy setting did get updated in the SCOM console, but I’m not sure if this is supported or not, thus I wrote this script instead.

MP Authoring: Targeting RMS or MS?

Written by Tao Yang

I’m writing a write action module for a management pack that I’m currently working on. This module contains a PowerShell script that connects to SCOM SDK service and interacts with agent computers. I originally wrote the script and planed to target the workflow to the RMS. which I thought it would make sense because SDK service runs on it no matter whether the management group version is 2007 or 2012 (RMS Emulator).

My initial PowerShell code in the write action module looked something like this:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager") | Out-Null

$MGConnSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings($Env:COMPUTERNAME)
$MG = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MGConnSetting)

As you can see, I wrote the script to connect to the SDK on the local machine.

I was talking to a Microsoft SCOM PFE yesterday, and he asked me why not target the workflow to the Management Server class since in 2012, SDK runs on all management servers. Because I want this module to work on both 2007 and 2012, Initially I thought it’s not going to work on 2007 if I target the workflow to the management server class because the SDK only runs on RMS in 2007.

Anyways, I had another thought tonight, it would be nice if I could target MS instead of RMS to take the load off RMS and get each MS to only interact with the agents that are reporting to itself. This probably makes more sense and would be more efficient in 2012 rather than 2007.

So in order to make this script run on both 2007 and 2012, I changed the script to:

#Locate SDK service machine
$MachineRegKeyPath = "HKLM:\software\Microsoft\Microsoft Operations Manager\3.0\Machine Settings"
$MachineRegValueName = "DefaultSDKServiceMachine"
$regValue = Get-ItemProperty -path:$MachineRegKeyPath -name:$MachineRegValueName -ErrorAction:SilentlyContinue;

if ($regValue -ne $null)
{
$SDKServiceMachine = $regValue.DefaultSDKServiceMachine;
} else {
#cannot determine which SDK to connect
Exit
}

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager") | Out-Null

$MGConnSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings($SDKServiceMachine)
$MG = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MGConnSetting)

Basically, the script now reads the default SDK service computer name from the registry of each management server and connect to this SDK machine instead of local computer. in 2007, this registry value points to RMS and in 2012, it points to the management server itself.

Of course, now that the script runs on multiple management servers, I had to rewrite the rest of it so it only interact with the agents on the local management server rather than the whole lot as if it’s running on the RMS.

The only concern I have with 2007 is, because my workflow runs on a schedule, when all management servers run this workflow at the same time, it will consume a large number of concurrent SDK connections on the RMS, which could be an issue in a large environment. to work around the issue, I would make sure that I make the SyncTime parameter overridable for the scheduler data source module so I can then create overrides for each management servers to run the workflow on different time window.

PowerShell Function: Get-WeekDayInMonth

Written by Tao Yang

Often, IT admins need to workout the first/second/third/fourth Mon/Tue/Wed/Thur/Fri/Sat/Sun of any given month. some good examples are:

  • Prepare themselves for Microsoft’s patching Tuesday of each month
  • Planning for any admin tasks caused by Day Light Saving time change

So I wrote this simple function today to calculate the date for any given month & year.

Here’s the function:

Function Get-WeekDayInMonth ([int]$Month, [int]$year, [int]$WeekNumber, [int]$WeekDay)
{

$FirstDayOfMonth = Get-Date -Year $year -Month $Month -Day 1 -Hour 0 -Minute 0 -Second 0
#First week day of the month (i.e. first monday of the month)
[int]$FirstDayofMonthDay = $FirstDayOfMonth.DayOfWeek
$Difference = $WeekDay - $FirstDayofMonthDay
If ($Difference -lt 0)
{
$DaysToAdd = 7 - ($FirstDayofMonthDay - $WeekDay)
} elseif ($difference -eq 0 )
{
$DaysToAdd = 0
}else {
$DaysToAdd = $Difference
}
$FirstWeekDayofMonth = $FirstDayOfMonth.AddDays($DaysToAdd)
Remove-Variable DaysToAdd
#Add Weeks
$DaysToAdd = ($WeekNumber -1)*7
$TheDay = $FirstWeekDayofMonth.AddDays($DaysToAdd)
If (!($TheDay.Month -eq $Month -and $TheDay.Year -eq $Year))
{
$TheDay = $null
}
$TheDay
}

the $weekday variable represents the week day you after:

0 Sunday
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday
Usage:
Example #1: to query the 2nd Tuesday of October 2012:
Get-WeekDayInMonth –month 10 –year 2012 –Weeknumber 2 –Weeday 2
OR
Get-WeekDayInMonth 10 2012 2 2
image
Example #2: to query the 1st Sunday of May 2013:
Get-WeekDayInMonth –month 5 –year 2013 –Weeknumber 1 –Weeday 0
OR
Get-WeekDayInMonth 5 2013 1 0

image