マルチモニタをオフにして Bastion で RDP を使う
Bastion が規定でマルチモニタ有効化されるのが辛い
というのがありまして、GitHub でも議論がなされています。
現在では状況が少し変わって、なんか Azure CLI 側には --configure
という option がついたようで close されてますね。
じゃあ PowerShell function にしちゃいましょうねという話
いろいろ GitHub 上でやり取りした結果を PowerShell Function にして profile に追加してしまおうかと思います。
profile はたとえば手元のマシンでは OneDrive for Business が有効化されているのでこちらのフォルダにありました。
"C:\Users\xxxxxxxx\OneDrive - Microsoft\Documents\PowerShell\profile.ps1"
たぶん環境によるので以下の URL を見てください。
その profile.ps1 的なやつに以下の PowerShell の code を追加します。
必須ではない parameter として $VMResourceGroupName
がありますが、Azure VM が Azure Bastion と異なる Resource group の場合には指定します。
同じ場合には省略すれば $VMResourceGroupName
は $ResourceGroupName
と同一とします。
Function Connect-MyAzBastionRdp() {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)] [string] $VMName,
[string] $VMResourceGroupName,
[Parameter(Mandatory = $true)] [string] $ResourceGroupName,
[Parameter(Mandatory = $true)] [string] $BastionName
)
if ([string]::IsNullOrEmpty($VMResourceGroupName)) {
$VMResourceGroupName = $ResourceGroupName
}
@('Az.Accounts', 'Az.Network') | Import-Module
$SubscriptionId = (Get-AzContext).Subscription.Id
$VMResourceID = "/subscriptions/$SubscriptionId/resourceGroups/$VMResourceGroupName/providers/Microsoft.Compute/virtualMachines/$VMName"
$BastionDnsName = (Get-AzBastion -ResourceGroupName $ResourceGroupName -Name $BastionName).DnsName
$Params = @{
Method = 'GET'
Uri = "https://$BastionDnsName/api/rdpfile?resourceId=$VMResourceId&format=rdp"
Headers = @{
'Content-Type' = 'application/json'
'Authorization' = "Bearer $((Get-AzAccessToken).Token)"
}
}
$RdpExclude = @('use multimon', 'signscope', 'signature')
$RdpFile = (Invoke-RestMethod @Params).Split("`n") | Where-Object {
if (-Not [string]::IsNullOrEmpty($_)) {
($Name, $Type, $Value) = $_.Split(':', 3, [System.StringSplitOptions]::TrimEntries)
(-Not $RdpExclude.Contains($Name))
}
}
$RdpFilePath = Join-Path $Env:TEMP "$VMName.rdp"
@('screen mode id:i:1', 'desktopwidth:i:1920', 'desktopheight:i:1080', 'smart sizing:i:1', $RdpFile) | Out-File $RdpFilePath
& 'mstsc.exe' $RdpFilePath
}
これにより、以下のような cmdlet が使えるようになります。
Connect-MyAzBastionRdp -VMName vm-ad01 -ResourceGroupName active-directory -BastionName bast-hub00
My
という部分が独自 cmdlet を示している気持ちで作っていますが、別にどんな名前にしても大丈夫です。
Workaround を GitHub の issue で共有したらもっと改善されたのが来た
過去の内容の記録なのでしまっちゃいます
長くはなったけどわかりやすいっすね。
すばらしー!
$VMName = "RDM-WOA"
$ResourceGroupName = "TestWoa"
$BastionName = "TestWoA-vnet-bastion"
@('Az.Accounts','Az.Network') | Import-Module
$SubscriptionId = (Get-AzContext).Subscription.Id
$VMResourceID = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroupName/providers/Microsoft.Compute/virtualMachines/$VMName"
$BastionDnsName = (Get-AzBastion -ResourceGroupName $ResourceGroupName -Name $BastionName).DnsName
$Params = @{
Method = 'GET'
Uri = "https://$BastionDnsName/api/rdpfile?resourceId=$VMResourceId&format=rdp"
Headers = @{
'Content-Type' = 'application/json'
'Authorization' = "Bearer $((Get-AzAccessToken).Token)"
}
}
$RdpExclude = @('use multimon','signscope','signature')
$RdpFile = (Invoke-RestMethod @Params).Split("`n") | Where-Object {
if (-Not [string]::IsNullOrEmpty($_)) {
($Name, $Type, $Value) = $_.Split(':', 3, [System.StringSplitOptions]::TrimEntries)
(-Not $RdpExclude.Contains($Name))
}
}
$RdpFilePath = Join-Path $Env:TEMP "$VMName.rdp"
$RdpFile | Out-File $RdpFilePath
& 'mstsc.exe' $RdpFilePath
わーくあらうんど
過去の内容の記録なのでしまっちゃいます
叩いてる API の様子を Fiddler で眺めていたら、以下のような感じでマルチモニタをオフにしつつ、つなげられるようになりました。
ポイントとしては Get-AzAccessToken
で JWT をもらってきて、それを使って Bastion の API を叩いて RDP ファイルをもらい、手元で少し編集した後 mstsc
に食わせる、という感じです。
$ResourceGroupName = "xxxxxxxx"
$BastionName = "bast-xxxxxxxx"
$ResourceId = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xxxxxxxx/providers/Microsoft.Compute/virtualMachines/vm-xxxxxxxx"
$RdpFileName = "$($ResourceId.Split("/")[8]).rdp"
$Token = (Get-AzAccessToken).Token
$Headers = @{
'Content-Type' = 'application/json'
'Authorization' = "Bearer $token"
}
$BastionDnsName = (Get-AzBastion -ResourceGroupName $ResourceGroupName -Name $BastionName).DnsName
$(Invoke-RestMethod -Method Get `
-Uri "https://$BastionDnsName/api/rdpfile?resourceId=$ResourceId&format=rdp" `
-Headers $headers).Replace("use multimon:i:1","") | Out-File $RdpFileName
mstsc $RdpFileName
# Remove-Item $RdpFileName
あと、地味にうれしいのは az network bastion rdp
を叩いた Terminal で prompt が返ってこないのに対し、こちらの場合には prompt 返ってくるのでその Terminal がそのまま使えます。
注意事項
一応 API に沿ってるので問題ないかなとは思いますが、使えなくなっても何も保証はないです。
参考
-
Get-AzAccessToken
Azure AD の JWT がこんなに簡単に取れるとは思ってもみなかった
az network bastion rdp
- リモート デスクトップ サービスでサポートされる RDP プロパティ
- PowerShell だけで (Azure CLI を使わずに) Bastion を Native Client で RDP する
- Remote Desktop したときに、最大化してるんだけど Window は小さくしたい
Discussion