TechNet Magazine > Home > Issues > 2008 > August >  Windows PowerShell in System Center Operations ...
System Center
Windows PowerShell in System Center Operations Manager
Marco Shaw
 
At a Glance:
  • The OpsMgr Command Shell
  • The OpsMgr monitoring provider
  • Automating common administrative tasks
  • Some real-world Windows PowerShell examples

System Center Operations Manager 2007 (OpsMgr) has given administrators access to Windows PowerShell, a powerful new scripting language for automating tasks. Released to the public in November 2006, it has been downloaded more than two million times since then.
In this article, I am going to talk about Windows PowerShell® and discuss how it applies to Operations Manager. I'll cover some of the common tasks that Windows PowerShell can help you accomplish in a far easier and more automated manner, and refer you to some Web sites that provide useful scripts and explanations. I've gathered insights and blog posts from many of the experts using Windows PowerShell today.
Although Microsoft has started releasing the Community Technology Preview (CTP) versions of Windows PowerShell 2.0, these versions are not production-ready, have not been tested with OpsMgr, and should not be installed on a production system.

Operations Manager Command Shell
In OpsMgr, you access Windows PowerShell through the Command Shell, which is similar to the default Windows PowerShell environment except it loads a console file as well as a script that initializes the environment with OpsMgr cmdlets, functions, and a default connection.
You can start the Command Shell from an icon on the OpsMgr Start menu or by right-clicking on a computer name in the OpsMgr UI console (see Figure 1). This places you directly in the OpsMgr Monitoring drive path (which I will discuss shortly).
Figure 1 Opening the Command Shell from the OpsMgr UI (Click the image for a larger view)
Windows PowerShell interfaces with Ops­Mgr through the OpsMgr SDK. Luckily for administrators, cmdlets have already been provided for many of the tasks you would typically want to automate or complete from a command line. If there's no cmdlet for a particular task, you can use Windows Power­Shell to interact with the SDK.
The commands provided by the Operations Manager Command Shell are contained in a snap-in—a DLL that gets loaded by Windows PowerShell and contains cmdlets for OpsMgr administration. The snap-in also includes the OperationsManager­Monitoring Windows PowerShell provider. Also known as the Monitoring provider, this tool allows for navigation on connections, groups, and monitoring objects, much like navigating the file system.
You can get a list of all the cmdlets specific to OpsMgr using the Get-OperationsManager­Command cmdlet, as shown in Figure 2. (In the first version, this was a function, which did not support tab completion; it became a cmdlet in SP1.) The original release of Operations Manager included 74 cmdlets, while OpsMgr SP1 has 87.
Figure 2 Getting a list of the OpsMgr cmdlets (Click the image for a larger view)

The OpsMgr Monitoring Provider
By using the cmdlet Set-Location, or the alias cd, you can navigate through the layout of groups and computers. The base layout for the default Monitoringdrive is something like the following:
Monitoring:\->RMS->Groups (as defined in OpsMgr)
  ->Computers(as defined in OpsMgr)
From here, you can get to more specific objects. Note that I am only dealing with a simple environment in this case, where there is only a single management server. The first management server installed in a management group is known as a Root Management Server (RMS).
When the Command Shell is started, it creates a drive named Monitoring, maps the drive to the root of OperationsManager­Monitoring provider, and finally sets the current location or path to the root of the Monitoring drive. The Command Shell then searches the registry for the name of the default RMS with which to connect. If the connection to the RMS succeeds, the current location or path is set to the name of the connection, or RMS, as shown in Figure 3.
Figure 3 The Command Shell location is set to the RMS (Click the image for a larger view)

