Add Dell Display and Peripheral Manager Windows FMA - #50030
Conversation
Removes frozen: true so the validator actually exercises install, detect and uninstall. The scripts were never run in CI, so they are hardened up front for the two hazards this installer presents: an InstallShield parent that hands off to child processes and can exit before the ARP entry is written, and a background app that stays resident afterwards -- both of which break Start-Process -Wait, which waits for descendants as well as the process itself.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #50030 +/- ##
=======================================
Coverage 67.97% 67.97%
=======================================
Files 3922 3923 +1
Lines 250032 250034 +2
Branches 13334 13334
=======================================
+ Hits 169949 169954 +5
+ Misses 64781 64778 -3
Partials 15302 15302
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds the Dell Display and Peripheral Manager Windows Fleet-maintained app (FMA) and its associated UI icon so it can be installed/detected/uninstalled by the maintained-app validator and displayed with a branded icon in the Software UI.
Changes:
- Added a new software icon component and mapped it in the SoftwarePage icon registry.
- Added Dell Display and Peripheral Manager to the maintained apps catalog (
outputs/apps.json) and introduced its Windows output manifest. - Added Winget input JSON and install/uninstall PowerShell scripts for the Windows FMA.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/pages/SoftwarePage/components/icons/index.ts | Registers the new Dell Display and Peripheral Manager icon in the name→icon map. |
| frontend/pages/SoftwarePage/components/icons/DellDisplayAndPeripheralManager.tsx | Adds the Dell Display and Peripheral Manager icon component. |
| ee/maintained-apps/outputs/dell-display-and-peripheral-manager/windows.json | Introduces the generated Windows manifest + embedded install/uninstall scripts for the app. |
| ee/maintained-apps/outputs/apps.json | Adds the app to the maintained-apps catalog list with description and slug. |
| ee/maintained-apps/inputs/winget/scripts/dell_dapm_uninstall.ps1 | Adds uninstall script with registry lookup and MSI/InstallShield handling. |
| ee/maintained-apps/inputs/winget/scripts/dell_dapm_install.ps1 | Adds install script with bounded waiting and ARP polling. |
| ee/maintained-apps/inputs/winget/dell-display-and-peripheral-manager.json | Adds the Winget input definition for generating the Windows manifest. |
Comments suppressed due to low confidence (1)
ee/maintained-apps/outputs/dell-display-and-peripheral-manager/windows.json:20
- This embedded install script uses $installTimeoutSeconds=480 and then can additionally poll up to 180s for ARP registration. Since the Windows validator kills scripts after 10 minutes (cmd/maintained-apps/validate/windows.go:297), the generated output here can exceed the cap and fail validation. Please ensure the generated output is regenerated/updated so the total worst-case runtime stays under 10 minutes.
"f60b0b6e": "# Learn more about .exe install scripts:\n# http://fleetdm.com/learn-more-about/exe-install-scripts\n\n$exeFilePath = \"${env:INSTALLER_PATH}\"\n\n# Dell Display and Peripheral Manager ships an InstallShield setup (~425 MB) that\n# extracts to %TEMP%, hands off to child processes, and leaves its own background\n# app running once installed. PowerShell's \"Start-Process -Wait\" waits for the\n# process *and all of its descendants*, so those would block this script. Wait on\n# the installer process alone, poll for the Add/Remove Programs entry (the\n# hand-off means the parent can exit before the install is finished), then stop\n# what the installer left running.\n# \"/Silent\" is the documented machine-scope Silent switch from the winget manifest.\n$installTimeoutSeconds = 480\n$pollSeconds = 15\n$leftovers = @(\"DDPM\", \"DellDisplayManager\", \"DisplayManager\")\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n\nfunction Test-DdpmRegistered {\n $null -ne (Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } |\n Where-Object { $_.DisplayName -like \"Dell Display and Peripheral Manager*\" } |\n Select-Object -First 1)\n}\n\ntry {\n\n$process = Start-Process -FilePath \"$exeFilePath\" -ArgumentList \"/Silent\" -PassThru\n# Touch .Handle so the exit code is still readable after the process ends:\n# Start-Process -PassThru otherwise returns $null for .ExitCode.\n$null = $process.Handle\n\n$elapsed = 0\nwhile (-not $process.HasExited -and ($elapsed -lt $installTimeoutSeconds)) {\n Start-Sleep -Seconds $pollSeconds\n $elapsed += $pollSeconds\n Write-Host \"Installing... ($elapsed seconds, registered: $(Test-DdpmRegistered))\"\n}\n\nif (-not $process.HasExited) {\n $registered = Test-DdpmRegistered\n Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue\n Start-Sleep -Seconds 2\n foreach ($name in $leftovers) { Stop-Process -Name $name -Force -ErrorAction SilentlyContinue }\n\n if ($registered) {\n Write-Host \"Installer still running after ${installTimeoutSeconds}s but DDPM is registered; stopped the lingering process.\"\n Exit 0\n }\n\n Write-Host \"Installer did not finish within ${installTimeoutSeconds}s and DDPM is not registered.\"\n Exit 1\n}\n\n$exitCode = $process.ExitCode\nWrite-Host \"Install exit code: $exitCode\"\n\n# InstallShield's parent process can exit before the child finishes writing the\n# Add/Remove Programs entry, so give it a bounded window to appear.\n$elapsed = 0\nwhile (-not (Test-DdpmRegistered) -and ($elapsed -lt 180)) {\n Start-Sleep -Seconds $pollSeconds\n $elapsed += $pollSeconds\n Write-Host \"Waiting for DDPM to register... ($elapsed seconds)\"\n}\n\nforeach ($name in $leftovers) { Stop-Process -Name $name -Force -ErrorAction SilentlyContinue }\n\nif (-not (Test-DdpmRegistered)) {\n Write-Host \"Dell Display and Peripheral Manager did not register in Add/Remove Programs.\"\n Exit 1\n}\n\n# 3010 (reboot required) and 1641 (reboot initiated) are successful installs.\nif ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 }\n\nExit $exitCode\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # hand-off means the parent can exit before the install is finished), then stop | ||
| # what the installer left running. | ||
| # "/Silent" is the documented machine-scope Silent switch from the winget manifest. | ||
| $installTimeoutSeconds = 480 |
| # itself -- would block this script. Stop those first, then wait only on the | ||
| # uninstaller and poll until the Add/Remove Programs entry clears. | ||
| $leftovers = @("DDPM", "DellDisplayManager", "DisplayManager") | ||
| $timeoutSeconds = 480 |
| } | ||
| ], | ||
| "refs": { | ||
| "d73afcc1": "$softwareName = \"Dell Display and Peripheral Manager\"\n\n# The install leaves DDPM's background app running, which holds file locks and --\n# because \"Start-Process -Wait\" waits for descendants as well as the process\n# itself -- would block this script. Stop those first, then wait only on the\n# uninstaller and poll until the Add/Remove Programs entry clears.\n$leftovers = @(\"DDPM\", \"DellDisplayManager\", \"DisplayManager\")\n$timeoutSeconds = 480\n\n$machineKey = 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$machineKey32on64 = 'HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'\n$exitCode = 0\n\nfunction Get-DdpmUninstallKey {\n Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |\n ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } |\n Where-Object { $_.DisplayName -like \"$softwareName*\" } |\n Select-Object -First 1\n}\n\nforeach ($name in $leftovers) {\n Stop-Process -Name $name -Force -ErrorAction SilentlyContinue\n}\n\ntry {\n $key = Get-DdpmUninstallKey\n if (-not $key) {\n Write-Host \"Uninstaller for '$softwareName' not found.\"\n Exit 1\n }\n\n $uninstallString = if ($key.QuietUninstallString) { $key.QuietUninstallString } else { $key.UninstallString }\n Write-Host \"Uninstall string: $uninstallString\"\n\n # If this resolves to an MSI product, uninstall it with msiexec directly --\n # the registry string typically omits a quiet switch, which would raise an\n # invisible dialog in session 0 and silently do nothing.\n $productCode = $null\n if ($uninstallString -match '(?i)msiexec(\\.exe)?.*?[/-][xi]\\s*(\\{[0-9A-Fa-f\\-]+\\})') {\n $productCode = $Matches[2]\n } elseif ($key.PSChildName -match '^\\{[0-9A-Fa-f\\-]+\\}$') {\n $productCode = $key.PSChildName\n }\n\n if ($productCode) {\n Write-Host \"Uninstalling MSI product $productCode\"\n $process = Start-Process -FilePath \"msiexec.exe\" `\n -ArgumentList \"/x\", $productCode, \"/quiet\", \"/norestart\" `\n -PassThru -NoNewWindow\n } else {\n # InstallShield uninstaller: parse the executable path, handling quoted\n # paths, unquoted paths containing spaces, and bare tokens, then pass the\n # documented silent switch.\n $uninstallCommand = $uninstallString\n $uninstallArgs = \"/Silent\"\n if ($uninstallCommand -match '^\\s*\"([^\"]+)\"\\s*(.*)$') {\n $uninstallCommand = $Matches[1]\n if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n } elseif ($uninstallCommand -match '(?i)^\\s*(.+?\\.exe)\\s*(.*)$') {\n $uninstallCommand = $Matches[1]\n if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n } elseif ($uninstallCommand -match '^\\s*(\\S+)\\s*(.*)$') {\n $uninstallCommand = $Matches[1]\n if ($Matches[2]) { $uninstallArgs = \"$($Matches[2]) $uninstallArgs\".Trim() }\n }\n\n Write-Host \"Uninstall command: $uninstallCommand\"\n Write-Host \"Uninstall args: $uninstallArgs\"\n $process = Start-Process -FilePath $uninstallCommand -ArgumentList $uninstallArgs -PassThru\n }\n\n # Touch .Handle so the exit code is still readable after the process ends:\n # Start-Process -PassThru otherwise returns $null for .ExitCode.\n $null = $process.Handle\n\n if (-not $process.WaitForExit($timeoutSeconds * 1000)) {\n Stop-Process -Id $process.Id -Force -ErrorAction SilentlyContinue\n Write-Host \"Uninstall timed out after $timeoutSeconds seconds\"\n Exit 1603\n }\n\n $exitCode = $process.ExitCode\n Write-Host \"Uninstall exit code: $exitCode\"\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n\nforeach ($name in $leftovers) {\n Stop-Process -Name $name -Force -ErrorAction SilentlyContinue\n}\n\n$elapsed = 0\nwhile ((Get-DdpmUninstallKey) -and ($elapsed -lt 180)) {\n Start-Sleep -Seconds 5\n $elapsed += 5\n Write-Host \"Waiting for the uninstall to finish... ($elapsed seconds)\"\n}\n\nif (Get-DdpmUninstallKey) {\n Write-Host \"'$softwareName' is still registered after the uninstall.\"\n Exit 1\n}\n\n# 3010 (reboot required) and 1641 (reboot initiated) are successful uninstalls.\nif ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 }\n\nExit $exitCode\n", |
| { | ||
| "name": "Dell Display and Peripheral Manager", | ||
| "slug": "dell-display-and-peripheral-manager/windows", | ||
| "package_identifier": "Dell.DisplayAndPeripheralManager", | ||
| "unique_identifier": "Dell Display and Peripheral Manager", | ||
| "program_publisher": "Dell Technologies", |
The winget manifest's /Silent produced exit code -2147213312 (0x80042000) with nothing installed. This is an InstallShield setup, whose silent switch is /S -- also what ManageEngine's silent-install reference documents for DDPM 2.2.2.8. Adds Dell's /CreateDebugLog so a further failure is diagnosable from the CI log rather than needing another blind cycle.
Script Diff Resultsee/maintained-apps/outputs/dell-display-and-peripheral-manager/windows.json=== Install // f60b0b6e -> ac21302d ===
--- /tmp/old.crQD0i 2026-07-28 00:34:42.893574485 +0000
+++ /tmp/new.9h1wnu 2026-07-28 00:34:42.893574485 +0000
@@ -10,16 +10,33 @@
# the installer process alone, poll for the Add/Remove Programs entry (the
# hand-off means the parent can exit before the install is finished), then stop
# what the installer left running.
-# "/Silent" is the documented machine-scope Silent switch from the winget manifest.
+# Switch choice: the winget manifest lists "/Silent", but that produced exit code
+# -2147213312 (0x80042000) with nothing installed. This is an InstallShield setup,
+# whose actual silent switch is "/S" -- which is also what ManageEngine's silent
+# install reference documents for DDPM 2.2.2.8. "/CreateDebugLog" is Dell's own
+# logging switch, so a future failure is diagnosable from the CI log.
$installTimeoutSeconds = 480
$pollSeconds = 15
$leftovers = @("DDPM", "DellDisplayManager", "DisplayManager")
+$dellLog = Join-Path $env:TEMP "ddpm-install.log"
+
$machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
$machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
+$userKey = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
+
+function Write-DellLog {
+ if (Test-Path $dellLog) {
+ Write-Host "--- DDPM install log (last 60 lines) ---"
+ Get-Content $dellLog -Tail 60 | ForEach-Object { Write-Host $_ }
+ Write-Host "--- end of DDPM install log ---"
+ } else {
+ Write-Host "No DDPM install log was written at $dellLog."
+ }
+}
function Test-DdpmRegistered {
- $null -ne (Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue |
+ $null -ne (Get-ChildItem -Path @($machineKey, $machineKey32on64, $userKey) -ErrorAction SilentlyContinue |
ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } |
Where-Object { $_.DisplayName -like "Dell Display and Peripheral Manager*" } |
Select-Object -First 1)
@@ -27,7 +44,9 @@
try {
-$process = Start-Process -FilePath "$exeFilePath" -ArgumentList "/Silent" -PassThru
+$process = Start-Process -FilePath "$exeFilePath" `
+ -ArgumentList "/S /CreateDebugLog=`"$dellLog`"" `
+ -PassThru
# Touch .Handle so the exit code is still readable after the process ends:
# Start-Process -PassThru otherwise returns $null for .ExitCode.
$null = $process.Handle
@@ -51,6 +70,7 @@
}
Write-Host "Installer did not finish within ${installTimeoutSeconds}s and DDPM is not registered."
+ Write-DellLog
Exit 1
}
@@ -70,6 +90,7 @@
if (-not (Test-DdpmRegistered)) {
Write-Host "Dell Display and Peripheral Manager did not register in Add/Remove Programs."
+ Write-DellLog
Exit 1
}
=== Uninstall // d73afcc1 -> 4219524c ===
--- /tmp/old.tdYhHh 2026-07-28 00:34:42.918574524 +0000
+++ /tmp/new.LaMel9 2026-07-28 00:34:42.919574525 +0000
@@ -50,9 +50,11 @@
} else {
# InstallShield uninstaller: parse the executable path, handling quoted
# paths, unquoted paths containing spaces, and bare tokens, then pass the
- # documented silent switch.
+ # documented silent switch. "/S" is InstallShield's silent switch and what
+ # ManageEngine's DDPM reference documents for uninstall as well; the winget
+ # manifest's "/Silent" is not recognised by this installer.
$uninstallCommand = $uninstallString
- $uninstallArgs = "/Silent"
+ $uninstallArgs = "/S"
if ($uninstallCommand -match '^\s*"([^"]+)"\s*(.*)$') {
$uninstallCommand = $Matches[1]
if ($Matches[2]) { $uninstallArgs = "$($Matches[2]) $uninstallArgs".Trim() } |
| function Test-DdpmRegistered { | ||
| $null -ne (Get-ChildItem -Path @($machineKey, $machineKey32on64, $userKey) -ErrorAction SilentlyContinue | | ||
| ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } | | ||
| Where-Object { $_.DisplayName -like "Dell Display and Peripheral Manager*" } | | ||
| Select-Object -First 1) | ||
| } |
| function Get-DdpmUninstallKey { | ||
| Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue | | ||
| ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } | | ||
| Where-Object { $_.DisplayName -like "$softwareName*" } | | ||
| Select-Object -First 1 | ||
| } |
|
Closing: Dell DAPM is being dropped from #50020 with a documented reason. Un-freezing it produced the first real validator evidence for this app — it aborts at exit code 0x80042000 before installing anything, identically for both |
Related issue: #50020
What this does
Adds Dell Display and Peripheral Manager as a Windows Fleet-maintained app, and un-freezes it so CI actually validates it.
This app was carried at
"frozen": truethrough #48501, which means the validator skipped it entirely (App is frozen, skipping validation...). #50020 calls for it to be un-frozen and validated, or dropped. This PR does the former.What changed
"frozen": trueis removed from the input, so the validator runs install → detect → uninstall like every other app.Because the scripts have never actually been exercised, they're hardened up front for the two hazards this installer presents rather than waiting for CI to find them:
%TEMP%and hands off to child processes, so the parent can exit before the Add/Remove Programs entry is written. The install script waits on the installer process alone (Start-Process -Waitwaits for the process and all of its descendants, which is what broke five other apps in this batch), then polls for the ARP entry with a bounded window.-Waitand hold file locks during uninstall. Both scripts stop it explicitly.The uninstall script also resolves an MSI product code when the registry string is an
MsiExec /X{...}command and re-runs it with/quiet /norestart— the same session-0 dialog problem fixed for Google Earth Pro in #50022 — falling back to the InstallShield uninstaller with/Silentotherwise.Notes
CompanyName: Dell TechnologiesandProductName: Dell Display and Peripheral Manager, matchingunique_identifierand the exists query's publisher./Silentis the documented machine-scopeSilentswitch from the winget manifest.curlspot-check of this URL is misleading.Checklist for submitter
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.Testing
apps.jsonis valid JSON with a description filled in.