<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** #50020 # What this does Adds **Azure Data Studio** as a Windows Fleet-maintained app. One of the 11 apps split out of #48501 that failed the FMA validator; #50016 shipped the 6 that passed. ## Why it was failing The install itself worked — the validator logged `New application detected at: C:\Program Files\Azure Data Studio`. The *script* never returned: ``` 20:08:19 INFO msg="Executing install script..." app="Azure Data Studio" 20:18:19 ERROR msg="Error executing install script: exit status 1" # exactly 10:00 later 20:18:19 INFO msg="New application detected at: C:\Program Files\Azure Data Studio" ``` Ten minutes on the nose is the validator's `executeScript` timeout. Azure Data Studio is a Visual Studio Code fork and ships the same Inno Setup script — including the **`runcode` task, which launches the app when the install finishes**. Because `Start-Process -Wait` waits for the process *and all of its descendants*, the launched app kept the script blocked forever. The fix is the switch VS Code's own FMA already uses: `/MERGETASKS=!runcode` (see [`vscode_install.ps1`](ee/maintained-apps/inputs/winget/scripts/vscode_install.ps1) and [`vscodium_install.ps1`](ee/maintained-apps/inputs/winget/scripts/vscodium_install.ps1), both of which pass validation). The script also waits on the installer process alone rather than its descendants, polls for the Add/Remove Programs entry, and stops a stray `azuredatastudio` process as a backstop in case a future build ignores the task suppression. ## Notes - Machine-scope x64 installer, per the winget manifest — Azure Data Studio publishes both user and machine scope, and Fleet installs run as SYSTEM, so machine scope is required. - Clean ARP `DisplayName` (`Azure Data Studio`), so exact name matching. Publisher `Microsoft Corporation`. - Uninstall is unchanged: the Inno uninstaller doesn't leave anything resident, and `-Wait` waiting on descendants is the desired behavior there (Inno relaunches itself from `%TEMP%`). - Ships a new catalog icon and website asset. # Checklist for submitter - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. - [x] Timeouts are implemented and retries are limited to avoid infinite loops ## Testing - [x] FMA CI validator (install → detect → uninstall) **passes** on the SYSTEM-context Windows runner — [run 30384162280](https://github.com/fleetdm/fleet/actions/runs/30384162280) (`All checks passed`) - [x] Generated output verified locally: manifest SHA matches the winget manifest, exists/patched queries reviewed for name + publisher correctness, `apps.json` is valid JSON with a description filled in. - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Azure Data Studio to the available Windows software catalog. * Added support for installing and uninstalling Azure Data Studio (version 1.52.0) via silent installer and uninstaller flows with completion detection. * Added an Azure Data Studio icon to the software interface for better visual identification. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
37 lines
2.1 KiB
PowerShell
37 lines
2.1 KiB
PowerShell
$softwareName = "Azure Data Studio"
|
|
$softwareNameLike = "$softwareName*"
|
|
$softwarePublisher = "Microsoft Corporation"
|
|
$uninstallArgs = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART"
|
|
|
|
$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
|
|
$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
|
|
$exitCode = 0
|
|
|
|
try {
|
|
[array]$uninstallKeys = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |
|
|
ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue }
|
|
|
|
$foundUninstaller = $false
|
|
foreach ($key in $uninstallKeys) {
|
|
if ($key.DisplayName -like $softwareNameLike -and $key.Publisher -eq $softwarePublisher) {
|
|
$foundUninstaller = $true
|
|
$uninstallCommand = if ($key.QuietUninstallString) { $key.QuietUninstallString } else { $key.UninstallString }
|
|
if ($uninstallCommand -match '^\s*"([^"]+)"\s*(.*)$') {
|
|
$uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = "$($Matches[2]) $uninstallArgs".Trim() }
|
|
} elseif ($uninstallCommand -match '(?i)^\s*(.+?\.exe)\s*(.*)$') {
|
|
$uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = "$($Matches[2]) $uninstallArgs".Trim() }
|
|
} elseif ($uninstallCommand -match '^\s*(\S+)\s*(.*)$') {
|
|
$uninstallCommand = $Matches[1]; if ($Matches[2]) { $uninstallArgs = "$($Matches[2]) $uninstallArgs".Trim() }
|
|
}
|
|
Write-Host "Uninstall command: $uninstallCommand"; Write-Host "Uninstall args: $uninstallArgs"
|
|
$processOptions = @{ FilePath = $uninstallCommand; PassThru = $true; Wait = $true }
|
|
if ($uninstallArgs -ne '') { $processOptions.ArgumentList = $uninstallArgs }
|
|
$process = Start-Process @processOptions
|
|
$exitCode = $process.ExitCode; Write-Host "Uninstall exit code: $exitCode"; break
|
|
}
|
|
}
|
|
if (-not $foundUninstaller) { Write-Host "Uninstall entry not found for '$softwareName'."; Exit 0 }
|
|
} catch { Write-Host "Error: $_"; Exit 1 }
|
|
|
|
Exit $exitCode
|