Automating Common Tasks
Let's see how Windows PowerShell can handle some of the most common administrative tasks.
Controlling Maintenance Mode No matter what task you're dealing with, you generally will want to specify the date and time it should occur. I'll take a brief look at the Get-Date cmdlet to show you how easy this can be. Figure 4 shows a few examples.
Figure 4 Using the Get-Date cmdlet (Click the image for a larger view)
As you can see, I created a $date variable that contains an object representing the current time. I then used some documented methods supported by the object to show how you can easily get the date and time five minutes later, and then five hours later. If I wanted to get values from the past, I would simply use (-5) instead of (5).
When you need to block all alerts coming from a computer, you can enable maintenance mode. OpsMgr 2007 allows you to put a Windows® service, or even a particular database, into maintenance mode instead of an entire computer or group. There are three cmdlets that deal specifically with maintenance mode tasks: Get-MaintenanceWindow, New-MaintenanceWindow, and Set-MaintenanceWindow.
To put a computer into maintenance mode from within the Command Shell, navigate to the desired computer or monitoring object using the Monitoring provider and invoke the New-MaintenanceWindow cmd­let, as shown in Figure 5. As you can see, this action places the computer called Denver.contoso.com into maintenance mode. I have also defined the start time for the maintenance window to take effect immediately and the end time to take effect exactly one hour later. Note that putting a computer into maintenance mode using this method does not stop all alerts, as the HealthService and HealthService­Watcher instances for this object are still enabled.
Figure 5 Using the New-MaintenanceWindow cmdlet (Click the image for a larger view)
Boris Yanushpolsky, Program Manager on the Microsoft Ops­Mgr team, has provided some very handy Windows PowerShell code that can be used to set all objects that refer to a computer into maintenance mode, and he has explained how to use this once you've created a script. To read more about this, see his blog at blogs.msdn.com/boris_yanushpolsky/archive/2007/07/25/putting-a-computer-into-maintenance-mode.aspx.
Sometimes you need to determine if objects are in maintenance mode that shouldn't be. Cycling through all of the objects to try to figure this out could be a pretty big undertaking, though. Fortunately, Boris Yanushpolsky comes to the rescue again with a Windows PowerShell script that uses the OpsMgr SDK. You can take the code directly from his blog post (blogs.msdn.com/boris_yanushpolsky/archive/2007/08/06/so-what-is-in-maintenance-mode.aspx) and paste it into a Command Shell window to get a listing of all objects in maintenance mode.
When an object is in maintenance mode, you may want to end the maintenance period before the originally specified end time. If you're familiar with Windows PowerShell, you may expect a cmdlet with a stop or remove verb, but you must actually use Set-MaintenanceWindow, as in Figure 6.
Figure 6 Using Set-MaintenanceWindow to change the end time (Click the image for a larger view)
Managing Agents Administrators very often work with agents, and there are six cmdlets and one function (as of the release) that deal with various agent-related tasks. You can get a list of them with this command:
Get-Command *-agent*
As of the SP1 release, Install-AgentBy­Name is packaged as a cmdlet instead of a function. It is recommended that you use the Install-AgentByName cmdlet, as it provides a better basis for support and consistency.
The built-in help included with the Command Shell provides some good examples of using the Install-Agent and Uninstall-Agent cmdlets. Roger Sprague, Senior Software Design Engineer on the Microsoft Ops­Mgr team, posted an alternative method on his blog, which is reproduced in Figure 7 (see his original post at blogs.msdn.com/scshell/archive/2006/09/28/getting-started.aspx).
This script works fine with the OpsMgr RTM (you must be located in the root of the monitoring provider—in this article it is monitoring:\oxford.contoso.com), but it fails with OpsMgr SP1. To make it work with OpsMgr SP1, the first command in Figure 7 should be changed to the following:
 $managementServer = Get-RootManagementServer
# Get the Root Management Server.
$managementServer = Get-ManagementServer -Root: $true

# Create the discovery configuration for computer2 and computer3.
$discoConfig = New-WindowsDiscoveryConfiguration -ComputerName: computer2, computer3

# Discover the computers.
$discoResult = Start-Discovery -ManagementServer: $managementServer -WindowsDiscoveryConfiguration: $discoConfig

# Install an agent on each computer.
Install-Agent -ManagementServer: $managementServer -AgentManagedComputer: $discoResult.CustomMonitoringObjects
At this point, the agent is installed on the remote system that should be monitored, but there is still one last step where the management server must actually accept the new agent before it is completely monitored. If no further action is taken, the monitoring server will automatically accept the new agent for monitoring. But this acceptance process can also be fast-tracked by using the Get-AgentPendingAction cmdlet. This one-liner will fast-track the agent acceptance process:
Get-AgentPendingAction | Where Object {$_.AgentName –like 
'computer*'} | Approve-AgentPendingAction
By piping this to Reject-AgentPending­Action, instead of Approve-AgentPending­Action, you can block the acceptance of this agent by the OpsMgr server, if the action is still outstanding. If it is not outstanding, use the Uninstall-Agent cmdlet instead.
As I mentioned, you can also use Install-­AgentByName for specifying a computer directly at the command line where the agent is to be installed.
Working with Management Packs There are four cmdlets to help you deal with various management pack tasks. You can list them using this:
Get-Command –noun ManagementPack
This simple command provides the currently installed management packs and their version numbers:
Get-ManagementPack | Format-Table –autosize
Now I'll use the Command Shell to install two common management packs using these installers:
  • Internet Information Services System Center Operations Manager2007 Management Pack.msi
  • Windows Server® Base OS System Center Operations Manager2007 Management Pack.msi.
