PowerShell tools to create, inspect, and remove Windows Scheduled Tasks that run under a Group Managed Service Account (gMSA).
  • PowerShell 100%
Find a file
2026-07-02 11:25:27 -05:00
.github Add gMSA Scheduled Task scripts, docs, and community health files 2026-06-30 16:06:01 -05:00
.gitattributes Add .gitattributes to normalize line endings 2026-06-30 16:05:46 -05:00
CODE_OF_CONDUCT.md Add gMSA Scheduled Task scripts, docs, and community health files 2026-06-30 16:06:01 -05:00
CONTRIBUTING.md Add gMSA Scheduled Task scripts, docs, and community health files 2026-06-30 16:06:01 -05:00
Get-GmsaScheduledTask.ps1 Fix StrictMode error on COM-handler task actions in Get-GmsaScheduledTask 2026-06-30 16:18:15 -05:00
Get-TaskCacheSummary.ps1 Fix false OrphanTreeEntry findings from ignorable chars in TaskCache Ids 2026-07-02 10:48:52 -05:00
LICENSE Add gMSA Scheduled Task scripts, docs, and community health files 2026-06-30 16:06:01 -05:00
New-GmsaScheduledTask.ps1 Add gMSA Scheduled Task scripts, docs, and community health files 2026-06-30 16:06:01 -05:00
README.md Add TaskCache count summary and Get-TaskCacheSummary diagnostic 2026-07-02 09:07:54 -05:00
Remove-GmsaScheduledTask.ps1 Add gMSA Scheduled Task scripts, docs, and community health files 2026-06-30 16:06:01 -05:00
SECURITY.md Add gMSA Scheduled Task scripts, docs, and community health files 2026-06-30 16:06:01 -05:00
Test-ScheduledTaskHealth.ps1 Fix false OrphanTreeEntry findings from ignorable chars in TaskCache Ids 2026-07-02 10:48:52 -05:00
THIRD-PARTY-NOTICES.md Add gMSA Scheduled Task scripts, docs, and community health files 2026-06-30 16:06:01 -05:00

GmsaScheduledTaskTools

PowerShell scripts for creating, inspecting, and removing Windows Scheduled Tasks that run under a Group Managed Service Account (gMSA). Running scheduled tasks as a gMSA means there is no password to store, manage, or rotate - Active Directory handles the managed password automatically, which reduces the credential-exposure surface for unattended jobs.

Why gMSA-backed tasks

A gMSA can run a Windows Scheduled Task on Windows Server 2012 or later. The catch is that the Task Scheduler GUI (taskschd.msc) cannot configure a gMSA principal cleanly - it tries to prompt for a password the account does not have. These scripts register the task via PowerShell using a principal with -LogonType Password, which tells Task Scheduler to retrieve the managed password from AD at run time. No password is ever supplied.

Scripts

Script Purpose
New-GmsaScheduledTask.ps1 Create (or idempotently update) a Scheduled Task that runs as a gMSA. Optionally validates the gMSA on the host and grants the "Log on as a batch job" right.
Get-GmsaScheduledTask.ps1 Report the principal, action, and trigger of one or more tasks, with a focus on gMSA detail. Read-only.
Remove-GmsaScheduledTask.ps1 Unregister a task and, optionally, revoke the gMSA's "Log on as a batch job" right.
Test-ScheduledTaskHealth.ps1 Diagnose a stalled/hung Task Scheduler by reconciling the on-disk task XML files against the TaskCache registry, without calling the Task Scheduler service. Emits a summary of counts and can -Repair (with backup). Read-only by default.
Get-TaskCacheSummary.ps1 Quick read-only count comparison of the TaskCache Tree, TaskCache Tasks, and on-disk XML sources, with optional per-GUID spot-checks. Use to tell real corruption from a false alarm before repairing.

Every script ships with comment-based help. Run Get-Help .\New-GmsaScheduledTask.ps1 -Full for full parameter documentation and examples.

