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:
- Creating a Log Analytics workspace in Azure
- Registering an app in Azure Active Directory
- Creating a PowerShell Runbook using Automation Accounts
- Building an Azure dashboard
- Building a Log Analytics workspace dashboard
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
Click on ‘Add’
Fill in the required information. Note that we are not using a Run As account for this automation.
Click on ‘Create’
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.
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 |
Creating the runbook
Click on ‘Create a runbook’
Click on ‘Create’
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
Click on ‘Test pane’
Click on ‘Start’
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
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.
Add a schedule
Create and go to the schedule under the runbook itself.
Click on ‘Add a schedule’
OK
Verify if the runbooks work correctly
You can browse to the Log Analytics workspace to verify if log information is present.
There should be two Custom Logs present which contain data.