通过 Powershell 获取与 Azure ARM VM 的一组 NIC 关联的当前 IP 地址

Get current IP addresses associated with an Azure ARM VM's set of NICs via Powershell

我正在尝试编写一些 Powershell 来获取 Azure ARM 虚拟机列表(非经典)及其 NIC 当前关联的 IP 地址。

在经典中,这是 VM 对象的一部分,但在 ARM 中它是一个单独的对象,我正在努力让 Powershell 以我想要的方式工作。

我有以下代码段:

$nic = (((Get-AzureRmVM).NetworkProfile).NetworkInterfaces).Id
ForEach ($i in $nic) {
  $nicname = $i.substring($i.LastIndexOf("/")+1)
  Get-AzureRmNetworkInterface -Name $nicname -ResourceGroupName RGTEST | Get-AzureRmNetworkInterfaceIpConfig | select-object  PrivateIpAddress,PrivateIpAllocationMethod
}

有效,但仅适用于指定资源组中的 VM 'RGTEST'。

Get-AzureRmNetworkInterface 似乎只有在传入 NIC Name 和 ResourceGroupName 时才能工作,但我似乎无法从要传入的 VM 中获取 RGname。

可能真的很容易,但我正在努力!

我使用这段代码来获取我所有的 ARM VM,它们的私有 IP 地址和分配方法,它适用于跨资源组。

$vms = get-azurermvm
$nics = get-azurermnetworkinterface | where VirtualMachine -NE $null #skip Nics with no VM

foreach($nic in $nics)
{
    $vm = $vms | where-object -Property Id -EQ $nic.VirtualMachine.id
    $prv =  $nic.IpConfigurations | select-object -ExpandProperty PrivateIpAddress
    $alloc =  $nic.IpConfigurations | select-object -ExpandProperty PrivateIpAllocationMethod
    Write-Output "$($vm.Name) : $prv , $alloc"
}

示例输出:
proddc:10.0.0.4,静态
stagedc : 10.1.0.4 , 静态

找了很多,终于成功了。使用资源组名称和 azure 虚拟机名称,您可以检索私有或 public ip 地址:

$Resourcegroup=""

$VmName=""

$VmNetworkdetails= (((Get-AzureRmVM -ResourceGroupName $Resourcegroup -Name $VmName).NetworkProfile).NetworkInterfaces).Id

$nicname = $VmNetworkdetails.substring($VmNetworkdetails.LastIndexOf("/")+1)

$privateIp =(Get-AzureRmNetworkInterface -Name $nicname -ResourceGroupName $Resourcegroup)|Select-Object -ExpandProperty IPConfigurations 

write-host $privateIp.PrivateIpAddress

下面是我用来获取 Azure ARM VM 的私有 IP 和 Public IP 的脚本。如果 VM 具有多个 NIC 或 IpConfig,则可能需要使用循环。

$rg = Get-AzureRmResourceGroup -Name "MyResourceGroup01"
$vm = Get-AzureRmVM -ResourceGroupName $rg.ResourceGroupName -Name "MyVM01"
$nic = Get-AzureRmNetworkInterface -ResourceGroupName $rg.ResourceGroupName -Name $(Split-Path -Leaf $VM.NetworkProfile.NetworkInterfaces[0].Id)
$nic | Get-AzureRmNetworkInterfaceIpConfig | Select-Object Name,PrivateIpAddress,@{'label'='PublicIpAddress';Expression={Set-Variable -name pip -scope Global -value $(Split-Path -leaf $_.PublicIpAddress.Id);$pip}}
(Get-AzureRmPublicIpAddress -ResourceGroupName $rg.ResourceGroupName -Name $pip).IpAddress

#Output:    
Name      PrivateIpAddress PublicIpAddress
----      ---------------- ---------------
ipconfig1 10.0.0.10        MyVM01-pip

40.80.217.1

这是我用来获取相关 VM Private/Public 用于各种任务的 IP 地址信息的脚本。它将 运行 来自 MAC OS 或 Windows OS 因为我有一个 MAC 和一个 Widows 10 Parallels VM 运行宁的兼容性。随心所欲地使用它。

