💭

AVD RdAgent とかを再インストールする PowerShell Cmdlet (2024/04 版)

2024/04/09に公開

TL;DR

  • 過去の記事の更新版です
  • Invoke-AzVMRunCommand-InlineScript に対応したので、シンプルになりました
  • その他、細かい変更点がありますが、使い方は変わっていません

はじめに

AVD RdAgent とかを再インストールする PowerShell Cmdlet というのを以前書いていたのですが、これの更新版です。
以前は cim.ps1 を別の script として用意する必要があったのですが、Invoke-AzVMRunCommand-InlineScript に対応したので、これを使う形に変更しています。
そのほか、細かい変更点がちまちまありますが、使用感としては変わっていません。

更新した PowerShell script

はこちらです。

reset-azwvdsessionhostagent.ps1
Function Reset-AzWvdSessionHostAgent() {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)] [string] $ResourceGroupName,
        [Parameter(Mandatory = $true)] [string] $Location,
        [Parameter(Mandatory = $true)] [string] $HostPoolName,
        [Parameter(Mandatory = $true)] [string] $SessionHostVMName,
        [Parameter(Mandatory = $true)] [string] $DomainName
    )

    try {
        $sessionHost = Get-AzWvdSessionHost -HostPoolName $HostPoolName -Name "${SessionHostVMName}.${DomainName}" -ResourceGroupName $ResourceGroupName -ErrorAction SilentlyContinue
    
        if ($sessionHost) {
            Write-Debug "$(Get-Date -Format 'h:mm:ss tt') - Deleting session host '${SessionHostVMName}' from session pool '${HostPoolName}'."
            Remove-AzWvdSessionHost -HostPoolName $HostPoolName -Name "${SessionHostVMName}.${DomainName}" -ResourceGroupName $ResourceGroupName
        } else {
            Write-Debug "$(Get-Date -Format 'h:mm:ss tt') - Session host '${SessionHostVMName}' does not exist in host pool '${HostPoolName}'. Skipping deletion."
        }
    } catch {
        # Log the caught exception, assuming it's an unexpected error.
        Write-Error "An unexpected error occurred: $_"
    }

    Write-Debug "$(Get-Date -Format "h:mm:ss tt") - Deleting DSC extension from session host `"${SessionHostVMName}`"."
    Remove-AzVMExtension -ResourceGroupName $ResourceGroupName -Name Microsoft.PowerShell.DSC -VMName $SessionHostVMName -Force | Out-Null

    Write-Debug "$(Get-Date -Format "h:mm:ss tt") - Deleting RdAgent and AVD-related softwares from session host `"${SessionHostVMName}`"."
    $commandId = "RunPowerShellScript"
    $script = @"
Get-CimInstance -Class Win32_Product -Filter 'Name="Remote Desktop Agent Boot Loader"' | Invoke-CimMethod -MethodName Uninstall
Get-CimInstance -Class Win32_Product -Filter 'Name="Remote Desktop Services Infrastructure Agent"' | Invoke-CimMethod -MethodName Uninstall
Get-CimInstance -Class Win32_Product -Filter 'Name LIKE "Remote Desktop Services Infrastructure Geneva Agent %"' | Invoke-CimMethod -MethodName Uninstall
"@
    Invoke-AzVMRunCommand -ResourceGroupName $ResourceGroupName -VMName $SessionHostVMName -CommandId $commandId -ScriptString $script | Out-Null

    Write-Debug "$(Get-Date -Format 'h:mm:ss tt') - Get AVD registration key for the host pool '${HostPoolName}'."
    $HostpoolToken = (Get-AzWvdRegistrationInfo -ResourceGroupName $ResourceGroupName -HostPoolName $HostPoolName).Token

    if ($null -eq $HostpoolToken) {
        $HostpoolToken = (New-AzWvdRegistrationInfo -ResourceGroupName $ResourceGroupName -HostPoolName $HostPoolName -ExpirationTime $((Get-Date).ToUniversalTime().AddHours(3).ToString('yyyy-MM-ddTHH:mm:ss.fffffffZ'))).Token
    }

    # Convert hostpoolToken to SecureString
    $SecureHostpoolToken = ConvertTo-SecureString $HostpoolToken -AsPlainText -Force

    Write-Debug "$(Get-Date -Format 'h:mm:ss tt') - Re-installing RdAgent to session host '${SessionHostVMName}' for binding to host pool '${HostPoolName}'."
    New-AzResourceGroupDeployment -ResourceGroupName $ResourceGroupName -TemplateFile template.json -vmName $SessionHostVMName -location $Location -hostpoolToken $SecureHostpoolToken -hostpoolName $HostPoolName | Out-Null
}
  • ReInstall- という動詞は Approved Verbs for PowerShell Commands で推奨されるものではなかったので Reset- に変更しています
  • すでに session host が消されていた時用に、Remove-AzWvdSessionHost の周りに少しエラー処理を追加しています
  • template.json で使う hostpoolToken が SecureString に変わったため ConvertTo-SecureString を使っています
  • Get-Date -Format で与えていた文字列が間違っていたので修正しています。。。("h:MM:ss tt" → 'h:mm:ss tt'、MM は 月 の数字が出力されるので純粋なミスです、、)

