[Azure] Azure Virtual Desktopでユーザーセッション数の推移をグラフ表示する

Azure Virtual Desktop(2021/6まで Windows Virtual Desktop)は、Azure上に構築可能なデスクトップ・アプリの仮想化サービスです。

ユーザセッション数の推移をグラフ表示したいと思ったのですが、現在の診断情報では簡単に表示することができないようでした（ [LogAnalysisにセッションの開始と終了ログは残っている](https://cloudsteady.jp/post/23073/) のでがんばればできそうですが）。

[前回Automationアカウントの設定をして](https://qiita.com/VA_nakatsu/items/ee07ef2d08a04c8272b6)、カスタムメトリクス使えば簡単にグラフ化できそうだったので、作成してみたのが本記事の内容になります。

# 1．Application Insight作成

カスタムメトリクスの送信先として、Application Insightを使用します。アカウント作成してインストルメンテーションキーを控えておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/8c74a4bd-3bf6-750a-fe1e-967f8a1af03b.png)

# 2．Azure Automationアカウントの設定

[前回の記事にあるように](https://qiita.com/VA_nakatsu/items/ee07ef2d08a04c8272b6)、Automationアカウントを作成後、 マネージドIDを有効にして `"Az.Accounts"` モジュールをインポートしておきます。

その後、Azure Virtual Desktop用の追加モジュールをインポートします。

`"Az.DesktopVirtualization"` モジュールをインポート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/8159f884-9b14-71b8-51ad-5983c522a5f5.png)

`"Az.ResourceGraph"` モジュールをインポート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/318f67e0-22fa-9299-038d-15be75b31d8d.png)

`"Az.Resources"` モジュールをインポート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/d3d77aca-248f-4757-7aee-efa406591d53.png)

`"Az.Wvd"` モジュールをインポート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/6b707d2e-9d1c-37ac-7501-58ce11578084.png)

※モジュールのインストールですが、事前に依存関係をチェックしてくれるものと、インストール時にチェックされ失敗するものがあるようです。失敗した場合はログに依存関係が表示されているので、一旦削除して先に依存しているモジュールをインストールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/b290de14-e8c9-2a16-7ef4-0306e2b7aa67.png)

# 3．マネージドIDにロールを付与

セッション数を取得するため、「デスクトップ仮想化ホスト プールの閲覧者」権限が必要です。マネージドIDに対して、サブスクリプションまたは対象リソースの権限を付与しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/531e403a-1f20-1a13-254c-06245c8481e0.png)

# 4．Application Insightsへ出力用のモジュールを作成

[こちらの記事:Azure Automation(PowerShell)からApplication Insightsへログを出力する](https://qiita.com/mkyz08/items/ee448a30f61468dcc0c4) にそのまま実行可能な手順がまとまっていました（ありがとうございます）。

今回はこれをそのままインポートしたのと、メトリクス用にもう一つモジュールを作成しました。元記事からの差分としては

・psm1スクリプトで Trace → Metric に修正

```ApplicationInsightsCustomMetric.psm1
function Write-ApplicationInsightsMetric
{
    [CmdletBinding()]
    param(
            [Parameter(Mandatory=$true)][string] $InstrumentationKey,
            [Parameter(Mandatory=$true)][string] $MetricKey,
            [Parameter(Mandatory=$true)][string] $MetricValue
            )
    try
    {
	    $TelClient = New-Object -TypeName Microsoft.ApplicationInsights.TelemetryClient
	    $TelClient.InstrumentationKey = $InstrumentationKey
	    $TelClient.TrackMetric($MetricKey, $MetricValue)
	    $TelClient.Flush()
    }
    catch
    {
        Write-Output "Exception while logging into Application Insights: $($_.Exception.Message)"
    }
}

Export-ModuleMember -Function Write-ApplicationInsightsMetric
```

・psd1スクリプトで Trace → Metric に修正

```ApplicationInsightsCustomMetric.psd1

@{

    # Script module or binary module file associated with this manifest.
    RootModule = 'ApplicationInsightsCustomMetric.psm1'
    
    # Version number of this module.
    ModuleVersion = '1.0.0'
    
    # Author of this module
    Author = 'mkyz08'
    
    # Company or vendor of this module
    CompanyName = ''
    
    # Copyright statement for this module
    Copyright = ''
    
    # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
    NestedModules = @('.\Microsoft.ApplicationInsights.dll') 
    
    # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
    FunctionsToExport = @('*')
    
    # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
    CmdletsToExport = @('*')
    
    # Variables to export from this module
    VariablesToExport = '*'
    
    # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
    AliasesToExport = @()
    
    # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
    PrivateData = @{
    
        PSData = @{
    
        } # End of PSData hashtable
    
    } # End of PrivateData hashtable
    
    }    
```

あとはZipファイルを作成して2つのモジュールをインポートしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/47d44cbd-19f6-89b6-0e94-97dbf11709f7.png)

