Skip to content
adatum
  • Home
  •  About adatum
  •  Learn Azure Bicep
  •  SCOM Web API
Automation

Script to add SCOM agent management group

  • 03/10/201607/01/2025
  • by Martin Ehrnst

 

We wanted to change how SCOM agents is installed and configured. That involved some scripting. As a part of the process we add a management Group to the agent after it is installed. SCOM 2016 is also released now so if you want to migrate instead of upgrading, you can use this script to add an additional MG.

Script will have two mandatory parameters management server and management Group name. A Third parameter is optional, which is the port number and defaults to 5723. You can save the below script as Add-SCOMManagementGroup.ps1

<#

.SYNOPSIS
    Adding management group to agent

.DESCRIPTION
    Adding first or additional management group to agent. for example use this to multihome agent when migrating to a new management group.

.EXAMPLE
    Add-SCOMManagementGroup.ps1 -ManagementServer SCOM01.domain -MGMTGroupName SCOMMG

    Adds SCOMMG to the agent and set SCOM01 as primary management server. Default port 5723

.EXAMPLE
    Add-SCOMManagementGroup.ps1 -ManagementServer [Primary MS] -MGMTGroupName [Management group name] -port [INT]

    Adds SCOMMG to the agent and set SCOM01 as primary management server and set port you specify

.NOTES
    Author: Martin Ehrnst /Intility AS

#>

Param(
  [Parameter(Mandatory=$True)]
   [string]$ManagementServer,
	
   [Parameter(Mandatory=$True)]
   [string]$MGMTGroupName,

   [Parameter(Mandatory=$false)]
   [int]$Port = "5723"
)

$ErrorActionPreference='Stop'

Write-Warning "This will restart the agents health service"

#Adding MG to the agent
try{
$Agent = New-Object -ComObject AgentConfigManager.MgmtSvcCfg
$Agent.AddManagementGroup("$MGMTGroupName", "$ManagementServer", "$Port")}

catch{
CLS
Write-host "An error occured please se exeption message:"

Write-error $_.Exception.Message
BREAK
}

get-service HealthService | Restart-Service

Write-Host "Agent connected to the following management groups"
$Agent.GetManagementGroups()

 

 

Share this:

  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on X (Opens in new window) X
  • Click to share on Reddit (Opens in new window) Reddit
MPAuthoring

Operations Manager and ‘external’ services pt1 (the weather management…

  • 23/09/201607/01/2025
  • by Martin Ehrnst

This post will be the first in a series of posts covering how you can use System Center Operations Manager (SCOM) With external systems. This is a ‘off work’ Project for me where i try to use several external systems which in some whay communicate or can relate to a workflow running in SCOM.

While writing this, we are on the edge where SCOM 2016 will release shortly, but i will be using 2012 R2 in this series.

 

Now for this first post, i will start to create a maangement pack monitoring the weather conditions for a few locations i chose. I will use yr.no – a service provided by Norwegian Meteorological Institute and NRK.YR.no has a XML API and thats readable by Powershell and then also SCOM.

I remembered Trond Hindenes made a MP for this years ago and i was Lucky to find his blog post about it as well – that made Things alot easier. Thank you. Before we start I would also like to say, if you want do do MP Authoring With Visual studio and Authoring Extensions i suggest you check out Kevin Holmans VSAE fragments. They make a huge difference when trying to understand and create discoveries, monitors etc.- I did not use them when i first started creating this MP

Create the classes and ‘application’

Trond made this easy and i used his model as a spring Board and createt to classes and a relationship. One class will define the “Weather server” the server which is running Our Application. Nothing fancy at all. The Application is a registry key, a string property and a CSV file. I have Limited experience in MP Authoring, but i have created some small MP’s before, using VSAE, Silect MP Author etc. This example will be carried out using VSAE.

This Picture shows how i have organized my management pack project

vsae

As Trond I used registry to define where the Application is installed. Under HKLM\Software\TheWeatherSolution i have a New key called WeatherDB and further a string value, “WeatherDBConfigPath”. The string is a path to where i have created a CSV-file which has the location name and the xml-url from yr.no. Simple comma separated file With headers. Hemsedal is still present as it is the top skiing resort in Norway, especially if youre in to off piste skiing like me.

LocationName,YRnoURL
Hemsedal,http://www.yr.no/place/Norge/Buskerud/Hemsedal/Hemsedal_Skisenter/forecast.xml
Oslo,http://www.yr.no/place/Norway/Oslo/Oslo/Oslo/forecast.xml

using a csv is a chance from Tronds MP. So if you follow both examples trying to create Your own solution, make sure you notice this so you don’t end up scratching Your head without having to:)

