Script to import Office 365 IP list to Cisco ASA

I had problem with Office 365 because of firewall, so I wrote script that makes list of all IPs needed for O365 that can be easily imported to Cisco ASA:

# CHANGE PATH
$Path = 'E:'
 
$Report = "$Path\Report.txt"
$date = Get-Date -format "yyyyMMdd"
$dateReport = Get-Date -format "dd.MM.yyyy"
$Link = 'https://support.content.office.net/en-us/static/O365IPAddresses.xml'
$LastFile = Get-Content (Get-ChildItem -Path $Path -Filter "*- o365Rules.txt" | sort CreationTime | select -Last 1).FullName
$ChangeDate = Get-Content $Report
$Last = $ChangeDate[-1].Substring($ChangeDate[-1].Length -10,$ChangeDate[-1].Length - ($ChangeDate[-1].Length -10))
 
try { [xml]$o365IpList = Invoke-RestMethod $Link }
catch  {
    $_ | Out-File "$Path\$date - Errors.txt"
    Add-Content $Report "$dateReport Error!!!"
}
 
if (!(Test-Path "$Path\$date - Errors.txt")) {
    $Result = @()
    $ErrorList = @()
    foreach ($Product in $o365IpList.Products.product) {
            foreach ($Addresslist in $Product.addresslist) {
                if ($Addresslist.type -eq "IPV4") {
                    foreach ($Address in $Addresslist.address) {
                        try {
                            [string]$Parse = $Address
                            [string]$IPAddress = $Parse.Substring(0,$Parse.IndexOf("/"))
                            [string]$Cidr = $Parse.Substring($Parse.IndexOf("/")+1,$Parse.Length - $Parse.IndexOf("/")-1)
                            [int]$Prefix = $Cidr
                            if ($Prefix -eq 32) { [string]$Value = "network-object host $IPAddress" }
                            else {
                                $mask = ([Math]::Pow(2,$Prefix)-1) * [Math]::Pow(2,(32-$Prefix))
                                $bytes = [BitConverter]::GetBytes([UInt32] $mask)
                                $IPMask = (($bytes.Count-1)..0 | ForEach-Object {[String]$bytes[$_]}) -join "."
                                [string]$Value = "network-object $IPAddress $IPMask"
                            }
                            $Result += $Value.Trim()
                        }
                        catch { $ErrorList += "$Address --> $_" }
                    }
                }
            }
    }
    $Final = ,"object-group network o365Rules" + ($Result | Sort-Object -Unique)
    $Final | ft | Out-File "$Path\o365Rules.txt"
    $Final | ft | Out-File "$Path\$date - o365Rules.txt"
    if ($ErrorList) { 
        $ErrorList | Out-File "$Path\$date - Errors.txt"
        Add-Content $Report "$dateReport Error!!!"
    }
    else { 
        $Missing = @()
        $Changed = ($o365IpList.Products.updated).Split('/')
        $ChangedFormated = "{0}.{1}.{2}" -f $Changed[1],$Changed[0],$Changed[2]
        $Text = "$dateReport OK, last change $ChangedFormated"
        Add-Content $Report $Text
        $Current = $Text.Substring($Text.Length -10,$Text.Length - ($Text.Length -10))
        if (!($Current -eq $Last)) {
            $LatestRules = Get-Content "$Path\$date - o365Rules.txt"
            foreach ($line in $LatestRules) { if ($LastFile -notcontains $line)      {$Missing += $line} }
            foreach ($line in $LastFile)      { if ($LatestRules -notcontains $line) {$Missing += "no $line"} }
            $FinalMissing = ,"object-group network o365Rules" + ($Missing | sort)
            $FinalMissing | Out-File "$Path\$date - Changes.txt"
        }
    }
}

You need to change path in script (first line) to your custom folder.
You can run this script via Task Scheduler once per day.
First time it will generate few errors (they are safe to ignore, only because there are no files in folder $Path)

It will generate 4 files (date for first 2 files in format YYYYMMDD):

20171009 – Changes (Only changes compared to last report)
20171009 – o365Rules (All IPs in O365 on this date)
o365Rules – Latest report with all IPs [you need to import this file for first time]
Report – Script logging (when was script run, result, last IP change on Office 365)

13 Comments

  1. Thank you, works perfectly.

    Reply
  2. Hi,
    I am a security Guy,
    I will be greatfull, if you please help me to how to run this script and where to run this script.
    Thank you
    Tom

    Reply
  3. Hi, this is working very well, thank you.
    Any advise on how to use this file to import it into Cisco ASA in script way? I don’t feel like manually adding/updating this object group every X weeks…
    Thank you!
    Ori

    Reply
    • You can add lines in this script to import it directly (connect to ASA via SSH) or your network admin can use this file with his own script…

      Reply
  4. This is an awesome script. Saved me a ton of time

    Reply
  5. I have generated the file.
    Any advise on how to use this file to import it into Cisco ASA.

    Thanks

    Reply
  6. Shane Pollard26 June, 2018 at 15:50

    Have you updated this to take into account the new REST API?

    Reply
    • Hi Shane. Script still works the same – no change needed.

      Reply
      • Hi, I work on IP Address and URL publishing for Office 365. The XML file that the script here uses will be updated until October 2, 2018. The REST API provides all of the same data and directly provides the changes at a /changes web method. The data on the REST API is up to date and I’d encourage people to move to it early before the XML file is deprecated. – Paul

        Reply
        • Hi Paul. I’ll post a new, updated script in few days. I checked it and it’s easy fix, but I’ll rather make a new, more improved script.

          Reply
  7. Very good script. I was interest in how you are going to decode the JSON in Oct.

    Reply
  8. Jesse Smith17 August, 2018 at 19:52

    Bless you sir!!!!!

    Reply

Your email address will not be published.