Search code examples
powershellactive-directory

Get-ADUser -Filter using Variable Array


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?


Solution

  • 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.
    • Then that expression is followed by a -notmatch, which should be a logical operator -and / -or instead.
    • And lastly, the comparison explained at the top which can never be 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