Switch-Case with multiple Values - powershell

I'm writing a code at the moment where I want to install network-shared printers automatically. Which printer the script should install depends on whether a user works for example in Sales or HR. I wanted to solve this problem with a switch statement, but the problem is that it always matches the first value.
I tried several combinations of continue- or break-points, but none of them lead to my desired result.
$a = "HR"
switch ($a) {
{"Marketing", "Sales"} { "1" }
{"Sales Department", "HR"} { "2" }
"EDV" { "3" }
}
Output:
1
2
Normally, the console output should be "2", but it is "1" "2".

Change the condition block to:
{$_ -in "Marketing", "Sales"}
This way both terms will match the switch case

In response to Mathias's answer, couldn't you also use:
$a = "HR"
switch($a){
"Marketing"{}
"Sales"{"1"; break}
"Sales Department"{}
"HR"{"2";break}
}
outputs:
2

Once you put in a scriptblock on the left side, it becomes more like a where clause.
$a | where {"Marketing", "Sales"}
Anything returned, like an array of two strings, gets taken as true. This would return 0 as well:
$a = "HR"
switch ($a) {
{"whatever"} { "0" }
{"Marketing", "Sales"} { "1" }
{"Sales Department", "HR"} { "2" }
"EDV" { "3" }
}
Another way to make it work:
$a = "HR"
switch ($a) {
{$_ -eq "Marketing" -or $_ -eq "Sales"} { "1" }
{$_ -eq "Sales Department" -or $_ -eq "HR"} { "2" }
"EDV" { "3" }
}
Or using the -regex option:
$a = "HR"
switch -regex ($a) {
"Marketing|Sales" { "1" }
"Sales Department|HR" { "2" }
"EDV" { "3" }
}

Related

Pester test if list is empty do not run the tests

