Multiple condition in where clause - powershell

When I execute below code, I get an error as : A parameter cannot be found that matches name or. How can I get user list who don't have abc.com or xyz.com in their email address?
Get-ADGroupMember -Identity "AQ" -Recursive | where objectClass -eq 'user' | Get-ADUser -Properties *, "msDS-UserPasswordExpiryTimeComputed", PasswordNeverExpires |
where mail -notmatch "#abc.com" -or "#xyz.com" |
Select-Object #{Label = "SAM Account Name";Expression = {$_.SamAccountName}}

The curly braces (actually a scriptblock with the filter script) can not always be skipped with Where-Object.
You can do Where-Object objectClass -eq 'user' but everything that involves more than a single operator requires to be written as a filter script:
where {$_.mail -notmatch "#abc.com" -or "#xyz.com" }
Now this logic doesn't work, as this is equivalent to the following statement:
where {($_.mail -notmatch "#abc.com") -or $true }
So your where clause is true, regardless of the result of the -notmatch operation. You want two -notmatch operations instead:
Where-Object - { $_.Mail -notmatch '#abc.com' -and $_.Mail -notmatch '#xyz.com' }
Depending on the amount of email addresses, that you want to exclude in your filter script, you might want to use a different approach: Strip the user name from the email address and see, if this address appears in the array of email addresses that you want to exclude.
Where-Object { ( $_.Mail -replace '^[^#]+') -notin '#abc.com','#xyz.com','#foo.bar' }

for multiple conditions use full syntax:
where-object { $_.property -eq $b -and $_.otherproperty -match $a }

You're missing some brackets around your where-clause:
where {objectClass -eq 'user'}
And this:
where {mail -notmatch "#abc.com" -or "#xyz.com"}
Should look like that:
where {mail -notmatch "#abc.com" -or mail -notmatch "#xyz.com"}
Please rethink the logic of your second where since it will always be true.

Related

I am trying to add members to a AD group based on a value in the "title" attribute

I am trying to add members to a AD group based on a value in the "title" attribute. I have about 30 different tiles i want to use. Is there a way to write the command witout 30 "OR" statements?
Thanks
Get-ADuser -filter {(title -eq "SECSCH") -or (title -eq "SEC12") -or (title -eq
"LTOSEC") -or (title -eq "LTO12")} | %{Add-ADGroupMember "SDK test print color"
$_.SamAccountName}
Also, for another group I would like All "custod" in title except at location "85c" and "42c" Below is where i am at.
Get-ADuser -filter {(title -eq "custod") -and (locationNumber -ne "85c") -or (title -eq
"custod") -and (locationNumber -ne "42c")} | %{Add-ADGroupMember "SDK test print
convert" $_.SamAccountName}
For your first issue you can create an array which contains your titles and browse it.
Example :
$Titles = "SECSCH","SEC12","LTOSEC","LTO12"
foreach($Title in $Titles){
Get-ADuser -filter {title -eq $Title} | %{Add-ADGroupMember "SDK test print color" $_.SamAccountName}
}
The -Members parameter can take an array of ADPrincipal objects so what you can do instead of using so many 'OR's in the Filter is using a Where-Object clause afterwards.
This will allow you to use operators like -contains or -match
$titles = "SECSCH","SEC12","LTOSEC","LTO12" # your 30+ titles here
$users = Get-ADUser -Filter * -Properties Title | Where-Object { $titles -contains $_.Title }
Add-ADGroupMember -Identity "SDK test print color" -Members $users
As for your second code change the Filter to below
$filter = "Title -eq 'custod' -and (locationNumber -ne '85c' -and locationNumber -ne '42c')"
$users = Get-ADUser -Filter $filter -Properties Title, locationNumber
Add-ADGroupMember -Identity "SDK test print convert" -Members $users
Note: the property locationNumber is AFAIK not a standard attribute in AD. Is that a custom property in your organization or do you perhaps mean something else like Division or EmployeeNumber ?
I provided a different answer to the first at the other place it was asked, using -Ldapfilter, but I feel #Onyx's answer here is probably more intuitive if you're not so comfortable with that. It's efficient in that you're only getting the objects you need, not grabbing every account out of AD and throwing away most of them.
To be honest, doing -Filter 'title -like "*"' would be better than nothing if you MUST use a Where clause.
For the second question (as described in the comments), the same applies with maybe building an LDAPfilter or #Onyx's method of creating an array for your customlocations and doing a Foreach through those.
Or again, at the very least, do -Filter '(employeeType -ne "student") -and (CustomLocation -like "*")' before the Where.

Powershell where-object complex logic

I am having trouble coming up with a way to do complex logic using the where-object in PowerShell
I have the following code, but separating the and from the ors is not working as intended.
Get-ADComputer -Filter * | Where-Object {($_.Enabled) -and
(($_.DistinguishedName -Contains "world") -or
($_.DistinguishedName -Contains "foo")) -and
(($_.SID -Contains "bar") -or
($_.SID-Contains "something else"))}
If I do this in c# I get results, but in powershell I do not.
Any thoughts on how to get around this?
TIA
This is how you would perform your query using AD PS Module:
Get-ADComputer -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)"|where-object{
$_.DistinguishedName -match 'World|Foo' -and $_.SID -match 'bar|something else'
}
-LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)" = Enabled Computer Object
-match allows the use of regex, you can use the pipeline as OR.
-contains is the operator you would use to lookup an item on an array. Example:
PS /> #(
'apple'
'banana'
'pineapple'
) -contains 'apple'
True
In addition, as Dave Wyatt pointed out in a nice post on powershell.org a while ago, you might want to avoid where-object whenever possible since it's the slowest way to filter collections. It's only advantages are the low memory consumption and pipeline streaming.
Here are a few examples of faster efficient code:
#Example 1:
$computers=Get-ADComputer -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)"
$collection=[system.collections.generic.list[Microsoft.ActiveDirectory.Management.ADComputer]]::new()
foreach($computer in $computers)
{
if($computer.DistinguishedName -match 'World|Foo' -and $computer.SID -match 'bar|something else')
{
$collection.add($computer)
}
}
#Example 2:
filter myFilter{
if($_.DistinguishedName -match 'World|Foo' -and $_.SID -match 'bar|something else')
{
$_
}
}
$computers=Get-ADComputer -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)"|myFilter
#Example 3
$computers=(Get-ADComputer -LDAPFilter "(!userAccountControl:1.2.840.113556.1.4.803:=2)").where({
$_.DistinguishedName -match 'World|Foo' -and $_.SID -match 'bar|something else'
})
There is plenty on information on the different ways of filtering Collections on PowerShell and their pros / cons on Google.
this is not an Answer - so please let me know when you have read it so that i can delete it.
this is your code with more informative indentation, with the needless extra parens removed, and with spaces around the operators.
Get-ADComputer -Filter * |
Where-Object {
$_.Enabled -and
($_.DistinguishedName -Contains "world" -or
$_.DistinguishedName -Contains "foo") -and
($_.SID -Contains "bar" -or
$_.SID -Contains "something else")
}
note that the -contains operator is NOT for strings ... it is for membership in a collection. if you want to test against strings, use -match, or .Contains(), or -like with wildcards.

