Virtual WAN の有効なルートを PowerShell で取得する

azure
Published: 2022-10-03

はじめに

Azure には 有効なルート(Effective Routes) という機能が存在します。設定したルーティングではなく実際のルーティングテーブルを確認できる機能です。通信できない際のトラブルシュートで利用されていることが多いと思います。

Network Interface の有効なルートは、Azure ポータルだけでなく Azure PowerShell からでも確認できます。Network Interface の有効なルートを確認するためには Get-AzEffectiveRouteTable を利用します。

PS C:\>  Get-AzEffectiveRouteTable -ResourceGroupName "eval-arc-tmp-dns-eu" -NetworkInterfaceName "tmp-unbound230" | ft *

Name DisableBgpRoutePropagation State  Source                AddressPrefix      NextHopType           NextHopIpAddress
---- -------------------------- -----  ------                -------------      -----------           ----------------
                          False Active Default               {10.2.0.0/16}      VnetLocal             {}
                          False Active VirtualNetworkGateway {192.168.111.0/24} VirtualNetworkGateway {10.1.6.4}
                          False Active Default               {0.0.0.0/0}        Internet              {}
                          False Active Default               {10.0.0.0/8}       None                  {}
                          False Active Default               {100.64.0.0/10}    None                  {}
                          False Active Default               {172.16.0.0/12}    None                  {}
                          False Active Default               {25.48.0.0/12}     None                  {}
                          False Active Default               {25.4.0.0/14}      None                  {}
                          False Active Default               {198.18.0.0/15}    None                  {}

一方で、Azure PowerShell 8.3.0 のリファレンスを見る限りでは、Virtual WAN の有効なルートを確認する PowerShell コマンドがありません。存在するのは設定値を確認する Get-AzVHubRouteTable だけです。

キャプチャではなくテキスト形式のログの方がログとして残しやすく検索もしやすいので、何とかして PowerShell で Virtual WAN の有効なルートを取得できないのかと試行錯誤した結果をまとめます。

結論

API を使うことで、Virtual WAN の EffectiveRoutes を PowerShell で取得できます。

Virtual Hubs - Get Effective Virtual Hub Routes

実装

この API を利用するためには2段階の手順が必要です。まずはリファレンスの通りに API に対して POST します。

$ErrorActionPreference = "stop"
$subId = "xxxxxxxx-xxxx-xxxx-xxxx-c80ade3ac5ad"
$vhubRgName = "1003vwan"
$vhubName = "vhb"
$rtName = "defaultRouteTable"

$body = @{
    "resourceId" = "/subscriptions/$subId/resourceGroups/$vhubRgName/providers/Microsoft.Network/virtualHubs/$vhubName/hubRouteTables/$rtName"
    "virtualWanResourceType" =  "RouteTable"  
  } | convertto-json

Invoke-AzRest -Path "/subscriptions/$subId/resourceGroups/$vhubRgName/providers/Microsoft.Network/virtualHubs/$vhubName/effectiveRoutes?api-version=2022-05-01" -Method POST -Payload $body

するとコンテンツが Null な応答が返ってきます。あれ?肝心のルーティングテーブルは?

Headers    : {[Cache-Control, System.String[]], [Pragma, System.String[]], [Location, System.String[]], [Retry-After, System.String[]]…}
Version    : 1.1
StatusCode : 202
Method     : POST
Content    : null

Azure リソースマネージャの処理の中には、操作がすぐに完了しないために非同期で実行されるものがあります。リソースマネージャからの応答のステータスコードが201と202の場合、その要求が非同期で処理されたことを示しています。

非同期 Azure 操作の追跡

というわけで、有効なルートを取り出すためにはもうひと手間を書ける必要があります。応答の Azure-AsyncOperation ヘッダには 非同期処理の ID が含まれています。

$res = Invoke-AzRest -Path "/subscriptions/$subId/resourceGroups/$vhubRgName/providers/Microsoft.Network/virtualHubs/$vhubName/effectiveRoutes?api-version=2022-05-01" -Method POST -Payload $body
$operationUrl = $res.Headers.GetValues('Azure-AsyncOperation')
$operationUrl
https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-c80ade3ac5ad/providers/Microsoft.Network/locations/japaneast/operations/c27a59d8-9a7e-40df-9a33-ec2798660dab?api-version=2022-05-01            

