This post is part of a series where we will be using the Log Analytics workspace to store Office 365 information which will then be used to create a dashboard. We will first create the Log Analytics workspace in Azure, then create an app registration in Azure Active Directory, then a Runbook using Automation Accounts to upload data to the Log Analytics workspace and lastly we will be building a dashboard in the Log Analytics workspace.

The following posts are part of these series:

Automation Accounts and Runbooks

Azure Automation delivers a cloud-based automation and configuration service that provides consistent management across your Azure and non-Azure environments. It consists of process automation, update management, and configuration features. Azure Automation provides complete control during deployment, operations, and decommissioning of workloads and resources. Azure Automation accounts can be created through Azure. This method provides a browser-based user interface for creating and configuring Automation accounts and related resources. This quickstart steps through creating an Automation account and running a runbook in the account.

Creating a Log Analytics workspace using the browser

Browse to the Automation Accounts in Azure or use the direct link https://portal.azure.com/#blade/HubsExtension/BrowseResourceBlade/resourceType/Microsoft.Automation%2FAutomationAccounts

image

Click on ‘Add’

image

Fill in the required information. Note that we are not using a Run As account for this automation.
Click on ‘Create’

image

Click on the newly created Automation Account which we will use in the next steps.

Runbook variables

We are going to use variables in our Automation Account settings in PowerShell.

image

I’ve added the following variables

Name Type Value
LogType-Status String O365Status
LogType-Subscriptions String O365Subscriptions
LAW-SharedKey String Key
LAW-WorkspaceID String ID
SPFire-AppID String ID
SPFire-AppSecret Encrypted String Key
SPFire-TenantID String ID

image

Creating the runbook

image

Click on ‘Create a runbook’

image

Click on ‘Create’

image

The PowerShell window will be the default view. Copy and paste the following script in this window where you may need to change your variables.

$customerId = Get-AutomationVariable -Name 'LAW-WorkspaceID'
$SharedKey = Get-AutomationVariable -Name 'LAW-SharedKey'
$LogType = Get-AutomationVariable -Name 'LogType-Status'

# Helper functions to get the data to OMS using REST API
Function Build-Signature ($customerId, $sharedKey, $date, $contentLength, $method, $contentType, $resource)
{
    $xHeaders = "x-ms-date:" + $date
    $stringToHash = $method + "`n" + $contentLength + "`n" + $contentType + "`n" + $xHeaders + "`n" + $resource

    $bytesToHash = [Text.Encoding]::UTF8.GetBytes($stringToHash)
    $keyBytes = [Convert]::FromBase64String($sharedKey)

    $sha256 = New-Object System.Security.Cryptography.HMACSHA256
    $sha256.Key = $keyBytes
    $calculatedHash = $sha256.ComputeHash($bytesToHash)
    $encodedHash = [Convert]::ToBase64String($calculatedHash)
    $authorization = 'SharedKey {0}:{1}' -f $customerId,$encodedHash
    return $authorization
}

