Skip to content
09 · Passwords & Service AccountsPart 2 of 4Intermediate

Migrating service accounts to gMSA and dMSA

Step-by-step migration from static service accounts to gMSA and Windows Server 2025 dMSA: KDS root key, retrieval rights, per-app notes and rollback.

Florian Amette7 min read

A static service account is a long-lived credential with an SPN attached, a password nobody dares to change and logon rights on servers across several tiers. It is the textbook Kerberoasting target, and when its password ends up in a script share or a config file, it becomes a lateral movement path that survives every other hardening project. The service account hardening pillar explains why managed accounts fix this; this guide is the migration runbook: how to inventory what you have, stand up the KDS root key correctly, scope password retrieval tightly, move common workloads, and use dMSA on Windows Server 2025 for the accounts you cannot easily re-point.

The method follows the rest of this site: measure the estate, audit each account's dependencies, enforce the new identity per application, then verify that nothing still uses the old one before you disable it.

Measure: inventory every service identity

Start with user objects that behave like services: SPNs, non-expiring passwords, old password ages, and logon activity from servers rather than workstations.

PowerShell
Get-ADUser -Filter 'ServicePrincipalName -like "*" -or PasswordNeverExpires -eq $true' `
    -Properties ServicePrincipalName, PasswordNeverExpires, PasswordLastSet, LastLogonTimestamp, Description, adminCount |
  Select-Object SamAccountName, adminCount, PasswordNeverExpires, PasswordLastSet,
    @{n='LastLogon';e={[datetime]::FromFileTime($_.LastLogonTimestamp)}},
    @{n='SPNs';e={$_.ServicePrincipalName -join ';'}}, Description |
  Export-Csv .\service-account-inventory.csv -NoTypeInformation

Then find where each account actually runs. On member servers, the Service Control Manager and Task Scheduler are the usual consumers:

PowerShell
# Run against a server list from a Tier-appropriate admin host
$servers = Get-Content .\servers.txt
Invoke-Command -ComputerName $servers -ScriptBlock {
    Get-CimInstance Win32_Service | Where-Object StartName -match '\\' |
        Select-Object @{n='Host';e={$env:COMPUTERNAME}}, Name, StartName
    Get-ScheduledTask | Where-Object { $_.Principal.UserId -match '\\' } |
        Select-Object @{n='Host';e={$env:COMPUTERNAME}}, TaskName, @{n='StartName';e={$_.Principal.UserId}}
}

This misses IIS application pools, COM+ applications, SQL Agent proxies and credentials stored inside applications. Complement it with logon events: event 4624 logon type 5 (service) and type 4 (batch) on member servers, and event 4769 on domain controllers, which shows which SPNs are requested and by whom. The event IDs reference lists the fields worth extracting.

Audit: decide the target per account

Sort every account into one of four buckets:

  1. Dead: no logons in 90+ days and no consumer found. Disable, wait a cycle, delete.
  2. gMSA-compatible: Windows services, scheduled tasks, IIS app pools, SQL Server engine and Agent, most Microsoft server products. Migrate to gMSA.
  3. Hard to re-point: the account name is embedded in many clients, a vendor appliance or ACLs you cannot easily translate. Candidate for dMSA if you have Windows Server 2025 DCs.
  4. Incompatible: the application needs a password it can type, or runs on a non-Windows platform. Keep a standard account with a 30+ character random password, AES only, and a dedicated fine-grained password policy.

Also record whether the account needs delegation. A gMSA supports constrained delegation and resource-based constrained delegation like any other principal; do not carry over unconstrained delegation during the move.

Enforce: build the gMSA foundation once

KDS root key

gMSA passwords are derived from the forest's KDS root key, the gMSA's SID and the current time interval. The key must exist and have replicated before any DC computes a password.

PowerShell
Get-KdsRootKey | Select-Object KeyId, EffectiveTime, CreationTime

# Production: create once, then wait for replication (effective after 10 hours by default)
Add-KdsRootKey -EffectiveImmediately

Despite its name, -EffectiveImmediately still waits for the 10-hour safety window in practice; backdating -EffectiveTime is for single-DC labs only. The KDS root key lives in the Configuration partition, and anyone who can read it (Domain Admins, Enterprise Admins, SYSTEM on a DC) can compute every gMSA password offline, the attack known as Golden gMSA. Treat it as Tier 0 material and include it in your forest recovery plan.

Retrieval groups

Create one security group per gMSA containing only the computer accounts that run the workload. That group is written into msDS-GroupMSAMembership, exposed as PrincipalsAllowedToRetrieveManagedPassword.

PowerShell
New-ADGroup -Name "gMSA-svc-sqlapp-Hosts" -GroupScope Global -GroupCategory Security `
    -Path "OU=gMSA Groups,OU=Tier1,DC=corp,DC=example,DC=com"
