Back
Featured image of post PowerShell Function to get the Office 365 URLs and IP address ranges

PowerShell Function to get the Office 365 URLs and IP address ranges

Update: There is a newer Script, that uses the new JSON based service from Microsoft! You should use the newer one instead of this!

I know that there are a few functions and scripts like this available. Honestly, the roots of this function are a bit older.

Now some of our developers at enabling Technology tweaked and extended my old function, and they also quashed out a few bugs!

Here is what they came up with:

function Get-Office365NetworkInfo
{
    <#
            .SYNOPSIS
          The function gets the Office 365 URLs and IP address ranges.

            .DESCRIPTION
          Get the Office 365 URLs and IP address ranges via the Microsoft published XML format.
          You can filter what product (e.g. O365, SPO, etc.) and type (IPV4, IPV6, or URL) and select the Environment to use.

            .PARAMETER Type
          Service Types to get, default is All for everything
          Multiple values are allowd

          Possible values are:
          All = Everything (the default)
          URL = Only URLs
          IPv4 = Only IPv4 Information
          IPv6 = Only IPv6 Information

            .PARAMETER Product
          Products to get, default is All for everthing
          Multiple values are allowd

          Possible values are:
          All = Everything (the default)
          o365 = Office 365 portal and shared
          LYO = Skype for Business Online
          Planner = Microsoft Planner
          Teams = Microsoft Teams
          ProPlus = Office Clients
          OneNote = Microsoft OneNote
          Yammer = Microsoft Yammer
          EXO = Exchange Online
          Identity = Office 365 authentication and identity
          Office365Video = Office 365 Video and Microsoft Stream
          WAC = Office Online
          SPO = SharePoint Online and OneDrive
          RCA = Office 365 remote analyzer tools
          Sway = Microsoft Sway
          EX-Fed = Exchange Federation
          OfficeMobile =
          CRLs = Certificate revocation list
          OfficeiPad = Office for iOS
          EOP = Exchange Online Protection
          SfB = Skype for Business Online - USDefense & USDoD only
          OfficeOnline = Office Onlien CDN - USDefense & USDoD only
          Portal = Office 365 Portal - USDefense & USDoD only

            .PARAMETER Environment
          The Office365/Azure Environment to use, Default is Office 365 Worldwide (+GCC)
          Multiple values are not allowd

          Possible values are:
          Default = Office 365 Worldwide (+GCC)
          USDefense = Office 365 U.S. Government GCC High
          USDoD = Office 365 U.S. Government DoD
          Telekom = Office 365 Germany
          21Vianet = Office 365 operated by 21 Vianet

            .LINK
          https://aka.ms/o365endpoints

            .LINK
          http://aka.ms/o365ip

            .LINK
          https://support.content.office.net/en-us/static/Office365IPAddresses.xml

            .LINK
          http://iprange.omartin2010.com
          https://azurerange.azurewebsites.net

            .EXAMPLE
          PS C:\> Get-Office365NetworkInfo

          It gets the Office 365 URLs and IP address ranges.

            .EXAMPLE
          PS C:\> Get-Office365NetworkInfo -Type url

          It gets the Office 365 URLs only.

            .EXAMPLE
          PS C:\> Get-Office365NetworkInfo -Type url -Environment USDefense

          It gets the Office 365 U.S. Government GCC High URLs only for the.


            .EXAMPLE
          PS C:\> Get-Office365NetworkInfo -Product 'LYO'

          It gets the Office 365 URLs and IP address ranges for Skype for Business.

            .EXAMPLE
          PS C:\> Get-Office365NetworkInfo -Product 'Teams' -Type 'IPv4'

          It gets the Office 365 IPv6 address ranges for Microsoft Teams.

            .EXAMPLE
          PS C:\> Get-Office365NetworkInfo -Product 'Teams' -Type 'IPv4','IPv6'

          It gets the Office 365 IP (IPv4 and IPv6) address ranges for Microsoft Teams.

            .EXAMPLE
          PS C:\> (Get-Office365NetworkInfo -Product 'EXO' -Type url).Addresses | Sort-Object | Get-Unique

          It gets the Office 365 URLs for Exchange Online, sort them, and make them unique.

            .EXAMPLE
          PS C:\> Get-Office365NetworkInfo -Product 'Yammer','WAC' | Format-List

          It gets the Office 365 URLs and IP address ranges as formatted list.

            .EXAMPLE
          PS C:\> (Get-Office365NetworkInfo -Type url).Addresses | Select-String -Pattern '(Facebook)|(youtube)|(hockey)|(dropbox)|(google)' -NotMatch | Sort-Object | Get-Unique

          It gets the Office 365 URLs, sorts them, and makes them unique. And in this example, we remove the crappy (non Microsoft) URLs.

            .EXAMPLE
          PS C:\> (Get-Office365NetworkInfo -Type url).Addresses |Select-String -Pattern '(Facebook)|(youtube)|(hockey)|(dropbox)|(google)' | Sort-Object | Get-Unique

          In this example we filter all the non Microsoft URLs. We use this to implement es negative list :-)

            .NOTES
          Changelog:
          [Add] Multivalue for products
          [Add] Multivalue for types
          [Add] ExpressRoute Information (Still need some love)
          [Add] Environment support for the regional Office 365 instances (taken from our Office 365 module)
          [Changed] Splat some stuff
          [Changed] Refactored some older code
          [Removed] Removed extensive comments (Great job Josh)
          [Removed] Cisco Config Output (Has an own Filter-Function now)
          [Fix] Add missing products for USDefense & USDoD
  #>

	[CmdletBinding()]
	[OutputType([psobject])]
	param
	(

		[Parameter(ValueFromPipeline,
					  ValueFromPipelineByPropertyName,
					  Position = 1)]
		[ValidateNotNullOrEmpty()]
		[ValidateSet('All', 'o365', 'Portal', 'OfficeOnline', 'SfB', 'LYO', 'Planner', 'Teams', 'ProPlus', 'OneNote', 'Yammer', 'EXO', 'Identity', 'Office365Video', 'WAC', 'SPO', 'RCA', 'Sway', 'EX-Fed', 'OfficeMobile', 'CRLs', 'OfficeiPad', 'EOP', IgnoreCase)]
		[string[]]
		$Product = 'All',
		[Parameter(ValueFromPipeline,
					  ValueFromPipelineByPropertyName,
					  Position = 2)]
		[ValidateNotNullOrEmpty()]
		[ValidateSet('All', 'URL', 'IPv4', 'IPv6', IgnoreCase)]
		[string[]]
		$Type = 'All',
		[Parameter(ValueFromPipeline,
					  ValueFromPipelineByPropertyName,
					  Position = 3)]
		[ValidateSet('USDefense', 'USDoD', 'Telekom', '21Vianet', 'Default')]
		[Alias('AzureEnvironment', 'Office365Environment', 'O365Environment')]
		[string]
		$Environment = 'Default'
	)

	begin
	{
		# Cleanup
		$Office365IPAddresses = $null

		switch ($Environment)
		{
			'USDefense'
			{
				$Office365IPAddresses = 'https://support.content.office.net/en-us/static/O365IPAddresses_USDefense.xml'
			}
			'USDoD'
			{
				$Office365IPAddresses = 'https://support.content.office.net/en-us/static/O365IPAddresses_USDoD.xml'
			}
			'Telekom'
			{
				# Download only: https://www.microsoft.com/en-us/download/confirmation.aspx?id=54770
				Write-Warning -Message 'There is no dedicated List for Germany avalible, yet!'
				Write-Warning -Message 'Ask Microsoft to publish them'
				$Office365IPAddresses = $null
			}
			'21Vianet'
			{
				# Download only: https://www.microsoft.com/en-ca/download/confirmation.aspx?id=42064
				Write-Warning -Message 'There is no dedicated List for Chine avalible, yet!'
				Write-Warning -Message 'Ask Microsoft to publish them'
				$Office365IPAddresses = $null
			}

			default
			{
				$Office365IPAddresses = 'https://support.content.office.net/en-us/static/O365IPAddresses.xml'
			}
		}

		if (-not ($Office365IPAddresses))
		{
			exit 1
		}

		Write-Verbose -Message ('Get the Office 365 URLs and IP address ranges from {0}.' -f $Office365IPAddresses)

		# Cleanup
		$Office365IPAddressObj = @()
		$Office365ObjectInfoProduct = @()
		$Office365ObjectInfoType = @()

		# ExpressRoute Information (Both list are not finished yet)
		$ExpressRouteEnabled = @(
			'EXO',
			'EOP',
			'LYO',
			'Teams',
			'o365',
			'SPO'
		)

		$ExpressRouteDisabled = @(
			'Office365Video',
			'Yammer',
			'Sway',
			'Planner',
			'ProPlus',
			'CRLs'
		)
	}

	process
	{
		try
		{
			$paramInvokeWebRequest = @{
				Uri				  = $Office365IPAddresses
				DisableKeepAlive = $true
				ErrorAction	     = 'Stop'
			}
			[XML]$Office365XMLData = (Invoke-WebRequest @paramInvokeWebRequest)
		}
		catch
		{
			Write-Error -Message ('Failed to get the Office 365 IP address & URL information from {0}.' -f $Office365IPAddresses) -ErrorAction Stop

			exit 1
		}

		foreach ($Office365Product in $Office365XMLData.Products.Product)
		{
			foreach ($AddressList in $Office365Product.AddressList)
			{
				if ($AddressList.Address)
				{
					# Try to figure out if ExpressRoute is enabled for this product
					if ($ExpressRouteEnabled -contains $Office365Product.Name)
					{
						$ExpressRoute = 'Yes'
					}
					elseif ($ExpressRouteDisabled -contains $Office365Product.Name)
					{
						$ExpressRoute = 'No'
					}
					else
					{
						# Everything else
						$ExpressRoute = 'Unknown'
					}

					# Ordered is slower, but we like it this way
					$Office365IPAddressParams = [ordered]@{
						Product = $Office365Product.Name
						Type	  = $AddressList.Type
						Addresses = $AddressList.Address
						ExpressRoute = $ExpressRoute
					}

					# Append to our Object
					$Office365IPAddressObj += (New-Object -TypeName PSObject -Property $Office365IPAddressParams)
				}
			}
		}

		# Do we Filter?
		if ($Product -ne 'All')
		{
			Write-Verbose -Message ('Display only the {0}' -f $Product)

			foreach ($SingleProduct in $Product)
			{
				$Office365ObjectInfoProduct += $Office365IPAddressObj | Where-Object -FilterScript {
					$_.Product -eq $SingleProduct
				}
			}
		}
		else
		{
			$Office365ObjectInfoProduct += $Office365IPAddressObj
		}


		if ($Type -ne 'All')
		{
			Write-Verbose -Message ('Display only {0}' -f $Type)

			foreach ($SingleType in $Type)
			{
				$Office365ObjectInfoType += $Office365ObjectInfoProduct | Where-Object -FilterScript {
					$_.Type -eq $SingleType
				}
			}
		}
		else
		{
			$Office365ObjectInfoType += $Office365ObjectInfoProduct
		}
	}

	end
	{
		$Office365ObjectInfoType | Sort-Object -Property Product

	}

    <#
          Original Notes from the Author:

          I created this function a while ago. Basically, it was built to create several lists for equipment is used.
          For example: A HAProxy, a SquiD Proxy and my old Cisco Firewall and my pfSense Firewall.
          It started as something I created just for myself, to tweak my own stuff.
  #>

    <#
          Original License from the Author:

          Copyright 2015-2017 by Joerg Hochwald

          Redistribution and use in source and binary forms, with or without modification, are
          permitted provided that the following conditions are met:

          1. Redistributions of source code must retain the above copyright notice, this list of
          conditions and the following disclaimer.

          2. Redistributions in binary form must reproduce the above copyright notice, this list of
          conditions and the following disclaimer in the documentation and/or other materials
          provided with the distribution.

          3. Neither the name of the copyright holder nor the names of its contributors may be
          used to endorse or promote products derived from this software without specific prior
          written permission.

          THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
          EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
          MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
          COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
          EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
          SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
          HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
          OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
          SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

          By using the Software, you agree to the License, Terms and Conditions above!
  #>
}

There is a Gist available, and I uploaded it to my PowerShell collection repository.