Test if Microsoft services TCP ports are accessible

In a previous blog post, I showed how to retrieve all the Microsoft Services FQDNs, ports, and IP-Addresses. Nice to know those in secure environments where not everything is allowed to go onto the internet, but how can you test if they are accessible? This blog post will show how to test most of these services using PowerShell.

How the script works

It uses the method I used in this blog post to retrieve the most current list of services. It then checks for all the URLs in it and tries to connect to each TCP port. On-screen, while running the script, it will show the progress of the scan and will output it to an Out-GridView screen or a CSV file if specified.

Note: There are a few UDP ports for the Microsoft services, but this script does not check for them. I will try to update it to include UDP ports, but checking them is more difficult than checking TCP ports.

Running the script

The function Test-MicrosoftEndpoints has a few parameters which you can use to search for specific products and services or to specify the location of the CSV output file:

  • All, scans all the services and the associated TCP ports
  • CSVPath, the full path to the CSV file. For example, d:\data\endpointcheck.csv
  • Note this parameter followed by ‘Exchange,’ for example, will search for all Exchange ports.
  • ServiceDisplayName, this parameter followed by ‘OneDrive’ will search for all OneDrive ports
  • URL, this parameter followed by ‘Outlook,’ for example, will search for all URLs containing Outlook

Note: For a good overview of keywords to search for, create an output file using this blog post or go to this URL.

In the example below, I started the script with the -Note ‘Exchange’ parameter to test all Exchange TCP ports. As you can see, the script can’t check the wildcard (*) addresses.

The results in the Out-GridView look like this, in the IPAddressUsed column, you can see which IP address was returned from the DNS query for outlook.office.com at that moment:

Below is another example in which I used the -Note ‘Exchange’ and -CSVPath parameters to save the results for Exchange ports to d:\temp\output.csv.

The CSV file looks like this:

The script

Below is the script. Please save it to c:\data\Test-MicrosoftEndpoints.ps1, for example. You can run it in your current session by running ‘ . c:\data\Test-MicrosoftEndpoints.ps1’ to have the Test-MicrosoftEndpoints function available.

function Test-MicrosoftEndpoints {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [parameter(parameterSetName = "All")][switch]$All,
        [parameter(Mandatory = $false)][string]$CSVPath,
        [parameter(parameterSetName = "Note")][string]$Note,
        [parameter(parameterSetName = "ServiceAreaDisplayName")][string]$ServiceAreaDisplayName,
        [parameter(parameterSetName = "URL")][string]$URL
    )

    #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
        $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 | ConvertFrom-Json
        Write-Host ("Downloading worldwide Microsoft Endpoints") -ForegroundColor Green
    }
    catch {
        Write-Warning ("Error downloading worldwide Microsoft Endpoints, please check if {0} is accessible" -f $jsonlink)
        return
    }

    #Search for specified parameter value
    if ($All) {
        $TestEndpoints = $Endpoints | Where-Object urls -ne $null | Select-Object urls, tcpports, udpports, ips, notes
    }

    if ($note) {
        $TestEndpoints = $Endpoints | Where-Object Notes -Match $note | Select-Object urls, tcpports, udpports, ips, notes
    }

    if ($ServiceAreaDisplayName) {
        $TestEndpoints = $Endpoints | Where-Object ServiceAreaDisplayName -Match $ServiceAreaDisplayName | Select-Object urls, tcpports, udpports, ips, notes
    }

    if ($URL) {
        $TestEndpoints = $Endpoints | Where-Object urls -Match $URL | Select-Object urls, tcpports, udpports, ips, notes
    }

    if ($null -eq $TestEndpoints) {
        Write-Warning ("No results found...")
        return
    }

    #Test Microsoft Endpoint Adresses and report if failed or succeeded
    $Global:ProgressPreference = 'SilentlyContinue'
    $total = foreach ($TestEndpoint in $TestEndpoints) {
        if ($TestEndpoint.tcpPorts) {
            foreach ($tcpport in $TestEndpoint.tcpPorts.split(',')) {
                foreach ($testurl in $TestEndpoint.urls) {
                    if ($TestEndpoint.notes) {
                        $notes = $TestEndpoint.notes
                    }
                    else {
                        $notes = "No notes available"
                    }

                    #Test connection and retrieve all information
                    $test = Test-NetConnection -Port $tcpport -ComputerName $testurl -ErrorAction SilentlyContinue -InformationLevel Detailed 
                    if ($test.TcpTestSucceeded -eq $true) {
                        $Status = 'Succeeded'
                        $ipaddress = $test.RemoteAddress
                        Write-Host ("{0} is reachable on TCP port {1} ({2}) using IP-Address {3}" -f $testurl, $tcpport, $notes, $ipaddress) -ForegroundColor Green
                        
                    }
                    else {
                        $Status = "Failed or couldn't resolve DNS name"
                        $ipaddress = "Not applicable"
                    }

                    #Set iprange variable if applicable
                    if ($TestEndpoint.ips) {
                        $iprange = $TestEndpoint.ips -join (', ')
                    }
                    else {
                        $iprange = "Not applicable"
                    }
                    
                    [PSCustomObject]@{
                        Status          = $Status
                        URL             = $testurl
                        TCPport         = $tcpport
                        IPAddressUsed   = $ipaddress
                        Notes           = $notes
                        EndpointIPrange = $iprange
                    }
                }
            }
        }
    }

    #Output results to Out-Gridview or CSV
    if (-not $CSVPath) {
        Write-Host ("Output results to Out-GridView `nDone!") -ForegroundColor Green
        $total | Sort-Object Url, TCPport | Out-GridView -Title 'Microsoft Endpoints Test results'
    }
    else {
        try {
            New-Item -Path $CSVPath -ItemType File -Force:$true -ErrorAction Stop | Out-Null
            $Total | Sort-Object Url, TCPport | Export-Csv -Path $CSVPath -Encoding UTF8 -Delimiter ';' -NoTypeInformation
            Write-Host ("Saved results to {0} `nDone!" -f $CSVPath) -ForegroundColor Green
        }
        catch {
            Write-Warning ("Could not save results to {0}" -f $CSVPath)
        }
    }
}

Download the script(s) from GitHub here

3 thoughts on “Test if Microsoft services TCP ports are accessible

    • That’s strange, no errors while testing in PowerShell 7 in VSCode… But I added it now, if this helps for other people… Then it’s good, it still works for me too after adding πŸ™‚

  1. Pingback: Endpoint Manager Newsletter - 30th September 2022 - Andrew Taylor

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.