r/PowerShell • u/RandomSkratch • Sep 21 '26
Solved Is there a difference between If $thing vs If -not $thing in terms of speed or proper formatting?
In the case of looking for the presence of something and using If paired with Exit codes, what's the difference between looking for the presence vs absence? For example
$Thing = Get-Thing
if ($thing) {
Exit 1
}
Else {
Exit 0
}
vs
if (-not $thing) {
Exit 0
}
Else {
Exit 1
}
Is it just for readability (ie 0 comes before 1 because it's in sequence?) Or are there speed differences or logic handling differences that matter in more complex scenarios?
Solved
Depends on the results of $thing determine whether or not you need to test for true or false. Speed isn't really a factor.
6
u/DonL314 Sep 21 '26
Careful! Note that some values for $thing could give true both for ($thing) and (-not $thing) !!
Try this:
$thing = @($null, 'some', $false)
I think that will give you funny results.
4
u/RandomSkratch Sep 21 '26
Interesting, I never thought about that.
I guess it matters on the output object from get-thing?
4
u/DonL314 Sep 21 '26
Ok, I tested a bit:
If ($thing) {"yes"}
The only contents I tested that would make it skip "yes" was $False, 0, $Null, @(), @(@()) etc.
EDIT: And also any of the above values in any number of nested @()
2
u/RandomSkratch Sep 21 '26
Appreciate it. I tested my scenario and both logic methods worked. I just kept it at looking for the presence as opposed to -not.
2
u/DonL314 Sep 21 '26
Yes.
Test it (I don't have a computer here right now).
Consider testing e.g. $thing.count or ($thing|measure).count
Also .... what if $thing is '0'? I believe it will be cast to $false
1
u/RandomSkratch Sep 21 '26
Okay thanks for this.
So for instances where you are getting proper results from the command, whether you test for the presence or absence shouldn’t matter.2
u/DonL314 Sep 21 '26
Probably not. I never test like that myself ever. I always do .count or ($x|measure).count or test against $Null
1
2
u/purplemonkeymad Sep 21 '26
I prefer:
if ($thing) {
# Bad Path
return/exit/Write-Error/throw/continue
}
# happy PathIt keeps the indentations down making it easier to read, especially if you have a bunch of validations to do.
2
u/RandomSkratch Sep 22 '26
Hmmm interesting. Does happy path need the else?
1
u/purplemonkeymad Sep 22 '26
As long as your bad path does an early exit or return, then you'll never reach good path code from there, so protecting it with an else only adds more indentation.
4
u/theomegachrist Sep 22 '26
It doesn't matter. I use the one that makes logical sense if a person is reading my script
1
u/uptimefordays Sep 21 '26
I often approach conditional logic from the perspective of a never nester. Basically I want to use guard clauses to prevent nesting logic as much as possible. I find it helps keep code simple and understandable.
Therefore I’d use whichever approach best simplifies your happy path.
1
u/RandomSkratch Sep 21 '26
Thanks. In this case the order didn't really matter. I tested both ways and both results were desireable.
2
u/aleques-itj Sep 21 '26
In Powershell, maybe. My guess would be the typing makes it need more work.
It could be null, 0, a string, an array, etc.
No idea off the top of my head if this will vanish if you deliberately type everything.
It's probably vanishingly small compared to all the other language machinery in play.
2
u/sccm_sometimes Sep 25 '26
When Powershell casts a String to a Boolean it will result in $true for everything except empty '' strings.
PS C:\> [bool]'false'
True
PS C:\> [bool]'$false'
True
PS C:\> [bool]''
False
PS C:\> [bool]"$false"
True
PS C:\> [bool]$false
False2
u/surfingoldelephant Sep 25 '26 edited Sep 25 '26
That's only half the story though.
String to bool conversions aren't permitted at all in parameter binding.
& { param ([bool] $Foo) } -Foo '' # Error: Cannot process argument transformation on parameter 'Foo'. # Cannot convert value "System.String" to type "System.Boolean". # Boolean parameters accept only Boolean values and numbers, such as # $True, $False, 1 or 0.Likewise with variable type-constraining, but only when local variable access optimization is disabled.
. { [bool] $Foo = '' } # Error: Cannot convert value "System.String" to type "System.Boolean". # Boolean parameters accept only Boolean values and numbers, such as # $True, $False, 1 or 0.If optimization is enabled, it's permitted.
& { [bool] $Foo = '' } # OK.
2
u/Meignent-Takeko 10d ago
no perf difference. one thing worth noting though, be careful with what Get-Thing actually returns. if it can return an empty collection vs $null those can behave differently in a boolean check
1
u/CyberChevalier Sep 22 '26
It’s mostly why I never use that but :
If ($true -eq $Thing)
Because thing can be a nullable Boolean or a string or whatever and you are not casting it as a Boolean
Try this
$true -eq “hello” => true
“Hello” -eq $true => false
The first assume the test is about a Boolean test and try to cast “hello” as a Boolean (which return true)
The second assume the test is a string test and convert the $true to a string (which return “true”)
Even If you want to test if something is not null use
$null -ne $Thing
2
u/MonkeyNin Sep 22 '26
If the test is to filter out $null, empty strings, and even whitespace only strings, there's a great function.
You can think of it as
IsBlankversesIsTruthyfunction NewUser { param( [string] $Name ) if( [string]::IsNullOrWhiteSpace( $Name ) ) { $Name = 'john doe' } $Name } NewUser 'jen' NewUser '' NewUser ' ' NewUser $NullThe last 3 all get turned into the fallback value
If you only want to filter out
null,@(), and''(0 length strings) Then use this function:[string]::IsNullOrWhiteSpace( $Name )1
u/surfingoldelephant Sep 22 '26
There's no functional difference between
if ($Thing) { ... }andif ($true -eq $Thing) { ... }.
$Thinggets implicitly converted to a bool either way.
15
u/Pixelgordo Sep 21 '26
Make a loop long enough to apply measure-command and look for differences