Since my goal here is to show how the Command Shell can make regular tasks easier, I am going to do this using the fewest commands possible (as shown in Figure 8). I could have changed this installation procedure to pass the quiet flag to the installer (the .msi files), but I wanted to select the location where the files would be extracted manually.
Figure 8 Installing management packs (Click the image for a larger view)
Next, I need to install the common libraries, which I can do with the following:
Get-ChildItem –Path C:\MPs –filter *Library.mp |
ForEach-Object
  {Install-ManagementPack –filePath $_.FullName}
Then I install the other required management packs:
Get-ChildItem –Path C:\MPs –filter *200?.mp | 
ForEach-Object
  {Install-ManagementPack –filePath $_.FullName}
As Figure 9 shows, the built-in Command Shell help provides an excellent example of using the Export-ManagementPack cmdlet to export unsealed management packs. If you want to export all management packs, change this line
 $mps=Get-ManagementPack | 
Where-Object {$_.Sealed –eq $false} 
 $mps=Get-ManagementPack
Figure 9 Exporting a management pack (Click the image for a larger view)
Manipulating User Roles The Get-UserRole cmdlet provides some functionality for administering users but, oddly, doesn't come with a complementary Set cmdlet, and you don't typically use it to make edits or updates (according to the Windows PowerShell SDK documentation). As you can see in Figure 10, first I get a listing of the current user roles, and then I add a user to the Read-Only Operators group (see Figure 11).
Figure 10 Displaying user roles (Click the image for a larger view)
Figure 11 Adding a user (Click the image for a larger view)
Enabling Audit Collection Services (ACS) ACS is a new optional feature in Operations Manager 2007 that, in brief, provides a centralized way to deal with security audit information. ACS isn't enabled by default and typically might be configured later on in a future phase of an OpsMgr deployment.
When it comes time to enable a large number of agents for ACS, Windows PowerShell comes to the rescue by helping to automate the setup. During the OpsMgr beta, Microsoft provided a script to enable ACS on all agents. Neale Browne, a contributor and blogger for SystemCenterForum.org, took this a step further and added support for additional parameters.
The SystemCenterForum.org site (a community site that provides Microsoft® System Center solutions) has made two different Windows PowerShell scripts available for automating the setup of ACS. To set up all the agents in a particular group, use systemcenterforum.org/wp-content/uploads/ACSBulkEnableGroupDisplayName.zip. To set up all monitored agents, download systemcenterforum.org/wp-content/uploads/ACSBulkEnableAllAgents.zip.
Enabling Agent Proxying Your OpsMgr environment may include agentless monitored devices. These devices must be assigned to a management server or to an agent-managed device that will provide remote monitoring. You can find a detailed description of using a Windows PowerShell script to configure a large number of agents at systemcenterforum.org/enable-agent-act-as-a-proxy-in-bulk-via-powershell. An updated version of the script is available at systemcenterforum.org/wp-content/uploads/Set­AgentProxyBulk_FQDN.zip.
There are other conditions where particular management packs require that an agent be set to act as a proxy also. Please consult the management pack documentation for more details.

The Real World
Here are some real-world examples to demonstrate further into how Windows PowerShell can help with automation.
Resolving Alerts Have you ever had to delete several alerts for a particular computer? Perhaps something went wrong with an application or the alerts weren't being actively resolved. Here's a one-line command that will resolve all the alerts that have a resolution state of zero:
Get-Alert –criteria 'ResolutionState = ''0''' |
Resolve-Alert | Out-Null
This next example accomplishes the same thing as the first one, but it will run much faster in a bigger environment with more outstanding alerts:
Get-Alert | Where-Object {$_.ResolutionState -eq 0} |
Resolve-Alert | Out-Null
The reason behind the performance difference is that when the criteria parameter is used, the value passed is provided directly to the SQL Server® database, and only the relevant data is returned. This reduces the objects that must be passed all the way back to the Windows PowerShell console.
Now you have a quick way to remove all the outstanding alerts for one computer. Depending on your requirements, you can set this to run automatically.
Finally, here's a quick command that lets you view all of the alerts for a specific day:
Get-Alert -criteria 'TimeRaised >= ''4/25/2008'''
You can very easily change the date value, and you can pipe the output to the Resolve-Alert cmdlet.
Test Alerts Sometimes you want to be able to monitor certain events in the Windows Event Viewer and test for them. These two lines will create a quick event log entry:
 $api=New-Object -comObject MOM.ScriptAPI
