This is one of those scripts that come about when my boss walks into my office…

Boss: “Can powershell…”


He doesn’t even need to finish his sentence because I know powershell can do it. That doesn’t mean I will immediately know how to accomplish it with powershell, but Oh Yes, It will be done.

Anyway this time he wanted to give the script an OU in powershell, and have it spit back specific details of users in that OU. These specifics mainly had to do with Expiration Dates.

On to the script

param([string]$local=$(Read-Host "What OU Path?"), [string]$file="")
$ErrorActionPreference = "silentlycontinue"



while($i -le ($location.length-1))

$users=get-aduser -property * -filter * -searchbase $path -searchscope 1

ForEach($user in $users){
$userprops=""|select-object -property $userdetails
$userprops.passwordexpires= ($user.passwordlastset + (Get-ADDefaultDomainPasswordPolicy).maxpasswordage).toshortdatestring()
IF($file -eq ""){$out|sort -property username| FT * -auto}
Else{$out|export-csv $file }


Parameters: The $local parameter is setup to take input in the form of OU location, and it takes that info as you might type a path in windows. The $file parameter will take a file name “./userdeets.csv” and export the info to a csv, otherwise it will just display it in the PowerShell Window

I do an ErrorActionPreference of “silentlycontinue” because the only error I would really get is when it would try reformat the dates, when the dates were $null, in other words when it tried to do a method on a $null date it was throwing errors. As that was the only error I ever got with this I just decided to silently continue. If you have a better way to do error handling on methods let me know. I just thought the try and catch for two lines that rarely error otherwise wasn’t worth it.

Lines 10-15 You may recognize from my previous post. This section is the reason the script is able to take an OU path like “ToplevelOU/MiddleOU/OUyouwant” and translate into what powershell expects for the get-aduser cmdlet. For more details on my translation check out my other post

Line 17 This is where we grab all of our User details from AD. -searchscope 1 confines the get to the immediate children of the OU you specify. There are other settings for searchscope that allow it to the base 0, and all sub-OUs  2.

Line 25 Looking at it now I should have just assigned Get-ADDefaultDomainPasswordPolicy to a variable and just referenced that variable here….Oh well.

I would post a results of it in my own domain(at work), but I would have to pretty much edit out most of the columns…

Anyway let me know what you think, and if you want to take a screen of the results and don’t mind me posting it Let Me Know!!

Categories: Powershell


Jeffery Hicks · January 5, 2012 at 1:20 pm

Good work, but as usual I have some questions and suggestions. Avoid setting ErrorActionPreference to SilentlyContinue. You should be able to handle any errors or test for preconditions, such as verifying the AD module is loaded.

I would put the Path as a parameter. Go ahead and set a default. This makes your code more flexible for others to use.

Why are you formatting date times to strings? Leave them as date time objects so you can sort on them properly.

Finally, I would take out the Export-CSV line anf Format-Table commands., Just have your script write the custom object to the pipeline. This too gives you more flexibility.

.\get-myusers | export-csv myusers.csv
.\get-myusers | sort AccountExpires | format-table | out-file report.txt

C-Rad · January 5, 2012 at 9:18 am

Thanks again for the great comment again. I definitely agree adding the $path as a param would make it more flexible and I will do that.

The reason I used the method on the dates was because in the columns as the default date object it also had the time with it as well which was making those two columns much larger than they needed to be, since for an account or password expiration anyone only cares about the date, not time. Do you have any other suggestion as to how I could get around that? I did not think those dates had the nice -format as get-date does….

When I create these it is for a very specific purpose or audience(like my boss), however when I post them here I should start making them more accessable to the general public.

Jeffery Hicks · January 5, 2012 at 10:12 am

Even though you are creating to meet a need, don’t code yourself into a corner. Think re-use and flexibility from the very beginning. As the for date issue, I would keep the original date time object value. When you run the script then you can tweak the output to only give you the part of the date you want using a hash table with Select-Object or one of the format cmdlets.

vNoob » Getting Full NTBackup info with schtasks and Powershell · February 2, 2012 at 3:32 pm

[…] going after in the first place. Also following the Masterful Jeff Hicks’s tip from a previous post. I specifically left this one to be more generic so it would be immediately useable to more […]

Leave a Reply