Experts Inside Blog

Logging mit PowerShell, Azure Automation Account und Data Collection Rules zu LogAnalytics Workspace

Geschrieben von Michael Sedy | Dec 19, 2024 4:14:45 PM

Wir bei Experts Inside verwenden für viele automatisierte Aufgaben den Automation Account und Runbooks. Dabei hat sich das zuverlässige Logging oft als Problem herausgestellt. Deshalb werden bei uns wichtige Operationen in einen Log-Analytics-Workspace geschrieben.

Voraussetzungen für dieses Beispiel in diesem Blog sind ein Automation Account und ein Log Analytics workspace.

Aber es kann im Prinzip auch jede ARC-enabled Maschine verwendet werden.

Erstellen eines neuen Data collection Endpoints:

Erstellen einer neuen custom log Tabelle (DCR based)

Erstellen einer neuen data collection rule:

schemasample.json

Managed identity des Automation Account einschalten oder die Managed identity einer Maschine die Arc-enabled ist verwenden.

 

Hier das zugehörige PowerShell-Script (5.1):

$endpoint_uri = "https://xi-expertsinside-t-euw-dce-01-b1j8.westeurope-1.ingest.monitor.azure.com" #Get-AutomationVariable -Name 'LogAnalyticsWorkspaceID'

$ImmutableId = "dcr-d16763b3b5b14d00aa83827563515dc4" #Get-AutomationVariable -Name 'LogAnalyticsWorkspaceKey'

$PSDefaultParameterValues = @{

    "Write-XiLog:LogsIngestionEndpoint"  = $endpoint_uri

    "Write-XiLog:ImmutableId" = $ImmutableId

}

 

function Write-XiLog {

    <#

    .SYNOPSIS

        This function writes log output for automation accounts

    .DESCRIPTION

        Logging in automation account is crap, so we send everything to log analytics.

        The log ingestion api requires authentication, we need to grant the Monitoring Metrics Publisher role

        to any identiy that uses this function. We need to call Connect-AzAccount -Identity and retrieve an access token.

    .NOTES

        log everything

    .EXAMPLE

        Write-XiLog -Message "this is what's happening"

       

        This just writes a message to the output of the runbook

    .EXAMPLE

        Write-XiLog -Message "this is what's happening" -Scriptname RUN-ExchangeMigration

       

        This writes a message to the output of the runbook AND sends the message to log analytics

    .EXAMPLE

        Write-XiLog -Message "this is what's happening" -Scriptname RUN-ExchangeMigration -Type Warning

       

        This writes a warning to the output of the runbook AND sends the message to log analytics

    #>

    [CmdletBinding()]

    param(

        [string]$Message,

        [string]$ScriptName,

        [ValidatePattern('.ingest.monitor.azure.com$')]

        [string]$LogsIngestionEndpoint,

        [ValidatePattern('^dcr-')]

        [string]$ImmutableId,

        [ValidatePattern('^Custom-')]

        [string]$StreamName = 'Custom-AutomationEngine',

        [ValidateSet("output", "warning", "error")]

        $Type = "output"

    )

    begin {

        $azContext = Get-AzContext

        if (-not($azContext)) {

            Connect-AzAccount -identity -TenantID 'a6k4k3k2-b751-46b9-85e0-78e7c873hd61' -SubscriptionId '027463n9-a84b-4b53-b972-c9f7473hf685' -ErrorAction Stop -WarningAction SilentlyContinue

        }

        Get-AzContext

        $Token = (Get-AzAccessToken -ResourceUrl 'https://monitor.azure.com' -ErrorAction Stop -WarningAction SilentlyContinue).Token

        $secureToken = ConvertTo-SecureString -String $Token -AsPlainText -Force

        $accesToken = [System.Net.NetworkCredential]::new(0,$secureToken).Password

        if (-not($accesToken)) {

            Write-Error "Could not retrieve access token."

        }

    }

    process {

        $time = Get-Date ([datetime]::Now) -Format O

        $logEvent = @{

            TimeGenerated = $time

            EventType     = $type

            Message       = $message

            Script        = $scriptname

        }

        $uri = "$LogsIngestionEndpoint/dataCollectionRules/$ImmutableId/streams/$($StreamName)?api-version=2023-01-01"

        $headers = @{"Authorization" = "Bearer $accesToken" }

        $body = ConvertTo-Json -InputObject @($logevent) -Compress

        #$body = $logEvent | ConvertTo-Json -AsArray -Compress

        Write-Verbose "Invoking [$uri] with body [$body]"

        $null = Invoke-RestMethod -Uri $uri -Method "Post" -Body $body -Headers $headers -ContentType 'application/json'

        switch ($type) {

            "output" { Write-Output "$time`: $message" }

            "warning" { Write-Warning "$time`: $message" }

            "error" { Write-Error "$time`: $message" }

        }

    }

}

 

