Tag Archives: MimbolovePowershell

Using Royal TS for PowerShell Remote Sessions

Written by Tao Yang

Background

I have used many Remote Desktop applications in the past. I have to say Royal TS is the one that I like the most! Recently, I showed it to one of my colleagues, after a bit of playing around, he purchased a license for himself too.

Today, my colleague asked me if I knew that Royal TS is also able to run external commands, and he thought it’s pretty cool that he’s able to launch PowerShell in the Royal TS window. Then I thought, if you can run PowerShell in Royal TS, we should be able to establish PS remote sessions in Royal TS too. Within 10 minutes, we managed to create few connections in Royal TS like these:

SNAGHTML1c209a8d

SNAGHTMLa497d178

image

SNAGHTML1c2e5543

In this post, I’ll go through the steps I took to set them up.

Connections to Individual Servers

To create a connection to an individual server,

01. Choose add->External Application:

image

02. Enter the following Details:

Display Name: The name of the server you want to connect to.

Command: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

Arguments: -NoExit -Command “Enter-PSSession $CustomField1$”

Working Directory: C:\Windows\System32\WindowsPowerShell\v1.0

On the icon button next to the display name, choose “Use Application Icon” if you want to.

image

image

03. Choose a Credential if you want to connect using an alternative credential

SNAGHTML1c5136c4

If you choose to use an alternative credential,  you must also tick “Use Credentials” box under Advanced tab:

image

04. Enter the remote server name in Custom Field 1:

image

Note: in the arguments field from step 01, I’ve used a Royal TS variable $CustomField1$ as the name of the computer in the Enter-PSSession command. It is more user friendly to use the Custom Field for the computer name, rather than modifying the argument string for each connection that you wish to create.

Create An Ad-Hoc Connection

You can also create a connection in Royal TS for Ad-Hoc connections. In this scenario, you will need to enter the remote computer that you wish to connect to:

image

After the the computer name has been entered, the connection is then established:

image

To create this connection in Royal TS, instead of using the Custom Field 1 for the computer name, I’ve added an additional PowerShell command in the Arguments:

Arguments: -NoExit -Command “$Computer = Read-Host ‘Please enter the Computer Name'; Enter-PSSession $Computer”

image

The Custom Field 1 is no longer required in this scenario. Everything else is the same as the previous sample (for individual computers).

Other Considerations

Maximised PowerShell Window

You may have noticed from the screenshots above, that the PowerShell windows are perfectly fitted in the Royal TS frame. this is because I am also using a customised PS Module that I’ve written in the past to resize the PoewerShell window. Without this module, the PowerShell console would not automatically fit into the Royal TS frame:

image VS image

If you like your console looks like the left one rather than one on the right, please follow the instruction below.

01. Download the PSConsole Module and place it under C:\windows\system32\WindowsPowerShell\v1.0\Modules

image

02. Modify the “All Users Current Host” profile from a normal PowerShell window (NOT within PowerShell ISE). If you are not sure if this profile has been created, run the command below:

image

After the profile is created, open it in notepad (in PowerShell window, type: Notepad $Profile.AllUsersCurrentHost) and add 2 lines of code:

image

After saving the changes, next time when you initiate a connection in Royal TS, the console will automatically maximise to use all the usable space.

Note: Because most likely you will be using an alternative (privileged credential) for these PS remote sessions. therefore the resize console commands cannot be placed into the default profile (current user current host). It must be placed into an All users profile. And also because the resize command only works in a normal PowerShell console (not in PowerShell ISE), therefore the only profile that you can use is the “All Users Current Host” profile from the normal PowerShell console.

Alternatively, if you do not wish to make changes to the All Users Current host profile, you can also add the above mentioned lines into the Royal TS connection arguments field:

i.e.

Arguments: -NoExit -Command “import-module psconsole; resize -max; Enter-PSSession $CustomField1$”

image

Duplicating Royal TS Connections

If you want to create multiple connections, all you need to do is to create the first one manually, and then duplicate it multiple times:

image

When duplicating connections, the only fields you need to change are the Display Name and CustomField1.

WinRM configuration

Needless to say, WinRM must be enabled and properly configured for PS remoting to work. this is a pre-requisite. I won’t go through how to configure WinRM here. Someone actually wrote a whole book on this topic.

Conclusion

I’d like to thank Stefan Koell (blog, twitter), the Royal TS developer (and also my fellow SCCDM MVP) for such an awesome tool. This is now probably THE most used application on all my computers Smile.

If you haven’t tried Royal TS out, please give it a try. Other than the obvious Windows version, there are also a Mac version, an iOS version and an Android version.

A Simplified Way to Send Emails and Mobile Push Notifications in SMA

Written by Tao Yang

Background

For those who knows me, I’m an OpsMgr guy. I spend a lot of time in OpsMgr and I am very used to the way OpsMgr sends notifications (using notification channels and subscribers).

In OpsMgr, I like the idea of saving the SMTP configuration and notification recipients’ contact details into the system so everyone who has got enough privilege can use these configurations (when configuring alert subscriptions).

Over the last few months, I have spent a lot of time on SMA (Service Management Automation). As I started building more and more runbooks and integration modules, I really miss the simple way of sending notifications in OpsMgr. Although there is a built-in PowerShell cmdlet for sending emails (Send-MailMessage), it requires a lot of input parameters, and the runbook author needs to have all the SMTP information available. I thought it would be nice if I could save SMTP settings as connection objects (similar to notification channels in OpsMgr), and recipients’ contact details (email and mobile device push notification services’ api keys) also as connection objects (similar to subscribers in OpsMgr).

