[Azure][PowerShell] VM のパブリック IP アドレスを取得する

## 概要

PowerShell の Az モジュールでは `Get-AzPublicIpAddress` でパブリック IP アドレス (PIP) の情報を取得することができますが、このコマンドには PIP の名前が必要です。
普通 VM の名前とリソース グループとかでサーバーを認識してることのほうが多いので、VM の情報 (i.e. 名前、リソースグループ名) から PIP が取得できれば便利です。
そこで、`Get-AzVM` から取得された VM オブジェクトから紐づく PIP を (存在すれば) 取得する PowerShell スクリプトを紹介します。

## スクリプト

簡単にやり方を説明すると、次のようなステップで VM から PIP にたどり着くことができます。

- VM オブジェクトから、NIC Id を抽出
- NIC Id から、`Get-AzNetworkInterface` で NIC オブジェクトを取得
- NIC オブジェクトから、PIP 名を抽出
- PIP 名から、`Get-AzPublicIpAddress` で PIP オブジェクトを取得し、PIP を抽出

Azure リソースの観点でいうと、VM -> NIC -> PIP と遷移していきます。
具体的には、以下のようなスクリプトで上を実現します。

```powershell
# 何らかの条件で VM を取得
$VM = Get-AzVM | where { someconditionhere } | select -Last 1

# NIC を取得
$Nic = $VM.NetworkProfile.NetworkInterfaces.Id | Get-AzNetworkInterface

# PIP の ID を取得
$PipId = $Nic.IpConfigurations[0].PublicIpAddress.Id

if ($PipId) {
    # PIP は Id で Get-Az* を叩けないので名前と RG を抽出する必要がある
    # Id = /subscriptions/.../resourceGroups/<rg-name>/providers/Microsoft.Network/publicIPAddresses/<pip-name>
    $PipName = $PipId.Split('/')[-1]
    $PipResourceGroupName = $PipId.Split('/')[4]

    $Pip = Get-AzPublicIpAddress -Name $PipName -ResourceGroupName $PipResourceGroupName
    $Write-Output $Pip
}
```

なお、プライベート IP アドレスなら NIC.IpConfigurations プロパティに情報があるので、次のように NIC オブジェクトから直で取得できます

```powershell
$NICs = Get-AzNetworkInterface | where { somecondition }
$PrivateIpAddresses = $NICs | foreach { $_.IpConfigurations.PrivateIpAddress }
```

## 応用：特定サブネットに紐づくすべてのパブリック IP アドレスを取得

```powershell
# Parameters
# ----------

# VNet の名前とリソースグループ名
$VNetName = "<名前>"
$ResourceGroupName = "<リソースグループ名>"

# サブネットの名前/アドレス空間のどちらか一つを必ず指定
$SubnetName = "<サブネット名>"
$SubnetAddressPrefix = "<10.0.0.0/24 等のアドレス空間>"

# Process
# -------

# 対象のサブネットを取得
$VNet = Get-AzVirtualNetwork -Name $VNetName -ResourceGroupName $ResourceGroupName
if ($SubnetName) {
    $Subnet = $VNet.Subnets | ? Name -eq $SubnetName
} else {
    $Subnet = $VNet.Subnets | ? AddressPrefix -eq $SubnetAddressPrefix
}

# サブネット内部に存在する NIC リストを取得
$NICNames = $Subnet.IpConfigurations | % { $_.Id.Split('/')[8] }
$NICs = $NICNames | % { Get-AzNetworkInterface -ResourceGroupName $ResourceGroupName -Name $_ }

# NIC に紐付いている PIP リストを取得
$PIPNames = $NICs | `
    ? { $_.IpConfigurations.PublicIpAddress } | `
    % { $_.IpConfigurations.PublicIpAddress.Id.Split('/') | select -Last 1 }
$PIPs = $PIPNames | % { (Get-AzPublicIpAddress -ResourceGroupName $ResourceGroupName -Name $_).IpAddress }

Write-Output $PIPs
```

## Private IP Address

`Parameters` は同じなので省きます。

```powershell
# 対象のサブネットを取得
$VNet = Get-AzVirtualNetwork -Name $VNetName -ResourceGroupName $ResourceGroupName
if ($SubnetName) {
    $Subnet = $VNet.Subnets | ? Name -eq $SubnetName
} else {
    $Subnet = $VNet.Subnets | ? AddressPrefix -eq $SubnetAddressPrefix
}

# サブネット内部に存在する NIC リストを取得
$NICNames = $Subnet.IpConfigurations | % { $_.Id.Split('/')[8] }
$NICs = $NICNames | % { Get-AzNetworkInterface -ResourceGroupName $ResourceGroupName -Name $_ }

# ---- ここまでは PIP と同じ ----

# NIC に紐付いている Private IP Address のリストを取得
$PrivateIpAddresses = $NICs | % { $_.IpConfigurations.PrivateIpAddress }

Write-Output $PrivateIpAddresses 
```

## 参考

* [Get-AzVirtualNetwork (Az.Network) | Microsoft Docs](https://docs.microsoft.com/en-us/powershell/module/az.network/get-azvirtualnetwork)
* [Get-AzNetworkInterface (Az.Network) | Microsoft Docs](https://docs.microsoft.com/en-us/powershell/module/az.network/get-aznetworkinterface)
* [Get-AzPublicIpAddress (Az.Network) | Microsoft Docs](https://docs.microsoft.com/en-us/powershell/module/az.network/get-azpublicipaddress)