New-QADUser Setting Password Issue

Hey,

I need to create a large number of generic user accounts.

I created a really simple PowerShell script that does the following

  • Generates a random password.
  • Stores this password in our password manager by user.
  • Creates a new user account using New-QADUser.

When I was testing this by just creating a single account, outside of any sort of loop, it worked perfectly.

When I tried the same logic inside of a loop, everything works the same except for one step. The password in ARS/AD is wrong.

I use the following command to create the new user:

# Connect to ARS
$pw = read-host "Enter password" -AsSecureString

Try
{
    Connect-QADService -service '<ARS Servere>' -proxy -ConnectionAccount '<User Name>' -ConnectionPassword $pw | Out-Null
}
Catch
{
    Write-Host "Learn how to type your password correctly"
    Break
}

# Import our password generation script to be used to generate paswords
Import-Module -DisableNameChecking <Password Generation Script>

# Import the list of work centers
$wcNumbers = Import-Csv -Path '<Path to User Details CSV>\wc_numbers.csv'

# Assign ticket associated to the creation of all of these accounts.
$ticket = "134986"

# Prepare for log collection
$logCollection = @()

# Function used to store password in password PasswordState
function storePassword
{
   # - This function accepts two parameters
       # - Title = Title of password in PasswordState
       # - Name = User name
       
    param
    (
        [Parameter(Mandatory = $false)]
        [string]$title,
        [string]$uName,
        [string]$pwd
    )

    $pwd = Create-Password
    
    # PowerShell Request

    #JSON data for the object
    $jsonData = '
    {
        "PasswordListID":"<blank>",
        "Title":"' + $title + '",
        "UserName":"' + $uName + '",
        "Description":"<blank>",
        "ADDomainNetBIOS":"<blank>",
        "AccountType":"<blank>",
        "password":"' + $pwd + '",
        "APIKey":"<blank>"
    }
    '
    $passwordServiceUrl = '<blank>'
    $global:result = $null

    try
    {
        $global:result = Invoke-Restmethod -Method Post -Uri $passwordServiceUrl -ContentType "application/json" -Body $jsonData
        Write-Host $result
    }
    catch
    {
        $errorMessage = $_.Exception.Message
        if (Get-Member -InputObject $_.Exception -Name 'Response') {
            try {
                $result = $_.Exception.Response.GetResponseStream()
                $reader = New-Object System.IO.StreamReader($result)
                $reader.BaseStream.Position = 0
                $reader.DiscardBufferedData()
                $responseBody = $reader.ReadToEnd();
            } catch {
                throw "An error occurred while calling REST method at: $url. Error: $errorMessage. Cannot get more information."
                break
            }
        }
        throw "An error occurred while calling REST method at: $url. Error: $errorMessage. Response body: $responseBody"
        break
     }

}

# Begin loop for work centers
ForEach ( $wc in $wcNumbers )
{

# Uncomment to test single account
#If ( $wc.WC_Number -eq "53" ) 
#{
    
    # Figure out the location of the work center
    switch ( $wc.Location )
    {
        "location1"  { $wcLocation = "local1" }
        "location2" { $wcLocation = "local2" }
        "location3"   { $wcLocation = "local3" }    
    }

    # Generate account attributes
    $wcNewUserFirstName = ("Wc" + $wc.WC_Number + $wcLocation)
    $wcNewUserLastName = "User"
    $wcNewUserSamAccountName = $wcNewUserFirstName.ToLower() + "." + $wcNewUserLastName.ToLower()

    # Write something to terminal. Only for seeing progress.
    Write-Host "Working on $wcNewUserSamAccountName"
    
    # Generate unique password
    $pwd = Create-Password 
    
    # Store password and user in PasswordState
    storePassword -title "$wcNewUserFirstName $wcNewUserLastName" -uName "$wcNewUserSamAccountName" -pwd "$pwd"

    # Prepare parameters for the new user account creation
    $newQADUser = @{
        ParentContainer = "OU=someOU,DC=local,DC=domain"
        Name = "$firstname $lastname"
        userprincipalname = "$userprincipalname"
        UserPassword = "$pwd"
        Email = "$userSamAccountName@yourdomain.com"
        SamAccountName = "$userSamAccount"
        DisplayName = "$firstname $lastname"
        Description = "Ticket #$ticket"
        FirstName = "$firstname"
        LastName = "$lastname"
    }
        
    # Create user in ARS/AD
    New-QADUser @newQADUser
    Set-QADUser -Identity "$wcNewUserSamAccountName" -PasswordNeverExpires $TRUE
    
    # Collect some simple details about the process and dump to a CSV.
    $object = New-Object PSObject
    $object | Add-Member -MemberType NoteProperty -Name "User Name" -Value "$wcNewUserFirstName $wcNewUserLastName"
    $object | Add-Member -MemberType NoteProperty -Name "Work Center" -Value $wc.WC_Number
    $object | Add-Member -MemberType NoteProperty -Name "Location" -Value $wc.Location
    $logCollection += $object
#} Uncomment to test single account 
}