To achieve my goals, I have created 2 SMA Integration modules:

Module Name Connection Type Name PowerShell Functions
SendEmail SMTPServerConnection Send-Email
SendPushNotification SMAAddressBook Send-MobilePushNotification

SendEmail Module

This module defines a connection type where can be used to save all SMTP related information:

  • SMTP Server address
  • Port
  • Authentication Method (Anonymous, Integrate or Credential)
  • User name
  • Password
  • Sender Name
  • Sender Address
  • UseSSL (Boolean)

SNAGHTML1ba0bfc7

image

SNAGHTML1ba1992f

This module also provides a PowerShell function called “Send-Email”. Since when retrieving an automation connection in SMA, a hash table is returned, Not only you can pass individual SMTP parameters into the Send-Email function, you can also simply pass the SMA connection object that you have retrieved using “Get-AutomationConnection” cmdlet. for more information, please refer to the help topic of this function, and the sample runbook below.

SendPushNotification Module

This module provides a connection type called SMAAddressBook. It can be used like an address book to store recipient’s contact details:

  • Display Name
  • Email Address (optional)
  • NotifiyMyAndroid API Key (optional, encrypted)
  • Prawl (iOS push notification) API Key (optional, encrypted)
  • NotifyMyWndowsPhone API Key (optional, encrypted)

image

SNAGHTML1bb2b9d4

This module also provides a PowerShell function called Send-MobilePushNotification. It can be used to send push notification to either Prawl, NotifyMyAndroid or NotifyMyWindowsPhone.

Sample Runbook

As you can see from this sample, the runbook author does not need to know the SMTP server information (including login credentials), nor the contact details of the recipient. The runbook can simply pass the SMTP connection object (PowerShell Hash Table) into the Send-Email function.

After I executed this runbook, I received the notification via both Email and Android push notification:

SNAGHTML1bb9521f

image

Download

Please download from the download link below. Once downloaded, please import the zip files below into SMA:

image

Download Link

Related Posts

OpsMgr Alerts Push Notification to iOS (And Android, And Windows Phone) Devices

Authoring Integration Modules for SMA

Conclusion

As shown in the sample above, once the SMTP details are saved in SMTP connection objects, and recipients’ contact details are saved as SMAAddressBook connections, it is really simple to utilise the functions provided by these 2 modules to send notifications.

Also, I’d like to point out I had to create 2 integration modules instead of 1 because I need to create 2 kinds of connections. Having said that, these 2 modules do not depend on each other and can be used separately too.

As many people referring to SMA modules and runbooks as Lego pieces, I will definitely to share more and more my Lego pieces as they’ve been developed. In the meantime, please feel free to contact me if you have questions or suggestions.

Using PowerShell and OpsMgr SDK to Get and Set Management Group Default settings

Written by Tao Yang

Over the last couple of days, I have written few additional functions in the OpsMgrSDK PowerShell / SMA module that I’ve been working on over the last few months. Two of these functions are:

  • Get-MGDefaultSettings – Get ALL default settings of an OpsMgr 2012 (R2) management group
  • Set-MGDefaultSetting – Set any particular MG default setting

Since I haven’t seen anything similar to these on the net before, although they will be part of the module when I release it to the public later, I thought they are pretty cool and I’ll publish the code here now.

Get-MGDefaultSettings

This function returns an arraylist which contains ALL the default settings of the management group.

Usage:

$DefaultSettings = Get-MGDefaultSettings -SDK “OpsMgrMS01″ –verbose

image

As you can see, this function retrieves ALL default settings of a management group. It returns the following properties:

  • SettingFullName: The full name of the assembly type of the setting. This is required when using the Set-MGDefaultSetting function to set the value.
  • SettingName: The name of the assembly type of the setting. consider it as the setting category
  • FieldName: The actual name of the setting. It is required when using the Set-MGDefaultSetting function.
  • Value: The current default value of the setting.
  • AllowOverride: When it’s true, this value can be overridden to a particular instance (differ from the default value).

If you want to retrieve a particular setting, you can always use pipe (“|”) and where-object to filter to the particular setting:

image

 

Set-MGDefaultSetting

Usage:

Set-MGDefaultSetting -SDK “OpsMgrMS01″ -SettingType Microsoft.EnterpriseManagement.Administration.Settings+ManagementGroup+AlertResolution -FieldName AlertAutoResolveDays -Value 3 –verbose

image

I think these two functions are particularly useful when managing multiple management groups. they can be used in automation products such as SC Orchestrator and SMA, to synchronise settings among multiple management groups (i.e. Test vs Dev vs Prod).

PowerShell Script to Add MP References to Unsealed Management Packs

Written by Tao Yang

Background

Few months ago, I have written a script to remove obsolete MP references from unsealed management packs and have also built this into the OpsMgr Self Maintenance MP. Last week, I needed to write a script to do the opposite: creating obsolete MP references in unsealed MPs.

In the past, some of the MPs I have released had issues with creating overrides in the OpsMgr operational console. i.e. the OpsMgr 2012 Self Maintenance MP and the ConfigMgr 2012 Client MP. Both of them have one thing in common: the phrase “2012” is a part of the MP namespace, and if someone tries to create an override for these MPs in the operational console, he / she will get an “Alias atribute is invalid” error:

image

