Azure Log Analytics REST APIを使用してPowerShellでLog Analyticsのクエリを実行する

#背景
　本記事はAzure Log Analyticsの検索クエリをREST APIを使用してPowerShellで実行する方法について記載しています。REST APIから検索クエリを実行することで応用の幅が広がるのではないかと考え検証しました。結論として「Azure Log Analytics REST API」を使用することで実現できるのですが、私のようなREST APIの使用に習熟していない者にとってはその為の作業手順がそこそこ複雑でしたので記事として整理しました。

#方針
　冒頭に記載した通り「Azure Log Analytics REST API」を使用します。REST APIを呼び出す際にはPowerShellを使用して検索クエリを実行します。
　
#事前準備
　Azure サブスクリプションにてLog Analytics Workspaceを作成し、データソースとして仮想マシンを接続するなどして何らかのデータがLog Analytics Workspaceに保存されるようにしておきます。また、PowerShellスクリプトを実行する際にサブスクリプションIDとサブスクリプションが関連付けられているAzure AD のテナントIDが必要であるためこれらも事前に確認しておきます。

#手順概要
　続いて今回の作業手順の概要を以下に記載します。(1)～(4)を実行してREST APIを使用する準備を整え、最後にPowerShellスクリプトで検索クエリを実行します。

(1)Azure AD Web Applicationの作成
(2)Azure AD Web Applicationのアクセス許可設定
(3)Azure AD Web Applicationのクライアントシークレットの発行
(4)Log Analytics Workspaceのアクセス制御(IAM)設定

#手順詳細
(1)Azure AD Web Applicationの作成
①Azure ポータルへサインインします。

②「Azure Active Directory」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/c451acba-6482-c73f-5071-5f5bbdb9a9cb.png)

③「アプリの登録」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/5d8f6c5f-e1fc-c3bf-76d6-10bd9bfee352.png)
　
④「新規登録」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/98b9e5b1-2007-ef96-9215-0c0736361ff2.png)

⑤以下の通り設定し「登録」を選択します。
　・名前：任意(今回はAccess Log Analyticsとします。)
　・リダイレクトURL：http://localhost:3000/login

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/2253b85c-6026-fa3c-1d73-8e61b781b63c.png)

⑥Azure AD Web Applicationが作成されたことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/5dfb3912-eaf8-1fc4-a87f-10eead025682.png)


(2)Azure AD Web Applicationのアクセス許可設定
①(1)で登録した「Access Log Analytics」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/5dfb3912-eaf8-1fc4-a87f-10eead025682.png)


②「アプリケーションID」を控え、「APIのアクセス許可」を選択します。アプリケーションIDは後程PowerShellスクリプトを実行する際に使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/f096c5bf-00d8-a713-3180-52e739fd440d.png)

③「アクセス許可の追加」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/0a0f9b85-68bb-e6af-52d5-853e0c510ca2.png)

④「所属している組織で使用しているAPI」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/bc30327c-78d1-2dce-23d5-949917b0c797.png)

⑤「Log Analytics API」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/1464f620-f7ed-7b6b-71f4-f24b5ac32e10.png)

⑥「委任されたアクセス許可」を選択し、「Data.Read」にチェックを入れ「アクセス許可の追加」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/65381941-da7f-dd70-23ec-1aef83fcaeca.png)

⑦「アクセス許可」が追加されたことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/d33e8d9c-b466-565e-a38c-f4b9e8c0cb75.png)

(3)Azure AD Web Applicationのクライアントシークレットの発行
①(1)で登録した「Access Log Analytics」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/92edd47c-1a6e-79ca-baef-f54dcc7c26a4.png)

②「証明書とシークレット」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/313d97f5-280f-3dd7-0bba-cd27375b2804.png)

③「新しいクライアントシークレット」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/c380d6a9-03eb-4bc9-1f6e-00d4fe2cb1d5.png)

④「追加」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/db69756f-6a09-07b0-3b5e-224d6854231c.png)

⑤「クライアント シークレット」の「値」を控えます。後ほどPowerShellスクリプトを実行する際に使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/539dcc29-5ade-a033-8dc7-4b0b2a5f35ec.png)

