Using PowerShell, Azure Automation, and OMS – Part II
So last time we learned how to upload our custom modules into Azure Automation so we can start using them in Azure Automation Runbooks. This week we’re going to take a look at configuring a runbook to see what kind of data we can ingest from OMS Webhook data, and how we can leverage that data to pass into our functions.
Creating the Runbook Script
So first off, let’s talk about basic runbooks and running them against objects in Azure. As previously discussed, when your automation account is created, it creates with it an AzureRunAsAccount. This account is configured to act on behalf of the user that has access to the automation account and the runbooks in order to perform the runbook task. In order to leverage this account, you need to invoke it in the runbook itself. You can actually find an example of this snippet in the AzureAutomationTutorialScript runbook in your automation account.
$connectionName = "AzureRunAsConnection" try { # Get the connection "AzureRunAsConnection " $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName "Logging in to Azure..." Add-AzureRmAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId
-ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint } catch { if (!$servicePrincipalConnection) { $ErrorMessage = "Connection $connectionName not found." throw $ErrorMessage } else{ Write-Error -Message $_.Exception throw $_.Exception } }So now that we’ve got our opening snippet, we’ll add that into a new .ps1 script file in our preferred integrated scripting environment tool and get to work.
Now, in order to be able to ingest data from an OMS Alert, we need to be able to pass the data to our Azure Automation runbook. In order to do so, we only need to add a $WebHookData parameter to the runbook and specify the data type as object.
Param ( [Parameters()][object]$WebHookData ) Now, we need to convert that data from a JSON object into something readable in our output. Webhook data is presented with three primary datasets - WebhookName, RequestHeader, and RequestBody. WebhookName, obviously is the name of the incoming webhook. RequestHeader is a hash table containing all of the header data for the incoming requestion. And finally, RequestBody is the body of the incoming request. This is where the data we want to parse will reside. Specifically, it will reside under the SearchResults property of the RequestHeader dataset.
$WebhookData.WebhookName $WebhookData.RequestHeader $WebhookData.RequestBody So let’s configure our runbook to display the incoming data to examine what we have to play with.
$SearchResults = (ConvertFrom-Json $WebhookData.RequestBody).SearchResults.value $SearchResults Publish the Runbook
Now, we’ll go ahead and save our script as a .ps1 file and upload it to our automation account with the Import-AzureRmAutomationRunbook cmdlet.
Import-AzureRmAutomationRunbook -Path 'C:\Scripts\Presentations\OMSAutomation\ExampleRunbookScript.ps1' -Name WebhookNSGRule -Type PowerShell -ResourceGroupName $AutoAcct.ResourceGroupName -AutomationAccountName $AutoAcct.AutomationAccountName -Published And now we can see our return.
And if we check through the UI, we can see a brand-new, shiny runbook sitting in our automation account! Now, we can configure a basic alert to monitor in OMS.
Create an Alert
For the purposes of this example, I’ve create a couple of virtual machines with network security group rules for HTTP:80 and RDP:3389 accepting connections from anywhere. I do not recommend doing this for a production virtual machine. /endDisclaimer
As you can well expect, these machines are throwing MaliciousIP traffic alerts in Operations Management Suite’s console:
So if we click on the MaliciousIP flag, it’ll take us to the Log Search screen. This includes the query data that we can use for the alert. However, you’ll want to clean up the query data a bit to generalize it. In this example, the query is specific to the country that is displayed in the given flag. But if we remove the country specific portion of the query, it’ll allow us to cast a wider net and get data on potentially malicious traffic from any given country.
Canned Query: MaliciousIP=* AND (RemoteIPCountry=* OR MaliciousIPCountry=*) AND (((Type=WireData AND Direction=Outbound) OR (Type=WindowsFirewall AND CommunicationDirection=SEND) OR (Type=CommonSecurityLog AND CommunicationDirection=Outbound)) OR (Type=W3CIISLog OR Type=DnsEvents OR (Type = WireData AND Direction!= Outbound) OR (Type=WindowsFirewall AND CommunicationDirection!=SEND) OR (Type = CommonSecurityLog AND CommunicationDirection!= Outbound))) (RemoteIPCountry="People's Republic of China" OR MaliciousIPCountry="People's Republic of China") Modified Query: MaliciousIP=* AND (RemoteIPCountry=* OR MaliciousIPCountry=*) AND (((Type=WireData AND Direction=Outbound) OR (Type=WindowsFirewall AND CommunicationDirection=SEND) OR (Type=CommonSecurityLog AND CommunicationDirection=Outbound)) OR (Type=W3CIISLog OR Type=DnsEvents OR (Type = WireData AND Direction!= Outbound) OR (Type=WindowsFirewall AND CommunicationDirection!=SEND) OR (Type = CommonSecurityLog AND CommunicationDirection!= Outbound))) 
After testing our query to make sure it’s valid, we can now hit the alert button and configure the alert. Here you’ll need to give it an alert name, a schedule, and number of results before it triggers the alert. You’ll also want to select the Runbook option under actions and select the test runbook we created. Then we hit save, and wait for our alert to trigger and the runbook to fire.
And as you can see, I didn’t have to wait long:
Validate our Data
If we click on one of the completed instances, and navigate to the output blade, we can now see the data we’re receiving from our triggered alert. This particular data shows that inbound traffic from Colombia is attempting an RDP connection to my virtual machine. With the inbound IP Address and target system name, we now have enough data to be able to create a full-blown auto-remediation solution.
`Logging in to Azure… Environments Context
{[AzureCloud, AzureCloud], [AzureChinaCloud, AzureChinaCloud], [AzureUSGovernment, AzureUSGovernment]} Microsoft.Azur…
Computer : server1
MG : 00000000-0000-0000-0000-000000000001
ManagementGroupName : AOI-cb0eefe8-b88f-47ce-ae91-dbc46df99751
SourceSystem : OpsManager
TimeGenerated : 2017-07-21T12:17:37.45Z
SessionStartTime : 2017-07-21T12:16:52Z
SessionEndTime : 2017-07-21T12:16:52Z
LocalIP : 10.119.192.10
LocalSubnet : 10.119.192.0/21
LocalMAC : 00-0d-3a-03-ea-a6
LocalPortNumber : 3389
RemoteIP : 200.35.53.121
RemoteMAC : 12-34-56-78-9a-bc
RemotePortNumber : 4935
SessionID : 10.119.192.10_3389_200.35.53.121_4935_2184_2017-07-21T12:16:52.000Z
SequenceNumber : 0
SessionState : Listen
SentBytes : 20
ReceivedBytes : 40
TotalBytes : 60
ProtocolName : TCP
IPVersion : IPv4
SentPackets : 1
ReceivedPackets : 2
Direction : Inbound
ApplicationProtocol : RDP
ProcessID : 888
ProcessName : C:\Windows\System32\svchost.exe
ApplicationServiceName : ms-wbt-server
LatencyMilliseconds : 116
LatencySamplingTimeStamp : 2017-07-21T12:16:52Z
LatencySamplingFailureRate : 0.0%
MaliciousIP : 200.35.53.121
IndicatorThreatType : Botnet
Confidence : 75
Severity : 2
FirstReportedDateTime : 2017-07-20T20:10:32Z
LastReportedDateTime : 2017-07-21T11:25:11.0661909Z
IsActive : true
ReportReferenceLink : https://interflowinternal.azure-api.net/api/reports/download/generic/webbot.json
RemoteIPLongitude : -75.88
RemoteIPLatitude : 8.77
RemoteIPCountry : Colombia
id : 149270bc-74fc-13d0-34a9-3fd665a457b2
Type : WireData
__metadata : @{Type=WireData; TimeGenerated=2017-07-21T12:17:37.45Z}
`It’s a long road, and we’re almost there! Next week, I’ll take you through my process of modifying my module to directly ingest webhook data, and how we can take our OMS queries and deploy them to other Operations Management Suite solutions using PowerShell. See you then!
Part I - Azure Automation Account Creation and Adding Modules
Part II - Configuring Azure Automation Runbooks And Understanding Webhook Data
Part III - Utilizing Webhook Data in Functions and Validate Results - Coming Soon!
Related Articles
PowerShell Escape Room
PowerShell Escape Room by Michiel Hamers by Michiel Hamers https://about.me/michielhamers/ Why on earth you want to create an Escape Room with PowerShell as backend? I’ve always been a fan of escape rooms, so I decided to create my own for my kids. I wanted to make it something that would be challenging and fun for them, but also educational. I decided to use PowerShell as the backend for the escape room, as I’m a PowerShell developer and I thought it would be a great way to learn more about the language.
Microsoft Graph PowerShell Module: Getting Started Guide
Microsoft Graph PowerShell Module: Getting Started Guide by Jeff Brown Microsoft is retiring the Azure AD Graph API sometime after June 30, 2023 (announcement). This retirement includes the Azure AD PowerShell module. In its place, Microsoft has released the Microsoft Graph PowerShell module. The Microsoft Graph PowerShell module is the next-generation way of managing Microsoft cloud services using PowerShell. If you have used MSOnline or Azure AD PowerShell in the past, you’ll need to read on to learn about this new module.
ICYMI: PowerShell Week of 08-October-2021
Topics include VMWare, Windows 11, Web Reports and more… Special thanks to Robin Dadswell, Prasoon Karunan V, Kiran Patnayakuni and Kevin Laux How to gather your vCenter inventory data with this VMware PowerShell script by Scott Matteson on 7th October Inventory reports are a common request when administering a VMware vCenter environment. Learn how this VMware PowerShell script can make such requests quick and easy Building a Web Report in PowerShell, use the -Force Luke by Chris Noring on 8th October