PSSymantecCloud.psm1
#Region '.\Private\ConvertTo-FlatObject.ps1' 0 # From https://github.com/EvotecIT/PSSharedGoods/tree/master/Public/Converts Function ConvertTo-FlatObject { <# .SYNOPSIS Flattends a nested object into a single level object. .DESCRIPTION Flattends a nested object into a single level object. .PARAMETER Objects The object (or objects) to be flatten. .PARAMETER Separator The separator used between the recursive property names .PARAMETER Base The first index name of an embedded array: - 1, arrays will be 1 based: <Parent>.1, <Parent>.2, <Parent>.3, … - 0, arrays will be 0 based: <Parent>.0, <Parent>.1, <Parent>.2, … - "", the first item in an array will be unnamed and than followed with 1: <Parent>, <Parent>.1, <Parent>.2, … .PARAMETER Depth The maximal depth of flattening a recursive property. Any negative value will result in an unlimited depth and could cause a infinitive loop. .PARAMETER Uncut The maximal depth of flattening a recursive property. Any negative value will result in an unlimited depth and could cause a infinitive loop. .PARAMETER ExcludeProperty The propertys to be excluded from the output. .EXAMPLE $Object3 = [PSCustomObject] @{ "Name" = "Przemyslaw Klys" "Age" = "30" "Address" = @{ "Street" = "Kwiatowa" "City" = "Warszawa" "Country" = [ordered] @{ "Name" = "Poland" } List = @( [PSCustomObject] @{ "Name" = "Adam Klys" "Age" = "32" } [PSCustomObject] @{ "Name" = "Justyna Klys" "Age" = "33" } [PSCustomObject] @{ "Name" = "Justyna Klys" "Age" = 30 } [PSCustomObject] @{ "Name" = "Justyna Klys" "Age" = $null } ) } ListTest = @( [PSCustomObject] @{ "Name" = "Sława Klys" "Age" = "33" } ) } $Object3 | ConvertTo-FlatObject .NOTES Based on https://powersnippets.com/convertto-flatobject/ #> [CmdletBinding()] Param ( [Parameter(ValueFromPipeLine)][Object[]]$Objects, [String]$Separator = ".", [ValidateSet("", 0, 1)]$Base = 1, [int]$Depth = 5, [string[]] $ExcludeProperty, [Parameter(DontShow)][String[]]$Path, [Parameter(DontShow)][System.Collections.IDictionary] $OutputObject ) Begin { $InputObjects = [System.Collections.Generic.List[Object]]::new() } Process { foreach ($O in $Objects) { if ($null -ne $O) { $InputObjects.Add($O) } } } End { If ($PSBoundParameters.ContainsKey("OutputObject")) { $Object = $InputObjects[0] $Iterate = [ordered] @{} if ($null -eq $Object) { #Write-Verbose -Message "ConvertTo-FlatObject - Object is null" } elseif ($Object.GetType().Name -in 'String', 'DateTime', 'TimeSpan', 'Version', 'Enum') { $Object = $Object.ToString() } elseif ($Depth) { $Depth-- If ($Object -is [System.Collections.IDictionary]) { $Iterate = $Object } elseif ($Object -is [Array] -or $Object -is [System.Collections.IEnumerable]) { $i = $Base foreach ($Item in $Object.GetEnumerator()) { $NewObject = [ordered] @{} If ($Item -is [System.Collections.IDictionary]) { foreach ($Key in $Item.Keys) { if ($Key -notin $ExcludeProperty) { $NewObject[$Key] = $Item[$Key] } } } elseif ($Item -isnot [Array] -and $Item -isnot [System.Collections.IEnumerable]) { foreach ($Prop in $Item.PSObject.Properties) { if ($Prop.IsGettable -and $Prop.Name -notin $ExcludeProperty) { $NewObject["$($Prop.Name)"] = $Item.$($Prop.Name) } } } else { $NewObject = $Item } $Iterate["$i"] = $NewObject $i += 1 } } else { foreach ($Prop in $Object.PSObject.Properties) { if ($Prop.IsGettable -and $Prop.Name -notin $ExcludeProperty) { $Iterate["$($Prop.Name)"] = $Object.$($Prop.Name) } } } } If ($Iterate.Keys.Count) { foreach ($Key in $Iterate.Keys) { if ($Key -notin $ExcludeProperty) { ConvertTo-FlatObject -Objects @(, $Iterate["$Key"]) -Separator $Separator -Base $Base -Depth $Depth -Path ($Path + $Key) -OutputObject $OutputObject -ExcludeProperty $ExcludeProperty } } } else { $Property = $Path -Join $Separator if ($Property) { # We only care if property is not empty if ($Object -is [System.Collections.IDictionary] -and $Object.Keys.Count -eq 0) { $OutputObject[$Property] = $null } else { $OutputObject[$Property] = $Object } } } } elseif ($InputObjects.Count -gt 0) { foreach ($ItemObject in $InputObjects) { $OutputObject = [ordered]@{} ConvertTo-FlatObject -Objects @(, $ItemObject) -Separator $Separator -Base $Base -Depth $Depth -Path $Path -OutputObject $OutputObject -ExcludeProperty $ExcludeProperty [PSCustomObject] $OutputObject } } } } #EndRegion '.\Private\ConvertTo-FlatObject.ps1' 162 #Region '.\Private\Get-ConfigurationPath.ps1' 0 function Get-ConfigurationPath { <# .SYNOPSIS returns hashtable object with the BaseURL, SepCloudCreds, SepCloudToken full path .DESCRIPTION .INPUTS None .OUTPUTS Hashtable #> @{ BaseUrl = "api.sep.securitycloud.symantec.com" SepCloudCreds = "$env:TEMP\SepCloudOAuthCredentials.xml" CachedTokenPath = "$env:TEMP\SepCloudCachedToken.xml" } } #EndRegion '.\Private\Get-ConfigurationPath.ps1' 19 #Region '.\Private\Get-ExcelAllowListObject.ps1' 0 function Get-ExcelAllowListObject { <# TODO fill description .SYNOPSIS Imports excel allow list report from its file path as a PSObject .DESCRIPTION Imports excel allow list report as a PSObject. Same structure that Get-SepCloudPolicyDetails uses to compare Excel allow list and SEP Cloud allow list policy .EXAMPLE Get-ExcelAllowListObject -Path "WorkstationsAllowListPolicy.xlsx" Imports the excel file and returns a structured PSObject .INPUTS Excel path of allow list policy previously generated from Export-SepCloudAllowListPolicyToExcel CmdLet .OUTPUTS Custom PSObject #> param ( # excel path [Parameter( ValueFromPipeline )] [string[]] [Alias("Excel")] [Alias("Path")] $excel_path ) process { # List all excel tabs $AllSheets = Get-ExcelSheetInfo $excel_path $SheetsInfo = @{} # Import all Excel info in $SheetsInfo hashtable $AllSheets | ForEach-Object { $SheetsInfo[$_.Name] = Import-Excel $_.Path -WorksheetName $_.Name } # Get Object from ExceptionStructure Class $obj_policy_excel = [AllowListStructure]::new() # Populates $obj_policy_excel # Add Applications foreach ($line in $SheetsInfo['Applications']) { $obj_policy_excel.AddProcessFile( $line.sha2, $line.Name ) } # Add Files foreach ($line in $SheetsInfo['Files']) { # Parse "features.X" properties to gather the feature_names in an array [array]$feature_names = @() [array]$nb_features = $line.PSObject.properties.name | Select-String -Pattern feature $i = 0 foreach ($feat in $nb_features) { if ($null -ne $line.($nb_features[$i])) { $feature_names += $line.($nb_features[$i]) } $i++ } # Use AddWindowsFiles $obj_policy_excel.AddWindowsFiles( $line.pathvariable, $line.path, $line.scheduled, $feature_names ) } # Add Directories foreach ($line in $SheetsInfo['Directories']) { # Parse "features.X" properties to gather the feature names in an array [array]$feature_names = @() [array]$nb_features = $line.PSObject.properties.name | Select-String -Pattern feature $i = 0 foreach ($feat in $nb_features) { if ($null -ne $line.($nb_features[$i])) { $feature_names += $line.($nb_features[$i]) } $i++ } # Use AddWindowsDirectories $obj_policy_excel.AddWindowsDirectories( $line.pathvariable, $line.directory, $line.recursive, $line.scheduled, $feature_names ) } # Add Extensions # no loop required, whole array needed $obj_policy_excel.AddExtensions(@{ names = $sheetsInfo['Extensions'].extensions scheduled = $true features = 'AUTO_PROTECT' } ) # Add WebDomains foreach ($line in $SheetsInfo['Webdomains']) { $obj_policy_excel.AddWebDomains( $line.domain ) } # Add IPS Hosts foreach ($line in $SheetsInfo['Ips_Hosts']) { $obj_policy_excel.AddIpsHostsIpv4Address( $line.ip ) } # Add IPS Subnet v4 foreach ($line in $SheetsInfo['Ips_Hosts_subnet_v4']) { $obj_policy_excel.AddIpsHostsIpv4Subnet( $line.ip, $line.mask ) } # Add IPS Subnet v6 foreach ($line in $SheetsInfo['Ips_Hosts_subnet_v6']) { $obj_policy_excel.AddIpsHostsIpv6Subnet( $line.ipv6_subnet ) } # Add IPs ranges (includes both IPv4 & v6) foreach ($line in $SheetsInfo['Ips_range']) { $obj_policy_excel.AddIpsRange( $line.ip_start, $line.ip_end ) } # Add Certificates foreach ($line in $SheetsInfo['Certificates']) { $obj_policy_excel.AddCertificates( $line.signature_issuer, $line.signature_company_name, $line."signature_fingerprint.algorithm", $line."signature_fingerprint.value" ) } # Add Linux Files foreach ($line in $SheetsInfo['Linux Files']) { # Parse "features.X" properties to gather the feature_names in an array [array]$feature_names = @() [array]$nb_features = $line.PSObject.properties.name | Select-String -Pattern feature $i = 0 foreach ($feat in $nb_features) { if ($null -ne $line.($nb_features[$i])) { $feature_names += $line.($nb_features[$i]) } $i++ } # Use AddLinuxFiles $obj_policy_excel.AddLinuxFiles( $line.pathvariable, $line.path, $line.scheduled, $feature_names ) } # Add Mac Files foreach ($line in $SheetsInfo['Mac Files']) { # Parse "features.X" properties to gather the feature_names in an array [array]$feature_names = @() [array]$nb_features = $line.PSObject.properties.name | Select-String -Pattern feature $i = 0 foreach ($feat in $nb_features) { if ($null -ne $line.($nb_features[$i])) { $feature_names += $line.($nb_features[$i]) } $i++ } # Use AddMacFiles $obj_policy_excel.AddMacFiles( $line.pathvariable, $line.path, $line.scheduled, $feature_names ) } # Add Linux Directories foreach ($line in $SheetsInfo['Linux Directories']) { # Parse "features.X" properties to gather the feature names in an array [array]$feature_names = @() [array]$nb_features = $line.PSObject.properties.name | Select-String -Pattern feature $i = 0 foreach ($feat in $nb_features) { if ($null -ne $line.($nb_features[$i])) { $feature_names += $line.($nb_features[$i]) } $i++ } # Use AddLinuxDirectories $obj_policy_excel.AddLinuxDirectories( $line.pathvariable, $line.directory, $line.recursive, $line.scheduled, $feature_names ) } # Add Mac Directories foreach ($line in $SheetsInfo['Mac Directories']) { # Parse "features.X" properties to gather the feature names in an array [array]$feature_names = @() [array]$nb_features = $line.PSObject.properties.name | Select-String -Pattern feature $i = 0 foreach ($feat in $nb_features) { if ($null -ne $line.($nb_features[$i])) { $feature_names += $line.($nb_features[$i]) } $i++ } # Use AddMacDirectories $obj_policy_excel.AddMacDirectories( $line.pathvariable, $line.directory, $line.recursive, $line.scheduled, $feature_names ) } return $obj_policy_excel } } #EndRegion '.\Private\Get-ExcelAllowListObject.ps1' 239 #Region '.\Private\Get-SEPCloudToken.ps1' 0 function Get-SEPCloudToken { <# .SYNOPSIS Generates an authenticated Token from the SEP Cloud API .DESCRIPTION Gathers Bearer Token from the SEP Cloud console to interact with the authenticated API Securely stores credentials or valid token locally (By default on TEMP location) Connection information available here : https://sep.securitycloud.symantec.com/v2/integration/client-applications .PARAMETER ClientID ClientID parameter required to generate a token .PARAMETER Secret Secret parameter required in combinaison to ClientID to generate a token .EXAMPLE Get-SEPCloudToken .EXAMPLE Get-SEPCloudToken(ClientID,Secret) .NOTES Function logic 1. Test locally stored encrypted token 2. Test locally stored encrypted Client/Secret to generate a token 3. Requests Client/Secret to generate token #> [CmdletBinding()] param ( # ClientID from SEP Cloud Connection App [Parameter( ValueFromPipelineByPropertyName = $true )] [string] $ClientID, # Secret from SEP Cloud Connection App [Parameter( ValueFromPipelineByPropertyName = $true )] [string] $Secret ) begin { try { # init $BaseURL = (Get-ConfigurationPath).BaseUrl $SepCloudCreds = (Get-ConfigurationPath).SepCloudCreds $CachedTokenPath = (Get-ConfigurationPath).CachedTokenPath $URI_Tokens = 'https://' + $BaseURL + '/v1/oauth2/tokens' if (-not $BaseURL) { throw "Missing 'BaseUrl' configuration value" } if (-not $SepCloudCreds) { throw "Missing 'SepCloudCreds' configuration value" } if (-not $CachedTokenPath) { throw "Missing 'CachedTokenPath' configuration value" } } catch { throw "Error initializing SEPCloudToken: $_" } } process { # Check if we already have a valid token if (Test-Path -Path "$CachedTokenPath") { $CachedToken = Import-Clixml -Path $CachedTokenPath # Check if still valid if ((Get-Date) -lt $CachedToken.Expiration) { Write-Verbose "cached token valid - returning" return $CachedToken } else { Write-Verbose "Cached token expired - deleting" Remove-Item $CachedTokenPath } } # Test if OAuth cred present on the disk if (Test-Path -Path "$SepCloudCreds") { <# If true, Attempt to get a token #> $OAuth = "Basic " + (Import-Clixml -Path $SepCloudCreds) $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $OAuth } try { $response = Invoke-RestMethod -Method POST -Uri $URI_Tokens -Headers $Headers # Get the auth token from the response & store it locally Write-Verbose "Valid credentials - returning valid token" $CachedToken = [PSCustomObject]@{ Token = $response.access_token Token_Type = $response.token_type Token_Bearer = $response.token_type + " " + $response.access_token Expiration = (Get-Date).AddSeconds($response.expires_in) # token expiration is 3600s } $CachedToken | Export-Clixml -Path $CachedTokenPath return $CachedToken } catch { $StatusCode = $_.Exception.Response.StatusCode Write-Verbose "Authentication error - From locally stored credentials - Expected HTTP 200, got $([int]$StatusCode) - Continue..." # Invalid Credentials, deleting local credentials file Remove-Item $SepCloudCreds } } # If no token nor OAuth creds available locally # Encode ClientID and Secret to create Basic Auth string # Authentication requires the following "Basic + encoded CliendID:ClientSecret" if ($clientID -eq "" -or $Secret -eq "") { Write-Host "No local credentials found" $ClientID = Read-Host -Prompt "Enter ClientID" $Secret = Read-Host -Prompt "Enter Secret" } $Encoded_Creds = [convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(($ClientID + ':' + $Secret))) $Encoded_Creds | Export-Clixml -Path $SepCloudCreds # Create Basic Auth string $BasicAuth = "Basic " + $Encoded_Creds $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $BasicAuth } $Response = Invoke-RestMethod -Method POST -Uri $URI_Tokens -Headers $Headers -UseBasicParsing # Get the auth token from the response & store it locally Write-Verbose "Valid credentials - returning valid Bearer token" $CachedToken = [PSCustomObject]@{ Token = $response.access_token Token_Type = $response.token_type Token_Bearer = $response.token_type + " " + $response.access_token Expiration = (Get-Date).AddSeconds($response.expires_in) # token expiration is 3600s } $CachedToken | Export-Clixml -Path $CachedTokenPath return $CachedToken } } #EndRegion '.\Private\Get-SEPCloudToken.ps1' 138 #Region '.\Private\InternalClass.ps1' 0 # https://stackoverflow.com/a/74901407/2552996 class Extensions { [Collections.Generic.List[string]] $names = [Collections.Generic.List[string]]::new() [bool] $scheduled [Collections.Generic.List[string]] $features = [Collections.Generic.List[string]]::new() } class UpdateAllowlist { [object] $add [object] $remove UpdateAllowlist() { $ExceptionStructureAdd = [AllowListStructure]::new() $ExceptionStructureRemove = [AllowListStructure]::new() $this.add = $ExceptionStructureAdd $this.remove = $ExceptionStructureRemove } } class AllowListStructure { [object] $Applications [object] $Certificates [object] $webdomains [object] $ips_hosts [Extensions] $Extensions [object] $windows [object] $linux [object] $mac # Setting up the PSCustomObject structure from the JSON example : https://pastebin.com/FaKYpgw3 ExceptionStructure() { $this.applications = [System.Collections.Generic.List[object]]::new() $this.Certificates = [System.Collections.Generic.List[object]]::new() $this.webdomains = [System.Collections.Generic.List[object]]::new() $this.ips_hosts = [System.Collections.Generic.List[object]]::new() # Extensions obj be hashtable. Converting to JSON will not be incorrect format (list instead of k/v pair) $this.extensions = [Extensions]::new() $this.windows = [PSCustomObject]@{ files = [System.Collections.Generic.List[object]]::new() directories = [System.Collections.Generic.List[object]]::new() } $this.Linux = [PSCustomObject]@{ files = [System.Collections.Generic.List[object]]::new() directories = [System.Collections.Generic.List[object]]::new() } $this.mac = [PSCustomObject]@{ files = [System.Collections.Generic.List[object]]::new() directories = [System.Collections.Generic.List[object]]::new() } } # method to add APPLICATIONS tab to the main obj [void] AddProcessFile( [string] $sha2, [string] $name ) { $this.applications.Add([pscustomobject]@{ processfile = [pscustomobject]@{ sha2 = $sha2 name = $name } }) } # Method to add CERTIFICATES tab to the main obj [void] AddCertificates( [string] $signature_issuer, [string] $signature_company_name, # [string] $signature_fingerprint, [string] $algorithm, [string] $value ) { # $this.certificates.Add() $this.certificates.Add([pscustomobject]@{ signature_issuer = $signature_issuer signature_company_name = $signature_company_name signature_fingerprint = [pscustomobject]@{ algorithm = $algorithm value = $value } }) } # Method to add WEBDOMAINS to the main obj [void] AddWebDomains( [string] $domain ) { $this.webdomains.add([PSCustomObject]@{ domain = $domain }) } # Method to add IPv4 addresses IPS_HOSTS to the main obj [void] AddIpsHostsIpv4Address( [string] $ip ) { $this.ips_hosts.add([PSCustomObject]@{ ip = $ip }) } # Method to add IPv4 subnet IPS_HOSTS to the main obj [void] AddIpsHostsIpv4Subnet( [string] $ip, [string] $mask ) { $this.ips_hosts.add([pscustomobject]@{ ipv4_subnet = [pscustomobject]@{ ip = $ip mask = $mask } }) } # method to add IPv6 subnet IPS_HOSTS to the main obj [void] AddIpsHostsIpv6Subnet( [string] $ipv6_subnet ) { $this.ips_hosts.add([pscustomobject]@{ ipv6_subnet = $ipv6_subnet }) } #method to add ip ranges to the main obj [void] AddIpsRange( [string] $ip_start, [string] $ip_end ) { $this.ips_hosts.add([pscustomobject]@{ ip_range = [pscustomobject]@{ ip_start = $ip_start ip_end = $ip_end } }) } # Method to add EXTENSIONS tab to the main obj [void] AddExtensions([Extensions] $Extension) { $this.Extensions = $Extension } # Method to add Windows FILES excel tab to obj [void] AddWindowsFiles( [string] $pathvariable, [string] $path, [bool] $scheduled, [array] $features ) { $this.windows.files.add([pscustomobject]@{ pathvariable = $pathvariable path = $path scheduled = $scheduled features = $features }) } # Method to add Linux FILES excel tab to obj [void] AddLinuxFiles( [string] $pathvariable, [string] $path, [bool] $scheduled, [array] $features ) { $this.linux.files.add([pscustomobject]@{ pathvariable = $pathvariable path = $path scheduled = $scheduled features = $features }) } # Method to add Mac FILES excel tab to obj [void] AddMacFiles( [string] $pathvariable, [string] $path, [bool] $scheduled, [array] $features ) { $this.mac.files.add([pscustomobject]@{ pathvariable = $pathvariable path = $path scheduled = $scheduled features = $features }) } # Method to add Windows DIRECTORIES excel tab to obj [void] AddWindowsDirectories( [string] $pathvariable, [string] $directory, [bool] $recursive, [bool] $scheduled, [array] $features ) { $this.windows.directories.add([pscustomobject]@{ pathvariable = $pathvariable directory = $directory recursive = $recursive scheduled = $scheduled features = $features }) } # Method to add Linux DIRECTORIES excel tab to obj [void] AddLinuxDirectories( [string] $pathvariable, [string] $directory, [bool] $recursive, [bool] $scheduled, [array] $features ) { $this.linux.directories.add([pscustomobject]@{ pathvariable = $pathvariable directory = $directory recursive = $recursive scheduled = $scheduled features = $features }) } # Method to add Mac DIRECTORIES excel tab to obj [void] AddMacDirectories( [string] $pathvariable, [string] $directory, [bool] $recursive, [bool] $scheduled, [array] $features ) { $this.mac.directories.add([pscustomobject]@{ pathvariable = $pathvariable directory = $directory recursive = $recursive scheduled = $scheduled features = $features }) } } #EndRegion '.\Private\InternalClass.ps1' 237 #Region '.\Private\Merge-SepCloudAllowList.ps1' 0 function Merge-SepCloudAllowList { <# .SYNOPSIS Merges 2 SEP Cloud allow list policy to a single PSObject .DESCRIPTION Returns a custom PSObject ready to be converted in json as HTTP Body for Update-SepCloudAllowlistPolicy CmdLet Excel file takes precedence in case of conflicts. It is the main "source of truth". Logic goes as below - If SEP exception present in both excel & policy : no changes - If SEP exception present only in Excel : add exception - If SEP exception present only in policy (so not in Excel) : remove exception .NOTES Excel file takes precedence in case of conflicts .INPUTS - SEP cloud allow list policy PSObject - Excel report file path (previously generated from Export-SepCloudAllowListPolicyToExcel CmdLet) .OUTPUTS - Custom PSObject .EXAMPLE Merge-SepCloudAllowList -Policy_Name "My Allow List Policy For Servers" -Excel ".\Data\Centralized_exceptions_for_servers.xlsx" | Update-SepCloudAllowlistPolicy #> [CmdletBinding()] param ( # Policy version [Parameter( )] [string] [Alias("Version")] $Policy_Version, # Exact policy name [Parameter( Mandatory )] [string] [Alias("PolicyName")] $Policy_Name, # excel path [Parameter( Mandatory )] [string] [Alias("Excel")] [Alias("Path")] $excel_path ) # Get policy details to compare with Excel file # Use specific version or by default latest version switch ($PSBoundParameters.Keys) { 'Policy_Version' { $obj_policy = Get-SepCloudPolicyDetails -Policy_Name $Policy_Name -Policy_Version $Policy_Version } Default {} } if ($null -eq $PSBoundParameters['Policy_Version']) { $obj_policy = Get-SepCloudPolicyDetails -Policy_Name $Policy_Name } # Import excel report as a structured object with $obj_policy_excel = Get-ExcelAllowListObject -Path $excel_path # Initialize structured obj that will be later converted # to HTTP JSON Body with "add" and "remove" hive $obj_body = [UpdateAllowlist]::new() ########################### # Comparison starts here # ########################### # "Applications" tab # Parsing excel object first $policy_sha2 = $obj_policy.features.configuration.applications.processfile $excel_sha2 = $obj_policy_excel.Applications.processfile # Parsing first excel object foreach ($line in $excel_sha2) { # if sha2 appears in both lists if ($policy_sha2.sha2.contains($line.sha2)) { # No changes needed continue } else { # if sha2 only in excel list, set the sha to the "add" hive $obj_body.add.AddProcessFile( $line.sha2, $line.name ) } } # Parsing then policy object foreach ($line in $policy_sha2) { # if sha2 appears only in policy (so not in Excel) if (-not $excel_sha2.sha2.contains($line.sha2)) { # set the sha to the "remove" hive $obj_body.remove.AddProcessFile( $line.sha2, $line.name ) } } # "Files" tab # Parsing excel object first $policy_files = $obj_policy.features.configuration.windows.files $excel_files = $obj_policy_excel.windows.files foreach ($line in $excel_files) { # If file appears in both lists if ($policy_files.path.contains($line.Path)) { # No changes needed continue } else { # if file only in excel list, set the file to the "add" hive $obj_body.add.AddWindowsFiles( $line.pathvariable, $line.path, $line.scheduled, $line.features ) } } # Parsing then policy object foreach ($line in $policy_files) { # if file appears only in policy (so not in Excel) if (-not $excel_files.path.contains($line.path)) { # set the file to the "remove" hive $obj_body.remove.AddWindowsFiles( $line.pathvariable, $line.path, $line.scheduled, $line.features ) } } # "Directories" tab # Parsing excel object first $policy_directories = $obj_policy.features.configuration.windows.directories $excel_directories = $obj_policy_excel.windows.directories foreach ($line in $excel_directories) { # If directory appears in both lists if ($policy_directories.directory.contains($line.directory)) { # No changes needed continue } else { # if directory only in excel list, set the directory to the "add" hive $obj_body.add.AddWindowsDirectories( $line.pathvariable, $line.directory, $line.recursive, $line.scheduled, $line.features ) } } # parsing then policy object foreach ($line in $policy_directories) { # if directory appears only in policy (so not in Excel) if (-not $excel_directories.directory.contains($line.directory)) { # set the directory to the "remove" hive $obj_body.remove.AddWindowsDirectories( $line.pathvariable, $line.directory, $line.recursive, $line.scheduled, $line.features ) } } # "Certificates" tab # Parsing excel object first # TODO confirm this is the right way to compare certificates $policy_certs = $obj_policy.features.configuration.certificates $excel_certs = $obj_policy_excel.certificates foreach ($line in $excel_certs) { # If certs appears in both lists if ($policy_certs.signature_fingerprint.value.contains($line.signature_fingerprint.value)) { # No changes needed continue } else { # if cert only in excel list, set the cert to the "add" hive $obj_body.add.AddCertificates( $line.signature_issuer, $line.signature_company_name, $line.signature_fingerprint.algorithm, $line.signature_fingerprint.value ) } } # Parsing then policy object foreach ($line in $policy_certs) { # if cert appears only in policy (so not in Excel) if (-not $excel_certs.signature_fingerprint.value.contains($line.signature_fingerprint.value)) { # set the cert to the "remove" hive $obj_body.remove.AddCertificates( $line.signature_issuer, $line.signature_company_name, $line.signature_fingerprint.algorithm, $line.signature_fingerprint.value ) } } # "Webdomains" tab # Parsing excel object first $policy_webdomains = $obj_policy.features.configuration.webdomains $excel_webdomains = $obj_policy_excel.webdomains foreach ($line in $excel_webdomains) { # If webdomain appears in both lists if ($policy_webdomains.domain.contains($line.domain)) { # No changes needed continue } else { # if webdomain only in excel list, set the webdomain to the "add" hive $obj_body.add.AddWebDomains( $line.domain ) } } # Parsing then policy object foreach ($line in $policy_webdomains) { # if webdomain appears only in policy (so not in Excel) if (-not $excel_webdomains.domain.contains($line.domain)) { # set the webdomain to the "remove" hive $obj_body.remove.AddWebDomains( $line.domain ) } } # "Ips_hosts" tab # Parsing excel object first $policy_ips_hosts = $obj_policy.features.configuration.ips_hosts $excel_ips_hosts = $obj_policy_excel.ips_hosts foreach ($line in $excel_ips_hosts) { # If Ips_hosts appears in both lists if ($policy_ips_hosts.ip.contains($line.ip)) { # No changes needed continue } else { # if Ips_hosts only in excel list, set the Ips_hosts to the "add" hive $obj_body.add.AddIpsHostsIpv4Address( $line.ip ) } } # Parsing then policy object foreach ($line in $policy_ips_hosts) { # if Ips_hosts appears only in policy (so not in Excel) if (-not $excel_ips_hosts.ip.contains($line.ip)) { # set the Ips_hosts to the "remove" hive $obj_body.remove.AddIpsHostsIpv4Address( $line.ip ) } } # "Ips_Hosts_subnet_v6" tab # Parsing excel object first $policy_ips_hosts_subnet_v6 = $obj_policy.features.configuration.ips_hosts.ipv6_subnet | Where-Object { $_ } $excel_ips_hosts_subnet_v6 = $obj_policy_excel.ips_hosts.ipv6_subnet | Where-Object { $_ } foreach ($line in $excel_ips_hosts_subnet_v6) { # if subnet appears in both lists if ($policy_ips_hosts_subnet_v6.contains($line)) { # no changes continue } else { # if subnet only in excel list, set the subnet to the "add" hive $obj_body.add.AddIpsHostsIpv6Subnet( $line ) } # } } # parsing then policy object foreach ($line in $policy_ips_hosts_subnet_v6) { # if subnet appears only in policy (so not in Excel) if (-not $excel_ips_hosts_subnet_v6.contains($line)) { # set the subnet to the "remove" hive $obj_body.remove.AddIpsHostsIpv6Subnet( $line ) } } # "ip ranges" tab # Parsing excel object first $policy_ip_range = $obj_policy.features.configuration.ips_hosts.ip_range | Where-Object { $_ } $excel_ip_range = $obj_policy_excel.ips_hosts.ip_range | Where-Object { $_ } foreach ($line in $excel_ip_range) { # If ip_start appears in both lists if ($policy_ip_range.ip_start.contains($line.ip_start)) { # find the index of the ip_start in the policy list $policy_index = $policy_ip_range.ip_start.IndexOf($line.ip_start) # use index to find the corresponding ip_end $policy_ip_end = $policy_ip_range.ip_end[$policy_index] # if policy_ip_end is the same as in excel list, no changes needed if ($policy_ip_end -eq $line.ip_end) { continue } else { # if policy_ip_end is different, remove the ip_start & ip_end from policy and ... $obj_body.remove.AddIpsRange( $policy_ip_range.ip_start[$policy_index], $policy_ip_range.ip_end[$policy_index] ) # ... set the ip range from excel to the "add" hive $obj_body.add.AddIpsRange( $line.ip_start, $line.ip_end ) } } # if ip_start appears only in excel list else { # set the ip range to the "add" hive $obj_body.add.AddIpsRange( $line.ip_start, $line.ip_end ) } } # then parsing policy object foreach ($line in $policy_ip_range) { # if ip_start appears only in policy (so not in Excel) if (-not $excel_ip_range.ip_start.contains($line.ip_start)) { # set the ip range to the "remove" hive $obj_body.remove.AddIpsRange( $line.ip_start, $line.ip_end ) } } # "Ips_Hosts_subnet_v4" tab # Parsing excel object first $policy_ips_hosts_subnet_v4 = $obj_policy.features.configuration.ips_hosts.ipv4_subnet | Where-Object { $_ } $excel_ips_hosts_subnet_v4 = $obj_policy_excel.ips_hosts.ipv4_subnet | Where-Object { $_ } foreach ($line in $excel_ips_hosts_subnet_v4) { # If ip appears in both lists if ($policy_ips_hosts_subnet_v4.ip.contains($line.ip)) { # find the index of the ip in the policy list $policy_index = $policy_ips_hosts_subnet_v4.ip.IndexOf($line.ip) # use index to find the corresponding mask $policy_mask = $policy_ips_hosts_subnet_v4.mask[$policy_index] # if policy_mask is the same as in excel list, no changes needed if ($policy_mask -eq $line.mask) { continue } else { # if policy_mask is different, remove the ip and mask from policy and ... $obj_body.remove.AddIpsHostsIpv4Subnet( $policy_ips_hosts_subnet_v4.ip[$policy_index], $policy_ips_hosts_subnet_v4.mask[$policy_index] ) # ... set the ip from excel to the "add" hive $obj_body.add.AddIpsHostsIpv4Subnet( $line.ip, $line.mask ) } } } # then parsing policy object foreach ($line in $policy_ips_hosts_subnet_v4) { # if ip appears only in policy (so not in Excel) if (-not $excel_ips_hosts_subnet_v4.ip.contains($line.ip)) { # set the ip to the "remove" hive $obj_body.remove.AddIpsHostsIpv4Subnet( $line.ip, $line.mask ) } } # "Extensions" tab # Parsing excel object first $policy_extensions = $obj_policy.features.configuration.extensions $excel_extensions = $obj_policy_excel.extensions $extensions_list_to_add = @() foreach ($line in $excel_extensions.names) { # If extension appears in both lists if ($policy_extensions.names.contains($line)) { # No changes needed continue } else { # if extension only in excel list, set the extension to the "add" hive # Adding it to $extensions_list_to_add $extensions_list_to_add += $line } } # If extensions to add not empty if ($null -ne $extensions_list_to_add) { [PSCustomObject]$ext = @{ Names = $extensions_list_to_add scheduled = $true features = 'AUTO_PROTECT' } $obj_body.add.AddExtensions( $ext ) } # Parsing then policy object $extensions_list_to_remove = @() foreach ($line in $policy_extensions.names) { # if extension appears only in policy (so not in Excel) # Adding it to the $extensions_list_to_remove if (-not $excel_extensions.names.contains($line)) { $extensions_list_to_remove += $line } } # If extensions to remove not empty if ($null -ne $extensions_list_to_remove) { # set the extension to the "remove" hive [PSCustomObject]$ext = @{ Names = $extensions_list_to_remove scheduled = $true features = 'AUTO_PROTECT' } $obj_body.remove.AddExtensions( $ext ) } # "Linux Files" tab # Parsing excel object first $policy_linux_files = $obj_policy.features.configuration.linux.files $excel_linux_files = $obj_policy_excel.linux.files foreach ($line in $excel_linux_files) { # If file appears in both lists if ($policy_linux_files.contains($line.Path)) { # No changes needed continue } else { # if file only in excel list, set the file to the "add" hive $obj_body.add.AddLinuxFiles( $line.pathvariable, $line.path, $line.scheduled, $line.features ) } } # Parsing then policy object foreach ($line in $policy_linux_files) { # if file appears only in policy (so not in Excel) if (-not $excel_linux_files.path.contains($line.path)) { # set the file to the "remove" hive $obj_body.remove.AddLinuxFiles( $line.pathvariable, $line.path, $line.scheduled, $line.features ) } } # "Linux Directories" tab # Parsing excel object first $policy_linux_directories = $obj_policy.features.configuration.linux.directories $excel_linux_directories = $obj_policy_excel.linux.directories foreach ($line in $excel_linux_directories) { # If directory appears in both lists if ($policy_linux_directories.contains($line.directory)) { # No changes needed continue } else { # if directory only in excel list, set the directory to the "add" hive $obj_body.add.AddLinuxDirectories( $line.pathvariable, $line.directory, $line.recursive, $line.scheduled, $line.features ) } } # Parsing then policy object foreach ($line in $policy_linux_directories) { # if directory appears only in policy (so not in Excel) if (-not $excel_linux_directories.directory.contains($line.directory)) { # set the directory to the "remove" hive $obj_body.remove.AddLinuxDirectories( $line.pathvariable, $line.directory, $line.recursive, $line.scheduled, $line.features ) } } # "Mac Files" tab # Parsing excel object first $policy_mac_files = $obj_policy.features.configuration.mac.files $excel_mac_files = $obj_policy_excel.mac.files foreach ($line in $excel_mac_files) { # If file appears in both lists if ($policy_mac_files.contains($line.Path)) { # No changes needed continue } else { # if file only in excel list, set the file to the "add" hive $obj_body.add.AddMacFiles( $line.pathvariable, $line.path, $line.scheduled, $line.features ) } } # Parsing then policy object foreach ($line in $policy_mac_files) { # if file appears only in policy (so not in Excel) if (-not $excel_mac_files.path.contains($line.path)) { # set the file to the "remove" hive $obj_body.remove.AddMacFiles( $line.pathvariable, $line.path, $line.scheduled, $line.features ) } } # "Mac Directories" tab # Parsing excel object first $policy_mac_directories = $obj_policy.features.configuration.mac.directories $excel_mac_directories = $obj_policy_excel.mac.directories foreach ($line in $excel_mac_directories) { # If directory appears in both lists if ($policy_mac_directories.contains($line.directory)) { # No changes needed continue } else { # if directory only in excel list, set the directory to the "add" hive $obj_body.add.AddMacDirectories( $line.pathvariable, $line.directory, $line.recursive, $line.scheduled, $line.features ) } } # Parsing then policy object foreach ($line in $policy_mac_directories) { # if directory appears only in policy (so not in Excel) if (-not $excel_mac_directories.directory.contains($line.directory)) { # set the directory to the "remove" hive $obj_body.remove.AddMacDirectories( $line.pathvariable, $line.directory, $line.recursive, $line.scheduled, $line.features ) } } return $obj_body } #EndRegion '.\Private\Merge-SepCloudAllowList.ps1' 574 #Region '.\Public\Export-SepCloudAllowListPolicyToExcel.ps1' 0 function Export-SepCloudAllowListPolicyToExcel { <# .SYNOPSIS Export an Allow List policy to a human readable excel report .INPUTS Policy name Policy version Excel path .OUTPUTS Excel file .DESCRIPTION Exports an allow list policy object it to an Excel file, with one tab per allow type (filename/file hash/directory etc...) Supports pipeline input with allowlist policy object .EXAMPLE Export-SepCloudAllowListPolicyToExcel -Name "My Allow list Policy" -Version 1 -Path "allow_list.xlsx" Exports the policy with name "My Allow list Policy" and version 1 to an excel file named "allow_list.xlsx" .EXAMPLE Get-SepCloudPolicyDetails -Name "My Allow list Policy" | Export-SepCloudAllowListPolicyToExcel -Path "allow_list.xlsx" Gathers policy in an object, pipes the output to Export-SepCloudAllowListPolicyToExcel to export in excel format #> [CmdletBinding(DefaultParameterSetName = 'PolicyName')] param ( # Path of Export [Parameter(Mandatory)] [Alias("Path")] [Alias("Excel")] [string] $excel_path, # Policy version [Parameter( ParameterSetName = 'PolicyName' )] [string] [Alias("Version")] $Policy_Version, # Exact policy name [Parameter( ParameterSetName = 'PolicyName' )] [string] [Alias("Name")] $Policy_Name, # Policy Obj to work with [Parameter( ValueFromPipeline, ParameterSetName = 'PolicyObj' )] [Alias("PolicyObj")] [pscustomobject] $obj_policy ) process { # If no PSObject is provided, get it from Get-SepCloudPolicyDetails if ($null -eq $PSBoundParameters['obj_policy']) { # Use specific version or by default latest if ($Policy_version -ne "") { $obj_policy = Get-SepCloudPolicyDetails -Name $Policy_Name -Policy_Version $Policy_Version } else { $obj_policy = Get-SepCloudPolicyDetails -Name $Policy_Name } } # Verify the policy is an allow list policy if ($obj_policy.features.properties.name -ne "EXCEPTION") { throw "ERROR - The policy is not an allow list policy" } # Init $Applications = $obj_policy.features.configuration.applications.processfile $Certificates = $obj_policy.features.configuration.certificates $Webdomains = $obj_policy.features.configuration.webdomains $Extensions_list = $obj_policy.features.configuration.extensions.names $Files = $obj_policy.features.configuration.windows.files $Directories = $obj_policy.features.configuration.windows.directories $linux_Files = $obj_policy.features.configuration.linux.files $linux_Directories = $obj_policy.features.configuration.linux.directories $mac_Files = $obj_policy.features.configuration.mac.files $mac_Directories = $obj_policy.features.configuration.mac.directories # Split IPS ipv4 addresses & subnet in different arrays to export in different excel sheets $Ips_Hosts = $obj_policy.features.configuration.ips_hosts | Where-Object { $null -ne $_.ip } # removing empty strings $Ips_Hosts_subnet_v4 = $obj_policy.features.configuration.ips_hosts.ipv4_subnet | Where-Object { $_ } # removing empty strings $Ips_Hosts_subnet_v6_list = $obj_policy.features.configuration.ips_hosts.ipv6_subnet | Where-Object { $_ } # removing empty strings $Ips_range = $obj_policy.features.configuration.ips_hosts.ip_range | Where-Object { $_ } # removing empty strings # Split Extensions in an array of objects for correct formating $Extensions = @() foreach ($line in $Extensions_list) { $obj = New-Object -TypeName PSObject $obj | Add-Member -MemberType NoteProperty -Name Extensions -Value $line $Extensions += $obj } # split ipv6 subnet in an array of objects for correct formating $Ips_Hosts_subnet_v6 = @() foreach ($line in $Ips_Hosts_subnet_v6_list) { $obj = New-Object -TypeName PSObject $obj | Add-Member -MemberType NoteProperty -Name ipv6_subnet -Value $line $Ips_Hosts_subnet_v6 += $obj } # Exporting data to Excel # Import-Module -Name ImportExcel $Applications | Export-Excel $excel_path -WorksheetName "Applications" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $Files | ConvertTo-FlatObject | Export-Excel $excel_path -WorksheetName "Files" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $Directories | ConvertTo-FlatObject | Export-Excel $excel_path -WorksheetName "Directories" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $Extensions | Export-Excel $excel_path -WorksheetName "Extensions" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $Webdomains | Export-Excel $excel_path -WorksheetName "Webdomains" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $Ips_Hosts | Export-Excel $excel_path -WorksheetName "Ips_Hosts" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $Ips_Hosts_subnet_v4 | Export-Excel $excel_path -WorksheetName "Ips_Hosts_subnet_v4" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $Ips_Hosts_subnet_v6 | Export-Excel $excel_path -WorksheetName "Ips_Hosts_subnet_v6" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $Ips_range | Export-Excel $excel_path -WorksheetName "Ips_range" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $Certificates | ConvertTo-FlatObject | Export-Excel $excel_path -WorksheetName "Certificates" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $linux_Files | ConvertTo-FlatObject | Export-Excel $excel_path -WorksheetName "Linux Files" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $linux_Directories | ConvertTo-FlatObject | Export-Excel $excel_path -WorksheetName "Linux Directories" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $mac_Files | ConvertTo-FlatObject | Export-Excel $excel_path -WorksheetName "Mac Files" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter $mac_Directories | ConvertTo-FlatObject | Export-Excel $excel_path -WorksheetName "Mac Directories" -ClearSheet -BoldTopRow -AutoSize -FreezeTopRow -AutoFilter } } #EndRegion '.\Public\Export-SepCloudAllowListPolicyToExcel.ps1' 124 #Region '.\Public\Get-SepCloudDeviceDetails.ps1' 0 function Get-SepCloudDeviceDetails { # TODO add documentation <# .SYNOPSIS Gathers device details from the SEP Cloud console .DESCRIPTION Gathers device details from the SEP Cloud console .PARAMETER Device_ID id used to lookup a unique computer .NOTES Information or caveats about the function e.g. 'This function is not supported in Linux' .EXAMPLE Get-SepCloudDeviceDetails -id wduiKXDDSr2CVrRaqrFKNx .EXAMPLE Get-SepCloudDeviceDetails -computername MyComputer #> [CmdletBinding(DefaultParameterSetName = 'Computername')] param ( # device_ID parameter [Parameter( ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Device_ID')] [Alias("id")] [string] $Device_ID, # Computer Name [Parameter( ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Computername' )] [ValidateNotNullOrEmpty()] [Alias("Computer")] [Alias("Device")] [Alias("host")] [string] $Computername ) begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $Token = Get-SEPCloudToken.Token_Bearer } process { switch ($PSBoundParameters.Keys) { Computername { # Get Device_ID if computername is provided $Device_ID = (Get-SepCloudDevices -Computername $Computername).id } Default {} } # Setup URI $URI = 'https://' + $BaseURL + "/v1/devices/$Device_ID" # Setup Headers $Body = @{} $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token Body = $Body } $Response = Invoke-RestMethod -Method GET -Uri $URI -Headers $Headers -Body $Body -UseBasicParsing return $Response } } #EndRegion '.\Public\Get-SepCloudDeviceDetails.ps1' 73 #Region '.\Public\Get-SepCloudDevices.ps1' 0 function Get-SepCloudDevices { <# .SYNOPSIS Gathers list of devices from the SEP Cloud console .PARAMETER Computername Specify one or many computer names. Accepts pipeline (up to 10 devices per query) Supports partial match .PARAMETER is_online Switch to lookup only online machines .PARAMETER Device_status Lookup devices per security status. Accepts only "SECURE", "AT_RISK", "COMPROMISED", "NOT_COMPUTED" .EXAMPLE Get-SepCloudDevices .EXAMPLE Get-SepCloudDevices -Computername MyComputer .EXAMPLE Get-SepCloudDevices -Online -Device_status AT_RISK .EXAMPLE Get-SepCloudDevices -group "Aw7oerlBROSIl9O_IPFewx" #> [CmdletBinding()] param ( # Optional ComputerName parameter [Parameter(ValueFromPipeline = $true)] [string] $Computername, # Optional Is_Online parameter [Parameter()] [Alias("Online")] [switch] $is_online, # Optional include_details parameter [Parameter()] [Alias("Details")] [switch] $include_details, # Device Group [Parameter()] [Alias("Group")] [string] $Device_group, # Optional Device_Status parameter [Parameter()] [Alias("DeviceStatus")] [ValidateSet("SECURE", "AT_RISK", "COMPROMISED", "NOT_COMPUTED")] $Device_status ) begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $URI_Tokens = 'https://' + $BaseURL + "/v1/devices" $ArrayResponse = @() $Token = (Get-SEPCloudToken).Token_Bearer } process { # HTTP body content containing all the queries $Body = @{} # Iterating through all parameters and add them to the HTTP body switch ($PSBoundParameters.Keys) { Computername { $Body.Add("name", "$Computername") } is_online { $Body.Add("is_online", "true") } include_details { $Body.Add("include_details", "true") } Device_status { $Body.Add("device_status", "$Device_status") } Device_group { $Body.Add("device_group", "$Device_group") } Default {} } # Setup Headers $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token } try { $Response = Invoke-RestMethod -Method GET -Uri $URI_Tokens -Headers $Headers -Body $Body -UseBasicParsing $ArrayResponse += $Response.devices $Devices_count_gathered = (($ArrayResponse | Measure-Object).count) <# If pagination #> if ($Response.total -gt $Devices_count_gathered) { <# Loop through via Offset parameter as there is no "next" parameter for /devices/ API call #> do { # change the "offset" parameter for next query $Body.Remove("offset") $Body.Add("offset", $Devices_count_gathered) # Run query, add it to the array, increment counter $Response = Invoke-RestMethod -Method GET -Uri $URI_Tokens -Headers $Headers -Body $Body -UseBasicParsing $ArrayResponse += $Response.devices $Devices_count_gathered = (($ArrayResponse | Measure-Object).count) } until ( $Devices_count_gathered -ge $Response.total ) } } catch { $StatusCode = $_ $StatusCode } return $ArrayResponse } } #EndRegion '.\Public\Get-SepCloudDevices.ps1' 124 #Region '.\Public\Get-SepCloudEventSearch.ps1' 0 function Get-SepCloudEventSearch { <# .SYNOPSIS Get list of SEP Cloud Events. By default it will gather data for past 30 days .DESCRIPTION Get list of SEP Cloud Events. You can use the following parameters to filter the results: FileDetection, FullScan, or a custom Lucene query .PARAMETER Query Runs a custom Lucene query .PARAMETER PastDays Number of days to go back in the past. Default is 29 days .PARAMETER FullScan Runs the following Lucene query "Event Type Id:8020-Scan AND Scan Name:Full Scan" .PARAMETER FileDetection Runs the following Lucene query "feature_name:MALWARE_PROTECTION AND ( type_id:8031 OR type_id:8032 OR type_id:8033 OR type_id:8027 OR type_id:8028 ) AND ( id:12 OR id:11 AND type_id:8031 )" .EXAMPLE Get-SepCloudEventSearch Gather all possible events. ** very slow approach & limited to 10k events ** .EXAMPLE Get-SepCloudEventSearch -FileDetection -pastdays 20 Gather all file detection events for the past 20 days .EXAMPLE Get-SepCloudEventSearch -FullScan Gather all full scan events .EXAMPLE Get-SepCloudEventSearch -Query "type_id:8031 OR type_id:8032 OR type_id:8033" Runs a custom Lucene query .EXAMPLE Get-SepCloudEventSearch -Query "type_id:8031 OR type_id:8032 OR type_id:8033" -PastDays 14 Runs a custom Lucene query for the past 14 days #> [CmdletBinding(DefaultParameterSetName = 'Query')] param ( # file Detection [Parameter(ParameterSetName = 'FileDetection')] [switch] $FileDetection, # full scan [Parameter(ParameterSetName = 'FullScan')] [switch] $FullScan, # Custom query to run [Parameter(ParameterSetName = 'Query')] [string] $Query, # Date parameter [Parameter()] [Alias("Days")] [int] $PastDays = 29 ) begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $URI_Tokens = 'https://' + $BaseURL + "/v1/event-search" $ArrayResponse = @() $Token = (Get-SEPCloudToken).Token_Bearer } process { # HTTP body content containing all mandatory info to start a query $Body = @{ "product" = "SAEP" "feature_name" = "ALL" } <# Setting dates for the query Date Format required : -UFormat "%Y-%m-%dT%T.000+00:00" Example : "start_date": "2022-10-16T00:00:00.000+00:00", "end_date": "2022-11-16T00:00:00.000+00:00" #> # Setting dates for the query Date Format required : -UFormat "%Y-%m-%dT%T.000+00:00" $end_date = (Get-Date -Format "yyyy-MM-ddTHH:mm:ss.fffK") $start_date = ((Get-Date).AddDays(-$PastDays) | Get-Date -Format "yyyy-MM-ddTHH:mm:ss.fffK") $Body.Add("start_date", $start_date) $Body.Add("end_date", $end_date) # Iterating through all parameter and adding them to the HTTP body switch ($PSBoundParameters.Keys) { 'FileDetection' { $Body.Add("query", '( feature_name:MALWARE_PROTECTION AND ( type_id:8031 OR type_id:8032 OR type_id:8033 OR type_id:8027 OR type_id:8028 ) AND ( id:12 OR id:11 AND type_id:8031 ) )') } 'FullScan' { $Body.Add("query", 'Event Type Id:8020-Scan AND Scan Name:Full Scan') } 'Query' { $Body.Add("query", "$Query") } Default {} } # Convert body to Json after adding potential query with parameters $Body_Json = ConvertTo-Json $Body $Headers = @{ Host = $BaseURL Accept = "application/json" "Content-Type" = "application/json" Authorization = $Token } try { $Response = Invoke-RestMethod -Method POST -Uri $URI_Tokens -Headers $Headers -Body $Body_Json -UseBasicParsing $ArrayResponse += $Response while ($Response.next) { # change the "next" offset for pagination $Body.Remove("next") $Body.Add("next", $Response.next) $Body_Json = ConvertTo-Json $Body # Run query & add it to the array $Response = Invoke-RestMethod -Method POST -Uri $URI_Tokens -Headers $Headers -Body $Body_Json -UseBasicParsing $ArrayResponse += $Response } } catch { $StatusCode = $_ $StatusCode } return $ArrayResponse.events } } #EndRegion '.\Public\Get-SepCloudEventSearch.ps1' 127 #Region '.\Public\Get-SepCloudFeatureList.ps1' 0 function Get-SepCloudFeatureList { <# TODO : fill in description Get-SepCloudFeatureList .SYNOPSIS retrieve SES enumeration details for your devices like feature names, security status and reason codes. .DESCRIPTION retrieve SES enumeration details for your devices like feature names, security status and reason codes. .PARAMETER None .OUTPUTS PSObject .EXAMPLE Get-SepCloudFeatureList Gathers all possible feature name, content name, security status and reason codes the API can provide and its related IDs #> [CmdletBinding()] param () begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $URI_Tokens = 'https://' + $BaseURL + "/v1/devices/enums" $Token = (Get-SEPCloudToken).Token_Bearer } process { # HTTP body content containing all the queries $Body = @{} $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token Body = $Body } $Response = Invoke-RestMethod -Method GET -Uri $URI_Tokens -Headers $Headers -Body $Body -UseBasicParsing return $Response } } #EndRegion '.\Public\Get-SepCloudFeatureList.ps1' 38 #Region '.\Public\Get-SepCloudIncidentDetails.ps1' 0 function Get-SepCloudIncidentDetails { <# TODO fill description TODO finish up the API query from incident_number and not UID for ease of use .SYNOPSIS Gathers details about an open incident .DESCRIPTION Gathers details about an open incident. Currently only supports gathering details from an incident UID .PARAMETER incident_uid Incident GUID .PARAMETER incident_number Incident number -- NOT IMPLEMENTED YET -- .EXAMPLE Get-SepCloudIncidentDetails -incident_uid "ed5924c6-b36d-4449-88c1-4a1f974a01bb" #> [CmdletBinding()] param ( # Incident GUID [Parameter( ValueFromPipelineByPropertyName = $true )] [string] [Alias("incident_uid")] $Incident_ID # # Incident number # [Parameter( # ValueFromPipeline # )] # [string[]] # [Alias("Name")] # $Incident_number ) begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $Token = (Get-SEPCloudToken).Token_Bearer } process { $URI = 'https://' + $BaseURL + "/v1/incidents/$Incident_ID" $Body = @{} $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token Body = $Body } $Resp = Invoke-RestMethod -Method GET -Uri $URI -Headers $Headers -Body $Body -UseBasicParsing $Resp } } #EndRegion '.\Public\Get-SepCloudIncidentDetails.ps1' 56 #Region '.\Public\Get-SepCloudIncidents.ps1' 0 function Get-SepCloudIncidents { <# TODO fill description for Get-SepCloudIncidents .SYNOPSIS Get list of SEP Cloud incidents. By default, shows only opened incidents .DESCRIPTION Get list of SEP Cloud incidents. Using the LUCENE query syntax, you can customize which incidents to gather. More information : https://techdocs.broadcom.com/us/en/symantec-security-software/endpoint-security-and-management/endpoint-security/sescloud/Endpoint-Detection-and-Response/investigation-page-overview-v134374740-d38e87486/Cloud-Database-Search/query-and-filter-operators-by-data-type-v134689952-d38e88796.html .PARAMETER Open filters only opened incidents. Simulates a query "state_id: [0 TO 3]" which represents incidents with the following states <0 Unknown | 1 New | 2 In Progress | 3 On Hold> .PARAMETER Include_events Includes every events that both are part of the context & triggered incident events .PARAMETER Query Custom Lucene query to pass to the API .OUTPUTS PSObject containing all SEP incidents .EXAMPLE Get-SepCloudIncidents -Open -Include_Events .EXAMPLE Get-SepCloudIncidents -Query "state_id: [0 TO 5]" This query a list of every possible incidents (opened, closed and with "Unknown" status) #> [CmdletBinding(DefaultParameterSetName = 'QueryOpen')] param ( # Opened incidents [Parameter( ParameterSetName = "QueryOpen" )] [switch] $Open, # Include events [Parameter()] [switch] $Include_events, # Custom query to run [Parameter( ParameterSetName = "QueryCustom" )] [string] $Query ) begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $URI_Tokens = 'https://' + $BaseURL + "/v1/incidents" $ArrayResponse = @() $Token = Get-SEPCloudToken } process { # HTTP body content containing all the queries $Body = @{} # Settings dates $end_date = Get-Date -Format "yyyy-MM-ddTHH:mm:ss.fffK" $start_date = ((Get-Date).addDays(-29) | Get-Date -Format "yyyy-MM-ddTHH:mm:ss.fffK") $Body.Add("start_date", $start_date) $Body.Add("end_date", $end_date) # Iterating through all parameter and adding them to the HTTP body switch ($PSBoundParameters.Keys) { 'Query' { $Body.Add("query", "$Query") } 'Open' { $Body.Add("query", "state_id: [0 TO 3]") } 'Include_events' { $Body.Add("include_events", "true") } Default { } } $Body_Json = ConvertTo-Json $Body $Headers = @{ Host = $BaseURL Accept = "application/json" "Content-Type" = "application/json" Authorization = $Token } try { $Response = Invoke-RestMethod -Method POST -Uri $URI_Tokens -Headers $Headers -Body $Body_Json -UseBasicParsing $ArrayResponse += $Response if ($null -ne $Response.next) { <# If pagination #> do { # change the "next" offset for next query $Body.Remove("next") $Body.Add("next", $Response.next) $Body_Json = ConvertTo-Json $Body # Run query & add it to the array $Response = Invoke-RestMethod -Method POST -Uri $URI_Tokens -Headers $Headers -Body $Body_Json -UseBasicParsing $ArrayResponse += $Response } until ( ($null -eq $Response.next) ) } } catch { $StatusCode = $_ $StatusCode } return $ArrayResponse.incidents } } #EndRegion '.\Public\Get-SepCloudIncidents.ps1' 112 #Region '.\Public\Get-SepCloudPolices.ps1' 0 function Get-SepCloudPolices { <# .SYNOPSIS Provides a list of all policies in your SEP Cloud account .DESCRIPTION Provides a list of all policies in your SEP Cloud account .PARAMETER None .OUTPUTS PSObject .EXAMPLE Get-SepCloudPolices Gathers all possible policies in your SEP Cloud account #> begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $URI_Tokens = 'https://' + $BaseURL + "/v1/policies" $Token = (Get-SEPCloudToken).Token_Bearer $Body = @{} $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token Body = $Body } } process { try { $Response = Invoke-RestMethod -Method GET -Uri $URI_Tokens -Headers $Headers -Body $Body -UseBasicParsing } catch { $StatusCode = $_ $StatusCode } $Response } } #EndRegion '.\Public\Get-SepCloudPolices.ps1' 43 #Region '.\Public\Get-SepCloudPolicyDetails.ps1' 0 function Get-SepCloudPolicyDetails { <# .SYNOPSIS Gathers detailed information on SEP Cloud policy .DESCRIPTION Gathers detailed information on SEP Cloud policy .PARAMETER Policy_UUID Policy UUID .PARAMETER Policy_Version Policy version .PARAMETER Policy_Name Exact policy name .OUTPUTS PSObject .EXAMPLE Get-SepCloudPolicyDetails -name "My Policy" Gathers detailed information on the latest version SEP Cloud policy named "My Policy" .EXAMPLE Get-SepCloudPolicyDetails -name "My Policy" -version 1 Gathers detailed information on the version 1 of SEP Cloud policy named "My Policy" .EXAMPLE "My Policy","My Policy 2" | Get-SepCloudPolicyDetails Piped strings are used as policy name to gather detailed information on the latest version SEP Cloud policy named "My Policy" & "My Policy 2" #> param ( # Policy UUID [Parameter( ValueFromPipelineByPropertyName = $true )] [string] [Alias("policy_uid")] $Policy_UUID, # Policy version [Parameter()] [string] [Alias("Version")] $Policy_Version, # Exact policy name [Parameter( Mandatory, ValueFromPipeline )] [string[]] [Alias("Name")] $Policy_Name ) begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $Token = (Get-SEPCloudToken).Token_Bearer $obj_policies = (Get-SepCloudPolices).policies $Body = @{} $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token Body = $Body } } process { # Get list of all SEP Cloud policies and get only the one with the correct name $obj_policy = ($obj_policies | Where-Object { $_.name -eq "$Policy_Name" }) if ($null -eq $Policy_version ) { $obj_policy = ($obj_policy | Sort-Object -Property policy_version -Descending | Select-Object -First 1) } $Policy_Version = ($obj_policy).policy_version $Policy_UUID = ($obj_policy).policy_uid $URI = 'https://' + $BaseURL + "/v1/policies/$Policy_UUID/versions/$Policy_Version" $Resp = Invoke-RestMethod -Method GET -Uri $URI -Headers $Headers -Body $Body -UseBasicParsing return $Resp } } #EndRegion '.\Public\Get-SepCloudPolicyDetails.ps1' 84 #Region '.\Public\Get-SepCloudTargetRules.ps1' 0 function Get-SepCloudTargetRules { <# .SYNOPSIS Provides a list of all target rules in your SEP Cloud account .DESCRIPTION Provides a list of all target rules in your SEP Cloud account. Formely known as SEP Location awareness .PARAMETER None .OUTPUTS PSObject .EXAMPLE Get-SepCloudTargetRules Gathers all possible target rules #> begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $URI_Tokens = 'https://' + $BaseURL + "/v1/policies/target-rules" $Token = (Get-SEPCloudToken).Token_Bearer $Body = @{} $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token Body = $Body } } process { try { $Response = Invoke-RestMethod -Method GET -Uri $URI_Tokens -Headers $Headers -Body $Body -UseBasicParsing } catch { $StatusCode = $_ $StatusCode } $Response } } #EndRegion '.\Public\Get-SepCloudTargetRules.ps1' 43 #Region '.\Public\Get-SepThreatIntelCveProtection.ps1' 0 function Get-SepThreatIntelCveProtection { <# .SYNOPSIS Provide information whether a given CVE has been blocked by any of Symantec technologies .DESCRIPTION Provide information whether a given URL/domain has been blocked by any of Symantec technologies. These technologies include Antivirus (AV), Intrusion Prevention System (IPS) and Behavioral Analysis & System Heuristics (BASH) .PARAMETER cve Specify one or many CVE to check .EXAMPLE Get-SepThreatIntelCveProtection -cve CVE-2023-35311 Gathers information whether CVE-2023-35311 has been blocked by any of Symantec technologies .EXAMPLE "CVE-2023-35311","CVE-2023-35312" | Get-SepThreatIntelCveProtection Gathers cve from pipeline by value whether CVE-2023-35311 & CVE-2023-35312 have been blocked by any of Symantec technologies #> [CmdletBinding()] param ( # Mandatory cve [Parameter( Mandatory, ValueFromPipeline = $true)] [Alias('vuln')] [Alias('vulnerability')] [string[]] $cve ) begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $Token = (Get-SEPCloudToken).Token_Bearer # HTTP body content containing all the queries $Body = @{} $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token Body = $Body } } process { $array_cve = @() foreach ($c in $cve) { $URI = 'https://' + $BaseURL + "/v1/threat-intel/protection/cve/" + $c $Response = Invoke-RestMethod -Method GET -Uri $URI -Headers $Headers -Body $Body -UseBasicParsing $array_cve += $Response } return $array_cve } } #EndRegion '.\Public\Get-SepThreatIntelCveProtection.ps1' 54 #Region '.\Public\Get-SepThreatIntelFileProtection.ps1' 0 function Get-SepThreatIntelFileProtection { <# .SYNOPSIS Provide information whether a given file has been blocked by any of Symantec technologies .DESCRIPTION Provide information whether a given file has been blocked by any of Symantec technologies. These technologies include Antivirus (AV), Intrusion Prevention System (IPS) and Behavioral Analysis & System Heuristics (BASH) .INPUTS sha256 .OUTPUTS PSObject .PARAMETER file_sha256 Specify one or many sha256 hash .EXAMPLE Get-SepThreatIntelFileProtection -file_sha256 eec3f761f7eabe9ed569f39e896be24c9bbb8861b15dbde1b3d539505cd9dd8d Gathers information whether the file with sha256 has been blocked by any of Symantec technologies .EXAMPLE "eec3f761f7eabe9ed569f39e896be24c9bbb8861b15dbde1b3d539505cd9dd8d","eec3f761f7eabe9ed569f39e896be24c9bbb8861b15dbde1b3d539505cd9dd8e" | Get-SepThreatIntelFileProtection Gathers sha from pipeline by value whether the files with sha256 have been blocked by any of Symantec technologies #> [CmdletBinding()] param ( # Mandatory file sha256 [Parameter( Mandatory, ValueFromPipeline = $true)] [Alias('sha256')] [string[]] $file_sha256 ) begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $Token = (Get-SEPCloudToken).Token_Bearer $Body = @{} $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token Body = $Body } } process { $array_file_sha256 = @() foreach ($f in $file_sha256) { $URI = 'https://' + $BaseURL + "/v1/threat-intel/protection/file/" + $f $Response = Invoke-RestMethod -Method GET -Uri $URI -Headers $Headers -Body $Body -UseBasicParsing $array_file_sha256 += $Response } return $array_file_sha256 } } #EndRegion '.\Public\Get-SepThreatIntelFileProtection.ps1' 56 #Region '.\Public\Get-SepThreatIntelNetworkProtection.ps1' 0 function Get-SepThreatIntelNetworkProtection { <# .SYNOPSIS Provide information whether a given URL/domain has been blocked by any of Symantec technologies .DESCRIPTION Provide information whether a given URL/domain has been blocked by any of Symantec technologies. These technologies include Antivirus (AV), Intrusion Prevention System (IPS) and Behavioral Analysis & System Heuristics (BASH) .PARAMETER domain Specify one or many URL/domain to check .OUTPUTS PSObject .EXAMPLE Get-SepThreatIntelNetworkProtection -domain nicolascoolman.eu Gathers information whether the URL/domain has been blocked by any of Symantec technologies .EXAMPLE "nicolascoolman.eu","google.com" | Get-SepThreatIntelNetworkProtection Gathers somains from pipeline by value whether the URLs/domains have been blocked by any of Symantec technologies #> [CmdletBinding()] param ( # Mandatory domain name [Parameter( Mandatory, ValueFromPipeline = $true)] [Alias('domain')] [Alias('URL')] [string[]] $network ) begin { # Init $BaseURL = (Get-ConfigurationPath).BaseUrl $Token = (Get-SEPCloudToken).Token_Bearer $Body = @{} $Headers = @{ Host = $BaseURL Accept = "application/json" Authorization = $Token Body = $Body } } process { $array_network = @() foreach ($n in $network) { $URI = 'https://' + $BaseURL + "/v1/threat-intel/protection/network/" + $n $Response = Invoke-RestMethod -Method GET -Uri $URI -Headers $Headers -Body $Body -UseBasicParsing $array_network += $Response } return $array_network } } #EndRegion '.\Public\Get-SepThreatIntelNetworkProtection.ps1' 55 #Region '.\Public\Test-SepCloudConnectivity.ps1' 0 function Test-SepCloudConnectivity { <# .SYNOPSIS Test SEP Cloud connectivity .DESCRIPTION Test SEP Cloud connectivity. returns boolean $true if OK, $false if not .EXAMPLE Test-SepCloudConnectivity Test SEP Cloud connectivity and return $true if OK, $false if not #> param ( ) if (Get-SEPCloudToken) { Write-Host "Authentication OK" return $true else { Write-Host "Authentication failed" return $false } } } #EndRegion '.\Public\Test-SepCloudConnectivity.ps1' 24 #Region '.\Public\Update-SepCloudAllowlistPolicy.ps1' 0 function Update-SepCloudAllowlistPolicy { <# TODO verify description .SYNOPSIS Updates Symantec Allow List policy using an excel file .DESCRIPTION Gathers Allow List policy information from an Excel file generated from Export-SepCloudAllowListPolicyToExcel function You can manually add or remove lines to the Excel file, and the updated Excel will be used to add or remove new exceptions to the Allow list policy of your choice .INPUTS - Excel file generated from Export-SepCloudAllowListPolicyToExcel function - Policy name to update - OPTIONAL : policy version (default latest version) .PARAMETER Policy_Version Optional parameter - Version of the policy to update. By default, latest version selected .PARAMETER Policy_Name Exact name of the policy to update .PARAMETER ExcelFile Path fo the Excel file that contains updated information on Allow list to update Takes Excel template from Export-SepCloudAllowListPolicyToExcel function .EXAMPLE First generate an excel file from the policy you want to update Get-SepCloudPolicyDetails -name "Workstations Allow List Policy" | Export-SepCloudAllowListPolicyToExcel -Path .\Data\WorkstationsAllowList.xlsx Manualy perform changes to the Excel file (add or remove exceptions) Then update the policy to reflect the changes to the cloud Update-SepCloudAllowlistPolicy -policy "Workstations Allow List Policy" -ExcelFile .\WorkstationsAllowList.xlsx #> param ( # Policy version [Parameter( )] [string] [Alias("Version")] $Policy_Version, # Exact policy name [Parameter( ValueFromPipeline # Mandatory )] [string] [Alias("PolicyName")] $Policy_Name, # Excel file to import data from [Parameter( # Mandatory # TODO add this parameter as mandatory once development is done )] [string] [Alias("Excel")] $excel_path ) # init $BaseURL = (Get-ConfigurationPath).BaseUrl $Token = (Get-SEPCloudToken).Token_Bearer # Get list of all versions of the SEP Cloud policy $obj_policy = ((Get-SepCloudPolices).policies | Where-Object { $_.name -eq "$Policy_Name" }) switch ($PSBoundParameters.Keys) { 'Policy_Version' { # Merge cloud policy with excel file with specified version $obj_merged_policy = Merge-SepCloudAllowList -Excel $excel_path -Policy_Name $Policy_Name -Policy_Version $Policy_Version $obj_policy = $obj_policy | Where-Object { $_.name -eq "$Policy_Name" -and $_.policy_version -eq $Policy_Version } } Default {} } if ($null -eq $PSBoundParameters['Policy_Version']) { # Merge cloud policy with excel file with latest version $obj_merged_policy = Merge-SepCloudAllowList -Excel $excel_path -Policy_Name $Policy_Name $obj_policy = ($obj_policy | Sort-Object -Property policy_version -Descending | Select-Object -First 1) } # Setup API query $Body = $obj_merged_policy | ConvertTo-Json -Depth 10 $Policy_UUID = ($obj_policy).policy_uid $Policy_Version = ($obj_policy).policy_version $URI = 'https://' + $BaseURL + "/v1/policies/allow-list/$Policy_UUID/versions/$Policy_Version" # API query $Headers = @{ Host = $BaseURL "Content-Type" = "application/json" Accept = "application/json" Authorization = $Token } $Response = Invoke-RestMethod -Method PATCH -Uri $URI -Headers $Headers -Body $Body -UseBasicParsing # TODO uncomment API query when development is done return $Response } #EndRegion '.\Public\Update-SepCloudAllowlistPolicy.ps1' 96 |