Powershell Switch - Multiple Clauses - powershell

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 {
...
}
}

Related

How to use dism.exe to check whether Windows Features are turned on/off on Windows 7?

I use Get-WindowsOptionalFeature to check whether the Windows feature is turned on/off successfully, but Windows 7 does not support this instruction.
$IIS_InstallPro = "IIS-WebServerRole","IIS-WebServer","IIS-CommonHttpFeatures","IIS-HttpErrors"
#$features = Get-WindowsOptionalFeature -Online -FeatureName IIS*
$features = Dism /Online /Get-Features
function CheckIIS{
foreach($feature in $features)
{
if($feature.State -eq "Disabled" -and $IIS_InstallPro -match $feature.FeatureNmae)
{
return $False
}
}
return $true
}
CheckIIS
Should I use dism.exe to check and return the result?
Wanted to know if it's good practice to do that and what would be the best way to do that?
No, there is not a way to make those cmdlets work on Windows 7.
While you really shouldn't be using Windows 7 anymore, you should still be able to get this information from WMI. I don't recall if the Get-CimInstnace cmdlets were available on 7, so I'll use the Get-WmiObject method:
Function Get-WmiWindowsOptionalFeatures {
[CmdletBinding()]
Param(
[string]$FeatureName,
[ValidateSet('Enabled', 'Disabled', 'Absent', 'Unknown', '1', '2', '3', '4')]
[string]$InstallState
)
Get-WmiObject Win32_OptionalFeature | Where-Object {
$feature = $_
$featureMatch = !$FeatureName -or ( $FeatureName -and $feature.Name -like $FeatureName )
$installStateMatch = switch ( $InstallState ) {
{ $_ -in 'Enabled', '1' } {
$feature.InstallState -eq 1
break
}
{ $_ -in 'Disabled', '2' } {
$feature.InstallState -eq 2
break
}
{ $_ -in 'Absent', '3' } {
$feature.InstallState -eq 3
break
}
{ $_ -in 'Unknown', '4' } {
$feature.InstallState -eq 4
break
}
default {
$true
break
}
}
$featureMatch -and $installStateMatch
} | Select-Object Name, Caption, Description, InstallDate, #{
Label = 'InstallState'
Expression = {
switch ( $_.InstallState ) {
1 {
'Enabled'
break
}
2 {
'Disabled'
break
}
3 {
'Absent'
break
}
4 {
'Unknown'
break
}
default {
$_.ToString()
break
}
}
}
}
}
This will give you back a nice operable object with the important fields which can be evaluated and operated upon. The class you have to inspect is Win32_OptionalFeatures.
To use the function:
No arguments: returns all features
-FeatureName: returns features matching the Name. Supports -like patterns.
-InstallState: returns features matching the InstallState. Takes convenient strings or the numbered value as mapped below.
To understand the install state, here are the possible values for each (they are stored as a uint32):
Enabled
Disabled
Absent
Unknown
Unfortunately, there is no way to use WMI to install the features, so you'll have to install them with dism.exe.

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...
}
}

How to specify what to do if a Pester assertion fails?

