How to set PowerShell variables to True or False - powershell

PowerShell logic question:
$a = 1
$b = 2
if ($a = $b) {
$ans = $true
}
else {
$ans = $false
}
Write-Host $ans
Output:
True
Can someone explain to me why this evaluates as true? Is it because I assign $ans to true first? Also, could someone show me how to get this to evaluate the way I think it should?

You're doing an assignment $a = $b, the assignment succeeds and that returns true because b was true, so the first case will always evaluate to true at the moment, instead use a comparison: $a -eq $b.
More detailed information on comparisons in powershell.

Related

How to navigate nested loops within Powershell

I am trying to do something of the following nature
if(...){
}
elseif(...){
if(...){
}
else{
...
}
}
else{
...
}
However, it seems that powershell does not like having both an if and and else statement within the elseif loop. Any workarounds for this? Thanks for your help! I am really new to Powershell
I have tried switch statements but they do not make sense for what I am trying to do
Not an answer per se, but I tested the structure exactly as provided and it works just fine:
function iftest($a, $b, $c) {
if ($a) {
'$a true. $b and $c not tested.'
}
elseif ($b) {
if ($c) {
'$a false. $b true. $c true.'
}
else {
'$a false. $b true. $c false.'
}
}
else {
'$a false. $b false. $c not tested.'
}
}
# command # output
iftest $true $false $false # $a true. $b and $c not tested.
iftest $false $false $false # $a false. $b false. $c not tested.
iftest $false $true $false # $a false. $b true. $c true.
iftest $false $true $true # $a false. $b true. $c false.
As noted by mclayton in the comments, formatting goes a long way toward making the structure clear.

Sorting not working in a Powershell function [duplicate]

This question already has answers here:
How do I pass multiple parameters into a function in PowerShell?
(15 answers)
Powershell function call changing passed string into int
(1 answer)
Closed 1 year ago.
I have the following function in Powershell. It always returns False and also the sorting of the arrays doesn't work within the function while it works in the console. The function is
# $a = [121, 144, 19, 161, 19, 144, 19, 11]
# $b = [121, 14641, 20736, 361, 25921, 361, 20736, 361]
function comp($a, $b) {
if( -Not ($a.length -Eq $b.length) || -Not $a || -Not $b) {
return $false
}
$a = $a | sort
$b = $b | sort
# Adding echo statements here to check if $a and $b are sorted tells that both are NOT sorted despite assigning them to the same variable
# Assigning the sorted arrays to other variables such as $x and $y again doesn't solve the problem. $x and $y also have the unsorted values
for($i=0;$i -lt $a.length;$i++) {
if( -Not ($b[$i] -Eq $a[$i]*$a[$i])) {
return $false
}
}
return $true
}
Note: $a and $b in the top are initialized without [ and ] and it is just provided to give emphasis that they are arrays.
The above function returns False while it must be True. I then tried this
function comp($a, $b) {
if( -Not ($a.length -Eq $b.length) || -Not $a || -Not $b) {
return $false
}
for($i=0;$i -lt $a.length;$i++) {
$flag = $false
for($j=0;$j -lt $b.length; $j++) {
if($b[$j] -Eq $a[$i]*$a[$i]) {
$flag = $true
# Never gets into this i.e. never executed
break;
}
}
if( -Not $flag) {
return $flag
}
}
return $true
}
But this works on the console when run without a function. Please see the image below
It didn't return False. And hence, the output is True which is correct
Now see the output for the above functions
Now for the second one
What is wrong here?
You're passing the arguments to comp incorrectly.
PowerShell's command invocation syntax expects you to pass arguments separated by whitespace, not a comma-separated list.
Change:
comp($a, $b)
to:
comp $a $b
# or
comp -a $a -b $b
See the about_Command_Syntax help topic for more information on how to invoke commands in PowerShell

Powershell 'x or y' assignment

There are several languages that provide either a defaulting or logical or mechanism for assignment:
a = b || c;
a = b or c
a="${b:-$c}"
a = b ? b : c;
So far the only equivalent I've found in Powershell Core is the exceedingly verbose:
$a = if ($b) { $b } else { $c }
which in some cases has to become
$a = if ($b -ne $null) { $b } else { $c }
Is there a better alternative [edit:] which doesn't sacrifice readability?
There's no || short-circuit operator in PowerShell assignments, and nothing equivalent to Perl's // "defined-or" operator - but you can construct a simple null coalesce imitation like so:
function ?? {
param(
[Parameter(Mandatory=$true,ValueFromRemainingArguments=$true,Position=0)]
[psobject[]]$InputObject,
[switch]$Truthy
)
foreach($object in $InputObject){
if($Truthy -and $object){
return $object
}
elseif($object -ne $null){
return $object
}
}
}
Then use like:
$a = ?? $b $c
or, if you want to just have return anything that would have evaluated to $true like in your first example:
$a = ?? $b $c -Truthy
So a simple method for reducing this:
$a = if ($b -ne $null) { $b } else { $c }
Would be to use the fact that true and false are just one or zero and could be used as an array index like so:
$a = #($c, $b)[$b -ne $null]

