IntegrisDeploymentTool.psm1

### Support Functions
FUNCTION Set-RegistryValueForAllUsers { 
    <#
    .SYNOPSIS
        This FUNCTION uses Active Setup to create a "seeder" key which creates or modifies a user-based registry value
        for all users on a computer. If the key path doesn't exist to the value, it will automatically create the key and add the value.
    .EXAMPLE
        PS> SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'Setting'; 'Type' = 'String'; 'Value' = 'someval'; 'Path' = 'SOFTWARE\Microsoft\Windows\Something'}
      
        This example would modify the string registry value 'Type' in the path 'SOFTWARE\Microsoft\Windows\Something' to 'someval'
        for every user registry hive.
    .PARAMETER RegistryInstance
         A hash table containing key names of 'Name' designating the registry value name, 'Type' to designate the type
        of registry value which can be 'String,Binary,Dword,ExpandString or MultiString', 'Value' which is the value itself of the
        registry value and 'Path' designating the parent registry key the registry value is in.
    #>
 
    [CmdletBinding()] 
    param ( 
        [Parameter(Mandatory=$True)] 
        [hashtable[]]$RegistryInstance 
    ) 
    try { 
        New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS | Out-Null 
         
        ## Change the registry values for the currently logged on user. Each logged on user SID is under HKEY_USERS
        $LoggedOnSids = (GET-ChildItem HKU: | where { $_.Name -match 'S-\d-\d+-(\d+-){1,14}\d+$' }).PSChildName 
        Write-Verbose "$($(Get-Date).ToShortTimeString()): Found $($LoggedOnSids.Count) logged on user SIDs" 
        foreach ($sid in $LoggedOnSids) { 
            Write-Verbose -Message "$($(Get-Date).ToShortTimeString()): Loading the user registry hive for the logged on SID $sid" 
            foreach ($instance in $RegistryInstance) { 
                ## Create the key path if it doesn't exist
                New-Item -ErrorAction SilentlyContinue -Path ("HKU:\$sid\$($instance.Path)" | Split-Path -Parent) -Name ("HKU:\$sid\$($instance.Path)" | Split-Path -Leaf) | Out-Null
                ## Create (or modify) the value specified in the param
                New-Item -Path "HKU:\$sid\SOFTWARE\WatchGuard\" | Out-Null
                New-Item -Path "HKU:\$sid\SOFTWARE\WatchGuard\SSLVPNClient\" | Out-Null
                New-Item -Path "HKU:\$sid\SOFTWARE\WatchGuard\SSLVPNClient\Settings" | Out-Null

                SET-ItemProperty -Path "HKU:\$sid\$($instance.Path)" -Name $instance.Name -Value $instance.Value -Type $instance.Type -Force 
            } 
        } 
         
        ## Create the Active Setup registry key so that the reg add cmd will get ran for each user
        ## logging into the machine.
        ## http://www.itninja.com/blog/view/an-active-setup-primer
        Write-Verbose "$($(Get-Date).ToShortTimeString()): Setting Active Setup registry value to apply to all other users" 
        foreach ($instance in $RegistryInstance) { 
            ## Generate a unique value (usually a GUID) to use for Active Setup
            $Guid = [guid]::NewGuid().Guid 
            $ActiveSetupRegParentPath = 'HKLM:\Software\Microsoft\Active Setup\Installed Components' 
            ## Create the GUID registry key under the Active Setup key
            New-Item -Path $ActiveSetupRegParentPath -Name $Guid | Out-Null 
            $ActiveSetupRegPath = "HKLM:\Software\Microsoft\Active Setup\Installed Components\$Guid" 
            Write-Verbose "$($(Get-Date).ToShortTimeString()): Using registry path '$ActiveSetupRegPath'" 
             
            ## Convert the registry value type to one that reg.exe can understand. This will be the
            ## type of value that's created for the value we want to set for all users
            switch ($instance.Type) { 
                'String' { 
                    $RegValueType = 'REG_SZ' 
                } 
                'Dword' { 
                    $RegValueType = 'REG_DWORD' 
                } 
                'Binary' { 
                    $RegValueType = 'REG_BINARY' 
                } 
                'ExpandString' { 
                    $RegValueType = 'REG_EXPAND_SZ' 
                } 
                'MultiString' { 
                    $RegValueType = 'REG_MULTI_SZ' 
                } 
                default { 
                    throw "Registry type '$($instance.Type)' not recognized" 
                } 
            } 
             
            ## Build the registry value to use for Active Setup which is the command to create the registry value in all user hives
            $ActiveSetupValue = "reg add `"{0}`" /v {1} /t {2} /d {3} /f" -f "HKCU\$($instance.Path)", $instance.Name, $RegValueType, $instance.Value 
            Write-Verbose -Message "$($(Get-Date).ToShortTimeString()): Active setup value is '$ActiveSetupValue'" 
            ## Create the necessary Active Setup registry values
            SET-ItemProperty -Path $ActiveSetupRegPath -Name '(Default)' -Value 'Active Setup Test' 
            SET-ItemProperty -Path $ActiveSetupRegPath -Name 'Version' -Value '1' 
            SET-ItemProperty -Path $ActiveSetupRegPath -Name 'StubPath' -Value $ActiveSetupValue
        } 
    } catch { 
        Write-Warning -Message $_.Exception.Message 
    } 
}
FUNCTION Test-IsPrivateIP {
    PARAM (
        [Parameter(Mandatory)]
        [System.Net.IPAddress]$IPAddress
    )

    $Split = $IPAddress.IPAddressToString.Split('.')

    IF ($IPAddress -eq "127.0.0.1") { RETURN $True }
    IF ($Split[0] -eq 10) { RETURN $True }
    IF ($Split[0] -eq 192 -and $Split[1] -eq 168) { RETURN $True }
    IF ($Split[0] -eq 172 -and $Split[1] -ge 16 -and $Split[1] -le 31) { RETURN $True }
    IF ($Split[0] -eq 169 -and $Split[1] -eq 254) { RETURN $True }
    
    RETURN $False
}
FUNCTION Test-IsPublicIP {
    PARAM (
        [Parameter(Mandatory)]
        [System.Net.IPAddress]$IPAddress
    )

    IF ((Test-IsPrivateIP $IPAddress) -eq $False) { RETURN $True }
    ELSE { RETURN $False }
}
FUNCTION Test-IsDomainController {
    $ProductType = (GET-CIMInstance Win32_OperatingSystem).ProductType

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

    RETURN $False    
}
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 ((Test-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 (Test-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
    )

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

        $Count++
        IF ($Count -lt $Key.Count) { 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 3
    }
    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
    }
}
FUNCTION Install-WindowsUpdates {

    <#
    .SYNOPSIS
    Installs Windows updates.
 
    .DESCRIPTION
    This function installs windows updates and optionally reboots the computer.
 
    .PARAMETER RetryCount
    This specifies additional install attempts if updates remain uninstalled after the first attempt. Default 2.
 
    .PARAMETER ForceReboot
    This specifies a forced reboot if needed when updates are finished installing.
 
    .PARAMETER RebootTime
    This specifies a future time to reboot the computer once updates are finished installing.
 
    .EXAMPLE
    Install-WindowsUpdates -ForceReboot -RebootTime "5/5/25 20:00"
    Installs updates and forces a reboot at 8PM on 5/5/25.
 
    .NOTES
    The function will install driver updates if available, but doesn't care if they don't install successfully.
    #>


    [CmdletBinding(DefaultParameterSetName='Default')]
    PARAM (
        [Parameter(Mandatory,ParameterSetName = 'Reboot')]
        [SWITCH]$ForceReboot = $False,
        [Parameter(ParameterSetName = 'Default')]
        [Parameter(ParameterSetName = 'Reboot')]
        [INT]$RetryCount = 0,
        [Parameter(ParameterSetName = 'Reboot')]
        [DATETIME]$RebootTime = "1/1/1"
    )
    
    IF ($RebootTime -le (Get-Date) -and $RebootTime -ne "1/1/1") { Write-Host ""; Write-Warning "Specified time has already passed. Please specify a time in the future or no time for immediate reboot when done."; RETURN }
    ELSEIF ($RebootTime -ne "1/1/1") { Write-Verbose "Reboot scheduled for $RebootTime. (Approximately $([Math]::Round(($RebootTime - (Get-Date)).TotalHours,0)) Hour(s) from Now)" }
    ELSE { }

    Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned -force

    Write-Verbose "Checking for Windows updates..."
    $TryCount = 0    

    $UpdatesRemaining = 0
    $Searcher = New-Object -ComObject Microsoft.Update.Searcher
    $SearchResult = $Searcher.Search("IsInstalled=0 and RebootRequired=0").Updates
    FOREACH ($Result in $SearchResult) { IF ($Result.Type -eq 1) { $UpdatesRemaining++ } }      
        
    WHILE ($UpdatesRemaining -gt 0 -and $TryCount -le $RetryCount) {
        
        IF ($TryCount -gt 0) { Write-Verbose "Some updates found not installed. Trying again." }
        $TryCount++
        Write-Verbose "Updates found. Attempt $TryCount of $($RetryCount + 1)"


        Write-Verbose "Downloading updates..."
        #Download updates.
        $Session = New-Object -ComObject Microsoft.Update.Session
        $Downloader = $Session.CreateUpdateDownloader()
        $Downloader.Updates = $SearchResult
        $Downloader.Download()

        Write-Verbose "Done downloading updates. Installing..."
        #Install updates.
        $Installer = New-Object -ComObject Microsoft.Update.Installer
        $Installer.Updates = $SearchResult
        $InstallerResults = $Installer.Install() | Out-Null
        Write-Verbose "Finished installing. Checking results..."

        $Searcher = New-Object -ComObject Microsoft.Update.Searcher
        $SearchResult = $Searcher.Search("IsInstalled=0 and RebootRequired=0").Updates | Out-Null
        $UpdatesRemaining = 0
        FOREACH ($Result in $SearchResult) { IF ($Result.Type -eq 1) { $UpdatesRemaining++ } }   
        IF ($UpdatesRemaining -eq 0) { continue }
    }

    IF ($TryCount -eq 0) { Write-Verbose "No Updates Found. Checking if reboot is needed..." }

    FOREACH ($Result in $SearchResult) { IF ($Result.Type -eq 1 -and $Result.IsInstalled -eq $False) { Write-Verbose "Retry count exceeded. Some updates failed to install." } }

    ### Reboot if Required by Updates
    
    IF ((($Searcher.Search("RebootRequired=1").Updates) | select RebootRequired).RebootRequired -contains $true)
    { 
        IF ($ForceReboot -eq $False) { Write-Verbose "Reboot required but no reboot requested. Done." }
        ELSEIF ($RebootTime -ne "1/1/1") { 
            [int]$Delay = [MATH]::Round(($RebootTime - (Get-Date)).TotalSeconds,0) 
            Write-Verbose "Reboot required. Scheduled Reboot for $RebootTime."
            Shutdown.exe /t $Delay /r 
        }
        ELSE {
            Write-Verbose "Reboot required. Rebooting in 5 seconds..."
            Shutdown.exe /t 5 /r 
        }
    }
    ELSE {
        Write-Verbose "No reboot required. Done."
    }

    $VerbosePreference = $VerbosePreferenceTemp
}  


### 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\Temp",
        [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
    }
    

    ### ===============================
    ### === 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) -and $InvokeInstallCommand -eq $False) { $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") { 

                IF ($ForceDownload -or !(GET-ChildItem -Path $ApplicationInstallerPath -ErrorAction SilentlyContinue)) {                
                    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
        $InvokeJob = $null

        IF ($InvokeInstallCommand) { 
            $InvokeJob = Start-Job -ScriptBlock { Invoke-Expression -Command $($Using:CustomInstallCommand) } -ErrorAction SilentlyContinue
            Wait-Job -Job $InvokeJob -Timeout $InstallTimeout -ErrorAction SilentlyContinue | Out-Null
            Stop-Job -Job $InvokeJob -ErrorAction SilentlyContinue | Out-Null
        }
        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,
        [SWITCH]$RunWinGetUpdate = $False,
        [SWITCH]$ResultsToDesktop = $True,
        [SWITCH]$RunWindowsUpdates = $False,
        [SWITCH]$RestartWhenComplete = $False
    )

    $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()): ### ===================================================== ###"


    $WindowsUpdateJob = $null
    IF ($RunWindowsUpdates) {


        Write-Host ""
        Write-Host "$($(Get-Date).ToShortTimeString()): ### ========================================= ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### Running Windows Updates ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### ========================================= ###"
        Write-Host ""
        Write-Host "$($(Get-Date).ToShortTimeString()): Starting Windows Update Job in the Background..." 
        $WindowsUpdateJob = Start-Job -ScriptBlock { Invoke-Expression -Command "Install-WindowsUpdates" } -ErrorAction SilentlyContinue
    }
    
        
    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
    }       
        
    $Results += [PSCustomObject]@{
        Action = "Total"
        Duration = (Get-TimeDifferenceToString $SessionStartTime)
        RequestedName = $Null
        Name = $Null
        RequestedVersion = $Null
        Version = $Null
        Success = $Null
        Details = $Null
    }


    IF ($RunWindowsUpdates) {
        Write-Host ""
        Write-Host "$($(Get-Date).ToShortTimeString()): ### ========================================= ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### Running Windows Updates ###"
        Write-Host "$($(Get-Date).ToShortTimeString()): ### ========================================= ###"
        Write-Host ""
        Write-Host "$($(Get-Date).ToShortTimeString()): Waiting for Windows Update to Complete..." -NoNewline
        Wait-Job -Job $WindowsUpdateJob | Out-Null
        Write-Host "Windows Update Finished."
    }
        
    IF ($ResultsToDesktop) { $Results | Select Action, Duration, Name, Version, Success, Details | FT | Out-File "C:\Users\Public\Desktop\IDTResults.txt" }
    IF ($RestartWhenComplete) { 
        Write-Host ""
        Write-Host "$($(Get-Date).ToShortTimeString()): RestartWhenComplete is enabled. Attempting Restart..."
        Shutdown -r -t 10
    }
    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-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
}
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-EnvironmentVariable {
    
    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory=$true)]
        [STRING]$Name,
        
        [Parameter(Mandatory=$true)]
        [STRING]$Value,
        
        [ValidateSet("User", "Machine", "Process")]
        [STRING]$Scope = "Machine",

        [ValidateSet("Overwrite", "Append", "Prefix")]
        [STRING]$Method = "Overwrite"
    )

    FUNCTION Set-EnvironmentVariable {
    param (
        [Parameter(Mandatory=$true)]
        [string]$Name,
        
        [Parameter(Mandatory=$true)]
        [string]$Value,
        
        [ValidateSet("User", "Machine", "Process")]
        [string]$Scope = "User"
    )
    
    try {
        # Set the environment variable based on scope
        switch ($Scope) {
            "User" {
                [Environment]::SetEnvironmentVariable($Name, $Value, [EnvironmentVariableTarget]::User)
            }
            "Machine" {
                # Requires admin privileges for Machine scope
                if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
                    throw "Setting Machine environment variables requires administrative privileges."
                }
                [Environment]::SetEnvironmentVariable($Name, $Value, [EnvironmentVariableTarget]::Machine)
            }
            "Process" {
                [Environment]::SetEnvironmentVariable($Name, $Value, [EnvironmentVariableTarget]::Process)
            }
        }
        
        Write-Output "Environment variable '$Name' set to '$Value' in $Scope scope successfully."
    }
    catch {
        Write-Error "Failed to set environment variable: $_"
    }
}

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

    FUNCTION Set-EnvironmentVariable {
    param (
        [Parameter(Mandatory=$true)]
        [string]$Name,
        
        [Parameter(Mandatory=$true)]
        [string]$Value,
        
        [ValidateSet("User", "Machine", "Process")]
        [string]$Scope = "Machine"
    )
    
    try {
        # Set the environment variable based on scope
        switch ($Scope) {
            "User" {
                [Environment]::SetEnvironmentVariable($Name, $Value, [EnvironmentVariableTarget]::User)
            }
            "Machine" {
                # Requires admin privileges for Machine scope
                if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
                    throw "Setting Machine environment variables requires administrative privileges."
                }
                [Environment]::SetEnvironmentVariable($Name, $Value, [EnvironmentVariableTarget]::Machine)
            }
            "Process" {
                [Environment]::SetEnvironmentVariable($Name, $Value, [EnvironmentVariableTarget]::Process)
            }
        }
        
        #Write-Output "Environment variable '$Name' set to '$Value' in $Scope scope successfully."
    }
    catch {
        #Write-Error "Failed to set environment variable: $_"
    }
}       
    FUNCTION Get-EnvironmentVariable {
        param (
            [Parameter(Mandatory=$true)]
            [string]$VariableName,
            [ValidateSet("User","Machine","Process")]
            [string]$Scope = "Machine"
        )
    
        try {
            $value = [Environment]::GetEnvironmentVariable($VariableName, $Scope)
            if ($null -eq $value) {
                #Write-Warning "Environment variable '$VariableName' not found in $Scope scope"
                return $null
            }
            return $value
        }
        catch {
            #Write-Error "Error retrieving environment variable: $_"
            return $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 ($Method -eq "Overwrite") { Set-EnvironmentVariable -Name $Name -Value $Value -Scope $Scope }
    IF ($Method -eq "Append") {
        $EVTemp = Get-EnvironmentVariable -VariableName $Name -Scope $Scope
        Set-EnvironmentVariable -Name $Name -Value "$EVTemp;$Value" -Scope $Scope
    }
    IF ($Method -eq "Prefix") {
        $EVTemp = Get-EnvironmentVariable -VariableName $Name -Scope $Scope
        Set-EnvironmentVariable -Name $Name -Value "$Value;$EVTemp" -Scope $Scope
    }

    IF ((Get-EnvironmentVariable -VariableName $Name -Scope Machine) -like "*$Value*") { $Result.Success = $true }

    ### End
    RETURN Return-Results
}
FUNCTION Configure-FileAndPrinterSharing {
    
    [CmdletBinding()]
    PARAM (
        [Parameter(Mandatory)]
        [ValidateSet("Enable","Disable")]
        [STRING]$Status
    )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Configure"
        Duration = $null
        RequestedName = $null
        Name = "File and Printer Sharing"
        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 ($Status -eq "Enable"){ 
        TRY {
            
            IF ((Get-NetFirewallRule -DisplayGroup "File And Printer Sharing").Enabled -contains "False") { }
            ELSE { $Result.Success = $True; RETURN Return-Results }

            Set-NetFirewallRule -DisplayGroup "File And Printer Sharing" -Enabled True -Profile Domain
            Set-NetFirewallRule -DisplayGroup "File And Printer Sharing" -Enabled True -Profile Private

            IF ((Get-NetFirewallRule -DisplayGroup "File And Printer Sharing").Enabled -contains "False") { }
            ELSE { $Result.Success = $True }
        }
        CATCH { }
    }

    IF ($Status -eq "Disable"){ 
        TRY {
            IF ((Get-NetFirewallRule -DisplayGroup "File And Printer Sharing").Enabled -contains "True") { }
            ELSE { $Result.Success = $True; RETURN Return-Results }

            Set-NetFirewallRule -DisplayGroup "File And Printer Sharing" -Enabled False -Profile Domain
            Set-NetFirewallRule -DisplayGroup "File And Printer Sharing" -Enabled False -Profile Private

            IF ((Get-NetFirewallRule -DisplayGroup "File And Printer Sharing").Enabled -contains "True") { }
            ELSE { $Result.Success = $True }
        }
        CATCH { }
    }

    
    ### End
    RETURN Return-Results
}
FUNCTION Configure-PowerSettings {

    [CmdletBinding()]
    PARAM (
        [int]$ACMonitorTimeout = $null,
        [int]$ACSleepTimeout = $null,
        [int]$DCMonitorTimeout = $null,
        [int]$DCSleepTimeout = $null
        #[int]$PowerButtonAction = $null,
        #[int]$SleepButtonAction = $null,
        #[int]$LidAction = $null
    )

    $StartTime = (Get-Date)

    $Results = @()
    #$PowerPlans = powercfg /list
            
    #IF ($PowerPlans -like "*($Name)*") { $GUID = ($PowerPlans -like "*$Name*")[0].Replace("Power Scheme GUID: ","").substring(0,36) }
    #ELSE {
    # $GUID = New-GUID
    # powercfg /duplicateScheme 381b4222-f694-41f0-9685-ff5bb260df2e $GUID
    # powercfg /changename $GUID $Name
    #}
    #powercfg -SetActive $GUID

    TRY {

        IF ($ACMonitorTimeout -ne $null) { powercfg -change -monitor-timeout-ac $ACMonitorTimeout }
        IF ($ACSleepTimeout -ne $null) { powercfg -change -standby-timeout-ac $ACSleepTimeout }
        IF ($DCMonitorTimeout -ne $null) { powercfg -change -monitor-timeout-dc $DCMonitorTimeout }
        IF ($DCSleepTimeout -ne $null) { powercfg -change -standby-timeout-dc $DCSleepTimeout }


        IF ($PowerButtonAction -ne $null) {
            powercfg -SETACVALUEINDEX $GUID 4f971e89-eebd-4455-a8de-9e59040e7347 7648efa3-dd9c-4e3e-b566-50f929386280 $PowerButtonAction
            powercfg -SETDCVALUEINDEX $GUID 4f971e89-eebd-4455-a8de-9e59040e7347 7648efa3-dd9c-4e3e-b566-50f929386280 $PowerButtonAction
            powercfg -SETACVALUEINDEX 381b4222-f694-41f0-9685-ff5bb260df2e 4f971e89-eebd-4455-a8de-9e59040e7347 7648efa3-dd9c-4e3e-b566-50f929386280 $PowerButtonAction
            powercfg -SETDCVALUEINDEX 381b4222-f694-41f0-9685-ff5bb260df2e 4f971e89-eebd-4455-a8de-9e59040e7347 7648efa3-dd9c-4e3e-b566-50f929386280 $PowerButtonAction
        }
        IF ($SleepButtonAction -ne $null) {
            powercfg -SETACVALUEINDEX $GUID 4f971e89-eebd-4455-a8de-9e59040e7347 96996bc0-ad50-47ec-923b-6f41874dd9eb $SleepButtonAction
            powercfg -SETDCVALUEINDEX $GUID 4f971e89-eebd-4455-a8de-9e59040e7347 96996bc0-ad50-47ec-923b-6f41874dd9eb $SleepButtonAction
            powercfg -SETACVALUEINDEX 381b4222-f694-41f0-9685-ff5bb260df2e 4f971e89-eebd-4455-a8de-9e59040e7347 96996bc0-ad50-47ec-923b-6f41874dd9eb $SleepButtonAction
            powercfg -SETDCVALUEINDEX 381b4222-f694-41f0-9685-ff5bb260df2e 4f971e89-eebd-4455-a8de-9e59040e7347 96996bc0-ad50-47ec-923b-6f41874dd9eb $SleepButtonAction
        }
        IF ($LidAction -ne $null) { 
            powercfg -SETACVALUEINDEX $GUID 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-476b1d01c936 $LidAction
            powercfg -SETDCVALUEINDEX $GUID 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-476b1d01c936 $LidAction
            powercfg -SETACVALUEINDEX 381b4222-f694-41f0-9685-ff5bb260df2e 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-476b1d01c936 $LidAction
            powercfg -SETDCVALUEINDEX 381b4222-f694-41f0-9685-ff5bb260df2e 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-476b1d01c936 $LidAction
        }
          
        $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Action = "Configure"
            RequestedName = $null
            Name = "Power Settings"
            RequestedVersion = $null
            Version = $null
            Duration = (Get-TimeDifferenceToString $StartTime)
            Success = $True
            Details = $null
        }
    }
    CATCH {
        $Results += New-Object PSObject -WarningAction SilentlyContinue -Property @{
            Action = "Configure"
            RequestedName = $null
            Name = "Power Settings"
            RequestedVersion = $null
            Version = $null
            Duration = (Get-TimeDifferenceToString $StartTime)
            Success = $False
            Details = $null
        }
    }

    RETURN $Results
}
FUNCTION Configure-TimeSettings {
    
    [CmdletBinding()]
    PARAM ( 
        [STRING]$InternetTimeServer = "0.us.pool.ntp.org,1.us.pool.ntp.org,2.us.pool.ntp.org,3.us.pool.ntp.org",
        [STRING]$LocalTimeServer = $null,
        [ValidateSet("Enable", "Disable")]
        [STRING]$AutomaticTimeZone = $null
    )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Configure"
        Duration = $null
        RequestedName = $null
        Name ="Time Servers"
        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 }
    }

    ### Set Time Server
    IF ($True) {
        $ServerString = $null

        IF (Test-NotNull $LocalTimeServer) {       
            $ServerString = "$LocalTimeServer,$InternetTimeServer"
        }
        ELSE {
            $ServerString = "$InternetTimeServer"
        
        }

        Set-Service W32Time -StartupType Automatic | Out-Null
        Start-Service W32Time -ErrorAction SilentlyContinue | Out-Null
        Start-Sleep 3
        Start-Service W32Time -ErrorAction SilentlyContinue | Out-Null
        Start-Sleep 3

        w32tm /config /manualpeerlist:"$InternetTimeServer" /syncfromflags:manual /reliable:yes /update | Out-Null

        Start-Service W32Time -ErrorAction SilentlyContinue | Out-Null
        Start-Sleep 3


        # Force immediate time sync
        w32tm /resync /force | Out-Null
    
        $TimeServers = w32tm /query /configuration
        $TimeServers = $TimeServers | Select-String "NtpServer:"

        IF ((Get-Service W32Time).Status -eq "Stopped" | Out-Null) { $Result.Success = $False; $Result.Details = "Time Service Not Running" }
        ELSEIF ($TimeServers -like "*$ServerString*") {  }
        ELSE { $Result.Success = $False; $Result.Details = "Setting Time Servers Failed" }
    }

        ### Timezone
    IF ($AutomaticTimeZone -eq "Enable") { 
        IF (!(Set-RegistryValue -Hive HKLM -Path "SYSTEM\CurrentControlSet\Services\tzautoupdate" -Name Start -Value 3 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Enable TZAutoUpdate" } 
        IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\location" -Name Value -Value "Allow" -Type String)) { $Result.Success = $False; $Result.Details = "Failed to Enable Location Services" } 
    }
    IF ($AutomaticTimeZone -eq "Disable") { 
        IF (!(SSet-RegistryValue -Hive HKLM -Path "SYSTEM\CurrentControlSet\Services\tzautoupdate" -Name Start -Value 4 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Disable TZAutoUpdatee" }  
    }

   

    ### End
    RETURN Return-Results
}
FUNCTION Configure-WatchGuardSSLVPNClient {
    
    [CmdletBinding()]
    PARAM ( 
        [STRING]$Server,
        [STRING]$Username
    )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Configure"
        Duration = $null
        RequestedName = $null
        Name = "Watchguard SSL VPN"
        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 }
    }
    
    IF (Test-NotNull $Server) { SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'Server'; 'Type' = 'String'; 'Value' = $Server; 'Path' = 'SOFTWARE\WatchGuard\SSLVPNClient\Settings'} -ErrorAction SilentlyContinue }
    IF (Test-NotNull $Username) { SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'Username'; 'Type' = 'String'; 'Value' = $Username; 'Path' = 'SOFTWARE\WatchGuard\SSLVPNClient\Settings'} -ErrorAction SilentlyContinue }
    SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'AutoReconnect'; 'Type' = 'DWORD'; 'Value' = 1; 'Path' = 'SOFTWARE\WatchGuard\SSLVPNClient\Settings'} -ErrorAction SilentlyContinue
   
    ### End
    RETURN Return-Results
}
FUNCTION Configure-WindowsUserSettings {
    
    [CmdletBinding()]
    PARAM ( 
        [ValidateSet("Show", "Hide")]
        [STRING]$TaskbarSearch = $null,
        [ValidateSet("Show", "Hide")]
        [STRING]$FileExtensions = $null,
        [ValidateSet("Enable", "Disable")]
        [STRING]$NewsandWeather = $null
    )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Configure"
        Duration = $null
        RequestedName = $null
        Name = "Windows User Settings"
        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 }
    }

    IF ($TaskbarSearch -eq "Show") { Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'SearchboxTaskbarMode'; 'Type' = 'DWORD'; 'Value' = '1'; 'Path' = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Search'} }
    IF ($TaskbarSearch -eq "Hide") { Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'SearchboxTaskbarMode'; 'Type' = 'DWORD'; 'Value' = '0'; 'Path' = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Search'} }

    IF ($FileExtensions -eq "Show") { Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'HideFileExt'; 'Type' = 'DWORD'; 'Value' = '0'; 'Path' = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced'} }
    IF ($FileExtensions -eq "Hide") { Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'HideFileExt'; 'Type' = 'DWORD'; 'Value' = '1'; 'Path' = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced'} }

    IF ($NewsandWeather -eq "Show") { Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'ShellFeedsTaskbarViewMode'; 'Type' = 'DWORD'; 'Value' = '0'; 'Path' = 'Software\Microsoft\Windows\CurrentVersion\Feeds'} }
    IF ($NewsandWeather -eq "Hide") { Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'ShellFeedsTaskbarViewMode'; 'Type' = 'DWORD'; 'Value' = '2'; 'Path' = 'Software\Microsoft\Windows\CurrentVersion\Feeds'} }
 

   
    ### End
    RETURN Return-Results
}
FUNCTION Configure-WindowsSystemSettings {
    
    [CmdletBinding()]
    PARAM ( 
        [ValidateSet("Enable", "Disable")]
        [STRING]$AllowCortana = $null,
        [ValidateSet("Enable", "Disable")]
        [STRING]$AllowWindowsHello = $null
    )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Configure"
        Duration = $null
        RequestedName = $null
        Name = "Windows System Settings"
        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 }
    }

    ### Cortana
    IF ($AllowCortana -eq "Enable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\Windows\Windows Search" -Name AllowCortana -Value 1 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Allow Cortana" } }
    IF ($AllowCortana -eq "Disable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\Windows\Windows Search" -Name AllowCortana -Value 0 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Disable Cortana" } }

    ### Windows Hello
    IF ($AllowWindowsHello -eq "Enable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\PassportForWork" -Name Enabled -Value 1 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Allow Windows Hello" } }
    IF ($AllowWindowsHello -eq "Disable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\PassportForWork" -Name Enabled -Value 0 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Disable Windows Hello" } }
   
    ### End
    RETURN Return-Results
}
FUNCTION Configure-OneDrive {
    
    [CmdletBinding()]
    PARAM (
        [ValidateSet("Enable", "Disable")]
        [STRING]$AllowOneDriveBackup = $null
    )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Configure"
        Duration = $null
        RequestedName = $null
        Name = "OneDrive"
        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 }
    }

    ### OneDrive Backup
    IF ($AllowOneDriveBackup -eq "Enable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\OneDrive" -Name KFMBlockOptIn -Value 1 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Allow OneDrive Backup" } }
    IF ($AllowOneDriveBackup -eq "Disable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\OneDrive" -Name KFMBlockOptIn -Value 0 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Disable OneDrive Backup" } }
   
    ### End
    RETURN Return-Results
}
FUNCTION Configure-Screensaver {
    
    [CmdletBinding()]
    PARAM (
        [ValidateSet("Enable", "Disable")]
        [STRING]$Status = $null,
        [INT]$Timeout = $null,
        [ValidateSet("Enable", "Disable")]
        [STRING]$SecureScreensaver = $null
    )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Configure"
        Duration = $null
        RequestedName = $null
        Name = "Screensaver"
        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 }
    }

    ### Screensaver Active
    IF ($Status -eq "Enable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\Windows\Control Panel\Desktop" -Name ScreenSaveActive -Value 1 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Enable Screensaver" }  }
    IF ($Status -eq "Disable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\Windows\Control Panel\Desktop" -Name ScreenSaveActive -Value 0 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Disable Screensaver" } }

    ### Screensaver Timeout
    IF (Test-NotNull $Timeout) { 
        IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\Windows\Control Panel\Desktop" -Name ScreenSaveTimeOut -Value $Timeout -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Set Timeout" }
        IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name InactivityTimeoutSecs -Value $Timeout -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Set Timeout" }
    }

    ### Screensaver Active
    IF ($SecureScreensaver -eq "Enable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\Windows\Control Panel\Desktop" -Name ScreenSaverIsSecure -Value 1 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Set Secure" } }
    IF ($SecureScreensaver -eq "Disable") { IF (!(Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Policies\Microsoft\Windows\Control Panel\Desktop" -Name ScreenSaverIsSecure -Value 0 -Type DWORD)) { $Result.Success = $False; $Result.Details = "Failed to Set Secure" } }
   
    ### End
    RETURN Return-Results
}


### Completed Cleanup Packages
FUNCTION CleanUp-AppXClutter {
    
    [CmdletBinding()]
    PARAM ( )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "CleanUp"
        Duration = $null
        RequestedName = $null
        Name = "AppX Clutter"
        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 }
    }
       
    Get-AppxPackage -AllUsers -Name *King.com* -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue
    Get-AppxPackage -AllUsers -Name *Zune* -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue
    Get-AppxPackage -AllUsers -Name *Solitaire* -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue
    Get-AppxPackage -AllUsers -Name *MixedReality* -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue
    Get-AppxPackage -AllUsers -Name *Bing* -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue
    Get-AppxPackage -AllUsers -Name *microsoft.windowscommunicationsapps* -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue
    Get-AppxPackage -AllUsers -Name *Microsoft.Microsoft3DViewer* -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue
    Get-AppxPackage -AllUsers -Name *Microsoft.WindowsMaps* -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue
    Get-AppxPackage -AllUsers -Name *YourPhone* -ErrorAction SilentlyContinue | Remove-AppxPackage -AllUsers -ErrorAction SilentlyContinue
   
    ### End
    RETURN Return-Results
}
FUNCTION CleanUp-WindowsClutter {
    
    [CmdletBinding()]
    PARAM ( )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "CleanUp"
        Duration = $null
        RequestedName = $null
        Name = "Windows Clutter"
        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 }
    }
       
    
    ### Turn off Application Suggestions
    Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'SubscribedContent-338388Enabled'; 'Type' = 'DWORD'; 'Value' = '0'; 'Path' = 'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager'} 

    ### Turn off Windows Welcome Experience
    Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'SubscribedContent-310093Enabled'; 'Type' = 'DWORD'; 'Value' = '0'; 'Path' = 'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager'} 

    ### Turn off 'Get Even More out of Windows' Popup
    Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'SubscribedContent-338389Enabled'; 'Type' = 'DWORD'; 'Value' = '0'; 'Path' = 'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager'} 

    ### Turn off Windows Promotional Apps
    Set-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'SoftLandingEnabled'; 'Type' = 'DWORD'; 'Value' = '0'; 'Path' = 'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager'}

    ### Other Clutter Items for OOBE
    Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" -Name "DisablePrivacyExperience" -Value 1 -Type DWORD | Out-Null
    Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" -Name "DisableVoice" -Value 1 -Type DWORD | Out-Null
    Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" -Name "PrivacyConsentStatus" -Value 1 -Type DWORD | Out-Null
    Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" -Name "Protectyourpc" -Value 3 -Type DWORD | Out-Null
    Set-RegistryValue -Hive HKLM -Path "SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" -Name "HideEULAPage" -Value 1 -Type DWORD | Out-Null
    Set-RegistryValue -Hive HKLM -Path "Software\Microsoft\Windows\CurrentVersion\Policies\System" -Name "EnableFirstLogonAnimation" -Value 1 -Type DWORD | Out-Null
   
    ### 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
}
FUNCTION Verify-DomainJoin {
    
    [CmdletBinding()]
    PARAM ( 
        [ValidateSet("AD","AAD","Workgroup")]
        [Parameter(Mandatory)]
        [STRING]$Type,
        [STRING]$Name = $null
    )

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

    $DomainJoinStatus = Get-DomainInfo

    ### 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 ($Type -eq "AD") {
        IF ($Type -ne $DomainJoinStatus.DomainType) { $Result.Success = $False; $Result.Details = "Domain Type Doesn't Match"; RETURN Return-Results }
        IF (Test-NotNull $Name) {
            IF ($Name -ne $DomainJoinStatus.FQDN) { $Result.Success = $False; $Result.Details = "Name Doesn't Match"; RETURN Return-Results }
        }
        IF ($DomainJoinStatus.DomainJoinHealth -eq "Unhealthy") { $Result.Success = $False; $Result.Details = "Join Status Unhealthy"; RETURN Return-Results }
    }
    IF ($Type -eq "AAD") {
        IF ($Type -ne $DomainJoinStatus.DomainType) { $Result.Success = $False; $Result.Details = "Domain Type Doesn't Match"; RETURN Return-Results }
        IF (Test-NotNull $Name) {
            IF ($Name -ne $DomainJoinStatus.TenantName) { $Result.Success = $False; $Result.Details = "Name Doesn't Match"; RETURN Return-Results }
        }
        IF ($DomainJoinStatus.DomainJoinHealth -eq "Unhealthy") { $Result.Success = $False; $Result.Details = "Join Status Unhealthy"; RETURN Return-Results }
    }
    IF ($Type -eq "Workgroup") {
        IF ($Type -ne $DomainJoinStatus.DomainType) { $Result.Success = $False; $Result.Details = "Domain Type Doesn't Match"; RETURN Return-Results } 
    }

    ### End
    RETURN Return-Results
}
FUNCTION Verify-BitLockerEncryption {
    
    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [STRING[]]$Volume
    )

    ### Variables
    $StartTime = (Get-Date)
    $Result = [PSCustomObject]@{
        Action = "Verify"
        Duration = $null
        RequestedName = $null
        Name = "BitLocker Encryption"
        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 }
    }
    
    $BitLockerVolumes = Get-BitLockerVolume

    FOREACH ($Item in $Volume) {
        $Item = $Item.Replace(':','')
        IF ($Item -eq "All") {
            FOREACH ($Item2 in $BitLockerVolumes.EncryptionPercentage) {
                IF ($Item2 -ne 100) { $Result.Success = $False; $Result.Details = "Not All Volumes Encrypted"; RETURN Return-Results }
            }
        }
        ELSE {
            IF (!(Test-NotNull (Get-Volume $Item -ErrorAction SilentlyContinue))) { continue }            
            ELSEIF (($BitLockerVolumes | Where-Object { $_.MountPoint -like "*$Item*" }).EncryptionPercentage -ne 100) {
                $Result.Success = $False; $Result.Details = "$Item Not Encrypted"; RETURN Return-Results
            } 
        }
    }   

    ### End
    RETURN Return-Results
}


### 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-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
}
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              = 15
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = 'Send-Keystroke -Title "Dynamsoft Service" -Key "{Enter}","{Enter}","{Enter}","{Enter}","{Enter}" -Delay 5'
        
        ### 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-EpsonOposADK {

    [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             = "EPSON OPOS ADK"
        ApplicationVersion          = "3.26.0.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/EWqnCOLDSFxPoDr1pRKAXIwB8JftMcIUuY-fFf37QpnF5w?Download=1"       
        FileName                    = "EPSON_OPOS_ADK_V3.00ER26.zip"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = "EPSON_OPOS_ADK_V3.00ER26.exe"

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/INSTALL /QUIET /NORESTART"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\ProgramData\Package Cache\{98ebde93-e9a2-48a5-8ad2-02956e12ec0f}\EPSON_OPOS_ADK_V3.00ER26.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/UNINSTALL /QUIET /NORESTART"
        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 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-iNovahCashier {

    [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             = "iNovah 2 - Cashier"
        ApplicationVersion          = "2.61.80.196"
        ExactVersion                = $False
        CustomVersionCommand        = $null

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

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/swsurl:http://inovahapps.atm.local/iNovah2System/ /instance:Default"
        InstallTimeout              = 5
        PostInstallDelay            = 2
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = 'Start-Sleep 15;
                                       Send-Keystroke -Title "iNovah 2 - Cashier - InstallShield Wizard" -Key "{Enter}","{Enter}" -Delay 25'

        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files (x86)\InstallShield Installation Information\{689994BA-D700-4F98-A9D7-612F3FC74525}\setup.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "-runfromtemp -l0x0409 -removeonly"
        UninstallTimeout            = 45
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = 'Start-Sleep 15;
                                       Send-Keystroke -Title "iNovah 2 - Cashier - InstallShield Wizard" -Key "{Enter}","{Enter}","{Enter}" -Delay 15'

                       
        ### 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-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-MicroDicomDICOMViewer {

    [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             = "MicroDicom DICOM Viewer*"
        ApplicationVersion          = "2025.1"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://www.microdicom.com/downloads/Software/MicroDicom-2025.3-x64.exe"       
        FileName                    = "MicroDicom-2025.3-x64.exe"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/S"
        InstallTimeout              = 300
        PostInstallDelay            = 30
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Program Files\MicroDicom\uninstall.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/S"
        UninstallTimeout            = 180
        PostUninstallDelay          = 20
        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-MSSQLLocalDB2017 {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Run","Install","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 SQL Server 2017 LocalDB*"
        ApplicationVersion          = "14.0.100.169"
        ExactVersion                = $False
        CustomVersionCommand        = $null

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

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/QN /NORESTART IAcceptSqlLocalDBLicenseTerms=YES"
        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=Microsoft Corporation, OU=MOPR, 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-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-OracleInstantClient {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","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             = "Oracle Instant Client"
        ApplicationVersion          = "12.1"
        ExactVersion                = $False
        CustomVersionCommand        = "12.1"

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

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = 'Expand-Archive -Path "C:\Integris\Temp\instantclient_21_1.zip" -DestinationPath "C:\Oracle\instantclient_12_1\"'
        InvokeInstallCommand        = $True
        InstallArguments            = $null
        InstallTimeout              = 500
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF (((Get-ChildItem -Path "C:\Oracle\instantclient_12_1\" -Recurse -File -ErrorAction SilentlyContinue | Measure-Object -ErrorAction SilentlyContinue -Property Length -Sum).Sum / 1MB) -gt 175) { $True } ELSE { $False }'
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = 'Remove-Item -Path "C:\Oracle\instantclient_12_1\" -Recurse -Force -ErrorAction SilentlyContinue'
        InvokeUninstallCommand      = $True
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = 'IF ((Get-Item -Path "C:\Oracle\instantclient_12_1\" -ErrorAction SilentlyContinue)) { $False } ELSE { $True }'
        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-OrionServicesCertificate {

    [CmdletBinding()]
    PARAM ( 
        [Parameter(Mandatory)]
        [ValidateSet("Install","Download","Uninstall","Reinstall")]
        [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             = "Orion Services Certificate"
        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/EeQCKwduFzpHnhQMCdcmWwIBChsKdpEvuQhkG6DuwuwBDQ?Download=1" 
        FileName                    = "OrionServices.zip"                  
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = "OrionServices.pfx"

        ### Package Preference
        CleanupMode                 = "Never"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = 'netsh http delete sslcert ipport=0.0.0.0:8443 | out-null;
                                       certutil -p b33t%%JU -importPFX "C:\Integris\Temp\Orion Services Certificate\OrionServices.pfx";
                                       netsh http add sslcert ipport=0.0.0.0:8443 certhash=5850451632562b90747964dc7987caab5a925082 appid="{2DD85661-11A0-471B-9C62-2F465B954B8D}";
                                       Start-Sleep 5'
                                      
        InvokeInstallCommand        = $True
        InstallArguments            = $null
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = 'IF (Get-ChildItem -Path Cert:\LocalMachine -Recurse | Where-Object { $_.Issuer -like "*andrewweatherspoon@flhsmv.gov*" -and $_.HasPrivateKey -eq $True }) { $True } ELSE { $False }' 
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = 'Get-ChildItem -Path Cert:\LocalMachine -Recurse | Where-Object { $_.Issuer -like "*andrewweatherspoon@flhsmv.gov*" -and $_.HasPrivateKey -eq $True } | Remove-Item'
        InvokeUninstallCommand      = $True
        UninstallArguments          = $null
        UninstallTimeout            = 180
        PostUninstallDelay          = 2
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = 'IF (Get-ChildItem -Path Cert:\LocalMachine -Recurse | Where-Object { $_.Issuer -like "*andrewweatherspoon@flhsmv.gov*" -and $_.HasPrivateKey -eq $True }) { $False } ELSE { $True }' 
        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-OrionHost {

    [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             = "Orion Version 1.0"
        ApplicationVersion          = "1.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/EeQCKwduFzpHnhQMCdcmWwIBChsKdpEvuQhkG6DuwuwBDQ?Download=1"     
        FileName                    = "OrionServices.zip"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = "OrionHostSetup-2.0.20.0.exe"

        ### Package Preference
        CleanupMode                 = "Never"
        UpdateMethod                = "UninstallReinstall"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/VERYSILENT /NORESTART"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Drive\Host\unins000.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/VERYSILENT /NORESTART"
        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 App-OrionServices {

    [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             = "Orion Services Version 1.0"
        ApplicationVersion          = "1.0"
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://integristech-my.sharepoint.com/:u:/g/personal/david_mcvicker_integrisit_com/EeQCKwduFzpHnhQMCdcmWwIBChsKdpEvuQhkG6DuwuwBDQ?Download=1"      
        FileName                    = "OrionServices.zip"              
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = "OrionServicesSetup-2.0.40.0.exe"

        ### Package Preference
        CleanupMode                 = "Never"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/VERYSILENT /NORESTART"
        InstallTimeout              = 300
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\Drive\WindowsServices\unins000.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/VERYSILENT /NORESTART"
        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 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-TBarcodeActiveX {

    [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             = "TBarCode ActiveX*"
        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/EX2XSJsSZ_hJkaWFncGdJwQBj3PwCreYNNzA52ElZ6y0Bw?Download=1"      
        FileName                    = "Tbarcode2.1.8.zip"               
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = "setup.exe"

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = $null
        InstallTimeout              = 40
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = 'Start-Sleep 10;
                                       Send-Keystroke -Title "Question" -Key "{Enter}" -Delay 4;
                                       Start-Sleep 4;
                                       Send-Keystroke -Title "Software License Agreement" -Key "{Enter}" -Delay 4;
                                       Start-Sleep 4;
                                       Send-Keystroke -Title "Choose Destination Location" -Key "{Enter}" -Delay 8;
                                       Start-Sleep 8;
                                       Send-Keystroke -Title "Setup Complete" -Key "{Enter}" -Delay 4;
                                       Start-Sleep 4;
                                       Send-Keystroke -Title "Information" -Key "{Enter}" -Delay 4'

        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\WINDOWS\IsUninst.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = '-f"C:\Program Files (x86)\TEC-IT Datenverarbeitung GmbH\TBarCode2\Uninst.isu"'
        UninstallTimeout            = 20
        PostUninstallDelay          = 10
        PreUninstallEndProcess      = $null
        PostUninstallEndProcess     = $null
        CustomUninstallVerification = $null
        UninstallKeystrokes         = 'Start-Sleep 10;
                                       Send-Keystroke -Title "Confirm File Deletion" -Key "{Enter}","{Enter}" -Delay 4;
                                       Send-Keystroke -Title "Remove Shared File?" -Key "{Enter}","{Enter}" -Delay 4;
                                       Send-Keystroke -Title "Remove Programs From Your Computer" -Key "{Enter}","{Enter}" -Delay 4'

                       
        ### 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-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          = "25000.0.0"
        ExactVersion                = $False
        CustomVersionCommand        = '(Get-AppXPackage "MSTeams" -AllUsers).Version | select -First 1'

        #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,
        [STRING]$Server,
        [STRING]$Username,        
        [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 $Server) { SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'Server'; 'Type' = 'String'; 'Value' = $Server; 'Path' = 'SOFTWARE\WatchGuard\SSLVPNClient\Settings'} -ErrorAction SilentlyContinue }
    IF (Test-NotNull $Username) { SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'Username'; 'Type' = 'String'; 'Value' = $Username; 'Path' = 'SOFTWARE\WatchGuard\SSLVPNClient\Settings'} -ErrorAction SilentlyContinue }
    SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'AutoReconnect'; 'Type' = 'DWORD'; 'Value' = 1; 'Path' = 'SOFTWARE\WatchGuard\SSLVPNClient\Settings'} -ErrorAction SilentlyContinue

    $Parameters  = @{
        #Application Info
        ApplicationName             = "WatchGuard Mobile VPN*"
        ApplicationVersion          = "12.11.2"
        ExactVersion                = $False
        CustomVersionCommand        = $null
        
        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://cdn.watchguard.com/SoftwareCenter/Files/MUVPN_SSL/12_11_2/WG-MVPN-SSL_12_11_2.exe"
        FileName                    = "WG-MVPN-SSL_12_11_2.exe"          
        BackupDownloadLink          = "https://cdn.watchguard.com/SoftwareCenter/Files/MUVPN_SSL/12_11/WG-MVPN-SSL_12_11.exe"
        BackupFileName              = "WG-MVPN-SSL_12_11.exe"
        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      = "wgsslvpnc","wgsslvpnsrc"
        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

    IF (Test-NotNull $Server) { SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'Server'; 'Type' = 'String'; 'Value' = $Server; 'Path' = 'SOFTWARE\WatchGuard\SSLVPNClient\Settings'} -ErrorAction SilentlyContinue }
    IF (Test-NotNull $Username) { SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'Username'; 'Type' = 'String'; 'Value' = $Username; 'Path' = 'SOFTWARE\WatchGuard\SSLVPNClient\Settings'} -ErrorAction SilentlyContinue }
    SET-RegistryValueForAllUsers -RegistryInstance @{'Name' = 'AutoReconnect'; 'Type' = 'DWORD'; 'Value' = 1; 'Path' = 'SOFTWARE\WatchGuard\SSLVPNClient\Settings'} -ErrorAction SilentlyContinue

}
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-VisualC++2005Redistributablex86 {

    [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 Visual C++ 2005 Redistributable"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://download.microsoft.com/download/8/b/4/8b42259f-5d70-43f4-ac2e-4b208fd8d66a/vcredist_x86.EXE"      
        FileName                    = "vcredist_x86.EXE"          
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/Q"
        InstallTimeout              = 120
        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            = 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-VisualC++2005Redistributablex64 {

    [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 Visual C++ 2005 Redistributable (x64)"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://download.microsoft.com/download/8/b/4/8b42259f-5d70-43f4-ac2e-4b208fd8d66a/vcredist_x64.EXE"      
        FileName                    = "vcredist_x64.EXE"          
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/Q"
        InstallTimeout              = 120
        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            = 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-VisualC++20152022Redistributablex86 {

    [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 Visual C++ 2015-2022 Redistributable (x86)*"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://aka.ms/vs/17/release/vc_redist.x86.exe"     
        FileName                    = "vc_redist.x86.exe"          
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/Q"
        InstallTimeout              = 120
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\ProgramData\Package Cache\{46c3b171-c15c-4137-8e1d-67eeb2985b44}\VC_redist.x86.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/uninstall /Q"
        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-VisualC++20152022Redistributablex64 {

    [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 Visual C++ 2015-2022 Redistributable (x64)*"
        ApplicationVersion          = $null
        ExactVersion                = $False
        CustomVersionCommand        = $null

        #Download Info
        SavePath                    = "C:\Integris\Temp"
        DownloadLink                = "https://aka.ms/vs/17/release/vc_redist.x64.exe"     
        FileName                    = "vc_redist.x64.exe"          
        BackupDownloadLink          = $null
        BackupFileName              = $null
        ZipInstallerPath            = $null

        ### Package Preference
        CleanupMode                 = "AfterSuccess"
        UpdateMethod                = "InstallOver"
        ForceDownload               = $False
        
        ### Install Specific
        CustomInstallCommand        = $null
        InvokeInstallCommand        = $null
        InstallArguments            = "/Q"
        InstallTimeout              = 120
        PostInstallDelay            = 5
        PreInstallEndProcess        = $null
        PostInstallEndProcess       = $null
        CustomInstallVerification   = $null
        InstallKeystrokes           = $null
        
        ### Run Specific
        RunPath                     = $null
        RunArguements               = $null
         
        ### Uninstall Specific
        UninstallCommand            = "C:\ProgramData\Package Cache\{9387bec2-2f2b-48d1-a0ce-692c5df7042d}\VC_redist.x64.exe"
        InvokeUninstallCommand      = $False
        UninstallArguments          = "/uninstall /Q"
        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-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
}









### 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 -AllowClobber -Force
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force
 
 
Run-DeploymentSet "App-MSSQLLocalDB2017 Install",
                  "App-7Zip Install",
                  "App-Teams Install",
                  "App-Chrome Install",
                  "App-Greenshot Install",
                  "App-Firefox Install",
                  "App-Java Install",
                  "Font-ArialRoundedMTBoldTall Install",
                  "Font-AlphaTypeMS Install",
                  "Font-FloridaVehicleFont Install",
                  "Font-Swis721CnBT Install",
                  "Font-Swiss911UCmBT Install",
                  "App-VisualC++2005Redistributablex86 Install",
                  "App-VisualC++2005Redistributablex64 Install",
                  "App-VisualC++20152022Redistributablex86 Install",
                  "App-VisualC++20152022Redistributablex64 Install",
                  "Driver-DS530II Install",
                  "App-AcrobatDC Install",
                  "App-NotePad++ Install",
                  "App-OneDrive Install",
                  "App-TBarcodeActiveX Install",
                  "App-Slack Install",
                  "App-DynamsoftService Install",
                  "App-Office365ProPlusx64 Install",
                  "App-EpsonOposADK Install" -RestartWhenComplete | FT
 
--#>