ついでに必要な template.json はこちらです。

template.json
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "artifactsLocation": {
            "defaultValue": "https://wvdportalstorageblob.blob.core.windows.net/galleryartifacts/Configuration_1.0.02643.274.zip",
            "type": "String",
            "metadata": {
                "description": "The base URI where artifacts required by this template are located."
            }
        },
        "vmName": {
            "type": "String"
        },
        "location": {
            "defaultValue": "",
            "type": "String",
            "metadata": {
                "description": "Location for all resources to be created in."
            }
        },
        "hostpoolToken": {
            "type": "SecureString",
            "metadata": {
                "description": "The token for adding VMs to the hostpool"
            }
        },
        "hostpoolName": {
            "type": "String",
            "metadata": {
                "description": "The name of the hostpool"
            }
        },
        "aadJoin": {
            "defaultValue": false,
            "type": "Bool",
            "metadata": {
                "description": "IMPORTANT: You can use this parameter for the test purpose only as AAD Join is public preview. True if AAD Join, false if AD join"
            }
        }
    },
    "variables": {},
    "resources": [
        {
            "type": "Microsoft.Compute/virtualMachines/extensions",
            "apiVersion": "2021-07-01",
            "name": "[concat(parameters('vmName'), '/', 'Microsoft.PowerShell.DSC')]",
            "location": "[parameters('location')]",
            "properties": {
                "publisher": "Microsoft.Powershell",
                "type": "DSC",
                "typeHandlerVersion": "2.73",
                "autoUpgradeMinorVersion": true,
                "settings": {
                    "modulesUrl": "[parameters('artifactsLocation')]",
                    "configurationFunction": "Configuration.ps1\\AddSessionHost",
                    "properties": {
                        "hostPoolName": "[parameters('hostpoolName')]",
                        "registrationInfoTokenCredential": {
                            "UserName": "PLACEHOLDER_DO_NOT_USE",
                            "Password": "PrivateSettingsRef:RegistrationInfoToken"
                        },
                        "aadJoin": "[parameters('aadJoin')]",
                        "UseAgentDownloadEndpoint": true
                    }
                },
                "protectedSettings": {
                    "Items": {
                        "RegistrationInfoToken": "[parameters('hostpoolToken')]"
                    }
                }
            }
        }
    ],
    "outputs": {}
}
  • 以前は hostpoolToken を平文で与える形になっていましたが、見慣れない protectedSettings という文法と hostpoolToken の SecureString 化により安全になった感じっぽいです

使い方

そのまんまですが、こんな感じです。

Reset-AzWvdSessionHostAgent -ResourceGroupName <ResourceGroupName> -Location <Location> -HostPoolName <HostPoolName> -SessionHostVMName <SessionHostVMName> -DomainName <DomainName>

少し待っていれば、RdAgent などもろもろが install されているはずです。

まとめ

AVD の RdAgent の再インストールについて、ちょっと時間が経ったので内容を更新しました。
Invoke-AzVMRunCommand-InlineScript に対応したので、少しシンプルになりました。

参考

  • AVD RdAgent とかを再インストールする PowerShell Cmdlet

https://zenn.dev/skmkzyk/articles/avd-rdagent-reinstall

  • Azure VM の OS ディスクのサイズを変更する

https://zenn.dev/skmkzyk/articles/extend-os-disk-azure-vm

  • Azure Virtual Desktop エージェントの概要

https://learn.microsoft.com/azure/virtual-desktop/agent-overview

  • Approved Verbs for PowerShell Commands

https://learn.microsoft.com/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands

  • Azure Resource Manager テンプレートを使用した Desired State Configuration 拡張機能 - Azure Virtual Machines

https://learn.microsoft.com/azure/virtual-machines/extensions/dsc-template#settings-vs-protectedsettings

Discussion