1

I am working on a Powershell script (with a GUI) to help my colleagues easier find redundant and disabled AD accounts.

Here is a little preview...

$props = "Name, Enabled, PasswordExpired, Company,passwordNeverExpires, Office"

$propsAsArray = $props -split ',\s*'

Get-ADUser -filter * -properties $propsAsArray | where {$_.Enabled -eq $true} | where {$_.PasswordNeverExpires -eq $false}| where {$_.passwordexpired -eq $false} | Select-Object $propsAsArray | Export-csv -Path "C:\report.csv"

This all works fine and outputs a CSV report.

The snag though is how to assign all the possible combinations and permutations of AD account status to a variable and later substitute in the variable into the Get-ADUser cmdlet (depending on which radio button the user clicks in the GUI).

I've tried all can think of but only ever get back the error Expressions are only allowed as the first element of a pipeline.

I'm sure that $accountStatus = "where {$_.Enabled -eq $true} | where {$_.PasswordNeverExpires -eq $false}" (or subtle variants) are not how it is done.

I'm relatively new to Powershell and am eager to get experience. Thanks, William.

4
  • 2
    It is actually not the best idea to query All users from your AD each time you run such a query and filter them afterwards with several Where-Objects. Better would be to create the appropriate filter strings to use with the paramter -Filter as this puts less stress to your AD. ;-) Commented Mar 14, 2021 at 17:52
  • Thanks for tip. The final version of the script will use the 'SearchBase' parameter to reduce the load on the DC(s). I'd gladly the -Filter parameter to find users whose passwords have expired but it looks like that is not possible. My research suggests that 'PasswordExpired' is a method and not a standard property and thus cannot be filtered. The 'chained' where statements are the only workaround that seems to work. Commented Mar 14, 2021 at 17:57
  • My code is based on the final suggested solution over at serverfault.com/questions/723217/…. My main concern is how to get the chained 'Where-Object" statements into a variable that i can substitute into the "Get-ADUser" cmdlet. Thanks. Commented Mar 14, 2021 at 18:07
  • @WilliamLombard - i suspect that i am misunderstanding your Question ... but the W-O scriptblock can be just like any other scriptblock. put each test in ONE scriptblock with the appropriate -and or -or operators. Commented Mar 14, 2021 at 18:08

2 Answers 2

4

Note: This answer addresses the question as asked, using a generalized Where-Object-based solution based on script blocks ({ ... }), but in the case at hand a string-based solution based on Get-ADUser's -Filter parameter, which efficiently filters at the source, as shown in the second command in Thomas' answer, is preferable.


Store an array of script blocks ({ ... }) representing the conditionals in a variable, and use an array of indices to select which conditionals to apply situationally, based on the user's GUI selections:

# All individual conditions to test, expressed as an array of script blocks.
# Note: No need for `-eq $true` to test Boolean properties, and
#       `-eq $false` is better expressed via the `-not` operator.
$blocks = 
  { $_.Enabled },
  { -not $_.PasswordNeverExpires },
  { $_.PasswordExpired }


# Select the subset of conditions to apply using AND logic, using 
# an array of indices, based on the GUI selections.
$indices = 0..2   # e.g., all 3 conditions (same as: 0, 1, 2)

Get-ADUser -Filter * -properties $propsAsArray | Where-Object { 
  # The following is equivalent to combining the conditionals of interest
  # with -and (AND logic):
  foreach ($block in $blocks[$indices]) { # Loop over selected conditionals
    if (-not (& $block)) { return $false } # Test, and return $false instantly if it fails.
  }
  $true # Getting here means that all conditions were met.
}

Note how each block is executed via &, the call operator.

Sign up to request clarification or add additional context in comments.

Comments

3

You can condense your multiple Where-Object calls by concatenating each condition with and:

Get-ADUser -Filter * -Properties $propsAsArray | Where-Object {(($_.Enabled -eq $true) -and ($_.PasswordNeverExpires -eq $false)) -and ($_.passwordexpired -eq $false)} | Select-Object $propsAsArray | Export-csv -Path "C:\report.csv"

But as Olaf already pointed out in the comments, it is even better to already use the -Filter parameter of Get-ADUser. There, you can use a similar combination of your conditions:

Get-ADUser -Filter {((Enabled -eq $true) -and (PasswordNeverExpires -eq $true)) -and (passwordexpired -eq $false)} -Properties $propsAsArray | Select-Object $propsAsArray | Export-csv -Path "C:\report.csv"

4 Comments

Thanks, but how can I assign the chained "Where-Object" statements to a variable that can then later be substituted back into "Get-ADUser" cmdlet (to then produce a report)?. There are going to many variants depending on whether or not the account is still enabled but the password has expired etc etc.
Thanks, I've just given that a very quick try and it's not throw back any errors. Legend! :-)
You can store each radio button setting in a variable and insert them instead of $true or $false. E. g.: ((Enabled -eq $rbEnabled) -and (PasswordNeverExpires -eq $rbPasswordNeverExpires)) -and (passwordexpired -eq $rbpasswordexpired)
Nice, but as an aside: While seductively convenient, the use of script blocks ({ ... }) as -Filter arguments is conceptually problematic and can lead to misconceptions. It would work in this case, however.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.