Write-XiLog -Message "Testcomment" -Scriptname RUN-ExchangeMigration

 

Folgende Parameter müssen jetzt im Powershell-Skript eingesetzt werden:


Tenant-ID
Subscription-ID
Data collection endpoint:

 

Data collection rule Immutable ID:

 

StreamName Parameter:

 

Jetzt kann das Script ausgeführt werden:

Jetzt heisst es sich in Geduld zu üben bis der Eintrag in Log Analytics erscheint.
Die KQL Abfrage ist einfach der Tabellenname.

 

Code-Archiv:

schemasample.json

[

    {

        "TimeGenerated": "2024-12-02T14:45:32Z",

        "EventType": "SampleEvent",

        "Script": "SampleScript",

        "Message": "This is a sample message."

    }

]

 

RUN-WriteToLogAnalytics.ps1

$endpoint_uri = "https://xi-expertsinside-t-euw-dce-01-b1j8.westeurope-1.ingest.monitor.azure.com" #Get-AutomationVariable -Name 'LogAnalyticsWorkspaceID'

$ImmutableId = "dcr-d16763b3b5b14d00aa83827563515dc4" #Get-AutomationVariable -Name 'LogAnalyticsWorkspaceKey'

$PSDefaultParameterValues = @{

   "Write-XiLog:LogsIngestionEndpoint" = $endpoint_uri

   "Write-XiLog:ImmutableId" = $ImmutableId

}

 

function Write-XiLog {

   <#

   .SYNOPSIS

       This function writes log output for automation accounts

   .DESCRIPTION

       Logging in automation account is crap, so we send everything to log analytics.

       The log ingestion api requires authentication, we need to grant the Monitoring Metrics Publisher role

       to any identiy that uses this function. We need to call Connect-AzAccount -Identity and retrieve an access token.

   .NOTES

       log everything

   .EXAMPLE

       Write-XiLog -Message "this is what's happening"

      

       This just writes a message to the output of the runbook

   .EXAMPLE

       Write-XiLog -Message "this is what's happening" -Scriptname RUN-ExchangeMigration

      

       This writes a message to the output of the runbook AND sends the message to log analytics

   .EXAMPLE

       Write-XiLog -Message "this is what's happening" -Scriptname RUN-ExchangeMigration -Type Warning

      

       This writes a warning to the output of the runbook AND sends the message to log analytics

   #>

   [CmdletBinding()]

   param(

       [string]$Message,

       [string]$ScriptName,

       [ValidatePattern('.ingest.monitor.azure.com$')]

       [string]$LogsIngestionEndpoint,

       [ValidatePattern('^dcr-')]

       [string]$ImmutableId,

       [ValidatePattern('^Custom-')]

       [string]$StreamName = 'Custom-AutomationEngine',

       [ValidateSet("output", "warning", "error")]

       $Type = "output"

   )

   begin {

       $azContext = Get-AzContext

       if (-not($azContext)) {

           Connect-AzAccount -identity -TenantID 'a6k4k3k2-b751-46b9-85e0-78e7c873hd61' -SubscriptionId '027463n9-a84b-4b53-b972-c9f7473hf685' -ErrorAction Stop -WarningAction SilentlyContinue

       }

       Get-AzContext

       $Token = (Get-AzAccessToken -ResourceUrl 'https://monitor.azure.com' -ErrorAction Stop -WarningAction SilentlyContinue).Token

       $secureToken = ConvertTo-SecureString -String $Token -AsPlainText -Force

       $accesToken = [System.Net.NetworkCredential]::new(0,$secureToken).Password

       if (-not($accesToken)) {

           Write-Error "Could not retrieve access token."

       }

   }

   process {

       $time = Get-Date ([datetime]::Now) -Format O

       $logEvent = @{

           TimeGenerated = $time

           EventType     = $type

           Message       = $message

           Script       = $scriptname

       }

       $uri = "$LogsIngestionEndpoint/dataCollectionRules/$ImmutableId/streams/$($StreamName)?api-version=2023-01-01"

       $headers = @{"Authorization" = "Bearer $accesToken" }

       $body = ConvertTo-Json -InputObject @($logevent) -Compress

       #$body = $logEvent | ConvertTo-Json -AsArray -Compress

       Write-Verbose "Invoking [$uri] with body [$body]"

       $null = Invoke-RestMethod -Uri $uri -Method "Post" -Body $body -Headers $headers -ContentType 'application/json'

       switch ($type) {

           "output" { Write-Output "$time`: $message" }

           "warning" { Write-Warning "$time`: $message" }

           "error" { Write-Error "$time`: $message" }

       }

   }

}

 

Write-XiLog -Message "Testcomment" -Scriptname RUN-ExchangeMigration