This script is supposed to grab users from several OUs and assign the users to one variable, then it takes the users from that variable and filters through each one based on last logon dates over 30 days of age. Then it exports to a CSV with some info I'd like.
The problem is, when I get to the foreach part, it searches through the entire directory and doesn't use the users in the variable I supplied.
Any criticism is greatly appreciated as well.
$30days = (get-date).adddays(-30)
$Users1 = Get-ADUser -SearchBase 'OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users2 = Get-ADUser -SearchBase 'OU=Users-Remote,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users3 = Get-ADUser -SearchBase 'OU=Contractors,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users4 = Get-ADUser -SearchBase 'OU=Temps,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users5 = Get-ADUser -SearchBase 'OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users6 = Get-ADUser -SearchBase 'OU=Users,OU=US-Location,OU=Americas,DC=Domain,DC=Domain,DC=com' -LdapFilter '(UserPrincipalName=*)(extensionAttribute9=*)'
$Users = $Users1,$Users2,$Users3,$Users4,$Users5,$Users6
$useraccountsover30days = foreach ($user in $($Users)){Get-ADUser -filter {lastlogondate -le $30days} -Properties lastlogondate}
$lastlogonreadable = $useraccountsover30days | Select-Object SamAccountName,lastlogondate
$lastlogonreadable | Export-Csv C:/Users/myname/Desktop/Usersover30days.csv
Best Answer
There are a few recommendations I'd make with your current script.
First off, a single large query is almost always going to perform better than many smaller queries. So rather than running
get-aduser
separately for each target OU, I would combine them into a single call using a higher level common OU as the search base. Obviously, this may end up returning results from OUs you didn't want to include. But it's much faster to filter those out later.You're also calling
get-aduser
again for each result from the first set of queries just to filter on lastLogonDate. But you could instead combine that filter with the-ldapfilter
from your original queries. It's just a matter of converting the-filter
version with an equivalent-ldapfilter
version. The secret to doing this is knowing that lastLogonDate is just a Powershell converted version of the lastLogonTimestamp attribute. And you can convert a normal Powershell DateTime value into the format that lastLogonTimestamp uses with theToFileTime()
method.The last thing that confused me was the
(UserPrincipalName=*)
portion of your ldapfilter. In every domain I've ever touched, this attribute will always have a value (just like SamAccountName or DistinguishedName). It may be different than the default value of<SamAccoutnName>@<DomainFQDN>
, but it's never empty. The filter isn't hurting anything necessarily. It's just one extra thing for AD to spend CPU cycles evaluating when it doesn't need to. But if you have reason to believe it might be empty in your environment, by all means leave it in.So here's how I'd modify your script if I understand your intentions correctly.
P.S. Be wary of treating
lastLogonTimestamp
(orlastLogonDate
) as 100% accurate. It may be anywhere from 9 to 14 days out of date by design.