powershellautomationchange-password

Reset Multiple User Passwords in PowerShell via Text File


I have script that (that I tweaked from a forum) that reads a text file which contains usernames.

This generates a 9 character random password and outputs the password via PowerShell:

 $ListOfUsers = Get-Content C:\temp\list.txt
 foreach ($user in $ListOfUsers) {
     #Generate a 9-character random password
     $Password = -join ((33..126) | Get-Random -Count 9 | ForEach-Object { [char]$_ })
     #Convert the password to secure string
     $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
     #Reset the account password
     Set-ADAccountPassword $user -NewPassword $Pass -Reset
     #Display userid and password values 
     Write-Host $user, $Password
 }

Since the password it displays contains special characters - this cause problems for certain users who access access special pieces of equipment on our network, I am forced to set random password manually in AD for these users.

I was wondering if it is possible to define a random password that contains letters (lower and higher case) and numbers only?

OR

Could I supply a text file with passwords on each line for PowerShell to set for each user?

UPDATE 1

@Theo I ran your code and got this error:

PS C:\Windows\system32> $ListOfUsers = Get-Content C:\temp\list.txt
$result = foreach ($user in $ListOfUsers) {
    #Generate a 9-character random password
    $Password = New-Password -TotalLength 9 -Symbols 0
    #Convert the password to secure string
    $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
    #Reset the account password
    Set-ADAccountPassword $user -NewPassword $Pass -Reset
    #Display userid and password values 
    #Write-Host $user, $Password

    # or better yet, output the newly set passwords as PsCustomObject to use in a csv file
    [PsCustomObject]@{User = $user; Password = $Password}
}

# show on screen
$result | Format-Table -AutoSize