When I was testing the latest release ConfigMgr 2012 Client MP (version 1.2.0.0) last week, I also got this error when assigning a RunAs account to the RunAs profile defined in the MP – because the assignment is basically a Secure Reference Override, and a MP reference to the ConfigMgr 2012 Client Library MP needs to be created in the Microsoft.SystemCenter.SecureReferenceOverride MP.

Although we can easily workaround this issue by exporting the unsealed MP, add the MP reference in by manually editing the XML, I thought I’ll write a PowerShell script to do this to make everyone’s life easier.

Script

To make it a bit easier for the users, this PowerShell function CAN ONLY be used on a OpsMgr management server.

Usage Example:

Add-MPRef -ReferenceMPName “ConfigMgr.2012.Client.Library” -Alias “C2CL” -UnsealedMPName “Microsoft.SystemCenter.SecureReferenceOverride” –Verbose

Conclusion

By using this script, we can pick the alias name that we prefer. Although this script is already included in the ConfigMgr 2012 Client MP package, I’d also like to share this script on this blog. For me, it’s a rare scenario that I had to do this, but I hope this can also help someone out there.

SMA Runbook: Update A SharePoint 2013 List Item

Written by Tao Yang

Background

This blog hasn’t been too active lately. I’ve been spending a lot of time learning the new member in System Center family: Service Management Automation.

Yesterday, I needed a SMA runbook to update SharePoint 2013 list items, I found a sample from a blog post by Christian Booth, which contains a SMA runbook written by Ryan Andorfer, a System Center Cloud and Datacenter MVP.  Looks Ryan’s code was written for SharePoint 2010, which does not work for SharePoint 2013 because the SharePoint REST API has been updated. So I have spent some time, learned a bit more about SharePoint 2013’s REST API, and developed a new runbook for SharePoint 2013 based on Ryan’s code.

PowerShell Code

Here’s the finished work:

Unlike Ryan’s code, which also monitors the SP list, my runbook ONLY updates a specific list item.

Pre-Requisite and Parameters

Prior to using this runbook, you will need to save a credential in SMA which has  access to the SharePoint site

SNAGHTML7ebadf0

The runbook is expecting the following parameters:

SharePointSiteURL: The URL to the sharepoint site. i.e. http://SharepointServer/Sites/DemoSite

SavedCredentialName: name of the saved credential to connect to SharePoint site

ListName: Name of the list. i.e. “Test List”

ListItemID: the ID for the list item that the runbook is going to update

PropertyName: the field / property of the item that is going to be updated.

PropertyValue: the new value that is going to be set to the list item property.

Note: The list Item ID is the reference number for the item within the list. If you point the mouse cursor to the item, you will find the list item ID in the URL.

SNAGHTML90254b7

Putting it into Test:

To test, I’ve created a new list as shown in the above screenshot, I have kicked off the runbook with the the following parameters:

image

image

Here’s the result:

SNAGHTML8fd5d4a

SNAGHTML8fed515

Using It Together With Orchestrator SharePoint IP

Since this SMA runbook requires the List Item ID to locate the specific list item, when you design your solution, you will need to find a way to retrieve this parameter prior to calling this runbook.

If you are also using SC Orchestrator and have deployed the SharePoint IP, you can use the “Monitor List Items” activity, and the List Item ID is published by this activity:

image

Conclusion

Although I’m still a newbie when comes to SMA, it got me really excited. Before its time, when I design Orchestrator runbooks, I often ended up just write the entire solution in PowerShell and then chopped up my PowerShell scripts into many “Run .Net Script” activities. I thought, wouldn’t it be nice if there is an automation engine that only uses PowerShell? Well, looks like SMA is the solution. I wish I have started using it sooner.

If you are like me and want to learn more about this product, i highly recommend you to read the Service Management Automation Whitepaper (currently version 1.0.4) from my fellow SCCDM MVP Michael Rueefli. I have read it page by page like a bible!

How to Create a PowerShell Console Profile Baseline for the Entire Environment

Written by Tao Yang

Background

Often when I’m working in my lab, I get frustrated because the code in PowerShell profiles varies between different computers and user accounts. And your user profile is also different between the normal PowerShell command console and PowerShell ISE. I wanted to be able to create a baseline for the PowerShell profiles across all computers and all users, no matter which PowerShell console is being used (normal command console vs PowerShell ISE).

For example, I would like to achieve the following when I start any 64 bit PowerShell consoles on any computers in my lab under any user accounts:

This is what I want the consoles to look like:

SNAGHTML65445bb.png

image.png

Although I can manually copy the code into the profiles for each of my user accounts and enable roaming profile for  these users, I don’t want to take this approach because it’s too manual and I am not a big fan of roaming profiles.

Instructions

My approach is incredibly simple, all I had to do is to create a simple script and deployed it as a normal software package  using ConfigMgr. I’ll now go through the steps.

All Users All Hosts Profile

Firstly, there are actually not one (1), but six (6) different PowerShell profiles (I have to admit, I didn’t know this until now Smile with tongue out). This article from the Scripting Guy explained it very well. Based on this article, I have identified that I need to work on the All Users All Hosts profile. Because I want the code to run regardless which user account am I using, and no matter whether I’m using the normal command console or PowerShell ISE.

Pre-Requisite

As I mentioned previously, because I want to use the PSConsole module I have developed earlier, I need to make sure this module is deployed to all computers in my lab. To do so, I have created a simple msi to copy the module to the PowerShell Module’s folder and deployed it to all the computers using ConfigMgr. I won’t go through how I created the msi here.

Code Inside the All Users All Hosts profile