Class1, WeatherDB

I created the first class which is based  Windows Local Application. If you want to create this exactly as i have, you willl have to change the base class which default is LocalApplicationComponent. WeatherDB has an extra property called ConfigPath. This property string will have the path to where i placed my CSV file

Code from vsae:

ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        
        <!-- In this section, modify the attributes based on your needs. Ensure the
             Base attribute matches the application you are modeling.
             More information can be found in the Management Pack Development Kit: 
             http://msdn.microsoft.com/en-us/library/ee533867.aspx -->
        <ClassType ID="TheWeatherSolution.WeatherDB" Base="Windows!Microsoft.Windows.LocalApplication" Accessibility="Internal" Abstract="false" Hosted="true" Singleton="false">
          
          <!-- Inside this section, you can add and remove properties as needed.
               More information can be found in the Management Pack Development Kit: 
               http://msdn.microsoft.com/en-us/library/ee533714.aspx -->
      
          <Property ID="ConfigPath" Key="false" Type="string" />

        </ClassType>
      
      </ClassTypes>
    </EntityTypes>
  </TypeDefinitions>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        
        <!-- This is the string users of the Operations Console and Web Console will see. 
             Descriptions are also helpful when the user is doing a search in the Console. -->
        <DisplayString ElementID="TheWeatherSolution.WeatherDB">
          <Name>Weather server Class</Name>
          <Description>Computers with weather location database</Description>
        </DisplayString>

        <!-- Uncomment the below section if you need to add a user friendly string for each property. -->
        
        <DisplayString ElementID="TheWeatherSolution.WeatherDB" SubElementID="ConfigPath">
          <Name>Configuration Path</Name>
          <Description>The path to where configuration files are stored</Description>
        </DisplayString>
        
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 

Class2, Weather Locations

Weather locations is a class based on LocalApplicationComponent and has a relationship to my WeatherDB class. Weather locations will be defined in the csv file created earlier. It has two Properties, LocationName and LocationURL +  the inherited Properties from it’s base class and relationship. LoactionName is the key property for this class.

