User Account Tasks
Note
Manage local Windows user accounts and passwords with Get-LocalUser, New-LocalUser, Set-LocalUser, and related cmdlets.
Overview
The Microsoft.PowerShell.LocalAccounts module (built into Windows 10/Server 2016+) replaces net user for local account management. It's scriptable, returns real objects instead of parsed text, and handles password security properly through SecureString rather than plaintext command-line arguments.
Basic Syntax
Get-LocalUser
New-LocalUser -Name "svc-backup" -Password (Read-Host -AsSecureString "Password")
Set-LocalUser -Name "svc-backup" -PasswordNeverExpires $true
Remove-LocalUser -Name "svc-backup"
Add-LocalGroupMember -Group "Administrators" -Member "svc-backup"
Key Points
- These cmdlets manage local accounts only — for Active Directory, use the
ActiveDirectorymodule (Get-ADUser,New-ADUser, etc.) - Passwords must be
SecureStringobjects, never plain strings, when creating or changing them Set-LocalUserandNew-LocalUserrequire an elevated (Administrator) sessionDisable-LocalUseris safer thanRemove-LocalUserwhen you're not sure the account is still needed
Viewing Accounts
# All local accounts
Get-LocalUser
# A specific account
Get-LocalUser -Name "svc-backup"
# Only enabled accounts
Get-LocalUser | Where-Object { $_.Enabled }
# Accounts that have never logged in
Get-LocalUser | Where-Object { $_.LastLogon -eq $null }
# Local group membership
Get-LocalGroupMember -Group "Administrators"
Output:
Name Enabled Description
---- ------- -----------
Administrator False Built-in account for administering the computer/domain
svc-backup True Backup service account
raymond True
Creating Accounts
# Prompt for a password interactively (never types plaintext into the script)
$password = Read-Host -AsSecureString "Enter password"
New-LocalUser -Name "svc-backup" -Password $password -FullName "Backup Service Account" -Description "Used by nightly backup jobs"
# Build a SecureString from a known value (fine for one-time bootstrap scripts, not for storing secrets)
$securePassword = ConvertTo-SecureString "TempP@ssw0rd!" -AsPlainText -Force
New-LocalUser -Name "svc-temp" -Password $securePassword
# Create a disabled account (activate it later once fully configured)
New-LocalUser -Name "svc-future" -Password $securePassword -Disabled
Never Hardcode Real Passwords in Scripts
# BAD - plaintext password sitting in a script file / source control
$securePassword = ConvertTo-SecureString "RealP@ssw0rd" -AsPlainText -Force
# GOOD - prompt for it, or pull from a secret store
$securePassword = Read-Host -AsSecureString "Enter password"
ConvertTo-SecureString -AsPlainText -Force is fine for local testing or ephemeral automation passwords, but a hardcoded real credential in a script is a credential leak waiting to happen. See Credential Management for safer storage patterns. Modifying Accounts
# Set password to never expire
Set-LocalUser -Name "svc-backup" -PasswordNeverExpires $true
# Force a password change at next logon
Set-LocalUser -Name "raymond" -Description "Updated description"
# Reset a password
$newPassword = Read-Host -AsSecureString "New password"
Set-LocalUser -Name "svc-backup" -Password $newPassword
# Rename an account
Rename-LocalUser -Name "svc-old" -NewName "svc-new"
Enabling, Disabling, and Removing
# Disable without deleting (reversible, preserves SID and group membership)
Disable-LocalUser -Name "svc-backup"
# Re-enable
Enable-LocalUser -Name "svc-backup"
# Delete permanently
Remove-LocalUser -Name "svc-old"
Disable Instead of Delete
Deleting a local account removes its SID permanently — any file permissions, group memberships, or scheduled task ownership tied to that SID become orphaned and can't be easily recovered. Disable-LocalUser blocks logon while keeping everything intact, which is almost always the safer first move for an account you're not 100% sure is unused.
Managing Group Membership
# Add to a local group
Add-LocalGroupMember -Group "Administrators" -Member "svc-backup"
# Remove from a group
Remove-LocalGroupMember -Group "Administrators" -Member "svc-backup"
# List members of a group
Get-LocalGroupMember -Group "Remote Desktop Users"
# Create a new local group
New-LocalGroup -Name "BackupOperators-Custom" -Description "Custom backup group"
Important Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
-Name | String | Account/group name | Get-LocalUser -Name "svc-backup" |
-Password | SecureString | Account password | New-LocalUser -Password $sec |
-FullName | String | Display name | -FullName "Backup Account" |
-Description | String | Account description | -Description "Used by..." |
-PasswordNeverExpires | Bool | Exempt from password expiration policy | -PasswordNeverExpires $true |
-Disabled | Switch | Create the account in a disabled state | New-LocalUser -Disabled |
-Member | String | Add/Remove-LocalGroupMember: account to add/remove | -Member "svc-backup" |
Common Patterns
# Pattern 1: Create-if-missing service account
$accountName = "svc-backup"
if (-not (Get-LocalUser -Name $accountName -ErrorAction SilentlyContinue)) {
$password = ConvertTo-SecureString ([guid]::NewGuid().ToString()) -AsPlainText -Force
New-LocalUser -Name $accountName -Password $password -PasswordNeverExpires $true -Description "Service account"
}
# Pattern 2: Audit accounts that haven't logged in for 90+ days
Get-LocalUser | Where-Object {
$_.Enabled -and $_.LastLogon -and $_.LastLogon -lt (Get-Date).AddDays(-90)
} | Select-Object Name, LastLogon
# Pattern 3: Ensure an account is a member of a required group
$groupMembers = Get-LocalGroupMember -Group "Administrators" | Select-Object -ExpandProperty Name
if ($groupMembers -notcontains "DOMAIN\svc-backup") {
Add-LocalGroupMember -Group "Administrators" -Member "svc-backup"
}
Real-World Examples
Example: Provision a Service Account With a Random Password
Scenario: Set up a new local service account with a strong, random, never-expiring password, and record the generated password securely for retrieval later.
$accountName = "svc-app"
$vaultPath = "C:\Secure\svc-app-credential.xml"
if (-not (Get-LocalUser -Name $accountName -ErrorAction SilentlyContinue)) {
# Generate a strong random password
$bytes = New-Object byte[] 24
[System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes)
$plainPassword = [Convert]::ToBase64String($bytes)
$securePassword = ConvertTo-SecureString $plainPassword -AsPlainText -Force
New-LocalUser -Name $accountName -Password $securePassword `
-Description "Application service account" -PasswordNeverExpires $true
# Save the credential securely (encrypted to the current user/machine)
$credential = New-Object System.Management.Automation.PSCredential($accountName, $securePassword)
$credential | Export-Clixml -Path $vaultPath
Write-Output "Created $accountName and saved credential to $vaultPath"
}
Explanation: The random password never appears in a script file or command history. Export-Clixml on a PSCredential encrypts the password using Windows DPAPI, tied to the current user and machine — see Credential Management for the full round-trip including Import-Clixml.
Tips & Tricks
Check Group Membership by SID, Not Just Name
Domain accounts and orphaned SIDs (from deleted accounts) can show up in group membership without a clean matching local name. CheckingSID and ObjectClass alongside Name avoids scripts silently missing entries that don't resolve to a friendly name. Local Accounts Module Requires Windows
Microsoft.PowerShell.LocalAccounts only works on Windows — there's no cross-platform equivalent in PowerShell 7 on Linux/macOS. For Active Directory environments, these cmdlets manage the local SAM database only; use the ActiveDirectory module's Get-ADUser/New-ADUser for domain accounts instead.
Related Topics
- Credential Management - Storing and retrieving the passwords these cmdlets create
- Services Management - Service accounts created here are often used to run services