PSSymantecSEPM.psm1

#Region '.\Private\Get-ConfigurationPath.ps1' 0
function Get-ConfigurationPath {
    <# TODO update help
    .SYNOPSIS
        returns hashtable object with the BaseURL, SepCloudCreds, SepCloudToken full path
    .DESCRIPTION
    .INPUTS
        None
    .OUTPUTS
        Hashtable
    #>


    @{
        BaseUrl         = "api.sep.securitycloud.symantec.com"
        $ServerAddress  = Read-Host -Prompt "Value"
        SepCloudCreds   = "$env:TEMP\SepCloudOAuthCredentials.xml"
        CachedTokenPath = "$env:TEMP\SepCloudCachedToken.xml"
    }

}
#EndRegion '.\Private\Get-ConfigurationPath.ps1' 20
#Region '.\Private\Get-RestError.ps1' 0
function Get-RestError($Err) {
    #Allows backwards compatibility with older versions of Powershell
    if ($PSVersionTable.PSVersion.Major -lt 6) {
        if ($Err.Exception.Response) {  
            $Reader = New-Object System.IO.StreamReader($Err.Exception.Response.GetResponseStream())
            $Reader.BaseStream.Position = 0
            $Reader.DiscardBufferedData()
            $ResponseBody = $Reader.ReadToEnd()
            if ($ResponseBody.StartsWith('{')) {
                $ResponseBody = $ResponseBody | ConvertFrom-Json
            }
            return $ResponseBody
        } else {
            return $Err.ErrorDetails.Message
        }
    }
}
#EndRegion '.\Private\Get-RestError.ps1' 18
#Region '.\Private\Get-RestErrorDetails.ps1' 0
Function Get-RestErrorDetails {
    <#
    .SYNOPSIS
    Provides basic Rest Error Information from the API call in the event that the REST API call could not be performed successfully.
 
    .EXAMPLE
    try{
        Invoke-RestMethod -Method GET -URI $URI -headers $headers
    }catch{
        Get-RestErrorDetails
    }
    #>

    "An error was found with this command. Please review the resultant error for details."
    "Error Code:" + $_.Exception.Response.StatusCode.Value__ + " " + $_.Exception.Response.ReasonPhrase
    "Error Message: " + $_
}
#EndRegion '.\Private\Get-RestErrorDetails.ps1' 17
#Region '.\Private\Import-SepmConfiguration.ps1' 0
function Import-SepmConfiguration {
    <#
    .SYNOPSIS
        Loads in the default configuration values, and then updates the individual properties
        with values that may exist in a file.
 
    .DESCRIPTION
        Loads in the default configuration values, and then updates the individual properties
        with values that may exist in a file.
 
        The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub
 
    .PARAMETER Path
        The file that may or may not exist with a serialized version of the configuration
        values for this module.
 
    .OUTPUTS
        PSCustomObject
 
    .NOTES
        Internal helper method.
        No side-effects.
 
    .EXAMPLE
        Import-SepmConfiguration -Path 'c:\foo\config.json'
 
        Creates a new default config object and updates its values with any that are found
        within a deserialized object from the content in $Path. The configuration object
        is then returned.
#>

    [CmdletBinding()]
    param(
        [string] $Path
    )

    # Create a configuration object with all the default values. We can then update the values
    # with any that we find on disk.

    $config = [PSCustomObject]@{
        'ServerAddress' = ''
        'port'          = '8446'
        'domain'        = ''
    }

    $jsonObject = Read-SepmConfiguration -Path $Path
    Get-Member -InputObject $config -MemberType NoteProperty |
        ForEach-Object {
            $name = $_.Name
            $type = $config.$name.GetType().Name
            $config.$name = Resolve-PropertyValue -InputObject $jsonObject -Name $name -Type $type -DefaultValue $config.$name
        }

    return $config
}
#EndRegion '.\Private\Import-SepmConfiguration.ps1' 55
#Region '.\Private\Read-SepmConfiguration.ps1' 0
function Read-SepmConfiguration {
    <#
    .SYNOPSIS
        Loads in the default configuration values and returns the deserialized object.
 
    .DESCRIPTION
        Loads in the default configuration values and returns the deserialized object.
 
        The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub
 
    .PARAMETER Path
        The file that may or may not exist with a serialized version of the configuration
        values for this module.
 
    .OUTPUTS
        PSCustomObject
 
    .NOTES
        Internal helper method.
        No side-effects.
 
    .EXAMPLE
        Read-SepmConfiguration -Path 'c:\foo\config.json'
 
        Returns back an object with the deserialized object contained in the specified file,
        if it exists and is valid.
#>

    [CmdletBinding()]
    param(
        [string] $Path
    )

    $content = Get-Content -Path $Path -Encoding UTF8 -ErrorAction Ignore
    if (-not [String]::IsNullOrEmpty($content)) {
        try {
            return ($content | ConvertFrom-Json)
        } catch {
            $message = 'The configuration file for this module is in an invalid state. Use Reset-SepmConfiguration to recover.'
            Write-Warning -Message $message
        }
    }

    return [PSCustomObject]@{}
}
#EndRegion '.\Private\Read-SepmConfiguration.ps1' 45
#Region '.\Private\Resolve-PropertyValue.ps1' 0
function Resolve-PropertyValue {
    <#
    .SYNOPSIS
        Returns the requested property from the provided object, if it exists and is a valid
        value. Otherwise, returns the default value.
 
    .DESCRIPTION
        Returns the requested property from the provided object, if it exists and is a valid
        value. Otherwise, returns the default value.
 
        The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub
 
    .PARAMETER InputObject
        The object to check the value of the requested property.
 
    .PARAMETER Name
        The name of the property on InputObject whose value is desired.
 
    .PARAMETER Type
        The type of the value stored in the Name property on InputObject. Used to validate
        that the property has a valid value.
 
    .PARAMETER DefaultValue
        The value to return if Name doesn't exist on InputObject or is of an invalid type.
 
    .EXAMPLE
        Resolve-PropertyValue -InputObject $config -Name defaultOwnerName -Type String -DefaultValue $null
 
        Checks $config to see if it has a property named "defaultOwnerName". If it does, and it's a
        string, returns that value, otherwise, returns $null (the DefaultValue).
#>

    [CmdletBinding()]
    param(
        [PSCustomObject] $InputObject,

        [Parameter(Mandatory)]
        [string] $Name,

        [Parameter(Mandatory)]
        [ValidateSet('String', 'Boolean', 'Int32', 'Int64')]
        [String] $Type,

        $DefaultValue
    )

    if ($null -eq $InputObject) {
        return $DefaultValue
    }

    $typeType = [String]
    if ($Type -eq 'Boolean') { $typeType = [Boolean] }
    if ($Type -eq 'Int32') { $typeType = [Int32] }
    if ($Type -eq 'Int64') { $typeType = [Int64] }
    $numberEquivalents = @('Int32', 'Int64', 'long', 'int')

    if (Test-PropertyExists -InputObject $InputObject -Name $Name) {
        if (($InputObject.$Name -is $typeType) -or
            (($Type -in $numberEquivalents) -and ($InputObject.$Name.GetType().Name -in $numberEquivalents))) {
            return $InputObject.$Name
        } else {
            return $DefaultValue
        }
    } else {
        return $DefaultValue
    }
}
#EndRegion '.\Private\Resolve-PropertyValue.ps1' 67
#Region '.\Private\Save-SepmConfiguration.ps1' 0
function Save-SepmConfiguration {
    <#
    .SYNOPSIS
        Serializes the provided settings object to disk as a JSON file.
 
    .DESCRIPTION
        Serializes the provided settings object to disk as a JSON file.
 
        The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub
 
    .PARAMETER Configuration
        The configuration object to persist to disk.
 
    .PARAMETER Path
        The path to the file on disk that Configuration should be persisted to.
 
    .NOTES
        Internal helper method.
 
    .EXAMPLE
        Save-SepmConfiguration -Configuration $config -Path 'c:\foo\config.json'
 
        Serializes $config as a JSON object to 'c:\foo\config.json'
#>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory)]
        [PSCustomObject] $Configuration,

        [Parameter(Mandatory)]
        [string] $Path
    )

    if (-not $PSCmdlet.ShouldProcess('Sepm Configuration', 'Save')) {
        return
    }

    $null = New-Item -Path $Path -Force
    ConvertTo-Json -InputObject $Configuration |
        Set-Content -Path $Path -Force -ErrorAction SilentlyContinue -ErrorVariable ev

    if (($null -ne $ev) -and ($ev.Count -gt 0)) {
        $message = "Failed to persist these updated settings to disk. They will remain for this PowerShell session only."
        Write-Warning -Message $message
    }
}
#EndRegion '.\Private\Save-SepmConfiguration.ps1' 47
#Region '.\Private\Skip-Cert.ps1' 0
    function Skip-Cert {
        <#
    .SYNOPSIS
        This function allows skipping the SSL/TLS Secure channel check in the event that there is not a valid certificate available
    .DESCRIPTION
        This function allows skipping the SSL/TLS Secure channel check in the event that there is not a valid certificate available
    .PARAMETER
    None
    .EXAMPLE
        Skip-Cert
    .OUTPUTS
        None
    #>

        if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type) {
            $certCallback = @"
        using System;
        using System.Net;
        using System.Net.Security;
        using System.Security.Cryptography.X509Certificates;
        public class ServerCertificateValidationCallback
        {
            public static void Ignore()
            {
                if(ServicePointManager.ServerCertificateValidationCallback ==null)
                {
                    ServicePointManager.ServerCertificateValidationCallback +=
                        delegate
                        (
                            Object obj,
                            X509Certificate certificate,
                            X509Chain chain,
                            SslPolicyErrors errors
                        )
                        {
                            return true;
                        };
                }
            }
        }
"@

            Add-Type $certCallback
        }
        [ServerCertificateValidationCallback]::Ignore()
    }