Here is the full fragment from VSAE

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        
        <!-- In this section, modify the attributes based on your needs. Ensure the
             Base attribute matches the application you are modeling.
             More information can be found in the Management Pack Development Kit: 
             http://msdn.microsoft.com/en-us/library/ee533867.aspx -->
        <ClassType ID="TheWeatherSolution.WeatherLocation" Base="Windows!Microsoft.Windows.ApplicationComponent" Accessibility="Internal" Abstract="false" Hosted="true" Singleton="false">
          
          <!-- Inside this section, you can add and remove properties as needed.
               More information can be found in the Management Pack Development Kit: 
               http://msdn.microsoft.com/en-us/library/ee533714.aspx -->
    
          <Property ID="LocationName" Key="true" Type="string" />
          <Property ID="LocationURL" Key="false" Type="string" />


        </ClassType>
      
      </ClassTypes>
      <RelationshipTypes>

        <RelationshipType

          ID="TheWeatherSolution.WeatherLocation.Realtionship"

          Base="System!System.Hosting"

          Accessibility="Internal"

          Abstract="false">

          <Source ID="Source" Type="TheWeatherSolution.WeatherDB" />

          <Target ID="Target" Type="TheWeatherSolution.WeatherLocation" />

        </RelationshipType>

      </RelationshipTypes>
    </EntityTypes>
  </TypeDefinitions>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        
        <!-- This is the string users of the Operations Console and Web Console will see. 
             Descriptions are also helpful when the user is doing a search in the Console. -->
        <DisplayString ElementID="TheWeatherSolution.WeatherLocation">
          <Name>WeatherLocation Class</Name>
          <Description></Description>
        </DisplayString>

        <!-- Uncomment the below section if you need to add a user friendly string for each property. -->
        
        <DisplayString ElementID="TheWeatherSolution.WeatherLocation" SubElementID="LocationName">
          <Name>Location Name</Name>
          <Description>The name of the weather forcast location.</Description>
        </DisplayString>
        <DisplayString ElementID="TheWeatherSolution.WeatherLocation" SubElementID="LocationURL">
          <Name>Location URL</Name>
          <Description>the yr.no URL for this location</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
    <LanguagePack ID="NOR" IsDefault="false">
      <DisplayStrings>

        <!-- This is the string users of the Operations Console and Web Console will see. 
             Descriptions are also helpful when the user is doing a search in the Console. -->
        <DisplayString ElementID="TheWeatherSolution.WeatherLocation">
          <Name>WeatherLocation Class</Name>
          <Description></Description>
        </DisplayString>

        <!-- Uncomment the below section if you need to add a user friendly string for each property. -->

        <DisplayString ElementID="TheWeatherSolution.WeatherLocation" SubElementID="LocationName">
          <Name>Location Name</Name>
          <Description>The name of the weather forcast location.</Description>
        </DisplayString>
        <DisplayString ElementID="TheWeatherSolution.WeatherLocation" SubElementID="LocationURL">
          <Name>Location URL</Name>
          <Description>the yr.no URL for this location</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

Relationships was somewhat New to me, i have cut out the relationship section here. Its located just below the class types section.

<RelationshipTypes>
        <RelationshipType ID="TheWeatherSolution.WeatherLocation.Realtionship"
          Base="System!System.Hosting"
          Accessibility="Internal"
          Abstract="false">
          <Source ID="Source" Type="TheWeatherSolution.WeatherDB" />
          <Target ID="Target" Type="TheWeatherSolution.WeatherLocation" />
        </RelationshipType>
      </RelationshipTypes>

Next step would be to import the MP and see if you have two working discoveries. You can confirm this by using “Discovered Inventory”. Unfortinatly, i forgot to take a screenshot at this stage, but hopefully, after everything is discovered it should look something like this (only not monitored) 🙂

classmonitored

Creating a monitor for the location Objects

My goal With this Project isn’t exactly to do weather forecasting or monitoring – there are a few other Tools for that, but as I said I want to test scom and my capabilities. Other than that, i do not want Objects being unmonitored so i created a “location observation freaking Cold monitor” which will generate an alert when observations og below the configured degree. I set -15 deg. celcius. That’s when Norwegians tend to say. “It’s Cold today”

I found that each loaction on YR had something called Observations. I do knot know, but i assume it more like real time data than forecasting. Each location has a few obeservations from surrounding areas, i chose to select the first one. In Powershell thi is how it looks.

[xml]$yr = Invoke-WebRequest -Uri "http://www.yr.no/sted/Norway/Oslo/Oslo/Oslo/forecast.xml"
$Observations = $yr.SelectNodes("//observations").weatherstation | select-object -First 1
[int]$Obstemperature = $Observations.temperature.value
$temperatureUnit = $Observations.temperature.unit
if ($Obstemperature -lt "-15"){
Write-Host "IT IS FREAKING COLD, $obstemperature $temperatureUnit"}
else{ write-host "youre good"}

In PowerShell it seems to be working. No error handling in this Version thoug

isetest

 

