Skip to main content

How to Grant "Log on as a Service" Right in Batch Script

Many critical applications, like SQL Server, IIS, and backup agents, require a Service Account to run. This account must have a specific "User Right Assignment" called "Log on as a Service" (SeServiceLogonRight). Without this privilege, your service will fail to start, reporting an "Error 1069: The service did not start due to a logon failure." While you can use the Local Security Policy GUI (secpol.msc), automating this entitlement via a Batch script is essential for deploying new servers or configuring application clusters.

This guide explains how to use the secedit utility or PowerShell to grant this permission.

Why Automate Service Rights?

  • Deployment Reliability: Ensuring that your automated SQL Server installation doesn't fail because the service account lacks permission to start.
  • Security Compliance: Assigning only the minimum rights required for a service account, rather than making it a Local Administrator "just to make it work."
  • Standardization: Applying the same service rights to every node in a failover cluster to ensure consistent behavior.
Built-in Methods

While the legacy ntrights.exe (from the Windows Resource Kit) was once the standard tool for this task, it is not included in modern Windows. This guide uses the built-in secedit utility and PowerShell, which are available on all Windows systems without additional downloads.

Method 1: Using Secedit (Built-in, No Dependencies)

The secedit utility can apply user rights by importing a security template. This method works on any Windows system without additional modules.

@echo off
setlocal

:: Check for admin rights
net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Administrator privileges are required.
pause
exit /b 1
)

set /p "USN=Enter service account name: "

if "%USN%"=="" (
echo [ERROR] No account name entered.
pause
exit /b 1
)

echo [PROCESS] Granting 'Log on as a Service' to "%USN%"...

:: Step 1: Export current security policy
set "TMP_CFG=%TEMP%\svc_rights_%RANDOM%.inf"
set "TMP_DB=%TEMP%\svc_rights_%RANDOM%.sdb"
secedit /export /cfg "%TMP_CFG%" /areas USER_RIGHTS >nul 2>&1

:: Step 2: Check if SeServiceLogonRight already exists in the export
set "CURRENT_LINE="
for /f "tokens=1,* delims==" %%a in ('findstr /i "SeServiceLogonRight" "%TMP_CFG%" 2^>nul') do set "CURRENT_LINE=%%b"

:: Step 3: Create a new template that appends the user
:: Use PowerShell to generate UTF-16 LE encoded INF
if defined CURRENT_LINE (
:: Append to existing list
powershell -NoProfile -Command ^
"$content = '[Unicode]`r`nUnicode=yes`r`n[Privilege Rights]`r`nSeServiceLogonRight = %CURRENT_LINE%,%USN%`r`n';" ^
"[System.IO.File]::WriteAllText('%TMP_CFG%', $content, [System.Text.Encoding]::Unicode)" 2>nul
) else (
:: Create new entry
powershell -NoProfile -Command ^
"$content = '[Unicode]`r`nUnicode=yes`r`n[Privilege Rights]`r`nSeServiceLogonRight = %USN%`r`n';" ^
"[System.IO.File]::WriteAllText('%TMP_CFG%', $content, [System.Text.Encoding]::Unicode)" 2>nul
)

:: Step 4: Apply the template
secedit /configure /db "%TMP_DB%" /cfg "%TMP_CFG%" /areas USER_RIGHTS >nul 2>&1

if %errorlevel% equ 0 (
echo [SUCCESS] 'Log on as a Service' granted to "%USN%".
) else (
echo [ERROR] Failed to apply right. Code: %errorlevel%
echo [HELP] Check: %windir%\security\logs\scesrv.log
)

:: Cleanup
del "%TMP_CFG%" >nul 2>&1
del "%TMP_DB%" >nul 2>&1
del "%TMP_DB%.log" >nul 2>&1
del "%TMP_DB%.jfm" >nul 2>&1
pause

Method 2: Using PowerShell (Direct .NET Approach)

For a more streamlined approach, PowerShell can call the Windows LSA (Local Security Authority) API directly without requiring third-party modules.

@echo off
setlocal

:: Check for admin rights
net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Administrator privileges are required.
pause
exit /b 1
)

set /p "USN=Enter service account name: "

if "%USN%"=="" (
echo [ERROR] No account name entered.
pause
exit /b 1
)

echo [PROCESS] Granting 'Log on as a Service' to "%USN%"...

powershell -NoProfile -Command ^
"try {" ^
" $account = if ('%USN%' -notmatch '\\') { '.\%USN%' } else { '%USN%' };" ^
" $sid = (New-Object Security.Principal.NTAccount($account)).Translate([Security.Principal.SecurityIdentifier]);" ^
" $tmp = [System.IO.Path]::GetTempFileName();" ^
" secedit /export /cfg $tmp /areas USER_RIGHTS | Out-Null;" ^
" $cfg = Get-Content $tmp;" ^
" $sidStr = '*' + $sid.Value;" ^
" $found = $false;" ^
" $newCfg = $cfg | ForEach-Object {" ^
" if ($_ -match '^SeServiceLogonRight') {" ^
" if ($_ -notmatch [regex]::Escape($sid.Value)) { $_ + ',' + $sidStr } else { $_ };" ^
" $found = $true" ^
" } else { $_ }" ^
" };" ^
" if (-not $found) { $newCfg += 'SeServiceLogonRight = ' + $sidStr };" ^
" $newCfg | Set-Content $tmp -Encoding Unicode;" ^
" $db = [System.IO.Path]::GetTempFileName();" ^
" secedit /configure /db $db /cfg $tmp /areas USER_RIGHTS | Out-Null;" ^
" Remove-Item $tmp, $db -Force -ErrorAction SilentlyContinue;" ^
" Write-Host '[SUCCESS] Right granted to %USN%.';" ^
"} catch {" ^
" Write-Host ('[ERROR] ' + $_.Exception.Message);" ^
" exit 1" ^
"}" 2>nul

