A complete modernisation of the classic LazyWinAdmin (2012) PowerShell GUI tool, rebuilt from scratch as a native PowerShell 7.4+ WPF module. Manages Windows workstations and servers through a clean tabbed interface with async operations, cloud integration, and a full Pester v5 test suite.
Before/after: the original 2012 WinForms interface is preserved in
Media/lwa-v0.4-main01.png.
| Requirement | Details |
|---|---|
| PowerShell | 7.4 or newer |
| OS | Windows 10 / 11 / Server 2019+ |
| .NET | Included with PS 7.4+ |
| Microsoft Graph modules | Microsoft.Graph.Authentication, .Users, .Groups, .DeviceManagement |
| Azure modules | Az.Accounts, Az.ResourceGraph |
| Exchange (optional) | ExchangeOnlineManagement — required for the Exchange tab |
| RSAT (optional) | Rsat.ActiveDirectory — required for the Active Directory tab |
# Install required modules (first time only)
Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Users, `
Microsoft.Graph.Groups, Microsoft.Graph.DeviceManagement, `
Az.Accounts, Az.ResourceGraph -Scope CurrentUser
# Optional: Exchange tab
Install-Module ExchangeOnlineManagement -Scope CurrentUser
# Import and launch
Import-Module .\LazyWinAdminModule\LazyWinAdminModule.psd1 -Force
Start-LazyWinAdminTip: Some features (hardware inventory, RDP toggle, registry writes) require local Administrator rights. The status bar shows your elevation level and offers a Restart as Admin button when needed.
- Ping — tests WinRM port 5985 reachability (the actual transport used by CIM)
- Get Uptime — last boot time formatted as
D Days H Hours M Minutes S Seconds - Enable / Disable RDP — toggles
fDenyTSConnectionsregistry key and Windows Firewall rule group (requires admin)
- List all services or filter to stopped-but-auto-start services
- Search by service name
- Start / Stop / Restart the selected service (requires admin) (new in v1.3.0)
- Export CSV — saves the current list to a file (new in v1.3.0)
- Result count displayed after each query (new in v1.3.0)
- Right-click any row → Copy Row to Clipboard (new in v1.3.0)
- Enumerates installed software via StdRegProv registry enumeration (never
Win32_Productwhich triggers MSI consistency repair) - Deduplicates across 32-bit and 64-bit uninstall keys
- Optional search/filter
- Export CSV + result count (new in v1.3.0)
- Model, manufacturer, serial number, CPU, RAM, OS via CIM (requires admin for WMI hardware classes)
- Motherboard product, serial, version
- Disk inventory with size/free/percent
- All network adapters with IP, MAC, DHCP status, default gateway
- Optional filter: IP-enabled adapters only
- Export CSV + adapter count (new in v1.3.0)
- Local users (no password hash exposure —
Passwordproperty intentionally excluded) - Local groups
- Users and groups from Microsoft Entra ID via Microsoft Graph
- OData injection guard on search terms
- Requires cloud authentication (Cloud Auth tab)
- Computer, user, and group queries via RSAT
- LDAP injection guard on AdFilter
SamAccountNameexcluded from user results (PII protection)- Requires RSAT ActiveDirectory module
Reads and remediates local device compliance settings — no network required:
| Check | Remediation |
|---|---|
| Location Services | Re-enables the lfsvc service and clears policy overrides |
| OneDrive | Uninstalls OneDrive client cleanly (process + registry + files) |
| Outlook External Images | Sets the registry flag that blocks automatic external image loading |
| Windows Update active hours | Writes configurable start/end hours to HKLM (dynamic — enter any 0-23 value) |
| UWF (Unified Write Filter) | Reports current UWF state (read-only — no remediation needed) |
Requires ExchangeOnlineManagement module and a one-time sign-in via the Exchange › Connection sub-tab.
- View Mailbox Permissions — lists all shared mailboxes a user has FullAccess or SendAs on
- Mirror Permissions — copies all mailbox permissions from a source user to a target user
- Grant Permissions — grants FullAccess + SendAs on a specific mailbox to a user
- Intune — list managed devices with compliance state, OS, model, serial; Export CSV + device count (count new in v1.3.0)
- Intune Scripts (new in v1.2.0) — browse and optionally download all scripts deployed via Intune (
deviceManagement/deviceManagementScripts). UsesInvoke-MgGraphRequestagainst the beta endpoint — no deprecatedMicrosoft.Graph.Intuneneeded. - Azure Resources — resource type summary via
Search-AzGraph(notGet-AzResource)
- Read, write, and delete registry values via StdRegProv CIM
- Supports String, DWord, QWord, ExpandString, MultiString
- Hives: HKLM, HKCU, HKU, HKCR (writes to HKLM require admin)
- Interactive sign-in via Microsoft Graph (
Connect-MgGraph) - Service principal sign-in (Tenant ID + Client ID + Client Secret)
- Connection state tracked in
$state.SyncHash.CloudConnected— cloud feature buttons blocked with a friendly message when not authenticated
The status bar always shows your elevation level:
| Status | Meaning |
|---|---|
Administrator (green) |
Full functionality available |
(!) Standard User (amber) |
Hardware, RDP, and registry writes may fail |
Click Restart as Admin in the status bar to relaunch elevated. Features that fail due to insufficient rights display a clear hint in the output box.
LazyWinAdminModule/
├── LazyWinAdminModule.psd1 # Module manifest (v1.3.0, requires PS 7.4+)
├── LazyWinAdminModule.psm1 # Root module — dot-sources all Private/Public files
├── Classes/
│ └── ApplicationState.ps1 # LazyWinAdminState class: SyncHash, RunspacePool, CimSessions, UIQueue
├── Private/ # 24 private functions (CIM, Graph, Az, AD, Exchange, Compliance)
├── Public/
│ └── Start-LazyWinAdmin.ps1 # WPF window, async dispatch, all button handlers
├── UI/
│ └── MainView.xaml # WPF layout (11 tabs)
└── Tests/
├── Integrity.Tests.ps1 # File structure, manifest, XAML, ApplicationState
├── Functions.Tests.ps1 # All private functions (228 tests, 0 failures)
└── Run-Tests.ps1 # Test runner with summary output
All button actions run in background thread jobs via Start-ThreadJob. Completed results are enqueued into a ConcurrentQueue by a Register-ObjectEvent handler, then dequeued by a DispatcherTimer (50 ms tick) running on the WPF UI thread. This eliminates all cross-thread delegate issues and ensures the UI never blocks — even when multiple jobs complete simultaneously.
v1.1.x note: Earlier versions used
Dispatcher.InvokeAsync([action]{…})which proved fragile under certain runspace/closure conditions. The ConcurrentQueue pattern replaces it entirely.
In PowerShell 7+, Get-CimInstance -ComputerName localhost routes through WSMan (WinRM) even for the local machine. If WinRM is not running, CIM jobs stall for the full connection timeout (30 s), saturate the Start-ThreadJob pool (5 slots), and freeze the UI. All CIM-based private functions now detect a local target and omit -ComputerName entirely, using a direct in-process CIM session instead.
| Guard | Blocks |
|---|---|
$RequireComputerName |
Any CIM operation when the computer name field is empty |
$RequireCloudSession |
Any Graph/Azure operation when not authenticated |
$RequireExchangeSession |
Any Exchange operation when Exchange is not connected |
# Summary output
pwsh -NoProfile -File .\LazyWinAdminModule\Tests\Run-Tests.ps1
# Detailed output
pwsh -NoProfile -File .\LazyWinAdminModule\Tests\Run-Tests.ps1 -Output Detailed
# Single suite
pwsh -NoProfile -File .\LazyWinAdminModule\Tests\Run-Tests.ps1 -Suite Integrity228 tests, 0 failures. Requires Pester 5.0+ (auto-installed by the runner if missing).
.claude/launch.json contains three configurations:
| Name | Command |
|---|---|
| LazyWinAdmin GUI | pwsh → Import-Module … ; Start-LazyWinAdmin |
| Pester Tests (Detailed) | pwsh -File Run-Tests.ps1 -Output Detailed |
| Pester Tests (Normal) | pwsh -File Run-Tests.ps1 |
- Service control — Start, Stop, and Restart the selected service directly from the Services tab via new CIM-based
Invoke-ComputerServiceControlprivate function (requires admin) - Export to CSV — "Export CSV" button on Services, Software, Network, Intune Devices, and Mailbox Permissions tabs; opens SaveFileDialog, writes UTF-8 CSV
- Result count labels — all major list views now show "N item(s)" after each query (Services, Software, Network, Intune Devices, Mailbox Permissions)
- Status bar clock — live
HH:mm:ssdisplay in the status bar (second DispatcherTimer, 1 s tick) - Ping refactored — now uses
Test-ComputerPort(private function) instead of inlineTest-NetConnection, consistent with the rest of the codebase - Copy to Clipboard — right-click any row in any ListView to copy the tab-separated values to the clipboard (context menu added to all 12 list views in code)
- 16 new Pester tests for
Invoke-ComputerServiceControl(parameter validation, Start/Stop/Restart, non-zero return codes, error path, local routing) - 228 Pester v5 tests, 0 failures (up from 212)
- Device Compliance tab — check and remediate Location Services, OneDrive, Outlook external images, Windows Update active hours (dynamic), UWF state. Runs locally, no network required.
- Exchange tab — view, mirror, and grant mailbox permissions via Exchange Online. Requires
ExchangeOnlineManagementmodule. Auth tracked separately from Graph ($state.SyncHash.ExchangeConnected). - Intune Scripts sub-tab — browse and download all Intune-deployed scripts via
deviceManagement/deviceManagementScriptsbeta endpoint. - CIM local routing fix — all 10 CIM-based private functions now detect localhost targets and skip
-ComputerName, eliminating WinRM dependency and the associated UI freeze. - Async architecture fix — replaced
Dispatcher.InvokeAsync([action]{…})withConcurrentQueue+DispatcherTimer(50 ms tick). Event handlers only enqueue; UI thread only dequeues. No cross-thread delegate issues possible. $RequireExchangeSessionguard — Exchange operations blocked with a clear message when Exchange is not connected.- 212 Pester v5 tests, 0 failures (up from 178)
- Complete rewrite as a PowerShell 7.4+ WPF module
- Async UI via
Start-ThreadJob+Register-ObjectEvent— no blocking - Cloud integration: Entra ID (users/groups), Intune devices, Azure Resource Graph
- Active Directory support (RSAT)
- Admin elevation detection with Restart as Admin button
- Registry CRUD via StdRegProv (no
Win32_Product) - Pre-flight guards for cloud auth and computer name
- OData/LDAP injection protection on all search inputs
- 178 Pester v5 tests, 0 failures
.claude/launch.jsondev launch configurations
- PowerShell 2.0 WinForms GUI built with Sapien PowerShell Studio 2012
- On-premises only: services, software, hardware, network, AD, RDP, registry
- See legacy source in
LazyWinAdmin/andSources/
Contributions are welcome. See LICENSE for details.