The All Users All Hosts profile is located at $PsHome\profile.ps1

image

Here’s the code I’ve added to this profile:

if (Get-module -name PSConsole -List)
{
Import-Module PSConsole
}

$host.UI.RawUI.BackgroundColor = "Black"
$host.UI.RawUI.ForegroundColor = "Green"
$host.UI.RawUI.WindowTitle = $host.UI.RawUI.WindowTitle + "  - Tao Yang Test Lab"
If ($psISE)
{
$psISE.Options.ConsolePaneBackgroundColor = "Black"
} else {
Resize-Console -max -ErrorAction SilentlyContinue
}
set-location C:\
Clear-Host

Note: The $psISE variable only exists in the PowerShell ISE environment, therefore I’m using it to identify which console am I currently in and used an IF… Else… statement to control what’s getting executed within PowerShell ISE and normal PowerShell console.

Script To create All Users All Hosts Profile

Next, I have created a PowerShell script to create the All Users All Hosts profile:

#=====================================================================
# Script Name:        CreateAllUsersAllHostsProfile.ps1
# DATE:               03/08/2014
# Version:            1.0
# COMMENT:            - Script to create All users All hosts PS profile
#=====================================================================

$ProfilePath = $profile.AllUsersAllHosts

#Create the profile if doesn't exist
If (!(test-path $ProfilePath))
{
New-Item -Path $ProfilePath -ItemType file -Force
}

#content of the profile script
$ProfileContent = @"
if (Get-module -name PSConsole -List)
{
Import-Module PSConsole
}

<code>$host.UI.RawUI.BackgroundColor = &quot;Black&quot;
</code>$host.UI.RawUI.ForegroundColor = &quot;Green&quot;
<code>$host.UI.RawUI.WindowTitle = </code>$host.UI.RawUI.WindowTitle + &quot;  - Tao Yang Test Lab&quot;
If (<code>$psISE)
{
</code>$psISE.Options.ConsolePaneBackgroundColor = &quot;Black&quot;
} else {
Resize-Console -max -ErrorAction SilentlyContinue
}
set-location C:\
Clear-Host
&quot;@
#write contents to the profile
if (test-path $ProfilePath)
{
Set-Content -Path $ProfilePath -Value $ProfileContent -Force
} else {
Write-Error &quot;All Users All Hosts PS Profile does not exist and this script failed to create it.&quot;
}

