How to Create a New Local User Account with PowerShell

Key Takeaways

  • PowerShell Efficiency: Utilizes PowerShell to create and manage local user accounts efficiently.
  • Advanced Features: Includes scheduling for account enable/disable and adding users to admin groups.
  • Automated Security: Generates secure passwords automatically, enhancing account security.
  • Time Management: Saves time in user account management, particularly useful for MSPs.
  • Customizable Script: Allows for customization through user-defined parameters.
  • Schedule Tasks: Capable of scheduling tasks to enable or disable accounts at specific times.
  • Group Management: Facilitates adding users to specific groups, including administrators.
  • Adaptable for Bulk Creation: While designed for individual accounts, can be adapted for bulk user creation.
  • Security Implications: Highlights the need for strict access controls and regular auditing.
  • NinjaOne Compatibility: Can be integrated with NinjaOne for centralized IT management.

In today’s digital landscape, managing user accounts efficiently is crucial for IT professionals. PowerShell, a powerful scripting language and command-line shell, offers a dynamic way to handle these tasks. This blog post explores a PowerShell script that not only creates local user accounts but also provides options for scheduling and group management, showcasing its utility in various IT environments.

Background

This PowerShell script stands out for its ability to create local user accounts with advanced features like scheduling enable/disable dates and adding users to the local admin group. These functionalities are particularly relevant for IT professionals and Managed Service Providers (MSPs) who manage a large number of user accounts and need to ensure timely and secure access to systems.

The Script:

#Requires -Version 5.1

<#
.SYNOPSIS
    Create a local user account with options to enable and disable at specific dates, and add to local admin group. Saves randomly generated password to a custom field.
.DESCRIPTION
    You can specify when the account will be enabled and/or disabled.
    You can have the account be added as a member of the local Administrators group.

PARAMETER: -UserNameToAdd "JohnTSmith" -Name "John T Smith"
    Create use with the name JohnTSmith and display name of John T Smith.
.EXAMPLE
    -UserNameToAdd "JohnTSmith" -Name "John T Smith"
    ## EXAMPLE OUTPUT ##
    User JohnTSmith has been created successfully.
    User JohnTSmith was added to the local Users group.

PARAMETER: -UserNameToAdd "JohnTSmith" -Name "John T Smith" -DateAndTimeToEnable "Monday, January 1, 2020 1:00:00 PM"
    Create use with the name JohnTSmith and display name of John T Smith.
    The user will start out disabled.
    A scheduled task will be create to enable the user after "Monday, January 1, 2020 1:00:00 PM"
.EXAMPLE
    -UserNameToAdd "JohnTSmith" -Name "John T Smith" -DateAndTimeToEnable "Monday, January 1, 2020 1:00:00 PM"
    ## EXAMPLE OUTPUT ##
    User JohnTSmith has been created successfully.
    User JohnTSmith was added to the local Users group.
    Created Scheduled Task: Enable User JohnTSmith
    User JohnTSmith will be able to login after Monday, January 1, 2020 1:00:00 PM.

PARAMETER: -UserNameToAdd "JohnTSmith" -Name "John T Smith" -DisableAfterDays 10
    Create use with the name JohnTSmith and display name of John T Smith.
    The user will be disabled after 10 days after the user's creation.
.EXAMPLE
    -UserNameToAdd "JohnTSmith" -Name "John T Smith" -DisableAfterDays 10
    ## EXAMPLE OUTPUT ##
    User JohnTSmith has been created successfully.
    User JohnTSmith was added to the local Users group.

PARAMETER: -UserNameToAdd "JohnTSmith" -Name "John T Smith" -AddToLocalAdminGroup
    Create use with the name JohnTSmith and display name of John T Smith.
    User will be added as a member of the local Administrators group.
.EXAMPLE
    -UserNameToAdd "JohnTSmith" -Name "John T Smith" -AddToLocalAdminGroup
    ## EXAMPLE OUTPUT ##
    User JohnTSmith has been created successfully.
    User JohnTSmith was added to the local Users group.
    User JohnTSmith was added to the local Administrators group.
.OUTPUTS
    None
.NOTES
    Minimum OS Architecture Supported: Windows 10, Windows Server 2016
    Release Notes: Initial Release
By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#>

[CmdletBinding()]
param (
    [Parameter()]
    [String]$UserNameToAdd,
    [Parameter()]
    [String]$Name,
    [Parameter()]
    [String]$PasswordCustomField,
    [Parameter()]
    [int]$PasswordLength,
    [Parameter()]
    [DateTime]$DateAndTimeToEnable,
    [Parameter()]
    [int]$DisableAfterDays,
    [Parameter()]
    [Switch]$AddToLocalAdminGroup,
    [Parameter()]
    $PasswordOptions
)

