Azure security

How to find virtual machines with a public IP in Azure

Find virtual machines with a public IP with Azure PowerShell and Resource Graph, run the query in Resource Graph Explorer, or run Altivane's Azure Virtual Machines report.

By the Published

To find virtual machines with a public IP in Azure, join the public IP addresses in Azure Resource Graph to the network interfaces that hold them, and those to the machines they're attached to. The answer covers addresses on a machine's own network interfaces; whether traffic gets through also depends on its network security group rules.

Choose the method that fits the job
MethodBest fit
PowerShellA CSV of every machine's public addresses across your enabled subscriptions.
Admin centreA quick query in Resource Graph Explorer, with nothing to install.
AltivaneRecommended for security reviews, with each machine flagged and its addresses in a workbook.

Before you start

Use an account with read access to the subscriptions, such as the Reader role: Resource Graph returns nothing for resources you can't read. Microsoft lists no licence for Resource Graph, and it indexes changes with a short delay, so an address attached a moment ago can be missing.

Know what the query follows. A public IP address names the network interface configuration it is attached to, and the network interface names its virtual machine. Machines in a scale set with Uniform orchestration are in the ComputeResources table, not in Resources, so the example leaves them out. The examples read and export; they change nothing. The script's finally block disconnects the account and clears its saved Azure contexts.

Option 1

Find virtual machines with a public IP with PowerShell

Install the modules once. The script runs 1 Resource Graph query with 2 joins across the enabled subscriptions, follows every page of results, and saves 1 row for each public address.

PowerShell
Install-Module -Name Az.Accounts, Az.ResourceGraph -Repository PSGallery -Scope CurrentUser
PowerShell
$ErrorActionPreference = 'Stop'
Connect-AzAccount -ErrorAction Stop
try {
    $subscriptionIds = @(
        Get-AzSubscription | Where-Object State -eq 'Enabled' | Select-Object -ExpandProperty Id
    )
    if ($subscriptionIds.Count -eq 0) {
        Write-Output 'No enabled subscriptions are available to this account.'
        return
    }
    $query = @(
        'Resources'
        '| where type =~ "microsoft.network/publicipaddresses"'
        '| where isnotempty(properties.ipConfiguration.id)'
        '| project id, publicIpName = name, ipAddress = tostring(properties.ipAddress),'
        'nicId = tolower(tostring(split('
        'properties.ipConfiguration.id, "/ipConfigurations/")[0]))'
        '| join kind=inner (Resources'
        '    | where type =~ "microsoft.network/networkinterfaces"'
        '    | project nicId = tolower(id),'
        '    vmId = tolower(tostring(properties.virtualMachine.id))'
        ') on nicId'
        '| join kind=inner (Resources'
        '    | where type =~ "microsoft.compute/virtualmachines"'
        '    | project vmId = tolower(id), vmName = name, resourceGroup, subscriptionId'
        ') on vmId'
        '| project id, vmName, ipAddress, publicIpName, resourceGroup, subscriptionId'
        '| order by id asc'
    ) -join ' '
    $rows = [System.Collections.Generic.List[object]]::new()
    $skipToken = $null
    do {
        $arguments = @{ Query = $query; Subscription = $subscriptionIds; First = 1000 }
        if ($skipToken) { $arguments.SkipToken = $skipToken }
        $page = Search-AzGraph @arguments
        foreach ($record in $page.Data) { $rows.Add($record) }
        $skipToken = $page.SkipToken
    } while ($skipToken)
    if ($rows.Count -eq 0) {
        Write-Output 'No virtual machine in the enabled subscriptions has a public IP address.'
    } else {
        $rows | Sort-Object vmName |
            Select-Object vmName, ipAddress, publicIpName, resourceGroup, subscriptionId, id |
            Export-Csv -Path './vms-with-public-ip.csv' -NoTypeInformation -Encoding utf8
        $machines = @($rows | Select-Object -ExpandProperty vmName -Unique).Count
        Write-Output "$machines machines with $($rows.Count) public addresses saved."
    }
} finally {
    Disconnect-AzAccount | Out-Null
}

Each row is 1 public IP address: the machine's name, the address, the public IP resource's name, the resource group, the subscription and the address's resource ID. A machine with 2 addresses has 2 rows. Resource Graph paging needs id in the results, so keep it if you edit the query.

Option 2

Query machines with a public IP in Resource Graph Explorer

  1. Sign in to the Azure portal with an account that can read the subscriptions.
  2. Search for Resource Graph Explorer and open it.
  3. Paste this query in Query 1 and choose Run query:
    KQL
    Resources
    | where type =~ 'microsoft.network/publicipaddresses'
    | where isnotempty(properties.ipConfiguration.id)
    | project id, publicIpName = name, ipAddress = tostring(properties.ipAddress),
        nicId = tolower(tostring(split(properties.ipConfiguration.id, '/ipConfigurations/')[0]))
    | join kind=inner (Resources
        | where type =~ 'microsoft.network/networkinterfaces'
        | project nicId = tolower(id), vmId = tolower(tostring(properties.virtualMachine.id))
    ) on nicId
    | join kind=inner (Resources
        | where type =~ 'microsoft.compute/virtualmachines'
        | project vmId = tolower(id), vmName = name, resourceGroup, subscriptionId
    ) on vmId
    | project vmName, ipAddress, publicIpName, resourceGroup, subscriptionId
  4. Read the machines in Results, or choose Download as CSV for a file.

Explorer suits an occasional check with nothing to install. Its download stops at 55,000 records; for a larger estate or the same file each month, use PowerShell or Altivane.

Common questions

Does a public IP mean the machine is open to the internet?

It means the machine has an address on the internet. Which traffic reaches it depends on the network security group rules on its network interface and subnet, so read those too. See how to find NSG rules open to the internet in Azure.

Why is a public IP address missing from the list?

The query keeps addresses attached to a virtual machine's network interface. An address attached to nothing, or to another kind of resource, isn't on a machine, so it is left out.

Why does the query fail with too many joins?

Resource Graph allows 3 join or union operations in 1 query. This query uses 2, so add at most 1 more if you extend it.

Microsoft references

Technical references checked on 7 November 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.

Talk to us about Altivane

Questions, or pricing? Get in touch.

Contact us