In an environment with strict internet access, you need to determine which Microsoft services to open and which destinations to allow for services like Exchange Online, Teams, Endpoint Manager, and more. Microsoft publishes this on its website, but in this blog post, I’ll show you a convenient way to export that information to Out-GridView or a CSV file.
How the script works
It downloads information from a Microsoft-hosted link containing all IP addresses and FQDNs with their TCP or UDP ports, then converts the JSON into an object. Afterward, it displays the information in an Out-GridView or Out-ConsoleGridview Window for easy sorting and filtering (you can copy your selection in the window with CTRL-C), or exports to a CSV if you use the CSVPath parameter.
Running the script
When running it without any parameters, it looks like this:

When running it with the -CSVPath parameter and specifying the output path, like in the example below, which saves it to d:\temp\endpoints.csv, it looks like this:
Get-MicrosoftEndpoints -CSVPath d:\temp\endpoints.csv

The script
Below is the script. You can add it to your PowerShell profile by:
notepad $profile add '. c:\scripts\get-microsoftendpoints.ps1' quit/save and start a new PowerShell session
function Get-MicrosoftEndpoints {
param (
[parameter(parameterSetName = "CSV")][string]$CSVPath
)
# Stop if $CSVPath was not specified and PowerShell v6 is being used
if (-not $CSVPath -and $PSVersionTable.PSVersion.Major -eq 6) {
Write-Warning ("Only -CSVPath can be used when running PowerShell v6, exiting...")
return
}
#Hide download progress, get current JSON url, retrieve all Endpoints and Convert it from JSON format
$ProgressPreference = "SilentlyContinue"
try {
$site = Invoke-WebRequest -Uri 'https://learn.microsoft.com/en-us/microsoft-365/enterprise/urls-and-ip-address-ranges?view=o365-worldwide' -UseBasicParsing -ErrorAction Stop
$jsonlink = ($site.Links | Where-Object OuterHTML -Match 'JSON formatted').href
}
catch {
Write-Warning ("Error downloading JSON file, please check if https://learn.microsoft.com/en-us/microsoft-365/enterprise/urls-and-ip-address-ranges?view=o365-worldwide is accessible")
return
}
try {
$Endpoints = Invoke-WebRequest -Uri $jsonlink -ErrorAction Stop -UseBasicParsing | ConvertFrom-Json
Write-Host ("Downloading worldwide Microsoft Endpoints") -ForegroundColor Green
}
catch {
Write-Warning ("Error downloading worldwide Microsoft Endpoints, please check if $($jsonlink) is accessible")
return
}
Write-Host ("Processing items...") -ForegroundColor Green
$Total = foreach ($Endpoint in $Endpoints) {
#Check if IPs are available for the Endpoint, set to not available if not
if (-not $Endpoint.ips) {
$IPaddresses = 'Not available'
}
else {
$IPaddresses = $Endpoint.ips -join ', '
}
#Check if TCP ports are available for the Endpoint, set to not available if not
if (-not $Endpoint.tcpPorts) {
$TCPPorts = 'Not available'
}
else {
$TCPPorts = $Endpoint.TCPPorts -join ', '
}
#Check if UDP ports are available for the Endpoint, set to not available if not
if (-not $Endpoint.udpPorts) {
$UDPPorts = 'Not available'
}
else {
$UDPPorts = $Endpoint.udpPorts -join ', '
}
#Check if there are notes for the Endpoint, set to not available if not
if (-not $Endpoint.notes) {
$Notes = 'Not available'
}
else {
$Notes = $Endpoint.Notes
}
#Check if URLs are available for the Endpoint, set to not available if not
if (-not $Endpoint.urls) {
$URLlist = 'Not available'
}
else {
$URLlist = $Endpoint.urls -join ', '
}
[PSCustomObject]@{
serviceArea = $Endpoint.serviceArea
serviceAreaDisplayName = $Endpoint.serviceAreaDisplayName
urls = $URLlist
ips = $IPaddresses
tcpPorts = $TCPPorts
udpPorts = $UDPPorts
notes = $notes
expressRoute = $Endpoint.expressRoute
category = $Endpoint.Category
required = $Endpoint.required
}
}
#Export data to specified $CSVPath if specified
if ($CSVPath) {
try {
New-Item -Path $CSVPath -ItemType File -Force:$true -ErrorAction Stop | Out-Null
$Total | Sort-Object serviceAreaDisplayName | Export-Csv -Path $CSVPath -Encoding UTF8 -Delimiter ';' -NoTypeInformation -ErrorAction Stop
Write-Host ("Saved results to {0} `nDone!" -f $CSVPath) -ForegroundColor Green
}
catch {
Write-Warning ("Could not save results to {0}" -f $CSVPath)
Write-Warning $_.Exception.Message
return
}
}
else {
#Export to Out-Gridview or Out-ConsoleGridview depending on $Host.Version.Major
if ($PSVersionTable.PSVersion.Major -ge 7) {
if (-not (Get-Module Microsoft.PowerShell.ConsoleGuiTools -ListAvailable)) {
try {
Install-Module Microsoft.PowerShell.ConsoleGuiTools -Scope CurrentUser -ErrorAction Stop
Import-Module Microsoft.PowerShell.ConsoleGuiTools -ErrorAction Stop
Write-Host ('Installed missing PowerShell Module Microsoft.PowerShell.ConsoleGuiTools which is needed for ConsoleGridView output') -ForegroundColor Green
}
catch {
Write-Warning ('Could not install missing PowerShell Module Microsoft.PowerShell.ConsoleGuiTools which is needed for ConsoleGridView output, exiting...')
return
}
}
Write-Host ("Exporting results to Out-ConsoleGridView `nDone!") -ForegroundColor Green
$Total | Sort-Object serviceAreaDisplayName | Out-ConsoleGridView -Title 'Microsoft Endpoints Worldwide'
}
if ($PSVersionTable.PSVersion.Major -eq 5) {
Write-Host ("Exporting results to Out-GridView `nDone!") -ForegroundColor Green
$Total | Sort-Object serviceAreaDisplayName | Out-GridView -Title 'Microsoft Endpoints Worldwide'
}
}
}
Download the script(s) from GitHub here
You should include UUID generation in your script as it mentions on the page here: https://learn.microsoft.com/en-us/microsoft-365/enterprise/microsoft-365-ip-web-service?view=o365-worldwide. The UUID used in your example may become unusable in the future, which will break all the script for all the people who’re using it!
Yep, you’re right and I did mention it too in the post 😊 I’ve did a blog earlier in which I retrieved the current link, will update this one later with the same method
I changed the script so that it checks for the current JSON link, this makes it more dynamic in case the download link changes on the page.
you have a typo on the suggestion for the profile edit. “add ‘. c:\scripts\get-microsoftendpoints.csv’” should presumably be add ‘. c:\scripts\get-microsoftendpoints.ps1’
You’re right! Thanks, updated it now 😅