‘Sup PSHomies,
See if you can relate. You’re in the middle of a migration, the users need to be created asap. You get a xlsx file with all the necessary properties. A quick Copy/Paste to csv file, Import-Csv user.csv -Delimiter "`t" | New-ADUser
and presto! Whew! Glad we got that out of the way 😉
Feels pretty awesome right? 15 minutes after, your project manager comes asking: “Say, which file did you use?” The one you sent me last week, why? “Uh, there’s a new version on sharepoint, did you use that one?” Well I did ask which file I should use (in my defense I did, that’s why I always email, written proof!). “Well there’s an updated version, could you make sure the users get updated? Thanks!!!” Sigh, here we go again…
At this point I can do two things:
- Just delete and recreate. Thing is you’ll loose SIDs and access to homedirectory etc etc. Not exactly ideal.
- Update the user properties. Definitely a better option. Still tricky especially using the Set-ADUser cmdlet, but that’s another story.
But before you go off to update the user settings, how about validating what has been changed? Maybe the damage isn’t that bad. I mean if it’s under five changes, I just might do it manually… Oh who am I kidding? Wait, gimme a minute to catch my breathe from laughing! 😛
Enter Pester for ADUser validation!
With a Pester script to validate your ADUser settings, you’ll never have to second guess if the settings are as they should.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
Author: I.C.A. Strachan | |
Version: 1.0 | |
Version History: | |
Purpose: Pester script to validate ADUser properties. | |
#> | |
[CmdletBinding()] | |
Param( | |
[string] | |
$csvFile = 'Users.csv', | |
[Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding] | |
$Encoding = 'UTF8' | |
) | |
$csvParam = @{ | |
Path = ".\source\csv\$csvFile" | |
Delimiter = "`t" | |
Encoding = $Encoding | |
} | |
$csvADUsers = Import-Csv @csvParam | |
$ADPropertiesToVerify = ($csvADUsers | Get-Member | Where-Object {$_.membertype -eq 'noteproperty'}).name | |
Foreach ($user in $csvADUsers){ | |
#Get AD User attirbutes | |
try{ | |
$verify = Get-ADUser –Identity $user.SamAccountName –Properties * | |
if ($verify) { | |
Describe "AD User operational readiness for $($user.DisplayName)" { | |
Context 'Verifying ADUser Attributes'{ | |
ForEach($attribute in $ADPropertiesToVerify){ | |
if (([string]::isNullOrEmpty($user.$attribute))) { | |
$user.$attribute = $null | |
} | |
if($attribute -eq 'Path'){ | |
it "User is located in $($user.$attribute)" { | |
$verify.DistinguishedName.Contains($user.$attribute) | |
} | |
} | |
else{ | |
it "User property $($attribute) value is $($verify.$attribute)" { | |
$user.$attribute | Should be $verify.$attribute | |
} | |
} | |
} | |
} | |
Context 'Verifying ADUser HomeDirectory Security'{ | |
it 'User HomeDirectory attribute is not empty'{ | |
$user.HomeDirectory | Should not be $null | |
} | |
It "Homedirectory $($user.HomeDirectory) exists"{ | |
Test-Path $user.HomeDirectory | Should be $true | |
} | |
It "User is owner of $($user.HomeDirectory)"{ | |
(Get-Acl $user.HomeDirectory).Owner| Should be "$($env:USERDOMAIN)\$($user.sAMAccountName)" | |
} | |
} | |
} | |
} | |
} | |
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]{ | |
Write-Error –Message "User $($user.SamAccountName) account NOT present" | |
} | |
catch { | |
Write-Error –Message "Unhandled exception looking up $($user.SamAccountName)) account." | |
throw $_ | |
} | |
} | |
Here’s the result:
Here’s a quick rundown of the script:
First I’ll just get all the user settings using $verify = Get-ADUser -Identity $user.SamAccountName -Properties *
.
$ADPropertiesToVerify = ($csvADUsers | Get-Member | Where-Object {$_.membertype -eq 'noteproperty'}).name
will get me all the properties in the csv file. No need to map properties manually. Now I can loop through any amount of properties!
Next up, making sure empty properties get $null
if (([string]::isNullOrEmpty($user.$attribute))) { $user.$attribute = $null }
$null isn’t equal to empty (Ofcourse you already knew that!)
Now compare what’s in the csv to what Get-ADUser found:
if($attribute -eq 'Path'){ it "User is located in $($user.$attribute)" { $verify.DistinguishedName.Contains($user.$attribute) } } else{ it "User property $($attribute) value is $($verify.$attribute)" { $user.$attribute | Should be $verify.$attribute } }
Quick note: I used Path to create the user in a specific OU. There’s no Path property in Get-ADUser. So I did the next best thing, just verify that path is part of the user’s distinguishedname 😉
I also added a little bonus to verify the user’s homedirectory exists and that the user is also the owner.
Being able to validate will definitely give you peace of mind…
Hope it’s worth something to you
Ttyl,
Urv