Adding multiple -and and -or statements in WHERE clause in Powershell - powershell

I'm currently using Powershell, and i'm trying to sort data in my variable that i'm pulling from another system. At the moment i'm trying to use one -and statement and -or statements after an -eq sign. So I was wondering what's the correct way I need to make the syntax in my where statement.
$DLPList | Select Node.NodeName, Properties.OSType, PropsView.version, Node.NodeTextPath2 | where PropsView.version -ne '1.4.706.172' -and (Properties.OSType -eq $win7 -or $win8 -or $win81 -or $win10)
I know there's multiple other stuff on this, but everything i've tried so far doesn't work. Thanks for the help.

Yes, you have to use the script block version of where-object. Also note that -and and -or have EQUAL PRECEDENCE in powershell, which is very unusual in a language.

Alright, what I figured out for this is that you cannot just add use -or. Instead you must do Properties.ostype for each one. Here is the code that I came up with to get it to work. Also a little tip is to do Where-Object before Select-Object to save computing power.
$DLPList = $list1 | Where-Object{ $_.'UDLP.prodversion' -lt '9.5.704.112' -and ($_.'Properties.OSType' -ne 'Windows XP') -and ($_.'EPOComputerProperties.OSType' -ne 'Windows Vista') -and ($_.'EPOComputerProperties.OSType' -ne 'Windows 2003') -and ($_.'Properties.OSType' -ne 'Windows 2003 R2') -and ($_.'EPOComputerProperties.OSType' -ne 'Windows 2008') -and ($_.'Properties.OSType' -ne 'Windows 2008 R2') -and ($_.'Properties.OSType' -ne 'Windows Server 2012' -and ($_.'Properties.OSType' -ne 'Windows Server 2012 R2') -and ($_.'Properties.OSType' -ne 'Windows Server 2016')) } | Select-Object Node.NodeName, Properties.OSType, UDLP.productversion, Node.NodeText | Sort-Object -Property Node.NodeText -Descending

Try adding brackets and replacing the chained boolean operators with a regular expression "-match" operator condition:
$DLPList | Select Node.NodeName, Properties.OSType, PropsView.version, Node.NodeTextPath2 | where { $_.'PropsView.version' -ne '1.4.706.172' -and ($_.'Properties.OSType' -match "($win7|$win8|$win81|$win10)") }
Here's sample code that works for me:
$DLPList = #(2, 4, 6, 7)
$DLPList | where { ($_ -ne 7) -and ($_ -lt 10) -and ($_ -gt 0) }
2
4
6
$DLPList | where { ($_ -ne 7) -and ($_ -match "(4|5|11)" -and ($_ -gt 0)) }
4

Related

Where object as variable

After reading many of the posted solutions here, none fully applies mine.
This works (returns expected number of instancesNames based on criteria):
$response.result | Where-Object {$_.targetType -eq "webserver" -and ($_.agentHostName -eq "ServerA" -or $_.agentHostName -eq "ServerB")} | select-Object "instanceName"
However, since n number of servers may be found, I created a loop to dynamically create this query:
[System.Text.StringBuilder]$clause = " {`$_.targetType -eq ""webserver"" -and ("
$i = 1;
foreach ($server in $serversArray) {
if ( $i -eq $serversArray.Count ) {
$clause.Append("`$_.agentHostName -eq ""${server}"")}")
} else {
$clause.Append( "`$_.agentHostName -eq ""${server}"" -or ")
}
$i++
}
$clause.Append(" | select-Object ""instanceName""")
$filter = [scriptblock]::Create($clause)
$instances = $response.result | where-object $filter
debugging:
the $clause variable contains:
{$_.targetType -eq "webserver" -and ($_.agentHostName -eq "serverA" -or $_.agentHostName -eq "serverB")} | select-Object "instanceName"
However, it returns all instanceNames (not filtered) instead of the ones that meet the criteria. What am I doing wrong here?
The -in operator would simplify your code. For example:
$response.result |
Where-Object {($_.targetType -eq 'webserver') -and ($_.agentHostName -in $serversArray)} |
Select-Object 'instanceName'

Where-Object filtering - Alternative to multiple and