pause

Creating a Service Account Configurator

This script validates the account, grants the right, and verifies the result.

@echo off
setlocal EnableDelayedExpansion

echo ============================================================
echo Service Account Rights Assignment
echo ============================================================

:: 1. Verify admin rights
net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Administrator privileges are required.
pause
exit /b 1
)

:: 2. Get account name
set /p "SVC_USER=Enter Service Account Name: "

if "!SVC_USER!"=="" (
echo [ERROR] No account name entered.
pause
exit /b 1
)

:: 3. Verify the account exists
net user "!SVC_USER!" >nul 2>&1
if !errorlevel! neq 0 (
net user "!SVC_USER!" /domain >nul 2>&1
if !errorlevel! neq 0 (
echo [ERROR] Account "!SVC_USER!" not found locally or in the domain.
pause
exit /b 1
)
)

:: 4. Check current rights
echo.
echo [CHECK] Current 'Log on as a Service' assignments:
set "ALREADY=0"
set "TMP_CHK=%TEMP%\rights_check_%RANDOM%.inf"
secedit /export /cfg "!TMP_CHK!" /areas USER_RIGHTS >nul 2>&1
findstr /i "SeServiceLogonRight" "!TMP_CHK!" 2>nul | findstr /i "!SVC_USER!" >nul 2>&1
if !errorlevel! equ 0 (
echo [INFO] "!SVC_USER!" already has this right.
set "ALREADY=1"
)
findstr /i "SeServiceLogonRight" "!TMP_CHK!" 2>nul
del "!TMP_CHK!" >nul 2>&1

if !ALREADY! equ 1 (
echo.
echo [OK] No changes needed.
echo ============================================================
pause
exit /b 0
)

:: 5. Grant the right via secedit
echo.
echo [PROCESS] Granting 'Log on as a Service' to "!SVC_USER!"...

set "TMP_CFG=%TEMP%\svc_grant_%RANDOM%.inf"
set "TMP_DB=%TEMP%\svc_grant_%RANDOM%.sdb"

:: Build the template with the existing assignments plus the new account
set "CURRENT="
for /f "tokens=1,* delims==" %%a in ('findstr /i "SeServiceLogonRight" "!TMP_CHK!" 2^>nul') do set "CURRENT=%%b"

powershell -NoProfile -Command ^
"if ('%CURRENT%') {" ^
" $line = 'SeServiceLogonRight = %CURRENT%,!SVC_USER!';" ^
"} else {" ^
" $line = 'SeServiceLogonRight = !SVC_USER!';" ^
"};" ^
"$content = '[Unicode]' + \"`r`n\" + 'Unicode=yes' + \"`r`n\" + '[Privilege Rights]' + \"`r`n\" + $line + \"`r`n\";" ^
"[System.IO.File]::WriteAllText('!TMP_CFG!', $content, [System.Text.Encoding]::Unicode)" 2>nul

secedit /configure /db "!TMP_DB!" /cfg "!TMP_CFG!" /areas USER_RIGHTS >nul 2>&1

if !errorlevel! equ 0 (
echo [SUCCESS] 'Log on as a Service' granted to "!SVC_USER!".
echo [NOTE] The service must be restarted to pick up the new token.
) else (
echo [ERROR] Failed to apply right. Code: !errorlevel!
echo [HELP] Check: %windir%\security\logs\scesrv.log
)

:: Cleanup
del "!TMP_CFG!" >nul 2>&1
del "!TMP_DB!" >nul 2>&1
del "!TMP_DB!.log" >nul 2>&1
del "!TMP_DB!.jfm" >nul 2>&1

echo ============================================================
pause

Common Pitfalls and How to Avoid Them

"Logon Failure" (Error 1069)

This error almost always means the account has the correct password but lacks the SeServiceLogonRight.

GPO Overrides

Domain Group Policy (GPO) can overwrite your local settings. If you grant the right via script but a GPO sets "Log on as a Service" to a restricted list, your change will be reverted every 90 minutes.

SEO and UX Tip

Advise your users that for domain-joined servers, it is far better to manage User Rights Assignments via a Group Policy Object (GPO) linked to the server's OU, rather than scripting local policy changes.

Best Practices for Service Accounts

  1. Use Managed Service Accounts (gMSA): Whenever possible, use Active Directory Group Managed Service Accounts. They manage their own passwords and rights automatically, eliminating the need for this script entirely.
  2. Least Privilege: Never add a service account to the "Administrators" group. Granting SeServiceLogonRight specifically is much safer.
  3. Audit Rights: Use secedit /export /areas USER_RIGHTS to dump the current security policy and verify that your service accounts have the rights they need.
Restart Required?

Typically, granting a user right takes effect immediately, but the service itself must be restarted to pick up the new token.

Conclusion

Granting the "Log on as a Service" right via Batch script is a critical step in deploying robust Windows applications. By automating this permission assignment, you ensure that your critical background services start reliably after every reboot or deployment. This professional approach to configuration management reduces deployment errors, enhances security posture, and ensures that your infrastructure adheres to the principle of least privilege across your entire server environment.