它将导出为 CSV 并尝试在 Excel 或注册到 CSV 扩展名的任何内容中打开。在下面的示例中,它被保存为 PS_AzureRM_Get_VMs.ps1 或只是 运行 它作为 PowerShell 中的原始代码。

#Login to AZURE from PowerShell
#Below works in MAC/Linux PowerShell 6.0.1+ and Windows WMF 4.0+
#pwsh on MAC OS or powershell_ise.exe on Windows
#Connect-AzureRmAccount (Login-AzureRMAcount and Add-AzureRMAccount are the older Azure cmdlets)
# Goto URL https://microsoft.com/devicelogin and the password it provides example Q9KZ3HGN2
#  You may need to select-azurermsubscription -subscriptionid $SubscriptionID #Define $SubscriptionID = 'replace everything with your actual subscription  xxx-xxxx-xxx'

#Example location using the . way of running a script or just cut and paste to PowerShell
#Example location using the . way of running a script
#MAC PWSH syntax
#. ~/Documents/Scripts/AzureRM/PS_AzureRM_Get_VMs.ps1
#Windows PowerShell.exe/PowerShell_ISE.exe syntax
#. $env:userprofile\Scripts\AzureRM\PS_AzureRM_Get_VMs.ps1

$Project="DevOps"
$clientFilePrefix="AzureRM"
$clientFileCampaign="VMs"

#Get Date Time
$Date = ([DateTime]::Now).ToString("yyyyMMdd")
$Time = ([DateTime]::Now).ToString("HHmmss")
$DateStart=get-date

#Change to Windows Path if running in Windows $env:USERPROFILE
If ($($env:USERPROFILE)) {
  $fldrRoot="$($env:USERPROFILE)\"
  $fldrPathseparator='\'
} Else {
  $fldrRoot="~/"
  $fldrPathseparator='/'
}

# Make Directory if not exist
$fldrPath=$fldrRoot+"Documents"+$fldrPathseparator+$Project+$fldrPathseparator+$clientFilePrefix+$fldrPathseparator+$clientFileCampaign
New-Item -ErrorAction Ignore -ItemType directory -Path $fldrPath

#Make Imports Folder
$fldrPathimports=$fldrPath+$fldrPathseparator+"Imports"
New-Item -ErrorAction Ignore -ItemType directory -Path $fldrPathimports

#Make Exports Folder Directory
$fldrPathexports=$fldrPath+$fldrPathseparator+"Exports"
New-Item -ErrorAction Ignore -ItemType directory -Path $fldrPathexports

#Assign the variable to the export file Prefix
$VMInfo_Export=$fldrPathexports+$fldrPathseparator+$clientFilePrefix+"_"+$Project+"_"+$clientFileCampaign+"_"+$Date+"_"+$Time+".csv"

#Create a Table to use for filtering the results
$VMInfo = New-Object System.Data.DataTable
#Now Add some columns for use later
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'ResourceGroup',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'VM',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'Location',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'VM_ID',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'VM_NIC',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'IP',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'Public_IP_Name',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'Public_IP',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'IP_MAC',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'Priv_Dyn',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'Status',([String])))
$VMInfo.Columns.Add((New-Object System.Data.DataColumn 'Date_Time',([String])))
$VMInfo_Array_Count=($VMInfo | Measure-Object | Select Count).Count

#List the Array to show it='s empty
Write-Host "Created Array VMInfo with $VMInfo_Array_Count objects"

$Date_Time=([DateTime]::Now).ToString("yyyy/MM/dd")+" "+([DateTime]::Now).ToString("HH:mm:ss")
#Check the OS type
If ($($ENV:OS)) {$OSTYPE="WINDOWS";Write-Host "The OS is"$OSTYPE" Based"} Else {$OSTYPE="LINUX";Write-Host "The OS is"$OSTYPE" Based"}
#Get the VM's
$VMs = Get-AzureRmVM
$VMstatus = Get-AzureRmVM -Status
#Get the NIC and their properties for matching against the VMs
$NICs = get-azurermnetworkinterface | where VirtualMachine -NE $null #skip NICs with no VM
#Get the Public IPs for matching against the VMs
#Public IPs work only if the naming convention starts with the VM Name used in Azure
$PublicIPs=Get-AzureRmPublicIpAddress | Select-Object Name,ResourceGroupName,IpAddress

