This pull request adds support for several new Windows applications to the maintained apps catalog, along with robust PowerShell install and uninstall scripts for each. The main focus is on enabling automated, silent deployment and removal of these apps using Winget, with careful handling of installer quirks and registry lookups to ensure reliability in enterprise environments. **New application support:** * Added `Citrix Workspace`, `Evernote`, `ExpressVPN`, `Front`, `Hyper`, `Jabra Direct`, `Microsoft Teams`, `OneDrive`, `Opera`, `Podman Desktop`, and `REAPER` to the `ee/maintained-apps/inputs/winget` catalog with appropriate metadata for each app. [[1]](diffhunk://#diff-3ba331a553f359a02dd3d824d3edab85292e2d1d9c1a6a739e313a9b63d5a88fR1-R13) [[2]](diffhunk://#diff-917d3e25bae801c48ae70f70bf43e8540d962046bb773dbeed633eb52323e084R1-R12) [[3]](diffhunk://#diff-b8f4026fc2a89254c0bdeb905120761ee78c6a76101deaf3dadd814ce3cafa94R1-R12) [[4]](diffhunk://#diff-72a2bcc2c2b9fadcf09505f8caefb681e79679ee99fb068a84698c783e81f17dR1-R12) [[5]](diffhunk://#diff-5bdb4220ac0cc23ff96963f975a55ef081493ee797545e0a1f65f9f4c50ef982R1-R12) [[6]](diffhunk://#diff-941487a1c1f2ba4d2da50e47f47bbab46478f2bb7c7e009fdd21bf2b68090413R1-R12) [[7]](diffhunk://#diff-9b5681ffd0b55fd89ce4f69e07668fa23df9582a921bf2000d9d2230429e16c9R1-R12) [[8]](diffhunk://#diff-b69363f34d224c471ec183bf7a2d6bab13d776c8905e499cac0e39f31868fd19R1-R12) [[9]](diffhunk://#diff-c8b49c5881565261369d37c862e055087cc65819900f961841c7dc76a83a879dR1-R13) [[10]](diffhunk://#diff-88ceb0a6b8de6484bfcb3f0d19264e307d3166a34f992eba11fcc9d60facb052R1-R13) [[11]](diffhunk://#diff-2557d37d79e9889f60f30557f28efb327e02bf33d4b255deefa912f855111412R1-R14) **Install script implementations:** * Added PowerShell install scripts for each new app, ensuring silent, machine- or user-scoped installs as appropriate, with correct handling of installer arguments and exit codes (including treating reboot-required codes as success for Citrix Workspace and ExpressVPN). [[1]](diffhunk://#diff-ccd33aec25bdbda547e3c4c9b4bcc32d923dcacfe6ebda1a80256d3388bb9003R1-R41) [[2]](diffhunk://#diff-2b0d909e843c3c8265f67dd0e69843c4b59cea7d33741c5be8662ad464f39832R1-R34) [[3]](diffhunk://#diff-fa9d859aa98e8240b9882363a62dc7c69a61186d186cf07c8065a8e11547a3c7R1-R37) [[4]](diffhunk://#diff-9baf7c34c008963410a30fec1e6949023d03d3c400ec0166c029dd5eebcfaefeR1-R27) **Uninstall script implementations:** * Added PowerShell uninstall scripts for each new app, using registry lookups to locate the correct uninstaller and applying silent uninstall arguments. Scripts handle argument parsing defensively and ensure correct removal in both per-user and per-machine contexts. [[1]](diffhunk://#diff-ab38143c2c6f191c4f57aff0adb35e8c7a67cd95522da13da25febc8f65cc73eR1-R92) [[2]](diffhunk://#diff-4657653f749298d4ae84fb467023108a273c8e621c8cc711d5821fbeacfa03cdR1-R91) [[3]](diffhunk://#diff-1280127be173a1bdce9e7f18343fa6aae26fc3d15e1935e196669131deb484bdR1-R89) These additions significantly expand the catalog's Windows app coverage and improve reliability and automation for enterprise deployments.
100 lines
4.0 KiB
PowerShell
100 lines
4.0 KiB
PowerShell
# MSIX: provision machine-wide so the app is available to all users at sign-in, then
|
|
# opportunistically register for the currently logged-on console user (via a scheduled
|
|
# task in their session) so the app is immediately visible without requiring sign-out.
|
|
#
|
|
# The Fleet agent runs as Local System on Windows, and Add-AppxPackage cannot run in that
|
|
# context (HRESULT 0x80073CF9). The scheduled task is the supported way to register a
|
|
# package in a user session from a system-context script.
|
|
|
|
$softwareName = "WindowsApp"
|
|
$taskName = "fleet-install-$softwareName.msix"
|
|
$scriptPath = "$env:PUBLIC\install-$softwareName.ps1"
|
|
$exitCodeFile = "$env:PUBLIC\install-exitcode-$softwareName.txt"
|
|
|
|
try {
|
|
|
|
$msixPath = $env:INSTALLER_PATH
|
|
if (-not $msixPath) {
|
|
throw "INSTALLER_PATH is not set"
|
|
}
|
|
|
|
Write-Host "Provisioning MSIX for all users..."
|
|
$result = Add-AppxProvisionedPackage -Online -PackagePath $msixPath -SkipLicense -ErrorAction Stop
|
|
$result | Out-String | Write-Host
|
|
|
|
# Win32_ComputerSystem.UserName returns the console user (DOMAIN\User) or null when no
|
|
# interactive session is active. Other RDP/fast-user-switch sessions won't get the
|
|
# immediate registration; those users will pick it up from the provisioned install at
|
|
# their next sign-in.
|
|
$userName = (Get-CimInstance Win32_ComputerSystem).UserName
|
|
if (-not $userName -or $userName -notlike "*\*") {
|
|
Write-Host "No interactive user logged on; provisioned install will register for each user at sign-in."
|
|
Start-Sleep -Seconds 5
|
|
Exit 0
|
|
}
|
|
|
|
Write-Host "Registering MSIX for logged-on user '$userName' via scheduled task..."
|
|
|
|
$userScript = @"
|
|
`$msixPath = "$msixPath"
|
|
`$exitCodeFile = "$exitCodeFile"
|
|
try {
|
|
Add-AppxPackage -Path `$msixPath -ErrorAction Stop | Out-String | Write-Host
|
|
Set-Content -Path `$exitCodeFile -Value 0
|
|
} catch {
|
|
Write-Host "Add-AppxPackage failed: `$(`$_.Exception.Message)"
|
|
Set-Content -Path `$exitCodeFile -Value 1
|
|
}
|
|
"@
|
|
|
|
Set-Content -Path $scriptPath -Value $userScript -Force
|
|
|
|
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
|
|
-Argument "-WindowStyle Hidden -ExecutionPolicy Bypass -File `"$scriptPath`""
|
|
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries
|
|
$principal = New-ScheduledTaskPrincipal -UserId $userName -RunLevel Highest
|
|
$task = New-ScheduledTask -Action $action -Settings $settings -Principal $principal
|
|
Register-ScheduledTask -TaskName $taskName -InputObject $task -User $userName -Force | Out-Null
|
|
Start-ScheduledTask -TaskName $taskName
|
|
|
|
$startDate = Get-Date
|
|
$state = (Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue).State
|
|
while ($state -ne "Running") {
|
|
Start-Sleep -Seconds 1
|
|
if ((New-Timespan -Start $startDate).TotalSeconds -gt 30) {
|
|
Write-Host "Per-user registration task did not start within 30s; provisioned install is still valid."
|
|
break
|
|
}
|
|
$state = (Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue).State
|
|
}
|
|
|
|
while ($state -eq "Running") {
|
|
Start-Sleep -Seconds 2
|
|
if ((New-Timespan -Start $startDate).TotalSeconds -gt 90) {
|
|
Write-Host "Per-user registration task did not complete within 90s; provisioned install is still valid."
|
|
break
|
|
}
|
|
$state = (Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue).State
|
|
}
|
|
|
|
if (Test-Path $exitCodeFile) {
|
|
$code = (Get-Content $exitCodeFile -ErrorAction SilentlyContinue | Select-Object -First 1).Trim()
|
|
if ($code -eq "0") {
|
|
Write-Host "Per-user registration completed for '$userName'."
|
|
} else {
|
|
Write-Host "Per-user registration did not complete cleanly (exit code: $code). Provisioned install is still valid."
|
|
}
|
|
}
|
|
|
|
Start-Sleep -Seconds 5
|
|
Exit 0
|
|
|
|
} catch {
|
|
Write-Host "Error: $_"
|
|
Exit 1
|
|
} finally {
|
|
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue | Out-Null
|
|
Remove-Item -Path $scriptPath -Force -ErrorAction SilentlyContinue
|
|
Remove-Item -Path $exitCodeFile -Force -ErrorAction SilentlyContinue
|
|
}
|