powershellazure-functionsazure-log-analyticsazure-functions-core-tools

Powershell script for azure function to post to a log analytics


I am trying to write an azure function which posts data to a specific table e.g. (Table_CL) inside log analytics workspace. I am running into errors.

Install-Module -Name Az.OperationalInsights -Scope CurrentUser -Force

$logAnalyticsClient = Get-AzOperationalInsightsWorkspace -ResourceGroupName "rg-name" -Name "log-analytics-wsp"
 

$WorkspaceId = "/subscriptions/subscriptionID/resourceGroups/rg-name/providers/Microsoft.OperationalInsights/workspaces/log-analytics-wsp"
$SharedKey = "some-value"
$CustomTableName = "Table_CL"


# Obtain an authentication token
$tenantId = 'some value'
$clientId = 'value of Function App identity client IOD'
$Uri = "https://log-analytics-wsp.ods.opinsights.azure.com/api/logs?api-version=2016-04-01"


$Body = @{
    "EventId" = $eventGridEvent.id;
    "eventType" = $eventGridEvent.eventType;
    "subject" = $eventGridEvent.subject;
    "TimeGenerated" = [datetime]$eventGridEvent.eventTime;
    "data" = (ConvertTo-Json -InputObject $eventGridEvent.data);
    "dataVersion" = $eventGridEventvent.dataVersion;
    "metadataVersion" = $eventGridEvent.metadataVersion;
}
$signature = $SharedKey + (get-date -uformat '%a, %d %b %Y %H:%M:%S ')

$hex = ""
foreach ($byte in $signature) {
    $hex += "{0:x2}" -f $byte
}
$Signature = $hex




$Headers = @{
    "Content-Type" = "application/json"
    "Log-Type" = $CustomTableName
    "Authorization" = $Signature
}



# Use the authentication token to send a request to the Log Analytics API
Invoke-WebRequest -Uri $Uri -Method Post -Body $Body -Headers $Headers

I am getting errors, can someone please guide me on how to post to specific table in log analytics using powershell script. I am getting the following errors.

2023-01-18T19:56:48Z   [Error]   ERROR: The format of value 'some-shared-key-value-==Wed, 18 Jan 2023 19:56:47 GMT' is invalid.

Exception             : 
   Type       : System.FormatException
   TargetSite : 
       Name          : ParseValue
       DeclaringType : System.Net.Http.Headers.HttpHeaderParser, System.Net.Http, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
       MemberType    : Method
       Module        : System.Net.Http.dll
   Message    : The format of value 'some-shared-key-value-Wed, 18 Jan 2023 19:56:47 GMT' is invalid.
   Source     : System.Net.Http
   HResult    : -2146233033
   StackTrace : 
  at System.Net.Http.Headers.HttpHeaderParser.ParseValue(String value, Object storeValue, Int32& index)
  at System.Net.Http.Headers.HttpHeaders.ParseAndAddValue(HeaderDescriptor descriptor, HeaderStoreItemInfo info, String value)
  at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetRequest(Uri uri)
  at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()
  at System.Management.Automation.Cmdlet.DoProcessRecord()
  at System.Management.Automation.CommandProcessor.ProcessRecord()
CategoryInfo          : NotSpecified: (:) [Invoke-WebRequest], FormatException
FullyQualifiedErrorId : System.FormatException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
InvocationInfo        : 
   MyCommand        : Invoke-WebRequest
   ScriptLineNumber : 55
   OffsetInLine     : 1
   HistoryId        : 1
   ScriptName       : C:\home\site\wwwroot\EventGridTrigger1\run.ps1
   Line             : Invoke-WebRequest -Uri $Uri -Method Post -Body $Body -Headers $Headers
                      
   PositionMessage  : At C:\home\site\wwwroot\EventGridTrigger1\run.ps1:55 char:1
                      + Invoke-WebRequest -Uri $Uri -Method Post -Body $Body -Headers $Header …
                      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   PSScriptRoot     : C:\home\site\wwwroot\EventGridTrigger1
   PSCommandPath    : C:\home\site\wwwroot\EventGridTrigger1\run.ps1
   InvocationName   : Invoke-WebRequest
   CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, C:\home\site\wwwroot\EventGridTrigger1\run.ps1: line 55

Any suggestions? I am looking for way to post to Log Analytics workspace specific table, any help would be great.
Thanks


Solution

  • I had to use the following API from azure docs. This works neatly as it is. Just plug the values and the post command is able to create table in Azure Monitor. Following is the reference for the docs as well.

    # Replace with your Workspace ID
    $CustomerId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"  
    
    # Replace with your Primary Key
    $SharedKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    
    # Specify the name of the record type that you'll be creating
    $LogType = "MyRecordType"
    
    # Optional name of a field that includes the timestamp for the data. If the time field is not specified, Azure Monitor assumes the time is the message ingestion time
    $TimeStampField = ""
    
    
    # Create two records with the same set of properties to create
    $json = @"
    [{  "StringValue": "MyString1",
        "NumberValue": 42,
        "BooleanValue": true,
        "DateValue": "2019-09-12T20:00:00.625Z",
        "GUIDValue": "9909ED01-A74C-4874-8ABF-D2678E3AE23D"
    },
    {   "StringValue": "MyString2",
        "NumberValue": 43,
        "BooleanValue": false,
        "DateValue": "2019-09-12T20:00:00.625Z",
        "GUIDValue": "8809ED01-A74C-4874-8ABF-D2678E3AE23D"
    }]
    "@
    
    # Create the function to create the authorization signature
    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" = $TimeStampField;
        }
    
        $response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $body -UseBasicParsing
        return $response.StatusCode
    
    }
    
    # Submit the data to the API endpoint
    Post-LogAnalyticsData -customerId $customerId -sharedKey $sharedKey -body ([System.Text.Encoding]::UTF8.GetBytes($json)) -logType $logType