Log results from Azure Automation Runbooks directly to OMS

An easy way to keep track of Azure Automation runbook operations is to create log entries to OMS during execution.

There is a Rest API service as part of OMS that let's you post log entries directly into your OMS Workspace, allowing for easy searching and alerting of anything you're runbooks do.  There are some code samples provided, in the link above, that allow you to build your own functions to use this API, or you can use the hard work someone else has done and import the OMSIngestionAPI module, which is what I have done.

Before you start, you will need to have your OMS Workspace Name, ID, and key available.  You can get these from the OMS Workspace settings page.
I recommend using (and will use in this post) Azure KeyVault to hold your OMS Workspace Key securely and allow for any key rotation or changes in a programmatic way.  Have a look at Getting Started - Azure KeyVault to get one set up if you haven't got one already.

Here's the code I used to get things setup and ready for use.
This creates Automation variables for OMSWorkspaceName, OMSWorkspaceID and KeyVaultName.
Also created is a KeyVault secret for the OMS Workspace Key, granting the Automation RunAs account rights to get secrets from your KeyVault.

$AutomationAccountName = "{My Automation Account Name}"
$ResourceGroupName = "{My Automation Account Resource Group Name}"
$KeyVaultName = "{My KeyVault Name}"
$KeyVaultResourceGroupName = "{My KeyVault Resource Group Name}"
$OMSWorkspaceName = "{My OMS Workspace Name}"
$OMSWorkspaceID = "{My OMS Workspace ID}"
$OMSWorkspaceKey_Raw = "{My OMS Workspace Key}"
$OMSWorkspaceKey = convertto-securestring ($OMSWorkspaceKey_Raw)  -asplaintext -force 

New-AzureRmAutomationVariable -Name "OMSWorkspaceName" -Value $OMSWorkspaceName -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName -Encrypted $false
New-AzureRmAutomationVariable -Name "OMSWorkspaceID" -Value $OMSWorkspaceID -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName -Encrypted $false
New-AzureRmAutomationVariable -Name "KeyVaultName" -Value $KeyVaultName -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName -Encrypted $false
Set-AzureKeyVaultSecret -VaultName $KeyVaultName -Name "OMSWorkspaceKey-$($OMSWorkspaceName)" -SecretValue $OMSWorkspaceKey

$RunAsConn = Get-AzureRmAutomationConnection -Name 'AzureRunAsConnection' -ResourceGroupName $ResourceGroupName -AutomationAccountName $AutomationAccountName
Set-AzureRmKeyVaultAccessPolicy -VaultName $KeyVaultName -ServicePrincipalName $RunAsConn.FieldDefinitionValues.ApplicationId -ResourceGroupName $KeyVaultResourceGroupName -PermissionsToSecrets get

Now, to log information to OMS you need to pass a json payload and a LogType.  I have some script that I add to the top of all my scripts to do this.
You will notice I've include various data types so as to ensure the log data is formatted correctly, I've borrowed this from the Rest API reference, so please look the 'Record type and properties' section for all the details.
For example, if it's a number the use _d (double) at the end of the parameter so no quotes are placed around the value.

#Retrive the RunAs Connection details
$Conn = Get-AutomationConnection -Name 'AzureRunAsConnection'

#Login with the RunAs Account
Add-AzureRMAccount -ServicePrincipal -Tenant $Conn.TenantID `
    -ApplicationId $Conn.ApplicationID `
    -CertificateThumbprint $Conn.CertificateThumbprint `
    -SubscriptionId $Conn.SubscriptionId

#Retrieve KeyVault Name to get secure variables (Namely, the OMS Workspace Key)
$KeyVaultName = Get-AutomationVariable -Name "KeyVaultName"

#Get OMS Workspace details
$OMSWorkspaceID = $null
$OMSWorkspaceName = Get-AutomationVariable -Name "OMSWorkspaceName"
$OMSWorkspaceID = Get-AutomationVariable -Name "OMSWorkspaceID"
if ($OMSWorkspaceID -ne $null) {
    $OMSKey = (Get-AzureKeyVaultSecret -VaultName $KeyVaultName -Name "OMSWorkspaceKey-$($OMSWorkspaceName)").SecretValueText
    $LogType = "Runbook_AutoshutdownFinal"
} else {
    $OMSKey = $null
    $LogType = $null

#Set the LogType to use when posting to OMS
$LogType = "OMSLogTest"

function AddToLog ([Object]$OMSLogData) {

    if ($OMSWorkspaceID -ne $null) {
        $LogData = ''
        foreach ($Key in $OMSLogData.Keys) {
            switch ($Key.Substring($Key.Length-2)) {
                '_s' {$sep = '"';$trim=$Key.Length-2}
                '_t' {$sep = '"';$trim=$Key.Length-2}
                '_b' {$sep = '';$trim=$Key.Length-2}
                '_d' {$sep = '';$trim=$Key.Length-2}
                '_g' {$sep = '"';$trim=$Key.Length-2}
                default {$sep = '"';$trim=$Key.Length}
            $LogData = $LogData + '"' + $Key.Substring(0,$trim) + '":' + $sep + $OMSLogData.Item($Key) + $sep + ','
        $TimeStamp = Get-Date (Get-Date).ToUniversalTime()
        $LogData = $LogData + '"TimeStamp":"' + $timestamp + '"'

        Write-Verbose "LogData: $($LogData)"
        $json = "{$($LogData)}"

        $PostResult = Send-OMSAPIIngestionFile -customerId $OMSWorkspaceID -sharedKey $OMSKey -body $json -logType $LogType -TimeStampField "TimeStamp"
        Write-Verbose "PostResult: $($PostResult)"
        if ($PostResult -ne "Accepted") {
            Write-Error "Error posting to OMS - $PostResult"

So whenever you want to log anything you would build a hashtable of the data you want to log and pass that to the AddToLog function.
For example, if you were to log information from a runbook that starts and stops VMs you would use something like this -

$VMName = "MyVM1"
$ResourceGroupName = "MyResourceGroup"
$SubscriptionID = "7d94a8a1-12c4-1234-aaaa-xxxxxxxxxxxx"
$VMState = Get-AzureRmVM -Name $VMName -ResourceGroupName $ResourceGroupName -Status
if ($VMState.Statuses[1].DisplayStatus -eq "VM running") {
    Stop-AzureRmVM -Name $VMName -ResourceGroupName $ResourceGroupName -Force
    $Action = "Stop VM"
} else {
    $Action = "VM Already Stopped"

$LogData = @{
    Trigger_s = "Scheduled"
    VMName_s = $VMName
    SubscriptionGUID_g = $SubscriptionId
    ResourceGroup_s = $ResourceGroupName
    TargetState_s = "VM dealloacted"
    CurrentSatet_s = $($VMState.Statuses[1].DisplayStatus)
    Action_s = $Action
AddToLog -OMSLogData $LogData

Which will look something like this in the OMS logs