$api.logscriptevent("API test",100,0,
  "Test using PowerShell")
By default, however, this will write to the Operations Manager event log, which probably isn't the place where you'll be watching for a particular event to be logged. Fortunately, Stefan Stranger, Premier Field Engineer with Microsoft, has written a script to create events in the Windows Event Viewer, and it provides more flexibility on being able to write to a particular log. You'll find the script at go.microsoft.com/fwlink/?LinkId=120308. (Stefan has packaged the script in a .cab file. You will need to download the file, then right-click it to extract his script.)
The only thing to note with Stefan's script is that the value entered for the event source determines to which log the entry will be written. Perhaps the easiest way to make sure an alert is directed toward the proper log is to open the Windows Event Viewer and find the source of the latest entry.
Set the Owner It may sometimes be useful to set the owner of an alert automatically. Here's a simple way to do it from the Command Shell:
 $alert = Get-Alert 
  -id f3f73d62-37ab-45ce-a7ff-2bdda0dfaeb4
$alert.set_owner("Administrator")
$alert.update("Updated owner")
The first line of this code gets the ID of a particular alert object and passes it to the $alert variable. In the second line, that variable is used to set the owner, and, finally, the update is applied to the OpsMgr database. If you check the owner of the alert with the following command, you'll see it changed:
Get-Alert -id f3f73d62-37ab-45ce-a7ff-2bdda0dfaeb4 |
Select-Object Owner
To set the owner for an entire set of alerts, you could simplify the code like this:
Get-Alert | ForEach-Object {$_.Set_
  Owner("Administrator");
  $_.Update("Owner set")}
Restore Monitoring State Chances are you have come across agents in a "not monitored" state. When this happens, you may need to restore all the agents to a full monitored state quickly, and then attempt to determine what happened. Running the script in Figure 12 directly from the Command Shell should restore full monitoring to any agents affected.
 $all="Microsoft.SystemCenter.AllComputersGroup"
$agents = Get-ChildItem Microsoft.SystemCenter.AllComputersGroup | `
  Where-Object {$_.HealthState -eq 'Uninitialized'}
foreach ($agent in $agents)
{
$agent.DisplayName
Push-Location $all\$agent\Microsoft.SystemCenter.HealthService
Get-Task | Where-Object {$_.Name -eq "Microsoft.SystemCenter.ResetHealthServiceStore"} | `
    Start-Task -Asynchronous