#Now Loop through the NICs in Azure and match against the VMs and the Public IPs
ForEach ($nic in $NICs)
{
    #Get the VM Info
    $VM = $VMs | where-object -Property Id -EQ $nic.VirtualMachine.id
    $VM_Name = $($VM.name)
    $VM_Location = $($VM.Location)
    $VM_Resourcegroup = $($VM.ResourceGroupName)
    $VM_ID = $($VM.VMid)
    $VM_NIC = $nic.Name -Join ';'
    $VM_Status = (($VMstatus | Where {$_.ResourceGroupName -eq $VM_Resourcegroup -and $_.Name -eq $VM_Name}).PowerState).Replace('VM ', '')
    $VM_IP =  ($nic.IpConfigurations | select-object -ExpandProperty PrivateIpAddress) -Join ';'
    $VMPIPName = ($nic.IpConfigurations.PublicIpAddress.Id -Split '/')[-1]
    $VM_PublicIP =  ($PublicIPs | Where-Object {$_.ResourcegroupName -eq $VM_Resourcegroup -and $_.Name -like "$VMPIPName"} | Select IpAddress).IpAddress
    $VM_IP_MAC =  (($nic | Select MacAddress).MacAddress) -Join ';'
    $VM_Alloc =  $nic.IpConfigurations | select-object -ExpandProperty PrivateIpAllocationMethod

    #Uncomment this to check the values before going into the Array $VMINFO
    #Write-Output "$($VM.ResourceGroupName), $($VM.Name), $($VM.VMid), $($VM.Location), $VM_IP, $VM_PublicIP, $VM_IP_MAC, $VM_Alloc"

    #Now populate the $VMInfo array
    $row = $VMInfo.NewRow()
    $row.'ResourceGroup'=$VM_Resourcegroup
    $row.'VM'=$VM_Name
    $row.'VM_ID'=$VM_ID
    $row.'VM_NIC'=$VM_NIC
    $row.'Location'=$VM_Location
    $row.'IP'=$VM_IP
    $row.'Public_IP_Name'=$VMPIPName
    $row.'Public_IP'=$VM_PublicIP
    $row.'IP_MAC'=$VM_IP_MAC
    $row.'Priv_Dyn'=$VM_Alloc
    $row.'Status'=$VM_Status
    $row.'Date_Time'=$Date_Time
    $VMInfo.Rows.Add($row)
}
cls
$TotalTime=(NEW-TIMESPAN –Start $DateStart –End $(GET-DATE))
Write-Host "Script Ran in $($TotalTime.Hours) hours and $($TotalTime.Minutes) minutes and $($TotalTime.Seconds) seconds"

#Export the Info
Write-Host "Exporting VMINFO Report to `n`t$($VMInfo_Export)"
$VMInfo | Export-CSV -NoTypeInformation -Path $VMInfo_Export

#Depending on OS run the Open/Start command for the CSV Export
If ($OSTYPE -eq "LINUX") {open $VMInfo_Export} `
ElseIf ($OSTYPE -eq "WINDOWS") {start $VMInfo_Export} `
Else {Write-Host "Unknown OS"}

break

#####     ######     #####
#######     ######     #####
##     Extra Tasks to Filter the Exports
#####     ######     #####
#######     ######     #####

#Get the Array Size
$VMInfo_Array_Count=($VMInfo | Measure-Object | Select Count).Count

#ECHO the Array size
Write-Host "`n`n*****     *****"
Write-Host "Array VMInfo has $VMInfo_Array_Count objects"
Write-Host "*****     *****"

break
#Shows Configured Resource Group Names
$VMInfo_ResourceGroupNames=($vminfo | Select ResourceGroup -Unique).ResourceGroup

#ECHO Configured Resource Group Names
Write-Host "`n`n*****     *****"
Write-Host "*****     List of Groups*****"
Write-Host "*****     *****"
$($VMInfo_ResourceGroupNames)

break
#Get DC's from resource Group Name
$VM_Environment="dtdaily"
$VMInfo_GetDCs=$vminfo | where {$_.ResourceGroup -eq $VM_Environment -and $_.VM -like "*dc*"}

