OMSIngestionAPI.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#requires -Version 2
#PowerShell Module leveraged for ingesting data into Log Analytics API ingestion point

<#
.SYNOPSIS
    Builds an OMS authorization to securely communicate to a customer workspace.
.DESCRIPTION
    Leveraging a customer workspaceID and private key for Log Analytics
    this function will build the necessary api signature to securely send
    json data to the OMS ingestion API for indexing
.PARAMETER customerId
    The customer workspace ID that can be found within the settings pane of the
    OMS workspace.
.PARAMETER sharedKey
    The primary or secondary private key for the customer OMS workspace
    found within the same view as the workspace ID within the settings pane
.PARAMETER date
    RFC 1123 standard UTC date string converted variable used for ingestion time stamp
.PARAMETER contentLength
    Body length for payload being sent to the ingestion endpoint
.PARAMETER method
    Rest method used (POST)
.PARAMETER contentType
    Type of data being sent in the payload to the endpoint (application/json)
.PARAMETER resource
    Path to send the logs for ingestion to the rest endpoint
#>

Function Get-OMSAPISignature
{
    Param
    (
        [Parameter(Mandatory = $True)]$customerId,
        [Parameter(Mandatory = $True)]$sharedKey,
        [Parameter(Mandatory = $True)]$date,
        [Parameter(Mandatory = $True)]$contentLength,
        [Parameter(Mandatory = $True)]$method,
        [Parameter(Mandatory = $True)]$contentType,
        [Parameter(Mandatory = $True)]$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
}
<#
.SYNOPSIS
    Sends the json payload securely to a customer workspace leveraging a
    customer ID and shared key
.DESCRIPTION
    Leveraging a customer workspaceID and private key for Log Analytics
    this function will send a json payload securely to the OMS ingestion
    API for indexing
.PARAMETER customerId
    The customer workspace ID that can be found within the settings pane of the
    OMS workspace.
.PARAMETER sharedKey
    The primary or secondary private key for the customer OMS workspace
    found within the same view as the workspace ID within the settings pane
.PARAMETER body
    json payload
.PARAMETER logType
    Name of log to be ingested assigned to JSON payload
    (will have "_CL" appended upon ingestion)
.PARAMETER TimeStampField
    Time data was ingested. If $TimeStampField is defined for JSON field
    when calling this function, ingestion time in Log Analytics will be
    associated with that field.
 
    example: $Timestampfield = "Timestamp"
 
    foreach($metricValue in $metric.MetricValues)
    {
        $sx = New-Object PSObject -Property @{
            Timestamp = $metricValue.Timestamp.ToString()
            MetricName = $metric.Name;
            Average = $metricValue.Average;
            SubscriptionID = $Conn.SubscriptionID;
            ResourceGroup = $db.ResourceGroupName;
            ServerName = $SQLServer.Name;
            DatabaseName = $db.DatabaseName;
            ElasticPoolName = $db.ElasticPoolName
        }
        $table = $table += $sx
    }
    Send-OMSAPIIngestionFile -customerId $customerId -sharedKey $sharedKey`
     -body $jsonTable -logType $logType -TimeStampField $Timestampfield
 
.PARAMETER EnvironmentName
    If $EnvironmentName is defined for AzureUSGovernment
    when calling this function, ingestion will go to an Azure Government Log Analytics
    workspace. Otherwise, Azure Commercial endpoint is leveraged by default.
#>

Function Send-OMSAPIIngestionFile
{
    Param
    (
        [Parameter(Mandatory = $True)]$customerId,
        [Parameter(Mandatory = $True)]$sharedKey,
        [Parameter(Mandatory = $True)]$body,
        [Parameter(Mandatory = $True)]$logType,
        [Parameter(Mandatory = $False)]$TimeStampField,
        [Parameter(Mandatory = $False)]$EnvironmentName
    )

    #<KR> - Added to encode JSON message in UTF8 form for double-byte characters
    $body=[Text.Encoding]::UTF8.GetBytes($body)
    
    $method = "POST"
    $contentType = "application/json"
    $resource = "/api/logs"
    $rfc1123date = [DateTime]::UtcNow.ToString("r")
    $contentLength = $body.Length
    $signature = Get-OMSAPISignature `
     -customerId $customerId `
     -sharedKey $sharedKey `
     -date $rfc1123date `
     -contentLength $contentLength `
     -method $method `
     -contentType $contentType `
     -resource $resource
    if($EnvironmentName -eq "AzureUSGovernment")
    {
        $Env = ".ods.opinsights.azure.us"
    }
    Else
    {
        $Env = ".ods.opinsights.azure.com"
    }
    $uri = "https://" + $customerId + $Env + $resource + "?api-version=2016-04-01"
    if ($TimeStampField.length -gt 0)
    {
        $headers = @{
            "Authorization" = $signature;
            "Log-Type" = $logType;
            "x-ms-date" = $rfc1123date;
            "time-generated-field"=$TimeStampField;
        }
    }
    else {
         $headers = @{
            "Authorization" = $signature;
            "Log-Type" = $logType;
            "x-ms-date" = $rfc1123date;
        }
    } 
    $response = Invoke-WebRequest `
        -Uri $uri `
        -Method $method `
        -ContentType $contentType `
        -Headers $headers `
        -Body $body `
        -UseBasicParsing `
        -verbose
    
    if ($response.StatusCode -ge 200 -and $response.StatusCode -le 299)
    {
        write-output 'Accepted'
    }
}