この非同期処理の URL に Invoke-AzRest でアクセスしてデータを取得します。非同期処理が終わるのを待つ必要があるので、応答のステータスが InProgress ではなくなるまでループで待ちながらリクエストし続けます。

$res = Invoke-AzRest -Path "/subscriptions/$subId/resourceGroups/$vhubRgName/providers/Microsoft.Network/virtualHubs/$vhubName/effectiveRoutes?api-version=2022-05-01" -Method POST -Payload $body
$operationUrl = $res.Headers.GetValues('Azure-AsyncOperation')
$operationUrl =  $operationUrl[0] -replace "https://management.azure.com",""

do {
  $routes = Invoke-Azrest -path $operationUrl -method Get
  sleep -Seconds 1
  Write-Output ($routes.Content | convertfrom-json).status
} until ( ($routes.Content | convertfrom-json).status -ne "InProgress" )

非同期処理が終わった後の Invoke-Azrest では Virtual WAN の有効なルートが返ってきます。ただし JSON そのままでとても読めたものではないので、見た目を整えて完成です。

  ($routes.Content | convertfrom-json).properties.output.value | Select-Object addressPrefixes, `
          @{Label="nextHops"; Expression={[regex]::Match($_.nextHops,"Microsoft.Network/(.*)").Groups[1].value}}, `
          @{Label="nextHopType"; Expression={$_.nextHopType}}, `
          @{Label="routeOrigin"; Expression={[regex]::Match($_.routeOrigin,"Microsoft.Network/(.*)").Groups[1].value}}, `
          @{Label="asPath"; Expression={$_.asPath}} | ft 

addressPrefixes nextHops                                       nextHopType                routeOrigin                                    asPath
--------------- --------                                       -----------                -----------                                    ------
{10.1.1.0/24}   virtualHubs/vhb/hubVirtualNetworkConnections/1 Virtual Network Connection virtualHubs/vhb/hubVirtualNetworkConnections/1
{10.2.1.0/24}   virtualHubs/vhb/hubVirtualNetworkConnections/2 Virtual Network Connection virtualHubs/vhb/hubVirtualNetworkConnections/2
{172.17.0.0/16} virtualHubs/vhb/hubVirtualNetworkConnections/a Virtual Network Connection virtualHubs/vhb/hubVirtualNetworkConnections/a

まとめ

Virtual WAN の有効なルートを PowerShell で取得する方法をまとめました。普段は Azure PowerShell が裏でやってくれているであろう Azure Resource Manager の非同期処理を理解する良い機会になりました。

おまけ

関数化した PowerShell

function Get-AzVhubEffectiveRoutes {
  param (
    [Parameter(Mandatory=$true)][string]$subId,
    [Parameter(Mandatory=$true)][string]$vhubRgName,
    [Parameter(Mandatory=$true)][string]$vhubName,
    [Parameter(Mandatory=$true)][string]$rtName
  )
  
  $body = @{
    "resourceId" = "/subscriptions/$subId/resourceGroups/$vhubRgName/providers/Microsoft.Network/virtualHubs/$vhubName/hubRouteTables/$rtName"
    "virtualWanResourceType" =  "RouteTable"  
  } | convertto-json

  $res = Invoke-AzRest -Path "/subscriptions/$subId/resourceGroups/$vhubRgName/providers/Microsoft.Network/virtualHubs/$vhubName/effectiveRoutes?api-version=2022-05-01" -Method POST -Payload $body
  $operationUrl = $res.Headers.GetValues('Azure-AsyncOperation')
  $operationUrl =  $operationUrl[0] -replace "https://management.azure.com",""

  do {
    $routes = Invoke-Azrest -path $operationUrl -method Get
  } until ( ($routes.Content | convertfrom-json).status -ne "InProgress" )

  ($routes.Content | convertfrom-json).properties.output.value | Select-Object addressPrefixes, `
          @{Label="nextHops"; Expression={[regex]::Match($_.nextHops,"Microsoft.Network/(.*)").Groups[1].value}}, `
          @{Label="nextHopType"; Expression={$_.nextHopType}}, `
          @{Label="routeOrigin"; Expression={[regex]::Match($_.routeOrigin,"Microsoft.Network/(.*)").Groups[1].value}}, `
          @{Label="asPath"; Expression={$_.asPath}} | ft 

}