After adding the SCOM bits to my script, this is how it looks

                  param([string]$LocationURL,[string]$LocationName)
                  # Load MomScript API and PropertyBag function
                  $api = new-object -comObject 'MOM.ScriptAPI'
                  $bag = $api.CreatePropertyBag()

                  #Log script event that we are starting task
                  $api.LogScriptEvent("TooCold.ps1",6789,0, "Starting toocold.ps1 script")

                  [xml]$yr = Invoke-WebRequest -Uri $LocationURL
                  #Getting the latest observation
                  $Observations = $yr.SelectNodes("//observations").weatherstation | select-object -First 1
                  [int]$Obstemperature = $Observations.temperature.value
                  $temperatureUnit = $Observations.temperature.unit
                  if ($Obstemperature -lt "15"){
                  $bag.AddValue("Result","BadCondition")
                  #$bag.AddValue("Description", "It is freaking cold observed temperature" + "$obstemperature" + "$temperatureUnit")
                  }
                  else{
                  $bag.addvalue("Result","GoodCondition")
                  }
                  $bag

 

To create the monitor i used Kevin Holmans fragments to and changed the Two state PowerShell fragment to my needs. I will try to go more in detail on this at a later stage, but for now this is all you get:)

The next part will cover how to use a rule or monitor against these locations and invoke another external system based on the status or alert of each Objects.

Share this:

  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on X (Opens in new window) X
  • Click to share on Reddit (Opens in new window) Reddit
Automation

Using webhook in scom subscription (POC)

  • 09/09/201607/01/2025
  • by Martin Ehrnst

Recently, I was at System Center Universe (Now, Experts Live) in Berlin. During one side session i got talk to Cameron Fuller (Microsoft MVP) and I asked if he knew if anybody had used azure automation and it’s webhook capabilites in a SCOM subscription.

At Intility (my employer) we have developed an alert central which handles alerts from Solarwinds and other systems we use daily. OpsMgr is one of few systems that still tap directly in to our ticketing system, but were working on a change here. Webhooks and azure automation is one thing were looking at.

My attempt (if possible), using webhooks and Azure automation is to be able to send alerts from SCOM, and not have something query for new alerts when there nothing to handle. Cameron quickly reached out to his fellow MVPs and a few ours later i got a reply. Turns out that Jakob Gottlieb Svendsen (MVP) from Coretech had used webhooks in a recovery task. He basicly done all the work now :).

http://blog.coretech.dk/jgs/azure-automation-scom-triggering-a-runbook-as-a-recovery-task-using-webhooks/ (read this :))

The rest of this post will quickly show how to.

 

  • Create azure automation account
  • Create a new runbook
  • Add webhook
  • Runbook parameter
  • SCOM Command Channel and subscription

 

Azure Automation Account

 

Search for automation accounts in services and add a new Automation account. Use an existing resource group or create a new. After wizard is finished we should have an account assigned to a subscription.

automationaccount

 

By now you have probably read Jakobs blog and you have a new runbook in place, but i will guide you through anyway 🙂

Create a new runbook and use “Powershell workflow”. Once finished you will be sent to the online editor which is fine for now, but i suggest you download azure automation addon for ISE if you plan to do a lot of scripting here 🙂

Azure Automation PS worflow will start like this. If you add script parameter and publish where able to create a webhook. Place your normal PS script between the two curly brackets.

workflow 'your runbook name'

{

Param [object]($WebhookData)

}

I have adde the parameter already, that way we are able to create webhook an parameter at the next step.

Next task is to create a webhook for your runbook. With a webhook you are able to call the runbook with a URL and also pass parameters with JSON data inside the url. (Heres where the parameter for your webhook and script comes in)

Remember, copy your webhook URL – it’s not available after it is created

webhook1

 

After youre ‘hooked’ add paramters and define where to run. For this test i just fire it off in azure, but you can run your script on prem with the hybrid worker. Use your script parameter in the webhook data input.

webhook

You have probably added your own script inside the Azure workflow already, but here is my OpsMgrAlertHandlerTEST script which is based on Jakobs example and will output some key alert datato the console. Instead of just output it to the console i can now pass this information to our alert central by triggering a new runbook or adding it directly within this script.

 

workflow OpsMgrAlertHandlerTEST

