User Tools

Site Tools


microsoft_windows:adduser_powershell

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
microsoft_windows:adduser_powershell [2025/05/16 01:18] rodolicomicrosoft_windows:adduser_powershell [2025/05/25 01:24] (current) rodolico
Line 5: Line 5:
  
 It should not be interactive at all. It should not be interactive at all.
 +
 +The following is **insecure** as both the AES256 key and the password encrypted by it are in the script itself, so treat the script with the same security as you would the password itself. It obscures the password instead of actually hiding it; one step above actually putting the password in the file in plain text. It is secure against someone just reading it, but any script kiddie can hack the password in no time.
 +
 +My initial, simplistic code did not take into account that when you create a secure passsword with no encryption key, it uses a key attached to the machine and user (maybe just the user). The result is that it will work just fine when run by the user on the same machine that generated it, but fails on other machines.
 +
 +Note: I put a lot of comments in the scripts to explain what is going on. The actual code is very small.
  
 ===== Generate password hash ===== ===== Generate password hash =====
  
-The first step is to generate a password hash (what Windows calls SecureString) so we are not passing around passwords in plaintext+The first step is to generate a password, and encrypt it with randomly generated key. This will save the results to two files, aes.key and encrypted_password.txt.
  
-<code powershell genPass.ps1+Run this script one time and put the contents of the key and the encrypted passwords files into updateUser.ps1. Each time this is run, a new key is generated.
-$password = ConvertTo-SecureString -String "password" -AsPlainText -Force +
-$plain = convertFrom-securestring -securestring $password +
-$plain +
-</code>+
  
