Skip to content

Service Account and AD

Webhook Server Wiki Sync edited this page May 8, 2026 · 2 revisions

Service account & Active Directory

The service runs as LocalSystem out of the box. That's right for local-only scripts and read-only AD queries (LocalSystem authenticates to the network as the machine account, which Authenticated Users includes by default). It is wrong for hooks that need to modify AD — passwords, group memberships, computer objects.

This page covers the four real-world choices and how to switch.

The four options

Account Network identity When to use
LocalSystem (default) Computer account DOMAIN\MACHINE$ on a domain-joined host; nothing on a workgroup host Default. Local file ops, simple PowerShell, read-only AD queries. Most powerful local account — any hook running under it has full local rights.
LocalService None Don't. Cannot talk to a domain controller. Listed only to rule it out.
NetworkService Same machine account as LocalSystem Slightly less local privilege than LocalSystem, same network identity. Rarely the right pick.
Domain user (DOMAIN\svc-webhookserver) That user Use when hooks need write access to AD and you can't use a gMSA. You own password rotation.
gMSA (DOMAIN\svc-webhookserver$) That gMSA Recommended for AD-write workloads. AD generates and rotates the password automatically every 30 days. Requires domain functional level 2012+.

Switching the service account at install time

Pass -ServiceAccount to install-service.ps1 (or to the deploy / dev launcher):

# Domain user
& "C:\Program Files\WebhookServer\scripts\install-service.ps1" `
    -BinaryPath "C:\Program Files\WebhookServer\WebhookServer.Service.exe" `
    -ServiceAccount "CONTOSO\svc-webhookserver" -Password "..."

# gMSA - note trailing $ and no -Password
& "C:\Program Files\WebhookServer\scripts\install-service.ps1" `
    -BinaryPath "C:\Program Files\WebhookServer\WebhookServer.Service.exe" `
    -ServiceAccount 'CONTOSO\svc-webhookserver$'

Or do it manually with sc.exe if the service is already installed:

sc.exe stop WebhookServer
sc.exe config WebhookServer obj= 'CONTOSO\svc-webhookserver$'
sc.exe start WebhookServer

gMSA setup (recommended for AD writes)

A gMSA is a Group Managed Service Account. Active Directory generates and stores its password and rotates it every 30 days; the host machine account retrieves the password as needed. You never see or store it. This is the cleanest pattern for production.

One-time domain setup

If your domain has never used gMSAs, create the KDS root key (only needed once per domain):

# from a Domain Admin PowerShell, on any DC
Add-KdsRootKey -EffectiveImmediately
# in production wait 10 hours for replication; in a lab, override:
# Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10))

Create the gMSA

# from a DC, with AD PowerShell module loaded
New-ADServiceAccount -Name svc-webhookserver `
    -DNSHostName webhook01.contoso.local `
    -PrincipalsAllowedToRetrieveManagedPassword "DOMAIN\WebhookHosts"

PrincipalsAllowedToRetrieveManagedPassword is the security group containing the computer accounts allowed to use the gMSA. Add your webhook host(s) to that group:

Add-ADGroupMember -Identity 'WebhookHosts' -Members 'WEBHOOK01$'
# the host needs to reboot OR have its kerberos ticket flushed for the new group membership to apply

Install the gMSA on the host

On the webhook server machine itself:

# from elevated PowerShell, AD PowerShell module installed (RSAT)
Install-ADServiceAccount svc-webhookserver
Test-ADServiceAccount svc-webhookserver  # should return True

If Test-ADServiceAccount returns False, check:

  • Host is in the WebhookHosts group (or whoever's in PrincipalsAllowedToRetrieveManagedPassword)
  • Host has been rebooted since being added to the group
  • KDS root key has had time to propagate (10 hours by default)

Configure the service to use it

# from elevated PowerShell on the webhook host
sc.exe stop WebhookServer
sc.exe config WebhookServer obj= 'CONTOSO\svc-webhookserver$'
sc.exe start WebhookServer

Note the trailing $. There is no password parameter for gMSAs. The trailing $ is what tells the SCM "look up this account in AD as a managed service account, retrieve its password automatically."

Grant AD permissions

Give the gMSA only what it needs. For a typical "reset user passwords" workload:

# Delegate "Reset password and force change at next logon" on a specific OU
$ou = "OU=Standard Users,DC=contoso,DC=local"
dsacls $ou /I:S /G "CONTOSO\svc-webhookserver$:CA;Reset Password;user"
dsacls $ou /I:S /G "CONTOSO\svc-webhookserver$:WP;pwdLastSet;user"

…or use the GUI Delegation of Control wizard in Active Directory Users and Computers.

Domain user (fallback when gMSA isn't available)

# 1. Create the user (one time)
New-ADUser -Name "svc-webhookserver" -SamAccountName "svc-webhookserver" `
    -AccountPassword (Read-Host -AsSecureString "password") -Enabled $true `
    -PasswordNeverExpires $true -CannotChangePassword $true

# 2. Grant "Log on as a service" right on the host:
#    secpol.msc -> Local Policies -> User Rights Assignment -> Log on as a service
#    Add CONTOSO\svc-webhookserver

# 3. Configure the service:
sc.exe config WebhookServer obj= "CONTOSO\svc-webhookserver" password= "..."

You own password rotation. When you change the password in AD, also update the service via sc.exe config WebhookServer password= "newpw" and restart it.

What changes for hooks when you switch the service account

  • Service mode hooks now run as the new account. PowerShell whoami from inside a hook will show the new identity.
  • InteractiveUser hooks stop working if you switch off LocalSystem. Only SYSTEM can call WTSQueryUserToken. If you need both AD-write hooks and UI-on-desktop hooks, pick one of:
    • Keep service as LocalSystem and use SpecificUser mode for AD-write hooks
    • Switch service to a gMSA / domain user and drop UI hooks (or move them to a separate Webhook Server instance running as LocalSystem)
  • SpecificUser hooks continue to work regardless. They use a separate LogonUser token per call.

Verifying the switch worked

After changing the service account, restart the service and add a quick diagnostic endpoint:

slug:           whoami
auth:           none
executor:       Windows PowerShell
inline command: whoami; whoami /groups

Hit it and verify the output matches the account you configured. The first line should be domain\svc-webhookserver (or domain\machine$ for LocalSystem on a domain-joined host).

Clone this wiki locally