smsagent.blog
  • docs.smsagent.blog
  • Custom Reporting in Microsoft Intune
    • Delivery Optimization Report
    • Windows Update for Business Custom Reporting
      • Power BI Report Walkthrough
      • Known issues / limitations
      • Change log
      • Deploy the solution
        • Create Azure Resources
        • Configure Azure Resources
        • Deploy the client-side script
        • Deploy the Azure automation runbooks
        • Configure the Power BI report
      • Adding additional language support
      • Table schema reference
    • Automating Data Exports from Microsoft Graph
      • Azure Automation account
        • Create / configure an Azure automation account
        • Grant API permissions
        • Create an Azure automation runbook
      • Azure Storage account
      • Automate Data Export to Azure Storage Account
      • Automate Data Export to Azure Monitor Logs
      • Creating / Troubleshooting Runbooks
      • Power BI
        • Connect Power BI to an Azure storage account data source
        • Connect Power BI to an Azure log analytics workspace as a data source
    • Managed Devices Report
      • Create / configure an Azure automation account
      • Grant API permissions
      • Create / configure an Azure storage account
      • Create an Azure automation runbook
      • Create a PowerBI report
      • MEM Managed Device Report template
      • Bonus! Unhealthy MEMCM Clients email report
    • Intune Assignments Report
      • Create / configure an Azure automation account
      • Grant API permissions
      • Create / configure an Azure storage account
      • Create an Azure automation runbook
      • Create a Power BI report
      • Change log
    • Patch My PC Report
      • A look at the Power BI reports
      • Change log
      • Video guides
      • Things to know
      • Create / configure an Azure automation account
      • Grant API permissions
      • Create / configure an Azure storage account
      • Create an Azure automation runbook
      • Create the Power BI report
      • Feedback
    • Windows 11 Hardware Readiness Report
    • Gathering Custom Inventory with Intune
      • Set up the Azure Resources
      • Create a Proactive remediations script package
      • Create a runbook
  • PowerShell Scripts Online Help
    • Get-AzSubscriptionActivityLog
  • Azure Solutions
    • Automated Azure Table Storage Backups
      • Change log
      • Deploy the solution
        • Create the Azure resources
        • Set the backup schedule
        • Add storage tables to the backup
        • Add role assignments to the storage account/s
        • Create a lifecycle management rule
      • Run a manual backup
      • Restore a backup
Powered by GitBook
On this page

Was this helpful?

  1. Custom Reporting in Microsoft Intune
  2. Automating Data Exports from Microsoft Graph

Automate Data Export to Azure Monitor Logs

PreviousAutomate Data Export to Azure Storage AccountNextCreating / Troubleshooting Runbooks

Last updated 3 years ago

Was this helpful?

Below is an example PowerShell Runbook that can be used in an Azure automation account to export data from Microsoft Graph and send it to a Log Analytics workspace. It exports Windows devices with a selection of fields.

The following is assumed:

  • You have enabled a system managed identity for the Azure automation account and granted it the appropriate API permissions to Microsoft Graph.

  • You have created two encrypted variables in the automation account for the WorkspaceID and the PrimaryKey of your log analytics workspace.

https://github.com/SMSAgentSoftware/MEM/blob/main/Intune%20reporting/Export-MSGraphToAzureMonitorLogs.ps1
############################################################

# Example Azure Automation Runbook for exporting data from #

# MS Graph and sending it to a custom Azure Monitor log    #

############################################################





# Variables

$ProgressPreference = 'SilentlyContinue'

$WorkspaceID = Get-AutomationVariable -Name "WorkspaceID" # Saved as an encrypted variable in the automation account 

$PrimaryKey = Get-AutomationVariable -Name "PrimaryKey" # Saved as an encrypted variable in the automation account

$LogType = "Devices" # The name of the log file that will be created or appended to





#############

# FUNCTIONS #

#############



# function to invoke a web request to MS Graph with error handling

Function script:Invoke-LocalGraphRequest {

    Param ($URL,$Headers,$Method,$Body,$ContentType)

    try {

        If ($Method -eq "Post")

        {

            $WebRequest = Invoke-WebRequest -Uri $URL -Method $Method -Headers $Headers -Body $Body -ContentType $ContentType -UseBasicParsing

        }

        else 

        {

            $WebRequest = Invoke-WebRequest -Uri $URL -Method $Method -Headers $Headers -UseBasicParsing

        }     

    }

    catch {

        $WebRequest = $_.Exception.Response

    }

    Return $WebRequest

}



# function to get managed Windows device data from MS Graph

Function Get-DeviceData {

    $URL = "https://graph.microsoft.com/beta/deviceManagement/manageddevices?`$filter=startsWith(operatingSystem,'Windows')&`$select=deviceName,Id,lastSyncDateTime,managementAgent,managementState,osVersion,skuFamily,deviceEnrollmentType,emailAddress,model,manufacturer,serialNumber,userDisplayName,joinType"

    $headers = @{'Authorization'="Bearer " + $accessToken}

    $GraphRequest = Invoke-LocalGraphRequest -URL $URL -Headers $headers -Method GET

    If ($GraphRequest.StatusCode -ne 200)

    {

        Return $GraphRequest

    }

    $JsonResponse = $GraphRequest.Content | ConvertFrom-Json

    $DeviceData = $JsonResponse.value

    If ($JsonResponse.'@odata.nextLink')

    {

        do {

            $URL = $JsonResponse.'@odata.nextLink'

            $GraphRequest = Invoke-LocalGraphRequest -URL $URL -Headers $headers -Method GET

            If ($GraphRequest.StatusCode -ne 200)

            {

                Return $GraphRequest

            }

            $JsonResponse = $GraphRequest.Content | ConvertFrom-Json

            $DeviceData += $JsonResponse.value

        } until ($null -eq $JsonResponse.'@odata.nextLink')

    }

    Return $DeviceData

}



# Create the function to create the authorization signature

# ref https://docs.microsoft.com/en-us/azure/azure-monitor/logs/data-collector-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

# ref https://docs.microsoft.com/en-us/azure/azure-monitor/logs/data-collector-api

Function Post-LogAnalyticsData($customerId, $sharedKey, $body, $logType)

{

    $method = "POST"

    $contentType = "application/json"

    $resource = "/api/logs"

    $rfc1123date = [DateTime]::UtcNow.ToString("r")

    $contentLength = $body.Length

    $TimeStampField = ""

    $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" = $TimeStampField;

    }



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

    return $response.StatusCode

}





####################

## AUTHENTICATION ##

####################



## Get MS Graph access token 

# Managed Identity

$url = $env:IDENTITY_ENDPOINT  

$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" 

$headers.Add("X-IDENTITY-HEADER", $env:IDENTITY_HEADER) 

$headers.Add("Metadata", "True") 

$body = @{resource='https://graph.microsoft.com/' } 

$script:accessToken = (Invoke-RestMethod $url -Method 'POST' -Headers $headers -ContentType 'application/x-www-form-urlencoded' -Body $body ).access_token





#########################

## THUNDERBIRDS ARE GO ##

#########################



$Devices = Get-DeviceData

$Json = $Devices | ConvertTo-Json

Post-LogAnalyticsData -customerId $WorkspaceID -sharedKey $PrimaryKey -body ([System.Text.Encoding]::UTF8.GetBytes($json)) -logType $logType