# 2018-04-3 TJB <# This script downloads the xml IP list from Microsoft, adds/removes Sophos Network Objects and creates/modifies a Group of Networks. Requirements: Sophos API Enabled Local Sophos account with admin privelages configures with an API Key Input Parameter: $UTM Script expects a hashtable to be passed in the following format: @{UTM = 'SophosDeviceName'; URL = 'https://SophosDeviceName.company.com:4444/api; KEY = 'apiKeyFromSophosDevice'; DBG = $true/$false - activates pause in script} #> Param([parameter(Mandatory=$true)]$utm) $ws = "https://endpoints.office.com" # webservice root URL $datapath = "C:\scripts\sophos\endpoints_clientid_latestversion.txt" # path where client ID and latest version number will be stored $exceptionUrlList = @() # Sophos Exception list # Personalize the Tenant name. $tenantName = 'tenantID' # API Tenant ID $comment = 'Microsoft URL | ' + (Get-Date).ToString("yyyy-MM-dd") + ' PS1' $apiURL = $utm.URL $exceptionUri = $apiURL + '/objects/http/exception/' $networkURI = $apiURL + '/objects/network/network/' $groupURI = $apiURL + '/objects/network/group/' $resultCSV = 'C:\scripts\sophos\resultList.csv' $exceptionUrls = @() # processed list of URLs for Sophos Formatting $msGroup = @() #Sophos Network Group that will contain all of the network object created $utmNetList = @() #All Networks retrieved from the UTM $msNetList = @() #UTM Networks filtered for MS- $ipList = @() #IP Addresses downloaded from Microsoft XML $ipNetList = @() #IP Addresses parsed into Network format $resultList = @() #Dispositon of networks for notification # Personalize the mail server and recipient/sender information $emailHeader = @{smtpserver = 'mailserver'; subject = 'Microosft IPv4 Address Update for ' + $utm.UTM; to = 'user@company.com'; from = 'script@company.com'} #Must have corresponding account configured with token on UTM $token = $utm.KEY $tokenBase64 = [Convert]::ToBase64String([System.Text.Encoding]::Default.GetBytes("token:" + $token)) #Common headers required by Sophos API $headers = @{} $headers.add("Authorization",'Basic ' + $tokenBase64) $headers.add("Content-Type", "application/json") $headers.add("Accept", "application/json") #Sets the TLS level to match Sophos $AllProtocols = [System.Net.SecurityProtocolType]'Tls,Tls11,Tls12' [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols #Retrieve the existing list of MS subnets from Sophos $utmNetList = Invoke-RestMethod -Uri $networkURI -Method Get -Headers $headers $msNetList = $utmNetList | where {$_.name -like 'MS-*/*' -and $_.comment -like 'Microsoft*PS1'} #Retrieve the existing list of HTTP Exceptions from Sophos $utmExceptionList = Invoke-RestMethod -Uri $exceptionUri -Method Get -Headers $headers $msExceptionList = $utmExceptionList | where {$_.name -match 'Microsoft Office365 URLs' -and $_.comment -like 'Microsoft*PS1'} # fetch client ID and version if data file exists; otherwise create new file if (Test-Path $datapath) { $content = Get-Content $datapath $clientRequestId = $content[0] $lastVersion = $content[1] } else { $clientRequestId = [GUID]::NewGuid().Guid $lastVersion = "0000000000" @($clientRequestId, $lastVersion) | Out-File $datapath } # call version method to check the latest version, and pull new data if version number is different $version = Invoke-RestMethod -Uri ($ws + "/version/O365Worldwide?clientRequestId=" + $clientRequestId) if ($version.latest -ge $lastVersion) { Write-Host "New version of Office 365 worldwide commercial service instance endpoints detected" # write the new version number to the data file @($clientRequestId, $version.latest) | Out-File $datapath # invoke endpoints method to get the new data $endpointSets = Invoke-RestMethod -Uri ($ws + "/endpoints/O365Worldwide?clientRequestId=" + $clientRequestId + "&TenantName=" + $tenantName) # filter results for Allow and Optimize endpoints, and transform these into custom objects with port and category $flatUrls = $endpointSets | ForEach-Object { $endpointSet = $_ $allowUrls = $(if ($endpointSet.allowUrls.Count -gt 0) { $endpointSet.allowUrls } else { @() }) $optimizeUrls = $(if ($endpointSet.optimizeUrls.Count -gt 0) { $endpointSet.optimizeUrls } else { @() }) $allowUrlCustomObjects = $allowUrls | ForEach-Object { [PSCustomObject]@{ category = "Allow"; url = $_; # Allow URLs should permit traffic across both Allow and Optimize ports tcpPorts = (($endpointSet.allowTcpPorts, $endpointSet.optimizeTcpPorts) | Where-Object { $_ -ne $null }) -join ","; udpPorts = (($endpointSet.allowUdpPorts, $endpointSet.optimizeUdpPorts) | Where-Object { $_ -ne $null }) -join ","; } } $optimizeUrlCustomObjects = $optimizeUrls | ForEach-Object { [PSCustomObject]@{ category = "Optimize"; url = $_; tcpPorts = $endpointSet.optimizeTcpPorts; udpPorts = $endpointSet.optimizeUdpPorts; } } $allowUrlCustomObjects, $optimizeUrlCustomObjects } $flatIps = $endpointSets | ForEach-Object { $endpointSet = $_ $ips = $(if ($endpointSet.ips.Count -gt 0) { $endpointSet.ips } else { @() }) # IPv4 strings have dots while IPv6 strings have colons $ip4s = $ips | Where-Object { $_ -like '*.*' } $allowIpCustomObjects = @() if ($endpointSet.allowTcpPorts -or $endpointSet.allowUdpPorts) { $allowIpCustomObjects = $ip4s | ForEach-Object { [PSCustomObject]@{ category = "Allow"; ip = $_; tcpPorts = $endpointSet.allowTcpPorts; udpPorts = $endpointSet.allowUdpPorts; } } } $optimizeIpCustomObjects = @() if ($endpointSet.optimizeTcpPorts -or $endpointSet.optimizeUdpPorts) { $optimizeIpCustomObjects = $ip4s | ForEach-Object { [PSCustomObject]@{ category = "Optimize"; ip = $_; tcpPorts = $endpointSet.optimizeTcpPorts; udpPorts = $endpointSet.optimizeUdpPorts; } } } $allowIpCustomObjects, $optimizeIpCustomObjects } Write-Output "IPV4 Firewall IP Address Ranges" ($flatIps.ip | Sort-Object -Unique) -join "," | Out-String Write-Output "URLs for Proxy Server" ($flatUrls.url | Sort-Object -Unique) -join "," | Out-String # Modifies the URLs for Sophos and populates the $exceptionUrls array foreach ($url in $flatUrls.url){ $newUrl = '' if ($url -like '`*-*') { $newUrl = ($url).Replace('.','\.').Replace('*-','^https?://companyname-') # Replace with specific company name - might could use the TenantID variable } elseif ($url -like '`*.*'){ $newUrl = ($url).Replace('.','\.').Replace('*\.','^https?://[^.]*\.') } else { $newUrl = '^https?://' + ($url -replace '\.','\.') } $exceptionUrls = $exceptionUrls += $newUrl } if ($msExceptionList.name.count -eq 0){ $exceptionMethod = 'Post' $msExceptionUri = $exceptionUri } elseif ($msExceptionList.name.count -eq 1){ $exceptionMethod = 'Patch' $msExceptionUri = $exceptionUri + $msExceptionList._ref } <#Options for the skiplist av -- anti-virus cache -- Caching certcheck -- Certificate Trust Check certdate -- Certificate Date Check check_max_download -- Block by download size content_removal -- Content removal contenttype_blacklist -- MIME type blocking extensions -- Extension blocking log_access -- Logging Accessed pages log_blocked -- Logging Blocked pages patience -- Do not display Download/Scan progress page ssl_scanning -- SSL Scanning url_filter -- URL Filter user_auth -- Authentication #> $skipList = @('av', 'content_removal', 'user_auth', 'extensions', 'url_filter', 'contenttype_blacklist', 'cache', 'log_access', 'log_blocked', 'ssl_scanning', 'check_max_download', 'patience' ) #$msUrlList = ConvertTo-Json $exceptionUrls $exceptionBody = @{'aaa' = @(); 'comment' = $comment; 'domains' = $exceptionUrls; 'endpoints_groups' = @(); 'name' = 'Microsoft Office365 URLs'; 'networks' = @(); 'operator' = 'AND'; 'skiplist' = $skipList; 'sp_categories' = @(); 'status' = $true; 'tags' = @(); 'user_agents' = @() } Invoke-RestMethod -Uri $msExceptionUri -Method $exceptionMethod -Headers $headers -Body (ConvertTo-Json $exceptionBody) # TODO Call Send-MailMessage with new endpoints data } else { Write-Host "Office 365 worldwide commercial service instance endpoints are up-to-date" }