# write to CSV file you can open in Excel by double-clicking it
$result | Export-Csv -Path 'C:\temp\NewPasswords.csv' -NoTypeInformation -UseCulture
New-Password : The term 'New-Password' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a 
path was included, verify that the path is correct and try again.
At line:4 char:17
+     $Password = New-Password -TotalLength 9 -Symbols 0
+                 ~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (New-Password:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
 
ConvertTo-SecureString : Cannot bind argument to parameter 'String' because it is null.
At line:6 char:36
+     $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
+                                    ~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [ConvertTo-SecureString], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ConvertToSecureStringCommand
 
Please enter the desired password for 'CN=Test User,CN=Users,DC=my,DC=domain,DC=net'
Password: 

Seem like New-Password is not available on my PowerShell.

Unless you can see something I can't?

UPDATE 2

@Theo ran it your script with changes (removed the symbols) got this error message:

PS C:\Windows\system32> function New-Password {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateRange(8, 128)]
        [int]$TotalLength = 9,
        [int]$LowerAlpha = 3,
        [int]$UpperAlpha = 4,
        [int]$Digits = 2
    )
    # check if the given parameters are => 0 and <= $TotalLength
    $LowerAlpha = [math]::Max(0,[math]::Min($LowerAlpha, $TotalLength))
    $UpperAlpha = [math]::Max(0,[math]::Min($UpperAlpha, $TotalLength))
    $Digits     = [math]::Max(0,[math]::Min($Digits, $TotalLength))

    if ($TotalLength - ($LowerAlpha + $UpperAlpha + $Digits) -lt 0) {
        throw "Too many alphas, digits or symbols to fit the total password length"
    }
    $list = [System.Collections.Generic.List[char]]::new()

    if ($LowerAlpha) { $list.AddRange([char[]]([char[]]'abcdefghijklmnopqrstuvwxyz' | Get-Random -Count $LowerAlpha)) }
    if ($UpperAlpha) { $list.AddRange([char[]]([char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ' | Get-Random -Count $UpperAlpha)) }
    if ($Digits)     { $list.AddRange([char[]]([char[]]'0123456789' | Get-Random -Count $Digits)) }

    ($list | Sort-Object {Get-Random}) -join ''
}

$ListOfUsers = Get-Content C:\temp\list.txt
$result = foreach ($user in $ListOfUsers) {
    #Generate a 9-character random password
    $Password = New-Password -TotalLength 9 -Symbols 0
    #Convert the password to secure string
    $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
    #Reset the account password
    Set-ADAccountPassword $user -NewPassword $Pass -Reset
    #Display userid and password values 
    #Write-Host $user, $Password

    # or better yet, output the newly set passwords as PsCustomObject to use in a csv file
    [PsCustomObject]@{User = $user; Password = $Password}
}

# show on screen
$result | Format-Table -AutoSize

# write to CSV file you can open in Excel by double-clicking it
$result | Export-Csv -Path 'C:\temp\NewPasswords.csv' -NoTypeInformation -UseCulture
New-Password : A parameter cannot be found that matches parameter name 'Symbols'.
At line:31 char:45
+     $Password = New-Password -TotalLength 9 -Symbols 0
+                                             ~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [New-Password], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,New-Password
 
ConvertTo-SecureString : Cannot bind argument to parameter 'String' because it is null.
At line:33 char:36
+     $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
+                                    ~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [ConvertTo-SecureString], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ConvertToSecureStringCommand
 
Please enter the desired password for 'CN=Test User,CN=Users,DC=my,DC=domain,DC=net'
Password: 

I even removed changed this line from this:

+     $Password = New-Password -TotalLength 9 -Symbols 0

To this:


+     $Password = New-Password

Got this error then:

PS C:\Windows\system32> function New-Password {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateRange(8, 128)]
        [int]$TotalLength = 9,
        [int]$LowerAlpha = 3,
        [int]$UpperAlpha = 4,
        [int]$Digits = 2
    )
    # check if the given parameters are => 0 and <= $TotalLength
    $LowerAlpha = [math]::Max(0,[math]::Min($LowerAlpha, $TotalLength))
    $UpperAlpha = [math]::Max(0,[math]::Min($UpperAlpha, $TotalLength))
    $Digits     = [math]::Max(0,[math]::Min($Digits, $TotalLength))

    if ($TotalLength - ($LowerAlpha + $UpperAlpha + $Digits) -lt 0) {
        throw "Too many alphas, digits or symbols to fit the total password length"
    }
    $list = [System.Collections.Generic.List[char]]::new()

    if ($LowerAlpha) { $list.AddRange([char[]]([char[]]'abcdefghijklmnopqrstuvwxyz' | Get-Random -Count $LowerAlpha)) }
    if ($UpperAlpha) { $list.AddRange([char[]]([char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ' | Get-Random -Count $UpperAlpha)) }
    if ($Digits)     { $list.AddRange([char[]]([char[]]'0123456789' | Get-Random -Count $Digits)) }

    ($list | Sort-Object {Get-Random}) -join ''
}

$ListOfUsers = Get-Content C:\temp\list.txt
$result = foreach ($user in $ListOfUsers) {
    #Generate a 9-character random password
    $Password = New-Password
    #Convert the password to secure string
    $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
    #Reset the account password
    Set-ADAccountPassword $user -NewPassword $Pass -Reset
    #Display userid and password values 
    #Write-Host $user, $Password

    # or better yet, output the newly set passwords as PsCustomObject to use in a csv file
    [PsCustomObject]@{User = $user; Password = $Password}
}

# show on screen
$result | Format-Table -AutoSize

# write to CSV file you can open in Excel by double-clicking it
$result | Export-Csv -Path 'C:\temp\NewPasswords.csv' -NoTypeInformation -UseCulture
Method invocation failed because [System.Collections.Generic.List`1[[System.Char, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]] does 
not contain a method named 'new'.
At line:19 char:5
+     $list = [System.Collections.Generic.List[char]]::new()
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound
 
You cannot call a method on a null-valued expression.
At line:21 char:24
+     if ($LowerAlpha) { $list.AddRange([char[]]([char[]]'abcdefghijklmnopqrstuvwx ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
 
You cannot call a method on a null-valued expression.
At line:22 char:24
+     if ($UpperAlpha) { $list.AddRange([char[]]([char[]]'ABCDEFGHIJKLMNOPQRSTUVWX ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
 
You cannot call a method on a null-valued expression.
At line:23 char:24
+     if ($Digits)     { $list.AddRange([char[]]([char[]]'0123456789' | Get-Random ...
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
 
ConvertTo-SecureString : Cannot bind argument to parameter 'String' because it is an empty string.
At line:33 char:36
+     $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
+                                    ~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [ConvertTo-SecureString], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ConvertToSecureStringCommand
 
Please enter the desired password for 'CN=Test User,CN=Users,DC=my,DC=domain,DC=net'
Password: 

Seems like the issue is on this line:

$list = [System.Collections.Generic.List[char]]::new()

UPDATE 3

I tried all your code without any changes and got this error message:

PS C:\Windows\system32> function New-Password {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateRange(8, 128)]
        [int]$TotalLength = 10,
        [int]$LowerAlpha = 3,
        [int]$UpperAlpha = 2,
        [int]$Digits = 3,
        [int]$Symbols = 2
    )
    # check if the given parameters are => 0 and <= $TotalLength
    $LowerAlpha = [math]::Max(0,[math]::Min($LowerAlpha, $TotalLength))
    $UpperAlpha = [math]::Max(0,[math]::Min($UpperAlpha, $TotalLength))
    $Digits     = [math]::Max(0,[math]::Min($Digits, $TotalLength))
    $Symbols    = [math]::Max(0,[math]::Min($Symbols, $TotalLength))

    if ($TotalLength - ($LowerAlpha + $UpperAlpha + $Digits + $Symbols) -lt 0) {
        throw "Too many alphas, digits or symbols to fit the total password length"
    }
    $list = [System.Collections.Generic.List[char]]::new()
    # older PowerShell versions use: $list = New-Object System.Collections.Generic.List[char]

    if ($LowerAlpha) { $list.AddRange([char[]]([char[]]'abcdefghijklmnopqrstuvwxyz' | Get-Random -Count $LowerAlpha)) }
    if ($UpperAlpha) { $list.AddRange([char[]]([char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ' | Get-Random -Count $UpperAlpha)) }
    if ($Digits)     { $list.AddRange([char[]]([char[]]'0123456789' | Get-Random -Count $Digits)) }
    if ($Symbols)    { $list.AddRange([char[]]([char[]]'!@#$%^&*()_-+=[{]};:<>|./?~' | Get-Random -Count $Symbols)) }

    ($list | Sort-Object {Get-Random}) -join ''
}

$ListOfUsers = Get-Content C:\temp\list.txt
$result = foreach ($user in $ListOfUsers) {
    #Generate a 9-character random password
    $Password = New-Password -TotalLength 9 -Symbols 0
    #Convert the password to secure string
    $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
    #Reset the account password
    Set-ADAccountPassword $user -NewPassword $Pass -Reset
    #Display userid and password values 
    #Write-Host $user, $Password

    # or better yet, output the newly set passwords as PsCustomObject to use in a csv file
    [PsCustomObject]@{User = $user; Password = $Password}
}

# show on screen
$result | Format-Table -AutoSize

# write to CSV file you can open in Excel by double-clicking it
$result | Export-Csv -Path 'C:\temp\NewPasswords.csv' -NoTypeInformation -UseCulture
Method invocation failed because [System.Collections.Generic.List`1[[System.Char, mscorlib, Version=4.0.0.0, Culture=neutral, 
PublicKeyToken=b77a5c561934e089]]] does not contain a method named 'new'.
At line:21 char:5
+     $list = [System.Collections.Generic.List[char]]::new()
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound
 
You cannot call a method on a null-valued expression.
At line:24 char:24
+     if ($LowerAlpha) { $list.AddRange([char[]]([char[]]'abcdefghijklmnopqrstuvwx ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
 
You cannot call a method on a null-valued expression.
At line:25 char:24
+     if ($UpperAlpha) { $list.AddRange([char[]]([char[]]'ABCDEFGHIJKLMNOPQRSTUVWX ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
 
You cannot call a method on a null-valued expression.
At line:26 char:24
+     if ($Digits)     { $list.AddRange([char[]]([char[]]'0123456789' | Get-Random ...
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
 
ConvertTo-SecureString : Cannot bind argument to parameter 'String' because it is an empty string.
At line:37 char:36
+     $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
+                                    ~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [ConvertTo-SecureString], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.ConvertToSecureStringCommand
 
Please enter the desired password for 'CN=Test User,CN=Users,DC=my,DC=domain,DC=net'
Password: 

Solution

  • You could use below helper function to generate passwords with or without special characters:

    function New-Password {
        [CmdletBinding()]
        param(
            [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
            [ValidateRange(8, 128)]
            [int]$TotalLength = 10,
            [int]$LowerAlpha = 3,
            [int]$UpperAlpha = 2,
            [int]$Digits = 3,
            [int]$Symbols = 2
        )
        # check if the given parameters are => 0 and <= $TotalLength
        $LowerAlpha = [math]::Max(0,[math]::Min($LowerAlpha, $TotalLength))
        $UpperAlpha = [math]::Max(0,[math]::Min($UpperAlpha, $TotalLength))
        $Digits     = [math]::Max(0,[math]::Min($Digits, $TotalLength))
        $Symbols    = [math]::Max(0,[math]::Min($Symbols, $TotalLength))
    
        if ($TotalLength - ($LowerAlpha + $UpperAlpha + $Digits + $Symbols) -lt 0) {
            throw "Too many alphas, digits or symbols to fit the total password length"
        }
        $list = [System.Collections.Generic.List[char]]::new()
        # older PowerShell versions use: $list = New-Object System.Collections.Generic.List[char]
    
        if ($LowerAlpha) { $list.AddRange([char[]]([char[]]'abcdefghijklmnopqrstuvwxyz' | Get-Random -Count $LowerAlpha)) }
        if ($UpperAlpha) { $list.AddRange([char[]]([char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ' | Get-Random -Count $UpperAlpha)) }
        if ($Digits)     { $list.AddRange([char[]]([char[]]'0123456789' | Get-Random -Count $Digits)) }
        if ($Symbols)    { $list.AddRange([char[]]([char[]]'!@#$%^&*()_-+=[{]};:<>|./?~' | Get-Random -Count $Symbols)) }
    
        ($list | Sort-Object {Get-Random}) -join ''
    }
    

    Usage:

    Paste the function above on top of your script and then your code would become:

    $ListOfUsers = Get-Content C:\temp\list.txt
    $result = foreach ($user in $ListOfUsers) {
        #Generate a 9-character random password
        $Password = New-Password -TotalLength 9 -Symbols 0
        #Convert the password to secure string
        $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
        #Reset the account password
        Set-ADAccountPassword $user -NewPassword $Pass -Reset
        #Display userid and password values 
        #Write-Host $user, $Password
    
        # or better yet, output the newly set passwords as PsCustomObject to use in a csv file
        [PsCustomObject]@{User = $user; Password = $Password}
    }
    
    # show on screen
    $result | Format-Table -AutoSize
    
    # write to CSV file you can open in Excel by double-clicking it
    $result | Export-Csv -Path 'C:\temp\NewPasswords.csv' -NoTypeInformation -UseCulture
    

    As per your comment, here's a stripped-down version of the code, where the New-Password function now only has one optional parameter: $TotalLength.
    It will only use uppercase and lowercase characters plus digits. No more symbols.

    function New-Password {
        [CmdletBinding()]
        param(
            [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
            [ValidateRange(8, 128)]
            [int]$TotalLength = 10
        )
        # calculate the minimum number of characters (lower/upper and digits) needed: 
        # maximum in $TotalLength divided by 3 (rounded up)
        $numChars = [int][math]::Ceiling($TotalLength / 3)
    
        $list = New-Object System.Collections.Generic.List[char]
        # PowerShell versions => 5 use: 
        # $list = [System.Collections.Generic.List[char]]::new()
    
        while ($list.Count -lt $TotalLength) {
            # add lower, upper characters and digits to the list
            $list.AddRange([char[]]([char[]]'abcdefghijklmnopqrstuvwxyz' | Get-Random -Count $numChars))
            $list.AddRange([char[]]([char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ' | Get-Random -Count $numChars))
            $list.AddRange([char[]]([char[]]'0123456789' | Get-Random -Count $numChars))
        }
        # return the randomized password
        (($list | Sort-Object {Get-Random}) -join '').Substring(0, $TotalLength)
    }
    
    $ListOfUsers = Get-Content -Path 'C:\temp\list.txt'
    $result = foreach ($user in $ListOfUsers) {
        #Generate a 9-character random password
        $Password = New-Password -TotalLength 9  # if you don't set the TotalLength it will default to 10
        #Convert the password to secure string
        $Pass = ConvertTo-SecureString $Password -AsPlainText -Force
        #Reset the account password
        Set-ADAccountPassword $user -NewPassword $Pass -Reset
    
        # output the newly set passwords as PsCustomObject to use in a csv file
        [PsCustomObject]@{User = $user; Password = $Password}
    }
    
    # show on screen
    $result | Format-Table -AutoSize
    
    # write to CSV file you can open in Excel by double-clicking it
    $result | Export-Csv -Path 'C:\temp\NewPasswords.csv' -NoTypeInformation -UseCulture