I am trying to modify a PowerShell script found here:
https://www.cyberdrain.com/monitoring-with-powershell-wan-ip-changes-and-active-directory-ages/
Ideally, I would like the script to return user accounts that haven't been logged into for $ENV:UserAge
while also filtering out user accounts I know do not need to be included in the results.
$ENV:UserAge = 90
$ENV:Excluded = ("[email protected]")
$age = (get-date).AddDays(-$ENV:UserAge)
$OldUsers = Get-ADuser -Filter * -properties UserPrincipalName, Enabled, WhenCreated, LastLogonDate |
select UserPrincipalName, Enabled, WhenCreated, LastLogonDate |
Where-Object { ($_.LastLogonDate -lt $age -and $_.LastLogonDate -gt $null) -and ($_.Enabled -eq $True) -and ($_.UserPrincipalName -gt $Null) -notmatch ($_.UserPrincipalName -in $Env:Excluded ) }
This will filter out a user with UserPrincipalName = [email protected]
, but when I add another account like
$ENV:Excluded = ("[email protected]", "[email protected]")
this returns a result including both of the intended excluded accounts.
Any suggestions for being able to exclude multiple strings under the $ENV:Excluded
variable?
An environmental variable can only be of type string, by assigning an array to an env:
variable what you end up is with a string joined by $OFS
(by default, a space ' '
) and you can clearly see this if you try:
$ENV:Excluded = "[email protected]", "[email protected]"
$ENV:Excluded
# Outputs: [email protected] [email protected]
So, you either don't use env:
and use a normal variable, or pick a delimiter for your env:
variable that you can later Split()
on, for example, semi-colon:
$ENV:Excluded = "[email protected]", "[email protected]" -join ';'
$usersToExclude = $ENV:Excluded.Split(';')
Also your, Where-Object
filter has many issues, some of them are:
($_.UserPrincipalName -gt $Null)
- Using -gt
is incorrect here, if you want to get user's where that attribute populated you can simply do -and ($_.UserPrincipalName) ...
. PowerShell's boolean coercion already ensures you will get a non-null value.-notmatch
, which should be a logical operator -and
/ -or
instead.true
since you have every UPN joined by a space: ($_.UserPrincipalName -in $Env:Excluded)
. You can use ($_.UserPrincipalName -notin $usersToExclude)
if going the env:
route explained above and after splitting on ;
.Needless to say, all of this could've been filtering using the AD Filter, either -Filter
or -LDAPFilter
and removing Where-Object
:
$ENV:UserAge = 90
# assuming you need to use `env:` var here
$ENV:Excluded = '[email protected]', '[email protected]' -join ';'
# creates clauses to exclude the users from the array
$usersToExclude = $ENV:Excluded.Split(';') |
ForEach-Object { '(!userPrincipalName={0})' -f $_ }
$age = [datetime]::UtcNow.AddDays(-$ENV:UserAge).ToFileTimeUtc()
$filter = -join @(
# AND, all clauses must be met
'(&'
# lastLogonTimestamp lower than $age
'(!lastLogonTimestamp>={0})' -f $age
# enabled users only
'(!userAccountControl:1.2.840.113556.1.4.803:=2)'
# userPrincipalName is not null
'(userPrincipalName=*)'
# the users userPrincipalName does not match either of these
-join $usersToExclude
')'
)
# The LDAP filter created by the above logic would look like this:
#
# (&
# (!lastLogonTimestamp>=133748049844796588)
# (!userAccountControl:1.2.840.113556.1.4.803:=2)
# (userPrincipalName=*)
# ([email protected])
# ([email protected])
# )
$properties = 'UserPrincipalName', 'Enabled', 'WhenCreated', 'LastLogonDate'
$OldUsers = Get-ADuser -LDAPFilter $filter -Properties $properties |
Select-Object $properties