As you can see, I have stored the content in a multi-line string variable. The only thing to pay attention to is that I have to add the PowerShell escape character backtick (`)  in front of each variable (dollar sign $).

This script will overwrite the profile if already exists, so it will make sure the profile is consistent across all computers.

Deploy the Profile Creation Script Using ConfigMgr

In SCCM, I have created a Package with one program for this script:

image

Command Line: %windir%\Sysnative\WindowsPowerShell\v1.0\Powershell.exe .\CreateAllUsersAllHostsProfile.ps1

Note: I’m using ConfigMgr 2012 R2 in my lab, although the ConfigMgr client seems to be 64-bit, this command will still be executed under 32-bit environment. Therefore I have to use “Sysnative” instead of “System32” to overcome 32-bit redirection in 64-bit OS.

I created a re-occurring deployment for this program:

image

I’ve set it to run it once a day at 8:00am and always rerun.

Conclusion

This is an example on how we can standardise the baseline of PowerShell consoles within the environment. Individual users will still be able to add the users specific stuff in different profiles.

For example, on one of my computers, I have added one line to the default Current User Current Host profile:

image

In the All Users All Hosts profile, I have set the location to C:\, but in the Current User Current Host profile, I’ve set the location to “C:\Scripts\Backup Script”. The result is, when I started the console, the location is set to “C:\Scripts\Backup Script”. Obviously the Current User Current Host profile was executed after the All Users All Hosts profile. Therefore we can use the All Users All Hosts profile as a baseline and using Current User Current Host profile as a delta Smile.

OpsMgr 2012: A Trick to Drive Another Contextual Widget From PowerShell Grid Widget

Written by Tao Yang

PowerShell Grid widget and PowerShell Web Browser Widget were released as part of OpsMgr 2012 SP1 UR6 and R2 UR2. To me, these two widgets have opened a window of opportunities, because by using PowerShell, it allows OpsMgr 2012 users to customise and present the data exactly the way they wanted on dashboards.

Since it has been released, many people have share their work. Recently, Microsoft has started a new repository for the PowerShell widgets in TechNet Gallery.

The best article for the PowerShell Grid Widget that I have seen so far is from Oleg Kapustin’s blog: SCOM Powershell Grid Widget for Mere Mortals. In Oleg’s article (and seems to be a common practice), for each item that to be listed by the PowerShell Grid Widget, a unique Id is assigned to it (an auto incremented number):

image

Today, I want to share a small trick with you, something I’ve only picked up couple of days ago when I was writing the Location History dashboard for the 3rd part of my Location, Location, Location series. This is what the dashboard looks like:

SNAGHTML52cdecf

On this dashboard, users suppose to make their way from section 1 (state widget) to section 2 (PowerShell Grid Widget) and finally to section 3 (PowerShell Web Browser Widget). The PowerShell script in section 2 retrieves particular events generated by the object from section 1 using OpsMgr cmdlets, then display the data on this customised list. This script is listed below:

Param($globalSelectedItems)

$i = 1
foreach ($globalSelectedItem in $globalSelectedItems)
{
 $MonitoringObjectID = $globalSelectedItem["Id"]
 $MG = Get-SCOMManagementGroup
 $globalSelectedItemInstance = Get-SCOMClassInstance -Id $MonitoringObjectID
 $Computername = $globalSelectedItemInstance.DisplayName
 $strInstnaceCriteria = "FullName='Microsoft.Windows.Computer:$Computername'"
 $InstanceCriteria = New-Object Microsoft.EnterpriseManagement.Monitoring.MonitoringObjectGenericCriteria($strInstnaceCriteria)
 $Instance = $MG.GetMonitoringObjects($InstanceCriteria)[0]
 $Events = Get-SCOMEvent -instance $Instance -EventId 10001 -EventSource "LocationMonitoring" | Where-Object {$_.Parameters[1] -eq 4} |Sort-Object TimeAdded -Descending | Select -First 50
 foreach ($Event in $Events)
 {
 $EventID = $Event.Id.Tostring()
 $LocalTime = $Event.Parameters[0]
 $LocationStatus = $Event.Parameters[1]
 $Latitude = $Event.Parameters[2]
 $Longitude = $Event.Parameters[3]
 $Altitude = $Event.Parameters[4]
 $ErrorRadius = $Event.Parameters[5].trimend(".")
 
 $dataObject = $ScriptContext.CreateInstance("xsd://foo!bar/baz")
 $dataObject["Id"]=$EventID
 $dataObject["No"]=$i
 $dataObject["LocalTime"]=$LocalTime
 $dataObject["Latitude"]=$Latitude
 $dataObject["Longitude"]=$Longitude
 $dataObject["Altitude"]=$Altitude
 $dataObject["ErrorRadius (Metres)"]=$ErrorRadius
 $ScriptContext.ReturnCollection.Add($dataObject)
 $i++
 } 
}

 

Because I need to drive the contextual PowerShell Web Browser widget (section 3) from the PowerShell Grid Widget (section 2), the script used in section 3 needs to locate the exact event selected in section 2. As per Oleg’s article, based on his experiment, the only property passed between widgets is the “Id” property (of the data object). therefore, instead of using an auto increment number as the value for “Id” property as demonstrated in the previous screenshot from Oleg’s blog, I assigned the actual event Id as the data object Id so script in section 3 can use the event ID to retrieve data from the particular event.

From Section 2:

image

From Section 3:

image

Conclusion

Please keep in mind, the only property (and its value) for $globalselectedItems that travels between contextual widgets is “Id” property. if you want to drive another contextual widget based on the data passed from a PowerShell Grid Widget, please make sure you use the actual Id of the OpsMgr object (monitoring object, class, event, alert, etc…) so the next widget can use this Id to retrieve the object from OpsMgr.

PowerShell Script: Remove Obsolete References from Unsealed OpsMgr Management Packs

Written by Tao Yang

Background

Last month, in TechEd North America, Cameron Fuller demonstrated a PowerShell script to search and remove obsolete MP references from an unsealed management pack. The script was written by Cameron’s colleague Matthew Dowst. You can watch Cameron’s presentation here and get the script here.

After TechEd, Cameron emailed me and suggest me to add this script into my OpsMgr Self Maintenance management pack. So before I built this functionality into the Self Maintenance MP, I have written a similar stand-alone script as a proof-of-concept.

Script Highlights:

The differences between my version and Matthew Dowst version are:

  • No need to export and re-import unsealed management packs: My script directly reads and updates MP contents using SCOM SDK. therefore unsealed MPs don’t need to be exported and re-imported.
  • Scan through all unsealed MPs: My script go through all unsealed MPs rather than individual XML files.
  • Option to backup MPs before changes are made: the script accept parameters to backup original unsealed MPs before any changes are made.
  • Option to increase MP version or keep version the same: Users can choose whether the MP version should be increased.
  • Allow test run (-WhatIf): Users can use –WhatIf switch to test run the script before changes are made.
  • MP Verify: the script verifies the MP before and after changes. if MP verify fails (including pre-existing errors), no changes will be made to the particular MP.
  • Allow Users to customize a “white list” for common MPs: When obsolete references are detected for the “common management packs” defined in the CommonMPs.XML (placed in the same folder as the script), these references will be ignored. This is because these common management packs are referenced in many out-of-box unsealed management packs by default. Additionally, since it is very unlikely these management packs will ever be deleted from the management group, therefore it should not be an issue when they are referenced in other management packs. Users can manually add / remove MPs from the list by editing the CommonMPs.XML. I have pre-populated the white list and included the following MPs:
    • Microsoft.SystemCenter.Library
    • Microsoft.Windows.Library
    • System.Health.Library
    • System.Library
    • Microsoft.SystemCenter.DataWarehouse.Internal
    • Microsoft.SystemCenter.Notifications.Library
    • Microsoft.SystemCenter.DataWarehouse.Library
    • Microsoft.SystemCenter.OperationsManager.Library
    • System.ApplicationLog.Library
    • Microsoft.SystemCenter.Advisor.Internal
    • Microsoft.IntelligencePacks.Types
    • Microsoft.SystemCenter.Visualization.Configuration.Library
    • Microsoft.SystemCenter.Image.Library
    • Microsoft.SystemCenter.Visualization.ServiceLevelComponents
    • Microsoft.SystemCenter.NetworkDevice.Library
    • Microsoft.SystemCenter.InstanceGroup.Library
    • Microsoft.Windows.Client.Library

Instruction:

You can run this script on any computers have OpsMgr 2012 console /agent / management server installed. The script includes a help documentation. you can access it via:

get-help .\MPReferencesCleanUp.ps1 –full

SNAGHTML436c9dc6

Examples:

#1. Test run using -WhatIf: .\MPReferencesCleanUp.ps1 -ManagementServer “OPSMGRMS01″ –BackupBeforeModify –BackupLocation “C:\Temp” -IncrementVersion –WhatIf

image

#2. Real run without –WhatIf: .\MPReferencesCleanUp.ps1 -ManagementServer “OPSMGRMS01″ –BackupBeforeModify –BackupLocation “C:\Temp” –IncrementVersion

image

Download

The script can be downloaded HERE.

What’s next?

As I mentioned in the beginning, the next version of the OpsMgr 2012 Self Maintenance MP will have the ability to detect and remove these obsolete references. The MP is pretty much done. I’ve sent it to few people to test. I should be able to publish it in few days. Despite the new functionalities of the self maintenance MP, this script will still be a good standalone tool to run ad-hoc when needed.

Credit

I’d like to thank the following people for testing and advices provided to this script (in random order):

  • Cameron Fuller
  • Raphael Burri
  • Marnix Wolf
  • Bob Cornelissen
  • Dan Kregor

I also want to thank Matthew Dowst for the original script and Matthew Long for his blog post where I got the ideas from.

Lastly, as always, please feel free to contact me if you have questions / issues.

Programmatically Generating the OpsMgr 2012 Alert Update Connector Configuration XML

Written by Tao Yang

Background

After been working on a project for over a year, I’ve start to see some light at the end of the tunnel. The last task I have in order to production-transition the 4 OpsMgr 2012 R2 management groups that I have designed and built is to configure integration between our ticket logging tool and OpsMgr to allow alerts to be automatically logged as IM’s.

Back in the OpsMgr 2007 days, before I started with the organisation, one of my colleagues have designed a set of very comprehensive Opalis policies (yes, they were called policies instead of runbooks back then) to populate various information for alerts such as product types, problem types, endpoints NetBIOS names, etc. then forward alerts to the ticketing system. In my opinion, my colleague did a very good job designing those Opalis policies and it was bullet-proof back then. But as the time goes by, we have been writing / introducing new management packs to monitor additional applications. This set of Opalis policies have become a pain in the butt to update to keep up with the changes because the logics have become really complicated.

Now, it’s up to me to migrate this set of Opalis policies to Orchestrator 2012 R2 and modify them to work with each OpsMgr 2012 R2 management groups. Because we did not just build a 2012 management group for each 2007 management group and we will have different agents / management packs in each 2012 MG, also in the new environment, we are going to have different support groups managing same applications (but different groups of agents), so we are moving to a multi-tenant setup if you like. So when I opened up the old Opalis policies and had a look, I’ve decided to give the 2012 Alert Update Connector a try and see if it will help me simplifies the Orchestrator runbooks.

My Initial Experience with Alert Update Connector

Because of these two excellent blog posts, It was very easy for me to setup the connector to test:

OpsMgr: Public release of the Alert Update Connector

SCOM Alert Updater Service – connector example updating SCOM alerts

In my opinion, based on my requirements, the only place that I think that needs improvement is how the configuration XML file is populated using the GUI tool(ConnectorConfiguration.exe):

image

Improvements required in my opinion:

01. Perf and event collection rules are available for selection (i.e. all the highlighted ones above). These rules will never generate alert, There is no need to add them to the configuration XML.

02. Although I can select multiple workflows at once, and specify the fields to update, it’s still a manual process and very time consuming if I want to configure all alerts in a management group. Also, being manual means the process is prone to human error. I would love to be able to configure all alerts at once, in bulk. it’s like cherry picking using hands VS. harvesting the entire field using a harvester.

SNAGHTML11522d3b

03. It’s hard to find workflows in the configuration xml which this GUI tool populated:

image

I’ve quickly generated a XML using ConnectorConfiguration.exe as shown above. I can’t really identify the workflow by just reading it.

Solution

In order to overcome these issues, and establish a process to maintain and update the configuration XML in the years to come, I have written a PowerShell script to generate the Alert Update Connector configuration XML based on a set of policies I have defined.

This script (called “ConfigAlertUpdateConnector.ps1”) is expecting an input XML file called “ConfigAlertUpdateConnector.xml” from the same directory. The “ConfigAlertUpdateConnector.xml” stores all the policies that I have defined.

Let’s look at the finishing piece first. The output of this script looks like this:

image

As you can see, not only every eligible rule / monitor has been populated according to the policies I defined, I added a comment line (highlighted) that contains the following information:

  • Workflow type (rule or monitor)
  • Rule / Monitor Name
  • Rule / Monitor Display Name
  • Target Class Name
  • Target Class DisplayName

it would be so much easier to search for a particular alert in this XML than the one generated by the GUI interface. We can simply copy the monitor / rule display name from the Operations Console and search in XML:

Display name from the Operations console:

SNAGHTML16816481

Search in XML:

SNAGHTML16828dce

In the script, I have also filtered out all rules and monitors that do not generate alerts so they won’t appear in the output XML.

Now let’s take a look at the “ConfigAlertUpdateConnector.xml”:

image

Each Policy is defined within a <AlertUpdateRule> tag. Under <AlertUpdateRule>, There is a <ClassSearchPhrase> tag. you can specify the search phrase for either target class name or display name, or both. When both name and display name are specified, both criteria must be true during search. For any classes that have returned from the search result, the alerts generated by any workflows targeting these classes will have the properties updated as what’s defined in the <PropertiesToModify> tag. Note, the schema within <PropertiesToModify> is same as the Alert Update Connector configuration file (the output).

Hint: Using Name VS Display Name in <ClassSearchPhrase>

The Name refers to the actual class ID from the management pack where the target class is defined. i.e. Some classes defined in VMM 2012 MP:

image

The Display Name is what you see in the Operations Console.

SNAGHTML1699fb1e

As you can see, normally, all classes defined in a particular MP will have the same prefix. in this case, with SCVMM 2012, the prefix is “Microsoft.SystemCenter.VirtualMachineMananager.2012”.

all VMM 2008 classes will have “Microsoft.SystemCenter.VirtualMachineMananager.2008”. So if I want to update all the alerts generated from Microsoft’s VMM MPs regardless the version, I’d use “Microsoft.SystemCenter.VirtualMachineMananager” as the NAME search phrase.

Another example, if I want to update any alerts generated for any “disks” related classes defined in Windows ServerOS MPs, I’d use both Name and Display search phrase:

  • DisplayName=”disk”
  • Name=”Microsoft.Windows.Server”

This leads to another issue. I thought I had everything covered, until I configured Fujitsu PRIMERGY server MP (sorry to use Fujitsu as an example in my blog again :P).

Use of Exceptions

If I open up Fujitsu MP version 6.0.0.5 in MP Viewer, there are many server components have been defined, such Network component:

image

But when I looked at the rules in this MP, all the ones related to the network component are targeting the top level Fujitsu PRIMERGY Server class rather than the Network component:

image

In fact, all the rules in this MP are targeting the Server class. I’m not sure how many MPs out there are targeting workflows in “less-appropriate” classes, so in order to work around this issue, I have coded my script to also process exceptions. This is why in my screenshot for “ConfigAlertConnector.xml” above, in the Fujitsu section, I have a lot of exceptions defined:

image

As shown above, by default, any Fujitsu alerts will have CustomField1 updated to “FUJ_MISC”, which is the default value. However, if the workflow’s (rule / monitor) Display Name contains the phrase “network”, the value for CustomField1 will be set to “FUJ_NIC”. The other 2 default properties defined (ResolutionState and Owner”) will remain the same. In the output xml file, it looks like this:

image

The first one have the “network” exception applied so the value has set to “FUJ_NIC”. the second one does not have any exceptions applied so it has the default value of “FUJ_MISC”.

Note: When exceptions are specified in the policies, the script will only apply an exception if both property name and GroupIdFilter match the default value:

image

Executing “ConfigAlertUpdateConnector.ps1”

Once all the policies have been configured in “ConfigAlertUpdateConnector.xml”, and this XML file is placed at the same folder as the ps1 script, we can simply run the script without any parameters. If the output file already exists in the script directory, the script will append the output file name with the current time stamp and move it to a sub folder called “Archive”. In my work’s fully tuned test management group, this script took less than 2 minutes to run, and generated the config file containing just less than 3000 workflows for Alert Update Connector.

In future, when we add new management packs or update / delete existing management packs, we can simply make minor modifications to the existing policies in “ConfigAlertUpdateConnector.xml” and re-run this script to generate the config file for Alert Update Connector.

You can download the script, the sample “ConfigAlertUpdateConnector.xml” and the sample output file HERE.

Lastly, I encourage anyone using the OpsMgr 2012 Alert Update Connector to try this script and any feedbacks are welcome. I believe I have covered everything in terms of how to configure the input xml (“ConfigAlertUpdateConnector.xml”). If I have missed anything, please feel free to drop me an email.

PowerShell Functions: Get OpsMgr Alert Generating Rules and Monitors

Written by Tao Yang

This is my second post today. Bad weather, both wife and daughter have got flu. So I’m sitting home catching up with blogs…

I wrote 2 functions as part of a PowerShell script I’ve been working on: Get-AlertRules and Get-AlertMonitors.

As the names suggest, these two functions get all Rules / Monitors of a particular monitoring class that generate alerts.

I didn’t end up using these 2 functions in my script, but I thought they are too good to be trashed. so I thought I’ll put them here for future reference.

Get-AlertRules:

Function Get-AlertRules
{
PARAM (
[Parameter(Mandatory=$true,HelpMessage="OpsMgr Management Group Connection" )][Microsoft.EnterpriseManagement.ManagementGroup] $ManagementGroup,
[Parameter(Mandatory=$false,HelpMessage="Monitoring Class Name" )][string] $MonitoringClassName = $null
)
$arrAlertRules = New-object System.Collections.ArrayList
#Get GenerateAlert WriteAction module
$HealthMPId = [guid]"0abff86f-a35e-b08f-da0e-ff051ab2840c" #this is unique
$HealthMP = $MG.GetManagementPack($HealthMPId)
$AlertWA = $HealthMP.GetModuleType("System.Health.GenerateAlert")
$AlertWAId = $AlertWA.Id
#firstly get all monitoring classes
#Populate Search criteria
If ($MonitoringClassName)
{
$strClassCriteria = "Name = '$MonitoringClassName'"
} else {
$strClassCriteria = "Name LIKE '%'"
}
$ClassCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitoringClassCriteria($strClassCriteria)
$MonitoringClasses = $MG.GetMonitoringClasses($ClassCriteria)
Foreach ($MC in $MonitoringClasses)
{
$MCId = $MC.Id
$strRuleCriteria = "TargetMonitoringClassId = '$MCId'"
$RuleCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitoringRuleCriteria($strRuleCriteria)
$Rules = $MG.GetMonitoringRules($RuleCriteria)
Foreach ($rule in $Rules)
{
#Unfortunately, we cannot use a member module name/id in MonitoringRUleCriteria.
#So we have to manually filter out the rules with GenerateAlert Write Action Module
#Check if it has a GenerateAlert WriteAction module
$bAlertRule = $false
Foreach ($WAModule in $Rule.WriteActionCollection)
{
if ($WAModule.TypeId.Id -eq $AlertWAId)
{
#this rule generates alert
$bAlertRule = $true
} else {
#need to detect if it's using a customized WA which the GenerateAlert WA is a member of
$WAId = $WAModule.TypeId.Id
$WASource = $MG.GetMonitoringModuleType($WAId)
#Check each write action member modules in the customized write action module...
Foreach ($item in $WASource.WriteActionCollection)
{
$itemId = $item.TypeId.Id
If ($ItemId -eq $AlertWAId)
{
$bAlertRule = $true
}
}
}

if ($bAlertRule)
{
#Add to arraylist
[void]$arrAlertRules.Add($rule)
}
}
}
}
,$arrAlertRules
}

Get-AlertMonitors:

Function Get-AlertMonitors
{
PARAM (
[Parameter(Mandatory=$true,HelpMessage="OpsMgr Management Group Connection" )][Microsoft.EnterpriseManagement.ManagementGroup] $ManagementGroup,
[Parameter(Mandatory=$false,HelpMessage="Monitoring Class Name" )][string] $MonitoringClassName = $null
)
$arrAlertMonitors = New-object System.Collections.ArrayList
#firstly get all monitoring classes
#Populate Search criteria
If ($MonitoringClassName)
{
$strClassCriteria = "Name = '$MonitoringClassName'"
} else {
$strClassCriteria = "Name LIKE '%'"
}
$ClassCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitoringClassCriteria($strClassCriteria)
$MonitoringClasses = $MG.GetMonitoringClasses($ClassCriteria)
Foreach ($MC in $MonitoringClasses)
{
$MCId = $MC.Id
$strMonitorCriteria = "TargetMonitoringClassId = '$MCId' AND AlertOnState IS NOT NULL"
$MonitorCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitorCriteria($strMonitorCriteria)
$Monitors = $MG.getmonitors($MonitorCriteria)
Foreach ($Monitor in $Monitors)
{
#Add to arraylist
[void]$arrAlertMonitors.Add($Monitor)
}
}
,$arrAlertMonitors
}

Both functions are expecting an OpsMgr management group connection and the name (not the display name, but the Class ID from the management pack where the class is defined). so in order to use these 2 functions, I’ll need 2 other functions:

Load-SDK:

function Load-SDK()
{
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager") | Out-Null
}

Get-MonitoringClass:

Function Get-MonitoringClass
{
PARAM (
[Parameter(Mandatory=$true,HelpMessage="OpsMgr Management Group Connection" )][Microsoft.EnterpriseManagement.ManagementGroup] $ManagementGroup,
[Parameter(Mandatory=$true,HelpMessage="Monitoring Class Display Name" )][string] $MonitoringClassDisplayName
)
#Populate Search criteria
$strClassCriteria = "DisplayName = '$MonitoringClassDisplayName'"
$ClassCriteria = New-Object Microsoft.EnterpriseManagement.Configuration.MonitoringClassCriteria($strClassCriteria)
#Search monitoring class
$MonitoringClasses = $MG.GetMonitoringClasses($ClassCriteria)
$MonitoringClasses
}

as the name suggests, Load-SDK function loads OpsMgr SDK, when can then create the connection to the management group. Get-MonitoringClass function gets the Monitoring Class object based on it’s display name (the name you see in the Operations Console), such as this one:

SNAGHTML1f11d89

Here’s an example of how to these functions:

#Load SDK DLL's
Load-SDK

#Connect to the management group via management server "OpsMgrMS01":
$MGConnSetting = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings("OPSMGRMS01")
$MG = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MGConnSetting)

#Get the monitoring class
$MonitoringClassDisplayName = "Data Access Service"
$MonitoringClass = Get-MonitoringClass $MG $MonitoringClassDisplayName
$MonitoringClassName = $MonitoringClass.Name

#Display Monitoring Class Name
$MonitoringClassName

#Get Alert rules
$AlertRules = Get-AlertRules $MG $MonitoringClassName

#Rule Count
$alertRules.count

#Alert Monitors
$AlertMonitors = Get-AlertMonitors $MG $MonitoringClassName

#Monitor Count
$AlertMonitors.Count

SNAGHTML1f339a2

Logics in these 2 functions:

Get-AlertRules:

Searching for rules either have the “System.Health.GenerateAlert” module from System.Health.Library MP as a Write Action member module, or one of the rule’s Write Action member modules has “System.Health.GenerateAlert” as its member.

Get-AlertMonitors:

This function is much easier to write than Get-AlertRules. I’ simply search for monitors that “AlertOnState” property is not NULL. Please keep in mind this function does not only return unit monitors, but also aggregate and dependency monitors.

Both functions return a “System.Collections.ArrayList” containing the rules / monitors. Since I used the OpsMgr SDK directly, instead of it’s PowerShell snapin or module. these functions should work in both 2007 and 2012. – And this is one of the reasons why I always just use SDK, hardly use the snapin or the module :)

I’ve also zipped up all the code used in this article. You can download them HERE. I know it’s a bit hard to read the code in WordPress :)