Requirements

  • Windows Server 2012 / Windows 8 or later (gMSA support).
  • A KDS root key in the domain, and the gMSA already created with the target host listed in PrincipalsAllowedToRetrieveManagedPassword, then installed on the host via Install-ADServiceAccount.
  • Run the scripts elevated (Administrator) on the host that will run the task.
  • The RSAT ActiveDirectory module is needed only for the optional Test-ADServiceAccount validation (-TestGmsa / the create-time gMSA check).

Quick start

Create a daily 2 AM task that runs a script as a gMSA, granting the batch logon right and running elevated:

.\New-GmsaScheduledTask.ps1 -TaskName 'NightlyExport' -GmsaAccount 'CONTOSO\svc-export$' `
    -Execute 'powershell.exe' -Argument '-NoProfile -File C:\Scripts\Export.ps1' `
    -TriggerType Daily -At 2:00AM -GrantBatchLogonRight -RunLevel Highest -Verbose

Report on every gMSA-backed task on the host and whether each gMSA is installed:

.\Get-GmsaScheduledTask.ps1 -GmsaOnly -Recurse -TestGmsa |
    Select-Object TaskName, UserId, RunLevel, TriggerSummary, GmsaInstalled

Remove a task (leaving the batch logon right in place for other workloads):

.\Remove-GmsaScheduledTask.ps1 -TaskName 'NightlyExport'

Diagnose a Task Scheduler that hangs while enumerating tasks (the MMC, schtasks, and Get-ScheduledTask all stall when the service is stuck on one damaged task). Run elevated:

.\Test-ScheduledTaskHealth.ps1 |
    Where-Object Severity -eq 'Error' |
    Select-Object Category, TaskPath, TaskGuid, FilePath, SuggestedAction | Format-List

Test-ScheduledTaskHealth.ps1 is read-only by default and does not call the Task Scheduler service, so it works even while taskschd.msc is unresponsive. It flags orphaned TaskCache registry entries, missing or zero-byte or malformed task XML, and (with -ResolvePrincipals) unresolvable principal SIDs.

To repair the damaged/orphaned tasks it finds, add -Repair. Repair backs up each item (a native .reg export of the registry key plus a copy of the XML file, to -BackupPath) before removing it, and honors -WhatIf / -Confirm. Always do a read-only run first, then reboot after a repair so the service re-reads TaskCache:

# Preview what a repair would back up and remove (no changes):
.\Test-ScheduledTaskHealth.ps1 -Repair -WhatIf

# Back up and remove every damaged/orphaned task, then reboot:
.\Test-ScheduledTaskHealth.ps1 -Repair -Confirm:$false

If a run reports a large number of OrphanTreeEntry findings, confirm the damage is real before repairing. Get-TaskCacheSummary.ps1 compares the counts of TaskCache\Tree nodes, TaskCache\Tasks GUID keys, and on-disk XML files, and can spot-check specific GUIDs:

.\Get-TaskCacheSummary.ps1
.\Get-TaskCacheSummary.ps1 -CheckGuid '{31C5D67F-4872-4930-9927-901B20E3A4D3}' | Format-List

If TasksGuidKeys is close to TreeTaskNodes and the spot-checks return TasksKeyExists = True, the orphan findings are false and you should not repair. If TasksGuidKeys is far smaller and the keys are genuinely absent, prefer System Restore or DISM /Online /Cleanup-Image /RestoreHealth and sfc /scannow over mass deletion.

Notes

  • The gMSA account name is referenced with a trailing $ (e.g. CONTOSO\svc-export$). The scripts add the $ automatically if you omit it.
  • New-GmsaScheduledTask.ps1 is idempotent: if a matching task already exists it is left unchanged unless you pass -Force.
  • Get-GmsaScheduledTask.ps1 does not gather last/next run times by default, because Get-ScheduledTaskInfo makes a per-task RPC that can be slow on hosts with many tasks. Pass -IncludeRunInfo (bounded by -RunInfoTimeoutSeconds) when you need that data.
  • Revoking the "Log on as a batch job" right affects every task or service that logs on as a batch job under that account on the host, so Remove-GmsaScheduledTask.ps1 leaves it in place unless you explicitly pass -RevokeBatchLogonRight.

License

MIT - see LICENSE.