#ECHO DC's from resource Group Name
Write-Host "`n`n*****     *****"
Write-Host "*****     List of DC's"
Write-Host "*****     *****"
$($VMInfo_GetDCs)

break
#Get Public IP VMs
$VMInfo_PublicIPs=$vminfo | Where {$_.Public_IP -like "*.*"}

#ECHO Public IP VMs
Write-Host "`n`n*****     *****"
Write-Host "*****     *****"
Write-Host "*****     List of Public IP VMs"
Write-Host "*****     *****"
$($VMInfo_PublicIPs)

break
#ECHO All VMs
$VMInfo

Break

对于那些正在寻找适用于租户中多个订阅的解决方案的人来说,这里有一个脚本,它循环遍历每个订阅并报告每个私有 IP、NIC、VM、资源组和相关订阅。输出为对象格式并导出为 CSV 文件。

<#
    .SYNOPSIS
        Returns IP addresses and associated network interfaces and virtual machines across all Azure subscriptions the
        user has access to.

    .DESCRIPTION
        This script returns all private IP addresses, the IP configuration resources they are associated with, the network interfaces and virtual
        machines across all subscriptions. This script requires:

        1. The Azure module to be installed (https://docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-2.8.0)
        2. The user to be logged in to an Azure account using Connect-AzAccount / Connect-AzureRmAccount
        3. The user must have subscription wide read permissions assigned for each subscription being queried

    .PARAMETER FileName
        Optional. Specify the file name and path for a CSV export.

    .EXAMPLE
        Get-IpAddressAllocation.ps1 -FileName .\AzureIpAddressReport.csv
#>

<#
    .AUTHOR
        Michael Wheatfill

    .LICENSEURI
        https://github.com/mwheatfill/mwheatfill.github.io/blob/master/LICENSE.txt
#>

#region Parameters
[CmdletBinding()]
param (
    [Parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]
    $FileName
)
#endregion Parameters

#region Initializations
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
#endregion Initializations

#region Functions
function Get-IpAddresses {
    param ()

    $networkInterfaces = Get-AzNetworkInterface | Where-Object {$_.VirtualMachine -ne $null}
    $virtualMachines = Get-AzVM
    $results = @()

    foreach($interface in $networkInterfaces) {
        $ipConfigurations = $interface.IpConfigurations

        foreach($ipConfig in $ipConfigurations) {
            $vm = $virtualMachines | Where-Object {$_.Id -eq $interface.VirtualMachine.Id}

            $ipDetails = [pscustomobject]@{
                PrivateIpAddress = $ipConfig.PrivateIpAddress
                VMName = $vm.Name
                NetworkInterface = $interface.Name
                IpConfigName = $ipConfig.Name
                Primary = $ipConfig.Primary
                ResourceGroup = $vm.ResourceGroupName
                Subscription = $subscription.Name
            }
            $results += $ipDetails
        }
    }
    return $results
}
#endregion Functions

#region Main
$subscriptions = Get-AzSubscription | Select-Object
$ipAddressesInAllSubscriptions = @()
$progressCount = 0

foreach ($subscription in $subscriptions) {
    $progressCount++
    $progressComplete = ($progressCount / $subscriptions.count * 100)
    $progressMessage = "Gathering IP address informtion for subscription $progressCount of $($subscriptions.Count)"
    Write-Progress -Activity $progressMessage -Status ($subscription.Name) -PercentComplete $progressComplete

    $subscription | Select-AzSubscription > $null
    $ipAddressesInSubscription = Get-IpAddresses -SubscriptionObject $subscription
    $ipAddressesInAllSubscriptions += $ipAddressesInSubscription
}

$ipAddressesInAllSubscriptions | Sort-Object -Property Subscription, VMName, NetworkInterface, IpConfigName, Primary | Format-Table
$ipAddressesInAllSubscriptions | Export-Csv -Path $FileName -NoTypeInformation
#endregion Main

自从 2016 年有人提出这个问题后,Microsoft 决定不再维护 Dec 2020 之后的 AzureRM 模块,以及 *-AzureRM* cmdlet。 Az 模块将取代它。

但是,有一个 快速 的替代方法,可以通过使用 Azure Resource Graph (ARG ).

具体来说,对于分布在数百个 Azure 订阅中的数千台 VM,使用 ARG 只需要 ,而使用 Az 需要 20 多分钟 Get-AzVM cmdlet.

即使在多个 vmNic 和每个 vmNic 的多个 IP 配置上,进一步向下的脚本也会正确报告。它将跨租户中的 Azure 订阅检索所有 ARM VM 数据。如果 运行 来自本地 Powershell 会话或云 Shell,请确保先安装 Az.ResourceGraph 模块。

小型测试 Azure 租户的示例输出:

脚本如下:

function RunARGquery {
    param (
        [string[]]$SubscriptionIds,
        [string]$ARG_query
    )
    
    $fullResultSet = @()
    $pageSize = 5000
    
    # Subscription batching code below taken
    #  from https://docs.microsoft.com/en-us/azure/governance/resource-graph/troubleshoot/general#toomanysubscription
    # Create a counter, set the batch size, and prepare a variable for the results
    $counter = [PSCustomObject] @{ Value = 0 }
    $batchSize = 1000
    # Group the subscriptions into batches
    $subscriptionsBatch = $subscriptionIds | Group -Property { [math]::Floor($counter.Value++ / $batchSize) }

    $currentBatchNo = 0
    # Run the query for each batch
    foreach ($batch in $subscriptionsBatch) {
        $pagesProcessedSoFar = 0
        do {
            $results = @()
            if($pagesProcessedSoFar -eq 0) {
                $results = Search-AzGraph -Subscription $batch.Group -Query $ARG_query -First $pageSize
            }
            else {
                $results = Search-AzGraph -Subscription $batch.Group -Query $ARG_query -First $pageSize -Skip ($pagesProcessedSoFar * $pageSize)
            }
            $pagesProcessedSoFar++
            Write-Host "Processed $pagesProcessedSoFar pages so far. A number of $(($results | Measure-Object).count) results returned in the last page"
            $fullResultSet += $results
        } while(($results | Measure-Object).count -eq $pageSize)
        Write-Host "Finished subscription batch $currentBatchNo"
        $currentBatchNo++
    }
    return $fullResultSet
}

# Get the date/time now, for timestamping both output files
$currentDateTime = Get-Date -Uformat "%Y%m%d-%H%M%S"

Write-Host "Getting list of Azure subscriptions..."
# Fetch the full array of subscription IDs
$subscriptions = Get-AzSubscription
$subscriptionIds = $subscriptions.Id
Write-Host "Found $(($subscriptionIds | Measure-Object).count) subscriptions"

# ARG query from Listing 23
$ARM_ARG_query = @"
Resources
    | where type =~ 'microsoft.compute/virtualmachines'
    | project id, vmId = tolower(tostring(id)), vmName = name
    | join (Resources
        | where type =~ 'microsoft.network/networkinterfaces'
        | mv-expand ipconfig=properties.ipConfigurations
        | project vmId = tolower(tostring(properties.virtualMachine.id)), privateIp = ipconfig.properties.privateIPAddress, publicIpId = tostring(ipconfig.properties.publicIPAddress.id)
        | join kind=leftouter (Resources
            | where type =~ 'microsoft.network/publicipaddresses'
            | project publicIpId = id, publicIp = properties.ipAddress
        ) on publicIpId
        | project-away publicIpId, publicIpId1
        | summarize privateIps = make_list(privateIp), publicIps = make_list(publicIp) by vmId
    ) on vmId
    | project-away vmId, vmId1
    | sort by vmName asc
"@
Write-Host "Running ARM ARG query..."
RunARGquery -SubscriptionIds $subscriptionIds -ARG_query $ARM_ARG_query `
    | Select-Object -ExcludeProperty ResourceId `
    | Sort-Object -Property vmName `
    | Export-Csv -NoTypeInformation "AzureVMs_$currentDateTime.csv"

如果您还想检索经典的 Azure VM(ASM 模型),也可以使用 ARG,可以使用脚本 here. A detailed discussion around the Azure Resource Graph queries for retrieving the VM data, throttling, permissions, etc can be found in this post