#EndRegion '.\Private\Skip-Cert.ps1' 45
#Region '.\Private\Test-PropertyExists.ps1' 0
function Test-PropertyExists {
    <#
    .SYNOPSIS
        Determines if an object contains a property with a specified name.
 
    .DESCRIPTION
        Determines if an object contains a property with a specified name.
 
        This is essentially using Get-Member to verify that a property exists,
        but additionally adds a check to ensure that InputObject isn't null.
 
    .PARAMETER InputObject
        The object to check to see if it has a property named Name.
 
    .PARAMETER Name
        The name of the property on InputObject that is being tested for.
 
    .EXAMPLE
        Test-PropertyExists -InputObject $listing -Name 'title'
 
        Returns $true if $listing is non-null and has a property named 'title'.
        Returns $false otherwise.
 
    .NOTES
        Internal-only helper method.
#>

    [CmdletBinding()]
    [OutputType([bool])]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification = "Exists isn't a noun and isn't violating the intention of this rule.")]
    param(
        [Parameter(Mandatory)]
        [AllowNull()]
        $InputObject,

        [Parameter(Mandatory)]
        [String] $Name
    )

    return (($null -ne $InputObject) -and
            ($null -ne (Get-Member -InputObject $InputObject -Name $Name -MemberType Properties)))
}
#EndRegion '.\Private\Test-PropertyExists.ps1' 42
#Region '.\Private\Test-SEPMAccessToken.ps1' 0
function Test-SEPMAccessToken {
    <#
    .SYNOPSIS
        Test if the access token is still valid
    .DESCRIPTION
        Test if the access token is still valid.
        If no token is passed, will test the cached token.
 
        Returns $true if the token is still valid, $false otherwise
    .PARAMETER TokenInfo
        The token to test
    .OUTPUTS
        System.Boolean
    .NOTE
        Internal helper method.
        This function is used internally by the module and should not be called directly.
    #>

    
    
    param (
        [Alias('AccessToken', 'Token')]
        [PSCustomObject]$TokenInfo
    )

    # If no paramater is passed, test the cached token
    if ($null -eq $TokenInfo) {
        # if token in memory
        if (-not [string]::IsNullOrEmpty($script:accessToken.token) ) {
            # if token still valid
            if ($script:accessToken.tokenExpiration -gt (Get-Date)) {
                return $true
            } 
        }
    }

    # Check if the access token has expired
    if ($TokenInfo.tokenExpiration -gt (Get-Date)) {
        return $true
    }

    # If we get here, no valid token was found
    return $false
}
#EndRegion '.\Private\Test-SEPMAccessToken.ps1' 44
#Region '.\Public\Clear-SepmAuthentication.ps1' 0
function Clear-SepmAuthentication {
    <#
    .SYNOPSIS
        Clears out any API token from memory, as well as from local file storage.
 
    .DESCRIPTION
        Clears out any API token from memory, as well as from local file storage.
 
    .EXAMPLE
        Clear-SepmAuthentication
 
        Clears out any API token from memory, as well as from local file storage.
 
    .NOTES
        This command will not clear your configuration settings.
        Please use Reset-SepmConfiguration to accomplish that.
#>



    $script:Credential = $null
    $script:accessToken = $null

    if (-not $SessionOnly) {
        Remove-Item -Path $script:credentialsFilePath -Force -ErrorAction SilentlyContinue -ErrorVariable ev
        Remove-Item -Path $script:accessTokenFilePath -Force -ErrorAction SilentlyContinue -ErrorVariable ev

        if (($null -ne $ev) -and
            ($ev.Count -gt 0) -and
            ($ev[0].FullyQualifiedErrorId -notlike 'PathNotFound*')) {
            $message = "Experienced a problem trying to remove the file that persists the Access Token [$script:credentialsFilePath]."
            Write-Warning -Message $message
        }
    }

    $message = "This has not cleared your configuration settings. Call Reset-SepmConfiguration to accomplish that."
    Write-Verbose -Message $message
}
#EndRegion '.\Public\Clear-SepmAuthentication.ps1' 38
#Region '.\Public\Get-SEPAdmins.ps1' 0
Function Get-SEPAdmins {
    <#
    .SYNOPSIS
        Displays a list of admins in the Symantec Database
 
    .DESCRIPTION
        Gets the list of administrators for a particular domain.
 
        The Git repo for this module can be found here: https://github.com/Douda/PSSymantecSEPM
 
    .PARAMETER AdminName
        Displays only a specific user from the Admin List
 
    .EXAMPLE
    Get-SEPAdmins -AdminName admin
 
    .EXAMPLE
    Get-SEPAdmins
#>

    [CmdletBinding()]
    Param (
        # AdminName
        [Parameter(
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true
        )]
        [String]
        [Alias("Admin", "AdminName")]
        $AdminName
    )

    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/admin-users"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        # URI query strings
        $QueryStrings = @{
            domain = $script:configuration.domain
        }

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    $params = @{
                        Method  = 'GET'
                        Uri     = $URI
                        headers = $headers
                    }
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }

            }
        }

        # Process the response
        if ([string]::IsNullOrEmpty($AdminName)) {
            return $resp
        } else {
            $resp = $resp | Where-Object { $_.loginName -eq $AdminName }
            return $resp
        }
    }
}
#EndRegion '.\Public\Get-SEPAdmins.ps1' 104
#Region '.\Public\Get-SEPClientDefVersions.ps1' 0
function Get-SEPClientDefVersions {
    <#
    .SYNOPSIS
        Gets a list of clients for a group by content version.
    .DESCRIPTION
        Gets a list of clients for a group by content version.
    .EXAMPLE
        Get-SEPClientDefVersions
 
        Gets a list of clients for a group by content version.
#>


    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/stats/client/content"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method  = 'GET'
            Uri     = $URI
            headers = $headers
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPClientDefVersions.ps1' 78
#Region '.\Public\Get-SEPClientStatus.ps1' 0
function Get-SEPClientStatus {
    <#
    .SYNOPSIS
        Gets a list and count of the online and offline clients.
    .DESCRIPTION
        Gets a list and count of the online and offline clients.
    .EXAMPLE
        Get-SEPClientStatus
 
        Gets a list and count of the online and offline clients.
#>


    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/stats/client/onlinestatus"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method  = 'GET'
            Uri     = $URI
            headers = $headers
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPClientStatus.ps1' 78
#Region '.\Public\Get-SEPClientThreatStats.ps1' 0
function Get-SEPClientThreatStats {
    <#
    .SYNOPSIS
        Gets threat statistics
    .DESCRIPTION
        Gets threat statistics
    .EXAMPLE
        Get-SEPClientThreatStats
 
        Gets threat statistics
#>


    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/stats/threat"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method  = 'GET'
            Uri     = $URI
            headers = $headers
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPClientThreatStats.ps1' 78
#Region '.\Public\Get-SEPClientVersion.ps1' 0
function Get-SEPClientVersion {
    <#
    .SYNOPSIS
        Gets a list and count of clients by client product version.
    .DESCRIPTION
        Gets a list and count of clients by client product version.
    .EXAMPLE
        PS C:\PSSymantecSEPM> $SEPversions = Get-SEPClientVersion
        PS C:\PSSymantecSEPM> $SEPversions.clientVersionList
 
        version clientsCount formattedVersion
        ------- ------------ ----------------
        11.0.6000.550 1 11.0.6 (11.0 MR6) build 550
        12.1.2015.2015 1 12.1.2 (12.1 RU2) build 2015
        12.1.6867.6400 1 12.1.6 (12.1 RU6 MP4) build 6867
        12.1.7004.6500 3 12.1.6 (12.1 RU6 MP5) build 7004
        12.1.7454.7000 177 12.1.7 (12.1 RU7) build 7454
        14.0.3752.1000 36 14.0.3 (14.0 RU3 MP7) build 1000
        14.2.1031.0100 21 14.2.1 (14.2 RU1) build 0100
        14.2.3335.1000 3 14.2.3 (14.2 RU3 MP3) build 1000
        14.3.510.0000 12 14.3 (14.3) build 0000
        14.3.558.0000 5 14.3 (14.3) build 0000
 
        Gets a list and count of clients by client product version.
#>


    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/stats/client/version"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method  = 'GET'
            Uri     = $URI
            headers = $headers
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPClientVersion.ps1' 92
#Region '.\Public\Get-SEPComputers.ps1' 0
function Get-SEPComputers {
    <#
    .SYNOPSIS
        Gets the information about the computers in a specified domain
    .DESCRIPTION
        Gets the information about the computers in a specified domain. either from computer names or group names
    .PARAMETER ComputerName
        Specifies the name of the computer for which you want to get the information.
    .PARAMETER GroupName
        Specifies the group full path name for which you want to get the information.
    .EXAMPLE
        Get-SEPComputers
 
        Gets computer details for all computers in the domain
    .EXAMPLE
        Get-SEPComputers -ComputerName "ComputerName"
 
        Gets computer details for the specified computer ComputerName
    .EXAMPLE
        "MyComputer1","MyComputer2" | Get-SEPComputers
 
        Gets computer details for the specified computer MyComputer
    .EXAMPLE
        Get-SEPComputers -GroupName "My Company\EMEA\Workstations"
 
        Gets computer details for all computers in the specified group MyGroup
#>

    [CmdletBinding(
        DefaultParameterSetName = 'ComputerName'
    )]
    Param (
        # ComputerName
        [Parameter(
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'ComputerName'
        )]
        [Alias("Hostname", "DeviceName", "Device", "Computer")]
        [String]
        $ComputerName,

        # group name
        [Parameter(
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'GroupName'
        )]
        [Alias("Group")]
        [String]
        $GroupName
    )

    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {

        if ($ComputerName) {
            $allResults = @()
            $URI = $script:BaseURLv1 + "/computers"

            # URI query strings
            $QueryStrings = @{
                sort         = "COMPUTER_NAME"
                pageIndex    = 1
                pageSize     = 100
                computerName = $ComputerName
            }

            # Construct the URI
            $builder = New-Object System.UriBuilder($URI)
            $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
            foreach ($param in $QueryStrings.GetEnumerator()) {
                $query[$param.Key] = $param.Value
            }
            $builder.Query = $query.ToString()
            $URI = $builder.ToString()
    
            # Invoke the request
            # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
            # else we need to use the Skip-Cert function if self-signed certs are being used.
            do {
                try {
                    # Invoke the request params
                    $params = @{
                        Method  = 'GET'
                        Uri     = $URI
                        headers = $headers
                    }
                    if ($script:accessToken.skipCert -eq $true) {
                        if ($PSVersionTable.PSVersion.Major -lt 6) {
                            Skip-Cert
                            $resp = Invoke-RestMethod @params
                        } else {
                            $resp = Invoke-RestMethod @params -SkipCertificateCheck
                        }
                    } else {
                        $resp = Invoke-RestMethod @params
                    } 
                
                    # Process the response
                    $allResults += $resp.content

                    # Increment the page index & update URI
                    $QueryStrings.pageIndex++
                    $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
                    foreach ($param in $QueryStrings.GetEnumerator()) {
                        $query[$param.Key] = $param.Value
                    }
                    $builder.Query = $query.ToString()
                    $URI = $builder.ToString()
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            } until ($resp.lastPage -eq $true)

            # return the response
            return $allResults
        }

        #Using computer name API call then filtering
        elseif ($GroupName) {
            $allResults = @()
            $URI = $script:BaseURLv1 + "/computers"

            # URI query strings
            $QueryStrings = @{
                sort         = "COMPUTER_NAME"
                pageIndex    = 1
                pageSize     = 100
                computerName = $ComputerName
            }

            # Construct the URI
            $builder = New-Object System.UriBuilder($URI)
            $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
            foreach ($param in $QueryStrings.GetEnumerator()) {
                $query[$param.Key] = $param.Value
            }
            $builder.Query = $query.ToString()
            $URI = $builder.ToString()
    
            # Invoke the request
            # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
            # else we need to use the Skip-Cert function if self-signed certs are being used.
            do {
                try {
                    # Invoke the request params
                    $params = @{
                        Method  = 'GET'
                        Uri     = $URI
                        headers = $headers
                    }
                    if ($script:accessToken.skipCert -eq $true) {
                        if ($PSVersionTable.PSVersion.Major -lt 6) {
                            Skip-Cert
                            $resp = Invoke-RestMethod @params
                        } else {
                            $resp = Invoke-RestMethod @params -SkipCertificateCheck
                        }
                    } else {
                        $resp = Invoke-RestMethod @params
                    } 
                
                    # Process the response
                    $allResults += $resp.content

                    # Increment the page index & update URI
                    $QueryStrings.pageIndex++
                    $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
                    foreach ($param in $QueryStrings.GetEnumerator()) {
                        $query[$param.Key] = $param.Value
                    }
                    $builder.Query = $query.ToString()
                    $URI = $builder.ToString()
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            } until ($resp.lastPage -eq $true)

            # Filtering
            $allResults = $allResults | Where-Object { $_.group.name -eq $GroupName }

            # return the response
            return $allResults
        }

        # Using groupname API call
        elseif ($GroupName) {
            $allResults = @()
                
            # Get SEP Group ID from group name
            $GroupID = Get-SEPMGroups | Where-Object { $_.fullPathName -eq $GroupName } | Select-Object -ExpandProperty id
            $URI = $script:BaseURLv1 + "/groups/$GroupID/computers"

            # URI query strings
            $QueryStrings = @{
                pageIndex = 1
                sort      = "COMPUTER_NAME"
            }

            # Construct the URI
            $builder = New-Object System.UriBuilder($URI)
            $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
            foreach ($param in $QueryStrings.GetEnumerator()) {
                $query[$param.Key] = $param.Value
            }
            $builder.Query = $query.ToString()
            $URI = $builder.ToString()
    
            # Invoke the request
            # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
            # else we need to use the Skip-Cert function if self-signed certs are being used.
            do {
                try {
                    # Invoke the request params
                    $params = @{
                        Method  = 'GET'
                        Uri     = $URI
                        headers = $headers
                    }
                    if ($script:accessToken.skipCert -eq $true) {
                        if ($PSVersionTable.PSVersion.Major -lt 6) {
                            Skip-Cert
                            $resp = Invoke-RestMethod @params
                        } else {
                            $resp = Invoke-RestMethod @params -SkipCertificateCheck
                        }
                    } else {
                        $resp = Invoke-RestMethod @params
                    } 
                
                    # Process the response
                    $allResults += $resp.content

                    # Increment the page index & update URI
                    $QueryStrings.pageIndex++
                    $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
                    foreach ($param in $QueryStrings.GetEnumerator()) {
                        $query[$param.Key] = $param.Value
                    }
                    $builder.Query = $query.ToString()
                    $URI = $builder.ToString()
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            } until ($resp.lastPage -eq $true)

            # return the response
            return $allResults
        }

        else {
            $allResults = @()
            $URI = $script:BaseURLv1 + "/computers"

            # URI query strings
            $QueryStrings = @{
                sort      = "COMPUTER_NAME"
                pageIndex = 1
                pageSize  = 100
            }

            # Construct the URI
            $builder = New-Object System.UriBuilder($URI)
            $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
            foreach ($param in $QueryStrings.GetEnumerator()) {
                $query[$param.Key] = $param.Value
            }
            $builder.Query = $query.ToString()
            $URI = $builder.ToString()
    
            # Invoke the request
            # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
            # else we need to use the Skip-Cert function if self-signed certs are being used.
            do {
                try {
                    # Invoke the request params
                    $params = @{
                        Method  = 'GET'
                        Uri     = $URI
                        headers = $headers
                    }
                    if ($script:accessToken.skipCert -eq $true) {
                        if ($PSVersionTable.PSVersion.Major -lt 6) {
                            Skip-Cert
                            $resp = Invoke-RestMethod @params
                        } else {
                            $resp = Invoke-RestMethod @params -SkipCertificateCheck
                        }
                    } else {
                        $resp = Invoke-RestMethod @params
                    } 
                
                    # Process the response
                    $allResults += $resp.content

                    # Increment the page index & update URI
                    $QueryStrings.pageIndex++
                    $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
                    foreach ($param in $QueryStrings.GetEnumerator()) {
                        $query[$param.Key] = $param.Value
                    }
                    $builder.Query = $query.ToString()
                    $URI = $builder.ToString()
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            } until ($resp.lastPage -eq $true)

            # return the response
            return $allResults
        }
    }
        
}
#EndRegion '.\Public\Get-SEPComputers.ps1' 326
#Region '.\Public\Get-SEPGUPList.ps1' 0
function Get-SEPGUPList {
    <#
    .SYNOPSIS
        Gets a list and count of clients by client product version.
    .DESCRIPTION
        Gets a list and count of clients by client product version.
    .EXAMPLE
        PS C:\PSSymantecSEPM> $SEPversions = Get-SEPGUPList
        PS C:\PSSymantecSEPM> $SEPversions.clientVersionList
 
        version clientsCount formattedVersion
        ------- ------------ ----------------
        11.0.6000.550 1 11.0.6 (11.0 MR6) build 550
        12.1.2015.2015 1 12.1.2 (12.1 RU2) build 2015
        12.1.6867.6400 1 12.1.6 (12.1 RU6 MP4) build 6867
        12.1.7004.6500 3 12.1.6 (12.1 RU6 MP5) build 7004
        12.1.7454.7000 177 12.1.7 (12.1 RU7) build 7454
        14.0.3752.1000 36 14.0.3 (14.0 RU3 MP7) build 1000
        14.2.1031.0100 21 14.2.1 (14.2 RU1) build 0100
        14.2.3335.1000 3 14.2.3 (14.2 RU3 MP3) build 1000
        14.3.510.0000 12 14.3 (14.3) build 0000
        14.3.558.0000 5 14.3 (14.3) build 0000
 
        Gets a list and count of clients by client product version.
#>


    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/gup/status"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method  = 'GET'
            Uri     = $URI
            headers = $headers
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPGUPList.ps1' 92
#Region '.\Public\Get-SepmAccessToken.ps1' 0
function Get-SepmAccessToken {
    <# TODO update this to use the new Get-SEPToken function
    .SYNOPSIS
        Retrieves the API token for use in the rest of the module.
 
    .DESCRIPTION
        Retrieves the API token for use in the rest of the module.
 
        First will try to use the one that may have been provided as a parameter.
        If not provided, then will try to use the one already cached in memory.
        If still not found, will look to see if there is a file with the API token stored on disk
        Finally, if there is still no available token, query one from the SEPM server.
 
    .PARAMETER AccessToken
        If provided, this will be returned instead of using the cached/configured value
 
    .OUTPUTS
        System.String
#>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [PSCustomObject] $AccessToken
    )

    # First will try to use the one that may have been provided as a parameter.
    if (-not [String]::IsNullOrEmpty($AccessToken.token)) {
        if (Test-SEPMAccessToken -Token $AccessToken) {
            $script:accessToken = $AccessToken
            return $AccessToken
        }
    }

    # If not provided, then will try to use the one already cached in memory.
    if (-not [String]::IsNullOrEmpty($script:accessToken)) {
        if (Test-SEPMAccessToken -Token $script:accessToken) {
            return $script:accessToken
        }
    }

    # If still not found, will look to see if there is a file with the API token stored in the disk
    if (Test-Path $script:accessTokenFilePath) {
        $AccessToken = Import-Clixml -Path $script:accessTokenFilePath -ErrorAction Ignore
        if (Test-SEPMAccessToken -Token $AccessToken) {
            $script:accessToken = $AccessToken
            return $script:accessToken
        }
    }
        
    # Finally, if there is still no available token, query one from the SEPM server.
    # Then caches the token in memory and stores it in a file on disk as a SecureString
    if ($null -eq $script:configuration.ServerAddress) {
        $message = "SEPM Server name not found. Use Set-SepmConfiguration to update it and try again"
        Write-Warning -Message $message
        throw $message
    }
    
    if ($null -eq $script:Credential) {
        $script:Credential = Get-Credential
    }

    $body = @{
        "username" = $script:Credential.UserName
        "password" = ([System.Net.NetworkCredential]::new("", $script:Credential.Password).Password)
        "appName"  = "PSSymantecSEPM PowerShell Module"
        "domain"   = $script:configuration.domain
    }

    $URI_Authenticate = $script:BaseURLv1 + '/identity/authenticate'
    try {
        Invoke-WebRequest $script:BaseURLv1
    } catch {
        'SSL Certificate test failed, skipping certificate validation. Please check your certificate settings and verify this is a legitimate source.'
        $Response = Read-Host -Prompt 'Please press enter to ignore this and continue without SSL/TLS secure channel'
        if ($Response -eq "") {
            if ($PSVersionTable.PSVersion.Major -lt 6) {
                Skip-Cert
                $script:SkipCert = $true
            }
            if ($PSVersionTable.PSVersion.Major -ge 6) {
                $script:SkipCert = $true
            }
        }
    }

    try {
        $Params = @{
            Method      = 'POST'
            Uri         = $URI_Authenticate
            ContentType = "application/json"
            Body        = ($body | ConvertTo-Json)
        }
        if ($PSVersionTable.PSVersion.Major -lt 6) {
            $Response = Invoke-RestMethod @Params
        }
        if ($PSVersionTable.PSVersion.Major -ge 6) {
            if ($script:SkipCert -eq $true) {
                $Response = Invoke-RestMethod @Params -SkipCertificateCheck
            } else {
                $Response = Invoke-RestMethod @Params
            }
        }
    } catch {
        Get-RestErrorDetails
    }

    # Caches the token in memory and stores token information & expiration in a file on disk
    $CachedToken = [PSCustomObject]@{
        token           = $response.token
        tokenExpiration = (Get-Date).AddSeconds($Response.tokenExpiration)
        SkipCert        = $script:SkipCert
    }
    $script:accessToken = $CachedToken

    if (-not (Test-Path ($Script:accessTokenFilePath | Split-Path))) {
        New-Item -ItemType Directory -Path ($Script:accessTokenFilePath | Split-Path) -Force | Out-Null
    }
    $script:accessToken | Export-Clixml -Path $script:accessTokenFilePath -Force
    return $script:accessToken
}
#EndRegion '.\Public\Get-SepmAccessToken.ps1' 121
#Region '.\Public\Get-SepmConfiguration.ps1' 0
function Get-SepmConfiguration {
    <#
    .SYNOPSIS
        Gets the currently configured value for the requested configuration setting.
 
    .DESCRIPTION
        Gets the currently configured value for the requested configuration setting.
 
        Always returns the value for this session, which may or may not be the persisted
        setting (that all depends on whether or not the setting was previously modified
        during this session using Set-SepmConfiguration -SessionOnly).
 
        The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub
 
    .PARAMETER Name
        The name of the configuration whose value is desired.
 
    .EXAMPLE
        Get-SepmConfiguration -Name WebRequestTimeoutSec
 
        Gets the currently configured value for WebRequestTimeoutSec for this PowerShell session
        (which may or may not be the same as the persisted configuration value, depending on
        whether this value was modified during this session with Set-SepmConfiguration -SessionOnly).
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateSet(
            'ServerAddress',
            'port',
            'username',
            'password',
            'SessionOnly')]
        [string] $Name
    )

    return $script:configuration.$Name
}
#EndRegion '.\Public\Get-SepmConfiguration.ps1' 39
#Region '.\Public\Get-SEPMDatabaseInfo.ps1' 0
function Get-SEPMDatabaseInfo {
    <#
    .SYNOPSIS
        Gets the database infromation of local site.
    .DESCRIPTION
        Gets the database infromation of local site : SQL or embedded database, DBUser, database...
    .INPUTS
        None
    .OUTPUTS
        System.Object
    .EXAMPLE
        Get-SEPMDatabaseInfo
 
        Gets detailed information on the database of the local site
    #>

    
    # initialize the configuration
    $test_token = Test-SEPMAccessToken
    if ($test_token -eq $false) {
        Get-SEPMAccessToken | Out-Null
    }
    $URI = $script:BaseURLv1 + "/admin/database"
    $headers = @{
        "Authorization" = "Bearer " + $script:accessToken.token
        "Content"       = 'application/json'
    }
    $params = @{
        Method  = 'GET'
        Uri     = $URI
        headers = $headers
    }

    # Invoke the request
    # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
    # else we need to use the Skip-Cert function if self-signed certs are being used.
    switch ($PSVersionTable.PSVersion.Major) {
        { $_ -ge 6 } { 
            try {
                if ($script:accessToken.skipCert -eq $true) {
                    $resp = Invoke-RestMethod @params -SkipCertificateCheck
                } else {
                    $resp = Invoke-RestMethod @params
                }
            } catch {
                Write-Warning -Message "Error: $_"
            }
        }
        default {
            try {
                if ($script:accessToken.skipCert -eq $true) {
                    Skip-Cert
                    $resp = Invoke-RestMethod @params
                } else {
                    $resp = Invoke-RestMethod @params
                }
            } catch {
                Write-Warning -Message "Error: $_"
            }
        }
    }

    return $resp

}
#EndRegion '.\Public\Get-SEPMDatabaseInfo.ps1' 65
#Region '.\Public\Get-SEPMDomain.ps1' 0
function Get-SEPMDomain {
    <#
    .SYNOPSIS
        Gets a list of all accessible domains
    .DESCRIPTION
        Gets a list of all accessible domains
    .EXAMPLE
        Get-SEPMDomain
 
        Gets a list of all accessible domains
#>


    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/domains"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method  = 'GET'
            Uri     = $URI
            headers = $headers
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPMDomain.ps1' 78
#Region '.\Public\Get-SEPMEventInfo.ps1' 0
function Get-SEPMEventInfo {
    <#
    .SYNOPSIS
        Gets the information about the computers in a specified domain
    .DESCRIPTION
        Gets the information about the computers in a specified domain. A system administrator account is required for this REST API.
    .EXAMPLE
        Get-SEPMEventInfo
 
        Gets computer details for all computers in the domain
    .EXAMPLE
        Get-SEPMEventInfo -ComputerName "ComputerName"
 
        Gets computer details for the specified computer ComputerName
    .EXAMPLE
        "MyComputer" | Get-SEPMEventInfo
 
        Gets computer details for the specified computer MyComputer
#>


    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/events/critical"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        $allResults = @()

        if (-not $ComputerName) {
            $ComputerName = ""
        }

        # URI query strings
        $QueryStrings = @{
            pageIndex = 1
            pageSize  = 100
        }

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.

        ############################################################################################################
        # As per documentation https://apidocs.securitycloud.symantec.com/#/doc?id=sepm_events #
        # Pagination is not yet implemented for this API. The response will contain all the events in the system. #
        # Commenting pagination code for now. #
        ############################################################################################################


        # do {
        # try {
        # # Invoke the request params
        # $params = @{
        # Method = 'GET'
        # Uri = $URI
        # headers = $headers
        # }
        # if ($script:accessToken.skipCert -eq $true) {
        # if ($PSVersionTable.PSVersion.Major -lt 6) {
        # Skip-Cert
        # $resp = Invoke-RestMethod @params
        # } else {
        # $resp = Invoke-RestMethod @params -SkipCertificateCheck
        # }
        # } else {
        # $resp = Invoke-RestMethod @params
        # }
                
        # # Process the response
        # $allResults += $resp.content

        # # Increment the page index & update URI
        # $QueryStrings.pageIndex++
        # $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        # foreach ($param in $QueryStrings.GetEnumerator()) {
        # $query[$param.Key] = $param.Value
        # }
        # $builder.Query = $query.ToString()
        # $URI = $builder.ToString()
        # } catch {
        # Write-Warning -Message "Error: $_"
        # }
        # } until ($resp.lastPage -eq $true)

        ###################################
        # Code without pagination for now #
        ###################################
        try {
            # Invoke the request params
            $params = @{
                Method  = 'GET'
                Uri     = $URI
                headers = $headers
            }
            if ($script:accessToken.skipCert -eq $true) {
                if ($PSVersionTable.PSVersion.Major -lt 6) {
                    Skip-Cert
                    $resp = Invoke-RestMethod @params
                } else {
                    $resp = Invoke-RestMethod @params -SkipCertificateCheck
                }
            } else {
                $resp = Invoke-RestMethod @params
            } 
            
            # Process the response
            $allResults += $resp
        } catch {
            Write-Warning -Message "Error: $_"
        }

        # return the response
        return $allResults
    }
}
#EndRegion '.\Public\Get-SEPMEventInfo.ps1' 133
#Region '.\Public\Get-SEPMExceptionPolicy.ps1' 0
function Get-SEPMExceptionPolicy {
    <#
    .SYNOPSIS
        Get Firewall Policy
    .DESCRIPTION
        Get Firewall Policy details
    .EXAMPLE
        PS C:\PSSymantecSEPM> Get-SEPMExceptionPolicy -PolicyName "Standard Servers - Firewall policy"
 
        sources :
        configuration : @{enforced_rules=System.Object[]; baseline_rules=System.Object[]; ignore_parent_rules=; smart_dhcp=False; smart_dns=False; smart_wins=False; token_ring_traffic=False; netbios_protection=False; reverse_dns=False; port_scan=False;
                        dos=False; antimac_spoofing=False; autoblock=False; autoblock_duration=600; stealth_web=False; antiIP_spoofing=False; hide_os=False; windows_firewall=NO_ACTION; windows_firewall_notification=False; endpoint_notification=; p2p_auth=;
                        mac=}
        enabled : True
        desc : Standard Server Firewall Policy - This policy is for standard servers. It is a strict policy that blocks all traffic except for the services that are explicitly allowed.
        name : Standard Servers - Firewall policy
        lastmodifiedtime : 1692253688318
 
        Shows an example of getting the firewall policy details for the policy named "Standard Servers - Firewall policy"
#>


    [CmdletBinding()]
    Param (
        # PolicyName
        [Parameter(
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Mandatory = $true
        )]
        [Alias("Policy_Name")]
        [String]
        $PolicyName
    )

    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        # BaseURL V2
        $URI = $script:BaseURLv2 + "/policies/exceptions"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
        # Stores the policy summary for all policies only once
        $policies = Get-SEPMPoliciesSummary
    }

    process {
        # Get Policy ID from policy name
        $policyID = $policies | Where-Object { $_.name -eq $PolicyName } | Select-Object -ExpandProperty id
        $policy_type = $policies | Where-Object { $_.name -eq $PolicyName } | Select-Object -ExpandProperty policytype

        if ($policy_type -ne "exceptions") {
            $message = "policy type is not of type EXCEPTIONS or does not exist - Please verify the policy name"
            Write-Error -Message $message
            throw $message
        }

        # Updating URI with policy ID
        $URI = $URI + "/" + $policyID
        
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method          = 'GET'
            Uri             = $URI
            headers         = $headers
            UseBasicParsing = $true
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # JSON response to convert to PSObject
        $resp = $resp | ConvertFrom-Json -AsHashtable -Depth 100
        
        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPMExceptionPolicy.ps1' 120
#Region '.\Public\Get-SEPMFirewallPolicy.ps1' 0
function Get-SEPMFirewallPolicy {
    <#
    .SYNOPSIS
        Get Firewall Policy
    .DESCRIPTION
        Get Firewall Policy details
    .EXAMPLE
        PS C:\PSSymantecSEPM> Get-SEPMFirewallPolicy -PolicyName "Standard Servers - Firewall policy"
 
        sources :
        configuration : @{enforced_rules=System.Object[]; baseline_rules=System.Object[]; ignore_parent_rules=; smart_dhcp=False; smart_dns=False; smart_wins=False; token_ring_traffic=False; netbios_protection=False; reverse_dns=False; port_scan=False;
                        dos=False; antimac_spoofing=False; autoblock=False; autoblock_duration=600; stealth_web=False; antiIP_spoofing=False; hide_os=False; windows_firewall=NO_ACTION; windows_firewall_notification=False; endpoint_notification=; p2p_auth=;
                        mac=}
        enabled : True
        desc : Standard Server Firewall Policy - This policy is for standard servers. It is a strict policy that blocks all traffic except for the services that are explicitly allowed.
        name : Standard Servers - Firewall policy
        lastmodifiedtime : 1692253688318
 
        Shows an example of getting the firewall policy details for the policy named "Standard Servers - Firewall policy"
#>


    [CmdletBinding()]
    Param (
        # PolicyName
        [Parameter(
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Mandatory = $true
        )]
        [Alias("Policy_Name")]
        [String]
        $PolicyName
    )

    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/policies/firewall"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
        # Stores the policy summary for all policies only once
        $policies = Get-SEPMPoliciesSummary
    }

    process {
        # Get Policy ID from policy name
        $policyID = $policies | Where-Object { $_.name -eq $PolicyName } | Select-Object -ExpandProperty id
        $policy_type = $policies | Where-Object { $_.name -eq $PolicyName } | Select-Object -ExpandProperty policytype

        if ($policy_type -ne "fw") {
            $message = "policy type is not of type FIREWALL or does not exist - Please verify the policy name"
            Write-Error -Message $message
            throw $message
        }

        # Updating URI with policy ID
        $URI = $URI + "/" + $policyID
        
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method  = 'GET'
            Uri     = $URI
            headers = $headers
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPMFirewallPolicy.ps1' 115
#Region '.\Public\Get-SEPMGroups.ps1' 0
function Get-SEPMGroups {
    <#
    .SYNOPSIS
        Gets threat statistics
    .DESCRIPTION
        Gets threat statistics
    .EXAMPLE
        Get-SEPMGroups
 
        Gets threat statistics
#>


    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/groups"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method  = 'GET'
            Uri     = $URI
            headers = $headers
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        do {
            try {
                # Invoke the request params
                $params = @{
                    Method  = 'GET'
                    Uri     = $URI
                    headers = $headers
                }
                if ($script:accessToken.skipCert -eq $true) {
                    if ($PSVersionTable.PSVersion.Major -lt 6) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    }
                } else {
                    $resp = Invoke-RestMethod @params
                } 
                
                # Process the response
                $allResults += $resp.content

                # Increment the page index & update URI
                $QueryStrings.pageIndex++
                $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
                foreach ($param in $QueryStrings.GetEnumerator()) {
                    $query[$param.Key] = $param.Value
                }
                $builder.Query = $query.ToString()
                $URI = $builder.ToString()
            } catch {
                Write-Warning -Message "Error: $_"
            }
        } until ($resp.lastPage -eq $true)

        # return the response
        return $allResults
    }
}
#EndRegion '.\Public\Get-SEPMGroups.ps1' 87
#Region '.\Public\Get-SEPMIpsPolicy.ps1' 0
function Get-SEPMIpsPolicy {
    # TODO : returned object has empty configuration fields. Could be a bug ?
    # Example
    # PS C:\PSSymantecSEPM> $IPS_example | ConvertTo-Json
    # {
    # "sources": null,
    # "configuration": {},
    # "enabled": true,
    # "desc": "Summary : added IP as excluded host to avoid ServiceNow discovery service conflicts",
    # "name": "Intrusion Prevention policy PRODUCTION",
    # "lastmodifiedtime": 1693559858824
    # }

    <# TODO update help
    .SYNOPSIS
        Get Firewall Policy
    .DESCRIPTION
        Get Firewall Policy details
    .EXAMPLE
        PS C:\PSSymantecSEPM> Get-SEPMIpsPolicy -PolicyName "Standard Servers - Firewall policy"
 
        sources :
        configuration : @{enforced_rules=System.Object[]; baseline_rules=System.Object[]; ignore_parent_rules=; smart_dhcp=False; smart_dns=False; smart_wins=False; token_ring_traffic=False; netbios_protection=False; reverse_dns=False; port_scan=False;
                        dos=False; antimac_spoofing=False; autoblock=False; autoblock_duration=600; stealth_web=False; antiIP_spoofing=False; hide_os=False; windows_firewall=NO_ACTION; windows_firewall_notification=False; endpoint_notification=; p2p_auth=;
                        mac=}
        enabled : True
        desc : Standard Server Firewall Policy - This policy is for standard servers. It is a strict policy that blocks all traffic except for the services that are explicitly allowed.
        name : Standard Servers - Firewall policy
        lastmodifiedtime : 1692253688318
 
        Shows an example of getting the firewall policy details for the policy named "Standard Servers - Firewall policy"
#>


    [CmdletBinding()]
    Param (
        # PolicyName
        [Parameter(
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Mandatory = $true
        )]
        [Alias("Policy_Name")]
        [String]
        $PolicyName
    )

    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/policies/ips"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
        # Stores the policy summary for all policies only once
        $policies = Get-SEPMPoliciesSummary
    }

    process {
        # Get Policy ID from policy name
        $policyID = $policies | Where-Object { $_.name -eq $PolicyName } | Select-Object -ExpandProperty id
        $policy_type = $policies | Where-Object { $_.name -eq $PolicyName } | Select-Object -ExpandProperty policytype

        if ($policy_type -ne "ips") {
            $message = "policy type is not of type IPS or does not exist - Please verify the policy name"
            Write-Error -Message $message
            throw $message
        }

        # Updating URI with policy ID
        $URI = $URI + "/" + $policyID
        
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method          = 'GET'
            Uri             = $URI
            headers         = $headers
            UseBasicParsing = $true
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPMIpsPolicy.ps1' 128
#Region '.\Public\Get-SEPMLatestDefinition.ps1' 0
function Get-SEPMLatestDefinition {
    <#
    .SYNOPSIS
        Get AV Def Latest Info
    .DESCRIPTION
        Gets the latest revision information for antivirus definitions from Symantec Security Response.
    .EXAMPLE
        Get-SEPMLatestDefinition
 
        Gets the latest revision information for antivirus definitions from Symantec Security Response.
#>


    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/content/avdef/latest"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
    }

    process {
        # URI query strings
        $QueryStrings = @{}

        # Construct the URI
        $builder = New-Object System.UriBuilder($URI)
        $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
        foreach ($param in $QueryStrings.GetEnumerator()) {
            $query[$param.Key] = $param.Value
        }
        $builder.Query = $query.ToString()
        $URI = $builder.ToString()

        $params = @{
            Method  = 'GET'
            Uri     = $URI
            headers = $headers
        }
    
        # Invoke the request
        # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
        # else we need to use the Skip-Cert function if self-signed certs are being used.
        switch ($PSVersionTable.PSVersion.Major) {
            { $_ -ge 6 } { 
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        $resp = Invoke-RestMethod @params -SkipCertificateCheck
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
            default {
                try {
                    if ($script:accessToken.skipCert -eq $true) {
                        Skip-Cert
                        $resp = Invoke-RestMethod @params
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            }
        }

        # return the response
        return $resp
    }
}
#EndRegion '.\Public\Get-SEPMLatestDefinition.ps1' 78
#Region '.\Public\Get-SEPMPoliciesSummary.ps1' 0
function Get-SEPMPoliciesSummary {
    <#
    .SYNOPSIS
        Get summary of all or feature specific policies
    .DESCRIPTION
        Get the policy summary for specified policy type.
        Also gets the list of groups to which the policies are assigned.
    .PARAMETER PolicyType
        The policy type for which the summary is to be retrieved.
        The valid values are hid, exceptions, mem, ntr, av, fw, ips, lucontent, lu, hi, adc, msl, upgrade.
 
    .EXAMPLE
        PS C:\PSSymantecSEPM> Get-SEPMPoliciesSummary
 
        content : {@{sources=System.Object[]; enabled=True; desc=Created automatically during product ...}}
        size : 136
        number : 0
        sort :
        numberOfElements : 136
        totalElements : 136
        totalPages : 1
        lastPage : True
        firstPage : True
 
        Get policy statistics for all policies and its assigned groups
    .EXAMPLE
        PS C:\PSSymantecSEPM> Get-SEPMPoliciesSummary -PolicyType fw
 
        Get policy statistics for firewall policies and its assigned groups
#>


    [CmdletBinding()]
    param (
        [Parameter()]
        [ValidateSet(
            'hid', 
            'exceptions', 
            'mem', 
            'ntr', 
            'av', 
            'fw', 
            'ips', 
            'lucontent', 
            'lu', 
            'hi', 
            'adc', 
            'msl', 
            'upgrade'
        )]
        [string]
        $PolicyType
    )

    begin {
        # initialize the configuration
        $test_token = Test-SEPMAccessToken
        if ($test_token -eq $false) {
            Get-SEPMAccessToken | Out-Null
        }
        $URI = $script:BaseURLv1 + "/policies/summary"
        $headers = @{
            "Authorization" = "Bearer " + $script:accessToken.token
            "Content"       = 'application/json'
        }
        # Get the list of groups and IDs to inject into the response
        $groups = Get-SEPMGroups
    }

    process {
        if (-not $PolicyType) {
            $allResults = @()
        
            # URI query strings
            $QueryStrings = @{}

            # Construct the URI
            $builder = New-Object System.UriBuilder($URI)
            $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
            foreach ($param in $QueryStrings.GetEnumerator()) {
                $query[$param.Key] = $param.Value
            }
            $builder.Query = $query.ToString()
            $URI = $builder.ToString()

            $params = @{
                Method  = 'GET'
                Uri     = $URI
                headers = $headers
            }
    
            # Invoke the request
            # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
            # else we need to use the Skip-Cert function if self-signed certs are being used.
            do {
                try {
                    # Invoke the request params
                    $params = @{
                        Method  = 'GET'
                        Uri     = $URI
                        headers = $headers
                    }
                    if ($script:accessToken.skipCert -eq $true) {
                        if ($PSVersionTable.PSVersion.Major -lt 6) {
                            Skip-Cert
                            $resp = Invoke-RestMethod @params
                        } else {
                            $resp = Invoke-RestMethod @params -SkipCertificateCheck
                        }
                    } else {
                        $resp = Invoke-RestMethod @params
                    }
                    
                    # Add group FullPath to the response from their Group ID for ease of use
                    # Parsing every response object
                    foreach ($policy in $resp.content) {
                        # Parsing every location this policy is applied to
                        foreach ($location in $policy.assignedtolocations) {
                            # Getting the group name from the group ID, and adding it to the response object
                            $group = $groups | Where-Object { $_.id -match $location.groupid }  | Get-Unique
                            $location | Add-Member -NotePropertyName "groupNameFullPath" -NotePropertyValue $group.fullPathName
                        }
                    }
                
                    # Process the response
                    $allResults += $resp.content

                    # Increment the page index & update URI
                    $QueryStrings.pageIndex++
                    $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
                    foreach ($param in $QueryStrings.GetEnumerator()) {
                        $query[$param.Key] = $param.Value
                    }
                    $builder.Query = $query.ToString()
                    $URI = $builder.ToString()
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            } until ($resp.lastPage -eq $true)

            # return the response
            return $allResults
        }
        if ($PolicyType) {
            $URI = $script:BaseURLv1 + "/policies/summary" + "/" + $PolicyType
            $allResults = @()
        
            # URI query strings
            $QueryStrings = @{}

            # Construct the URI
            $builder = New-Object System.UriBuilder($URI)
            $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
            foreach ($param in $QueryStrings.GetEnumerator()) {
                $query[$param.Key] = $param.Value
            }
            $builder.Query = $query.ToString()
            $URI = $builder.ToString()

            $params = @{
                Method  = 'GET'
                Uri     = $URI
                headers = $headers
            }


    
            # Invoke the request
            # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
            # else we need to use the Skip-Cert function if self-signed certs are being used.
            do {
                try {
                    # Invoke the request params
                    $params = @{
                        Method  = 'GET'
                        Uri     = $URI
                        headers = $headers
                    }
                    if ($script:accessToken.skipCert -eq $true) {
                        if ($PSVersionTable.PSVersion.Major -lt 6) {
                            Skip-Cert
                            $resp = Invoke-RestMethod @params
                        } else {
                            $resp = Invoke-RestMethod @params -SkipCertificateCheck
                        }
                    } else {
                        $resp = Invoke-RestMethod @params
                    } 

                    # Add group FullPath to the response from their Group ID for ease of use
                    # Parsing every response object
                    foreach ($policy in $resp.content) {
                        # Parsing every location this policy is applied to
                        foreach ($location in $policy.assignedtolocations) {
                            # Getting the group name from the group ID, and adding it to the response object
                            $group = $groups | Where-Object { $_.id -match $location.groupid }  | Get-Unique
                            $location | Add-Member -NotePropertyName "groupNameFullPath" -NotePropertyValue $group.fullPathName
                        }
                    }
                
                    # Process the response
                    $allResults += $resp.content

                    # Increment the page index & update URI
                    $QueryStrings.pageIndex++
                    $query = [System.Web.HttpUtility]::ParseQueryString($builder.Query)
                    foreach ($param in $QueryStrings.GetEnumerator()) {
                        $query[$param.Key] = $param.Value
                    }
                    $builder.Query = $query.ToString()
                    $URI = $builder.ToString()
                } catch {
                    Write-Warning -Message "Error: $_"
                }
            } until ($resp.lastPage -eq $true)

            # return the response
            return $allResults
        }
    }
}
#EndRegion '.\Public\Get-SEPMPoliciesSummary.ps1' 221
#Region '.\Public\Get-SEPMVersion.ps1' 0
Function Get-SEPMVersion {
    <# TODO update help
    .SYNOPSIS
        Gets the current version of Symantec Endpoint Protection Manager.
    .DESCRIPTION
        Gets the current version of Symantec Endpoint Protection Manager. This function dot not require authentication.
    .EXAMPLE
        Get-SEPMVersion
 
        Gets the current version of Symantec Endpoint Protection Manager.
    #>

    

    # initialize the configuration
    $test_token = Test-SEPMAccessToken
    if ($test_token -eq $false) {
        Get-SEPMAccessToken | Out-Null
    }
    $URI = $script:BaseURLv1 + "/version"
    $headers = @{
        "Authorization" = "Bearer " + $script:accessToken.token
        "Content"       = 'application/json'
    }
    $body = @{
    }
    $params = @{
        Method  = 'GET'
        Uri     = $URI
        headers = $headers
        Body    = ($body | ConvertTo-Json)
    }

    # Invoke the request
    # If the version of PowerShell is 6 or greater, then we can use the -SkipCertificateCheck parameter
    # else we need to use the Skip-Cert function if self-signed certs are being used.
    switch ($PSVersionTable.PSVersion.Major) {
        { $_ -ge 6 } { 
            try {
                if ($script:accessToken.skipCert -eq $true) {
                    $resp = Invoke-RestMethod @params -SkipCertificateCheck
                } else {
                    $resp = Invoke-RestMethod @params
                }
            } catch {
                Write-Warning -Message "Error: $_"
            }
                
        }
        default {
            try {
                if ($script:accessToken.skipCert -eq $true) {
                    Skip-Cert
                    $resp = Invoke-RestMethod @params
                } else {
                    $resp = Invoke-RestMethod @params
                }
            } catch {
                Write-Warning -Message "Error: $_"
            }
        }
    }

    return $resp
}
#EndRegion '.\Public\Get-SEPMVersion.ps1' 65
#Region '.\Public\Reset-SepmConfiguration.ps1' 0
function Reset-SepmConfiguration {
    <#
    .SYNOPSIS
        Clears out the user's configuration file and configures this session with all default
        configuration values.
 
    .DESCRIPTION
        Clears out the user's configuration file and configures this session with all default
        configuration values.
 
        This would be the functional equivalent of using this on a completely different computer.
 
        The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub
 
    .PARAMETER SessionOnly
        By default, this will delete the location configuration file so that all defaults are used
        again. If this is specified, then only the configuration values that were made during
        this session will be discarded.
 
    .EXAMPLE
        Reset-SepmConfiguration
 
        Deletes the local configuration file and loads in all default configuration values.
 
    .NOTES
        This command will not clear your authentication token.
        Please use Clear-SepmAuthentication to accomplish that.
#>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [switch] $SessionOnly
    )

    if (-not $PSCmdlet.ShouldProcess('Sepm Configuration', 'Reset')) {
        return
    }

    if (-not $SessionOnly) {
        $null = Remove-Item -Path $script:configurationFilePath -Force -ErrorAction SilentlyContinue -ErrorVariable ev

        if (($null -ne $ev) -and ($ev.Count -gt 0) -and ($ev[0].FullyQualifiedErrorId -notlike 'PathNotFound*')) {
            $message = "Reset was unsuccessful. Experienced a problem trying to remove the file [$script:configurationFilePath]."
            Write-Warning -Message $message
        }
    }

    Initialize-SepmConfiguration

    $message = "This has not cleared your authentication token. Call Clear-SepmAuthentication to accomplish that."
    Write-Verbose -Message $message
}
#EndRegion '.\Public\Reset-SepmConfiguration.ps1' 52
#Region '.\Public\Set-SepmAuthentication.ps1' 0
function Set-SepmAuthentication {
    <#
    .SYNOPSIS
        Allows the user to configure the API token that should be used for authentication
        with the GitHub API.
 
    .DESCRIPTION
        Allows the user to configure the API token that should be used for authentication
        with the GitHub API.
 
        The token will be stored on the machine as a SecureString and will automatically
        be read on future PowerShell sessions with this module. If the user ever wishes
        to remove their authentication from the system, they simply need to call
        Clear-SepmAuthentication.
 
        The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub
 
    .PARAMETER Credential
        If provided, instead of prompting the user for their API Token, it will be extracted
        from the password field of this credential object.
 
    .PARAMETER SessionOnly
        By default, this method will store the provided API Token as a SecureString in a local
        file so that it can be restored automatically in future PowerShell sessions. If this
        switch is provided, the file will not be created/updated and the authentication information
        will only remain in memory for the duration of this PowerShell session.
 
    .EXAMPLE
        Set-SepmAuthentication
 
        Prompts the user for their GitHub API Token and stores it in a file on the machine as a
        SecureString for use in future PowerShell sessions.
 
    .EXAMPLE
        $secureString = ("<Your Access Token>" | ConvertTo-SecureString -AsPlainText -Force)
        $cred = New-Object System.Management.Automation.PSCredential "username is ignored", $secureString
        Set-SepmAuthentication -Credential $cred
        $secureString = $null # clear this out now that it's no longer needed
        $cred = $null # clear this out now that it's no longer needed
 
        Allows you to specify your access token as a plain-text string ("<Your Access Token>")
        which will be securely stored on the machine for use in all future PowerShell sessions.
 
    .EXAMPLE
        Get-Credential | Set-SepmAuthentication
 
        Prompts the user for username and password and pipes the resulting credential object
 
    .EXAMPLE
        Set-SepmAuthentication -Credential $cred -SessionOnly
 
        Uses the API token stored in the password field of the provided credential object for
        authentication, but keeps it in memory only for the duration of this PowerShell session..
 
        .EXAMPLE
        Set-SepmAuthentication -Port 8888
 
        Changes the API communication port to 8888. Default is 8446.
#>

    [CmdletBinding(SupportsShouldProcess)]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUsePSCredentialType", "", Justification = "The System.Management.Automation.Credential() attribute does not appear to work in PowerShell v4 which we need to support.")]
    param(
        [string] $ServerAddress,

        [int] $Port = 8446,
        
        [PSCredential] $Creds,

        [switch] $SessionOnly
    )

    if (-not $PSCmdlet.ShouldProcess('Sepm Authentication', 'Set')) {
        return
    }

    if (-not $PSBoundParameters.ContainsKey('Creds')) {
        $message = 'Please provide your Username and Password.'
        if (-not $SessionOnly) {
            $message = $message + ' ***The token is being cached across PowerShell sessions. To clear caching, call Clear-SepmAuthentication.***'
        }

        $Creds = Get-Credential -Message $message
    }

    if ([String]::IsNullOrWhiteSpace($Creds.GetNetworkCredential().Password)) {
        $message = "Password not provided. Nothing to do."
        Write-Error -Message $message
        throw $message
    }

    # Setting script scope variables so that they can be used in other functions
    $script:Credential = $Creds

    if (-not $PSBoundParameters.ContainsKey('ServerAddress')) {
        $message = 'Please provide your ServerAddress.'
        if (-not $SessionOnly) {
            $message = $message + ' ***The token is being cached across PowerShell sessions. To clear caching, call Clear-SepmAuthentication.***'
        }

        $ServerAddress = Read-Host -Prompt "SEPM Server address"
    }

    # verify if the the $port is not the default one
    if ($Port -ne 8446) {
        $message = 'Please provide SEPM API Service port (Default 8446).'
        if (-not $SessionOnly) {
            $message = $message + ' ***The token is being cached across PowerShell sessions. To clear caching, call Clear-SepmAuthentication.***'
        }
        $Port = Read-Host -Prompt "SEPM API Service port"
    }



    if (-not $SessionOnly) {
        Set-SepmConfiguration -ServerAddress $ServerAddress
        Set-SepmConfiguration -Port $Port
        $Creds | Export-Clixml -Path $script:credentialsFilePath -Force
    }
}
#EndRegion '.\Public\Set-SepmAuthentication.ps1' 120
#Region '.\Public\Set-SepmConfiguration.ps1' 0
function Set-SepmConfiguration {
    <# TODO update help
    .SYNOPSIS
        Change the value of a configuration property for the PowerShellForGitHub module,
        for the session only, or globally for this user.
 
    .DESCRIPTION
        Change the value of a configuration property for the PowerShellForGitHub module,
        for the session only, or globally for this user.
 
        A single call to this method can set any number or combination of properties.
 
        To change any of the boolean/switch properties to false, specify the switch,
        immediately followed by ":$false" with no space.
 
        The Git repo for this module can be found here: http://aka.ms/PowerShellForGitHub
 
    .PARAMETER ServerAddress
        The hostname of the SEPM instance to communicate with.
 
    .PARAMETER SessionOnly
        By default, this method will store the configuration values in a local file so that changes
        persist across PowerShell sessions. If this switch is provided, the file will not be
        created/updated and the specified configuration changes will only remain in memory/effect
        for the duration of this PowerShell session.
 
    .EXAMPLE
        Set-SepmConfiguration -WebRequestTimeoutSec 120 -SuppressNoTokenWarning
 
        Changes the timeout permitted for a web request to two minutes, and additionally tells
        the module to never warn about no Access Token being configured. These settings will be
        persisted across future PowerShell sessions.
 
    .EXAMPLE
        Set-SepmConfiguration ServerAddress "MySEPMServer"
 
        Set the SEPM server address to "MySEPMServer" for the duration of this PowerShell session.
 
#>

    [CmdletBinding(
        PositionalBinding = $false,
        SupportsShouldProcess)]
    param(
        [string] $ServerAddress,

        [int] $Port,

        [string] $Username,

        [switch] $SessionOnly
    )

    $persistedConfig = $null
    if (-not $SessionOnly) {
        $persistedConfig = Read-SepmConfiguration -Path $script:configurationFilePath
    }

    if (-not $PSCmdlet.ShouldProcess('SepmConfiguration', 'Set')) {
        return
    }

    $properties = Get-Member -InputObject $script:configuration -MemberType NoteProperty | Select-Object -ExpandProperty Name
    foreach ($name in $properties) {
        if ($PSBoundParameters.ContainsKey($name)) {
            $value = $PSBoundParameters.$name
            if ($value -is [switch]) { $value = $value.ToBool() }
            $script:configuration.$name = $value

            if (-not $SessionOnly) {
                Add-Member -InputObject $persistedConfig -Name $name -Value $value -MemberType NoteProperty -Force
            }
        }
    }

    if (-not $SessionOnly) {
        Save-SepmConfiguration -Configuration $persistedConfig -Path $script:configurationFilePath
    }
}
#EndRegion '.\Public\Set-SepmConfiguration.ps1' 79
#Region '.\Public\zz_Initialize-SepmConfiguration.ps1' 0
####################################
# Init script for the whole module #
####################################

## This is the initialization script for the module. It is invoked at the end of the module's
## prefix file as "zz_" to load this module at last. This is done to ensure that all other functions are first loaded
## This function should be private but will stay Public for the moment as it needs to be the last function to be loaded in the module
## TODO make this function private

# The credentials used to authenticate to the SEPM server.
[PSCredential]   $script:Credential = $null
[PSCustomObject] $script:accessToken = $null

# SEPM Server configuration
[string] $script:ServerAddress = $null
[string] $script:BaseURLv1 = $null
[bool] $script:SkipCert = $false # Needed for self-signed certificates

# The location of the file that we'll store any settings that can/should roam with the user.
[string] $script:configurationFilePath = [System.IO.Path]::Combine(
    [System.Environment]::GetFolderPath('ApplicationData'),
    'PSSymantecSEPM',
    'config.json')

# The location of the file that we'll store credentials
[string] $script:credentialsFilePath = [System.IO.Path]::Combine(
    [System.Environment]::GetFolderPath('ApplicationData'),
    'PSSymantecSEPM',
    'creds.xml')

# The location of the file that we'll store the Access Token SecureString
# which cannot/should not roam with the user.
[string] $script:accessTokenFilePath = [System.IO.Path]::Combine(
    [System.Environment]::GetFolderPath('LocalApplicationData'),
    'PSSymantecSEPM',
    'accessToken.xml')

# The session-cached copy of the module's configuration properties
[PSCustomObject] $script:configuration = $null

function Initialize-SepmConfiguration {
    <#
    .SYNOPSIS
        Populates the configuration of the module for this session, loading in any values
        that may have been saved to disk.
 
    .DESCRIPTION
        Populates the configuration of the module for this session, loading in any values
        that may have been saved to disk.
 
    .NOTES
        Internal helper method. This is actually invoked at the END of this file.
#>

    [CmdletBinding()]
    param()

    $script:configuration = Import-SepmConfiguration -Path $script:configurationFilePath
    if ($script:configuration) {
        if ([string]::IsNullOrEmpty($script:configuration.ServerAddress)) {
            Set-SepmAuthentication
        }
        $script:BaseURLv1 = "https://" + $script:configuration.ServerAddress + ":" + $script:configuration.port + "/sepm/api/v1"
        $script:BaseURLv2 = "https://" + $script:configuration.ServerAddress + ":" + $script:configuration.port + "/sepm/api/v2"
    }
    if (Test-Path $script:credentialsFilePath) {
        $script:Credential = Import-Clixml -Path $script:credentialsFilePath -ErrorAction SilentlyContinue
    }
    if (Test-Path $script:accessTokenFilePath) {
        $script:accessToken = Import-Clixml -Path $script:accessTokenFilePath -ErrorAction SilentlyContinue
    }
    
}

# Invoke the initialization method to populate the configuration
Initialize-SepmConfiguration
#EndRegion '.\Public\zz_Initialize-SepmConfiguration.ps1' 76