Upload-AzMonitorLog.ps1
<#PSScriptInfo
.VERSION 1.2 .AUTHOR meirm@microsoft.com .GUID f983f286-7c77-46e2-adad-352926c13499 #> <# .DESCRIPTION Script to upload PowerShell objects to Azure Monitor Logs using the Data Collector API. .PARAMETER WorkspaceId The Workspace ID of the workspace that would be used to store this data .PARAMETER WorkspaceKey The primary or secondary key of the workspace that would be used to store this data. It can be obtained from the Windows Server tab in the workspace Advanced Settings .PARAMETER LogTypeName The name of the custom log table that would store these logs. This name will be automatically concatenated with "_CL" .PARAMETER AddComputerName If this switch is indicated, the script will add to every log record a field called Computer with the current computer name .PARAMETER TaggedAzureResourceId If exist, the script will associated all uploaded log records with the specified Azure resource. This will enable these log records for resource-centext queries .PARAMETER AdditionalDataTaggingName If exist, the script will add to every log record an additional field with this name and with the value that appears in AdditionalDataTaggingValue. This happens only if AdditionalDataTaggingValue is not empty .PARAMETER AdditionalDataTaggingValue If exist, the script will add to every log record an additional field with this value. The field name would be as specified in AdditionalDataTaggingName. If AdditionalDataTaggingName is empty, the field name will be "DataTagging" .EXAMPLE Import-Csv .\testcsv.csv | .\Upload-AzMonitorLog.ps1 -WorkspaceId '69f7ec3e-cae3-458d-b4ea-6975385-6e426' -WorkspaceKey $WSKey -LogTypeName 'MyNewCSV' -AddComputerName -AdditionalDataTaggingName "MyAdditionalField" -AdditionalDataTaggingValue "Foo" Will upload the CSV file as a custom log to Azure Monitor Logs (AKA:Log Analytics) .EXAMPLE Import-Csv .\testcsv.csv | .\Upload-AzMonitorLog.ps1 -WorkspaceId '69f7ec3e-cae3-458d-b4ea-6975385-6e426' -WorkspaceKey $WSKey -LogTypeName 'MyNewCSV' -AddComputerName -AdditionalDataTaggingName "MyAdditionalField" -AdditionalDataTaggingValue "Foo" Will upload the CSV file as a custom log to Azure Monitor Logs (AKA:Log Analytics) .LINK This script posted to and discussed at the following locations:PowerShell Gallery https://www.powershellgallery.com/packages/Upload-AzMonitorLog #> param ( [Parameter(mandatory=$true,ValueFromPipeline=$true)]$input, [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$WorkspaceId, [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$WorkspaceKey, [Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$LogTypeName, [Parameter(Mandatory=$false)][switch]$AddComputerName, [Parameter(Mandatory=$false)][string]$TaggedAzureResourceId, [Parameter(Mandatory=$false)][string]$AdditionalDataTaggingName, [Parameter(Mandatory=$false)][string]$AdditionalDataTaggingValue ) Write-Output ("Start process " + $input.Length.ToString("N0") + " items and uploading them to Azure Log Analytcs") $InputTypeName = $input.GetType().Name switch -Exact ($InputTypeName) { "ArrayListEnumeratorSimple" { $data = $input | ConvertTo-Json -Compress; Break } default { $data = $input.GetType().Name } } $customerId = $WorkspaceId $sharedKey = $WorkspaceKey # Specify the name of the record type that you'll be creating $LogType = $LogTypeName # Specify a field with the created time for the records $TimeStampField = "DateValue" #OBSOLETE exist just for backward compatability # Add computer name for each record if needed if ($AddComputerName) { $compName = $env:COMPUTERNAME if ($ENV:USERDNSDOMAIN -ne $env:COMPUTERNAME) { $compName = $env:COMPUTERNAME + "." + $ENV:USERDNSDOMAIN } #for domain joined computer, add FQDN foreach ($row in $input) {$row | Add-Member -MemberType NoteProperty -Name Computer -Value $compName} } # Add additional tagging if additional tagging is provided if ($AdditionalDataTaggingValue) { if(!($AdditionalDataTaggingName)) { $AdditionalDataTaggingName = "DataTagging" } foreach ($row in $input) {$row | Add-Member -MemberType NoteProperty -Name $AdditionalDataTaggingName -Value $AdditionalDataTaggingValue} } # Create json object based on the PowerShell data try { $json = $input | ConvertTo-Json -Compress } catch { throw("Input data cannot be converted into a JSON object. Please make sure that the input data is a standard PowerShell table") } # 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 } #Format the post request $method = "POST" $contentType = "application/json" $resource = "/api/logs" $rfc1123date = [DateTime]::UtcNow.ToString("r") $body = ([System.Text.Encoding]::UTF8.GetBytes($json)) $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; "x-ms-AzureResourceId" = $TaggedAzureResourceId "time-generated-field" = $TimeStampField; } #validate that payload data does not exceed limits if ($body.Length -gt (31.9 *1024*1024)) { throw("Upload payload is too big and exceed the 32Mb limit for a single upload. Please reduce the payload size. Current payload size is: " + ($body.Length/1024/1024).ToString("#.#") + "Mb") } Write-Output ("Upload payload size is " + ($body.Length/1024).ToString("#.#") + "Kb") ##### Send the Web request try { $response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $body -UseBasicParsing } catch { if ($_.Exception.Message.startswith('The remote name could not be resolved')) { throw ("Error - data could not be uploaded. Might be because workspace ID or private key are incorrect") } throw ("Error - data could not be uploaded: " + $_.Exception.Message) } # Present message according to the response code if ($response.StatusCode -eq 200) { Write-Output "200 - Data was successfully uploaded" } else { throw ("Server returned an error response code:" + $response.StatusCode)} |