# Create the function to create and post the request
Function Post-LogAnalyticsData($customerId, $sharedKey, $body, $logType)
{
    $method = "POST"
    $contentType = "application/json"
    $resource = "/api/logs"
    $rfc1123date = [DateTime]::UtcNow.ToString("r")
    $contentLength = $body.Length
    $signature = Build-Signature `
        -customerId $customerId `
        -sharedKey $sharedKey `
        -date $rfc1123date `
        -contentLength $contentLength `
        -method $method `
        -contentType $contentType `
        -resource $resource
    $uri = "https://" + $customerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01"

    $headers = @{
        "Authorization" = $signature;
        "Log-Type" = $logType;
        "x-ms-date" = $rfc1123date;
        "time-generated-field" = [string]::Empty
    }

    $response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $body -UseBasicParsing
    return $response.StatusCode
}

$tenantId = Get-AutomationVariable -Name 'SPFire-TenantId'
$appId = Get-AutomationVariable -Name 'SPFire-Appid'
$appSecret = Get-AutomationVariable -Name 'SPFire-AppSecret'

$accessTokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/token"
$o365serviceUrl = "https://manage.office.com/api/v1.0/$tenantId/ServiceComms/CurrentStatus"
$accessTokenContentType = "application/x-www-form-urlencoded"
$accessTokenBody = 'grant_type=client_credentials'
$accessTokenBody += '&client_id=' + $appId
$accessTokenBody += '&client_secret=' + [Uri]::EscapeDataString($appSecret)
$accessTokenBody += '&resource=' + [Uri]::EscapeDataString("https://manage.office.com")

# Get Access token using appId/secret to access the O365 Management API
$token = Invoke-RestMethod -Uri $accessTokenUrl -Method POST -Body $accessTokenBody -ContentType $accessTokenContentType
$accessToken = $token.access_token
$header = @{"Authorization" = "Bearer " + $accessToken}

# Call the O365 Management API
$result = Invoke-RestMethod -Uri $o365serviceUrl -Method GET -Headers $header
$json = $result.value | Convertto-json

# Sending the data to OMS
Post-LogAnalyticsData -customerId $customerId -sharedKey $sharedKey -body ([System.Text.Encoding]::UTF8.GetBytes($json)) -logType $logType

image

Click on ‘Test pane’

image

Click on ‘Start’

image

It should show completed. Go back and publish this runbook.
Create a new runbook with the following script to also retrieve the subscription information from Office 365.

$customerId = Get-AutomationVariable -Name 'LAW-WorkspaceID'
$SharedKey = Get-AutomationVariable -Name 'LAW-SharedKey'
$LogType = Get-AutomationVariable -Name 'LogType-Subscriptions'

# Helper functions to get the data to OMS using REST API
Function Build-Signature ($customerId, $sharedKey, $date, $contentLength, $method, $contentType, $resource)
{
    $xHeaders = "x-ms-date:" + $date
    $stringToHash = $method + "`n" + $contentLength + "`n" + $contentType + "`n" + $xHeaders + "`n" + $resource

    $bytesToHash = [Text.Encoding]::UTF8.GetBytes($stringToHash)
    $keyBytes = [Convert]::FromBase64String($sharedKey)

    $sha256 = New-Object System.Security.Cryptography.HMACSHA256
    $sha256.Key = $keyBytes
    $calculatedHash = $sha256.ComputeHash($bytesToHash)
    $encodedHash = [Convert]::ToBase64String($calculatedHash)
    $authorization = 'SharedKey {0}:{1}' -f $customerId,$encodedHash
    return $authorization
}

# Create the function to create and post the request
Function Post-LogAnalyticsData($customerId, $sharedKey, $body, $logType)
{
    $method = "POST"
    $contentType = "application/json"
    $resource = "/api/logs"
    $rfc1123date = [DateTime]::UtcNow.ToString("r")
    $contentLength = $body.Length
    $signature = Build-Signature `
        -customerId $customerId `
        -sharedKey $sharedKey `
        -date $rfc1123date `
        -contentLength $contentLength `
        -method $method `
        -contentType $contentType `
        -resource $resource
    $uri = "https://" + $customerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01"

    $headers = @{
        "Authorization" = $signature;
        "Log-Type" = $logType;
        "x-ms-date" = $rfc1123date;
        "time-generated-field" = [string]::Empty
    }

    $response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $body -UseBasicParsing
    return $response.StatusCode
}

$tenantId = Get-AutomationVariable -Name 'SPFire-TenantId'
$appId = Get-AutomationVariable -Name 'SPFire-Appid'
$appSecret = Get-AutomationVariable -Name 'SPFire-AppSecret'

$accessTokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$o365serviceUrl = "https://graph.microsoft.com/v1.0/subscribedSkus"
$accessTokenContentType = "application/x-www-form-urlencoded"
$accessTokenBody = 'grant_type=client_credentials'
$accessTokenBody += '&client_id=' + $appId
$accessTokenBody += '&client_secret=' + [Uri]::EscapeDataString($appSecret)
$accessTokenBody += '&scope=' + 'https%3A%2F%2Fgraph.microsoft.com%2F.default'

# Get Access token using appId/secret to access the O365 Management API
$token = Invoke-RestMethod -Uri $accessTokenUrl -Method POST -Body $accessTokenBody -ContentType $accessTokenContentType
$accessToken = $token.access_token
$header = @{"Authorization" = "Bearer " + $accessToken}

# Call the O365 Management API
$result = Invoke-RestMethod -Uri $o365serviceUrl -Method GET -Headers $header
$json = $result.value | Convertto-json

# Sending the data to OMS
Post-LogAnalyticsData -customerId $customerId -sharedKey $sharedKey -body ([System.Text.Encoding]::UTF8.GetBytes($json)) -logType $logType

image

Schedule the runbooks

Now we want to schedule the runbooks. In this case I will create an hourly schedule to pull information from Office 365 and store this information to the Log Analytics workspace.

image

Add a schedule

image

Create and go to the schedule under the runbook itself.

image

Click on ‘Add a schedule’

image

OK

Verify if the runbooks work correctly

You can browse to the Log Analytics workspace to verify if log information is present.

image

There should be two Custom Logs present which contain data.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.