なお、Microsoft.ApplicationInsights.dllは今回ローカルPCの Azモジュールに含まれていたもの（バージョン `2.4.0.32153`）で問題なく動作しました。

# 5．Runbook作成

後はRunbookを作成します。事前に 1．で確認したインストルメンテーションキーを変数(暗号化文字列)として登録しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/fbc86a6d-8031-0817-42db-2f835d1d909c.png)

作成したRunbookは以下の通りです。セッション数を取得し、Application Insight(Metric)へ連携後、セッション数が1以上の場合はユーザ名のリストをApplication Insight(Log)へ連携しています。

```powershell
# マネージドIDによる接続
Connect-AzAccount -Identity

try {
    $ResourceGroupName = 'resource-group-name'
    $HostPoolName = 'host-pool-name'
    $InstrumentationKey = Get-AutomationVariable -Name 'app-insight-instrumentation-key' # インストルメンテーションキー

    # セッション数取得
    $userSessions = Get-AzWvdUserSession -ResourceGroupName $ResourceGroupName -HostPoolName $HostPoolName
    Write-Output ("Session num:" + $userSessions.Count)

    # セッション数をApplication Insight(Metric)へ連携
    Write-ApplicationInsightsCustomMetric $InstrumentationKey "UserCount-HostPool-xxx" $userSessions.Count

    # ユーザがいる場合はユーザ名をApplication Insight(Log)へ連携
    if ( $userSessions.Count -gt 0 ){
        $userList = ''
        foreach($eachUser in $userSessions){
            $userList = $userList + '   ' + $eachUser.UserPrincipalName
        }
        Write-ApplicationInsightsTrace $InstrumentationKey $userList "Information"
    }
}
catch {
    $ErrorMessage = $_.Exception.message
    Write-Error ("Error occurred when starting vm:" + $ErrorMessage)
    Break
}
```

# 6．動作確認

Runbookをスケジュール設定して定期的に実行してみると、以下のようにカスタムメトリクスにセッション数が連携されました。

カスタムメトリクスが選択肢に追加された：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/c2fe8408-1a77-005f-6213-6da23586d516.png)

セッション数の推移グラフ：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/a84ecba4-6130-f90a-eb54-54a3093f53d7.png)

ログを検索すると、各セッションのユーザ名が確認できます。

```
traces
| where severityLevel == 1
```

で検索し、ログが増えたら時間で絞り込む：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172826/9bd16fe5-44c2-53a1-97be-4da067eddfd3.png)

以上でセッション数の推移が容易に確認できるようになりました。

# 参考資料

- [Log AnalyticsによるWVD診断情報の可視化](https://cloudsteady.jp/post/23073/)
- [Azure Monitor のカスタム メトリック (プレビュー)](https://docs.microsoft.com/ja-jp/azure/azure-monitor/essentials/metrics-custom-overview)