A scheduled task that had been running happily stopped working. Task Scheduler was reporting a last run result of 0x8007052E. The cause turned out to be simple: the task ran under a person’s account, that person had left, and their account no longer worked. Worse, it wasn’t an ordinary account. It was one with domain admin-level rights, and its password had been stored in Task Scheduler the whole time.
If you’ve managed Windows servers for long, you’ve probably met this exact situation, or you will. It’s one of those problems that’s easy to fix once and easy to miss everywhere else. This article covers how to read the error, why stored passwords on scheduled tasks are a problem even when they’re working, how to find every task like this across your servers before it breaks, and how to move them to group managed service accounts (gMSAs) so it doesn’t happen again.
Reading the error
0x8007052E is a Windows error wrapped in an HRESULT. Strip off the 0x8007 prefix and you’re left with 0x52E, which is error 1326: “The user name or password is incorrect.” Task Scheduler tried to log on as the task’s account with the password it had stored, and the domain said no.
A few related codes turn up in the same situations, and they’re worth recognising because they point at slightly different causes:
| Last run result | Win32 error | What it means for the task |
|---|---|---|
0x8007052E | 1326 | Wrong user name or password. Usually the password was reset or changed after the task was saved. |
0x80070532 | 1330 | The account’s password has expired. |
0x80070533 | 1331 | The account is disabled, which is the classic sign of a task tied to someone who has left. |
One small trap if you’re checking from PowerShell: Get-ScheduledTaskInfo reports the result as a decimal number, not hex. 0x8007052E shows up as 2147943726, which is worth knowing if you’re searching logs or reports for it.
Get-ScheduledTask -TaskName 'Nightly Export' | Get-ScheduledTaskInfo |
Select-Object TaskName, LastRunTime, LastTaskResultFor more detail, check two logs on the server. In Microsoft-Windows-TaskScheduler/Operational, a logon problem typically shows up as event 104 (Task Scheduler couldn’t log on the user) or event 101 (the task failed to start), with the error code included. In the Security log, the failed logon appears as event 4625, which names the account and gives a failure reason. Between the two, you can usually confirm the account in a couple of minutes.
If the operational log is empty, task history may simply be turned off, which is common on older servers. In Task Scheduler, select Task Scheduler Library and click Enable All Tasks History in the Actions pane, so you have a record next time.
Why stored passwords are the real problem
The quick fix is to open the task, put a current account and password in, and move on. It gets the job running again, but it keeps the design that caused the outage.
When a task is set to Run whether user is logged on or not with a user account, Task Scheduler saves that account’s password at the moment you save the task. Nothing tells it when the password later changes. Every reset, expiry or resignation is a future outage, and because these jobs run in the background, the first sign is often that something downstream hasn’t happened.
There’s a security cost too, and it’s the bigger one. Task Scheduler has to use that password unattended, so Windows stores it in a form it can decrypt. Anyone with administrator rights on the server, including an attacker who has got that far, can pull stored task credentials out with tools that are freely available. If the task runs as a domain admin-level account, every server it lives on becomes somewhere to collect domain admin credentials.
And it ties infrastructure to individuals. Tasks end up under someone’s own account because it’s quick and it works on the day. Years later, nobody remembers which jobs belong to whom, and offboarding becomes a case of waiting to see what breaks.
That security cost is why this belongs in an Essential Eight conversation, not just a troubleshooting one. The Restrict administrative privileges strategy is about limiting where privileged credentials exist and how they’re used (ASD: Essential Eight maturity model). A privileged password saved on several servers to run background jobs is exactly the sort of exposure it’s trying to remove.
So the real fix isn’t a new password. It’s removing the stored password altogether.
If you need it running today
Sometimes the job has to run tonight and the proper fix has to wait. You can update the stored credentials from PowerShell without rebuilding the task:
Set-ScheduledTask -TaskName 'Nightly Export' -User 'EXAMPLE\svc-export' -Password (Read-Host 'Password')Use a dedicated service account rather than another person’s account, so you aren’t setting up the same failure for the next departure. But treat it as a stop-gap. The password is still stored on the server, and the rest of this article is about getting rid of it.
Find every task like this before it breaks
Fixing the one task that failed is the easy part. The more useful job is finding all the others that will fail the next time someone leaves or a password changes.
The giveaway is the task’s logon type. A task that stores a password has a principal with LogonType set to Password. On a single server, this lists them:
Get-ScheduledTask |
Where-Object { $_.Principal.LogonType -eq 'Password' } |
Select-Object TaskPath, TaskName, @{ n = 'RunAs'; e = { $_.Principal.UserId } }To check every server at once, run the same query remotely. This version pulls the Windows servers from Active Directory, skips gMSAs (their names end in $), and adds each task’s last result so you can see which ones are already failing:
$servers = Get-ADComputer -Filter 'OperatingSystem -like "*Server*" -and Enabled -eq $true' |
Select-Object -ExpandProperty DNSHostName
Invoke-Command -ComputerName $servers -ErrorAction SilentlyContinue -ErrorVariable unreachable -ScriptBlock {
Get-ScheduledTask |
Where-Object { $_.Principal.LogonType -eq 'Password' -and $_.Principal.UserId -notlike '*$' } |
ForEach-Object {
$info = $_ | Get-ScheduledTaskInfo
[pscustomobject]@{
Task = "$($_.TaskPath)$($_.TaskName)"
RunAs = $_.Principal.UserId
LastRun = $info.LastRunTime
LastResult = '0x{0:X8}' -f $info.LastTaskResult
}
}
} | Select-Object PSComputerName, Task, RunAs, LastRun, LastResult |
Export-Csv .\stored-credential-tasks.csv -NoTypeInformation
"Servers that couldn't be checked: $($unreachable.Count)"The last line matters. A server the script can’t reach isn’t a server without the problem, so check the unreachable list rather than assuming the export is complete.
Once you have the list, look up each RunAs account in Active Directory. Accounts belonging to people, especially people who have left or are in privileged groups, are the priority. Shared service accounts with non-expiring passwords are the next tier: they won’t break when someone leaves, but their passwords are still stored on every server that uses them.
The same query is handy during offboarding. Before you disable an administrator’s account, check whether anything is running as them. Swap the filter for their user name:
Get-ScheduledTask | Where-Object { $_.Principal.UserId -like '*jsmith*' }Run it through Invoke-Command against your servers, as above, and you’ll know before the account is disabled, rather than after the first job fails.
The fix: move the task to a gMSA
A group managed service account is an Active Directory account whose password is generated and rotated by the domain itself. No person knows it, nobody types it into Task Scheduler, and it changes automatically. The servers you approve fetch the current password from Active Directory when they need it. That removes all three problems at once: nothing to break when someone leaves, no human password stored on the server, and an account that belongs to the job rather than a person (Microsoft Learn: Group Managed Service Accounts overview).
The setup has five steps.
1. Make sure the domain has a KDS root key. gMSA passwords are generated from a Key Distribution Service root key, which only needs creating once per forest. Check with Get-KdsRootKey. If nothing comes back, create one with Add-KdsRootKey -EffectiveImmediately. Despite the name, domain controllers wait up to 10 hours before using a new key, to give replication time to complete, so do this the day before you need it (Microsoft Learn: Create the KDS root key).
2. Create a group for the servers that may use the account, and add the server running the task. Using a group, rather than naming servers directly, makes it easy to move the task later.
3. Create the gMSA and allow that group to retrieve its password:
New-ADServiceAccount -Name 'gmsa-NightlyExp' `
-DNSHostName 'gmsa-NightlyExp.example.local' `
-PrincipalsAllowedToRetrieveManagedPassword 'gMSA-NightlyExport-Servers'gMSA names are limited to 15 characters, so keep them short.
4. Install and test it on the server. On the server that runs the task:
Install-ADServiceAccount -Identity 'gmsa-NightlyExp'
Test-ADServiceAccount -Identity 'gmsa-NightlyExp'Test-ADServiceAccount should return True. Then grant the account only what the task actually needs, such as Log on as a batch job on the server and permissions on the folders or shares it touches. Don’t drop it into Domain Admins just because the old account was there.
5. Re-register the task to run as the gMSA. This step has to be done in PowerShell. The key is -LogonType Password, which tells Task Scheduler to fetch the managed password from Active Directory. You don’t supply a password, because there isn’t one to supply:
$principal = New-ScheduledTaskPrincipal -UserId 'EXAMPLE\gmsa-NightlyExp$' -LogonType Password
Set-ScheduledTask -TaskName 'Nightly Export' -Principal $principalNote the $ on the end of the account name. Then run the task once by hand and check that LastTaskResult comes back as 0.
The gotchas
gMSAs are well worth it, but a few things catch people the first time.
Don’t edit the task in the Task Scheduler window afterwards. The graphical tool doesn’t understand gMSAs. If you open the task’s properties and click OK, it will ask for a password, and there’s no password to give it. Make any further changes to the task in PowerShell.
The server may not see its new group straight away. If you add a server to the group in step 2 and Test-ADServiceAccount returns False, it’s often because the server’s computer account hasn’t picked up the new group membership yet. A restart sorts it out. Failing that, purging the computer account’s Kerberos tickets with klist -li 0x3e7 purge, run as administrator, usually does it without a reboot.
Install-ADServiceAccount needs the AD PowerShell module. On a member server, that means installing the RSAT Active Directory module first.
Domain controllers can behave differently. Several admins have reported gMSA tasks failing on domain controllers with the batch logon right in place, and working once the account was also given Log on as a service (Microsoft Q&A: gMSA and log on as a batch job). If a gMSA task on a DC fails with a logon error, check the Security log for event 4625 and try that right. Better still, ask whether the task needs to run on a domain controller at all.
The task still needs the right permissions. A gMSA is a new account. If the old task ran as a domain admin, it may have been quietly relying on rights nobody documented. Expect the first run to fail on a share or folder permission, and treat that as useful information about what the job actually needs.
When a gMSA isn’t the answer
gMSAs solve the problem for jobs that run on domain-joined Windows servers and talk to Active Directory resources. They’re not the right fit for everything.
- Jobs that talk to cloud services such as Microsoft Graph or Azure are better moved to something like Azure Automation with a managed identity, which gives you the same “no stored secret” benefit on the cloud side.
- Tasks that only touch the local machine may not need a domain account at all. Running as
SYSTEM,LOCAL SERVICEorNETWORK SERVICEcan be enough, with less privilege than a domain account. - Non-domain machines can’t use gMSAs, so they need a different approach to credentials.
Whatever the platform, the goal is the same: scheduled work should run as an identity that belongs to the job, with no password that a person knows or that sits on a server waiting to be found.
Checklist: scheduled tasks and stored credentials
- Read the last run result:
0x8007052Eis a bad password,0x80070532an expired one,0x80070533a disabled account. - Remember PowerShell shows
0x8007052Eas2147943726. - Check the Task Scheduler operational log and Security event 4625, and enable the operational log if it’s off.
- Find every task with
LogonTypeset toPasswordacross your servers, and note which servers couldn’t be checked. - Prioritise tasks running as real people, especially privileged accounts and people who have left.
- Create a KDS root key a day ahead if your domain doesn’t have one.
- Move tasks to a gMSA, and grant it only the rights the job needs.
- Re-register tasks with
-LogonType Passwordin PowerShell, and don’t edit them in the Task Scheduler window afterwards. - Move cloud-facing jobs to a managed identity instead.
- Add “check scheduled tasks” to your offboarding process for anyone with admin rights.
That last item is the one I’d most like other teams to take away. Fixing the task that broke is easy. The lasting improvement is making sure the next person who leaves doesn’t take a handful of quiet, important jobs with them.
Sources
- Microsoft Learn: Group Managed Service Accounts overview
- Microsoft Learn: Create the Key Distribution Services KDS root key
- Microsoft Q&A: gMSA and log on as a batch job
- ASD: Essential Eight maturity model

From my early days on the helpdesk through roles as a service desk manager, systems administrator, and network engineer, I’ve spent more than 25 years in the IT world. As I transition into cyber security, my goal is to make tech a little less confusing by sharing what I’ve learned and helping others wherever I can.

