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.
Related
I am trying to loop through a list of Windows services and if any of them match a certain criteria, I would like to return exit code 1.
If there is no match, I would like to return exit code 0.
I am struggling to put this within an If statement, I think I'm putting the code in the wrong place!
Could anyone lend me a hand? Script below.
Thanks in advance.
Adrian
try
{
#Pull list of services from registry
$svclist = Get-ChildItem HKLM:\SYSTEM\CurrentControlSet\services | ForEach-Object {Get-ItemProperty $_.PsPath}
#Ignore anything after .exe, filter for vulnerable services
ForEach ($svc in $svclist) {
$svcpath = $svc.ImagePath -split ".exe"
if(($svcpath[0] -like "* *") -and ($svcpath[0] -notlike '"*') -and ($svcpath[0] -notlike "\*")) {
$svc | fl -Property DisplayName,ImagePath,PsPath
}
}
if (($svc -ne $null)){
Write-Host "Match"
Return $svc.count
exit 1
}
else{
Write-Host "No_Match"
exit 0
}
}
catch{
$errMsg = $_.Exception.Message
Write-Error $errMsg
exit 1
}
You can either return early or use a variable with a single [bool] value to keep track of whether anything was matched:
return early
foreach($svc in $svcList)
{
$svcpath = $svc.ImagePath -split ".exe"
if(($svcpath[0] -like "* *") -and ($svcpath[0] -notlike '"*') -and ($svcpath[0] -notlike "\*")) {
return 1
}
}
# if we've reached this point then no matches occurred
return 0
Using a [bool]
$matchFound = $false
foreach($svc in $svcList)
{
$svcpath = $svc.ImagePath -split ".exe"
if(($svcpath[0] -like "* *") -and ($svcpath[0] -notlike '"*') -and ($svcpath[0] -notlike "\*")) {
$matchFound = $true
}
}
return [int]$matchFound # $false = 0, $true = 1
I always try to use the most powershell-correct methods to achieve what I want. Especially when going through data I prefer to try filtering with the x-object cmdlets.
In your case my suggestion would be to simply loop over the original list with the Where-Object command, this allows you to retrieve a list of items that conform to your search, kind of like an SQL query:
$resultList = $svclist | Where-Object {
($_.ImagePath -like "* *") -and ($_.ImagePath -notlike '"*') -and ($_.ImagePath -notlike "\*")
}
In this case I skipped over the -split ".exe" part, as I didn't quite understand it's purpose, but you could also put that in your filter using regular expressions with the -match operator instead of the -like and -notlike values you make one regex match
Then you can check if that list is populated or not:
if ($resultList) {
return 1
}
else {
return 0
}
It is also considered best practice to only use the aliases for commands (e.g. fl should be Format-List). This will increase readability for future maintenance, of course if it's a one-time script is would be more appropriate. I just try to avoid it as much as I can these days.
I have been developing a script to send mail based on variables. I have a script like below.
Each of these 2 variables may be $null or not $null. What's the best practice to check for such condition?
Here is my script:
$variableA = ""
$variableB = ""
if($variableA) {
Write-Host "mail send variableA"
} else {
Write-Host "mail not send variableA"
}
if($variableB) {
Write-Host "mail send variableB"
} else {
Write-Host "mail not send variableB"
}
You can use negated -xor operator:
# Either both nulls or both have values
(-not (($null -eq $a) -xor ($null -eq $b)))
One can disagree what's more readable. I'd personally just go with more explicit formula:
(($null -eq $a) -and ($null -eq $b)) -or
(($null -ne $a) -and ($null -ne $b))
Remember to put $null in the left side of the comparison, it's considered as a best practice.
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.
Why does PowerShell need a line continuation backtick after the first condition of the Where-Object scriptblock? It should be clear that the scriptblock has not yet ended as there has been no closing curly brace }.
Why does this work:
Get-Process | Where-Object {
($_.Responding -ne $true) `
-or ($_.ProcessName -like 'W*')
}
and this doesn't:
Get-Process | Where-Object {
($_.Responding -ne $true)
-or ($_.ProcessName -like 'W*')
}
This also fails.
Get-Process | Where-Object {
(
($_.Responding -ne $true)
-or ($_.ProcessName -like 'W*')
)
}
Your first example works, because you tell PowerShell that the statement is continued in the next line (by escaping the linebreak).
The other two examples fail, because the expression on the first line is a complete expression in and by itself, whereas the expression on the second line is not. PowerShell first evaluates ($_.Responding -ne $true), then tries to evaluate -or ($_.ProcessName -like 'W*'), which is an invalid statement and thus fails.
To avoid this you need to make it clear to the interpreter that the statement on the first line is continued in the next line. That can be done either by escaping the linebreak like you do in your first example:
Get-Process | Where-Object {
($_.Responding -ne $true) `
-or ($_.ProcessName -like 'W*')
}
or by constructing your statement in a way that allows the interpreter to detect that there is more to come, e.g. by putting the operator at the end of the first line instead of at the beginning of the second line:
Get-Process | Where-Object {
($_.Responding -ne $true) -or
($_.ProcessName -like 'W*')
}
The curly braces can't be used to detect the end of the statement, because it's valid to put multiple statements in a Where-Object scriptblock.
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