Ternary operator in PowerShell

From what I know, PowerShell doesn't seem to have a built-in expression for the so-called ternary operator.
For example, in the C language, which supports the ternary operator, I could write something like:
<condition> ? <condition-is-true> : <condition-is-false>;
If that doesn't really exist in PowerShell, what would be the best way (i.e. easy to read and to maintain) to accomplish the same result?
$result = If ($condition) {"true"} Else {"false"}
For use in or as an expression, not just an assignment, wrap it in $(), thus:
write-host $(If ($condition) {"true"} Else {"false"})
Powershell 7 has it.
PS C:\Users\js> 0 ? 'yes' : 'no'
no
PS C:\Users\js> 1 ? 'yes' : 'no'
yes
The closest PowerShell construct I've been able to come up with to emulate that is:
#({'condition is false'},{'condition is true'})[$condition]
Try powershell's switch statement as an alternative, especially for variable assignment - multiple lines, but readable.
Example,
$WinVer = switch ( Test-Path -Path "$Env:windir\SysWOW64" ) {
$true { "64-bit" }
$false { "32-bit" }
}
"This version of Windows is $WinVer"
Per this PowerShell blog post, you can create an alias to define a ?: operator:
set-alias ?: Invoke-Ternary -Option AllScope -Description "PSCX filter alias"
filter Invoke-Ternary ([scriptblock]$decider, [scriptblock]$ifTrue, [scriptblock]$ifFalse)
{
if (&$decider) {
&$ifTrue
} else {
&$ifFalse
}
}
Use it like this:
$total = ($quantity * $price ) * (?: {$quantity -le 10} {.9} {.75})
As of PowerShell version 7, the ternary operator is built into PowerShell.
1 -gt 2 ? "Yes" : "No"
# Returns "No"
1 -gt 2 ? 'Yes' : $null
# Get a $null response for false-y return value
I too, looked for a better answer, and while the solution in Edward's post is "ok", I came up with a far more natural solution in this blog post
Short and sweet:
# ---------------------------------------------------------------------------
# Name: Invoke-Assignment
# Alias: =
# Author: Garrett Serack (#FearTheCowboy)
# Desc: Enables expressions like the C# operators:
# Ternary:
# <condition> ? <trueresult> : <falseresult>
# e.g.
# status = (age > 50) ? "old" : "young";
# Null-Coalescing
# <value> ?? <value-if-value-is-null>
# e.g.
# name = GetName() ?? "No Name";
#
# Ternary Usage:
# $status == ($age > 50) ? "old" : "young"
#
# Null Coalescing Usage:
# $name = (get-name) ? "No Name"
# ---------------------------------------------------------------------------
# returns the evaluated value of the parameter passed in,
# executing it, if it is a scriptblock
function eval($item) {
if( $item -ne $null ) {
if( $item -is "ScriptBlock" ) {
return & $item
}
return $item
}
return $null
}
# an extended assignment function; implements logic for Ternarys and Null-Coalescing expressions
function Invoke-Assignment {
if( $args ) {
# ternary
if ($p = [array]::IndexOf($args,'?' )+1) {
if (eval($args[0])) {
return eval($args[$p])
}
return eval($args[([array]::IndexOf($args,':',$p))+1])
}
# null-coalescing
if ($p = ([array]::IndexOf($args,'??',$p)+1)) {
if ($result = eval($args[0])) {
return $result
}
return eval($args[$p])
}
# neither ternary or null-coalescing, just a value
return eval($args[0])
}
return $null
}
# alias the function to the equals sign (which doesn't impede the normal use of = )
set-alias = Invoke-Assignment -Option AllScope -Description "FearTheCowboy's Invoke-Assignment."
Which makes it easy to do stuff like (more examples in blog post):
$message == ($age > 50) ? "Old Man" :"Young Dude"
Since a ternary operator is usually used when assigning value, it should return a value. This is the way that can work:
$var=#("value if false","value if true")[[byte](condition)]
Stupid, but working. Also this construction can be used to quickly turn an int into another value, just add array elements and specify an expression that returns 0-based non-negative values.
The ternary operator in PowerShell was introduced with the PowerShell version7.0.
[Condition] ? (output if True) : (output if False)
Example 01
$a = 5; $b = 6
($a -gt $b) ? "True" : "False"
Output
False
Example 02
($a -gt $b) ? ("$a is greater than $b") : ("$a is less than $b")
Output
5 is less than 6
more information
https://www.tutorialspoint.com/how-ternary-operator-in-powershell-works
Since I have used this many times already and didn't see it listed here, I'll add my piece :
$var = #{$true="this is true";$false="this is false"}[1 -eq 1]
ugliest of all !
kinda source
I've recently improved (open PullRequest) the ternary conditional and null-coalescing operators in the PoweShell lib 'Pscx'
Pls have a look for my solution.
My github topic branch: UtilityModule_Invoke-Operators
Functions:
Invoke-Ternary
Invoke-TernaryAsPipe
Invoke-NullCoalescing
NullCoalescingAsPipe
Aliases
Set-Alias :?: Pscx\Invoke-Ternary -Description "PSCX alias"
Set-Alias ?: Pscx\Invoke-TernaryAsPipe -Description "PSCX alias"
Set-Alias :?? Pscx\Invoke-NullCoalescing -Description "PSCX alias"
Set-Alias ?? Pscx\Invoke-NullCoalescingAsPipe -Description "PSCX alias"
Usage
<condition_expression> |?: <true_expression> <false_expression>
<variable_expression> |?? <alternate_expression>
As expression you can pass:
$null, a literal, a variable, an 'external' expression ($b -eq 4) or a scriptblock {$b -eq 4}
If a variable in the variable expression is $null or not existing, the alternate expression is evaluated as output.
PowerShell currently doesn't didn't have a native Inline If (or ternary If) but you could consider to use the custom cmdlet:
IIf <condition> <condition-is-true> <condition-is-false>
See: PowerShell inline If (IIf)
If you're just looking for a syntactically simple way to assign/return a string or numeric based on a boolean condition, you can use the multiplication operator like this:
"Condition is "+("true"*$condition)+("false"*!$condition)
(12.34*$condition)+(56.78*!$condition)
If you're only ever interested in the result when something is true, you can just omit the false part entirely (or vice versa), e.g. a simple scoring system:
$isTall = $true
$isDark = $false
$isHandsome = $true
$score = (2*$isTall)+(4*$isDark)+(10*$isHandsome)
"Score = $score"
# or
# "Score = $((2*$isTall)+(4*$isDark)+(10*$isHandsome))"
Note that the boolean value should not be the leading term in the multiplication, i.e. $condition*"true" etc. won't work.
Here's an alternative custom function approach:
function Test-TernaryOperatorCondition {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline = $true, Mandatory = $true)]
[bool]$ConditionResult
,
[Parameter(Mandatory = $true, Position = 0)]
[PSObject]$ValueIfTrue
,
[Parameter(Mandatory = $true, Position = 1)]
[ValidateSet(':')]
[char]$Colon
,
[Parameter(Mandatory = $true, Position = 2)]
[PSObject]$ValueIfFalse
)
process {
if ($ConditionResult) {
$ValueIfTrue
}
else {
$ValueIfFalse
}
}
}
set-alias -Name '???' -Value 'Test-TernaryOperatorCondition'
Example
1 -eq 1 |??? 'match' : 'nomatch'
1 -eq 2 |??? 'match' : 'nomatch'
Differences Explained
Why is it 3 question marks instead of 1?
The ? character is already an alias for Where-Object.
?? is used in other languages as a null coalescing operator, and I wanted to avoid confusion.
Why do we need the pipe before the command?
Since I'm utilising the pipeline to evaluate this, we still need this character to pipe the condition into our function
What happens if I pass in an array?
We get a result for each value; i.e. -2..2 |??? 'match' : 'nomatch' gives: match, match, nomatch, match, match (i.e. since any non-zero int evaluates to true; whilst zero evaluates to false).
If you don't want that, convert the array to a bool; ([bool](-2..2)) |??? 'match' : 'nomatch' (or simply: [bool](-2..2) |??? 'match' : 'nomatch')