read the value from registry rather than hard code in if statement

i have below powershell line. It will return 1 when there is account found in administrators group other than built-in administrator, group1, group2, group3.
If ((Get-LocalGroupMember -Group Administrators | Where-Object {($_.ObjectClass -eq 'User' -or $_.ObjectClass -eq 'Group') -and (($_.Name -notlike "$env:computername\administrator") -and ($_.Name -notlike 'group1') -and ($_.Name -notlike 'group2') -and ($_.Name -notlike 'group3') )}).Count -gt 0) {
echo 1
}else{
echo 0
}
how do i change the above if statement to read in the string value (which has commas) in registry so I don’t need to hard code group1, group2, group3 in the if statement?? Thanks
example i had set it at hklm:\system\test , named as adm and string value of group1,group2,group3
i am able to pull the value i set at registry using this line.
$listofadm = (Get-ItemProperty -Path "HKLM:\system\test" -ErrorAction Stop -Name adm).adm
Not sure why you are checking if user or group, if you can omit that it will simplify your check. To streamline this I would make a regex pattern of all the groups including the computer\adminsitrator account. If the groups indeed do not have a space then you can simply replace the commas with a pipe | character.
$listofadm = "$env:computername\administrator|" +
(Get-ItemProperty -Path "HKLM:\system\test" -ErrorAction Stop -Name adm).adm -replace ',','|'
This will make $listofadm contain something like
DESKTOP-NEKK74J\administrator|group1|group2|group3
Now if you just want to find any object whose name is not any of those 4
Get-LocalGroupMember -Group Administrators | where name -NotMatch $listofadm
Single item checks in the Where clause can omit the { } curly braces. If you do need to ensure it's a user or group object then this is how that would look.
Get-LocalGroupMember -Group Administrators |
Where-Object {($_.ObjectClass -eq 'User' -or $_.ObjectClass -eq 'Group') -and $_.name -NotMatch $listofadm}

Get-ADUser with multiple filters & variables