{

param (

[object]$WebhookData

)



    $WebhookName    =   $WebhookData.WebhookName

    $WebhookHeaders =   $WebhookData.RequestHeader

    $WebhookBody    =   $WebhookData.RequestBody



    $Inputs = ConvertFrom-JSON $webhookdata.RequestBody

    $ComputerName = $Inputs.ComputerName

$AlertName = $Inputs.Alert

$ResolutionState = $Inputs.State

$AlertID = $Inputs.AlertID



    Write-Output "Computername: $ComputerName"

Write-Output "Alert: $AlertName"

Write-Output "State: $ResolutionState"

Write-Output "ID: $AlertID"

Write-Output "$Inputs"

}

 

From scom we will use powershell to POST alert data with invoke-restmethod and the URL you copied from the webhook configuration, right?

Again Jakob is apparently our JSON webhook guy http://blog.coretech.dk/jgs/azure-automation-using-webhooks-part-1-input-data/

SCOM Command Channel and subscription

 

Our final step is to create a command channel, subscriber and a subscription to trigger the runbook. From the admin panel in scom create a new command notification channel

channel1

In settings we will add path to Powershell and a command to run. Remember. Webhook url and the parameters to POST

channel2

Here is my full commandline (i have removed my webhook uri here)

-executionpolicy Unrestricted -Command " &{Invoke-RestMethod -Method Post -Uri 'YOUR WEBHOOK URL' -Body (ConvertTo-Json -InputObject @{'ComputerName'='$Data[Default='Not Present']/Context/DataItem/ManagedEntityPath$\$Data[Default='Not Present']/Context/DataItem/ManagedEntityDisplayName$';'Alert'='$Data[Default='Not Present']/Context/DataItem/AlertName$';'State'='$Data[Default='Not Present']/Context/DataItem/ResolutionStateName$';'AlertID'='$Data/Context/DataItem/AlertId$'}) -ErrorAction Stop}"

Inside the JSON string we will pass Computer Name, Alert name and the resolution state. Modify this by using the picker on the right side. After you have created the channel, create a new subscriber to use with this channel and finally create the actual subscription

For this test/POC i have chosen to send all information alerts to this subscription. These are mostly rules i can close (and generate) during testing.

Subscriber and channel are the two we just created.

subscription

 

At this point you should have:

  • Azure automation account
  • Automation runbook, my example or your own
  • Web hook enabled
  • Command channel
  • Subscriber and subscription

 

Finally, lets test our solution. I have added all informational messages to this subscription. I will close one of those and cross my fingers. We can follow the process in azure portal

closealert


As you see the job is queued and in the output console we see the output from our webhook data
automationoutputwait

 

It worked!

automationoutput

 

 

As this is totally in  a proof of concept state for us i would greatly apriciate inputs on how we can accomplish the task using other methods.

As we see, using webhooks in a subscription works quite well. But i havent implemented it in our production environment or sent it to our alert central yet. I see some issues, one being limited by how many powershell scripts we can run at once. Jakob suggested maybe we will look in to creating a connector and let us query a subscription for new alerts but i haven’t gotten around to try it out.

 

Share this:

  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on X (Opens in new window) X
  • Click to share on Reddit (Opens in new window) Reddit

Posts pagination

1 … 7 8 9 10 11 12

Popular blog posts

  • SCOM Alerts to Microsoft Teams and Mattermost
  • How to move Azure blobs up the path
  • Creating Azure AD Application using Powershell
  • SCOM and OMS: The agents
  • Azure Application registrations, Enterprise Apps, and managed identities

Categories

Automation Azure Azure Active Directory Azure Bicep Azure DevOps Azure Functions Azure Lighthouse Azure Logic Apps Azure Monitor Azure Policy Community Conferences CSP Monitoring DevOps GitHub Guest blogs Infrastructure As Code Kubernetes Microsoft CSP MPAuthoring OMS Operations Manager Podcast Powershell Uncategorised Windows Admin Center Windows Server

Follow Martin Ehrnst

  • X
  • LinkedIn

RSS feed RSS - Posts

RSS feed RSS - Comments

Microsoft Azure MVP

Martin Ehrnst Microsoft Azure MVP
Adatum.no use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it. Cookie Policy
Theme by Colorlib Powered by WordPress