-The final line will give very long hex numberwhich is the hash of the password ("password" in first line).+<code powershell makepass.ps1> 
 +# script to create a secure password and save it encrypted 
 +# This will accept password input from the usergenerate a random key, 
 +# and save both the key and the encrypted password to files. 
 +# This was createed to be used with the updateUser.ps1 script 
 +# with the help of Copilot. 
 + 
 + 
 +# Ensure the script is run with administrative privileges 
 +# Requires -Version 5.1 
 +# Requires -RunAsAdministrator 
 + 
 +# Prompt for password 
 +$password = Read-Host "Enter password" -AsSecureString 
 + 
 +# Generate a random key and save it 
 +# Note: a new random key is generated each time this script runs. 
 +# we save teh contents of the key to a file named aes.key 
 +# This key should be kept secure and not shared publicly. 
 +$key = New-Object Byte[] 32 
 +[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($key) 
 +Set-Content -Path "aes.key" -Value ($key | ForEach-Object { $_.ToString() }) 
 + 
 +# Export the secure string using the key 
 +# The password will be encrypted using AES-256 with the generated key 
 +# Note: The encrypted password will be saved in a file named encrypted_password.txt 
 +$password | ConvertFrom-SecureString -Key $key | Set-Content "encrypted_password.txt" 
 +</code>
  
 ===== Download and Modify script ===== ===== Download and Modify script =====
Line 23: Line 52:
  
 Adjust the following to your needs Adjust the following to your needs
-  * $password: Replace //Very Long Hex String from above// with the hash from the previous step +  * $username: Replace with the username to update/create 
-  * $userThis will be the username you log in as +  * $key: Replace the comma separated integers with the 32 integers in the file aes.key 
-  * $groupThe group to add the user to +  * $securePasswordReplace //contents of encrypted_password.txt// with the contents of the file encrypted_password.txt 
-  * $fullnameThe display name of the user (optional+  * $fullNameThis is the diplay name of the user 
-  * $descriptionA description of the user (optional)+  * $descriptionAn optional Description of the user (defaults to Added by script
 +  * $localGroupGroup to add the user so (only one group)
  
-<code powershell adduser.ps1> 
-# script to add a local user with admin privileges on a Windows machine 
-# Generate the password hash with the following three lines (after changing "password" 
-# 
-# $password = ConvertTo-SecureString -String "password" -AsPlainText -Force 
-# $plain = convertFrom-securestring -securestring $password 
-# $plain 
-# 
-# paste the output into -String below 
-# adjust the user and which group to add them to. 
-# if user already exists, will ignore (with message. 
-# password is updated no matter what 
-# if user is already in group, will ignore (with message) 
  
-$password = ConvertTo-SecureString -String "Very Long Hex String from above" +<code powershell updateUser.ps1> 
-$user = 'test' +# Script to create or update a local user with a secure password 
-$group = "Administrators" +# This script checks if a local user exists, creates it if not, and sets the password. 
-$fullname = "Test Account" +# It also ensures the user is part of the Administrators group. 
-$description = 'Test Account'+# Requires -Version 5.1 
 +# Requires -RunAsAdministrator
  
-# Check if user exists +# this is insecure because both the key and the encrypted password are stored in plaintext within the script. 
-if (-not (Get-LocalUser -Name $user -ErrorAction SilentlyContinue)) {+# and can be reversed to obtain the original password. 
 +# This script is intended to be used with the makepass.ps1 script, which generates a secure password and key 
 +# and saves it encrypted. 
 + 
 +# For security, consider this password to be obscured, NOT secured. 
 + 
 +# Define variables 
 +# you must define $username, $key, and $securePassword variables before running this script. 
 + 
 + 
 +# Ensure the username is valid and does not contain special characters 
 +$userName = "Enter Username Here" # Replace with the actual username you want to create or update 
 + 
 +# Replace with your actual key, contents of aes.key file 
 +# The keyfile has 32 bytes, newline separated. Replace newlines with commas, 
 +# and paste below. 
 +# Example key: 96,255,122,11,73,230,146,112,214,11,216,253,111,225,240,99,181,82,26,48,245,158,216,219,236,151,62,127,98,155,136,68 
 +# Ensure the key is a byte array of 32 bytes 
 +# Note: The key must be exactly 32 bytes for AES-256 encryption 
 +$key = [Byte[]](1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32)  
 + 
 +# Enter the contents of the file encrypted_password.txt here, within quotes. 
 +# This should be the output from ConvertFrom-SecureString using the same key. 
 +# Example: '76492d1116743f0423413b.....16050a5345AzADgANQBjAA==' (the dots indicate a truncated string) 
 +# Note: The encrypted key will end with '==' if it is base64 encoded. 
 +$securePassword = 'contents of encrypted_password.txt' | ConvertTo-SecureString -Key $key 
 + 
 +$fullName = "" # Full name for the user, defaults to username if empty 
 +$description = "" # Description for the user, defaults to "User created by script" if empty 
 +$localGroup = "" # Group to add the user to, defaults to "Users" if empty. Use Administrators for admin access. 
 + 
 +# if $fullName is empty or null 
 +if (-not $fullName) { 
 +    $fullName = $userName 
 +
 + 
 +# if $description is empty or null 
 +if (-not $description) { 
 +    $description = "User created by script" 
 +
 + 
 +# if $localGroup is empty or null 
 +if (-not $localGroup) { 
 +    $localGroup = "Users" # Default group if not specified 
 +
 + 
 +# Check if user exists, create if not 
 +if (-not (Get-LocalUser -Name $userName -ErrorAction SilentlyContinue)) {
     try {     try {
-        New-LocalUser -Name $user  -Password $password -FullName $fullname -Description $description -PasswordNeverExpires +        New-LocalUser -Name $userName -Password $securePassword -FullName $fullName -Description $description -ErrorAction Stop
-        Write-Host "User '$user' created."+
     } catch {     } catch {
-        Write-Warning "Failed to create user '$user': $_"+        Write-Error "Failed to create user '$userName': $_" 
 +        exit 1
     }     }
-} else { 
-    Write-Host "User '$user' already exists." 
 } }
  
-# Set (or reset) the password+# Set the password (update if user exists)
 try { try {
-    Set-LocalUser -Name $user -Password $password +    Set-LocalUser -Name $userName -Password $securePassword
-    Write-Host "Password updated for user '$user'."+
 } catch { } catch {
-    Write-Warning "Failed to update password: $_"+    Write-Error "Failed to set password for user '$userName': $_" 
 +    exit 1
 } }
  
-Add to local group if not already a member +Ensure user is in correct group 
-try { +if (-not (Get-LocalGroupMember -Group $localGroup -Member $userName -ErrorAction SilentlyContinue)) 
-    if (-not (Get-LocalGroupMember -Group $group -Member $user -ErrorAction SilentlyContinue)) { +    try 
-        Add-LocalGroupMember -Group $group -Member $user +        Add-LocalGroupMember -Group $localGroup -Member $userName -ErrorAction Stop 
-        Write-Host "User '$user' added to group '$group'." +    } catch 
-    } else +        Write-Error "Failed to add user '$userNameto group '$localGroup': $_" 
-        Write-Host "User '$useris already in group '$group'."+        exit 1
     }     }
-} catch { 
-    Write-Warning "Failed to add user '$user' to group '$group': $_" 
 } }
 +# Output success message
 +Write-Host "User '$userName' has been created or updated successfully with the specified password." -ForegroundColor Green
 </code> </code>
  
Line 88: Line 151:
 ===== Enhancements ===== ===== Enhancements =====
  
-Note, if the password hash is to be transported over public media (e-mail, ftpchat), you may want add the -Key or -SecureKey parameters to the encoding (ConvertTo-SecureString) and decoding (ConvertTo-SecureString) commands+  * Do not send the script over any public media like e-mail. You can safely send the $key lineor the $securePassword linebut not both. 
- +  * Multiple groups could be set up by changing group to an array and then looping through them
--SecureKey appearantly uses single pad encryption to further secure the keySee https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/convertto-securestring for details.+  * <del>You can easily change the group to add to. I'd suggest replacing Administrators (two instances near bottom) with a variable, then define the variable at the top.</del> 
 +  * <del>FullName and Description likewise could be set up in variables if this script will be used multiple times</del>
  
 ===== Links ===== ===== Links =====
-  * https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts/set-localuser?view=powershell-5.1+  * This was all built on Linux ([[https://www.devuan.org/|Devuan]]) using Microsoft Code and PowerShell 
 +    * https://code.visualstudio.com/docs/setup/linux 
 +    * https://learn.microsoft.com/en-us/powershell/scripting/install/install-debian?view=powershell-7.5#installation-on-debian-11-or-12-via-the-package-repository 
 +  * Script was generated with the help of CopilotWhile I had a majority of it written beforehand, Copilot became a shortcut to doing the whole AES thing. 
 +    * https://copilot.microsoft.com/
   * https://www.danielengberg.com/powershell-script-add-user-to-local-admin-group/   * https://www.danielengberg.com/powershell-script-add-user-to-local-admin-group/
   * https://stackoverflow.com/questions/49595003/checking-if-a-local-user-account-group-exists-or-not-with-powershell   * https://stackoverflow.com/questions/49595003/checking-if-a-local-user-account-group-exists-or-not-with-powershell
Line 99: Line 167:
   * https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts/get-localuser?view=powershell-5.1   * https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts/get-localuser?view=powershell-5.1
   * https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/convertto-securestring   * https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/convertto-securestring
 +  * https://community.spiceworks.com/t/use-powershell-securestring-with-windows-system-account/974434
 +  * https://stackoverflow.com/questions/7109958/saving-credentials-for-reuse-by-powershell-and-error-convertto-securestring-ke
  
 Also, thanks to DavidN for tightening it up a little for me. Also, thanks to DavidN for tightening it up a little for me.
microsoft_windows/adduser_powershell.1747376302.txt.gz · Last modified: 2025/05/16 01:18 by rodolico