How can I alternate/switch parts of a string in PowerShell without using an intermediate value?

I'm trying to alternate a setting in a config file using PowerShell. For example, if a certain value is true, I'd like to switch it to false. If it's false, I'd like to switch it to true. I'd also like to change a path from \\servername\folder\ to \\servername\. Is there a way I can perform this in PowerShell without using an intermediate value?
If I do this:
$foo = 'aaa'
$foo -replace 'aaa', 'bbb' -replace 'bbb', 'aaa'
$foo will always be 'aaa'. I realize I could make an intermittent change ('aaa' becomes 'ccc' and then changes to 'bbb') but that's messy to read.
How can I alternate values without using an intermediate value?
I'm not quite sure what you're trying to achieve. Do you want to switch two values without a buffer variable? Or do you want to toggle a value between two states? The latter can be achieved like this:
function Toggle($s, $v1, $v2) {
$e1 = [regex]::Escape($v1)
$e2 = [regex]::Escape($v2)
$r = $s
if ($s -match $e1) {
$r = $s -replace $e1, $v2
} elseif ($s -match $e2) {
$r = $s -replace $e2, $v1
}
return ($r)
}
$foo = "..."
Toggle $foo "\\servername\folder\" "\\servername\"
Using a match evaluator. Not sure if this is any better or not.
Begin{
[regex]$ValueRegex = 'aaa|bbb'
$ValueToggles = #{
aaa='bbb'
bbb='aaa'
}
$toggleValue = {$ValueToggles[$args[0].groups[0].value]}
}
Process{
$foo = 'Value: aaa'
$ValueRegex.replace($foo,$toggleValue)
}
Value: bbb
You can alternate a boolean value ($true or $false) simply by using the -not operator; e.g.:
PS C:\> $value = $true
PS C:\> $value = -not $value
PS C:\> $value
False
Regular expression replacement:
PS C:\> '\\servername\folder\' -replace '^(\\\\[^\\]+)\\[^\\]+', '$1'
\\servername\
Bill