Skip to content

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 ActiveDirectory module (Get-ADUser, New-ADUser, etc.)
  • Passwords must be SecureString objects, never plain strings, when creating or changing them
  • Set-LocalUser and New-LocalUser require an elevated (Administrator) session
  • Disable-LocalUser is safer than Remove-LocalUser when 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

Get-LocalGroupMember -Group "Administrators" | Select-Object Name, SID, ObjectClass
Domain accounts and orphaned SIDs (from deleted accounts) can show up in group membership without a clean matching local name. Checking SID 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.

Additional Resources