Using PowerCLI to filter a list of virtual machines:
Get-VM | Where-Object {$_.Name -ne 'VM1001' -and $_.Name -ne 'VM2002' -and $_.Name -ne 'VM3003' -and $_.Name -ne 'VM4004'} | Select_Object ...
Is there a cleaner/better way to filter results? This would improve script readability.
Thanks
Like #JosefZ commented, using the -notin is good for PowerShell version 3 and later:
Get-VM | Where-Object { $_.Name -notin #('VM1001','VM2002','VM3003','VM4004') }
On PowerShell version 2, you can still can use the -notcontains comparison operator:
$Excluded = #('VM1001','VM2002','VM3003','VM4004')
Get-VM | Where-Object { $Excluded -notcontains $_.Name }

Powershell bitlocker check

Hi im having diffeculties to get my script working:
It keeps failing on the first write output, even when the powershell version is higher then 4. It only works when I remove And $winver -eq $os1 -or $os2 -or $os3.
Otherwise it keeps telling me my powershell version needs to be upgraded. Im on V5 currently and $PSVersionTable.PSVersion.Major does says it 5 indeed.
What am i doing wrong?
$winver = (Get-WmiObject -class Win32_OperatingSystem).Caption
$powershellversion = $PSVersionTable.PSVersion.Major
$os1 = "Microsoft Windows 7 Professional"
$os2 = "Microsoft Windows 10 Pro"
$os3 = "Microsoft Windows 10 Enterprise"
if($winver -ne ($os1, $os2, $os3) -contains $winver){
Write-Host "Bitlocker not supported on $winver"
Exit 0
}
if($powershellversion -lt 4){
Write-Host "Upgrade Powershell Version"
Exit 1010
}
else
{
$bitlockerkey = (Get-BitLockerVolume -MountPoint C).KeyProtector.RecoveryPassword
$pcsystemtype = (Get-WmiObject -Class Win32_ComputerSystem).PCSystemType
if ($pcsystemtype -eq "2"){
$setsystemtype = "Laptop"
}
else {
$setsystemtype = "Desktop"
}
if ($setsystemtype -eq "laptop" -And $bitlockerkey -eq $null -and ($os1, $os2, $os3) -contains $winver){
Write-Host "$setsystemtype without bitlocker"
Exit 1010
}
if ($setsystemtype -eq "desktop" -And $bitlockerkey -eq $null -and ($os1, $os2, $os3) -contains $winver){
Write-Host "$setsystemtype without bitlocker"
Exit 0
}
if ($winver -eq ($os1, $os2, $os3) -contains $winver){
Write-Host "$bitlockerkey"
Exit 0
}
}
Let's see what this actually does:
if ($powershellversion -lt 4 -And $winver -eq $os1 -or $os2 -or $os3) { ... }
If your powershell version is less than 4, and Win version is equal
to os1, then proceed
If os2 has a value, then proceed
If os3 has a value, then proceed
The topic here is Operator Precedence, specifically, what happens first when evaluating a line of code, what happens second, third, and so on. Just like in algebra math, adding parens around part of the formula changes the order in whcih you read it.
So, you can mess around with parens to get your logic to work:
if($powershellversion -lt 4 -and ( ($winver -eq $os1) -or ($winver -eq $os2) -or ($winver -eq $os3) ))
In other words
evaluate if PS version is < 4 ($powershellversion -lt 4), -and
evaluate if winver is either os1, os2 or os3: ( ($winver -eq $os1) -or ($winver -eq $os2) -or ($winver -eq $os3) ).
Or, you can rearrange your logic a bit by putting your os variables into an array, and seeing if $winver is in there:
if($powershellversion -lt 4 -and $winver -in ($os1, $os2, $os3)) { ... }
Edit: Or
if($powershellversion -lt 4 -and ($os1, $os2, $os3) -contains $winver) { ... }
for backwards compatibility with v2.0.

Clarification of syntax used

Can someone explain me this syntax? I think it didn't work, so if you can help me to find another syntax.
$fichesAEnvoyer = #($fiches | where {($_.TypeFiche -eq '2') -and (($_.Causes -eq '') -or ($_.Causes -eq $null) -or ($_.Causes.Count -eq 0) -or ($_.ActionCorrective -eq '') -or ($_.ActionCorrective -eq $null) -or ($_.DateActionCorrective -eq '') -or ($_.DateActionCorrective -eq $null) -or ($_.ActionPreventive -eq '') -or ($_.ActionPreventive -eq $null) -or ($_.DateActionPreventive -eq '') -or ($_.DateActionPreventive -eq $null) )})
I don't understand why there is $_ instead of $fiches
$_ is a variable that the where cmdlet creates to represent the current object in the pipeline. For example, if you do:
1,2,3 | where {$_ -ge 2} | Write-Host
Then $_ will be set to 1 followed by 2, followed by 3.

Conditional PowerShell operators

I am trying to get a list where the title does not have temp or temporary or *contractor or contractor*.
This code is working, meaning I get a list which does not have temporary records.
$pTitle = $profile["Title"]
if ($pTitle -ne "Temporary")
However the following code does not work when I add -or and -notlike for the wildcard.
$pTitle = $profile["Title"]
if ($pTitle -ne "Temporary" -or $pTitle -notlike "Temporary" -or $pTitle -notlike "contractor" -or $pTitle -notlike "Temp")
You actually want -and here. Your expression will only evaluate to false if all of the words are found currently.
$List = #(1,2,3)
If I ask you to return all the items in the list that are:
not equal to 1
or
not equal to 2
or
not equal to 3
the answer will be the whole list
$List | where { ($_ -ne 1) -or ($_ -ne 2) -or ($_ -ne 3) }
1
2
3
You are getting your logical operators mixed up.
Look at replacing -or with -and