-
-
Save MarcelMeurer/8347eb527a6fdb4839ee428bf0e6eee0 to your computer and use it in GitHub Desktop.
Azure Virtual Desktop - Behind the senes: Log Session Host information each minute to log analytics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"bindings": [ | |
{ | |
"name": "Timer", | |
"schedule": "*/60 * * * * *", | |
"direction": "in", | |
"type": "timerTrigger" | |
} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Azure Functions profile.ps1 | |
# Authenticate with Azure PowerShell using MSI. | |
# Remove this if you are not planning on using MSI or Azure PowerShell. | |
if ($env:MSI_SECRET) { | |
Disable-AzContextAutosave -Scope Process | Out-Null | |
Connect-AzAccount -Identity | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file enables modules to be automatically managed by the Functions service. | |
# See https://aka.ms/functionsmanageddependency for additional information. | |
# | |
@{ | |
# For latest supported version, go to 'https://www.powershellgallery.com/packages/Az'. | |
# To use the Az module in your function app, please uncomment the line below. | |
# 'Az' = '8.*' | |
'Az.Accounts' = '2.10.0' | |
'Az.DesktopVirtualization' = '3.1.1' | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Use the script with an Azure function. The Azure function must have a managed identity (System). | |
# Give the managed identity read access to the resource group containing the host pools (or on the pools themselves). | |
# Additionally, the managed identity needs read access to key vault secrets containing the WorkspaceId and WorkspaceKey. | |
# Create both secrets with the information about the log analytics workspace. Reference both secrets in the appsettings of the function app: | |
# WorkspaceId=@Microsoft.KeyVault(SecretUri=https://xxxx.vault.azure.net/secrets/WorkspaceId/) and WorkspaceKey=@Microsoft.KeyVault(SecretUri=https://xxxx.vault.azure.net/secrets/WorkspaceKey/) | |
# Input bindings are passed in via param block. | |
param($Timer) | |
# Get the current universal time in the default string format. | |
$currentUTCtime = (Get-Date).ToUniversalTime() | |
# The 'IsPastDue' property is 'true' when the current function invocation is later than scheduled. | |
if ($Timer.IsPastDue) { | |
Write-Host "PowerShell timer is running late!" | |
} | |
# Write an information log with the current time. | |
Write-Host "PowerShell timer trigger function ran! TIME: $currentUTCtime" | |
# Variables | |
$WorkspaceId=$env:WorkspaceId | |
$WorkspaceKey=$env:WorkspaceKey | |
$LogTypeName="AvdBehind_v2" | |
$TimeStampField="TimeStamp" | |
$ResourceGroup="WVD.Design2" # works on all pools in the resoruce group | |
# Functions | |
# Source: https://learn.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 | |
} | |
# Source: https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-collector-api | |
Function Post-OMSData($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" = $TimeStampField; | |
} | |
$response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $body -UseBasicParsing | |
return $response.StatusCode | |
} | |
# Main | |
$pools=Get-AzWvdHostPool -ResourceGroupName $ResourceGroup | |
$now=(Get-Date).ToString("o") | |
Write-Host "Starting iteration at $now" | |
Write-Host "Get $($pools.Count) host pools" | |
$pools | ForEach { | |
$hostPoolName=$_.Name | |
Write-Host "`nWorking on pool $hostPoolName" | |
$rg=$_.Id.Split("/")[4] | |
$sessionHosts=Get-AzWvdSessionHost -HostPoolName $_.Name -ResourceGroupName $rg | |
$sessionHosts | Add-Member -MemberType NoteProperty -Name "TimeStamp" -Value $now | |
Write-Host "Number of session hosts: $($sessionHosts.Count)" | |
# Send to log analytics | |
if ($sessionHosts.Count -gt 0) { | |
$response=Post-OMSData -customerId $WorkspaceId -sharedKey $WorkspaceKey -body ([System.Text.Encoding]::UTF8.GetBytes(($sessionHosts | ConvertTo-Csv|ConvertFrom-Csv|ConvertTo-Json -Depth 5))) -logType $LogTypeName | |
Write-Host "Data uploaded to $WorkspaceId. Response code: ",$response | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment