IntegrisDeploymentTool.ps1

### Support Functions
FUNCTION Get-AutomateAgentConfig {
   
    [CmdletBinding()]
    PARAM ( )
 
    $Results = New-Object PSObject -WarningAction SilentlyContinue -Property @{
        ServerAddress = (Get-ItemProperty -Path "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue)."Server Address"
        ServerPassword = (Get-ItemProperty -Path "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue).ServerPassword        
        ClientID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue).ClientID
        LocationID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue).LocationID
        DeviceID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue).ID        
        ProductCode = (Get-ItemProperty -Path "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue).ProductCode
        BasePath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue).BasePath
        Version = (Get-ItemProperty -Path "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue).Version
        LastCheckIn = (Get-ItemProperty -Path "HKLM:\SOFTWARE\LabTech\Service" -ErrorAction SilentlyContinue).LastSuccessStatus
      }

    RETURN $Results | Select ServerAddress, ServerPassword, DeviceID, ClientID, LocationID, ProductCode, BasePath, Version, LastCheckIn
}
FUNCTION GET-DomainInfo {

    ### Declare Variables
    ### =================
    $Results = @()
    $DomainFQDN = $Null
    $DomainResolves = $False
    $DomainType = $Null
    $DomainServicesRegistration = dsregcmd /status
    $ResolvedIPs = @()
    $DomainControllers = @()
    $DomainJoinHealth = $Null

    ### Begin Script
    ### ============
    IF ($DomainServicesRegistration -like "*DomainJoined : YES*") { $DomainType = "AD" }
    ELSEIF ($DomainServicesRegistration -like "*AzureAdJoined : YES*" -and $DomainServicesRegistration -like "*DomainJoined : NO*") { $DomainType = "AAD" }
    ELSEIF ($DomainServicesRegistration -like "*AzureAdJoined : NO*" -and $DomainServicesRegistration -like "*DomainJoined : NO*") { $DomainType = "Workgroup" }
    ELSE { RETURN $False }

    IF ($DomainType -eq "AD") {
        $DomainFQDN = (GET-CIMInstance Win32_ComputerSystem -Verbose:$false).Domain

        $Records = Resolve-DnsName $DomainFQDN -ErrorAction SilentlyContinue

        FOREACH ($Record in $Records) { IF ((IsPrivateIP $Record.IPAddress) -or $Record.Name -like "*.local*" ) { $DomainResolves = $True; $ResolvedIPs += $Record.IPAddress } }

        FOREACH ($IP in $ResolvedIPs) { TRY { $DomainControllers += (((Resolve-DNSName $IP).NameHost).Replace(".$($DomainFQDN)","").ToUpper()) } CATCH { "[Name Not Available]" } }

        IF ($ResolvedIPs.Count -ge 1) {
            TRY {
                IF (IsDomainController) { $DomainJoinHealth = "Domain Controller" }
                ELSEIF (Test-ComputerSecureChannel) { $DomainJoinHealth = "Healthy" } 
                ELSE { $DomainJoinHealth = "Unhealthy" }
            } CATCH {
                $DomainJoinHealth = "Unhealthy"
            }
        }
        ELSE { $DomainJoinHealth = "Domain Unavailable" }
                        
        $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Hostname = $env:COMPUTERNAME
            DomainType = $DomainType
            FQDN = $DomainFQDN
            TenantName = $Null
            TenantID = $Null
            ActiveDomainConnection = $DomainResolves
            ResolvedDomainControllerIP = $ResolvedIPs
            ResolvedDomainControllerName = $DomainControllers
            DomainJoinHealth = $DomainJoinHealth
        }

        RETURN $Results | Select Hostname, DomainType, FQDN, ActiveDomainConnection, ResolvedDomainControllerIP, ResolvedDomainControllerName, DomainJoinHealth
    }
    ELSEIF ($DomainType -eq "AAD") { 

        IF ((($DomainServicesRegistration | Select-String -Pattern "DeviceAuthStatus :").ToString().Replace("DeviceAuthStatus :","").Replace(" ","")) -eq "SUCCESS") { $DomainJoinHealth = "Healthy" } ELSE { $DomainJoinHealth = "Unhealthy" }

        $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Hostname = $env:COMPUTERNAME
            DomainType = $DomainType
            FQDN = "Login.Windows.Net"
            TenantName = ($DomainServicesRegistration | Select-String -Pattern " TenantName :").ToString().Replace("TenantName :","").Replace(" ","")
            TenantID = ($DomainServicesRegistration | Select-String -Pattern " TenantId :").ToString().Replace("TenantId :","").Replace(" ","")
            ActiveDomainConnection = $Null
            ResolvedDomainControllerIP = $Null
            ResolvedDomainControllerName = $Null
            DomainJoinHealth = $DomainJoinHealth
        }

        RETURN $Results | Select Hostname, DomainType, FQDN, TenantName, TenantID, DomainJoinHealth
    }
    ELSEIF ($DomainType -eq "Workgroup") { 
        $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Hostname = $env:COMPUTERNAME
            DomainType = $DomainType
            FQDN = $Null
            TenantName = $Null
            TenantID = $Null
            ActiveDomainConnection = $Null
            ResolvedDomainControllerIP = $Null
            ResolvedDomainControllerName = $Null
            DomainJoinHealth = $Null
        }

        RETURN $Results | Select Hostname, DomainType
    }
    ELSE {
        $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Hostname = $env:COMPUTERNAME
            DomainType = "Error"
            FQDN = $Null
            TenantName = $Null
            TenantID = $Null
            ActiveDomainConnection = $Null
            ResolvedDomainControllerIP = $Null
            ResolvedDomainControllerName = $Null
            DomainJoinHealth = $Null
        }

        RETURN $Results | Select Hostname, DomainType
    }
}
FUNCTION Test-IsLaptop {
    IF ((GET-CIMInstance Win32_SystemEnclosure -Verbose:$false).ChassisTypes -eq 8 -or
        (GET-CIMInstance Win32_SystemEnclosure -Verbose:$false).ChassisTypes -eq 9 -or
        (GET-CIMInstance Win32_SystemEnclosure -Verbose:$false).ChassisTypes -eq 10 -or
        (GET-CIMInstance Win32_SystemEnclosure -Verbose:$false).ChassisTypes -eq 14 -or
        (GET-CIMInstance Win32_SystemEnclosure -Verbose:$false).ChassisTypes -eq 30) {
        RETURN $True
    }
    RETURN $False
}
FUNCTION Get-ApplicationInstalled {
    
    [CmdletBinding()]
    PARAM (
        [STRING]$Name = "*",
        [SWITCH]$ExactMatch = $false
    )

    FUNCTION Convert-ToVersion {
    PARAM (
        $VersionString
    )

    TRY {
        $VersionString = $VersionString.Replace("v","")
        $VersionString = $VersionString -Split '\.'

        SWITCH ($VersionString.Count) {
            0 { RETURN $Null }
            1 { $Version = "$($VersionString[0])" }
            2 { $Version = "$($VersionString[0]).$($VersionString[1])" }
            3 { $Version = "$($VersionString[0]).$($VersionString[1]).$($VersionString[2])" }
            Default { $Version = "$($VersionString[0]).$($VersionString[1]).$($VersionString[2]).$($VersionString[3])" }
        }

        RETURN [VERSION]$Version
    } 
    CATCH {
        RETURN $null
    }
}

    $Results = @()
    $Apps = @()
    $Apps += Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" # 32 Bit
    $Apps += Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"             # 64 Bit


    FOREACH ($App in $Apps) {

        

        IF ($App.DisplayName -eq "" -or $App.DisplayName -eq $Null) { continue }
        TRY { $InstallDate = ([DateTime](($App.InstallDate).SubString(4,2)+"/"+($App.InstallDate).SubString(6,2)+"/"+($App.InstallDate).SubString(0,4))).ToString("MM/dd/yy") } Catch { $InstallDate = "" }
          
        $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Name = $App.DisplayName
            Publisher = $App.Publisher
            Version = (Convert-ToVersion $App.DisplayVersion)
            InstallDate = $InstallDate
            UninstallCommand = $App.UninstallString
        }
    }
 
    IF ($ExactMatch) { RETURN $Results | Select Name, Publisher, Version, InstallDate, UninstallCommand | Where-Object { $_.Name -like "$($Name)" } | Sort-Object Name }
    ELSE { RETURN $Results | Select Name, Publisher, Version, InstallDate, UninstallCommand | Where-Object { $_.Name -like "*$($Name)*" } | Sort-Object Name }
}
FUNCTION Test-ContextNotAdminElevated {
    IF (Test-ContextIsAdminElevated -eq $true) { RETURN $False }
    ELSE {$True}
}
FUNCTION Test-ContextIsAdminElevated {
    IF (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(` [Security.Principal.WindowsBuiltInRole] “Administrator”)) { RETURN $True }
    RETURN $False
}
FUNCTION Ensure-WinGet {
    # Check if Winget is already installed
    $ProgressPreferenceTemp = $ProgressPreference
    $ProgressPreference = "SilentlyContinue"
    try {
        $wingetVersion = winget --version
        
        IF ([VERSION]$wingetVersion.Replace("v","") -le [VERSION]"1.10") { 
            #Write-Verbose "Winget found, but is an old version: $wingetVersion";
        }
        ELSE { 
            #Write-Verbose "Winget is already installed. Version: $wingetVersion"
            return $true
        }
    }
    catch {
        #Write-Verbose "Winget not found. Attempting to install..."
    }

    try {
        # Install Winget
        #Write-Verbose "Attempting to Install Winet."
        Add-AppxPackage -Path "https://aka.ms/getwinget" -ErrorAction SilentlyContinue
        $ProgressPreference = $ProgressPreferenceTemp
        # Verify installation
        $wingetVersion = winget --version
        if ($?) {
            #Write-Verbose "Winget successfully installed. Version: $wingetVersion"
            return $true
        } else {
            #Write-Verbose "Failed to verify Winget installation"
            return $false
        }
    }
    catch {
        #Write-Verbose "Error during installation: $_"
        return $false
    }
}
FUNCTION Get-IPInfo {
    <#
    .SYNOPSIS
    Retrieves geographic information.
 
    .DESCRIPTION
    Retrieves geographic information about .
 
    .PARAMETER None
 
    .EXAMPLE
    Get-GeoInfo
 
    .NOTES
    The function uses a web API to cpllect geographic data.
    #>

    
    [CmdletBinding()]
    PARAM (
        [System.Net.IPAddress[]]$IPAddress = "127.0.0.1"
    )
    
    $Results = @()

    ### IP and Geo Location Data
    FOREACH ($IP in $IPAddress) {
        IF ($IP -eq "127.0.0.1") { 
            $GeoData = Invoke-RestMethod -Method Get -Uri "http://ip-api.com/json/$null" -Verbose:$false
            
            $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                IP = $GeoData.Query
                IPClass = "Public"
                Country = $GeoData.Country
                State = $GeoData.RegionName
                City = $GeoData.City
                ZipCode = $GeoData.Zip
                Org = $GeoData.Org
                ISP = $GeoData.ISP
            }        
        }
        ELSEIF ((TEST-IsPublicIP $IP)) {
            $GeoData = Invoke-RestMethod -Method Get -Uri "http://ip-api.com/json/$IP" -Verbose:$false
            
            $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                IP = $IP
                IPClass = "Public"
                Country = $GeoData.Country
                State = $GeoData.RegionName
                City = $GeoData.City
                ZipCode = $GeoData.Zip
                Org = $GeoData.Org
                ISP = $GeoData.ISP
            }
        }
        ELSE {
            $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                IP = $IP
                IPClass = "Private"
                Country = $null
                State = $null
                City = $null
                ZipCode = $null
                Org = $null
                ISP = $null
            }
        }
        
    }

    RETURN $Results | Select IP, IPClass, Country, State, City, ZipCode, Org, ISP
}
FUNCTION Test-VirusTotalHash {
    <#
    .SYNOPSIS
        Checks a file's hash against the VirusTotal database.
 
    .DESCRIPTION
        This function calculates the SHA256 hash of a specified file and queries the VirusTotal API to retrieve the analysis report, including the number of antivirus engines that detect it as malicious.
 
    .PARAMETER FilePath
        The full path to the file to be checked.
 
    .PARAMETER ApiKey
        Your VirusTotal API key. Obtain it from https://www.virustotal.com/gui/my-apikey.
 
    .EXAMPLE
        Get-VirusTotalFileReport -FilePath "C:\Downloads\example.exe" -ApiKey "your-api-key-here"
        Checks the SHA256 hash of example.exe against VirusTotal and displays the analysis results.
 
    .NOTES
        - Requires a VirusTotal API key.
        - Free API keys have rate limits (e.g., 4 requests per minute, 500 per day). Ensure compliance with VirusTotal's terms.
        - Ensure the file exists and is accessible.
        - Internet connectivity is required to query the VirusTotal API.
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$FilePath,        
        [string]$ApiKey = "938762c1c51c4d3825db13df683cbd4e3b3ad2d514bf79dcdb5a34eca32555b4",
        [int]$FailThreshold = 2,
        [SWITCH]$AllowUnknown = $False
    )

    # Get-VirusTotalFileReport -FilePath "C:\Downloads\example.exe" -ApiKey "your-api-key-here" -Verbose

    try {
        # Verify the file exists
        if (-not (Test-Path -Path $FilePath -PathType Leaf)) {
            throw "The file '$FilePath' does not exist or is not accessible."
        }

        # Calculate the SHA256 hash of the file
        #Write-Verbose "Calculating SHA256 hash for '$FilePath'..."
        $sha256 = Get-FileHash -Path $FilePath -Algorithm SHA256
        $fileHash = $sha256.Hash.ToLower()
        #Write-Verbose "SHA256 Hash: $fileHash"

        # Define VirusTotal API endpoint and headers
        $url = "https://www.virustotal.com/api/v3/files/$fileHash"
        $headers = @{
            "x-apikey" = $ApiKey
            "Accept"   = "application/json"
        }

        # Query VirusTotal API
        #Write-Verbose "Querying VirusTotal for hash '$fileHash'..."
        $response = Invoke-RestMethod -Uri $url -Method Get -Headers $headers -ErrorAction Stop -Verbose:$false

        # Parse the response
        $attributes = $response.data.attributes
        $lastAnalysisStats = $attributes.last_analysis_stats
        $totalEngines = $lastAnalysisStats.malicious + $lastAnalysisStats.suspicious + $lastAnalysisStats.undetected + $lastAnalysisStats.harmless
        $maliciousCount = $lastAnalysisStats.malicious
        $suspiciousCount = $lastAnalysisStats.suspicious

        # Prepare output
        $result = [PSCustomObject]@{
            FilePath         = $FilePath
            SHA256           = $fileHash
            TotalEngines     = $totalEngines
            MaliciousCount   = $maliciousCount
            SuspiciousCount  = $suspiciousCount
            DetectionRate    = "$maliciousCount/$totalEngines"
            LastAnalysisDate = (Get-Date -Date $attributes.last_analysis_date -Format "yyyy-MM-dd HH:mm:ss")
            VirusTotalLink   = "https://www.virustotal.com/gui/file/$fileHash"
        }

        # Output results
        #Write-Output "VirusTotal Analysis Report for '$FilePath':"
        #Write-Output $result | Format-Table -AutoSize
        if ($maliciousCount -gt 0 -or $suspiciousCount -gt 0) {
            #Write-Warning "File flagged as potentially malicious or suspicious by $maliciousCount/$totalEngines engines. Review the report at: https://www.virustotal.com/gui/file/$fileHash"
        } else {
            #Write-Output "No malicious or suspicious detections found."
        }

        IF ($result.MaliciousCount -gt $FailThreshold) { RETURN $False }
        ELSE { RETURN $True }
    }
    catch {
        RETURN $Null
        if ($_.Exception.Response.StatusCode -eq 404) {
            #Write-Warning "Hash '$fileHash' not found in VirusTotal database. Consider uploading the file for analysis."
        } elseif ($_.Exception.Response.StatusCode -eq 429) {
            #Write-Error "API rate limit exceeded. Wait and try again later or upgrade your VirusTotal API plan."
        } else {
            #Write-Error "An error occurred: $_"
        }

    }
}
FUNCTION Get-TimeDifferenceToString {
    
    [CmdletBinding()]
    PARAM (
        [DateTime]$Time
    )

    $TimeSpan = (Get-Date) - $Time

    IF ($TimeSpan.TotalHours -ge 1) {
        RETURN $Timespan.ToString("%h\:mm\:ss")
    }
    ELSE {
        RETURN $Timespan.ToString("%m\:ss")
    }
}
FUNCTION Remove-NullEntriesInObject {
    param (
        [Parameter(Mandatory=$true)]
        $InputArray
    )

   
        # Initialize an array list to store non-null entries
        $result = @()
  

  
        foreach ($item in $InputArray) {
            if ($null -ne $item.Action) {
                # Add non-null items to the result
                $result += $item
            }
        }
  

        # Return the filtered array
        return $result
 
}
Function Test-IPInCIDR {
    [cmdletbinding()]
    [outputtype([System.Boolean])]
    param(
        # IP Address to find.
        [parameter(Mandatory,
                   Position=0)]
        [validatescript({
            ([System.Net.IPAddress]$_).AddressFamily -eq 'InterNetwork'
        })]
        [string]
        $IPAddress,

        # Range in which to search using CIDR notation. (ippaddr/bits)
        [parameter(Mandatory,
                   Position=1)]
        [validatescript({
            $IP   = ($_ -split '/')[0]
            $Bits = ($_ -split '/')[1]

            (([System.Net.IPAddress]($IP)).AddressFamily -eq 'InterNetwork')

            if (-not($Bits)) {
                throw 'Missing CIDR notiation.'
            } elseif (-not(0..32 -contains [int]$Bits)) {
                throw 'Invalid CIDR notation. The valid bit range is 0 to 32.'
            }
        })]        
        [string]$CIDR
    )

    # Split range into the address and the CIDR notation
    [String]$CIDRAddress = $CIDR.Split('/')[0]
    [int]$CIDRBits       = $CIDR.Split('/')[1]

    # Address from range and the search address are converted to Int32 and the full mask is calculated from the CIDR notation.
    [int]$BaseAddress    = [System.BitConverter]::ToInt32((([System.Net.IPAddress]::Parse($CIDRAddress)).GetAddressBytes()), 0)
    [int]$Address        = [System.BitConverter]::ToInt32(([System.Net.IPAddress]::Parse($IPAddress).GetAddressBytes()), 0)
    [int]$Mask           = [System.Net.IPAddress]::HostToNetworkOrder(-1 -shl ( 32 - $CIDRBits))

    # Determine whether the address is in the range.
    if (($BaseAddress -band $Mask) -eq ($Address -band $Mask)) {
        $true
    } else {
        $false
    }
}
Function Test-NotNull {

    [CmdletBinding()]
    PARAM (
        [Parameter(Mandatory)]
        [AllowNull()]
        $Value
    )

    TRY {
        IF ($Value -eq $True) { RETURN $True }
        IF ($Value -eq $null) { RETURN $False }
        IF ($Value -eq "") { RETURN $False } 
        IF ($Value -eq " ") { RETURN $False }
        IF ($Value.count -eq 0) { RETURN $False }
        IF ($Value -eq $False) { RETURN $False }
    }
    CATCH {
        RETURN $False
    }

    RETURN $True
}
FUNCTION Test-IsDesktop {

    IF ((Test-IsLaptop) -or (Test-IsServer) -or (Test-IsVirtual)) { Return $False }
    ELSE { Return $True }
}
FUNCTION Test-IsLaptop {
    IF ((GET-CIMInstance Win32_SystemEnclosure -Verbose:$False).ChassisTypes -eq 8 -or
    (GET-CIMInstance Win32_SystemEnclosure -Verbose:$False).ChassisTypes -eq 9 -or
    (GET-CIMInstance Win32_SystemEnclosure -Verbose:$False).ChassisTypes -eq 10 -or
    (GET-CIMInstance Win32_SystemEnclosure -Verbose:$False).ChassisTypes -eq 14 -or
    (GET-CIMInstance Win32_SystemEnclosure -Verbose:$False).ChassisTypes -eq 30) {
        RETURN $True
    }
    RETURN $False
}
FUNCTION Test-IsVirtual {
    IF ((Get-WmiObject -Class Win32_ComputerSystem -Verbose:$False).Model -like "*Virtual*") { RETURN $True }
    IF ((Get-WmiObject -Class Win32_ComputerSystem -Verbose:$False).Model -like "*AWS*") { RETURN $True }
    IF ((Get-WmiObject -Class Win32_ComputerSystem -Verbose:$False).Model -like "*Google*") { RETURN $True }
    IF ((Get-WmiObject -Class Win32_ComputerSystem -Verbose:$False).Model -like "*VMWare*") { RETURN $True }
    IF ((Get-WmiObject -Class Win32_ComputerSystem -Verbose:$False).Model -like "*Xen*") { RETURN $True }
    RETURN $False
}
FUNCTION Test-IsPhysical {
    IF (Test-IsVirtual) { RETURN $False }
    ELSE { RETURN $True }
}
FUNCTION Test-IsServer {
    $ProductType = (GET-CIMInstance Win32_OperatingSystem -Verbose:$False).ProductType

    IF ($ProductType -eq 2) { RETURN $True }
    IF ($ProductType -eq 3) { RETURN $True }

    RETURN $False    
} 
FUNCTION Get-DuoForWindowsConfig {
   
    [CmdletBinding()]
    PARAM ( )

    $App = Get-ApplicationInstalled "Duo Auth"
 
    $Results = [PSCustomObject]@{
        AppName = $App.Name
        AppVersion = $App.Version
        IKey = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).IKey
        SKey = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).Skey
        HostAPI = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).Host
        AutoPush = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).AutoPush
        FailOpen = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).FailOpen
        RDPOnly = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).RDPOnly
        SmartCard = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).EnableSmartCards
        WrapSmartCard = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).WrapSmartCards
        EnableOffline = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).OfflineAvailable
        UserNameFormat = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).UserNameFormatForService        
        LogFile_MaxCount = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).LogFileMaxCount
        LogFile_MaxSizeMB = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).LogFileMaxSizeMB
        UAC_ProtectMode = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).ElevationProtectionMode
        UAC_Offline = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).ElevationOfflineEnable
        UAC_Offline_Enroll = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).ElevationOfflineEnrollment
        ProxyHost = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).ProxyHost
        ProxyPort = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Duo Security\DuoCredProv" -ErrorAction SilentlyContinue).ProxyPort
    }

    RETURN $Results
}
FUNCTION Send-Keystroke {
    PARAM (
        [Parameter(Mandatory)]
        [STRING]$Title,
        [Parameter(Mandatory)]
        [STRING[]]$Key,
        [INT]$Delay = 10
    )

    FOREACH ($Item in $Key) { 
        $AppShell = New-Object -ComObject wscript.shell
        $AppShell.AppActivate($Title) | Out-Null
        Start-Sleep -Milliseconds 100
        $AppShell.SendKeys($Item)

        Start-Sleep -Seconds $Delay
    }
}
FUNCTION Install-Font {
    <#
    .SYNOPSIS
        Installs a font on the system.
    .DESCRIPTION
        Copies a font file to the Windows Fonts directory and registers it in the system.
    .PARAMETER FontPath
        The full path to the font file (.ttf or .otf).
    .EXAMPLE
        Install-Font -FontPath "C:\Fonts\MyFont.ttf"
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, Position=0)]
        [ValidateScript({Test-Path $_ -PathType Leaf})]
        [string]$FontPath
    )

    try {
        # Get font file details
        $fontFile = Get-Item $FontPath
        $fontName = $fontFile.BaseName
        $fontExtension = $fontFile.Extension.ToLower()
        
        # Validate font file type
        if ($fontExtension -notin @('.ttf', '.otf')) {
            throw "Invalid font file type. Only .ttf and .otf files are supported."
        }

        # Windows Fonts directory
        $fontsFolder = [System.Environment]::GetFolderPath('Fonts')
        $destinationPath = Join-Path $fontsFolder $fontFile.Name

        # Copy font to Windows Fonts directory
        Copy-Item -Path $FontPath -Destination $destinationPath -Force

        # Register the font
        $shell = New-Object -ComObject Shell.Application
        $fontsNamespace = $shell.Namespace(0x14) # 0x14 is the Fonts folder
        $Job = Start-Job -ScriptBlock { $fontsNamespace.CopyHere($FontPath) }     
        

        # Add to registry
        $registryPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"
        $fontRegistryName = if ($fontExtension -eq '.ttf') { "$fontName (TrueType)" } else { "$fontName (OpenType)" }
        Set-ItemProperty -Path $registryPath -Name $fontRegistryName -Value $fontFile.Name -Force

        #Write-Output "Font '$fontName' installed successfully."

        Send-Keystroke -Title "Install Font" -Key "{Tab}","{Enter}" -Delay 2
    }
    catch {
        #Write-Error "Failed to install font: $_"
    }
}
FUNCTION Test-FontInstalled {
    <#
    .SYNOPSIS
        Checks if a font is installed on the system.
    .DESCRIPTION
        Verifies if a specified font is present in the Windows Fonts directory or registry.
    .PARAMETER FontName
        The name of the font to check (without file extension).
    .EXAMPLE
        Test-FontInstalled -FontName "Arial"
    .OUTPUTS
        Boolean: $true if the font is installed, $false otherwise.
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true, Position=0)]
        [string]$FontName
    )

    try {
        # Check Windows Fonts directory
        $fontsFolder = [System.Environment]::GetFolderPath('Fonts')
        $fontFiles = Get-ChildItem -Path $fontsFolder -Include "$FontName*.ttf", "$FontName*.otf" -File

        if ($fontFiles) {
            Write-Verbose "Font file for '$FontName' found in Fonts directory."
            return $true
        }

        # Check registry
        $registryPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"
        $fontRegistryNameTTF = "$FontName (TrueType)"
        $fontRegistryNameOTF = "$FontName (OpenType)"
        
        $fontInRegistry = (Get-ItemProperty -Path $registryPath -ErrorAction SilentlyContinue).PSObject.Properties.Name |
            Where-Object { $_ -eq $fontRegistryNameTTF -or $_ -eq $fontRegistryNameOTF }

        if ($fontInRegistry) {
            Write-Verbose "Font '$FontName' found in registry."
            return $true
        }

        Write-Verbose "Font '$FontName' not found."
        return $false
    }
    catch {
        Write-Error "Error checking font installation: $_"
        return $false
    }
}  


### Core Functions
FUNCTION Set-RegistryValue {
    [CmdletBinding()]
    PARAM (
        [Parameter(Mandatory=$true)]
        [ValidateSet("HKLM", "HKCU", "HKCR", "HKU", "HKCC")]
        [string]$Hive,

        [Parameter(Mandatory=$true)]
        [string]$Path,

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

        [Parameter(Mandatory=$true)]
        $Value,

        [Parameter(Mandatory=$true)]
        [ValidateSet("String", "DWORD", "QWORD", "MultiString", "Binary", "ExpandString")]
        [string]$Type
    )

    try {
        # Convert hive shorthand to full registry path
        $hivePath = switch ($Hive) {
            "HKLM" { "HKLM:\" }
            "HKCU" { "HKCU:\" }
            "HKCR" { "HKEY_CLASSES_ROOT\" }
            "HKU"  { "HKEY_USERS\" }
            "HKCC" { "HKEY_CURRENT_CONFIG\" }
        }

        # Construct full registry path
        $fullPath = Join-Path $hivePath $Path

        # Check if path exists, create if it doesn't
        if (-not (Test-Path $fullPath)) {
            New-Item -Path $fullPath -Force -ErrorAction SilentlyContinue | Out-Null
        }

        # Set the registry value
        Set-ItemProperty -Path $fullPath -Name $Name -Value $Value -Type $Type -ErrorAction SilentlyContinue     

        # Verify the value was set
        $setValue = Get-ItemProperty -Path $fullPath -Name $Name -ErrorAction SilentlyContinue
        $actualValue = $setValue.$Name

        # Compare set value with requested value
        if ($actualValue -eq $Value) {
            Write-Verbose "Registry key set successfully: $fullPath\$Name = $actualValue"
            return $true
        } else {
            Write-Verbose "Verification failed: Expected '$Value', but got '$actualValue'"
            return $false
        }



    }
    catch {
        Write-Verbose "Failed to set registry key: $($_.Exception.Message)"
        return $false
    }
}
FUNCTION Run-FileDownload {
    
    [CmdletBinding()]
    PARAM (
        [Parameter(Mandatory=$true)]
        [STRING]$URL,
        [Parameter(Mandatory=$true)]
        [STRING]$FileName,
        [STRING]$SavePath = "C:\Integris\Temp",
        [STRING]$FileHash,
        [SWITCH]$Force = $False,
        [SWITCH]$BasicOutput = $False
    )

    $Result = New-Object PSObject -WarningAction SilentlyContinue -Property @{
        DownloadURL = $URL
        FileName = $FileName
        SavePath = $SavePath
        FullName = "$($SavePath)\$($FileName)"
        FileHash = $FileHash
        DownloadHash = $null
        HashMatch = $null
        DownloadSuccess = $null
    }

    FUNCTION OutputFunctionResults {
        ### Set Progress Bar Back to Original Setting
        $ProgressPreference = $ProgressPreferenceTemp

        IF ($BasicOutput) { RETURN $Result.DownloadSuccess }
        ELSE { RETURN $Result | Select DownloadURL, SavePath, FileName, FullName, FileHash, DownloadHash, HashMatch, DownloadSuccess }
    }
        
    TRY {

        ### Progress Bar Needs to Be Disabled
        ### If Not Disabled, The GUI Attempts to Update on Every Byte Downloaded which Makes it Run Extremely Slow As a Download could Easily Be Millions of Bytes
        $ProgressPreferenceTemp = $ProgressPreference
        $ProgressPreference = "SilentlyContinue"


        ### Create Download Directory
        $SavePathSplit = $SavePath.Split("\")
        $NewFolderName = $null
        $NewFolderPath = $null
        IF ($SavePathSplit[$SavePathSplit.Count-1] -eq "") {
            $NewFolderName = $SavePathSplit[$SavePathSplit.Count-2]
            $Count = 2
            $NewFolderPath = ""
            While ($Count -lt $SavePathSplit.Count) { 
                $NewFolderPath += $SavePathSplit[$Count-2]
                $NewFolderPath += "\"
                $Count++
            }
            New-Item -Name $NewFolderName -Path $NewFolderPath -ItemType Directory -ErrorAction SilentlyContinue | Out-Null 
        }
        ELSE {
            $NewFolderName = $SavePathSplit[$SavePathSplit.Count-1]
            $Count = 1
            $NewFolderPath = ""
            While ($Count -lt $SavePathSplit.Count) { 
                $NewFolderPath += $SavePathSplit[$Count-1]
                $NewFolderPath += "\"
                $Count++
            }
            New-Item -Name $NewFolderName -Path $NewFolderPath -ItemType Directory -ErrorAction SilentlyContinue | Out-Null
        }


        ### Check if Already Downloaded
        $DownloadFile = GET-Item "$($SavePath)\$($FileName)" -ErrorAction SilentlyContinue
        $DownloadHash = (Get-FileHash -Path "$($SavePath)\$($FileName)" -Algorithm SHA256 -ErrorAction SilentlyContinue).Hash

        ### If File Exists and Hash Matches
        IF ($DownloadFile -and $DownloadHash -eq $FileHash) {
            $Result.DownloadHash = $DownloadHash; $Result.HashMatch = $true; $Result.DownloadSuccess = $true;
            #Write-Verbose "$($(Get-Date).ToShortTimeString()): File found. Already downloaded."
            IF ($Force) { 
                #Write-Verbose "$($(Get-Date).ToShortTimeString()): Download found and hash matches, but force download was specified."
            } ELSE { RETURN OutputFunctionResults }
        }

        ## IF File Exists and Hash Wasn't Specified
        IF ($DownloadFile -and ($FileHash -eq $null -or $FileHash -eq "")) {
            $Result.DownloadHash = $DownloadHash; $Result.HashMatch = $null; $Result.DownloadSuccess = $true;
            #Write-Verbose "$($(Get-Date).ToShortTimeString()): File found. Already downloaded."
            IF ($Force) { 
                #Write-Verbose "$($(Get-Date).ToShortTimeString()): Download found but force download was specified."
            } ELSE { RETURN OutputFunctionResults }
        }

        ### If File Exists and Hash Doesn't Match
        ELSEIF ($DownloadFile -and $DownloadHash -ne $FileHash) { 
            #Write-Verbose "$($(Get-Date).ToShortTimeString()): Download found and but Hash doesn't match. Attempting download."
        }
        

        ### Download the file
        #Write-Verbose "$($(Get-Date).ToShortTimeString()): Downloading file from $URL..."
        TRY { Invoke-WebRequest $URL -OutFile "$($SavePath)\$($FileName)" -UseBasicParsing -ErrorAction SilentlyContinue -Verbose:$false }
        catch { }

        #Write-Verbose "$($(Get-Date).ToShortTimeString()): File downloaded to $($SavePath)\$($FileName)"

        $DownloadFile = GET-Item "$($SavePath)\$($FileName)" -ErrorAction SilentlyContinue
        $DownloadHash = (Get-FileHash -Path "$($SavePath)\$($FileName)" -Algorithm SHA256 -ErrorAction SilentlyContinue).Hash
        
        ### If File Exists and Hash Matches
        IF ($DownloadFile -and $DownloadHash -eq $FileHash) {
            $Result.DownloadHash = $DownloadHash; $Result.HashMatch = $true; $Result.DownloadSuccess = $true; 
            #Write-Verbose "$($(Get-Date).ToShortTimeString()): Download Successful. Hash Matches. Done."
            RETURN OutputFunctionResults
        }
        ### If File Exists and Hash Doesn't Match
        ELSEIF ($DownloadFile -and $FileHash -ne $null -and $FileHash -ne "") {
            $Result.DownloadHash = $DownloadHash; $Result.HashMatch = $false; $Result.DownloadSuccess = $false; 
            #Write-Verbose "$($(Get-Date).ToShortTimeString()): Download Failure. Hash Doesn't Match. Fail."
            RETURN OutputFunctionResults   
        }
        ### If File Exists and Hash Wasn't Specified
        ELSEIF ($DownloadFile -and ($FileHash -eq $null -or $FileHash -eq "")) {
            $Result.DownloadHash = $DownloadHash; $Result.HashMatch = $null; $Result.DownloadSuccess = $true; 
            #Write-Verbose "$($(Get-Date).ToShortTimeString()): Download Successful. Verification hash not provided. Done."
            RETURN OutputFunctionResults   
        }
        ### If File Doesn't Exist and Hash wasn't specified
        ELSEIF ($DownloadFile -eq $null -and ($FileHash -eq $null -or $FileHash -eq "")) {
            $Result.DownloadHash = $null; $Result.HashMatch = $null; $Result.DownloadSuccess = $false; 
            #Write-Verbose "$($(Get-Date).ToShortTimeString()): Download Unsuccessful. Fail."
            RETURN OutputFunctionResults   
        }
        ### If File Doesn't Exist and Hash was specified
        ELSE {
            $Result.DownloadHash = $null; $Result.HashMatch = $false; $Result.DownloadSuccess = $false; 
            #Write-Verbose "$($(Get-Date).ToShortTimeString()): Download Unsuccessful. Fail."
            RETURN OutputFunctionResults
        }

    }
    CATCH {
        #Write-Error "Error occurred: $_"
        RETURN OutputFunctionResults
    }
}
FUNCTION Run-PackageHandler {

    [CmdletBinding(DefaultParameterSetName='Install')]
    PARAM (
        ### General
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [Parameter(Mandatory)]  
        [STRING]$ApplicationName = $null,
        [VERSION]$ApplicationVersion = $null,
        [SWITCH]$ExactVersion = $False, 
        [STRING]$CustomVersionCommand = $null,
        [SWITCH]$VerifyOnly = $False, 
        [STRING]$DownloadLink = $null,
        [STRING]$BackupDownloadLink = $DownloadLink,
        [STRING]$FileName = $null,
        [STRING]$BackupFileName = $FileName,
        [STRING]$ZipInstallerPath = $null,
        [STRING]$SavePath = "C:\Integris\IDTTemp",
        [ValidateSet("Always","AfterSuccess","Never")]
        [STRING]$CleanupMode = "AfterSuccess", 
        [SWITCH]$ForceDownload = $False,    
        [ValidateSet("NoUpdate","InstallOver","UninstallReinstall")]
        [STRING]$UpdateMethod = "NoUpdate",   


        ### Run Specific
        [STRING]$RunPath = $null,
        [STRING]$RunArguements = $null,


        ### Install Specific
        [STRING]$CustomInstallCommand = $null,
        [SWITCH]$InvokeInstallCommand = $False,
        [STRING]$InstallArguments = $null,   
        [INT]$InstallTimeout = 480,               
        [INT]$PostInstallDelay = 5,
        [STRING[]]$PreInstallEndProcess = $null, 
        [STRING[]]$PostInstallEndProcess = $null, 
        [STRING]$CustomInstallVerification = $null,  
        [STRING]$InstallKeystrokes = $null,


        ### Uninstall Specific
        [STRING]$UninstallCommand = $null,
        [SWITCH]$InvokeUninstallCommand = $False,
        [STRING]$UninstallArguments = $null,
        [INT]$UninstallTimeout = 240,
        [INT]$PostUninstallDelay = 10,
        [STRING[]]$PreUninstallEndProcess = @(),
        [STRING[]]$PostUninstallEndProcess = @(),
        [STRING]$CustomUninstallVerification = $null,  
        [STRING]$UninstallKeystrokes = $null,
               

        ### Smart Features Specific
        [AllowNull()]
        [STRING[]]$IncludeDeviceType = $null,
        [AllowNull()]
        [STRING[]]$ExcludeDeviceType = $null,
        [AllowNull()]
        [STRING[]]$IncludeHostname = $null,
        [AllowNull()]
        [STRING[]]$ExcludeHostname = $null,
        [AllowNull()]
        [STRING[]]$IncludeDN = $null,
        [AllowNull()]
        [STRING[]]$ExcludeDN = $null,
        [AllowNull()]
        [STRING[]]$IncludeADSite = $null,
        [AllowNull()]
        [STRING[]]$ExcludeADSite = $null,
        [AllowNull()]
        [STRING[]]$IncludeIPAddress = $null,
        [AllowNull()]
        [STRING[]]$ExcludeIPAddress = $null,
        [AllowNull()]
        [STRING[]]$IncludeGeoLocation = $null,
        [AllowNull()]
        [STRING[]]$ExcludeGeoLocation = $null,


        ### Security Specific
        [STRING]$DownloadHash = $null,
        [STRING]$BackupDownloadHash = $null,
        [SWITCH]$CertVerification = $null,
        [STRING]$CertName = $null,
        [SWITCH]$VirusTotal = $null,
           

        ### WinGet Specific
        [STRING]$WinGetAppName = $null
    ) 

    ### ================
    ### === Defaults ===
    ### ================
    IF (!(Test-NotNull $CustomInstallVerification)) { $CustomInstallVerification = "(Get-ApplicationInstalled '$ApplicationName' -ExactMatch)" }
    IF (!(Test-NotNull $CustomUninstallVerification)) { $CustomUninstallVerification = "!($CustomInstallVerification)" }

    IF ($Action -eq "Install") { $Action = "Install" }
    IF ($Action -eq "Uninstall") { $Action = "Uninstall" }
    IF ($Action -eq "Reinstall") { $Action = "Reinstall" }
    IF ($Action -eq "Update") { $Action = "Update" }
    IF ($Action -eq "Download") { $Action = "Download" }
    IF ($Action -eq "Run") { $Action = "Run" }


    ### ====================================
    ### === Dependacy and Error Checking ===
    ### ====================================

    ### Not Running in Elevated Context
    IF (Test-ContextNotAdminElevated) { Write-Warning "Script requires Admin elevation. Please re-run as an administrator."; $Result.Success = $False; $Result.Details = "Need Admin Elevation"; RETURN }

    ### Zip Download Missing Zip Installer Path
    IF ($FileName -like "*.zip" -and ($ZipInstallerPath -eq $null -or $ZipInstallerPath -eq "") ) { 
        Write-Warning "If the download is a zip file you must include the file and path of the installer inside the zip file. ex: 'foldername\setup.exe'"
        $Result.Success = $False; $Result.Details = "Missing Zip Installer Path"; RETURN RETURN-Results
    }
    

    ### ===============================
    ### === Results Return Function ===
    ### ===============================
    FUNCTION RETURN-Results { 

        ### Check Results
        IF ($Result.Name -eq $ApplicationName) {
            $TempName = Get-ApplicationInstalled $ApplicationName -ExactMatch
            IF ($TempName) { $Result.Name = $TempName.Name }
        }
        IF (!(Test-NotNull $Result.Version)) {

            IF (Test-NotNull $CustomVersionCommand) {
                $Result.Version = Invoke-Expression -Command $CustomVersionCommand
            }
            ELSE { 
                $TempVersion = Get-ApplicationInstalled $ApplicationName -ExactMatch
                IF ($TempVersion) { $Result.Version = $TempVersion.Version }
            }
        }

        
        ### Use WinGet if Install Failed
        IF (Test-NotNull $VerifyOnly) { }
        ELSEIF ((Test-NotNull $WinGetAppName) -and $Result.Success -ne $True -and ($Action -eq "Install" -or $Action -eq "Update" -or $Action -eq "Reinstall" -or $Action -eq "Run")) {
            
            Write-Host "$($(Get-Date).ToShortTimeString()): Attempting Install via WinGet... " -NoNewline
            IF (Ensure-Winget) {            

                
                WinGet Install $WinGetAppName --accept-package-agreements --accept-source-agreements | Out-Null
                

                $GetAppInstall = GET-ApplicationInstalled -Name $ApplicationName -ExactMatch
                IF ((Test-NotNull $CustomVersionCommand)) { $GetAppInstall.Version = Invoke-Expression -Command $CustomVersionCommand }

                ### =========================
                ### === Post WinGet Check ===
                ### =========================

                ### Reinstall
                IF ($Action -eq "Reinstall") {
                    IF ($InstallResult) {
                        Write-Host "Application reinstall successful. Done."
                        $Result.Name = $GetAppInstall.Name
                        $Result.Version = $GetAppInstall.Version       
                        $Result.Success = $True
                        $Result.Details = $null

                        IF ($GetAppInstall.Version -lt $ApplicationVersion) { $Result.Success = $False; $Result.Details = "Application Reinstalled, but Old Version" }
                    }      
                    ELSE {
                        Write-Host "Application reinstall unsuccesful."
                        $Result.Success = $False
                        $Result.Details = "Reinstall Unsuccessful"
                    }
                }
                ### Update
                ELSEIF ($Action -eq "Update") {
                    IF ($InstallResult) {
                        Write-Host "Application update successful. Done."
                        $Result.Name = $GetAppInstall.Name
                        $Result.Version = $GetAppInstall.Version       
                        $Result.Success = $True
                        $Result.Details = $null

                        IF ($GetAppInstall.Version -lt $ApplicationVersion) { $Result.Success = $False; $Result.Details = "Application is Updated, but Old Version" }
                    }
                    ELSE {
                        Write-Host "Application update unsuccesful."
                        $Result.Success = $False
                        $Result.Details = "Update Unsuccessful"
                    }    
                }
                ### Install
                ELSE {
                    IF ($InstallResult) {
                        Write-Host "Application install successful. Done."
                        $Result.Name = $GetAppInstall.Name
                        $Result.Version = $GetAppInstall.Version       
                        $Result.Success = $True
                        $Result.Details = $null

                        IF ($GetAppInstall.Version -lt $ApplicationVersion) { $Result.Success = $False; $Result.Details = "Application is Installed, but Old Version" }
                    }
                    ELSE {
                        Write-Host "Application install unsuccesful."
                        $Result.Success = $False
                        $Result.Details = "Install Unsuccessful"
                    }
                }
                
            }       
            ELSE { Write-Host "WinGet not found. Skipping install attempt." }
        }

        IF ($Action -eq "Run" -and (Test-NotNull $RunPath) -and $VerifyOnly -eq $False) { 
            TRY { 
                IF (!(Test-NotNull $RunArguments)) { Start-Process -FilePath $RunPath -PassThru | Out-Null }
                ELSE { Start-Process -FilePath $RunPath -ArgumentList $RunArguments -PassThru | Out-Null }
                Write-Host "$($(Get-Date).ToShortTimeString()): File ran successfully."
            }
            CATCH {
                $Result.Success = $False
                $Result.Details = "Run File not Found"
                Write-Host "$($(Get-Date).ToShortTimeString()): Fail to run. Run file not found."; $Result.Success = $False; $Result.Details = "Run File Not Found"
            }
        }

        $Duration = $(((Get-Date) - $StartTime))
        IF ($Duration.Hours -gt 0) { $Result.Duration = $(((Get-Date) - $StartTime).ToString("h\:m\:ss")) }
        ELSE { $Result.Duration = $(((Get-Date) - $StartTime).ToString("m\:ss")) }

        IF (($CleanupMode -eq "Always" -or ($Result.Success -eq $true -and $CleanupMode -eq "AfterSuccess")) -and ($ApplicationIsInstalled -eq $False -or $ApplicationNeedsUpdated -eq $True) -and $Action -ne "Download") { 
            #Write-Host "$($(Get-Date).ToShortTimeString()): Deleting Installer Files."
            IF ($ZipInstallerPath -ne $null -and $ZipInstallerPath -ne "") { Remove-Item -Path "$($SavePath)\$($($ApplicationName).Replace('*',''))\" -Recurse -ErrorAction SilentlyContinue }
            Remove-Item -Path "$($SavePath)\$($FileName)" -ErrorAction SilentlyContinue }        


        IF ((Get-PSCallStack).Command -like "*DeploymentSet*") { RETURN $Result | Select Action, Duration, RequestedName, Name, RequestedVersion, Version, Success, Details }
        ELSE { RETURN $Result | Select Action, Duration, Name, Version, Success, Details }
    }


    ### ==========================
    ### === Starting Variables ===
    ### ==========================
    $StartTime = Get-Date              ### Start time for tracking duration.
    $ApplicationIsInstalled = $null    ### Tracking if Application is Installed
    $ApplicationNeedsUpdated = $null   ### Tracking if Application Needs Updated
    $IPInfo = Get-IPInfo               ### Public IP and Geographic Info
    $RetryCount = 2


    ### ========================
    ### === Results Variable ===
    ### ========================
    $Result = [PSCustomObject]@{
        Action = $Action
        RequestedName = $ApplicationName
        Name = $ApplicationName
        RequestedVersion = $ApplicationVersion
        Version = $null
        Duration = $null
        Success = $null
        Details = $null
    }


    ### ==================
    ### === Log Header ===
    ### ==================
    $Callstack = Get-PSCallStack 
    IF (!((($Callstack).Command) -contains "Run-DeploymentSet")) {
        $PackageName = ($Callstack | Where-Object { ($_.Command -like "App-*" -or $_.Command -like "Driver-*" -or $_.Command -like "Font-*") -and $_.Command -notlike "*PackageHandler*" }).Command

        Write-Host ""
        Write-Host "$($(Get-Date).ToShortTimeString()): ### =============================================== ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### Starting Integris Deployment Tool Session ###" 
        Write-Host "$($(Get-Date).ToShortTimeString()): ### Action: $($Action.PadRight(36,' '))###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### Package: $($($PackageName).PadRight(36,' '))###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### =============================================== ###"
        Write-Host ""
    }
    

    ### =======================
    ### === Smart Targeting ===
    ### =======================
    IF ($True) {
        

        ### ===========================
        ### === Include Device Type ===
        ### ===========================
        IF (Test-NotNull $IncludeDeviceType) {
            ### Check
            $CheckStatus = $False
            $CheckDevice = $null
            IF (Test-IsDesktop) { $CheckDevice = "Desktop" }
            IF (Test-IsLaptop) { $CheckDevice = "Laptop" }
            IF (Test-IsServer) { $CheckDevice = "Server" }
            FOREACH ($Device in $IncludeDeviceType) { IF ($Device -eq $CheckDevice) { $CheckStatus = $True } }

            ### Pass
            IF ($CheckStatus) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Device Type for inclusion. Device type [$CheckDevice] matches include [$IncludeDeviceType]." }
            
            ### Fail
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Device Type for inclusion. Device type [$CheckDevice] does not match include [$IncludeDeviceType]. Skipping install."; $Result.Success = $True; $Result.Details = "Device Type [$CheckDevice] Skipped"; RETURN RETURN-Results }
        }


        ### ===========================
        ### === Exclude Device Type ===
        ### ===========================
        IF (Test-NotNull $ExcludeDeviceType) {
            ### Check
            $CheckStatus = $False
            $CheckDevice = $null
            IF (Test-IsDesktop) { $CheckDevice = "Desktop" }
            IF (Test-IsLaptop) { $CheckDevice = "Laptop" }
            IF (Test-IsServer) { $CheckDevice = "Server" }
            FOREACH ($Device in $ExcludeDeviceType) { IF ($Device -eq $CheckDevice) { $CheckStatus = $True } }

            ### Pass
            IF (!$CheckStatus) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Device Type for exclusion. Device type [$CheckDevice] does not match exclude [$ExcludeDeviceType]." }
            
            ### Fail
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Device Type for exclusion. Device type [$CheckDevice] matches exclude [$ExcludeDeviceType]. Skipping install."; $Result.Success = $True; $Result.Details = "Device Type [$CheckDevice] Skipped"; RETURN RETURN-Results }
        }

        ### ========================
        ### === Include Hostname ===
        ### ========================
        IF (Test-NotNull $IncludeHostname) {
            $Hostname = $env:COMPUTERNAME
            $HostnameMatch = $False
            FOREACH ($Entry in $IncludeHostname) {
                IF ($Hostname -like $Entry) { 
                    $HostnameMatch = $True; break
                }
            }

            IF ($HostnameMatch) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking hostname for inclusion. Hostname [$Hostname] matches [$IncludeHostname]." }
            ### Fail No Match
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking hostname for inclusion. Hostname [$Hostname] doesn't match [$IncludeHostname]. Skipping install."; $Result.Success = $True; $Result.Details = "Hostname Not Included"; RETURN RETURN-Results }
        }

        ### ========================
        ### === Exclude Hostname ===
        ### ========================
        IF (Test-NotNull $ExcludeHostname) {
            $Hostname = $env:COMPUTERNAME
            $HostnameMatch = $False
            FOREACH ($Entry in $ExcludeHostname) {
                IF ($Hostname -like $Entry) { 
                    $HostnameMatch = $True; break
                }
            }

            IF (!$HostnameMatch) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking hostname for exclusion. Hostname [$Hostname] doesn't match [$ExcludeHostname]." }
            ### Fail No Match
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking hostname for exclusion. Hostname [$Hostname] matches [$ExcludeHostname]. Skipping install."; $Result.Success = $True; $Result.Details = "Hostname Excluded"; RETURN RETURN-Results }
        }


        ### ==================
        ### === Include DN ===
        ### ==================
        IF (Test-NotNull $IncludeDN) {
            $DN = (gpresult /r /scope:computer) -Match "CN="
            $DN = $DN.Replace(" ","")
            IF (Test-NotNull $DN) {
                $DNMatch = $False
                FOREACH ($Entry in $IncludeDN) {
                    IF ($DN -like $Entry) {
                        $DNMatch = $True
                        break
                    }
                }
                ### Pass Match
                IF ($DNMatch) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Distinguished Name for inclusion. Distinguished Name [$DN] matches [$IncludeDN]." }
                ### Fail No Match
                ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Distinguished Name for inclusion. Distinguished Name [$DN] doesn't match [$IncludeDN]. Skipping install."; $Result.Success = $True; $Result.Details = "Distinguished Name Not Included"; RETURN RETURN-Results }
            }
            ### Fail Unknown
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Distinguished Name for inclusion. Distinguished Name not found and doesn't match [$IncludeDN]. Skipping install."; $Result.Success = $False; $Result.Details = "Distinguished Name Not Found"; RETURN RETURN-Results }
        }


        ### ==================
        ### === Exclude DN ===
        ### ==================
        IF (Test-NotNull $ExcludeDN) {
            $DN = (gpresult /r /scope:computer) -Match "CN="
            $DN = $DN.Replace(" ","")
            IF (Test-NotNull $DN) {
                $DNMatch = $False
                FOREACH ($Entry in $ExcludeDN) {
                    IF ($DN -like $Entry) {
                        $DNMatch = $True
                        break
                    }
                }
                ### Pass Match
                IF (!$DNMatch) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Distinguished Name for exclusion. Distinguished Name [$DN] doesn't match [$ExcludeDN]." }
                ### Fail No Match
                ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Distinguished Name for exclusion. Distinguished Name [$DN] matches [$ExcludeDN]. Skipping install."; $Result.Success = $True; $Result.Details = "Distinguished Name Excluded"; RETURN RETURN-Results }
            }
            ### Fail Unknown
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Distinguished Name for exclusion. Distinguished Name not found and not excluded." }
        }

        
        ### =======================
        ### === Include AD Site ===
        ### =======================
        IF (Test-NotNull $IncludeADSite) {
            $ADSite = ((nltest /dsgetsite) -split "The command completed successfully")[0]
            IF (Test-NotNull $ADSite) {
                $ADSiteMatch = $False
                FOREACH ($Entry in $IncludeADSite) {
                    IF ($ADSite -like $Entry) {
                        $ADSiteMatch = $True
                        break
                    }
                }
                ### Pass Match
                IF ($ADSiteMatch) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking AD Site for inclusion. AD Site [$ADSite] matches [$IncludeADSite]." }
                ### Fail No Match
                ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking AD Site for inclusion. AD Site [$ADSite] doesn't match [$IncludeADSite]. Skipping install."; $Result.Success = $True; $Result.Details = "AD Site Not Included"; RETURN RETURN-Results }
            }
            ### Fail Unknown
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking AD Site for inclusion. AD Site not found and doesn't match [$IncludeADSite]. Skipping install."; $Result.Success = $False; $Result.Details = "AD Site Not Found"; RETURN RETURN-Results }
        }


        ### =======================
        ### === Exclude AD Site ===
        ### =======================
        IF (Test-NotNull $ExcludeADSite) {
            $ADSite = ((nltest /dsgetsite) -split "The command completed successfully")[0]
            IF (Test-NotNull $ADSite) {
                $ADSiteMatch = $False
                FOREACH ($Entry in $ExcludeADSite) {
                    IF ($ADSite -like $Entry) {
                        $ADSiteMatch = $True
                        break
                    }
                }
                ### Pass Match
                IF (!$ADSiteMatch) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking AD Site for exclusion. AD Site [$ADSite] doesn't match [$ExcludeADSite]." }
                ### Fail No Match
                ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking AD Site for exclusion. AD Site [$ADSite] matches [$ExcludeADSite]. Skipping install."; $Result.Success = $True; $Result.Details = "AD Site Excluded"; RETURN RETURN-Results }
            }
            ### Fail Unknown
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking AD Site for exclusion. AD Site not found and not excluded." }
        }


        ### ==========================
        ### === Include IP Address ===
        ### ==========================
        IF (Test-NotNull $IncludeIPAddress) {
            $CurrentIPAddresses = @()
            $CurrentIPAddresses += $IPInfo.IP
            $CurrentIPAddresses += (get-netipaddress).IPv4Address | Where-Object { $_ -ne $null -and $_ -ne "" }
            $MatchFound = $False
            FOREACH ($IncludeEntry in $IncludeIPAddress) {
                FOREACH ($CurrentEntry in $CurrentIPAddresses) {
                    IF ($IncludeEntry -like "*/*") { IF ((Test-IPInCIDR -IPAddress $CurrentEntry -CIDR $IncludeEntry)) { $MatchFound = $True; break } }
                    ELSEIF ($IncludeEntry -eq $CurrentEntry) { $MatchFound = $True; break }
                }
                IF ($MatchFound) { break }
            }

            ### Pass Match
            IF ($MatchFound) {Write-Host "$($(Get-Date).ToShortTimeString()): Checking for IP address inclusion. IP Address [$CurrentIPAddresses] matches [$IncludeIPAddress]." }
            ### Fail No Match
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking for IP address inclusion. IP Address [$CurrentIPAddresses] doesn't match [$IncludeIPAddress]. Skipping install."; $Result.Success = $True; $Result.Details = "IP Address not Included"; RETURN RETURN-Results }
        }


        ### ==========================
        ### === Exclude IP Address ===
        ### ==========================
        IF (Test-NotNull $ExcludeIPAddress) {
            $CurrentIPAddresses = @()
            $CurrentIPAddresses += $IPInfo.IP
            $CurrentIPAddresses += (get-netipaddress).IPv4Address | Where-Object { $_ -ne $null -and $_ -ne "" }
            $MatchFound = $False
            FOREACH ($ExcludeEntry in $ExcludeIPAddress) {
                FOREACH ($CurrentEntry in $CurrentIPAddresses) {
                    IF ($ExcludeEntry -like "*\*") { IF ((Test-IPInCIDR -IPAddress $CurrentEntry -CIDR $ExcludeEntry)) { $MatchFound = $True; break } }
                    ELSEIF ($ExcludeEntry -eq $CurrentEntry) { $MatchFound = $True; break }
                }
                IF ($MatchFound) { break }
            }

            ### Pass Match
            IF (!$MatchFound) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking for IP address exclusion. IP Address [$CurrentIPAddresses] doesn't match [$ExcludeIPAddress]." }
            ### Fail No Match
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking for IP address exclusion. IP Address [$CurrentIPAddresses] doesn't match [$ExcludeIPAddress]. Skipping install."; $Result.Success = $True; $Result.Details = "IP Address Excluded"; RETURN RETURN-Results }
        }


        ### ============================
        ### === Include Geo Location ===
        ### ============================
        IF (Test-NotNull $IncludeGeoLocation) {
            $LocationMatch = $False
            $CurrentLocation = $IPInfo
            FOREACH ($Location in $IncludeGeoLocation) {
                IF ($CurrentLocation.State -like $Location -or $CurrentLocation.Country -like $Location) {
                    $LocationMatch = $True
                    break
                }
            }

            ### Pass Match
            IF ($LocationMatch) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking for geo location inclusion. Geo location [$($CurrentLocation.State), $($CurrentLocation.Country)] matches [$IncludeGeoLocation]." }
            ### Fail No Match
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking for geo location inclusion. Geo location [$($CurrentLocation.State), $($CurrentLocation.Country)] doesn't match [$IncludeGeoLocation]. Skipping install."; $Result.Success = $True; $Result.Details = "Geo Location not Included"; RETURN RETURN-Results }
        }


        ### ============================
        ### === Exclude Geo Location ===
        ### ============================
        IF (Test-NotNull $ExcludeGeoLocation) {
            $LocationMatch = $False
            $CurrentLocation = $IPInfo
            FOREACH ($Location in $ExcludeGeoLocation) {
                IF ($CurrentLocation.State -like $Location -or $CurrentLocation.Country -like $Location) {
                    $LocationMatch = $True
                    break
                }
            }

            ### Pass Match
            IF (!$LocationMatch) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking for geo location exclusion. Geo location [$($CurrentLocation.State), $($CurrentLocation.Country)] doesn't match [$ExcludeGeoLocation]." }
            ### Fail No Match
            ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking for geo location exclusion. Geo location [$($CurrentLocation.State), $($CurrentLocation.Country)] matches [$ExcludeGeoLocation]. Skipping install."; $Result.Success = $True; $Result.Details = "Geo Location Excluded"; RETURN RETURN-Results }
        }
    }

    
    ### ========================
    ### === Action Pre-Check ===
    ### ========================
    $ApplicationIsInstalled = $null
    $ApplicationNeedsUpdated = $null
    $CustomVersionResult = $null

    IF ($True) {
        IF ($Action -eq "Uninstall") { $Result.RequestedVersion = $null }

        ### Check if App is Installed
        IF ((Test-NotNull $CustomInstallVerification)) {
            $CustomInstallResult = Invoke-Expression -Command $CustomInstallVerification
            IF ((Test-NotNull $CustomInstallResult)) { $ApplicationIsInstalled = $True }
            ELSE { $ApplicationIsInstalled = $False }    
        }
        ELSE {
            $GetApp = GET-ApplicationInstalled -Name $ApplicationName -ExactMatch
            IF ((Test-NotNull $GetApp)) { $ApplicationIsInstalled = $True }
            ELSE { $ApplicationIsInstalled = $False }  
        }
    
        ### Check if App Needs Updated
        IF ((Test-NotNull $ApplicationIsInstalled)) {
            IF ((Test-NotNull $CustomVersionCommand)) {
                $CustomVersionResult = Invoke-Expression -Command $CustomVersionCommand
                IF ($ExactVersion) {
                    IF ([Version]$CustomVersionResult -eq [Version]$ApplicationVersion) { $ApplicationNeedsUpdated = $False }
                    ELSE { $ApplicationNeedsUpdated = $True }     
                }
                ELSE { 
                    IF ([Version]$CustomVersionResult -ge [Version]$ApplicationVersion) { $ApplicationNeedsUpdated = $False }
                    ELSE { $ApplicationNeedsUpdated = $True }   
                } 
            }
            ELSE {
                $CustomVersionResult = (GET-ApplicationInstalled -Name $ApplicationName -ExactMatch).Version
                IF ($ExactVersion) {
                    IF ([Version]$CustomVersionResult -eq [Version]$ApplicationVersion) { $ApplicationNeedsUpdated = $False }
                    ELSE { $ApplicationNeedsUpdated = $True }  
                }
                ELSE {
                    IF ([Version]$CustomVersionResult -ge [Version]$ApplicationVersion) { $ApplicationNeedsUpdated = $False }
                    ELSE { $ApplicationNeedsUpdated = $True }   
                }
            }
        } 
        ELSE { $ApplicationNeedsUpdated = $True }
        IF ($UpdateMethod -eq "NoUpdate") { $ApplicationNeedsUpdated = $False }
        
        ### If Verify Only
        IF ($VerifyOnly) {
            ### Uninstall
            IF ($ApplicationIsInstalled -eq $False -and $Action -eq "Uninstall") { Write-Host "$($(Get-Date).ToShortTimeString()): Application already uninstalled."; $Result.Success = $True; $Result.Details = "Already Uninstalled"; RETURN RETURN-Results }
            IF ($ApplicationIsInstalled -eq $True -and $Action -eq "Uninstall") { Write-Host "$($(Get-Date).ToShortTimeString()): Application not uninstalled. Verify only."; $Result.Success = $False; $Result.Details = "Not Uninstalled (Verify Only)"; RETURN RETURN-Results }

            ### Install
            IF ($ApplicationIsInstalled -eq $True -and $Action -eq "Install" -and $ApplicationNeedsUpdated -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): Application already installed."; $Result.Success = $True; $Result.Details = "Already Installed"; RETURN RETURN-Results }
            IF ($ApplicationIsInstalled -eq $False -and $Action -eq "Install" -and $ApplicationNeedsUpdated -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): Application not installed. Verify only."; $Result.Success = $False; $Result.Details = "Not Installed (Verify Only)"; RETURN RETURN-Results }
            IF ($ApplicationIsInstalled -eq $True -and $Action -eq "Install" -and $ApplicationNeedsUpdated -eq $True) { Write-Host "$($(Get-Date).ToShortTimeString()): Application not up to date. Verify only."; $Result.Success = $False; $Result.Details = "Needs Updated (Verify Only)"; RETURN RETURN-Results }
            IF ($ApplicationIsInstalled -eq $False -and $Action -eq "Install" -and $ApplicationNeedsUpdated -eq $True) { Write-Host "$($(Get-Date).ToShortTimeString()): Application not installed. Verify only."; $Result.Success = $False; $Result.Details = "Not Installed (Verify Only)"; RETURN RETURN-Results }

            ### Update
            IF ($ApplicationIsInstalled -eq $True -and $Action -eq "Update" -and $ApplicationNeedsUpdated -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): Application already up to date."; $Result.Success = $True; $Result.Details = "Already Up to Date"; RETURN RETURN-Results }
            IF ($ApplicationIsInstalled -eq $True -and $Action -eq "Update" -and $ApplicationNeedsUpdated -eq $True) { Write-Host "$($(Get-Date).ToShortTimeString()): Application not up to date. Verify only."; $Result.Success = $False; $Result.Details = "Needs Updated (Verify Only)"; RETURN RETURN-Results }
            IF ($ApplicationIsInstalled -eq $False -and $Action -eq "Update" -and $ApplicationNeedsUpdated -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): Application not installed, no update needed."; $Result.Success = $True; $Result.Details = "No Update Needed (Not Installed)"; RETURN RETURN-Results }
            IF ($ApplicationIsInstalled -eq $False -and $Action -eq "Update" -and $ApplicationNeedsUpdated -eq $True) { Write-Host "$($(Get-Date).ToShortTimeString()): Application not installed, no update needed."; $Result.Success = $True; $Result.Details = "No Update Needed (Not Installed)"; RETURN RETURN-Results }

            Write-Host "$($(Get-Date).ToShortTimeString()): Verify requested but not applicable for $Action action."; $Result.Success = $False; $Result.Details = "Verify Action Not Applicable"; RETURN RETURN-Results
        }
        
        ### If Uninstall and Already Uninstalled
        IF ($ApplicationIsInstalled -eq $false -and $Action -eq "Uninstall") { Write-Host "$($(Get-Date).ToShortTimeString()): Application already uninstalled."; $Result.Success = $True; $Result.Details = "Already Uninstalled"; RETURN RETURN-Results }
    
        ### If Install and Already Installed
        IF ($ApplicationIsInstalled -eq $true -and $Action -eq "Install" -and $ApplicationNeedsUpdated -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): Application already installed."; $Result.Success = $True; $Result.Details = "Already Installed"; RETURN RETURN-Results }

        ### If Update and Already Up to Date
        IF ($ApplicationIsInstalled -eq $true -and $Action -eq "Update" -and $ApplicationNeedsUpdated -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): Application already up to date."; $Result.Success = $True; $Result.Details = "Already Up to Date"; RETURN RETURN-Results }
        IF ($ApplicationIsInstalled -eq $false -and $Action -eq "Update") { Write-Host "$($(Get-Date).ToShortTimeString()): Application already up to date."; $Result.Success = $True; $Result.Details = "Not Installed, No Update Needed"; RETURN RETURN-Results }

        ### If Run and Already Installed
        IF ($Action -eq "Run" -and $ApplicationIsInstalled) { $Result.Success = $True; $Result.Details = "Already Installed"; RETURN RETURN-Results }
    }

    ### =======================
    ### === Initial Message ===
    ### =======================

    IF ($Action -eq "Install") {
        IF ($ApplicationIsInstalled -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Not installed. Processing request." }
        ELSEIF ($ApplicationIsInstalled -eq $True -and $ApplicationNeedsUpdated -eq $True -and $ExactVersion -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Old version [$CustomVersionResult] found. Processing [$Action] request." }
        ELSEIF ($ApplicationIsInstalled -eq $True -and $ApplicationNeedsUpdated -eq $True -and $ExactVersion -eq $True) { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Incorrect version [$CustomVersionResult] found. Processing [$Action] request." }
    }
    ELSEIF ($Action -eq "Uninstall") {
        IF ($ApplicationIsInstalled -eq $True) { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Install found. Processing [$Action] request." }
    }
    ELSEIF ($Action -eq "Download") {
        IF ($ApplicationIsInstalled -eq $True) { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Processing [$Action] request." }
    }
    ELSEIF ($Action -eq "Reinstall") { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Processing [$Action] request." }
    ELSEIF ($Action -eq "Update") {
        IF ($ApplicationNeedsUpdated -eq $True -and $ExactVersion -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Old version [$CustomVersionResult] found. Processing [$Action] request." }
        ELSEIF ($ApplicationNeedsUpdated -eq $True -and $ExactVersion -eq $True) { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Incorrect version [$CustomVersionResult] found. Processing [$Action] request." }
    }
    ELSEIF ($Action -eq "Run") {
        IF ($ApplicationIsInstalled -eq $True) { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Install found. Processing [$Action] request." }
        ELSEIF ($ApplicationIsInstalled -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): [$Action] of [$ApplicationName] requested. Install not found. Processing [$Action] request." }
    }

    ### ==============================
    ### === Action Processing Loop ===
    ### ==============================
    $TryCount = 0
    $Success = $False
    $ApplicationInstallerPath = $null
    WHILE (!$Success) {

        ### =========================
        ### === Trycount Tracking ===
        ### =========================
        IF ($TryCount -gt $RetryCount) { Write-Host "$($(Get-Date).ToShortTimeString()): Retry count exceeded."; RETURN RETURN-Results }
        IF ($TryCount -gt 0) { Write-Host "$($(Get-Date).ToShortTimeString()): Attempt $($TryCount) failed. Trying again..." }
        IF ($TryCount -gt 0) { $ForceDownload = $True } ### Sets Force Download so any Subsequent Download Attempts Force a Redownload (in case of corrupt downloads causing a problem)
        IF ($TryCount -gt 1) { 
            IF (!(Test-NotNull $BackupDownloadLink)) { Write-Host "$($(Get-Date).ToShortTimeString()): Retry count exceeded."; RETURN RETURN-Results }
            $DownloadLink = $BackupDownloadLink
            $FileName = $BackupFileName
            $DownloadHash = $BackupDownloadHash
        }

        IF (Test-NotNull $CustomInstallCommand) { $ApplicationInstallerPath = $CustomInstallCommand }         
        ELSEIF ($FileName -like "*.zip") { $ApplicationInstallerPath = "$($SavePath)\$($($ApplicationName).Replace('*',''))\$($ZipInstallerPath)" } 
        ELSE { $ApplicationInstallerPath = "$($SavePath)\$($FileName)" }
        
        $TryCount++

        
        ### ======================
        ### === Download Phase ===
        ### ======================
        IF ($Action -eq "Uninstall" -or !(Test-NotNull $DownloadLink)) { $Result.Version = $null }
        ELSE {
            $DownloadStart = Get-Date   
            Write-Host "$($(Get-Date).ToShortTimeString()): Starting Download of [$FileName] from [$DownloadLink]... " -NoNewline
            IF ((Run-FileDownload -FileName $FileName -SavePath $SavePath -URL $DownloadLink -Force:$ForceDownload -BasicOutput) -eq $false) { 
                Write-Host "Download attempt failed after $([MATH]::Round($(((Get-Date) - $DownloadStart).TotalSeconds),0)) second(s)." 
                CONTINUE 
            }            
            Write-Host "Download completed successfully in $([MATH]::Round($(((Get-Date) - $DownloadStart).TotalSeconds),0)) second(s)."    
                

            ### Check for Zip File
            IF ($FileName -like "*.zip") { Write-Host "$($(Get-Date).ToShortTimeString()): Unzipping files to ["$($SavePath)\$($($ApplicationName).Replace('*',''))\"]."
                Expand-Archive -Path "$($SavePath)\$($FileName)" -DestinationPath "$($SavePath)\$($($ApplicationName).Replace('*',''))\" -Force 
                IF ((GET-ChildItem -Path $ApplicationInstallerPath -ErrorAction SilentlyContinue)) { Write-Host "$($(Get-Date).ToShortTimeString()): Verifying Zip Installer File... Installer File Found: [$($ApplicationInstallerPath)]" }
                ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Verifying Zip Installer File... Installer File Not Found: [$($ApplicationInstallerPath)]"; CONTINUE }  
            }          
            
            ### If Download Only
            IF ($Action -eq "Download") { $Result.Action = "Download"; $Result.Success = $True; Write-Host "$($(Get-Date).ToShortTimeString()): Download only specified. Done."; RETURN RETURN-Results }
        }   
        
        
        ### =======================
        ### === Security Checks ===
        ### =======================
       
        IF ($True -and $Action -ne "Uninstall") {       
            ### Virus Total Hash Verification
            IF ($VirusTotal) {
                $VirusTotalResult = (Test-VirusTotalHash -FilePath "$($SavePath)\$($FileName)")           
                IF ($VirusTotalResult) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking file hash against VirusTotal database. Found. Clean." }
                ELSEIF ($VirusTotalResult -eq $False) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking file hash against VirusTotal database. Found. Not Clean. Blocking install."; CONTINUE }
                ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking file hash against VirusTotal database. Not found. Blocking install."; CONTINUE }
            }
            
            ### Cert Verification
            IF ($CertVerification -or $CertName) {
                $CertCheck = (Get-AuthenticodeSignature -FilePath "$($SavePath)\$($FileName)")  
            
                IF ($CertCheck.Status -eq "Valid") { Write-Host "$($(Get-Date).ToShortTimeString()): Checking cert validity... cert is valid." }
                ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Signature on installer file is not valid. Blocking install."; $Result.Success = $False; $Result.Details = "Cert Not Valid"; CONTINUE }
            
                    
                IF ($CertName -ne $null) { 
                    IF ($CertCheck.SignerCertificate.SubjectName.Name -like $CertName) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking cert name for [$Certname]... cert name matches." }
                    ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Signature name did not match [$CertName]. Blocking install."; $Result.Success = $False; $Result.Details = "Cert Name Doesn't Match"; CONTINUE }
                }            
            }
            
            ### Download Hash Check
            IF ($DownloadHash) {
                $DownloadedHash = (Get-FileHash -Path "$($SavePath)\$($FileName)" -Algorithm SHA256).Hash
                IF ($DownloadedHash -eq $DownloadHash) { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Hash. Requested hash [$DownloadHash] matches download hash [$DownloadedHash]." }
                ELSE { Write-Host "$($(Get-Date).ToShortTimeString()): Checking Hash. Requested hash [$DownloadHash] doesn't match download hash [$DownloadedHash]. Blocking install."; $Result.Success = $False; $Result.Details = "Hash Doesn't Match"; CONTINUE }
            }            
        }


        ### =======================
        ### === Uninstall Phase ===
        ### =======================
         
        IF ($True) {       
            ### Check for Uninstall Action Missing Uninstall Command
            IF ($Action -eq "Uninstall" -or 
                ($Action -eq "Reinstall" -and $ApplicationIsInstalled -eq $True) -or 
                ($Action -eq "Update" -and ($UpdateMethod -eq "UninstallReinstall" -or $ExactVersion) -and $ApplicationNeedsUpdated -eq $True) -or
                ($Action -eq "Install" -and $ApplicationIsInstalled -eq $True -and $ApplicationNeedsUpdated -eq $True -and ($UpdateMethod -eq "UninstallReinstall" -or $ExactVersion))) {
                IF (!(Test-NotNull $UninstallCommand)) { 
                    $GetApp = Get-ApplicationInstalled -Name $ApplicationName -ExactMatch
                    IF ($GetApp.UninstallCommand -like "msiexec.exe*") { $Split = ($GetApp.UninstallCommand -split " ").Replace("/X {","/X{"); $UninstallCommand = $Split[0]; $UninstallArguments = $Split[1].Replace("/I{","/X{") + " /QN" }
                    ELSEIF ($GetApp.UninstallCommand -like "*unins000.exe*") { $Split = $GetApp.UninstallCommand -split '"'; $UninstallCommand = $Split[1]; $UninstallArguments = "/silent /verysilent /norestart /SUPPRESSMSGBOXES" }
                    ELSE {
                        Write-Host "$($(Get-Date).ToShortTimeString()): Unable to uninstall. No uninstall command provided. Use the -UninstallCommand and -UninstallArguements parameters."
                        $Result.Success = $False
                        $Result.Details = "Uninstall Command Not Found"
                        RETURN RETURN-Results   
                    }
                }
            }

            ### Uninstall If Needed
            IF ($Action -eq "Uninstall" -or 
                ($Action -eq "Reinstall" -and $ApplicationIsInstalled -eq $True) -or 
                ($Action -eq "Update" -and ($UpdateMethod -eq "UninstallReinstall" -or $ExactVersion) -and $ApplicationNeedsUpdated -eq $True) -or
                ($Action -eq "Install" -and $ApplicationIsInstalled -eq $True -and $ApplicationNeedsUpdated -eq $True -and ($UpdateMethod -eq "UninstallReinstall" -or $ExactVersion))) {
            
                ### End Requested PreProcesses
                IF (Test-NotNull $PreUninstallEndProcess) {
                    #Write-Host "$($(Get-Date).ToShortTimeString()): Ending Requested Processses..."
                    $Now = (Get-Date).AddSeconds(20)
                    While ((Get-Date) -lt $Now -and (Get-Process $PreUninstallEndProcess -ErrorAction SilentlyContinue) -ne $null) { Get-Process $PreUninstallEndProcess -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue -Force; Start-Sleep -Seconds 2 }
                    IF (Get-Process $PreUninstallEndProcess -ErrorAction SilentlyContinue) { Write-Host "$($(Get-Date).ToShortTimeString()): Pre-Uninstall processess not ended. Attempting uninstall anyway." }
                    ELSE { #Write-Host "$($(Get-Date).ToShortTimeString()): Pre-uninstall processes ended successfully."
                    }
                }   

                ### Starting Uninstall
                Get-Process MSIEXEC -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
                Start-Sleep -Seconds 1
                $StartUninstall = Get-Date
                $UninstallProcess = $null

                IF ($InvokeUninstallCommand) { Invoke-Expression -Command $UninstallCommand }
                ELSE {
                    IF (!(Test-NotNull $UninstallArguments)) { 
                        $UninstallProcess = Start-Process -FilePath $UninstallCommand -PassThru 
                    }
                    ELSE { 
                        $UninstallProcess = Start-Process -FilePath $UninstallCommand -ArgumentList $UninstallArguments -PassThru 
                    }                
                    IF ($UninstallTimeout -eq 0) { 
                        Write-Host "$($(Get-Date).ToShortTimeString()): Started uninstall. Waiting for Uninstall to Complete..."
                        Start-Sleep -Seconds 1
                        IF (Test-NotNull $UninstallKeystrokes) { Invoke-Expression -Command $UninstallKeystrokes }
                        Wait-Process -ID $UninstallProcess.ID -ErrorAction SilentlyContinue 
                    }
                    ELSE { 
                        Write-Host "$($(Get-Date).ToShortTimeString()): Started uninstall. Waiting up to $UninstallTimeout seconds for uninstall to complete..."
                        Start-Sleep -Seconds 1
                        IF (Test-NotNull $UninstallKeystrokes) { Invoke-Expression -Command $UninstallKeystrokes }
                        Wait-Process -ID $UninstallProcess.ID -Timeout $UninstallTimeout -ErrorAction SilentlyContinue 
                    }
                                
                    Stop-Process -ID $UninstallProcess.ID -Force -ErrorAction SilentlyContinue
                    Get-Process MSIEXEC -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
                }

                ### End Requested PostProcesses
                IF (Test-NotNull $PostUninstallEndProcess) {
                    #Write-Host "$($(Get-Date).ToShortTimeString()): Ending Requested Processses..."
                    $Now = (Get-Date).AddSeconds(20)
                    While ((Get-Date) -lt $Now -and (Get-Process $PostUninstallEndProcess -ErrorAction SilentlyContinue) -ne $null) { Get-Process $PostUninstallEndProcess -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue -Force; Start-Sleep -Seconds 2 }
                    IF (Get-Process $PostUninstallEndProcess -ErrorAction SilentlyContinue) { Write-Host "$($(Get-Date).ToShortTimeString()): Post-Uninstall processess not ended. Continuing anyway." }
                    ELSE { #Write-Host "$($(Get-Date).ToShortTimeString()): Post-uninstall processes ended successfully."
                    }
                }  

                

                Start-Sleep -Seconds $PostUninstallDelay
                Write-Host "$($(Get-Date).ToShortTimeString()): Uninstall finished in $([MATH]::Round($(((Get-Date) - $StartUninstall).TotalSeconds),0)) second(s). Verifying..."            
                
                $GetAppUninstall = Invoke-Expression -Command $CustomUninstallVerification 

                ### Checking if Uninstall was Successful
                IF (!$GetAppUninstall -and $Action -eq "Uninstall") {
                    Write-Host "$($(Get-Date).ToShortTimeString()): Uninstall failed. Application Still Installed." 
                    $Result.Success = $False
                    $Result.Details = "Uninstall Failed"
                    CONTINUE
                }
                ELSEIF (!$GetAppUninstall -and $Action -eq "Reinstall") {
                    Write-Host "$($(Get-Date).ToShortTimeString()): Uninstall failed. Application Still Installed." 
                    $Result.Success = $False
                    $Result.Details = "Uninstall for Reinstall Failed"
                    CONTINUE
                }
                ELSEIF (!$GetAppUninstall -and $Action -eq "Update") {
                    Write-Host "$($(Get-Date).ToShortTimeString()): Uninstall failed. Application Still Installed." 
                    $Result.Success = $False
                    $Result.Details = "Uninstall for Update Failed"
                    CONTINUE
                }  
                ELSEIF (!$GetAppUninstall -and $Action -eq "Install") {
                    Write-Host "$($(Get-Date).ToShortTimeString()): Uninstall failed. Application Still Installed." 
                    $Result.Success = $False
                    $Result.Details = "Uninstall for Update Failed"
                    CONTINUE
                }           
                ELSEIF ($Action -eq "Uninstall") { Write-Host "$($(Get-Date).ToShortTimeString()): Application Uninstalled Successfully. Done."; $Result.Success = $True; $Result.Details = $null; RETURN RETURN-Results }

                Write-Host "$($(Get-Date).ToShortTimeString()): Application Uninstalled Successfully."
            }
        }

   
        ### =====================
        ### === Install Phase ===
        ### =====================

        ### End Requested PostProcesses
        $Now = (Get-Date).AddSeconds(20)
        IF ((Test-NotNull $PreInstallEndProcess)) {
            #Write-Host "$($(Get-Date).ToShortTimeString()): Ending Requested Install Processses."
            While ((Get-Date) -lt $Now -and (Get-Process $PreInstallEndProcess -ErrorAction SilentlyContinue) -ne $null) { Get-Process $PreInstallEndProcess -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue -Force; Start-Sleep -Seconds 2 }
            IF (Get-Process $PreInstallEndProcess -ErrorAction SilentlyContinue) { Write-Host "$($(Get-Date).ToShortTimeString()): Pre-install processess not ended. Continuing anyway." }
            ELSE { #Write-Host "$($(Get-Date).ToShortTimeString()): Pre-install processes ended successfully."
            }
        }

        ### Install Application
        Get-Process MSIEXEC -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
        Start-Sleep -Seconds 1
        Write-Host "$($(Get-Date).ToShortTimeString()): Starting [$ApplicationName] install." -NoNewline
        $StartInstall = Get-Date
        $InstallProcess = $null

        IF ($InvokeInstallCommand) { Invoke-Expression -Command $CustomInstallCommand }
        ELSE {
            IF (!(Test-NotNull $InstallArguments)) { $InstallProcess = Start-Process -FilePath $ApplicationInstallerPath -PassThru }
            ELSE { $InstallProcess = Start-Process -FilePath $ApplicationInstallerPath -Args $InstallArguments -PassThru }
            IF ($InstallTimeout -eq 0) { 
            Write-Host " Waiting for install to complete..." -NoNewline
            Start-Sleep -Seconds 1
            IF (Test-NotNull $InstallKeystrokes) { Invoke-Expression -Command $InstallKeystrokes }
            Wait-Process $InstallProcess.ID -ErrorAction SilentlyContinue 
        }        
            ELSE { 
            Write-Host " Waiting up to [$InstallTimeout] seconds for install to complete..." -NoNewline
            Start-Sleep -Seconds 1 
            IF (Test-NotNull $InstallKeystrokes) { Invoke-Expression -Command $InstallKeystrokes }
            Wait-Process $InstallProcess.ID -Timeout $InstallTimeout -ErrorAction SilentlyContinue 
        }               
                
            Stop-Process -ID $InstallProcess.ID -Force -ErrorAction SilentlyContinue
            Get-Process MSIEXEC -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
        }

        Start-Sleep -Seconds $PostInstallDelay
        Write-Host " Install finished in $([MATH]::Round($(((Get-Date) - $StartInstall).TotalSeconds),0)) second(s)."    
        
        ### End Requested PostProcesses
        $Now = (Get-Date).AddSeconds(20)
        IF ((Test-NotNull $PostInstallEndProcess)) {
            #Write-Host "$($(Get-Date).ToShortTimeString()): Ending Requested Install Processses."
            While ((Get-Date) -lt $Now -and (Get-Process $PostInstallEndProcess -ErrorAction SilentlyContinue) -ne $null) { Get-Process $PostInstallEndProcess -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue -Force; Start-Sleep -Seconds 2 }
            IF (Get-Process $PostInstallEndProcess -ErrorAction SilentlyContinue) { Write-Host "$($(Get-Date).ToShortTimeString()): Post-install processess not ended. Continuing anyway." }
            ELSE { #Write-Host "$($(Get-Date).ToShortTimeString()): Post-install processes ended successfully."
            }
        }
        Write-Host "$($(Get-Date).ToShortTimeString()): Verifying install of [$ApplicationName]... " -NoNewline
        ### Check Results
        $InstallResult = Invoke-Expression -Command "$CustomInstallVerification"
        $InstallVersion = $null
        IF ((Test-NotNull $CustomVersionCommand)) { $InstallVersion = Invoke-Expression -Command $CustomVersionCommand }
        ELSE { $InstallVersion = (Get-ApplicationInstalled "$ApplicationName" -ExactMatch).Version }

        $InstalledAppName = $null
        $InstalledApp = (Get-ApplicationInstalled -Name $ApplicationName -ExactMatch)
        IF ($InstalledApp) { $InstalledAppName = $InstalledApp.Name }
        ELSE { $InstalledAppName = $ApplicationName } 

        ### If Reinstall
        IF ($Action -eq "Reinstall") {
            IF ($InstallResult) {
                Write-Host "Application reinstall successful. Done."
                $Result.Name = $InstalledAppName
                $Result.Version = $InstallVersion       
                $Result.Success = $True
                $Result.Details = $null

                IF ($InstallVersion -lt $ApplicationVersion) { $Result.Success = $False; $Result.Details = "Application Reinstalled, but Old Version" }

                RETURN RETURN-Results
            }      
            ELSE {
                Write-Host "Application reinstall unsuccesful."
                $Result.Success = $False
                $Result.Details = "Reinstall Unsuccessful"
                CONTINUE
            }
        }
        ### If Update
        ELSEIF ($Action -eq "Update") {
            IF ($InstallResult) {
                Write-Host "Application update successful. Done."
                $Result.Name = $InstalledAppName
                $Result.Version = $InstallVersion      
                $Result.Success = $True
                $Result.Details = $null

                IF ($InstallVersion -lt $ApplicationVersion) { $Result.Success = $False; $Result.Details = "Application is Updated, but Old Version" }

                RETURN RETURN-Results
            }
            ELSE {
                Write-Host "Application update unsuccesful."
                $Result.Success = $False
                $Result.Details = "Update Unsuccessful"
                CONTINUE
            }    
        }
        ### If Install
        ELSE {
            IF ($InstallResult) {
                Write-Host "Application install successful. Done."
                $Result.Name = $InstalledAppName
                $Result.Version = $InstallVersion       
                $Result.Success = $True
                $Result.Details = $null

                IF ($InstallVersion -lt $ApplicationVersion) { $Result.Success = $False; $Result.Details = "Application is Installed, but Old Version" }

                RETURN RETURN-Results
            }
            ELSE {
                Write-Host "Application Install Unsuccesful."
                $Result.Success = $False
                $Result.Details = "Install Unsuccessful"
                CONTINUE
            }
        }

        ### Set Progress Bar Back to Original Setting
        $ProgressPreference = $ProgressPreferenceTemp

        RETURN RETURN-Results
    }
}
FUNCTION Run-DeploymentSet {
    
    [CmdletBinding()]
    PARAM (
        [Parameter(Mandatory)]
        [STRING[]]$Deployments,
        [STRING[]]$StartASync,
        [INT]$ASyncTimeout = $null,
        [SWITCH]$RunWinGetUpdate,
        [SWITCH]$ResultsToDesktop = $True
    )

    $SessionStartTime = (Get-Date)

    $Results = @()
    $DeploymentCount = $Deployments.Count
    $CurrentCount = 0

    $DateText = $(Get-Date).ToString()
    $IPInfo = Get-IPInfo -Verbose:$false
    $LocationLength = ($IPInfo.City).Length + ($IPInfo.State).Length

    Write-Host ""
    Write-Host "$($(Get-Date).ToShortTimeString()): ### ===================================================== ###"
    Write-Host "$($(Get-Date).ToShortTimeString()): ### Starting New Integris Deployment Tool Session ###"
    Write-Host "$($(Get-Date).ToShortTimeString()): ### ###"
    Write-Host "$($(Get-Date).ToShortTimeString()): ### Start Time : $($($DateText).PadRight(37," "))###"
    Write-Host "$($(Get-Date).ToShortTimeString()): ### Public IP : $($($IPInfo.IP).PadRight(37," "))###"
    Write-Host "$($(Get-Date).ToShortTimeString()): ### Location : $($IPInfo.City), $($IPInfo.State) $($($IPInfo.ZipCode).PadRight(34-$LocationLength," "))###"
    Write-Host "$($(Get-Date).ToShortTimeString()): ### ===================================================== ###"
    #Write-Verbose ""
    #Write-Verbose "$($(Get-Date).ToShortTimeString()): Setting Execution Policy to Remote Signed for this PowerShell process."
    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force

    $Jobs = @()

    IF (Test-NotNull $StartASync) {
        Write-Host ""
        Write-Host "$($(Get-Date).ToShortTimeString()): ### ========================================= ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### Starting Asynchronous Jobs ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### ========================================= ###"
        Write-Host ""
    }

    FOREACH ($Item in $StartASync) {
        Write-Host "$($(Get-Date).ToShortTimeString()): Starting Asynchronous Job: [$Item]"
        $Jobs += Start-Job -ScriptBlock { Invoke-Expression $($Using:Item) }
        Start-Sleep -Seconds 1
    }   

    
    FOREACH ($Deployment in $Deployments) {

 
    
        $CurrentCount++
        $CountLength = $CurrentCount.ToString().Length
        $ActionText = $Deployment -split " "
        Write-Host ""
        Write-Host "$($(Get-Date).ToShortTimeString()): ### ========================================= ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### Step: $CurrentCount of $($DeploymentCount.ToString().PadRight(26-$CountLength," ")) ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### Package: $($($ActionText[0]).PadRight(30," ")) ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### ========================================= ###"
        
        $Results += Invoke-Expression "$Deployment"

        $Results | Select Action, Duration, Name, Version, Success, Details | FT | Out-File "C:\Users\Public\Desktop\IDTResults.txt"
    }


    IF ($RunWinGetUpdate -eq $True -and (Ensure-Winget) -eq $true) {

        $WinGetStartTime = (Get-Date)
        $Results2 = Run-WinGetAppUpdates $Results
        $Results3 = Remove-NullEntriesInObject $Results2

        $Results3 += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Action = "Update"
            Duration = (Get-TimeDifferenceToString $WinGetStartTime)
            RequestedName = $Null
            Name = "WinGet Update All"
            RequestedVersion = $Null
            Version = $Null
            UpdatedVersion = $Null
            Success = $True
            Details = $Null
        }

        $Results3 += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Action = "Total"
            Duration = (Get-TimeDifferenceToString $SessionStartTime)
            RequestedName = $Null
            Name = $Null
            RequestedVersion = $Null
            Version = $Null
            UpdatedVersion = $Null
            Success = $Null
            Details = $Null
        }

        IF ($ResultsToDesktop) { $Results3 | Select Action, Duration, Name, Version, UpdatedVersion, Success, Details | FT | Out-File "C:\Users\Public\Desktop\IDTResults.txt" }
        RETURN $Results3 | Select Action, Duration, Name, Version, UpdatedVersion, Success, Details
    }


    $SecondsLeft = [int]($SessionStartTime - ((Get-Date).AddMinutes(-$ASyncTimeout))).TotalSeconds

    IF ($SecondsLeft -ge 0) { 
        Write-Host "$($(Get-Date).ToShortTimeString()): Waiting [$SecondsLeft] seconds for asynchronous jobs to complete... " -NoNewline
        Wait-Job -Job $Jobs -Timeout ($SessionStartTime - ((Get-Date).AddMinutes(-$ASyncTimeout))).TotalSeconds
        Write-Host "Asynchronous jobs complete."
    }

    $Results += [PSCustomObject]@{
        Action = "Total"
        Duration = (Get-TimeDifferenceToString $SessionStartTime)
        RequestedName = $Null
        Name = $Null
        RequestedVersion = $Null
        Version = $Null
        Success = $Null
        Details = $Null
    }
    
    IF ($ResultsToDesktop) { $Results | Select Action, Duration, Name, Version, Success, Details | FT | Out-File "C:\Users\Public\Desktop\IDTResults.txt" } 
    RETURN $Results | Select Action, Duration, Name, Version, Success, Details
}
FUNCTION Run-WinGetAppUpdates {
    
    [CmdletBinding()]
    PARAM (
        [Parameter(Mandatory)]
        $Results
    )

    $NewResults = @()

    IF (Ensure-Winget) { } ELSE { IF (Ensure-Winget) { Write-Host "Found WinGet" } ELSE { Write-Warning "Unable to install WinGet. You must install WinGet before you can use this command." } }

    
    Write-Host ""
    Write-Host "$($(Get-Date).ToShortTimeString()): ### ============================================== ###"
    Write-Host "$($(Get-Date).ToShortTimeString()): ### Starting WinGet Update Session ###"
    Write-Host "$($(Get-Date).ToShortTimeString()): ### This Could Take a While... ###"
    Write-Host "$($(Get-Date).ToShortTimeString()): ### ============================================== ###"
    winget update --all --accept-package-agreements --accept-source-agreements | Out-Null

    Write-Host ""
    Write-Host "$($(Get-Date).ToShortTimeString()): WinGet Update is Done Running. Finalizing Results." 
    Start-Sleep 3


    FOREACH ($Result in $Results) {
        
        ### All Configured
        IF ($Result.Action -eq "Configure") {
            $NewResults += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                Action = $Result.Action
                Duration = $Result.Duration
                RequestedName = $Result.RequestedName
                Name = $Result.Name
                RequestedVersion = $Result.RequestedVersion
                Version = $Result.Version
                UpdatedVersion = $null
                Success = $Result.Success
                Details = $Result.Details
            }
            continue
        }
        ### All Uninstalled
        IF ($Result.Action -eq "Uninstall") {
            $NewResults += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                Action = $Result.Action
                Duration = $Result.Duration
                RequestedName = $Result.RequestedName
                Name = $Result.Name
                RequestedVersion = $Result.RequestedVersion
                Version = $Result.Version
                UpdatedVersion = $null
                Success = $Result.Success
                Details = $Result.Details
            }
            continue
        }
        ### All Uninstalled
        IF ($Result.Action -eq "Verify") {
            $NewResults += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                Action = $Result.Action
                Duration = $Result.Duration
                RequestedName = $Result.RequestedName
                Name = $Result.Name
                RequestedVersion = $Result.RequestedVersion
                Version = $Result.Version
                UpdatedVersion = $null
                Success = $Result.Success
                Details = $Result.Details
            }
            continue
        }

        $NewApplicationInfo = Get-ApplicationInstalled | Where-Object { $_.Name -like "$($Result.RequestedName)" }
        $ResultDetails = $null
        $UpdatedVersion = $Null

        ### If Updated Version is Greater than Original Version
        IF ([VERSION]$NewApplicationInfo.Version -gt [VERSION]$Result.Version) { $UpdatedVersion = [VERSION]$NewApplicationInfo.Version }

        ### If Requested Version is NULL
        IF ($Result.RequestedVersion -eq $null) { $ResultSuccess = $Result.Success } 
        ### If Installed Version >= Requested Version
        ELSEIF ([VERSION]$Result.RequestedVersion -le [VERSION]$Result.Version -or
            [VERSION]$Result.RequestedVersion -le [VERSION]$NewApplicationInfo.Version) {
            $ResultSuccess = $True   
            $ResultDetails = $null     
        }
        ELSE { $ResultSuccess = $False; $ResultDetails = "Version Older than Requested" }  

        $NewResults += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Action = $Result.Action
            Duration = $Result.Duration 
            RequestedName = $Result.RequestedName
            Name = $Result.Name
            RequestedVersion = $Result.RequestedVersion
            Version = $Result.Version
            UpdatedVersion = $UpdatedVersion
            Success = $ResultSuccess
            Details = $ResultDetails
        }
    }

    RETURN $NewResults
}


### Package Templates
FUNCTION App-PackageTemplate {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = $null
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = $null       
        FileName                    = $null               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = $null
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION Verify-PackageTemplate {
    
    [CmdletBinding()]
    PARAM ( )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Verify"
        Duration = $null
        RequestedName = $null
        Name = $null
        RequestedVersion = $null
        Version = $null
        Success = $False
        Details = $null
    }

    ### Return Results Function
    FUNCTION Return-Results {
        $Result.Duration = (Get-TimeDifferenceToString $StartTime)
        IF ((Get-PSCallStack).Command -like "*DeploymentSet*") { RETURN $Result | Select Action, Duration, RequestedName, Name, RequestedVersion, Version, Success, Details }
        ELSE { RETURN $Result | Select Action, Duration, Name, Version, Success, Details }
    }

   
    
   

    ### End
    RETURN Return-Results
}
FUNCTION Configure-PackageTemplate {
    
    [CmdletBinding()]
    PARAM ( )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Configure"
        Duration = $null
        RequestedName = $null
        Name = $null
        RequestedVersion = $null
        Version = $null
        Success = $False
        Details = $null
    }

    ### Return Results Function
    FUNCTION Return-Results {
        $Result.Duration = (Get-TimeDifferenceToString $StartTime)
        IF ((Get-PSCallStack).Command -like "*DeploymentSet*") { RETURN $Result | Select Action, Duration, RequestedName, Name, RequestedVersion, Version, Success, Details }
        ELSE { RETURN $Result | Select Action, Duration, Name, Version, Success, Details }
    }

   
    
   

    ### End
    RETURN Return-Results
}


### Completed Configuration Packages
FUNCTION Configure-BatteryMode {
    
    [CmdletBinding()]
    PARAM (
        [Parameter(Mandatory)]
        [ValidateSet('Best Power Efficiency', 'Balanced', 'Best Performance')]
        [string]$Mode
    )
    $StartTime = (Get-Date)

    FUNCTION Return-Results {
        $Result.Duration = (Get-TimeDifferenceToString $StartTime)
        IF ((Get-PSCallStack).Command -like "*DeploymentSet*") { RETURN $Result | Select Action, Duration, RequestedName, Name, RequestedVersion, Version, Success, Details }
        ELSE { RETURN $Result | Select Action, Duration, Name, Version, Success, Details }
    }

    IF ((Test-IsLaptop) -eq $False) {
        $Result = [PSCustomObject]@{
            Action = "Configure"
            Duration = (Get-TimeDifferenceToString $StartTime)
            RequestedName = $null
            Name = "Battery Mode"
            RequestedVersion = $null
            Version = $Null
            Success = $True
            Details = "Not a Laptop"
        }
        RETURN Return-Results
    }

    FUNCTION GET-PowerMode {
$function = @'
[DllImport("powrprof.dll", EntryPoint="PowerGetEffectiveOverlayScheme")]
public static extern int PowerGetEffectiveOverlayScheme(out Guid EffectiveOverlayGuid);
'@

$power = Add-Type -MemberDefinition $function -Name "Power" -PassThru -Namespace System.Runtime.InteropServices

$effectiveOverlayGuid = [Guid]::NewGuid()
$ret = $power::PowerGetEffectiveOverlayScheme([ref]$effectiveOverlayGuid)

    if ($ret -eq 0) {
        IF ($effectiveOverlayGuid -eq "961cc777-2547-4f9d-8174-7d86181b8a7a") {
            $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                Hostname = $env:COMPUTERNAME
                PowerModeName = "Best Power Efficiency"
                PowerModeGUID = $effectiveOverlayGuid
            }
        }
        ELSEIF ($effectiveOverlayGuid -eq "00000000-0000-0000-0000-000000000000") { 
            $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                Hostname = $env:COMPUTERNAME
                PowerModeName = "Balanced"
                PowerModeGUID = $effectiveOverlayGuid
            }
        }
        ELSEIF ($effectiveOverlayGuid -eq "ded574b5-45a0-4f42-8737-46345c09c238") {
            $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                Hostname = $env:COMPUTERNAME
                PowerModeName = "Best Performance"
                PowerModeGUID = $effectiveOverlayGuid
            }
        }
        ELSE { 
            $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
                Hostname = $env:COMPUTERNAME
                PowerModeName = "Unknown"
                PowerModeGUID = $effectiveOverlayGuid
            }
        }
    } 
    ELSE {
        $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Hostname = $env:COMPUTERNAME
            PowerModeName = "Unknown"
            PowerModeGUID = $effectiveOverlayGuid
        }
    }

    RETURN $Results | Select Hostname, PowerModeName, PowerModeGUID
}
    FUNCTION SET-PowerMode {
    PARAM (
        [Parameter(Mandatory = $true)]
        [ValidateSet('Best Power Efficiency', 'Balanced', 'Best Performance')]
        [string]$Mode
    )

    $ModeToGuid = @{
        "Best Power Efficiency" = [guid] "961cc777-2547-4f9d-8174-7d86181b8a7a";
        "Balanced" = [guid] "00000000-0000-0000-0000-000000000000";
        "Best Performance" = [guid] "ded574b5-45a0-4f42-8737-46345c09c238"
    }
    
    function Set-Power-Mode-By-GUID {
    param (
        [Guid]$guid
    )

    $function = @'
    [DllImport("powrprof.dll", EntryPoint="PowerSetActiveOverlayScheme")]
    public static extern int PowerSetActiveOverlayScheme(Guid OverlaySchemeGuid);
'@


    $power = Add-Type -MemberDefinition $function -Name "Power" -PassThru -Namespace MyNamespace.PowerModeManager

    $ret = $power::PowerSetActiveOverlayScheme($guid)

    if ($ret -ne 0) {
        Write-Error "Failed to set the power mode profile ID."
    }
}

    Set-Power-Mode-By-GUID -guid $ModeToGuid[$Mode]
}

    $StartMode = (Get-PowerMode).PowerModeName 
        
    IF ($StartMode -eq $Mode) {
        $Result = [PSCustomObject]@{
            Action = "Configure"
            Duration = (Get-TimeDifferenceToString $StartTime)
            RequestedName = $null
            Name = "Battery Mode"
            RequestedVersion = $null
            Version = $Null
            Success = $True
            Details = $Mode + " Already Set"
        }
        RETURN Return-Results
    }

    Set-PowerMode -Mode $Mode
    
    IF ((Get-PowerMode).PowerModeName -eq $Mode) {
        $Result = [PSCustomObject]@{
            Action = "Configure"
            Duration = (Get-TimeDifferenceToString $StartTime)
            RequestedName = $null
            Name = "Battery Mode"
            RequestedVersion = $null
            Version = $Null
            Success = $True
            Details = $Mode + " Already Set"
        }
        RETURN Return-Results
    }
    ELSE {
        $Result = [PSCustomObject]@{
            Action = "Configure"
            Duration = (Get-TimeDifferenceToString $StartTime)
            RequestedName = $null
            Name = "Battery Mode"
            RequestedVersion = $null
            Version = $Null
            Success = $False
            Details = "Failed to Set Battery Mode"
        }

        RETURN Return-Results
    }

    
}
FUNCTION Configure-AcrobatDC {
    
    [CmdletBinding()]
    PARAM ( 
        [SWITCH]$DisableUpsell = $False,
        [SWITCH]$DisableForcedSignIn = $False,
        [SWITCH]$DisableDesktopNotifications = $False
    )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Configure"
        Duration = $null
        RequestedName = $null
        Name = "Adobe Acrobat DC"
        RequestedVersion = $null
        Version = $null
        Success = $True
        Details = $null
    }

    ### Return Results Function
    FUNCTION Return-Results {
        $Result.Duration = (Get-TimeDifferenceToString $StartTime)
        IF ((Get-PSCallStack).Command -like "*DeploymentSet*") { RETURN $Result | Select Action, Duration, RequestedName, Name, RequestedVersion, Version, Success, Details }
        ELSE { RETURN $Result | Select Action, Duration, Name, Version, Success, Details }
    }
   
    ### Disable Forced Signin
    IF ($DisableForcedSignIn) { 
        IF ((Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Adobe\Adobe Acrobat\DC\FeatureLockDown" -Name "bIsSCReducedModeEnforcedEx" -Value "1" -Type DWord)) { 
            Write-Host "Successfully set registry key bIsSCReducedModeEnforcedEx to disable forced signin." 
        } 
        ELSE { 
            $Result.Success = $False 
            Write-Host "Failed to set registry key bIsSCReducedModeEnforcedEx to disable forced signin." 
            $Result.Details = "Setting Registry Value Failed"
        } 
    } ELSE { }
    
    ### Disable Upsell
    IF ($DisableUpsell) { 
        IF ((Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Adobe\Adobe Acrobat\DC\FeatureLockDown" -Name "bAcroSuppressUpsell" -Value "1" -Type DWord)) { 
            Write-Host "Successfully set registry key bAcroSuppressUpsell to disable upsell advertisements." 
        } 
        ELSE { 
            $Result.Success = $False 
            Write-Host "Failed to set registry key bAcroSuppressUpsell to disable upsell advertisements." 
            $Result.Details = "Setting Registry Value Failed"
        } 
    } ELSE { }
    
    ### Disable Notifications
    IF ($DisableDesktopNotifications) { 
        IF ((Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Adobe\Adobe Acrobat\DC\FeatureLockDown\cServices" -Name "bToggleNotificationToasts" -Value "1" -Type DWord)) { 
            Write-Host "Successfully set registry key bToggleNotificationToasts to disable desktop notifications." 
        } 
        ELSE { 
            $Result.Success = $False 
            Write-Host "Failed to set registry key bToggleNotificationToasts to disable desktop notifications." 
            $Result.Details = "Setting Registry Value Failed"
        } 
    } ELSE { }
   
    ### End
    RETURN Return-Results
}


### Verification Packages
FUNCTION Verify-WindowsProEnterprise {
    
    [CmdletBinding()]
    PARAM ( )

    ### Variables
    $StartTime = (Get-Date)

    $Result = [PSCustomObject]@{
        Action = "Verify"
        Duration = $null
        RequestedName = $null
        Name = "Windows Pro\Enterprise"
        RequestedVersion = $null
        Version = $null
        Success = $False
        Details = $null
    }

    ### Return Results Function
    FUNCTION Return-Results {
        $Result.Duration = (Get-TimeDifferenceToString $StartTime)
        IF ((Get-PSCallStack).Command -like "*DeploymentSet*") { RETURN $Result | Select Action, Duration, RequestedName, Name, RequestedVersion, Version, Success, Details }
        ELSE { RETURN $Result | Select Action, Duration, Name, Version, Success, Details }
    }

    IF (Test-IsServer) {
        $Result.Success = $True
        $Result.Details = "Server, Not a Workstation" 
        RETURN Return-Results
    }
    ELSEIF ((GET-CIMInstance Win32_OperatingSystem -Verbose:$False).Caption -like "*Pro*" -or (GET-CIMInstance Win32_OperatingSystem -Verbose:$False).Caption -like "*Enterprise*") { 
        $Result.Success = $True
        $Result.Details = $null 
        RETURN Return-Results
    }
    ELSE { 
        $Result = $False
        $ResultDetails = "Windows Home" 
        RETURN Return-Results
    }
   

    ### End
    RETURN Return-Results
}


### Test Deployment
<#--
 
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Find-PackageProvider -Name NuGet -ErrorAction SilentlyContinue -Force | Install-PackageProvider -Force | Out-Null
Register-PackageSource -Provider NuGet -Name nugetRepository -Location https://www.nuget.org/api/v2 -Force | Out-Null
Install-Module IntegrisDeploymentTool -Force
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force
 
Run-DeploymentSet "App-7Zip Install",
                  "App-Teams Install",
                  "App-Chrome Install",
                  "App-Greenshot Install",
                  "App-Firefox Install",
                  "App-BoxDrive Install",
                  "App-GoogleEarth Install",
                  "App-Java Install",
                  "Font-ArialRoundedMTBoldTall Install",
                  "Font-AlphaTypeMS Install",
                  "Font-FloridaVehicleFont Install",
                  "Font-Swis721CnBT Install",
                  "Font-Swiss911UCmBT Install",
                  "Driver-DS530II Install",
                  "App-DynamsoftService Install",
                  "App-AcrobatDC Install",
                  "App-NotePad++ Install",
                  "App-OneDrive Install",
                  "App-Slack Install",
                  "App-Office365ProPlusx64",
                  "App-DotNetFramework2 Install" -StartASync "App-Office365ProPlusx64","App-DotNetFramework35 Install","App-AcrobatDC Download" | FT
 
 
--#>



### Completed App Packages
FUNCTION App-7Zip {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "7-Zip*"
        ApplicationVersion          = "24.9.0.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://www.7-zip.org/a/7z2409-x64.msi"      
        FileName                    = "7z2409-x64.msi"              
        BackupDownloadLink          = "https://www.7-zip.org/a/7z2301-x64.msi"
        BackupFileName              = "7z2301-x64.msi"
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART"
        InstallTimeout              = 100
        PostInstallDelay            = 5
        PreInstallEndProcess        = "7zFM","7z","7zG"
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\7-Zip\7zFM.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = "7zFM","7z","7zG"
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-7Zip-23.1 {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "7-Zip*"
        ApplicationVersion          = "23.1.0.0"
        ExactVersion                = $True
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://www.7-zip.org/a/7z2301-x64.msi"      
        FileName                    = "7z2301-x64.msi"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART"
        InstallTimeout              = 100
        PostInstallDelay            = 5
        PreInstallEndProcess        = "7zFM","7z","7zG"
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\7-Zip\7zFM.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = "7zFM","7z","7zG"
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-AcrobatDC {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Adobe Acrobat*"
        ApplicationVersion          = "25.1.20432"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://trials.adobe.com/AdobeProducts/APRO/Acrobat_HelpX/win32/Acrobat_DC_Web_x64_WWMUI.zip"      
        FileName                    = "Acrobat_DC_Web_x64_WWMUI.zip"           
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = "Adobe Acrobat\setup.exe"

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "NoUpdate"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/sAll /rs EULA_ACCEPT=YES"
        InstallTimeout              = 1500
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 300
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
    Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Adobe\Adobe Acrobat\DC\FeatureLockDown" -Name "bIsSCReducedModeEnforcedEx" -Value "1" -Type DWord | Out-Null
}
FUNCTION App-AdvancedIPScanner {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Advanced IP Scanner*"
        ApplicationVersion          = "2.5.4594.1"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://download.advanced-ip-scanner.com/download/files/Advanced_IP_Scanner_2.5.4594.1.exe"    
        FileName                    = "Advanced_IP_Scanner_2.5.4594.1.exe"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-"
        InstallTimeout              = 240
        PostInstallDelay            = 5
        PreInstallEndProcess        = "advanced_ip_scanner"
        PostInstallEndProcess       = "advanced_ip_scanner"
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files (x86)\Advanced IP Scanner\advanced_ip_scanner.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = "advanced_ip_scanner"
        PostUninstallEndProcess     = "advanced_ip_scanner"
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Famatech Corp., O=Famatech Corp., L=Road Town, C=VG*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-AdvancedPortScanner {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Advanced Port Scanner*"
        ApplicationVersion          = "2.5.3869"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://download.advanced-port-scanner.com/download/files/Advanced_Port_Scanner_2.5.3869.exe"    
        FileName                    = "Advanced_Port_Scanner_2.5.3869.exe"          
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-"
        InstallTimeout              = 240
        PostInstallDelay            = 5
        PreInstallEndProcess        = "Advanced_Port_Scanner*"
        PostInstallEndProcess       = "Advanced_Port_Scanner*"
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files (x86)\Advanced Port Scanner\advanced_port_scanner.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = "Advanced_Port_Scanner*"
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Famatech Corp., O=Famatech Corp., L=Road Town*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-AutomateAgent {

    [CmdletBinding()]
    PARAM ( 

        [Parameter(Mandatory)]
        [ValidateSet("Install","Download","Reinstall","Uninstall")]
        [STRING]$Action,


        [String]$ServerAddress,
        [String]$ServerPassword,
        [String]$Location,

        
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    IF ((!(Test-NotNull $ServerAddress) -or !(Test-NotNull $ServerPassword) -or !(Test-NotNull $Location)) -and ($Action -eq "Install" -or $Action -eq "Reinstall")) {
        Write-Warning "Installs require ServerAddress, ServerPassword, and Location."
        RETURN
    }

    IF ($Action -eq "Uninstall" -or $Action -eq "Reinstall") {
        Run-FileDownload -URL "https://s3.amazonaws.com/assets-cp/assets/Agent_Uninstaller.zip" -FileName "Agent_Uninstaller.zip" | Out-Null
        Start-Sleep -Seconds 2
        Expand-Archive -Path "C:\Integris\Temp\Agent_Uninstaller.zip" -DestinationPath "C:\Integris\Temp\Agent_Uninstaller\" -Force
    }
    
    $Parameters  = @{
        #Application Info
        ApplicationName             = "Connectwise Automate Agent"
        ApplicationVersion          = "250.204"
        ExactVersion                = $False
        CustomVersionCommand        = "(Get-AutomateAgentConfig).Version"

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/ER45L271hopPm_Y7wz-gOEUBgINlay4vu11Q2HDZFCspew?download=1"       
        FileName                    = "Agent_Install.msi"             
        BackupDownloadLink          = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/Eee1IKvUBtFPrcvxuro6WeABSPca_0lYpH_d_hANYvQFLQ?download=1"
        BackupFileName              = "Agent_Install.msi"
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "NoUpdate"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/quiet /norestart SERVERADDRESS=$ServerAddress SERVERPASS=$ServerPassword LOCATION=$Location"
        InstallTimeout              = 150
        PostInstallDelay            = 60
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = "IF ((Get-Item 'C:\Windows\LTSvc\LTSVC.exe' -ErrorAction SilentlyContinue)) { RETURN `$True } ELSE { RETURN `$False }"
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Integris\Temp\Agent_Uninstaller\Agent_Uninstall.exe"
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 50
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = "IF ((Get-Item 'C:\Windows\LTSvc\LTSVC.exe' -ErrorAction SilentlyContinue)) { RETURN `$False } ELSE { RETURN `$True }"
                       
        ### Security Specific
        DownloadHash                = "EB0835B77AE70CD79BD7DEFC99E08C517DF1704F641993A103E6D5CA81605E46"
        BackupDownloadHash          = "EB0835B77AE70CD79BD7DEFC99E08C517DF1704F641993A103E6D5CA81605E46"
        CertVerification            = $True
        CertName                    = 'CN="Connectwise, LLC", O="Connectwise, LLC*'
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters    
} 
FUNCTION App-BoxDrive {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Box"
        ApplicationVersion          = "2.45.187"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://e3.boxcdn.net/box-installers/desktop/releases/win/Box-x64.msi"    
        FileName                    = "BoxDrive.msi"             
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\Box\Box\Box.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = 'CN="Box, Inc.", O="Box, Inc.", L=Redwood City, S=California, C=US'
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-Chrome {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Google Chrome"
        ApplicationVersion          = "137.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi"     
        FileName                    = "googlechromestandaloneenterprise64.msi"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART"
        InstallTimeout              = 120
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\Google\Chrome\Application\chrome.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Google LLC, O=Google LLC, L=Mountain View, S=California*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-DellCommand {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Dell Command | Update*"
        ApplicationVersion          = "5.5.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://downloads.dell.com/FOLDER12925856M/1/Dell-Command-Update-Application_HW0K4_WIN64_5.5.0_A00.EXE"     
        FileName                    = "Dell-Command-Update-Application_HW0K4_WIN64_5.5.0_A00.EXE"             
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "UninstallReinstall"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/s"
        InstallTimeout              = 180
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Dell Technologies Inc., OU=DUP Client Creation Service, O=Dell Technologies Inc.*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = "Dell.CommandUpdate"
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-DynamsoftService {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Dynamsoft Service"
        ApplicationVersion          = "1.0.516"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/Ec_PLZnp-tpCh_S8NXbd73YBqjQgT7Qebk-qrznqS8MhzA?download=1"     
        FileName                    = "DynamsoftServiceSetup.exe"             
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = $null
        InstallTimeout              = 100
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = 'Send-Keystroke -Title "Dynamsoft Service" -Key "{Enter}","{Enter}","{Enter}","{Enter}","{Enter}","{Enter}" -Delay 4'
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 90
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-Dropbox {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Dropbox"
        ApplicationVersion          = "221.4.5365"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://www.dropbox.com/download?plat=win&type=full"       
        FileName                    = "DropboxOfflineInstaller.exe"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/NOLAUNCH"
        InstallTimeout              = 360
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files (x86)\Dropbox\Client\Dropbox.exe" 
        RunArguements               = "/home"
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files (x86)\Dropbox\Client\DropboxUninstaller.exe"
        UninstallArguments          = "/InstallType:MACHINE /S"
        UninstallTimeout            = 180
        PostUninstallDelay          = 60
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = 'CN="Dropbox, Inc", O="Dropbox, Inc", L=San Francisco, S=California, C=US'
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-DuoAuthenticationForWindowsLogon {
    
    [CmdletBinding()]
    PARAM ( 

        [ValidateSet("Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,

        [Parameter()]
        [string]$IKEY,

        [Parameter()]
        [string]$SKEY,

        [Parameter()]
        [string]$HOSTAPI,

        [Parameter()]
        [SWITCH]$AUTOPUSH = $false,

        [Parameter()]
        [SWITCH]$FAILOPEN = $false,

        [Parameter()]
        [SWITCH]$RDPONLY = $false,

        [Parameter()]
        [SWITCH]$SMARTCARD = $false,

        [Parameter()]
        [SWITCH]$WRAPSMARTCARD = $false,        

        [Parameter()]
        [SWITCH]$ENABLEOFFLINE = $false, 

        [Parameter()]
        [ValidateSet(0,1,2)]
        [int]$USERNAMEFORMAT = 0,        

        [Parameter()]
        [int]$LOGFILE_MAXCOUNT = $null,

        [Parameter()]
        [int]$LOGFILE_MAXSIZEMB = $null,

        [Parameter()]
        [ValidateSet(0,1,2)]
        [int]$UAC_PROTECTMODE = 0,

        [Parameter()]
        [SWITCH]$UAC_OFFLINE = $null,

        [Parameter()]
        [SWITCH]$UAC_OFFLINE_ENROLL = $null,

        [Parameter()]
        [string]$PROXYHOST = $null,

        [Parameter()]
        [ValidateRange(1,65535)]
        [int]$PROXYPORT = $null,

        
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )
    
    IF ($Action -eq "Install" -or $Action -eq "Reinstall") {

        IF (!(Test-NotNull $IKEY) -or !(Test-NotNull $SKEY) -or !(Test-NotNull $HOSTAPI)) {
            Write-Warning "Duo installs require IKEY, SKEY, and HOSTAPI."
            RETURN
        }

        $InstallArguments = "/S /V`"/qn"
        $InstallArguments += " IKEY=`"$IKEY`""
        $InstallArguments += " SKEY=`"$SKEY`""
        $InstallArguments += " HOST=`"$HOSTAPI`""
        IF (Test-NotNull $AUTOPUSH) { $InstallArguments += " AUTOPUSH=`"#1`"" }
        IF (Test-NotNull $FAILOPEN) { $InstallArguments += " FAILOPEN=`"#1`"" }
        IF (Test-NotNull $RDPONLY) { $InstallArguments += " RDPONLY=`"#1`"" }   
        IF (Test-NotNull $SMARTCARD) { $InstallArguments += " SMARTCARD=`"#1`"" }
        IF (Test-NotNull $WRAPSMARTCARD) { $InstallArguments += " WRAPSMARTCARD=`"#1`"" }
        IF (Test-NotNull $ENABLEOFFLINE) { $InstallArguments += " ENABLEOFFLINE=`"#1`"" }
        $InstallArguments += " USERNAMEFORMAT=`"#$USERNAMEFORMAT`"" 
        IF (Test-NotNull $PROXYHOST) { $InstallArguments += " PROXYHOST=`"$PROXYHOST`"" }
        IF (Test-NotNull $LOGFILE_MAXCOUNT) { $InstallArguments += " LOGFILE_MAXCOUNT=`"$LOGFILE_MAXCOUNT`"" }
        IF (Test-NotNull $LOGFILE_MAXSIZEMB) { $InstallArguments += " LOGFILE_MAXSIZEMB=`"$LOGFILE_MAXSIZEMB`"" }
        $InstallArguments += " UAC_PROTECTMODE=`"#$UAC_PROTECTMODE`""
        IF (Test-NotNull $UAC_OFFLINE) { $InstallArguments += " UAC_OFFLINE=`"#1`"" }
        IF (Test-NotNull $UAC_OFFLINE_ENROLL) { $InstallArguments += " UAC_OFFLINE_ENROLL=`"#1`"" }
        $InstallArguments += "`""
    }
    ELSEIF ($Action -eq "Update") {
        $InstallArguments = "/qn /norestart"
    }

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Duo Authentication for Windows Logon*"
        ApplicationVersion          = "5.1.1"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://dl.duosecurity.com/duo-win-login-latest.exe"      
        FileName                    = "duo-win-login-latest.exe"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = $InstallArguments
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Duo Security LLC, O=Duo Security LLC, L=Ann Arbor*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-FileZillaClient {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "FileZilla*"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/EYxOgmJCjCpNluKz5fH_ZZ0BcDYFt7AKsK7BfVvVsJSkdg?download=1"     
        FileName                    = "FileZilla_3.69.1_win64-setup.exe"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/S /user=all"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\FileZilla FTP Client\filezilla.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files\FileZilla FTP Client\uninstall.exe"
        UninstallArguments          = "/S"
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Tim Kosse, O=Tim Kosse, S=Nordrhein-Westfalen*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-Firefox {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Mozilla Firefox*"
        ApplicationVersion          = "139.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://download.mozilla.org/?product=firefox-msi-latest-ssl&os=win64&lang=en-US"        
        FileName                    = "FirefoxInstaller.msi"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART"
        InstallTimeout              = 240
        PostInstallDelay            = 5
        PreInstallEndProcess        = "FireFox"
        PostInstallEndProcess       = "FireFox"
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\Mozilla Firefox\firefox.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files\Mozilla Firefox\uninstall\helper.exe"
        UninstallArguments          = "/S /V"
        UninstallTimeout            = 120
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = "Firefox"
        PostUninstallEndProcess     = "Firefox"
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Mozilla Corporation, OU=Firefox Engineering Operations*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = "Mozilla.Firefox"
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-GoogleEarth {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Google Earth*"
        ApplicationVersion          = "7.3.6.10201"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://dl.google.com/release2/Earth/euzptyrdafdm4mf4kdtyt2ainq_7.3.6.10201/googleearth-win-pro-7.3.6.10201-x64.exe"      
        FileName                    = "googleearth-win-pro-7.3.6.10201-x64.exe"             
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "OMAHA=1"
        InstallTimeout              = 240
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\Google\Google Earth Pro\client\googleearth.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Google LLC, O=Google LLC, L=Mountain View, S=California, C=US,*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-Greenshot {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Greenshot*"
        ApplicationVersion          = "1.2.10.6"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://github.com/greenshot/greenshot/releases/download/Greenshot-RELEASE-1.2.10.6/Greenshot-INSTALLER-1.2.10.6-RELEASE.exe"    
        FileName                    = "Greenshot-Installer.exe"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/VERYSILENT"
        InstallTimeout              = 120
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\Greenshot\Greenshot.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = "Greenshot"
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = 'E=getgreenshot@gmail.com, CN="Open Source Developer, Robin Krom", O=Open Source Developer, C=DE'
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-Java {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Java 8*"
        ApplicationVersion          = "8.0.4510.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://javadl.oracle.com/webapps/download/AutoDL?xd_co_f=NzMxYmFlZmQtNmUxMy00NTJkLWE2ZjAtYzQ1MDViYTA3YWFl&BundleId=252044_8a1589aa0fe24566b4337beee47c2d29"     
        FileName                    = "jre-8u451-windows-x64.exe"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/s"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = 'CN="Oracle America, Inc.", O="Oracle America, Inc.",*'
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-NetExtender {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [ValidateSet("default","alwayson ","onlyone")]
        [STRING]$Mode = "default",
        [STRING]$Server = $null,
        [STRING]$Domain = $null,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $InstallArguments = "/QN /NORESTART"        
    IF (Test-NotNull $Mode) { $InstallArguments += " MODE=$Mode" }
    IF (Test-NotNull $Server) { $InstallArguments += " SERVER=$Server" }
    IF (Test-NotNull $Domain) { $InstallArguments += " DOMAIN=$Domain" }  

    $Parameters  = @{
        #Application Info
        ApplicationName             = "SonicWall NetExtender"
        ApplicationVersion          = "10.3.2"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://software.sonicwall.com/NetExtender/NetExtender-x64-10.3.2.msi"   
        FileName                    = "NetExtender-x64-10.3.2.msi"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "UninstallReinstall"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = $InstallArguments
        InstallTimeout              = 240
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\SonicWall\SSL-VPN\NetExtender\NetExtender.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=SONICWALL INC., O=SONICWALL INC., S=California, C=US"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = "SonicWALL.NetExtender"
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-NordLayer {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","Update","Download","Reinstall","Uninstall")]        
        [STRING]$Action,
        [STRING]$Organization = $null,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $InstallArguements = "/QN /NORESTART"
    IF (Test-NotNull $Organization) { $InstallArguements += " ORGANIZATION=$Organization" }

    $Parameters  = @{
        #Application Info
        ApplicationName             = "NordLayer"
        ApplicationVersion          = "3.5.2.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://downloads.nordlayer.com/win/releases/NordLayerSetup_v3.5.2.msi"     
        FileName                    = "NordLayerSetup_v3.5.2.msi"             
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = $InstallArguements
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files (x86)\NordLayer\NordLayer.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "E=admin@nordvpn.com, CN=nordvpn s.a., O=nordvpn s.a.*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = "NordSecurity.NordLayer"
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-OneDrive {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Microsoft OneDrive"
        ApplicationVersion          = "25.51.317.3"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://go.microsoft.com/fwlink/?linkid=844652"        
        FileName                    = "OneDriveSetup.exe"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/SILENT /ALLUSERS"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files\Microsoft OneDrive\$((GCI "C:\Program Files\Microsoft OneDrive\" -ErrorAction SilentlyContinue | Where-Object { $_ -like "*.*.*.*" } | Select-Object -First 1).Name)\OneDriveSetup.exe"
        UninstallArguments          = "/uninstall /allusers"
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = "CN=Microsoft Corporation, O=Microsoft Corporation,*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-OpenVPN {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "OpenVPN*"
        ApplicationVersion          = "3.7.2"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://openvpn.net/downloads/openvpn-connect-v3-windows.msi"      
        FileName                    = "openvpn-connect-3.7.2.4253_signed.msi"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = "OpenVPNConnect"
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\OpenVPN Connect\OpenVPNConnect.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = "OpenVPNConnect"
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=OpenVPN Inc., O=OpenVPN Inc.*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = "OpenVPNTechnologies.OpenVPN"
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-PrinterLogic {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        [String]$HomeURL,
        [String]$AuthCode,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $HomeURL = $HomeURL.Replace("https://","")
    $HomeURL = $HomeURL.Replace("http://","")

    IF ((!(Test-NotNull $HomeURL) -or !(Test-NotNull $AuthCode)) -and ($Action -eq "Install" -or $Action -eq "Reinstall")) {
        Write-Warning "PrinterLogic installs require HomeURL and AuthCode parameters."
        RETURN
    }

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Printer Installer Client"
        ApplicationVersion          = "25.1.0.1168"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/EchnH0bqBRhAsBAyGwBA-0QBjIC7BeN6ZGuxOGQfgnbiLQ?download=1"    
        FileName                    = "PrinterInstallerClient.msi"             
        BackupDownloadLink          = "https://claytonchildcare.printercloud.com/client/setup/PrinterInstallerClient.msi"  
        BackupFileName              = "PrinterInstallerClient.msi"
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = $null
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=PrinterLogic, O=PrinterLogic, L=St. George, S=Utah, C=US"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-RevoUninstaller {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Revo*"
        ApplicationVersion          = "1.1.1.1"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://f3b1cfc5d488c0384dc3-056ccca39cd416ca6db85fa26f78b9ef.ssl.cf1.rackcdn.com/revosetup.exe"
        FileName                    = "revosetup.exe"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/VERYSILENT /NORESTART"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\VS Revo Group\Revo Uninstaller\RevoUnin.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=VS REVO GROUP OOD, O=VS REVO GROUP OOD, L=Ruse,*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-RingCentral {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "RingCentral"
        ApplicationVersion          = "25.2.2010.684"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://app.ringcentral.com/download/RingCentral-x64.msi"  
        FileName                    = "RingCentral-x64.msi"             
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART"
        InstallTimeout              = 600
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\RingCentral\RingCentral.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = 'CN="RingCentral, Inc.", O="RingCentral, Inc.",*'
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-SeaMonkey {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "SeaMonkey*"
        ApplicationVersion          = "2.53.20"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://archive.seamonkey-project.org/releases/2.53.20/win64/en-US/seamonkey-2.53.20.en-US.win64.installer.exe"    
        FileName                    = "seamonkey-2.53.20.en-US.win64.installer.exe"             
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/S"
        InstallTimeout              = 180
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\SeaMonkey\seamonkey.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files\SeaMonkey\uninstall\helper.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/S"
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = "SeaMonkey"
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=SeaMonkey e.V., O=SeaMonkey e.V., S=Bayern, C=DE"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-Slack {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Slack (Machine)"
        ApplicationVersion          = "4.43.52"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://downloads.slack-edge.com/desktop-releases/windows/x64/4.43.52/slack-standalone-4.43.52.0.msi"     
        FileName                    = "Slack-Standalone-4.43.52.0.msi"           
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART"
        InstallTimeout              = 180
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\Slack\slack.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "MsiExec.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/X {15F7A686-AF58-4605-87A6-27D0299E3B5C} /QN /NORESTART"
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = 'CN="Slack Technologies, LLC", O="Slack Technologies, LLC",*'
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-Teams {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Microsoft Teams"
        ApplicationVersion          = "25122.1415.3698.6812"
        ExactVersion                = $False
        CustomVersionCommand        = '(Get-AppXPackage "MSTeams" -AllUsers).Version'

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://statics.teams.cdn.office.net/production-teamsprovision/lkg/teamsbootstrapper.exe"       
        FileName                    = "teamsbootstrapper.exe"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = '-p -o "C:\Integris\Temp\MSTeams-x64.msix"'
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = "ms-teams"
        PostInstallEndProcess       = "ms-teams"
        CustomInstallVerification   = 'IF (GET-AppXProvisionedPackage -Online | Where-Object { $_.DisplayName -like "MSTeams" }) { $True } ELSE { $False }'
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = 'Get-AppXProvisionedPackage -Online | Where-object { $_.DisplayName -like "*MSTeams*" } | Remove-AppXProvisionedPackage -AllUsers | Out-Null; Get-AppXPackage "*MSTeams*" -AllUsers | Remove-AppXPackage | Out-Null'
        InvokeUninstallCommand      = $True
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = "ms-teams"
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = 'IF (GET-AppXProvisionedPackage -Online | Where-Object { $_.DisplayName -like "MSTeams" }) { $False } ELSE { $True }'
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-FileDownload -URL "https://go.microsoft.com/fwlink/?linkid=2196106" -FileName "MSTeams-x64.msix" | Out-Null
    Run-PackageHandler @Parameters
}
FUNCTION App-Thunderbird {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Mozilla Thunderbird*"
        ApplicationVersion          = "137.0.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://download.mozilla.org/?product=thunderbird-latest&os=win64&lang=en-US"     
        FileName                    = "Thunderbird Setup.exe"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/S"
        InstallTimeout              = 180
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\Mozilla Thunderbird\thunderbird.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files\Mozilla Thunderbird\uninstall\helper.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/S /V"
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Mozilla Corporation, OU=Firefox Engineering Operations,*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-VLCMediaPlayer {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "VLC Media Player"
        ApplicationVersion          = "3.0.21"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://download.videolan.org/videolan/vlc/3.0.21/win64/vlc-3.0.21-win64.exe"      
        FileName                    = "vlc-3.0.21-win64.exe"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/L=1031 /S"
        InstallTimeout              = 240
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\VideoLAN\VLC\vlc.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files\VideoLAN\VLC\uninstall.exe"
        UninstallArguments          = "/S"
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=VideoLAN, O=VideoLAN, L=Paris, C=FR"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-WatchGuardSSLVPNClient {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "WatchGuard Mobile VPN*"
        ApplicationVersion          = "12.11"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://cdn.watchguard.com/SoftwareCenter/Files/MUVPN_SSL/12_11/WG-MVPN-SSL_12_11.exe"      
        FileName                    = "WG-MVPN-SSL_12_11.exe"             
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/silent /verysilent /Components=main,tapdriver /tasks=desktopicon /norestart"
        InstallTimeout              = 420
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files (x86)\WatchGuard\WatchGuard Mobile VPN with SSL\wgsslvpnc.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files (x86)\WatchGuard\WatchGuard Mobile VPN with SSL\unins000.exe"
        UninstallArguments          = "/silent /verysilent /norestart"
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=WatchGuard Technologies, O=WatchGuard Technologies, S=Washington, C=US"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-WinSCP {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "WinSCP*"
        ApplicationVersion          = "6.5.1"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/EW5kplpD2lVPuL4NKa5IKXQB0J7oObgoZCwYD8e2G4a2Qw?download=1"
        FileName                    = "WinSCP-6.5.1-Setup.exe"             
        BackupDownloadLink          = $null
        BackupFileName              = $null  
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/VERYSILENT /ALLUSERS /NORESTART"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files (x86)\WinSCP\WinSCP.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = "A54ECA431FDFBBF489805D995C1EBEAF7FF5A4E5AD825CC529F1B0F7525815AB"
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = "CN=Martin Prikryl, O=Martin Prikryl, L=Prague*"
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = "WinSCP.WinSCP"
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-NotePad++ {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Notepad++*"
        ApplicationVersion          = "8.7.1"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://github.com/notepad-plus-plus/notepad-plus-plus/releases/download/v8.7.1/npp.8.7.1.Installer.x64.exe"      
        FileName                    = "npp.8.7.1.Installer.x64.exe"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "UninstallReinstall"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/S"
        InstallTimeout              = 180
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files\Notepad++\notepad++.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = 'CN="Notepad++", O="Notepad++",*'
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-ScreenConnectClient {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "ScreenConnect Client*"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = $null       
        FileName                    = $null               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = $null
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-Zoom {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","Update","Download","Reinstall","Uninstall")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "*Zoom*"
        ApplicationVersion          = "6.4.63669"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://zoom.us/client/6.4.3.63669/ZoomInstallerFull.msi"     
        FileName                    = "ZoomInstallerFull.msi"            
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART"
        InstallTimeout              = 200
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        
        ### Run Specific
        RunPath                     = "C:\Program Files (x86)\Zoom\bin\Zoom.exe"
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $True
        CertName                    = 'CN="Zoom Video Communications, Inc.", O="Zoom Video Communications, Inc.",*'
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}

### Font Packages
FUNCTION Font-ArialRoundedMTBoldTall {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Arial_Rounded_MT_Bold_Tall"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/EdIuTpNomI5DnZ2pE1eKEdEB0qjt1jqrRKMhHwBA1IUcMQ?Download=1"    
        FileName                    = "Arial_Rounded_MT_Bold_Tall.ttf"           
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = "Install-Font 'C:\Integris\Temp\Arial_Rounded_MT_Bold_Tall.ttf'"
        InvokeInstallCommand        = $True
        InstallArguments            = $null
        InstallTimeout              = 15
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF (Test-FontInstalled "Arial_Rounded_MT_Bold_Tall") { $True } ELSE { $False }'
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 15
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION Font-AlphaTypeMS {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Alpha Type MS Regular"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/ETlNd-At4XRHrBJev-LutwkBnK-bQwAfPxKtuCzEz_-m-Q?Download=1"    
        FileName                    = "Florida Alpha MS.ttf"           
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = "Install-Font 'C:\Integris\Temp\Florida Alpha MS.ttf'"
        InvokeInstallCommand        = $True
        InstallArguments            = $null
        InstallTimeout              = 15
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF (Test-FontInstalled "Florida Alpha MS") { $True } ELSE { $False }'
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 15
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION Font-FloridaVehicleFont {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Personalized Plate Font"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/EbWxqP-kXexOuOTUM1Fm09oBiLJlWfd4Tp9yZd-85CAnnw?Download=1"    
        FileName                    = "Personalized Plate Font.ttf"           
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = "Install-Font 'C:\Integris\Temp\Personalized Plate Font.ttf'"
        InvokeInstallCommand        = $True
        InstallArguments            = $null
        InstallTimeout              = 15
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF (Test-FontInstalled "Personalized Plate Font") { $True } ELSE { $False }'
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 15
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION Font-Swis721CnBT {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Swiss 721 Bold Condensed BT"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/ETL4iJ88AJ5OqaODKqTYh2EBvOFTquzn2Wp6Ra__fvejeg?Download=1"    
        FileName                    = "Swiss 721 Bold Condensed BT.ttf"           
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = "Install-Font 'C:\Integris\Temp\Swiss 721 Bold Condensed BT.ttf'"
        InvokeInstallCommand        = $True
        InstallArguments            = $null
        InstallTimeout              = 15
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF (Test-FontInstalled "Swiss 721 Bold Condensed BT") { $True } ELSE { $False }'
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 15
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION Font-Swiss911UCmBT {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Swiss 911 Ultra Compressed BT"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/EcXIKM0EM0BNpPSkEWrATgsB2DY2cYeuCm7vMdd_ZWNGDQ?Download=1"    
        FileName                    = "Swiss 911 Ultra Compressed BT.ttf"           
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = "Install-Font 'C:\Integris\Temp\Swiss 911 Ultra Compressed BT.ttf'"
        InvokeInstallCommand        = $True
        InstallArguments            = $null
        InstallTimeout              = 15
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF (Test-FontInstalled "Swiss 911 Ultra Compressed BT") { $True } ELSE { $False }'
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = $null
        InvokeUninstallCommand      = $False
        UninstallArguments          = $null
        UninstallTimeout            = 15
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}


### Driver Packages
FUNCTION Driver-DS530II {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","Download")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Epson DS-530 II Driver"
        ApplicationVersion          = "1.1.0.0"
        ExactVersion                = $False
        CustomVersionCommand        = '(((& "pnputil.exe" /enum-drivers | Out-String).Replace("Published Name:","@Published Name:")).Split("@") | Where-Object { $_ -like "*ES0232.inf*" }) -match "\d+(\.\d+)+" | Out-null; RETURN $Matches[0]'

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://ftp.epson.com/drivers/DS530II_EScan2_67820_AM.exe"    
        FileName                    = "DS530II_EScan2_67820_AM.zip"        
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = "setup.exe"

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InstallArguments            = "/SI -sms /Nodisp"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF ((((& "pnputil.exe" /enum-drivers | Out-String).Replace("Published Name:","@Published Name:")).Split("@") | Where-Object { $_ -like "*ES0232.inf*" })) { $True } ELSE { $False }'
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files (x86)\epson\escndv\setup\setup.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/r -sms /Nodisp"
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}


### Packages in Progress
FUNCTION App-Office365ProPlusx64 {
    
    [CmdletBinding()]
    PARAM (
        [Parameter(Mandatory)]
        [ValidateSet("Install")]
        [STRING]$Action
    )

    $StartTime = (Get-Date)

    $Result = @()

    FUNCTION Return-Results {
        $Result.Duration = (Get-TimeDifferenceToString $StartTime)
        IF ((Get-PSCallStack).Command -like "*DeploymentSet*") { RETURN $Result | Select Action, Duration, RequestedName, Name, RequestedVersion, Version, Success, Details }
        ELSE { RETURN $Result | Select Action, Duration, Name, Version, Success, Details }
    }

    IF ($Action -eq "Uninstall" -or $Action -eq "Reinstall") {



    }
    IF ($Action -eq "Install" -or $Action -eq "Reinstall") {
    $InstallCheck = $null
    $InstallCheck = (Get-ApplicationInstalled | Where-Object { $_.Name -eq "Microsoft 365 Apps for Enterprise - en-us" })

    IF ($InstallCheck -ne $null) {

        Write-Verbose "$($(Get-Date).ToShortTimeString()): Already Installed. Done."

        $Result = [PSCustomObject]@{            
            Action = "Install"
            Duration = $null
            RequestedName = $null
            Name = "Microsoft 365 Apps for Enterprise - en-us"
            RequestedVersion = $null
            Version = [VERSION](Get-ApplicationInstalled | Where-Object { $_.Name -eq "Microsoft 365 Apps for Enterprise - en-us" }).Version
            Success = $True
            Details = "Already Installed"
        }

        RETURN Return-Results
    }

    $DownloadUrl = "https://download.microsoft.com/download/2/7/A/27AF1BE6-DD20-4CB4-B154-EBAB8A7D4A7E/officedeploymenttool_18129-20030.exe"
    IF ((GET-Item "C:\Integris\Temp" -ErrorAction SilentlyContinue | Out-Null) -eq $null) { New-Item -Name "Temp" -Path "C:\Integris" -ItemType Directory -ErrorAction SilentlyContinue | Out-Null }
    Invoke-WebRequest -Uri $DownloadUrl -OutFile "C:\Integris\Temp\OfficeDeploymentTool_18129-20030.exe" -UseBasicParsing

    [xml]$XMLString = "<Configuration ID='0c2f1074-0110-4338-bb20-42b0a50edf82'>
  <Info Description='' />
  <Add OfficeClientEdition='64' Channel='Current'>
    <Product ID='O365ProPlusRetail'>
      <Language ID='en-us' />
      <ExcludeApp ID='Access' />
      <ExcludeApp ID='Groove' />
      <ExcludeApp ID='Lync' />
      <ExcludeApp ID='Outlook' />
      <ExcludeApp ID='Publisher' />
      <ExcludeApp ID='Bing' />
    </Product>
  </Add>
  <Property Name='SharedComputerLicensing' Value='0' />
  <Property Name='FORCEAPPSHUTDOWN' Value='FALSE' />
  <Property Name='SCLCacheOverride' Value='0' />
  <Updates Enabled='TRUE' />
  <RemoveMSI>
    <IgnoreProduct ID='InfoPath' />
    <IgnoreProduct ID='InfoPathR' />
    <IgnoreProduct ID='PrjPro' />
    <IgnoreProduct ID='PrjStd' />
    <IgnoreProduct ID='SharePointDesigner' />
    <IgnoreProduct ID='VisPro' />
    <IgnoreProduct ID='VisStd' />
  </RemoveMSI>
  <AppSettings>
    <Setup Name='Company' Value='SharedComputerLicensing' />
    <User Key='software\microsoft\office\16.0\excel\options' Name='defaultformat' Value='51' Type='REG_DWORD' App='excel16' Id='L_SaveExcelfilesas' />
    <User Key='software\microsoft\office\16.0\powerpoint\options' Name='defaultformat' Value='27' Type='REG_DWORD' App='ppt16' Id='L_SavePowerPointfilesas' />
    <User Key='software\microsoft\office\16.0\word\options' Name='defaultformat' Value='' Type='REG_SZ' App='word16' Id='L_SaveWordfilesas' />
  </AppSettings>
</Configuration>"


    New-Item -Name "MicrosoftODT" -Path "C:\Integris\Temp" -ItemType Directory -ErrorAction SilentlyContinue | Out-Null
    Start-Process "C:\Integris\Temp\OfficeDeploymentTool_18129-20030.exe" -ArgumentList "/extract:C:\Integris\Temp\MicrosoftODT /quiet" -Wait
    $XMLString.Save("C:\Integris\Temp\MicrosoftODT\Configuration.xml")
 
    & "C:\Integris\Temp\MicrosoftODT\setup.exe" /configure C:\Integris\Temp\MicrosoftODT\configuration.xml

    $InstallCheck = $null
    $InstallCheck = (Get-ApplicationInstalled | Where-Object { $_.Name -eq "Microsoft 365 Apps for Enterprise - en-us" })

    $Duration = $(((Get-Date) - $StartTime))
    IF ($Duration.Hours -gt 0) { $Duration = $(((Get-Date) - $StartTime).ToString("h\:m\:ss")) }
    ELSE { $Duration = $(((Get-Date) - $StartTime).ToString("m\:ss")) }

    get-process OfficeC2RClient | Stop-Process -Force 

    IF ($InstallCheck -eq $null) {
        $Result = [PSCustomObject]@{
            Action = "Install"
            Duration = $null
            RequestedName = $null
            Name = "Microsoft 365 Apps for Enterprise - en-us"
            RequestedVersion = $null
            Version = $null
            Success = $False
            Details = "Application Failed to Install"
        }
    }
    ELSE {
        $Result = [PSCustomObject]@{
            Action = "Install"
            Duration = $null
            RequestedName = $null
            Name = "Microsoft 365 Apps for Enterprise - en-us"
            RequestedVersion = $null
            Version = [VERSION](Get-ApplicationInstalled | Where-Object { $_.Name -eq "Microsoft 365 Apps for Enterprise - en-us" }).Version
            Success = $True
            Details = $null
        }
    }
}

    RETURN Return-Results
}
FUNCTION App-DotNetFramework2 {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","Download")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Microsoft .Net Framework v2.0"
        ApplicationVersion          = "2.0.50727"
        ExactVersion                = $False
        CustomVersionCommand        = 'IF ((Get-ItemPropertyValue -Path "HKLM:SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727" -Name Install -ErrorAction SilentlyContinue) -eq 1) { "2.0.50727" } ELSE { $($null) }'

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = $null
        FileName                    = $null            
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = "Enable-WindowsOptionalFeature -Online -FeatureName NetFx3"
        InvokeInstallCommand        = $True
        InstallArguments            = $null
        InstallTimeout              = 1500
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF ((Get-ItemPropertyValue -Path "HKLM:SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727" -Name Install -ErrorAction SilentlyContinue) -eq 1) { $($True) } ELSE { $($False) }'
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "Disable-WindowsOptionalFeature -Online -FeatureName NetFx3"
        InvokeUninstallCommand      = $True
        UninstallArguments          = $null
        UninstallTimeout            = 900
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}
FUNCTION App-DotNetFramework35 {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","Download")]
        [STRING]$Action,
        [SWITCH]$VerifyOnly,
        ### Smart Features Specific
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$IncludeDeviceType = $null,
        [ValidateSet("Desktop","Laptop","Server")]
        [STRING[]]$ExcludeDeviceType = $null,
        [STRING[]]$IncludeHostname = $null,
        [STRING[]]$ExcludeHostname = $null,
        [STRING[]]$IncludeDN = $null,
        [STRING[]]$ExcludeDN = $null,
        [STRING[]]$IncludeADSite = $null,
        [STRING[]]$ExcludeADSite = $null,
        [STRING[]]$IncludeIPAddress = $null,
        [STRING[]]$ExcludeIPAddress = $null,
        [STRING[]]$IncludeGeoLocation = $null,
        [STRING[]]$ExcludeGeoLocation = $null
    )

    $Parameters  = @{
        #Application Info
        ApplicationName             = "Microsoft .Net Framework v3.5"
        ApplicationVersion          = "3.5"
        ExactVersion                = $False
        CustomVersionCommand        = 'IF ((Get-ItemPropertyValue -Path "HKLM:SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5" -Name Install -ErrorAction SilentlyContinue) -eq 1) { "3.5" } ELSE { $($null) }'

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = $null
        FileName                    = $null            
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = "Enable-WindowsOptionalFeature -Online -FeatureName NetFx3"
        InvokeInstallCommand        = $True
        InstallArguments            = $null
        InstallTimeout              = 1500
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF ((Get-ItemPropertyValue -Path "HKLM:SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5" -Name Install -ErrorAction SilentlyContinue) -eq 1) { $($True) } ELSE { $($False) }'
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "Disable-WindowsOptionalFeature -Online -FeatureName NetFx3"
        InvokeUninstallCommand      = $True
        UninstallArguments          = $null
        UninstallTimeout            = 900
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = $null
                       
        ### Security Specific
        DownloadHash                = $null
        BackupDownloadHash          = $null
        CertVerification            = $False
        CertName                    = $null
        VirusTotal                  = $False
        
        ### WinGet Specific
        WinGetAppName               = $null
        
        ### Options Used at Runtime
        Action                      = $Action
        VerifyOnly                  = $VerifyOnly
        IncludeDeviceType           = $IncludeDeviceType
        ExcludeDeviceType           = $ExcludeDeviceType
        IncludeHostname             = $IncludeHostname
        ExcludeHostname             = $ExcludeHostname
        IncludeDN                   = $IncludeDN
        ExcludeDN                   = $ExcludeDN
        IncludeADSite               = $IncludeADSite
        ExcludeADSite               = $ExcludeADSite
        IncludeIPAddress            = $IncludeIPAddress
        ExcludeIPAddress            = $ExcludeIPAddress
        IncludeGeoLocation          = $IncludeGeoLocation
        ExcludeGeoLocation          = $ExcludeGeoLocation
    }
    Run-PackageHandler @Parameters
}