(4)Log Analytics Workspaceのアクセス制御(IAM)設定
①Azure ポータルにて、事前に用意していた「Log Analytics Workspace」を選択します。

②「アクセス制御(IAM)」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/5927eff3-de68-18a6-5f2f-684ddbf8a2d1.png)

③「追加」-「ロールの割り当ての追加」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/c7df9b18-b135-be0a-c2a9-e50f8c7d8beb.png)

④(1)で作成したアプリケーション(Access Log Analytics)に対して「Log Analytics 閲覧者」の役割を設定し「保存」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/4bda1b65-c7e2-d5bf-a335-88e86a4e2a54.png)

⑤「Access Log Analytics」が「Log Analytics 閲覧者」として追加されたことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/24524351-d4f8-0462-fdce-6b72a47f0313.png)


#検索クエリを実行するPowerShellスクリプト
　以上で準備が整いました。続いて以下に検索クエリを実行するためのPowerShellスクリプトを記載します。
　※Azure サブスクリプションへのログインについては以下スクリプトでは割愛しています。

(1)パラメータ設定
本スクリプトを実行する上で必要なパラメータを以下に記載します。

①tenantId
Azure サブスクリプションが関連付けられているAzure AD テナントのテナントIDを確認し指定します。

```
$tenantId = "<Azure AD テナントID>"
```

②clientID
手順詳細(2)の②で確認したAzure AD Web ApplicationのアプリケーションIDを指定します。

```
$clientID = "<Azure AD アプリケーションID>"      
```

③clientSecret
手順詳細(3)の④で確認したAzure AD Web Applicationのクライアントシークレットを指定します。

```
$clientSecret = "<クライアントシークレット>"  
```

④subscriptionId
Azure サブスクリプションのサブスクリプションIDを確認し指定します。

```
$subscriptionId = "<サブスクリプションID>"
```

⑤workspaceRgName
Log Analytics Workspaceが存在するリソースグループの名称を指定します。

```
$workspaceRgName = "DefaultResourceGroup-EUS"
```

⑥workspacename
Log Analytics Workspaceの名称を指定します。

```
$workspacename = "DefaultWorkspace-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-EUS"
```

(2)認証Tokenの取得
以下のスクリプトにてREST APIを実行するための認証Tokenを取得します。

```
$loginURL       = "https://login.microsoftonline.com/$tenantId/oauth2/token"
$resource       = "https://management.azure.com/"         
$body           = @{grant_type="client_credentials";resource=$resource;client_id=$clientId;client_secret=$clientSecret}
$oauth          = Invoke-RestMethod -Method Post -Uri $loginURL -Body $body
$headerParams = @{"Authorization" = "Bearer " + $oauth.access_token} 
```

(3)検索クエリ
Log Analyticsで実行する検索クエリを記載します。
以下の「body」のシングルクォーテーション内に任意の検索クエリを記載します。
以下では例として2019年12月1日から12月31日までのすべてのHeartbeat通信を検索するクエリを記載しています。

```
$body = @{query = 
'let startdatetime=datetime(2019-12-01T00:00:00);
let enddatetime=datetime(2019-12-30T23:59:59);
Heartbeat | where TimeGenerated between(startdatetime .. enddatetime)
'
}| ConvertTo-Json
```

(4)REST APIの呼び出し(検索クエリの実行)
REST APIを呼び出し、検索クエリの実行結果を変数に格納します。

```
$url="https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$workspaceRgName/providers/Microsoft.OperationalInsights/workspaces/$workspacename/api/query?api-version=2017-01-01-preview"
$result = Invoke-RestMethod -UseBasicParsing -Headers $headerParams -Uri $url -Method Post -Body $body -ContentType "application/json"

```