Pop-Location
}
Take a look at the code in Figure 12. After declaring a variable, I get a list of all the agents on this RMS and filter on the ones that appear to be in trouble. Then I call a task asynchronously that resets the Health Service Store on all agents in the filtered list.
Associate Alerts with Management Packs Figure 13shows how to get a list of all new alerts as well as the management pack with which each is associated.
The code required a few tricks to make sure all of the management pack names could be resolved. The cmdlets used will vary, depending on whether the alert is from a rule or a monitor. (Note that in Figure 13 I needed to implement a small workaround for the Get-Monitor cmdlet. As of OpsMgr SP1, the cmdlet now supports a new ID parameter, which would slightly simplify the code.)
Get-Alert | Where-Object {($_.PrincipalName -ne $null) -and ($_.ResolutionState = '0')}| `
Format-Table –autosize PrincipalName,Severity, `
  @{Label="MP"
      Expression={If(!($_.IsMonitorAlert)){
        ForEach-Object {
          ((Get-Rule $_.MonitoringRuleId).GetManagementPack()).DisplayName}
       }  
       Else{
         ForEach-Object {
          $id=$_.ProblemId
          ((Get-Monitor -criteria "Id='$id'").GetManagementPack()).DisplayName}
         }
   }
}
Easy Reporting When you upgrade your environment, it may be useful to audit the versions of all installed agents. It takes just a simple script to print out a nice report:
Get-Agent| `
Format-Table DisplayName,@{ `
  Label="Version"
  Expression={ `
    switch ($_.Version){
    "6.0.5000.0" {"RTM"}
    "6.0.6246.0" {"SP1 (RC)"}
    "6.0.6278.0" {"SP1 (RTM)"}
    }
  }
}
Figure 14 shows output from the script. This script is an expanded version of examples provided at systemcenterforum.org/checking-operations-manager-2007-agent-and-server-versions-via-powershell.
Figure 14 Output showing the versions of some agents (Click the image for a larger view)
Scheduling a Task You may want to run a Windows PowerShell script on a regular basis. Let's say you use a client computer to connect to and manage your OpsMgr server, and you have the OpsMgr admin tools installed locally. And suppose, for example, you want to run the agent version report on a daily basis and have the output saved to a file with the current date used as the name. You can use the Windows built-in task scheduler to run the script from your local machine.
To do this, you simply set up a new task with the program set as powershell.exe (typically located in C:\Windows\System32\WindowsPowerShell\v1.0). After you have created the task, edit it and set the command to run as something like this:
C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe 
  –Command "& {& 'c:\agent_report2.ps1'}"
It turned out that I had to make quite a few changes to my original Windows PowerShell code, as you can see in Figure 15. I had to add the OpsMgr PowerShell snap-in, create the Monitoring drive mapped to the Operations­ManagerMonitoring provider, and create a connection to the RMS. I also load the Ops­Mgr custom Windows Power­Shell script (Microsoft.Enterprise­Management.OperationsManager.ClientShell.Startup.ps1) to load OpsMgr-specific functions.
Add-PSSnapin Microsoft.EnterpriseManagement.OperationsManager.Client
New-PSDrive Monitoring Microsoft.EnterpriseManagement.OperationsManager.Client\
  OperationsManagerMonitoring ""
New-ManagementGroupConnection Oxford.contoso.com

Set-Location 'C:\Program Files\System Center Operations Manager 2007'
./Microsoft.EnterpriseManagement.OperationsManager.ClientShell.NonInteractiveStartup.ps1

$file="C:\$(Get-Date -f `"MMddyyyy`").rpt"

Get-Agent -Path Monitoring:\Oxford.contoso.com | `
Format-Table DisplayName,@{ `
  Label="Version"
  Expression={ `
    switch ($_.Version){
    "6.0.5000.0" {"RTM"}
    "6.0.6246.0" {"SP1 (RC)"}
    "6.0.6278.0" {"SP1 (RTM)"}
    }
  }
} | Out-File $file
But that's not all. You might notice that every time the task is run, a black console window pops up on the screen if someone is logged onto the system where the script is being run. You'll find a little trick that takes care of this, provided by Don Jones and Jeffery Hicks from Sapien, at blog.sapien.com/index.php/2006/12/26/more-fun-with-scheduled-powershell.
Basically, you need to wrap the script within a VBScript. To accomplish this, you'd use code like that in Figure 16 instead of calling the following from your scheduled task:
C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe
  –Command "& {& 'c:\agent_report2.ps1'}"
Dim objShell
Set objShell=CreateObject("WScript.Shell")

'enter the PowerShell expression you need to use short filenames and paths 
strExpression="'c:\agent_report2.ps1'"

strCMD="powershell -nologo  -command " & Chr(34) & _
"&{&" & strExpression &"}" & Chr(34) 

'Uncomment next line for debugging
'WScript.Echo strCMD

'use 0 to hide window
objShell.Run strCMD,0
The task would now use the wscript.exe program, and the call would look similar to this:
C:\WINDOWS\System32\wscript.exe C:\agent_report.vbs 
Finally, I can create automated reports, and the process is hidden from logged-on users.

Wrapping Up
This has been a whirlwind tour of the new automation features available with OpsMgr 2007, and it barely scratches the surface of how you can use Windows PowerShell to take care of OpsMgr administration.
I'd like to thank all the people mentioned in the article, as well as Pete Zerger, MOM MVP and SystemCenterForum.org founder, for their valuable help.

Marco Shaw is an IT System Analyst for a Canadian telecommunications company. He has been working in the IT industry for more than 10 years, and he recently received a Windows PowerShell MVP award. Marco is also the Assistant Community Director of the new PowerShell Community Web site at powershellcommunity.org. He blogs at marcoshaw.blogspot.com.

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Page view tracker