Add Test-ScheduledTaskHealth.ps1 offline diagnostic with -Repair #3

Merged
hannah-vernon merged 1 commit from feature/task-scheduler-health-diagnostic into dev 2026-06-30 17:01:52 -05:00

What does this PR do?

Adds a fourth tool, Test-ScheduledTaskHealth.ps1, that diagnoses (and optionally repairs) a
stalled or hung Windows Task Scheduler.

When the Task Scheduler service stalls enumerating tasks, everything that goes through the
service hangs too: taskschd.msc, schtasks.exe, and the ScheduledTasks cmdlets
(Get-ScheduledTask / Get-ScheduledTaskInfo). The usual cause is a single damaged or
orphaned task definition.

This script avoids the service entirely and reconciles three sources that the service expects
to agree:

  • the task XML files under %SystemRoot%\System32\Tasks,
  • the TaskCache\Tree registry entries, and
  • the TaskCache\Tasks\{GUID} registry subkeys.

It reports: OrphanTreeEntry, OrphanTaskEntry, MissingXmlFile, OrphanXmlFile,
EmptyXmlFile, MalformedXml, UnresolvablePrincipal (opt-in), and ReadError.

With -Repair it backs up each item (a native .reg export of the registry key plus a copy
of the XML file to -BackupPath) and then removes it, gated by SupportsShouldProcess so
-WhatIf / -Confirm work. The registry backup uses the .NET registry API rather than
reg.exe, so it works on hosts where the DisableRegistryTools policy blocks reg.exe.
Backup precedes deletion, so a failed backup aborts the removal and no data is lost.

Fixes #

How was this tested?

  • Parser validation - 0 errors
  • Tested against a synthetic fixture (registry under HKCU + a temp Tasks folder) covering
    every finding category. Verified detection, -Repair -WhatIf (no changes), and a real
    -Repair run: backups written, damaged/orphaned entries removed, the healthy task left
    intact. Confirmed the native .reg export works where DisableRegistryTools blocks
    reg.exe, and that a failed registry backup aborts deletion.

Checklist

  • I have read the Contributing Guide
  • Changes are focused - one logical change per PR
  • Comment-based help updated for any changed parameters or behavior
  • Documentation updated (if user-visible behavior changed)
  • No commented-out code or debug leftovers
## What does this PR do? Adds a fourth tool, `Test-ScheduledTaskHealth.ps1`, that diagnoses (and optionally repairs) a stalled or hung Windows Task Scheduler. When the Task Scheduler service stalls enumerating tasks, everything that goes through the service hangs too: `taskschd.msc`, `schtasks.exe`, and the `ScheduledTasks` cmdlets (`Get-ScheduledTask` / `Get-ScheduledTaskInfo`). The usual cause is a single damaged or orphaned task definition. This script avoids the service entirely and reconciles three sources that the service expects to agree: - the task XML files under `%SystemRoot%\System32\Tasks`, - the `TaskCache\Tree` registry entries, and - the `TaskCache\Tasks\{GUID}` registry subkeys. It reports: `OrphanTreeEntry`, `OrphanTaskEntry`, `MissingXmlFile`, `OrphanXmlFile`, `EmptyXmlFile`, `MalformedXml`, `UnresolvablePrincipal` (opt-in), and `ReadError`. With `-Repair` it backs up each item (a native `.reg` export of the registry key plus a copy of the XML file to `-BackupPath`) and then removes it, gated by `SupportsShouldProcess` so `-WhatIf` / `-Confirm` work. The registry backup uses the .NET registry API rather than `reg.exe`, so it works on hosts where the `DisableRegistryTools` policy blocks `reg.exe`. Backup precedes deletion, so a failed backup aborts the removal and no data is lost. Fixes # ## How was this tested? - [x] Parser validation - 0 errors - [x] Tested against a synthetic fixture (registry under HKCU + a temp Tasks folder) covering every finding category. Verified detection, `-Repair -WhatIf` (no changes), and a real `-Repair` run: backups written, damaged/orphaned entries removed, the healthy task left intact. Confirmed the native `.reg` export works where `DisableRegistryTools` blocks `reg.exe`, and that a failed registry backup aborts deletion. ## Checklist - [x] I have read the [Contributing Guide](../CONTRIBUTING.md) - [x] Changes are focused - one logical change per PR - [x] Comment-based help updated for any changed parameters or behavior - [x] Documentation updated (if user-visible behavior changed) - [x] No commented-out code or debug leftovers
Add a fourth tool that diagnoses a stalled or hung Task Scheduler without calling
the Task Scheduler service (which is what hangs). It reconciles the on-disk task
XML files against the TaskCache Tree and Tasks registry entries and reports:
orphaned Tree/Tasks entries, missing/zero-byte/malformed task XML, and (opt-in)
unresolvable principal SIDs.

With -Repair it backs up each item (native .reg export of the registry key plus a
copy of the XML file to -BackupPath) and then removes it, gated by
SupportsShouldProcess so -WhatIf/-Confirm work. The registry backup uses the .NET
registry API rather than reg.exe, so it works on hosts where DisableRegistryTools
policy blocks reg.exe. Backup precedes deletion, so a failed backup aborts the
removal and no data is lost.

Verified against a synthetic fixture covering every finding category and the full
repair path (backup files written, entries removed, healthy task untouched).

Update README with usage and the troubleshooting/-Repair guidance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
hannah-vernon/GmsaScheduledTaskTools!3
No description provided.