Update / Change Password via PowerShell

Today the password rotation for my Service Accounts in Active Directory (AWS MS AD) is due. It is a pain to have to create dozens of random passwords, then update Active Directory, store them in AWS Secret Manager and then update all of the apps.

To cut down on the time this takes, I created two PowerShell scripts and one SQL script to handle this.

AWS Secret Manager Updater

My first script will grab all the Service Account names from last month’s update in Secret Manager. I’ll then create new passwords for them and store that as a new Secret.

Final result of what PowerShell script will create in AWS

The script assumes I am running PowerShell 5.0+ and have AWS CLI set up with PowerShell on my host.

# PasswordGeneratorSolutionForAwsSecretManager
# PowerShell 5.0
# Update Passwords in MS AD on AWS.
# Written By David Speight
# December 8, 2022
# (1) This script will retrieve a previous months Service Account list ($LastMonthSecretListID) from AWs Secret Manager
# (2) The script will create new Passwords for the users
# (3) The script will save those passwords to a new Secret Manager Secret

# Define variable:  The SECRET Name of the previous months list of usernames and passwords, new month list name, description.
$LastMonthSecretListID = "sql-202304"
$ThisMonth = (Get-Date -Format "yyyyMM").ToString()
$NewMonthDescription  = "MS AD service accounts for SQL server {0}."  -f $ThisMonth
$NewMonthSecretListID  = "sql-{0}" -f $ThisMonth

$a = aws secretsmanager get-secret-value --region us-east-1 --secret-id $LastMonthSecretListID | ConvertFrom-Json 
$c = $a.SecretString 
$c = $c.Replace("{","")
$c = $c.Replace("}","")
$c = $c.Replace("""","")

#Password Generating Function
Function GeneratePassword
{
    $FirstAlpha =  ([char[]]([char]97..[char]122) | sort {Get-Random})[0] -join ''
    $SpecialChar = ([char[]]([char]40..[char]43) | sort {Get-Random})[0..1] -join ''
    $NumChar = (0..9 | sort {Get-Random})[0..1] -join ''
    $genpass = $FirstAlpha + (([char[]]([char]65..[char]90 ) + ([char[]]([char]40..[char]43) ) + ([char[]]([char]97..[char]126)) + 0..9 | sort {Get-Random})[0..7] -join '') 
    $genpass = $genpass + $SpecialChar + (([char[]]([char]65..[char]90 ) + ([char[]]([char]40..[char]43) ) + ([char[]]([char]97..[char]126)) + 0..9 | sort {Get-Random})[0..7] -join '') 
    $genpass = $genpass + $NumChar + (([char[]]([char]65..[char]90 ) + ([char[]]([char]40..[char]43) ) + ([char[]]([char]97..[char]126)) + 0..9 | sort {Get-Random})[0..7] -join '') 

    Write-Output $genpass
}


#Create New SECRET in AWS Secret Manager
$SecretJson = ""
$Addcomma = "N"

$d = $c.Split(",")
foreach ($item in $d) {
    $i = $item.IndexOf(":")
    
    # Call Generate Password Function
    $Password = GeneratePassword  

    #Add a comma at start of new line except on first iteration.
    if ($Addcomma -eq 'Y')
    {
        $SecretJson = $SecretJson + ','    
    }
    #Add Pair to Secret Manager json
    $SecretJson = $SecretJson + '\"' + $item.SubString(0,$i) + '\":\"' + $Password + '\"'
    $Addcomma = "Y"
}

#  Final format:      "{\"MyUser1\":\"MyPassword1\",\"MyUser2\":\"MyPassword2\"}"
$SecretJson = '{' +  $SecretJson + '}' 
Write-output $SecretJson

#COMMENT THIS LINE TO TEST and NOT  WRITE TO AWS
aws secretsmanager create-secret --name $NewMonthSecretListID --description $NewMonthDescription --secret-string $SecretJson

Next I log into the AWS Console and verify that the new SECRET has been created.

Active Directory Updater

Typically I give the developers a few days to obtain the new passwords before I actually run the update on Microsoft Active Directory. As you can see, the above script is dated four (4) days ago. So I am now going to run this next script to complete the AD update.

This script will retrieve the username and password for each of my Service Accounts, and update MSAD. The script also allows me to strip the prefix from a key value in the Secret. For example user MyDomain\Dave can be stripped down to just Dave. In the script I have to add an extra escape character that comes along with the json code. So I will strip “MyDomain\” away by entering “MyDomain\\” instead.

# PowerShell 5.0
# Update Passwords in MS AD on AWS.
# Written By David Speight
# December 12, 2022
# This script will change the user names in Active directory

# Start Script A:  The SECRET Name of the previous months list of usernames and passwords
$ThisMonth = (Get-Date -Format "yyyyMM").ToString()
$SecretListID = "sql-{0}" -f $ThisMonth
$DomainPrefixClean = "MyDomain\\"

$a = aws secretsmanager get-secret-value --region us-east-1 --secret-id $SecretListID | ConvertFrom-Json 
$c = $a.SecretString 
$c = $c.Replace("{","")
$c = $c.Replace("}","")
$c = $c.Replace("""","")



$d = $c.Split(",")
foreach ($item in $d) {
    $i = $item.IndexOf(":")
    $u = $item.SubString(0,$i)
    $u = $u.Replace($DomainPrefixClean,"")

    $user = $u
    $Password =  $item.SubString(($i + 1),($item.length - $i- 1))

    #Convert the password to secure string and pass to AD.
    $NewPwd = ConvertTo-SecureString $Password -AsPlainText -Force
    Set-ADAccountPassword $user -NewPassword $NewPwd -Reset
    Write-Host  $user, $Password
    $user = ""
    $Password = ""
}

Write-Host 
Write-Host "-----------------------------------"
Write-Host "------AUTH TEST ---------"
Write-Host "-----------------------------------"
Write-Host 

# AUTENTICATION TEST: This will query AD and verify the password was changed.
Function Test-ADAuthentication {
 param(
 $username,
 $password)
 
(New-Object DirectoryServices.DirectoryEntry "",$username,$password).psbase.name -ne $null
}


$d = $c.Split(",")
foreach ($item in $d) {
    $i = $item.IndexOf(":")
    $u = $item.SubString(0,$i)
    $u = $u.Replace($DomainPrefixClean,"")

    $UserName = $u
    $Password =  $item.SubString(($i + 1),($item.length - $i- 1))
    #Convert the password to secure string and pass to AD.
    Get-ADUser -Identity $UserName -properties PwdLastSet,PasswordLastSet  | sort Name | ft Name,@{Name='PwdLastSet';Expression={[DateTime]::FromFileTime($_.PwdLastSet)}},PasswordLastSet
    Test-ADAuthentication -username $UserName -password $password
    Write-Host "-----------------------------------"
    $UserName = ""
    $Password = ""
}


The results panel will skip over any users not found. I like this, since I also store SQL Logins in the same monthly file with my Domain users.

Example ERROR OUTPUT of a missing MSADusername
Example OUPUT from Authentication Test section.

SQL Server Password Update

Lastly, this is the code I use to post the update for SQL Server User accounts. This one is manual.

USE [master];
ALTER LOGIN [ssis_user] WITH PASSWORD=N'MyNewPassword';
ALTER LOGIN [ssrs_user] WITH PASSWORD=N'MyNewPassword';