Add-ADGroupMember "gMSA-svc-sqlapp-Hosts" -Members "SQL01$","SQL02$"

New-ADServiceAccount -Name "gmsa-sqlapp" `
    -DNSHostName "gmsa-sqlapp.corp.example.com" `
    -PrincipalsAllowedToRetrieveManagedPassword "gMSA-svc-sqlapp-Hosts" `
    -KerberosEncryptionType AES128,AES256 `
    -ManagedPasswordIntervalInDays 30 `
    -Path "OU=Service Accounts,OU=Tier1,DC=corp,DC=example,DC=com"

ManagedPasswordIntervalInDays can only be set at creation. KerberosEncryptionType keeps RC4 off the account, which matters if you are working through disabling RC4. Move any SPNs from the old account to the gMSA with Set-ADServiceAccount -ServicePrincipalNames @{Add=...} after removing them from the old account, because duplicate SPNs break Kerberos.

On each host, refresh its group membership and test:

PowerShell
klist -li 0x3e7 purge
Test-ADServiceAccount -Identity "gmsa-sqlapp"

Install-ADServiceAccount is optional for gMSA on current Windows versions; Test-ADServiceAccount returning True is the check that matters.

Protect the gMSA itself

A gMSA is only as strong as the list of principals allowed to read its password. The DC returns the current and previous password in the constructed attribute msDS-ManagedPassword to any principal in msDS-GroupMSAMembership, so that list is effectively a credential store ACL. Three rules keep it honest:

  • Tier the gMSA with its hosts. A gMSA used by a Tier 1 application server must not be retrievable by a Tier 2 machine, and a gMSA with rights on DCs or backup infrastructure is Tier 0, as are the groups and OUs that control it.
  • Control who can change the retrieval list. Anyone with write access to msDS-GroupMSAMembership on the gMSA, or to the membership of the retrieval group, can add a machine they own and read the password. Review those ACLs with the same tooling you use for attack path management.
  • Audit retrieval. A SACL on the gMSA objects for reads of msDS-ManagedPassword produces event 4662 on DCs. Legitimate reads come from the hosts in the retrieval group, roughly on each password interval and at service start; reads from any other account deserve an alert.

Per-application notes

Windows services and scheduled tasks

Services take the account with a trailing $ and an empty password. The account needs Log on as a service, which sc.exe and the Services console grant automatically on the local host; if GPO manages User Rights Assignment, add the gMSA to that GPO or the next refresh removes it.

PowerShell
sc.exe config "AppService" obj= "CORP\gmsa-sqlapp$" password= ""

$principal = New-ScheduledTaskPrincipal -UserId "CORP\gmsa-report$" -LogonType Password
Set-ScheduledTask -TaskName "NightlyReport" -Principal $principal

Scheduled tasks need Log on as a batch job instead of the service right.

IIS application pools

In IIS Manager, set the pool identity to CORP\gmsa-web$ with a blank password. For Kerberos authentication against the site, register the HTTP SPN on the gMSA and enable kernel-mode authentication with useAppPoolCredentials so tickets are decrypted with the gMSA's keys. Web farms work well because every node is in the retrieval group.

SQL Server

Change the engine and Agent accounts through SQL Server Configuration Manager, not the Services console, so file system, registry and SPN permissions are updated. Check the SQL Server version documentation for failover cluster instances and Availability Groups: support has broadened over releases, and all replicas must be in the retrieval group. Move the MSSQLSvc/ SPNs to the gMSA.

What gMSA does not cover well

Applications that store the service password in their own database, cross-forest scenarios where the consuming host is in another forest, and most non-Windows platforms. These stay in bucket 4.

dMSA on Windows Server 2025

Delegated Managed Service Accounts (dMSA) require at least one Windows Server 2025 domain controller and the KDS root key. The migration links a new dMSA to an existing standard account; during migration, Kerberos authentication for the old account is redirected to the dMSA, and when complete the original account's password is no longer used.

PowerShell
New-ADServiceAccount -Name "dmsa-legacyapp" -DNSHostName "dmsa-legacyapp.corp.example.com" `
    -CreateDelegatedServiceAccount -KerberosEncryptionType AES256 `
    -Path "OU=Service Accounts,OU=Tier1,DC=corp,DC=example,DC=com"

Start-ADServiceAccountMigration -Identity "dmsa-legacyapp" `
    -SupersededAccount "CN=svc_legacyapp,OU=Service Accounts,DC=corp,DC=example,DC=com"

