CCDC Powershell Script For Password Changes

Problem: In the CCDC competition often the default passwords are insecure and it is good practice to immediately change all passwords on the AD server. We are then required to send a csv file with all the updated passwords for each user.

Solution: A powershell script that can run on any windows server version 2012 R2 or newer.

Requirements for script:

  1. Has to change ALL AD user passwords
  2. Generate secure passwords
  3. Create a csv file with username, and new password
  4. Must work on at least Windows Server 2012

Getting the AD accounts:

We can use Get-ADUser to create a list of users, in a specific domain.

$users = Get-ADUser -Filter * -SearchBase $domain -Properties DistinguishedName

Then to change the password we want to loop through each user.

foreach($user in $users){...}

I ran into an issue here. The $user variable contained all the information, but I could not use it directly to change the password.

Instead I had to use the DistinguishedName to reset the password. Although I could have instead used the GUID, but the DistinguishedName is easiest to read and recognize what user was changed.


Setting Account Passwords:

The command to reset a user password is Set-ADAccountPassword

foreach($user in $users)
{
    $name = $user | Select-Object -expand DistinguishedName
    Set-ADAccountPassword -Identity $name -Reset -NewPassword (ConvertTo-SecureString -AsPlainText $password -Force)
}

-Identity selects the user based on the DistinguishedName.

-Reset is the flag to reset the password.

-NewPassword signals a value for the password.


Password Generator:

I based my design on this website: https://techexpert.tips/powershell/powershell-generate-random-passwords/

First I created the different char arrays. I did one array for capital letters, lowercase letters, numbers, and special chars.

I had to change the special chars so they don’t include any of the following: “*&$/” this is to avoid issues with how windows AD interacts with linux.

$uppercase = "ABCDEFGHKLMNOPRSTUVWXYZ".tochararray() 
$lowercase = "abcdefghiklmnoprstuvwxyz".tochararray() 
$number = "0123456789".tochararray() 
$special = "%()=?}{@#+!".tochararray()

Inside the foreach loop we created earlier we are going to use the Get-Random function to select a random amount of chars from each array, and add them to the password. The smallest password possible is 11 chars which would still take years to crack with brute force. Also randomizing the size makes it harder to crack.

foreach($user in $users)
{
    #Start by generating the new count for each type of character
    #This is done to gearentee there is never a weak password
    $count = Get-Random -Minimum 2 -Maximum 10
    $password =($uppercase | Get-Random -count $count) -join ''
    $count = Get-Random -Minimum 5 -Maximum 10
    $password +=($lowercase | Get-Random -count $count) -join ''
    $count = Get-Random -Minimum 2 -Maximum 10
    $password +=($number | Get-Random -count $count) -join ''
    $count = Get-Random -Minimum 2 -Maximum 10
    $password +=($special | Get-Random -count $count) -join ''

    ...

At this point the password is complete. The issue is if you look at a password at this point it would have all the capitals first then lowercase, then numbers, and all specials last. This is probably not a huge issue, but for added security it is smart to randomize it.

    #Scramble the password so the chars are not bunched up by type
    $passArray = $password.tochararray()
    $password = ($passArray | Get-Random -Count $passArray.Count) -join ''
}

CSV File:

I started by getting the path the script was running from and storing it as a variable

$csvPasswordFile = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent

Then I added the filename and extension to the path, and turned it into a file.

$csvPasswordFile += "\UsersNewPasswords.csv"
New-Item $csvPasswordFile -ItemType File

Back inside the foreach loop, after the password is generated I use Add-content to add a new line to the csv file with an id value, name, and password.

$idValue = 0
foreach($user in $users)
{
    ...

    $csvPasswordFile ([string]$idValue + ",`"" + $name + "`"," + $password)
    $idValue += 1
}

Closing Notes:

This project was not as difficult as I anticipated. I ended up spending a significant amount of time learning how to get the directory that the script is running in, especially because it is possible that a server we need to run this on is running a much older version of powershell. Although I did not cover it in this blog I had to find out about elevating the powershell to admin if it was not started as such. The code that I found for it is a bit more complex then I really understand, but I looked it over and think I at least know what each block of code accomplishes.

If you would like to see the full script it is on my Github.

If you would like to do more reading these are the websites I used:

Get-ADUser

Export-Csv

Set-ADAccountPassword

Get-Random

ADUser Class

How to use Get-ADUser

Generate random passwords with powershell

Related Posts

One thought on “CCDC Powershell Script For Password Changes

  1. Spot on ѡith this wrіte-up, I truly beliеve
    this site needs a great deal more attention.
    I’ll probably be returning to read more, thanks for tһe information!

Leave a Reply