I would like to be able to skip tests if list is empty.
a very simplified example:
No name is -eq to "jens", therefore the $newlist would be empty, and of course the test will fail, but how do i prevent it from going though this test if the list is empty?
context {
BeforeAll{
$List = #(Harry, Hanne, Hans)
$newlist = #()
foreach ($name in $List) {
if (($name -eq "Jens")) {
$name += $newlist
}
}
}
It "The maximum name length is 10 characters" {
$newlist |ForEach-Object {$_.length | Should -BeIn (1..10) -Because "The maximum name length is 10 characters"}
}
}
fail message:
Expected collection #(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) to contain 0, because The maximum name length is 10 characters, but it was not found.
You can achieve this by using Set-ItResult, which is a Pester cmdlet that allows you to force a specific result. For example:
Describe 'tests' {
context 'list with content' {
BeforeAll {
$List = #('Harry', 'Hanne', 'Hans')
$newlist = #()
foreach ($name in $List) {
if (($name -eq "Jens")) {
$newlist += $name
}
}
}
It "The maximum name length is 10 characters" {
if (-not $newlist) {
Set-ItResult -Skipped
}
else {
$newlist | ForEach-Object { $_.length | Should -BeIn (1..10) -Because "The maximum name length is 10 characters" }
}
}
}
}
Note that there was an error in your example ($newlist wasn't being updated with name, you were doing the reverse) which I've corrected above, but your test doesn't actually fail for me in this example (before adding the Set-ItResult logic). I think this is because by using ForEach-Object with an empty array as an input the Should never gets executed when its empty, so with this approach your test would just pass because it never evaluates anything.

PowerShell: Multiple Conditions within IF Statement

Im struggling to understand why the following IF statement doesn't work...
I have a PS array:
$lunchArray = #('Pizza', 'Sushi', 'Sandwich')
However the following Foreach/IF statement doesn't work as expected.
foreach ($lunch in $lunchArray) {
if ($lunch -eq 'Pizza' -and $lunch -eq 'Sushi') {
"YAY" # not working...
}
}
What am I doing wrong here?
TIA
$lunchArray = #('Pizza', 'Sushi', 'Sandwich')
foreach ($lunch in $lunchArray) {
if ('Pizza' -eq $lunch -or 'Sushi' -eq $lunch) {
"YAY" # not working...
}
}

Powershell Switch - Multiple Clauses

I'm creating a script that will be updating an Excel spreadsheet depending on conditions.
This is what I currently have:
if ($endIRs -ne $null) {
$endIRs | ForEach-Object {
try {
$classification = $_.Classification
$priority = $_.Priority
$title = $_.Title
$id = $_.Id
switch ($classification) {
{($_ -eq 'Reports') -and ($priority -eq '1')} {
$GeAppsReportSheet.Cells.Item(8,2).Interior.ColorIndex = 3
$GeAppsReportSheet.Cells.Item(8,2) = 'RED'
}
#more switch statements to go here
}
catch {#catch tickets with $classification not listed}
}
}
The $endIRs at the start holds a series of high priority 'incidents' that have been logged in the last 12 hours. If there is none, everything will be 'GREEN' which is set by default.
What I am trying to achieve with the switch statement is if (($classification -eq 'Reports') -and ($priority -eq '1')) {'change the cell colour and text'} which I can do on its own, but I need it to check if the priority is "1" or "2" and do something different against the "Reports" classification cell in the spreadsheet.
Can you do an if statement within the switch statement, or is there a better way to do it?
You can use $true as the switch condition and put the checks as scriptblock values:
switch ($true) {
{($classification -eq 'Reports') -and ($priority -eq '1')} {
...
}
# ...
# more switch statements to go here
# ...
default {
...
}
}
I never really liked this approach, though. Always looked like an ugly hack to me. I'd prefer a if..elseif..else control structure:
if ($classification -eq 'Reports' -and $priority -eq '1') {
...
} elseif (...) {
...
} elseif (...) {
...
} else {
...
}
Edit: Of course you can also use a "regular" switch statement and nest other conditionals in the action scriptblocks:
switch ($classification) {
'Reports' {
if ($priority -eq '1') {
...
} elseif ($priority -eq '2') {
...
}
}
# ...
# more switch statements to go here
# ...
default {
...
}
}

to avoid null characters in powershell

$q = 0
do {
$a = write-input "enter value"
switch ($a) {
1.{ some option }
2.{}
default {}
}
} while ($a -gt $q)
In the above code, if we give $a=$null value then switch terminates from while loop. Please help me out to skip null checking and to continue in the loop.
As Ansgar Wiechers points out in the comments, the comparison $null -gt 0 is False. This terminates your While loop. You could update your while statement to while ($a -eq $null -or $a -gt $q)
Another alternative would be use a recursive function,
function Example-Function {
switch (Read-Host "Enter Value") {
1 { "Option 1"; Example-Function }
2 { "Option 2"; Example-Function }
default { "Invalid Option, Exiting" }
}
}

Clumsy function in Powershell - ideas to make it succinct?

I have just written a simple function in Powershell
Function Get-Stage
{
$myEnv = Get-Environment
$devEnvs = "D","Dev","Test","T"
$prodEnvs = "P","U","PTA","B"
if($devEnvs -contains $myEnv)
{
return "D"
}
elseif($prodEnvs -contains $myEnv)
{
return "P"
}
}
EDIT
Get-Environment is a function that reads the registry to find the environment text which can be any string value listed in $devEnvs and $prodEnvs. The function will just return either a D or a P based on what is returned from Get-Environment
I don't like it. Is there a nice readable, concise way to write it that you can think of?
Well, questions on better ways to write code is very much based on different opinions, but you could do something like the following:
function Get-Stage
{
$environment = Get-Environment
switch ($environment)
{
{$PSItem -in "D","Dev","Test","T"}{
Write-Output "D"
}
{$PSItem -in "P","U","PTA","B"}{
Write-Output "P"
}
default{
Write-Error "Invalid environment value in registry ('$PSItem')"
}
}
}
If you want to support PowerShell v2, just change the switch statement to the following:
switch ($environment)
{
{"D","Dev","Test","T" -contains $_}{
Write-Output "D"
}
{"P","U","PTA","B" -contains $_}{
Write-Output "P"
}
default{
Write-Error "Invalid environment value in registry ('$_')"
}
}
Does this make it any better?
Function Get-Stage
{
$myEnv = Get-Environment;
$envDict = #{
"D" = #("Dev","Test","T");
"P" = #("U","PTA","B")
};
$envDict.Keys | foreach {
$envs = #($_) + $dict[$_];
if($envs -contains $myenv) { return $_; }
}
}