marli-EndpointInUse.ps1

function marli-EndpointInUse{
 function New_Entry ([int]$xposi,[int]$yposi,[string]$Text,[System.ConsoleColor]$Color){
  $position=$Host.ui.RawUI.CursorPosition
  $position.x = $xposi
  $position.y = $yposi
  $Host.ui.RawUI.CursorPosition=$position
  Write-Host $Text -ForegroundColor $Color
 }
 function Mainmenu {
 
  Clear-Host
  
  Write-Host '[' -NoNewline
  Write-Host ' ]>------ Downloading Endpoints'
 
  Write-Host '[' -NoNewline
  Write-Host ' ]>------ Checking Connections'
 
  Write-Host '[' -NoNewline
  Write-Host ' ]>------ Compare results'
 
 }
 function Download-MicrosoftEndpoints {
     [CmdletBinding(DefaultParameterSetName = 'Default')]
 
     #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 -UseBasicParsing | ConvertFrom-Json
     }
     catch {
         Write-Warning ("Error downloading worldwide Microsoft Endpoints, please check if {0} is accessible" -f $jsonlink)
         return
     }
 
     $TestEndpoints = $Endpoints | Where-Object urls -ne $null | Select-Object urls, tcpports, udpports, ips, notes, serviceAreaDisplayName
 
     #Test Microsoft Endpoint Adresses and report if failed or succeeded
     $total = foreach ($TestEndpoint in $TestEndpoints) {
         if ($TestEndpoint.tcpPorts) {
             foreach ($tcpport in $TestEndpoint.tcpPorts.split(',')) {
                 foreach ($testurl in $TestEndpoint.urls) {

                     #Test connection and retrieve all information
                     $results = $null
                     If ($testurl -match "\*"){$testurl = $testurl.Replace("*.","")}
                     $results = (Resolve-DnsName -Name $testurl -DnsOnly -ErrorAction SilentlyContinue).IP4Address
                     If ($results)
                     {
                      $Status = 'Succeeded'
                      $ipaddress = $results
                     }
                     else {
                      $Status = "Failed or couldn't resolve DNS name"
                      $ipaddress = "Not applicable"
                     }
                    
                     [PSCustomObject]@{
                         Status          = $Status
                         URL             = $testurl
                         TCPport         = $tcpport
                         IPAddressUsed   = $ipaddress
                     }
                 }
             }
         }
     }
     return $total
  }
 function Get-NetAllConnections {
    # unfortunately netstat takes a lot of time to run
    $cmdOutput = netstat -a
    $connections = $cmdOutput[4..$cmdOutput.count] | ConvertFrom-String -PropertyNames Empty, Protocol, LocalAddress, RemoteAddress, State | Select Protocol, LocalAddress, RemoteAddress, State
    $getNetAllConnections = @()
    foreach ($connection in $connections)
    {
        $getNetTCPConnetion_FakeObject = New-Object -TypeName psobject
        $getNetTCPConnetion_FakeObject | Add-Member -MemberType NoteProperty -Name Protocol -Value $connection.Protocol
        # split netstat LocalAddress value by ':' because it contains both address and port
        $tempCon = $connection.LocalAddress -split "(:)"
        $lastIndexOfFirstPart = $tempCon.count - 3
        $tempConPart1Buffer = ""
        foreach ($row in $tempCon[0..$lastIndexOfFirstPart]) { $tempConPart1Buffer += $row }
        $tempConPart1 = $tempConPart1Buffer
        $indexOfSecondPart = $tempCon.count - 1
        $tempConPart2 = $tempCon[$indexOfSecondPart]
        # with PS version 7 this could be simplyfied, because -split supports negative values:
        #$tempCon = ($connection.LocalAddress -split "(:)", -1)
        #$tempConPart1 = $tempCon[0]
        #$tempConPart2 = $tempCon[1]
        $getNetTCPConnetion_FakeObject | Add-Member -MemberType NoteProperty -Name LocalAddress -Value $tempConPart1
        $getNetTCPConnetion_FakeObject | Add-Member -MemberType NoteProperty -Name LocalPort -Value $tempConPart2
        # split netstat RemoteAddress value by ':' because it contains both address and port
        $tempCon = $connection.RemoteAddress -split "(:)"
        $lastIndexOfFirstPart = $tempCon.count - 3
        $tempConPart1Buffer = ""
        foreach ($row in $tempCon[0..$lastIndexOfFirstPart]) { $tempConPart1Buffer += $row }
        $tempConPart1 = $tempConPart1Buffer
        $indexOfSecondPart = $tempCon.count - 1
        $tempConPart2 = $tempCon[$indexOfSecondPart]
        # with PS version 7 this could be simplyfied, because -split supports negative values:
        #$tempCon = ($connection.LocalAddress -split "(:)", -1)
        #$tempConPart1 = $tempCon[0]
        #$tempConPart2 = $tempCon[1]
        $getNetTCPConnetion_FakeObject | Add-Member -MemberType NoteProperty -Name RemoteAddress -Value $tempConPart1
        $getNetTCPConnetion_FakeObject | Add-Member -MemberType NoteProperty -Name RemotePort -Value $tempConPart2
        $getNetTCPConnetion_FakeObject | Add-Member -MemberType NoteProperty -Name State -Value connection.State
        $getNetAllConnections += $getNetTCPConnetion_FakeObject
    }
    # if you want to display output and format it the same as 'Get-NetTCPConnection' does:
    #$getNetAllConnections | Format-Table
    return $getNetAllConnections
 }
 function Filter-Results($Connections, $Endpoints){
    $List = @()

    If ($endpoints -and $Connections)
    {
      Foreach ($endpoint in $endpoints)
      {
        $ips = $endpoint.IPAddressUsed
        If ($ips.Count -ge 2)
        {     
          Foreach ($ip in $ips)
          {
            Foreach ($conn in $Connections)
            {            
              If ($conn -eq $ip)
              {
                $line = '' | Select URL, EndpointIP
                $line.URL = $endpoint.URL
                $line.EndpointIP = $ip
                $List += $line
              }
            }
          }
        }
        else{
          Foreach ($conn in $Connections)
          {      
            If ($conn -eq $ips)
            {
              $line = '' | Select URL, EndpointIP
              $line.URL = $endpoint.URL
              $line.EndpointIP = $ips
              $List += $line
            }
          }
        }
      }
    }

    If (!$List) {
      $line = '' | Select URL, EndpointIP
      $line.URL = ''
      $line.EndpointIP = ''
      $List += $line
    }
    return $List | Sort-Object -Unique URL, EndpointIP
  }
 
 [System.Console]::CursorVisible = $false
 Mainmenu
 
 #Download Endpoints
 If (!$endpoints){
   New_Entry -xposi 1 -yposi 0 -Text '<' -Color Yellow
   $endpoints = Download-MicrosoftEndpoints | Where-Object {$_.Status -eq 'Succeeded'} 
 }

 If ($endpoints){
   New_Entry -xposi 1 -yposi 0 -Text '+' -Color Green
 }
 else{
   New_Entry -xposi 1 -yposi 0 -Text 'x' -Color Red
   #break
 }

 #Check own Connections
 New_Entry -xposi 1 -yposi 1 -Text '<' -Color Yellow
 $Connections = $null
 $Connections = (Get-NetAllConnections).RemoteAddress | Where-Object {$_ -notmatch ':' -and $_ -like '*.*'} | Sort-Object -Unique
 
 If ($Connections){
   New_Entry -xposi 1 -yposi 1 -Text '+' -Color Green
 }
 else{
   New_Entry -xposi 1 -yposi 1 -Text 'x' -Color Red
   break
 }
 
 #Filtering results
 New_Entry -xposi 1 -yposi 2 -Text '<' -Color Yellow
 $results = Filter-Results -Connections $Connections -Endpoints $endpoints

 If ($results){
   New_Entry -xposi 1 -yposi 2 -Text '+' -Color Green
 }
 else{
   New_Entry -xposi 1 -yposi 2 -Text 'x' -Color Red
   break
 }

 Clear-Host
 return $results

 [System.Console]::CursorVisible = $True
}