PowerShell Pipeline
Managing Local User Accounts with PowerShell
Here's how to add, disable and delete accounts.
Creating local user accounts via the UI is pretty straightforward. You open up computer management and then go to the Users folder and can then just right click and create a new user. You can also go back to the old school command line ways of using net user /add and create an account that way. PowerShell is not without its own approach of doing this as well using the ADSI provider to create a local account.
Working with the ADSI WinNT provider against local systems can definitely be a process as none of the methods that you can use are easily discoverable unless you look up on the MSDN pages to see how to perform various methods.
Getting Started
Using the ADSI approach means that we will use the [ADSI] type accelerator to connect to our system.
$Computername = $env:COMPUTERNAME
$ADSIComp = [adsi]"WinNT://$Computername"
Now that I have made my connection using ADSI to the local system, we can go ahead and begin with creating a user account. I will use the Create() method and supply two arguments: the schema type of object being created and the name of the account.
$Username = 'TestProx'
$NewUser = $ADSIComp.Create('User',$Username)
Now the account has been created ... sort of. We have the object created, but we still need to set a password on the account before it can be officially created.
#Create password
$Password = Read-Host -Prompt "Enter password for $Username" -AsSecureString
$BSTR = [system.runtime.interopservices.marshal]::SecureStringToBSTR($Password)
$_password = [system.runtime.interopservices.marshal]::PtrToStringAuto($BSTR)
#Set password on account
$NewUser.SetPassword(($_password))
$NewUser.SetInfo()
#Cleanup
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
Remove-Variable Password,BSTR,_password
We can look at the event log to see that the account was created:
$xml = '
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[System[(EventID=4720)]]</Select>
</Query>
</QueryList>
'
Get-WinEvent -FilterXml $xml | Select -Expand Message
This event actually shows up if you put in a password that wasn't accepted due to the password policy set on the system. What would happen is that the account is created but then deleted once the unsupported password is applied.
From here, I can still use that existing object to perform some other things such as updating the description of user account.
$NewUser.Description ='Test account'
$NewUser.SetInfo()
Note that I have to call SetInfo() to actually apply the change to the user account.
Disabling the Account
Let's say that we want to disable the account after creating it until whoever needs this account stops by to reset the password. We can make use of some bitwise operations based off of the enumerations list in this MSDN page.
In this case, the enum for disabling an account is 2 (0x200). This means to test to see if the account is disabled, we can perform the following bitwise operation using –BAND:
$Disabled = 0x0002
[boolean]($newuser.UserFlags.value -BAND $Disabled)
Coming back with a False value means that the account is currently not disabled. Now that we have seen it is not currently disabled, we will go ahead and disable the account by using the –BOR operator (think of this as adding a user flag).
$newuser.userflags.value = $newuser.UserFlags.value -BOR $Disabled
$NewUser.SetInfo()
Testing the account again will show that it has now been disabled.
#Verify Disabled doing BitWise operation
[boolean]($newuser.UserFlags.value -BAND $Disabled)
Let's assume that the account is ready for pickup by a user, we can how re-enable the account and it is ready to go! We will simply reverse the process by using the –BXOR bitwise operator (think of this as removing a user flag).
#ReEnable Account
$newuser.userflags.value = $newuser.UserFlags.value -BXOR $Disabled
$NewUser.SetInfo()
And we will perform one final check on whether this account is enabled.
#Verify Enabled doing BitWise operation
[boolean]($newuser.UserFlags.value -BAND $Disabled)
This comes back as False which means that our job is done! The account has been created and is ready for use.
One last thing with this account. I could just give the user the password that I set and then force the password to be changed at logon using the following code:
$NewUser.PasswordExpired = 1
$NewUser.SetInfo()
This now forces the user to change the password upon logon.
Deleting an Account
Deleting a user account can be accomplished in a similar manner that we took to create an account. By using the ADSI WinNT provider we will connect to the system and then instead of using Create() to build an account, we will make use of Delete() instead.
The Delete method takes arguments similar to what Create took. We supply the schema type of User and the username of the account.
$Computername = $env:COMPUTERNAME
$ADSIComp = [adsi]"WinNT://$Computername"
$ADSIComp.Delete('User','TestProx')
We can verify that it was deleted:
$xml = '
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[System[(EventID=4726)]]</Select>
</Query>
</QueryList>
'
Get-WinEvent -FilterXml $xml | Select -Expand Message
And there we have it. You can now take this knowledge with you and perform some account creations or deletions as well as modifying some user flags if needed on local or remote systems.
About the Author
Boe Prox is a Microsoft MVP in Windows PowerShell and a Senior Windows System Administrator. He has worked in the IT field since 2003, and he supports a variety of different platforms. He is a contributing author in PowerShell Deep Dives with chapters about WSUS and TCP communication. He is a moderator on the Hey, Scripting Guy! forum, and he has been a judge for the Scripting Games. He has presented talks on the topics of WSUS and PowerShell as well as runspaces to PowerShell user groups. He is an Honorary Scripting Guy, and he has submitted a number of posts as a to Microsoft's Hey, Scripting Guy! He also has a number of open source projects available on Codeplex and GitHub. His personal blog is at http://learn-powershell.net.