If you wanted to say, 1 should equal 1, and if it doesn't then break, what would be the most eloquent way to do this in powershell with pester avoid code duplication?
Eg
{1 | should be 1} else {break}
rather than
1 | should be 1
if (1 -ne 1) {break}
There's no built in functionality for breaking the test execution when a failure occurs at the moment, but it has been discussed here: https://github.com/pester/Pester/issues/360 with some wrokarounds such as this one:
BeforeEach {
$FailedCount = InModuleScope -ModuleName Pester { $Pester.FailedCount }
if ($FailedCount -gt 0) {
Set-ItResult -Skipped -Because 'previous test failed'
}
}
Another option might be to break your tests up into several different Pester scripts. Then you could have some high level or initial tests that you check for success on first and if they have not all passed then you skip execution of the remaining test scripts.
For example:
$Failed = (Invoke-Pester -Path First.tests.ps1 -PassThru).FailedCount
If ($Failed -eq 0) {
Invoke-Pester -Path Second.tests.ps1
..
}
I landed here looking for a way to make one test have a dependency on another.
#Dependency in Pester v3.4.0
Describe 'testing pester' {
$dep = #{}
context 'when in here' {
It 'when the dependent test fails' {
$dep.aSpecificDependency = 'failed'
'a' | should be 'b'
$dep.aSpecificDependency = 'passed'
}
It 'then this is inconclusive' {
if($dep.ContainsKey('aSpecificDependency') -and $dep.aSpecificDependency -ne 'passed'){
Set-TestInconclusive -Message 'aSpecificDependency did not pass.'
}
'a' | should be 'a'
}
It 'and this should run fine' {
if($dep.ContainsKey('aDifferentDependency') -and $dep.aDifferentDependency -ne 'passed'){
Set-TestInconclusive -Message 'aDifferentDependency did not pass.'
}
'a' | should be 'a'
}
if($dep.ContainsKey('aSpecificDependency') -and $dep.aSpecificDependency -ne 'passed'){
return
}
It 'stops before running this one' {
'a' | should be 'a'
}
}
context 'when looking at another section' {
It 'goes fine' {
'a' | should be 'a'
}
}
if($dep.ContainsKey('aSpecificDependency') -and $dep.aSpecificDependency -ne 'passed'){
return
}
context 'when looking at another section' {
It 'or you could stop on that too' {
'a' | should be 'a'
}
}
}

PowerShell Switch Statement Issue

I have the following simple code and it isn't working (simplified from a much larger function)
The user in my first example doesn't exist in my use case
The switch statement doesn't work
A break-point (using ISE) on both the statements in the first switch never get triggered
The second example works without issue
The third code snippet is some troubleshooting code to prove $myADObject is null
What am I missing?
Snippet 1:
$user = "no.one"
$myADUsr = Get-ADObject -Filter { sAMAccountName -like $user }
switch ($myADUsr) {
$null { 'User object variable is null' }
default { 'User object variable has a value' }
}
Snippet 2:
$myADUsr = $null
switch ($myADUsr) {
$null { 'The variable is null' }
default { 'The variable has a value' }
}
Snippet 3:
clear-host
$member = "no.one"
$adobject = Get-ADObject -Filter { sAMAccountName -like $member }
'=== Frist switch ==='
switch ($adobject) {
{$null} { "tests as null"}
{$null -eq $_ } { 'another null test' }
{[string]::IsNullOrEmpty($_)} {'string null test'}
{$_ -eq [string]::Empty} { 'another string null test'}
{$null -ne $_ } { 'not null' }
default { "I don't think this is working ..." }
}
'==== if ====='
If ($null -eq $adobject) { 'null' } else { 'not null' }
'==== second switch ==='
$nullvariable = $null
switch ($nullvariable) {
$adobject { 'null object' }
$null { "null"}
default { "not null" }
}
The switch statement implicitly operates on collections (enumerable data types), and evaluates its branches for each element of the enumeration.
A function or cmdlet call that yields no output technically outputs the [System.Management.Automation.Internal.AutomationNull]::Value singleton, which can be conceived of as an array-valued $null - that is, in enumeration contexts such as switch it behaves like an empty collection: there's nothing to enumerate.
Therefore, because $myADUsr in your example contains [System.Management.Automation.Internal.AutomationNull]::Value due to Get-AdUser not producing any output, the switch statement is effectively skipped.
If all you need to know is whether an AD user object was returned, use PowerShell's implicit to-Boolean conversion in an if statement, because in an expression context [System.Management.Automation.Internal.AutomationNull]::Value behaves like $null (and therefore evaluates to $false):
$myADUsr = Get-ADObject -Filter 'sAMAccountName -like $user'
if ($myAdUsr) {
'User object variable has a value'
}
else {
'User object variable is null'
}
It think updating my original snippet #1 like this gets me out of trouble, it seems to work so I can continue to use the switch statement I have already written. I'm still testing.
$user = "no.one"
$myADUsr = Get-ADObject -Filter "sAMAccountName -like '$user'"
if ( #($myADUsr).Count -eq 0 ) { $myADUsr = $null }
switch ($myADUsr) {
$null { 'User object variable is null' }
default { 'User object variable has a value' }
}

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" }
}
}