This repository contains a PowerShell script for removing display driver packages by using devcon.exe.
The script is designed to remain true to its original operational use case: deployment through Microsoft Configuration Manager (ConfigMgr / MECM) as a script, with explicit process exit codes that can be collected and reported by the client.
It grew out of a Windows 7 to Windows 10 in-place upgrade effort where legacy display drivers repeatedly blocked the upgrade path. The practical problem was not just removing a display device. It was reliably removing the associated driver package without needing to know the environment-specific oem*.inf name ahead of time.
- PowerShell 7.4 development
Quick navigation:
- Portfolio Context
- Engineering Principles in Practice
- Validation And Maintenance
- Repository Structure
This repository is part of a PowerShell portfolio built from pwsh-dev-template, and it is anchored in a real deployment problem rather than a generic sample. It demonstrates how to preserve the operational shape of a ConfigMgr-delivered script while still improving readability, testability, and long-term maintainability.
A reviewer should pay attention first to the script's practical lineage, its deployment-aware safety model, and how the repo keeps a single-file operational artifact compatible with clearer structure, explicit exit behavior, and test-focused internal organization. It is not a demo script or an abstract exercise; it comes from an actual deployment blocker and is intended to preserve that lineage while improving maintainability over time.
- Deterministic Base Runtime: The development container is built from a pinned PowerShell 7.4 on Ubuntu 22.04 base image to reduce environmental drift
- ConfigMgr-Compatible Delivery Shape: The repository preserves a single-script artifact that can still be imported and executed through ConfigMgr Scripts without forcing an artificial package-first redesign
- Practical Tool Selection:
devcon.exeis used because the problem is hardware-ID-driven driver removal, not merely uninstalling a knownoem*.infpackage by name - Safe Driver Removal: Elevated-context checks, virtualization guards, dependency verification, and
ShouldProcesssupport are treated as integral behavior, not optional polish - Explicit Result Signaling: Exit codes remain part of the interface so ConfigMgr and operators can distinguish operational outcomes cleanly
- Testable Single-Script Design: Internal helper structure supports Pester validation without changing the deployable artifact into a multi-file operational unit
For the deeper operating model behind that approach, see docs/powershell-ai-operating-model.md. For repository-specific structure and script design notes, see docs/script-architecture-overview.md.
- Read the origin and ConfigMgr sections below first so the deployment shape and operational constraints stay clear.
- Review the safety checks and explicit exit-code behavior before making changes to execution flow.
- Use
-WhatIfwhen validating removal intent before running the script in a real environment. - Use the Pester tests and repo checks to validate changes without requiring
devcon.exein CI. - Refer to
Usage Notes,Exit Codes, and the script-architecture overview for the practical execution and maintenance path.
- Runtime: PowerShell 7.4.x (LTS) on Ubuntu 22.04
- Execution Target: The real operational target is Windows because the script removes Windows display driver packages through
devcon.exe - Deployment Shape: The deployable artifact remains a single
.ps1file suitable for ConfigMgr Scripts deployment - Development Modes: Local VS Code, Docker Dev Containers, and GitHub Codespaces
- Isolation Strategy: Use the container to reduce host tooling and credential exposure during development work
- Pester 6.0.0: For unit and integration testing
- PSScriptAnalyzer 1.25.0: To enforce PowerShell best practices and security rules
- Azure CLI: Pre-installed for cloud resource management
- PSReadLine 2.4.5: Configured for a more efficient terminal experience
The automated Pester workflow is surfaced through the badge at the top of this README and validates the script through mocked devcon.exe interactions rather than real device changes.
src/Public/Uninstall-DisplayDrivers.ps1: the deployable script artifactTests/Unit/Uninstall-DisplayDrivers.Tests.ps1: Pester coverage for script logic and behavior contractsdocs/: architecture notes, operating-model guidance, and supporting documentationscripts/: validation, sync, cleanup, and README workflow entrypoints delivered from the template baseline
Run the standard repository checks before committing meaningful changes:
pwsh -NoProfile -File ./scripts/Invoke-RepoChecks.ps1If this repository keeps the template-managed generated Markdown blocks, refresh or validate them through:
pwsh -NoProfile -File ./scripts/Update-GeneratedMarkdown.ps1 -CheckUse .codex/skills/downstream-guidance-sync/SKILL.md with scripts/Invoke-TemplateGuidanceSync.ps1 when you want to adopt newer pwsh-dev-template guidance or README workflow assets without overwriting repository-owned implementation.
- Install PowerShell 7.4 or use the repository Dev Container / Codespace baseline for development work.
- Run the script in an elevated context when executing it for real driver removal.
- Ensure
devcon.exeis present in the same directory as the deployable script before runtime use. - Use
-WhatIffirst when validating intended behavior before actual removal. - Review
docs/agent-workflows.md,AGENTS.md, and.github/copilot-instructions.mdbefore using agent-driven repository changes.
This repository versions the PowerShell driver management project itself using Semantic Versioning.
- Current project version: see
VERSION - Version history: see
CHANGELOG.md
The project version is separate from the template-version badge at the top of this README. That badge records the synced pwsh-dev-template guidance and workflow baseline used by this repository.
Uninstall-DisplayDrivers.ps1 uses devcon.exe to:
- enumerate devices in the display class
- extract matching PCI hardware IDs from the returned device list
- remove the associated driver packages for those display adapters
The script is intentionally scoped to display drivers only.
pnputil.exe can remove driver packages, but it generally requires you to already know the exact published driver package name, such as an oem*.inf file.
In this scenario, that was a major limitation. The installed display device could be identified, but the exact oem*.inf package name was not always known ahead of time, and simply removing the device did not guarantee that Windows would not reinstall the same driver on restart.
devcon.exe was a better fit because it can enumerate display devices by class and target removal by hardware ID. That made it practical to identify the active display adapters, remove the corresponding driver packages, and reduce the risk of the legacy drivers returning after reboot.
The script is kept as a single .ps1 file because it is intended for ConfigMgr Scripts deployment.
That design choice is deliberate:
- the script can be imported directly into the ConfigMgr console
- execution status can be interpreted through explicit exit codes
- the operational deployment shape stays close to the way the script was originally used
This repository may include tests and supporting documentation, but the deployable artifact remains a script rather than a package/program-oriented multi-file solution.
The repository preserves the script in a form that reflects its original operational shape while making it easier to review, test, and maintain over time.
The script includes several intentional guardrails:
- it requires an elevated administrative context
- it blocks execution on known virtual machine platforms
- it verifies that
devcon.exeis present before attempting removal - it supports
-WhatIfthroughShouldProcess
These checks are meant to make the script safer to review, test, and deploy.
The script exits with explicit codes so ConfigMgr can report outcomes more accurately:
0= Success1= General failure2= Dependency missing (devcon.exenot found)3= Virtual machine detected4=devcon.exe listclass displayfailed5= Administrative context required
Validation status is surfaced at the top of this README through the GitHub Actions badge.
That badge reflects the current result of the repository's automated CI workflow on the main branch, including repo checks and unit-test validation for the script's current behavior.
Although the deployment target is a single ConfigMgr-importable script, the script has been structured internally with helper functions so it can still be tested with Pester.
One intentional design choice was replacing a parse-time #Requires -RunAsAdministrator guard with a runtime administrative-context check. That keeps the operational requirement in place while also allowing non-elevated test sessions to validate the script's behavior safely.
The automated Pester tests validate script logic by mocking devcon.exe interactions rather than invoking the real executable. That means CI can run without devcon.exe being present in the repository, while production use still requires the real devcon.exe file to be present beside the script at runtime.
That balance is important here: the script remains faithful to its deployment origins, but it is no longer locked into a form that is difficult to validate safely.
Before using the script:
- run it in an elevated context
- ensure
devcon.exeis available in the same directory as the script - use
-WhatIffirst if you want to validate intended behavior before removal
Example:
.\Uninstall-DisplayDrivers.ps1 -WhatIf