# Write to log file
$LogCollection | Export-Csv "<Path to log>\Accounts Created.csv" -NoTypeInformation

# Disconnect from ARS
Disconnect-QADService

The loop I have basically just brings in the information for the user accounts, and then loops through each user executing the code above. There is more to the script that isn't shown here, but it all works as intended. The user gets created in ARS/AD, but the password doesn't get set properly in ARS/AD.

If I take this same code, and hardcode the values, and execute it, the password is set properly.

The script doesn't output any errors and I know that the passwords that are being generated meet our password policies.

Any ideas on what I can do to try and understand why the password doesn't get set properly when this code exists in a loop?

Regards,

Todd

Parents
  • Hi  

    I'm not 100% sure why your code isn't working, I tried your code as listed above but didn't work for me at all.

    If you're call the create from a function, and just parsing in the list of objects (say from a CSV), the below would remove the need for a hash table.

    IE:

      
      
      Function Create-User
      {
        Param
        (
            $Users= $null,
            $ticket=$null
        )
    
    
        If($Users)
        {
            ForEach($User in $Users)
            {
    
                $PWD = "$(New-RandomPassword -MinimumPasswordLength 10 -MaximumPasswordLength 15 -NumberOfAlphaNumericCharacters 6)"
                
                $NewUser = New-QADUser `
                            -ParentContainer $($User.Parent) `
                            -Name "$($User.FirstName) $($User.LastName) ($($User.samAccountName))" `
                            -FirstName "$($User.FirstName)"`
                            -LastName "$($User.LastName)" `
                            -DisplayName "$($User.FirstName) $($User.LastName)" `
                            -Description "Ticket #$($ticket)" `
                            -UserPrincipalName  "$($User.userPrincipalName)" `
                            -email "$($User.samAccountName)@$($User.domain)" `
                            -SamAccountName "$($User.samAccountName)" `
                            -UserPassword "$pwd"
    
                Write-Host "New User Create - $($NewUser.name) - with password $Pwd"
            }
        }
    }
    
    function New-RandomPassword {
        param(
            [Parameter()]
            [int]$MinimumPasswordLength = 5,
            [Parameter()]
            [int]$MaximumPasswordLength = 10,
            [Parameter()]
            [int]$NumberOfAlphaNumericCharacters = 5,
            [Parameter()]
            [switch]$ConvertToSecureString
        )
        
        Add-Type -AssemblyName 'System.Web'
        $length = Get-Random -Minimum $MinimumPasswordLength -Maximum $MaximumPasswordLength
        $password = [System.Web.Security.Membership]::GeneratePassword($length,$NumberOfAlphaNumericCharacters)
        if ($ConvertToSecureString.IsPresent) {
            ConvertTo-SecureString -String $password -AsPlainText -Force
        } else {
            $password
        }
    }
    
    $Users = Import-csv -Path "$($env:USERPROFILE)\Desktop\Users.csv"
    
    Create-User -Users $Users -ticket "123"

    NB: The password generation function comes from How to Create a Random Password Generator (adamtheautomator.com)

    This gives me the below output, naturally you'd need to change the code to output the data however you need.

    Please note however, by adding the -Proxy to the New-QADUser commandlet you may find more details. For instance with mine, running in bulk, most request succeed, but if for some reason it doesn't like the password (AD) an error is generated

    However without the proxy in this instance, I get a similar looking error message

  • Hi  ,

    I have updated my original post to include all of my original code except the password generation code.

    I normally don't do this as I am not an expert in scripting PowerShell. I am sure you find many inefficiencies in my code.

    That is interesting that my code doesn't work for you at all.

    The code you provided is far better laid out then mine. I pieced mine together from a bunch of other code from other scripts.

    Does your revised code work for you?

    Regards,

    Todd

  • Hi   

    I've had a look at the updated code, it look good.

    The only potential issue (without trying to run it), Within the storePassword function, the first thing you do is change the parameter variable for $pwd by callinging Create-Password

    However, within your code to create each user, your a generating a password, then parsing that to the storePassword method

    However as the password you've set in storePassword is not parsed back to the calling command, you now have two variables called $pwd (One in the StorePassword function, and the one in your main code), therefore the password you're setting against AD is not the one you've stored somewhere.

    I'd try commenting out the create-password line in storePassword and give it another try.

    Hope this helps.

    Stu

Reply
  • Hi   

    I've had a look at the updated code, it look good.

    The only potential issue (without trying to run it), Within the storePassword function, the first thing you do is change the parameter variable for $pwd by callinging Create-Password

    However, within your code to create each user, your a generating a password, then parsing that to the storePassword method

    However as the password you've set in storePassword is not parsed back to the calling command, you now have two variables called $pwd (One in the StorePassword function, and the one in your main code), therefore the password you're setting against AD is not the one you've stored somewhere.

    I'd try commenting out the create-password line in storePassword and give it another try.

    Hope this helps.

    Stu

Children
No Data