to avoid null characters in powershell - 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" }
}
}

Related

Switch-Case with multiple Values

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

Check if user input is a number and then select from switch to print

Code:
[int]$s = Read-Host "Enter number from 1-3"
switch ($s) {
1 { $s = 'Apple' }
2 { $s = 'Melon' }
3 { $s = 'Mango' }
}
$s
Output:
Cannot convert value "Apple" to type "System.Int32". Error
input was not in correct format.
So my question is: How do I check if my input is a number and at the same time select from my switch?
The problem with your code is that after you define $s as an integer, you then later try to assign a string value to it.
You could instead do this:
[int]$s = Read-Host "Enter number from 1-3"
$result = switch ($s) {
1 { 'Apple' }
2 { 'Melon' }
3 { 'Mango' }
}
$result
Note that i'm also simplifying your code here by returning the result of the switch to $result instead of assigning it inside each condition.
This works because $result is an undefined variable that becomes a string when you assign one to it.
If you want to validate that the input is an integer, you could also consider doing something like this:
$input = Read-Host "Enter number from 1-3"
if (($input -isnot [int])) { Throw 'You did not provide a number as input' }
$result = switch ($input) {
1 { 'Apple' }
2 { 'Melon' }
3 { 'Mango' }
}
$result
You don't need to use the integer to declare the variable:
$s = Read-Host "Enter number from 1-3"
switch ($s) {
1 { $s = 'Apple' }
2 { $s = 'Melon' }
3 { $s = 'Mango' }
}
$s
And if you check the type of variable:
When you have a predefined set of options like this, consider using a multiple-choice menu, like this:
$title = "Select Fruit"
$prompt = "Which fruit is your favorite?"
$apple = New-Object System.Management.Automation.Host.ChoiceDescription "&Apple","Apple"
$melon= New-Object System.Management.Automation.Host.ChoiceDescription "&Melon","Melon"
$mango= New-Object System.Management.Automation.Host.ChoiceDescription "Man&go", "Mango"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($apple, $melon, $mango)
$selectedFruit = $host.ui.PromptForChoice($title, $prompt, $options, 0)
switch($selectedFruit)
{
0 {Write-Host "You chose Apple"}
1 {Write-Host "You chose Melon"}
2 {Write-Host "You chose Mango"}
}
In the ISE, the user will see a GUI prompt, with buttons to click on, and at the console, a menu with specific allowed letters to select (A, M and G in this case).
This method has the benefit that it looks like a typical prompt from PowerShell and will check and re-prompt if the user enters an invalid value. You can add a 'quit' option, so the user has an easy way to skip all options.
How do I check if my input is a number and at the same time select from my switch?
How do you check if your input is a number? - I think you are already doing that since you are declaring you variable $s as [int] at the very beginning -
[int]$s = Read-Host "Enter number from 1-3"
Selecting from your switch - The error which you are getting is due to the type mismatch of your input to the read-host and the variable $s. $s is clearly an integer where as you are assigning it a string. Hence, the error You have to type-cast that again in order to correct that -
[int]$s = Read-Host "Enter number from 1-3"
switch ($s) {
1 { [string]$s = 'Apple' }
2 { [string]$s = 'Melon' }
3 { [string]$s = 'Mango' }
}
$s
If you enter any number other than 1, 2 or 3, then you $s will store that number in it. For example if you enter 5, $s will store 5 in it since the switch statement hadn't been executed.
function Verify-InputInteger {
Param (
$Question="Saisir un nombre",
$Min=0,
$Max=100
)
try {
[int]$string_Input = Read-Host $Question;
if($string_Input -LT $Min)
{
Throw "ErrorMin"
}
if($string_Input -GT $Max)
{
Throw "ErrorMax"
}
return $string_Input;
}
catch {
if($_.FullyQualifiedErrorId -EQ 'InvalidCastFromStringToInteger')
{
Write-Host 'You did not provide a number as input' -ForegroundColor Red;
Verify-InputInteger -Question $Question -Min $Min -Max $Max;
}
if($_.Exception.Message -EQ 'ErrorMin')
{
Write-Host 'You have entered a number lesser than the minimum limit' -ForegroundColor Red;
Verify-InputInteger -Question $Question -Min $Min -Max $Max;
}
if($_.Exception.Message -EQ 'ErrorMax')
{
Write-Host 'You have entered a number greater than the maximum limit' -ForegroundColor Red;
Verify-InputInteger -Question $Question -Min $Min -Max $Max;
}
}
}

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

Extracting the function body from a file using powershell

How can i extract the content of a powershell function definition?
Suppose the code is like,
Function fun1($choice){
switch($choice)
{
1{
"within 1"
}
2{
"within 2"
}
default{
"within default"
}
}
}
fun1 1
I want only the contents of the function definition and no other text.
Using PowerShell 3.0+ Language namespace AST parser:
$code = Get-Content -literal 'R:\source.ps1' -raw
$name = 'fun1'
$body = [Management.Automation.Language.Parser]::ParseInput($code, [ref]$null, [ref]$null).
Find([Func[Management.Automation.Language.Ast,bool]]{
param ($ast)
$ast.name -eq $name -and $ast.body
}, $true) | ForEach {
$_.body.extent.text
}
Outputs a single multi-line string in $body:
{
switch($choice)
{
1{
"within 1"
}
2{
"within 2"
}
default{
"within default"
}
}
}
To extract the first function definition body regardless of name:
$body = [Management.Automation.Language.Parser]::ParseInput($code, [ref]$null, [ref]$null).
Find([Func[Management.Automation.Language.Ast,bool]]{$args[0].body}, $true) | ForEach {
$_.body.extent.text
}
To extract the entire function definition starting with function keyword, use $_.extent.text:
$fun = [Management.Automation.Language.Parser]::ParseInput($code, [ref]$null, [ref]$null).
Find([Func[Management.Automation.Language.Ast,bool]]{$args[0].body}, $true) | ForEach {
$_.extent.text
}

Output true value for Foreach statement

I am trying to output the value which checks if the condition matches, but instead its returning value whether it is true or not.
$result = "VM name"
$name= get-content C:\monitor\Serverlist\Serverlist2.txt
foreach($nam1 in $name)
{
#Write-output $nam1
$l=Get-Vm -computername $nam1 |out-string
foreach ($l2 in $l)
{
if ( $l2 = $result )
{
Write-Output $input "is in" $nam1
}
else
{
""
}
}
}
but output i am getting is true in all case, where as VM name is present in comp1 only.
VM name is in comp1
VM name is in comp2
VM name is in comp3
If statement should return condition if it matches? I also tried looping if statement outside 1st foreach loop but that gives me result of last comp "comp3" even the matching result is in comp1.
Any Idea where I am going wrong?
The = sign not for conditional testing, it's for setting the value:
if ( $l2 = $result )
{
Write-Output $input "is in" $nam1
}
Should be... (note that I'm using -eq to test equality)
if ( $l2 -eq $result )
{
Write-Output $input "is in" $nam1
}
But even that wouldn't work. Your conditional test between a string and a VirtualMachine object won't work. Here's what you want...
if ( $l2.Name -eq $result )
{
Write-Output $input "is in" $nam1
}
In the above snippet, I'm doing a conditional test on VirtualMachine.Name (type string) with your variable.