(5)検索クエリ結果の整形
そのままの形式では閲覧に適さない為CSV形式に整形します。以下の整形の為のスクリプトについては[こちら](https://blog.darrenjrobinson.com/azure-ad-log-analytics-kql-queries-via-api-with-powershell/)を参考にしました。ここで1点注意点があります。REST APIの実行結果を格納した変数 $resultを確認するとテーブルが4つ(Table_0/Table_1/Table_2/Table_3)存在します。このうちクエリ結果が格納されているのはTable_0のみであるため、整形の際にはTable_0のデータのみを抽出します。

```
$headerRow = $null
$headerRow = $result.tables[0].columns | Select-Object ColumnName
$columnsCount = $headerRow.Count
$logData = @()
foreach ($row in $result.tables[0].rows) {
    $data = new-object PSObject
    for ($i = 0; $i -lt $columnsCount; $i++) {
        $data | add-member -membertype NoteProperty -name $headerRow[$i].ColumnName -value $row[$i]
    }
    $logData += $data
    $data = $null
}
```

(6)CSV出力
整形完了後以下のようにして任意のパスにcsvファイルとして出力します。例としてローカルPCのデスクトップを指定しています。

```
$logData | export-csv C:\Users\XXXXXX\Desktop\logAnalytics.csv -NoTypeInformation
```


※改めてスクリプト全体を以下に記載します。

```
#パラメータ設定
$tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$clientId       = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"      
$clientSecret   = "********************************"  

$subscriptionId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$workspaceRgName="DefaultResourceGroup-EUS"
$workspacename = "DefaultWorkspace-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-EUS"

#Tokenの取得
$loginURL       = "https://login.microsoftonline.com/$tenantId/oauth2/token"
$resource       = "https://management.azure.com/"         
$body           = @{grant_type="client_credentials";resource=$resource;client_id=$clientId;client_secret=$clientSecret}
$oauth          = Invoke-RestMethod -Method Post -Uri $loginURL -Body $body
$headerParams = @{"Authorization" = "Bearer " + $oauth.access_token} 

#検索クエリ
$body = @{query = 
'let startdatetime=datetime(2019-12-01T00:00:00);
let enddatetime=datetime(2019-12-30T23:59:59);
Heartbeat | where TimeGenerated between(startdatetime .. enddatetime)
'
}| ConvertTo-Json

#APIの呼び出し(検索クエリの実行)
$url="https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$workspaceRgName/providers/Microsoft.OperationalInsights/workspaces/$workspacename/api/query?api-version=2017-01-01-preview"
$result = Invoke-RestMethod -UseBasicParsing -Headers $headerParams -Uri $url -Method Post -Body $body -ContentType "application/json"

#検索クエリ結果の整形
$headerRow = $null
$headerRow = $result.tables[0].columns | Select-Object ColumnName
$columnsCount = $headerRow.Count
$logData = @()
foreach ($row in $result.tables[0].rows) {
    $data = new-object PSObject
    for ($i = 0; $i -lt $columnsCount; $i++) {
        $data | add-member -membertype NoteProperty -name $headerRow[$i].ColumnName -value $row[$i]
    }
    $logData += $data
    $data = $null
}

#CSV出力
$logData | export-csv C:\Users\XXXXXX\Desktop\logAnalytics.csv -NoTypeInformation
```

#実行結果
　上述のスクリプトを実行することで以下のようなcsvファイルが出力されます。勿論Azure ポータルで検索クエリの実行結果をエクスポートすることも可能ですので、これだけではわざわざREST APIを使用する意味は薄いと言えます。応用方法については今後の課題として引き続き検討したいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531201/8e9a6ffe-19dc-3268-31f7-fe98cd149ac7.png)

　

#参考情報
・[Azure REST API を使ってみよう](https://blogs.msdn.microsoft.com/dsazurejp/2018/11/13/azurerestapi/)
・[Azure Log Analytics REST API](https://dev.loganalytics.io/documentation/Overview)
・[Using PowerShell to query Azure Log Analytics via the REST API](https://www.jbmurphy.com/2018/12/11/using-powershell-to-query-azure-log-analytics-via-the-rest-api/)
・[Azure AD Log Analytics KQL queries via API with PowerShell](https://blog.darrenjrobinson.com/azure-ad-log-analytics-kql-queries-via-api-with-powershell/)