I'm trying to get AD users into a variable using multiple filters. However one of the filters has variables in it & I can't get it to work... I have searched for similar issues & tried applying those but nothing seems to work.
$FilterBase = "department"
$Filter = "IT"
$ADusers = Get-ADUser -ResultSetSize $null -SearchBase "OU=Users,DC=mydomain,DC=com" -Properties * -Filter {(Enabled -eq $True) -and ($FilterBase -like $Filter) -and (cn -notlike ""SMB_*"")} |
Select-Object distinguishedName |
Sort-Object distinguishedName
I'm trying to fill $ADusers with all enabled users whose commonname doesn't start with "SMB_" (don't ask) & where the department is IT. I used -like to prevent issues if the values in AD would have different casings (uppercase, lowercase, mixed case, ...).
The reason that I'm using variables for this is because in the end the script will be dynamic. At some point $FilterBase is going to be "company" instead of "department" and $Filter is going to be "HR" instead of "IT" etc...
But I just can't seem to get it to work:
Get-ADUser : Error parsing query: '(Enabled -eq $True) -and ($FilterBase -like $Filter) -and (cn -notlike ""SMB_*"")' Error Message: 'syntax error' at position: '74'.
At line:4 char:12
I have tried using quotes around the variables like "$Filter", "$($Filter)", ' $Filter ' but alas. And I know it's not best practice to use variables in Filter but I can't think of any other way to accomplish this.
Any suggestions?
the error has the key to the answer. I'm sure I'll find this again and use it myself because I look this up every year or so...
Error parsing query: '(Enabled -eq $True)...'
In this case the filter needs a simple string 'True' which the variable $True does equal.
Two options will work, either
Enabled -eq 'True'
or
Enabled -eq '$True'
but
Enabled -eq $True
will not.
This should work
Replaced the braces with double quotes so inside them the variables still parse
Put single quotes around all strings and variables that resolve into strings
'$True'
'$Filter'
'SMB_*'
$FilterBase = "department"
$Filter = "IT"
$ADusers = Get-ADUser -ResultSetSize $null -SearchBase "OU=Users,DC=mydomain,DC=com" -Properties CN -Filter "(Enabled -eq '$True') -and ('$FilterBase' -like '$Filter') -and (CN -notlike 'SMB_*')" |
Select-Object distinguishedName |
Sort-Object distinguishedName
Important to note the above syntax highlighting will make the sample above look wrong because it misses the tokens like $FilterBase and $Filter when there are inside single quotes inside double quotes. Remember that single quotes are just apostrophes when inside double quotes, therefore the tokens should be colored differently and not look like strings.
> "('$FilterBase' -like '$Filter')"
('department' -like 'IT')
Paste a sample like above and see what it resolves to - best way to figure it out.
its just simply syntax error.
$enabled = 'Enabled'
$EnabledTrueOrFalse = $true
$SN = 'Surname'
$surname = "Doe"
$OU = "OU=Users,DC=mydomain,DC=com"
Get-ADuser -filter{$enabled -eq $EnabledTrueOrFalse -and $SN -eq $surname} -SearchBase $OU -Properties * | Select-Object distinguishedName | Sort-Object distinguishedName
read more about it here
Thanks for the tips guys. I couldn't get it to work with multiple filters so I moved some filters to the where clause.
My current (working) code is now:
$FilterBase = "department"
$Filter = "IT"
$ADusers = Get-ADUser -ResultSetSize $null -SearchBase "OU=Users,DC=mydomain,DC=com" -Properties * -Filter "$FilterBase -like `"$Filter`"" |
Where {$_.Enabled -eq $True -and $_.CN -notlike "SMB_*"} |
Select-Object distinguishedName |
Sort-Object distinguishedName

foreach filtering out members already apart of group

$GetGroupsFromUser = Get-ADPrincipalGroupMembership $WPFnamelookupbox.Text |
Where-Object { $_.Name -like 'G1*' }
$Groups = Get-ADGroup -Filter {Name -like "G1*"}
foreach ($G in $Groups) {
if ($GetGroupsFromUser -contains $G) {
} else {
$WPFgroups.Items.Add($G.SamAccountName)
}
}
My goal is I want to only show groups that the user is not a member of.
So I made some progress going with the -contains operator. In order for -contains to work, I need to first create an array, correct?
You could use Compare-Object:
$GetGroupsFromUser = Get-ADPrincipalGroupMembership $WPFnamelookupbox.Text | Where-Object {$_.name -like 'G1*' }
$Groups = Get-ADGroup -Filter "name -like 'G1*'"
Compare-Object $Groups $GetGroupsFromUser | Where-Object {$_.SideIndicator -eq "<="}
-contains functions best when you are trying to find a match of an element in an array.
If you are just looking for the groups that matches a filter that a user does not already have we can use -notcontains inside a where clause as well for this.
$groupFilter = "G*"
$user = "user_bagel"
$allFilteredGroups = Get-ADGroup -Filter "name -like '$groupFilter'" | Select-Object -ExpandProperty name
$userFilteredGroups = Get-ADPrincipalGroupMembership $user | Where-object{$_.name -like $groupFilter} | Select-Object -ExpandProperty name
$allFilteredGroups | Where-Object{$userFilteredGroups -notcontains $_}
You don't need to expand the groups names as I have done. You will get similar results either way. Since you only wanted to know the names it seemed silly to keep the complete group object. In theory it will also perform faster this way. Setting up variables like $groupFilter makes it easier to make changes to your script down the line.