Can someone tell me why the -or does not work. If I run the code the first output is administrator which returns true but when it gets to the kahuna account it still returns false not true.
(Get-LocalUser).Name | Out-File C:\localusers.txt
ForEach ($User in Get-Content C:\localusers.txt)
{
If ($User -match "administrator" -or "kahuna")
{
Write-Host True
}
Else
{
Write-Host False
}
}
I get
True, False, False, False, False
Here are the accounts listed in order they appear
administrator, DefaultAccount, Guest, Kahuna, PCUser
Try
If ($User -match "administrator" -or $User -match "kahuna")
Your -or operator doesn't tie the values of the previous operator together. You need to specify a 2nd conditional operator after -or I believe.
Nick is right, vote up his answer. You can also use parens if that is easier to see:
If (($User -match "administrator") -or ($User -match "kahuna"))
The parens are implied and PSH sees them there anyway. With or without the parens, $User = "administrator" would first resolve to:
If (($true) -or ($false))
which resolves to $true.
Related
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.
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}
How can I exclude specific string collections
CN=HealthMailbox478eb865ff384698bf3ff10c9c889f1c,CN=MonitoringMailboxes,CN=Microsoft
Exchange System Objects,...
CN=HealthMailbox7s7df7s7vn3421nifdfu,CN=MonitoringMailboxes,CN=Microsoft Exchange System Objects,...
OU=Disabled Computers
OU=Service Accounts
from the result of the script below:
Get-ADObject -Filter 'ObjectClass -eq "user" -or ObjectClass -eq "computer" -and isDeleted -ne $True -and isRecycled -eq $false -and name -ne "Deleted Objects"'
Updated as per #Theo:
Get-ADObject -Filter "ObjectClass -eq 'user' -or ObjectClass -eq 'computer' -and isDeleted -ne $True -and isRecycled -eq $false -and name -ne 'Deleted Objects'"
However, the error is still:
Get-ADObject : Error parsing query: 'ObjectClass -eq 'user' -or ObjectClass -eq 'computer' -and isDeleted -ne True -and isRecycled -eq False -and name -ne 'Deleted Objects''
Error Message: 'syntax error' at position: '74'.
At line:1 char:1
+ Get-ADObject -Filter "ObjectClass -eq 'user' -or ObjectClass -eq 'com ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ParserError: (:) [Get-ADObject], ADFilterParsingException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADFilterParsingException,Microsoft.ActiveDirectory.Management.Commands.GetADObject
From within the -Filter argument You'll have a hard time excluding on the basis of when a collection contains a value. This may be a case to filter as much as you can on the left, but append a post filtering Where{} . The rule is to filter "as much as you can, as far left as you can" (quotes are mine). There are always going to be cases where there's a little more to be done. Something like:
$Exclusions = "Server1","Server2"
Get-ADObject ... | Where-Object{ $_.Name -notin $Exclusions }
Or:
Where-Object{ $Exclusions -notcontains $_.Name }
In similar cases I like to create a $Exclusions array, so it can be appended as needed while you are dev-ing or for later maintenance.
Note: You may not need -and isDeleted -ne $True If the
-IncludeDeletedObjects' parameter is any indication Get-ADObjectexcludes them by default. Also, as written it's another inversion, the literal idea "not deleted" is easier to read asisDeleted -eq
$false`
That said, and with the limited example above, you might be able to add Name -notlike "HealthMailbox*" to your filter string. You could probably add additional -and -notlike ..., but who knows when that'll get out of hand.
As I mentioned in my other answer Get-ADObject seems to reject double quoted queries as suggested in previous comments. Granted this seems to be unusual and backwards behavior, but in testing Get-ADObject seems to expect expansion of $true/$false. Replacing with single quotes just makes it fail. Indeed and so far as I can tell the query as given in the question is working. I invite others to comment...
Nevertheless About_Quoting_Rules, doc may be a helpful refresher...
Note: The AD cmdlets are known to be finicky regarding the typing of the -Filter's argument, so to a certain extend I'm not surprised.
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.
I have this, which doesn't work:
$var1 = "6.0.6001"
$var2 = "6.1.7001"
$var3 = "6.2.8074"
$var4 = "6.3.8074"
if($var1 -match "6.1.?" -or "6.2.?" -or "6.3.?") {
write-host "1"
}else{
write-host "2"
}
No matter what, 1 is returned.
What should this really look like?
Thanks.
Run this code:
if("6.2.?" -or "6.3.?") {
write-host "1"
}else{
write-host "2"
}
It'll also return 1 no matter what.
Change your condition to:
if($var1 -match "6.1.?" -or $var1 -match "6.2.?" -or $var1 -match "6.3.?")
Or even better:
if($var1 -match "6.[1-3].?")
Just to elaborate on Adam 's answer. You If statement was not working as intended since PowerShell only saw three conditions you didnt intend
if($var1 -match "6.1.?" -or "6.2.?" -or "6.3.?")
if(($var1 -match "6.1.?") -or ("6.2.?" -or "6.3.?"))
The two lines above function the same. To break down the second operation ("6.2.?" -or "6.3.?") just a little more: A non-zero length string converted to boolean will always be $true. Comparing two non-zero length string with -or will always return $true. The first clause ($var1 -match "6.1.?") in your example is $false. If($true -or $false) is essentially what your If statement boils down to which, again, would always return $true. Adams answer show how to get the logic you are looking for
if($var1 -match "6.1.?" -or $var1 -match "6.2.?" -or $var1 -match "6.3.?")
if(($var1 -match "6.1.?") -or ($var1 -match "6.2.?") -or ($var1 -match "6.3.?"))
Both the above statements are the same. The second one helps understand the logic. For more information see about_Logical_Operators. You only need brackets when the logic is not acting the way you want it to.