How to check to see if what went through the hashtable matched anything - powershell

I have a hashtable and I'm trying to make an if statement right now that will check to see if what went through the hashtable matched anything within it.
$netVerConv = #{
'v2.0' = "lib\net20";
'v3.0' = "lib\net30";
'v3.5' = "lib\net35";
'v4.0' = "lib\net40";
'v4.5' = "lib\net45";
}
$target = $netVerConv.Get_Item($netVerShort)
if () {
}
Above is the area of my code I'm working with, the target variable runs $netVerShort through the $netVerConv hashtable using a Get_Item command. The if statement that I've laid the framework for would check to see if netVerShort matched anything within the hashtable and if it didn't it will stop the program, which I know how to do with a simple exit command.

The other suggestions will work in your specific scenario but in general you should use the ContainsKey() method to see if a key exists in the hashtable. For instance the hashtable value could be $null or $false in which case, testing via the result of Get_Item() or more simply Item[$netVerShort], will return a false negative. So I recommend this approach for testing existence of a key in a hashtable. It is also more obvious what your intent is:
if (!$netVerConv.ContainsKey($netVerShort) {
...
}

How about this:
if( $target -eq $null ) {
echo "Didn't Match"
exit
}

Another option:
if (-not ($target = $netVerConv.Get_Item($netVerShort)))
{
Write-Error "Version $netVerShort not found"
Exit
}
You could also re-factor that as a Switch
$target =
Switch ($netVerShort)
{
'v2.0' {"lib\net20"}
'v3.0' {"lib\net30"}
'v3.5' {"lib\net35"}
'v4.0' {"lib\net40"}
'v4.5' {"lib\net45"}
Default {
Write-Error "Version $netVerShort not found"
Exit
}
}

Related

If Else Statement is not working in Else side using PowerShell

I use if else in my powershell script.
if ($match.Groups.Count) {
while ($match.Success) {
Write-Host ("Match found: {0}" -f $match.Value)
$match = $match.NextMatch()
}
}
else {
Write-Host "Not Found"
}
in the if side, it works, but in the else side, It cannot return "Not Found" . It does not show any error.
PetSerAl, as countless times before, has provided the crucial pointer in a comment:
Perhaps surprisingly, the [System.Text.RegularExpressions.Match] instance returned by the static [regex]::Match() method (or its instance-method counterpart) contains 1 element in its .Groups property even if the matching operation didn't succeed[1], so that, assuming an instance stored in $match, $match.Groups.Count always returns $true.
Instead, use the .Success property to determine if a match was found, as you already do in the while loop:
if ($match.Success) {
while ($match.Success) {
"Match found: {0}" -f $match.Value
$match = $match.NextMatch()
}
} else {
"Not Found"
}
Note that I've removed the Write-Host calls, because Write-Host is generally the wrong tool to use, unless the intent is explicitly to write to the display only, thereby bypassing PowerShell's output streams and thus the ability to send the output to other commands, capture it in a variable or redirect it to a file.
[1] [regex]::Match('a', 'b').Groups.Count returns 1, even though the match clearly didn't succeed.

Why weird assignment from variable inside Powershell switch statement?

I'm a beginner at Powershell and am struggling to understand some syntax from some code I found on Github. I've read the docs on Powershell assignment, and on switch statements, and can't understand what is going on with the = $Yes and = $No in this code snippet:
Switch ($Prompt3) {
Yes {
Stop-EdgePDF
Write-Output "Edge will no longer take over as the default PDF viewer."; = $Yes
}
No {
= $No
}
}
I haven't been able to find any references to this kind of syntax, and it doesn't seem to do anything in the script. So why is it there?
UPDATE: This issue has been resolved.
Looks to me like the variable name that was getting the assignment was deleted in a change back in August.
$PublishSettings = $Yes
Was changed to:
= $Yes
And:
$PublishSettings = $No
Was changed to:
= $No
Looks like poor search and replace.
I've created an issue for the problem at GitHub.
There are many characters that are valid in a function (or variable) name; this includes the = symbol. What you're observing is a function or alias.
Examples:
# standard function
function =
{
return $args
}
# accessing the function: drive
${Function:=} = {
return $args
}
# defining a new alias
New-Alias -Name = -Value Get-Variable
# using the Alias attribute
function Test-Thing
{
[Alias('=')]
param()
return $args
}

How to use a powershell function to return the expected value?

As we know, PowerShell has wacky return semantics.
Function return value in PowerShell shows there are two main ideas to wrap my head around:
All output is captured, and returned
The return keyword just indicates a logical exit point
Even things like reserving variables in outer scopes cause output, like [boolean]$isEnabled. Another good one is $someCollection.Add("toto") which spits the new collection count. Even Append() function causes output.
For example :
Function MyFunc {
$res1 = new-object System.Text.StringBuilder
$res1.Append("titi");
$res2 = "toto"
return $res2
}
$s = MyFunc
Write-Host $s
The output is : titi toto.
The expected output should be toto.
How to use a powershell function to return the expected value? (at least when viewed from a more traditional programming perspective)
Change
$res1.Append("titi");
to
$res1.Append("titi") | Out-Null
because the function returns every output which otherwise would be visible in the console.
if by using 'toto' you are trying to understand if your function succeeded, you could do
Function MyFunc {
$res1 = new-object System.Text.StringBuilder
$res1.Append("titi") | Out-Null
return $?
}
"$?" returns a boolean if the previous command succeeded (true) or failed (false). so externally it would look like
$s = MyFunc
if ($s) {
Write-Host "successful" -Foregroundcolor Green
}
else {
Write-Error "unsuccessful"
}
When PowerShell was being developed, the team wanted to make it simple to use. But, it was confusing to people who know return from other languages. The implementation in classes is an attempt to rectify that mistake.
The return keyword works very differently in methods in PowerShell classes. It works like the return statements in other languages.
In a class method, the return keyword:
Exits the current scope.
Returns the associated object (return ).
Returns only the associated object.
The object that Return returns must match the return type of the method.
It is consistent with the return keyword and analogous keywords in other languages.
class ClassMyFunc
{
[string] MyFunc
{
$res1 = new-object System.Text.StringBuilder
$res1.Append("titi")
$res2 = "toto"
return $res2
}
}
$cmf = New-Object -TypeName ClassMyFunc
$cmf.MyFunc()
The output is : toto, as expected.
Using classes solved my problem, without having to search all functions returning a value in the console and piping it to Out-Null (as suggested by #TobyU).

If statement - Four variables, only run if one true

I have the following which doesn't allow both variables to be enabled (boolean true value):
If (($Variable1) -and ($Variable2)) {
Write-Warning "Both variables have been enabled. Modify script to enable just one."
Pause
Break
}
This works great, however, how would I ensure only one is ever enabled when 4 possible variables exist? I'm thinking a combination of -and & -or?
You can add the boolean values and check their count:
If (([bool]$Variable1 + [bool]$Variable2 + [bool]$Variable3) -ne 1) {
...
}
but of course you have to make sure that these can actually be cast to boolean.
That's what "exclusive or" (xor) is for:
If ($Variable1 -xor $Variable2 -xor $Variable3) {
....
}
About logical operators in Powershell
Cannot think of a way to do this that avoids using a counter. You have to check the value of each variable and keep count of how many are $true.
$trueCount = 0
($variable1, $variable2, $variable3, $variable4) | % { if ($_ ) { $trueCount++} }
if ($trueCount -eq 1) {
write-host "only one variable true"
}
else {
write-host "condition not met"
}

Writing a hashtable value to an attribute

Powershell newbie here, my first script.
I have user objects with an AD custom attribute named tvCode with a values of 123456 or 6787682 or 983736 etc.
I would like to script something that will get the tvCode value from the user object
When:
123456 = Sony
6787682 = Samsung
9837343 = LG
Write the value of "Sony" or "Samsung" or "LG" to the "City" attribute of the user object.
Looks like i may need to use a hashtable.
If possible do this for a specific OU
hope this makes sense
thanks
function Convert-TVCode {
Param
(
[parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true)]
[String[]]
$Code
)
Process {
foreach ($C in $Code) {
switch ($C) {
"123456" {$brand = "Sony"}
"6787682" {$brand = "Samsung"}
"9837343" {$brand = "LG"}
default {
$brand = $null
Write-Warning "$C not included in switch statement. Returning"
return
}
}
if ($brand) {
Write-Verbose "Code '$C' matched to Brand '$brand' -- searching for users to update"
Get-ADUser -Filter "tvCode -eq '$C'" | Set-ADUser -Replace #{tvCode=$brand}
}
}
}
}
This function will allow you to update any users that have their tvCode attribute set as one of the target numerical values. You can have it hit multiple codes at once as well.
Examples:
Convert-TVCode -Code 123456
Convert-TVCode -Code 123456,6787682
Convert-TVCode -Code 123456,6787682,9837343 -Verbose
Update the switch statement in the function to customize it to your actual values and let me know if you have any questions!