Need help with logic for AD Powershell Audit <30 / 30-60 / >90 days inactive users

Posted on 2013-12-03
Last Modified: 2013-12-05
So I have this script I've been playing with... the goal is to do some basic AD auditing.  I'm using both Microsoft AD cmd-lets and the Quest cmd-lets (I find both have their place).

What I really need to make sure of is my logic for finding users that are inactive for 30 days, then inactive form 30-60 days, then inactive over 90 days.

The script will output:

- New accounts created in last seven days
- Groups modified in last seven days
- 30/30-60/90 and over inactive users
- Report user accounts that have never logged on to their account
- Send an email

Yeah, I know the attach as a text file is somewhat kludgy, but it works for these purposes.

Can someone take a look at the <30 / 30-60 / >90 logic strings and tell me what would work better, I'm not sure my results are accurate or my logic is correct.

# Prepare loading required modules

import-module activedirectory
Add-PSSnapin Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue

# Prepare and output file for mailing

$OutputfilePath = "C:\ADUserAudit-"+([datetime]::Now).tostring("yyyyMMdd")+".txt"

# Accounts created this week

$When = ((Get-Date).AddDays(-7)).Date
$UsersCreatedLastWeek = (Get-ADUser -Filter {whenCreated -ge $When} -Properties whenCreated) | select samaccountname,name,distinguishedname
$UsersCreatedLastWeekTable = ($UsersCreatedLastWeek | format-table) 

# Groups Modified this week

$When = ((Get-Date).AddDays(-7)).Date
$GroupsModifiedLastWeek = (Get-ADGroup -Filter {whenChanged -ge $When} -Properties whenChanged) | select samaccountname,name,distinguishedname 
$GroupsModifiedLastWeekTable =  ($GroupsModifiedLastWeek | format-table)

# List all users in that have not logged on within 
# XXX days in "Active Directory" 
# Get the Current Date 
# Number of Days to check back.   
# Organizational Units to search 

$OUList = "OU=Users,OU=company,DC=com","OU=Users2,OU=company,DC=com"

# Prepare arrays for totals

$30Days = @()
$60Days = @()
$90Days = @()

ForEach ($OU in $OUList) 

    #LastLogon.AddDays() adds x number of days making the users lastlogon x number of days into the future (e.g. Sep 28th somes October 27th...)

    $30Days += (GET-QADUSER -SearchRoot $OU | where { $_.LastLogon.AddDays(30) -lt $CURRENTDATE}) | select samaccountname,Name,DN

    $60Days += (GET-QADUSER -SearchRoot $OU | where { ($_.LastLogon.AddDays(60) -lt $CURRENTDATE -and $_.LastLogon.AddDays(60) -lt ($CURRENTDATE.AddDays(-30))) }) | select samaccountname,Name,DN

    $90Days += (GET-QADUSER -SearchRoot $OU | where { ($_.LastLogon.AddDays(90) -lt $CURRENTDATE -and $_.LastLogon.AddDays(90) -lt ($CURRENTDATE.AddDays(-30))) }) | select samaccountname,Name,DN

$30DaysTable = ($30Days | format-table)
$60DaysTable = ($60Days | format-table)
$90DaysTable = ($90Days | format-table)

# Get users that have never logged in, but use Windows AD Powershell cmdlets as it should look at all domain controllers. Not restricted to OU:

$NeverBeenKissed = get-aduser -f {-not ( lastlogontimestamp -like "*") -and (enabled -eq $true)} | select samaccountname,name,distinguishedname

$NeverBeenKissedTable = $NeverBeenKissed | format-table
# Write to a file

Out-File $OutputfilePath

Add-Content -Path $OutputfilePath "Users Created in the Last Week:"
Add-Content -Path $OutputfilePath " "
$UsersCreatedLastWeekTable | Out-File $OutputfilePath -append
Add-Content -Path $OutputfilePath "Groups Modified in the Last Week:"
Add-Content -Path $OutputfilePath " "
$GroupsModifiedLastWeekTable | Out-File $OutputfilePath -append
Add-Content -Path $OutputfilePath "Users not logged in for 30 days:"
Add-Content -Path $OutputfilePath " "
$30DaysTable | Out-File $OutputfilePath -append
Add-Content -Path $OutputfilePath "Users not logged in for 60-90 days:"
Add-Content -Path $OutputfilePath " "
$60DaysTable | Out-File $OutputfilePath -append
Add-Content -Path $OutputfilePath "Users not logged in for over 90 days:"
Add-Content -Path $OutputfilePath " "
$90DaysTable | Out-File $OutputfilePath -append
Add-Content -Path $OutputfilePath "Users who have NEVER logged in!:"
Add-Content -Path $OutputfilePath " "
$NeverBeenKissedTable | Out-File $OutputfilePath -append

# Send it in email as an attachment, since it's not as simple to port it into an email yet.

$smtpServer = “”

Send-MailMessage -To "” -Subject “AD User Audit 30/60/90” -From “” -Body “Current AD User Audit is attached.” -Priority High -SmtpServer $smtpServer -Attachments $OutputfilePath