# After the host has picked up the dMSA and the application is validated
Complete-ADServiceAccountMigration -Identity "dmsa-legacyapp" `
    -SupersededAccount "CN=svc_legacyapp,OU=Service Accounts,DC=corp,DC=example,DC=com"

Undo-ADServiceAccountMigration and Reset-ADServiceAccountMigration exist for rollback. Parameter names have been adjusted since release, so check Get-Help on your DCs before scripting. The link is stored in msDS-ManagedAccountPrecededByLink on the dMSA and msDS-SupersededManagedAccountLink on the old account.

Security note: in 2025 researchers published "BadSuccessor", showing that a principal able to create a dMSA in any OU could set that link to point at a privileged account and inherit its permissions. Microsoft addressed it in a security update (CVE-2025-53779), but the underlying lesson stands: audit who holds Create msDS-DelegatedManagedServiceAccount or generic Create Child rights on OUs, exactly as you would for any other dangerous ACL.

Verify

Before disabling an old account, confirm the new identity works and the old one is silent.

PowerShell
# gMSA health and retrieval scope
Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword, msDS-SupportedEncryptionTypes, PasswordLastSet |
  Select-Object Name, PasswordLastSet, msDS-SupportedEncryptionTypes,
    @{n='Retrievers';e={$_.PrincipalsAllowedToRetrieveManagedPassword -join ';'}}

# Old account: no recent authentication
Get-ADUser svc_legacyapp -Properties LastLogonTimestamp, ServicePrincipalName |
  Select-Object Name, @{n='LastLogon';e={[datetime]::FromFileTime($_.LastLogonTimestamp)}}, ServicePrincipalName

Flag any gMSA whose retrievers include user accounts, Domain Computers or nested groups you do not own. Watch for 4769 requests against the old SPNs and 4625 failures naming the old account for at least one full business cycle (month-end jobs), then disable it, keep it disabled for 30 days, and delete it. Re-run the Kerberoasting defense inventory to confirm the SPN is gone from user objects.

What it breaks

  • Services start before the host has a fresh TGT. A newly added host fails with a logon error until it reboots or you purge its tickets. Build that step into the change plan.
  • GPO-managed user rights remove the gMSA's Log on as a service or batch right at the next refresh if the gMSA is not in the policy.
  • Hard-coded credentials in connection strings, scripts and vendor consoles break because there is no password to type. Find them during the audit, not after cutover.
  • Duplicate SPNs during the move cause Kerberos failures and silent NTLM fallback. Remove before you add.
  • Cross-forest consumers and non-Windows clients cannot retrieve gMSA passwords; they stay on standard accounts.
  • dMSA requires Windows Server 2025 DCs and Windows Server 2025 hosts running the service; older hosts cannot use it.

Related reading: the Passwords & Service Accounts topic groups this with Windows LAPS deployment, and the gMSA glossary entry summarises the attribute model.

Frequently asked questions

Who should be allowed to retrieve a gMSA password?

Only the computer accounts that actually run the service, ideally through a dedicated security group per gMSA. Anything listed in PrincipalsAllowedToRetrieveManagedPassword can read the current password blob from msDS-ManagedPassword and derive the account's keys, so adding user accounts, helpdesk groups or broad groups such as Domain Computers turns the gMSA into a credential any of those principals can steal.

Do I need to reboot a server after adding it to a gMSA retrieval group?

Usually, yes, or at least refresh its Kerberos tickets. Group membership is evaluated from the computer's TGT, which was issued before you added it to the group. Rebooting, or purging the SYSTEM logon session tickets with klist -li 0x3e7 purge, forces a new TGT containing the new group. Until then Test-ADServiceAccount returns False and the service fails to start.

Should I use dMSA instead of gMSA for new services?

Not by default. gMSA is mature, works on every supported Windows Server version and is what most applications document. dMSA, introduced with Windows Server 2025, is primarily a migration tool for replacing an existing standard service account in place without reconfiguring every consumer. Use it where re-pointing clients is hard, and only after you have audited who can create dMSA objects in your OUs.

Migrating service accounts to gMSA and dMSA

Related guides

Passwords & Service Accounts

Service account hardening: gMSA, SPNs and LAPS

A practical guide to replacing risky service accounts with gMSA/dMSA, cleaning SPN exposure, fine-grained password policies, and Windows LAPS.

Foundation