begin {
    function Test-IsElevated {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
    }
    function New-SecurePassword {
        [CmdletBinding()]
        param (
            [Parameter(Mandatory = $false)]
            [int]$Length = 16,
            [Parameter(Mandatory = $false)]
            [bool]$IncludeSpecialCharacters = $true
        )
        # .NET class for generating cryptographically secure random numbers
        $cryptoProvider = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
        $SpecialCharacters = if ($IncludeSpecialCharacters) { '!@#$%&-' }
        $passwordChars = "abcdefghjknpqrstuvwxyzABCDEFGHIJKMNPQRSTUVWXYZ0123456789$SpecialCharacters"
        $password = for ($i = 0; $i -lt $Length; $i++) {
            $byte = [byte[]]::new(1)
            $cryptoProvider.GetBytes($byte)
            $charIndex = $byte[0] % $passwordChars.Length
            $passwordChars[$charIndex]
        }
        return $password -join ''
    }
    function New-LocalUserFromNinja {
        param(
            [string]$Username,
            [string]$Name,
            [string]$PasswordCustomField,
            [DateTime]$EnableDate,
            [int]$DisableAfterDays,
            [switch]$AddToLocalAdminGroup
        )
        # Generate a secure localUserPassword
        $Password = New-SecurePassword -Length $PasswordLength -IncludeSpecialCharacters $true
        if ($Username -and $Name) {
            # Check if the user already exists
            if (-not (Get-LocalUser -Name $Username -ErrorAction SilentlyContinue)) {
                # Create new local user
                $UserSplat = @{
                    Name                 = "$Username"
                    FullName             = "$Name"
                    Password             = ConvertTo-SecureString -String $($Password -join '') -AsPlainText -Force
                    Description          = "User account created on $(Get-Date)"
                    PasswordNeverExpires = $false
                }

                if ($EnableDate -and $EnableDate -gt (Get-Date)) {
                    $UserSplat['Disabled'] = $true
                }

                if (-not $EnableDate -and $DisableAfterDays) {
                    $UserSplat['AccountExpires'] = $(Get-Date).AddDays($DisableAfterDays)
                }
                elseif ($DisableAfterDays) {
                    $UserSplat['AccountExpires'] = $(Get-Date $EnableDate).AddDays($DisableAfterDays)
                }

                if ($env:passwordOptions -like 'Password Never Expires' -or $PasswordOptions -like 'Password Never Expires') {
                    $UserSplat['PasswordNeverExpires'] = $true
                }

                New-LocalUser @UserSplat
                if ($env:passwordOptions -like 'User Must Change Password' -or $PasswordOptions -like 'User Must Change Password') {
                    net.exe user $Username /logonpasswordchg:yes
                }
                # Write it to a secure custom field
                if ((Get-LocalUser -Name $Username -ErrorAction SilentlyContinue)) {
                    Write-Host "User $Username has been created successfully."
                    if ($PasswordCustomField -like "null") {
                        Write-Host "CustomField not specified."
                        Write-Host "Password set to: $Password"
                    }
                    else {
                        Ninja-Property-Set -Name "$PasswordCustomField" -Value "$Password"
                        Write-Host "Password saved to $PasswordCustomField Custom Field."
                    }
                }
                else {
                    throw "Failed to create User $Username."
                }

                Add-LocalGroupMember -Group $(Get-LocalGroup -Name "Users") -Member $Username

                Write-Host "User $UserName was added to the local Users group."

                # If date to enable account is specified, disable account until then
                if ($EnableDate) {
                    if ($EnableDate -gt (Get-Date)) {
                        # Schedule a job to enable the user at the specified date
                        $TaskSplat = @{
                            Description = "Ninja Automation Enable User $Username"
                            Action      = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -WindowStyle Hidden -Command & {Enable-LocalUser -Name `"$Username`"}"
                            Trigger     = New-ScheduledTaskTrigger -Once -At $EnableDate
                            Principal   = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount
                        }

                        try {
                            New-ScheduledTask @TaskSplat | Register-ScheduledTask -User "System" -TaskName "Enable User $Username" | Out-Null
                            if ($(Get-ScheduledTask -TaskName "Enable User $Username")) {
                                Write-Host "Created Scheduled Task: Enable User $Username"
                            }
                            else {
                                throw "Failed to find scheduled task with the name 'Enable User $Username'"
                            }
                        }
                        catch {
                            Write-Error $_
                            throw "Failed to create Enable User scheduled task."
                        }

                        Write-Host "User $Username will be able to login after $EnableDate."
                    }
                }
                else {
                    Write-Host "No Enable Date is Set, $UserName is able to login now."
                }

                # Add to local admin group if specified
                if ($AddToLocalAdminGroup) {
                    Add-LocalGroupMember -Group $(Get-LocalGroup -Name "Administrators") -Member $Username
                    if (-not (Get-LocalGroupMember -Group $(Get-LocalGroup -Name "Administrators") -Member $Username)) {
                        throw "Failed to add user to local Administrators group."
                    }
                    Write-Host "User $UserName was added to the local Administrators group."
                }
            }
            else {
                Write-Host "User $Username already exists."
            }
        }
        else {
            throw "Username and Name are required to create a local account."
        }
    }
}
process {
    if ($env:usernameToAdd -and $env:usernameToAdd -like "null") {
        Write-Error "usernameToAdd($env:usernameToAdd) parameter is invalid."
        exit 1
    }
    if ($env:name -and $env:name -like "null") {
        Write-Error "name($env:name) parameter is invalid."
        exit 1
    }
    if ($env:passwordCustomField -and $env:passwordCustomField -like "null") {
        Write-Error "passwordCustomField($env:passwordCustomField) parameter is invalid."
        exit 1
    }
    if (-not (Test-IsElevated)) {
        Write-Error -Message "Access Denied. Please run with Administrator privileges."
        exit 1
    }
    $params = @{
        Username = if ($PSBoundParameters.ContainsKey("UserNameToAdd")) { $UserNameToAdd }else { $env:usernameToAdd }
        Name     = if ($PSBoundParameters.ContainsKey("Name")) { $Name }else { $env:name }
    }
    # Conditionally add EnableDate
    if ($env:dateAndTimeToEnable -and $env:dateAndTimeToEnable -notlike "null") {
        $params["EnableDate"] = Get-Date "$env:dateAndTimeToEnable"
    }
    elseif ($PSBoundParameters.ContainsKey("DateAndTimeToEnable") -and $DateAndTimeToEnable) {
        $params["EnableDate"] = $DateAndTimeToEnable
    }
    # Conditionally add DisableAfterDays
    if ($env:disableAfterDays -notlike "null") {
        $params["DisableAfterDays"] = $env:disableAfterDays
    }
    elseif ($PSBoundParameters.ContainsKey("DisableAfterDays")) {
        $params["DisableAfterDays"] = $DisableAfterDays
    }

    # Conditionally add AddToLocalAdminGroup
    if ([Convert]::ToBoolean($env:addToLocalAdminGroup)) {
        $params["AddToLocalAdminGroup"] = $true
    }
    elseif ($PSBoundParameters.ContainsKey("AddToLocalAdminGroup")) {
        $params["AddToLocalAdminGroup"] = $AddToLocalAdminGroup
    }
    # Conditionally add AddToLocalAdminGroup
    if ($env:passwordCustomField -notlike "null") {
        $params["PasswordCustomField"] = $env:passwordCustomField
    }
    elseif ($env:passwordCustomField -like "null") {
        Write-Error "passwordCustomField: is Required"
        exit 1
    }
    elseif ($PSBoundParameters.ContainsKey("PasswordCustomField")) {
        $params["PasswordCustomField"] = $PasswordCustomField
    }

    if ($env:passwordLength -notlike "null") {
        $PasswordLength = $env:passwordLength
    }
    elseif (-not $passwordLength) {
        $PasswordLength = 20
    }

    try {
        New-LocalUserFromNinja @params
    }
    catch {
        Write-Error $_
        exit 1
    }
}
end {
    
    
    
}

 

Access over 300+ scripts in the NinjaOne Dojo

Get Access

Detailed Breakdown

The script is structured into several key sections, each performing a specific task:

  • Parameter Definition: Parameters like UserNameToAdd, Name, and DateAndTimeToEnable are declared, allowing for user input customization.
  • Functions: Critical functions like Test-IsElevated, New-SecurePassword, and New-LocalUserFromNinja are defined. Test-IsElevated checks for administrative privileges, New-SecurePassword generates a secure password, and New-LocalUserFromNinja encapsulates the core functionality of user creation and management.
  • User Creation and Management: The script checks if the specified user exists, creates a new user if not, and sets properties like password, description, and account expiry. It also handles the addition of users to groups and schedules tasks for enabling/disabling accounts.

Potential Use Cases

Imagine an MSP managing IT for a company with temporary staff. They can use this script to automate account creation for new employees, setting specific activation and deactivation dates, thus saving time and reducing manual errors.

Comparisons

Traditionally, user account management might involve manual processes or basic scripts that lack advanced features like secure password generation or scheduled enable/disable. This script offers a more sophisticated, secure, and time-efficient approach.

FAQs

  • Can this script handle bulk user creation?
    While designed for individual accounts, it can be adapted for bulk creation with modifications.
  • Is it secure to use for sensitive environments?
    Yes, it includes features like secure password generation.

Implications

Using such a script enhances security and efficiency but also underscores the need for strict access controls and monitoring, as automated account creation can be a potential vector for unauthorized access if not managed properly.

Recommendations

Best practices include regular script review, usage in conjunction with robust auditing policies, and ensuring that only authorized personnel have access to the script and its functionalities.

Final Thoughts

NinjaOne, a platform known for streamlining IT management tasks, can complement such scripts by providing a centralized and user-friendly interface for managing these automated processes. Incorporating PowerShell scripts into a NinjaOne environment could significantly enhance operational efficiency and security in IT management.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service deliver tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).