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.
| Method | Best fit |
|---|---|
| PowerShell | A CSV of every machine's public addresses across your enabled subscriptions. |
| Admin centre | A quick query in Resource Graph Explorer, with nothing to install. |
| Altivane | Recommended 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.
Install-Module -Name Az.Accounts, Az.ResourceGraph -Repository PSGallery -Scope CurrentUser$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
- Sign in to the Azure portal with an account that can read the subscriptions.
- Search for Resource Graph Explorer and open it.
- Paste this query in Query 1 and choose Run 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 vmName, ipAddress, publicIpName, resourceGroup, subscriptionId - 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.
Option 3 ยท Recommended for security reviews
Find virtual machines with a public IP with Altivane
- Open Altivane and choose the tenant.
- Run the Azure Virtual Machines report.
- Open the Excel workbook and find Azure virtual machines, then filter Findings to Has a public IP address.
- Read Public IP addresses for each address the machine can be reached on, beside its power state and size.
Altivane follows every network interface on each machine, lists each public address once, and says None for a machine with no address. The Azure Network Exposure scorecard report counts the machines with a public IP address beside the inbound rules open to the internet. The report needs a tenant signed in with a certificate and the Reader role for Altivane on the subscriptions.
Contact usCommon 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.