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 = ("guest@domain.local")
$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 = guest@domain.local, but when I add another account like

$ENV:Excluded = ("guest@domain.local", "test@domain.local")

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 = "guest@domain.local", "test@domain.local"
    $ENV:Excluded
    # Outputs: guest@domain.local test@domain.local
    

    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 = "guest@domain.local", "test@domain.local" -join ';'
    $usersToExclude = $ENV:Excluded.Split(';')
    

    Also your, Where-Object filter has many issues, some of them are:

    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 = 'guest@domain.local', 'test@domain.local' -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=*)
    #   (!userPrincipalName=guest@domain.local)
    #   (!userPrincipalName=test@domain.local)
    # )
    
    $properties = 'UserPrincipalName', 'Enabled', 'WhenCreated', 'LastLogonDate'
    $OldUsers = Get-ADuser -LDAPFilter $filter -Properties $properties |
        Select-Object $properties