Open in new window

Question by:gerhardub
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
LVL 40

Expert Comment

ID: 39694056
You can try with Search-ADAccount to search the inactive accounts.. for example..

$30  = Search-ADAccount -UsersOnly -AccountInactive -TimeSpan 30
$3060 = Search-ADAccount -UsersOnly -AccountInactive -TimeSpan 60 | ?{($30 | Select -ExpandProperty Samaccountname) -notcontains $_.Samaccountname}
$90 = Search-ADAccount -UsersOnly -AccountInactive -TimeSpan 90

Open in new window

LVL 40

Accepted Solution

footech earned 500 total points
ID: 39694175
What I really need to make sure of is my logic for finding users that are inactive for 30 days, then inactive form 30-60 days, then inactive over 90 days
This says to me - find the users;
 - who haven't logged in in the last 30 days, so last logon date must be greater than 30
 - whose last logon was between 30 and 60 days ago
 - whose last logon was greater than 90 days ago

The first two are pretty much the same, the second just has an additional limit placed on it.  And what about last logon between 60 and 90 days ago?

Your script logic is pretty convoluted (and a little different than my understanding of what you want).  The first will get users whose last logon was greater then 30 days ago.  The second will get users whose last logon was between 30 and 60 days ago.  The third will get users whose last logon was between 30 (I think you meant 60 here) and 90 days ago.

In addition to Search-ADAccount you could also do something like the following:
$lt30 = @()
$30Days = @()
$60Days = @()
$90Days = @()

$now = Get-Date
ForEach ($OU in $OUList) 
        Get-ADUser -filter * -Properties LastLogonDate -SearchBase $OU | ForEach `
        If ( $_.LastLogonDate -gt $now.AddDays(-30) )
        { $lt30 += $_ | Select samaccountname,Name,DistinguishedName }
        ElseIf ( $_.LastLogonDate -lt $now.AddDays(-30) -and $_.LastLogonDate -gt $now.AddDays(-60) )
        { #another way to do the same thing
          $30Days += New-Object PsObject -Property @{ samaccountname = $_.samaccountname; Name = $; DN = $_.DistinguishedName }
        ElseIf ( $_.LastLogonDate -lt $now.AddDays(-60) -and $_.LastLogonDate -gt $now.AddDays(-90) )
        { $60Days += $_ | Select samaccountname,Name,DistinguishedName }
        ElseIf ( $_.LastLogonDate -lt $now.AddDays(-90) )
        { $90Days += $_ | Select samaccountname,Name,DistinguishedName }

Open in new window


Author Comment

ID: 39694411
Folks ,

You rock.... Let me plug these in and play in the AM... I'll get back to you tomorrow!
Salesforce Has Never Been Easier

Improve and reinforce salesforce training & adoption using WalkMe's digital adoption platform. Start saving on costly employee training by creating fast intuitive Walk-Thrus for Salesforce. Claim your Free Account Now


Author Comment

ID: 39695312
Interestingly, the Search-ADAccount cmdlet gave me false results.  It was odd... $30 and $90 were exactly the same, $60 had zero results.... which makes sense in hindsight.

FooTech: Your understanding of what I really needed worked great.  The arrays literally break out the users from time as I needed, and then allowed me to break it out in a text based report that ended with 7/7/30/60/90 and "never been kissed." -grin-

Thanks for that... you've just saved me a ton of time, and I learned something from both of you.  I need to brush up on my Powershell logic... and revisit the cmdlets.

I'll open another ticket if either of your want 500 points toward figuring out how to format it in HTML and send that in an email! Let me know!


Author Closing Comment

ID: 39695317
Fantastic level of help... I can't thank you enough... and I'm a hardass.
LVL 40

Expert Comment

ID: 39699387
Glad I could help.

One thing to keep in mind if you want to explore the use of Search-ADAccount, when specifying a timespan to indicate days you should enclose the number in quotes.  So
Search-ADAccount -UsersOnly -AccountInactive -TimeSpan 30
would have a timespan of 30 ticks, and
Search-ADAccount -UsersOnly -AccountInactive -TimeSpan "30"
would have a timespan of 30 days.  You could also write it like
Search-ADAccount -UsersOnly -AccountInactive -TimeSpan 30.0:0
When written like this the quotes are optional.

Featured Post

Are your AD admin tools letting you down?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Here's a look at newsworthy articles and community happenings during the last month.
Let's recap what we learned from yesterday's Skyport Systems webinar.
This tutorial will walk an individual through the steps necessary to enable the VMware\Hyper-V licensed feature of Backup Exec 2012. In addition, how to add a VMware server and configure a backup job. The first step is to acquire the necessary licen…
This Micro Tutorial hows how you can integrate  Mac OSX to a Windows Active Directory Domain. Apple has made it easy to allow users to bind their macs to a windows domain with relative ease. The following video show how to bind OSX Mavericks to …
Suggested Courses

617 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question