I am using the @ sign in a powershell menu and I am not exactly sure what it means:
function show-menu
{
$menu=@"
1 View vCenter Hosts & statistics
2 Display VM Guest statistics
3 Disply datastore statistics
4 Display VM snapshots
5 Change selected host to process
6 Backup Host and vSwitch configurations
7 Enter Host Maintenance Mode
8 Power off host VM's
9 Power on host VM's
10 Display Host VM GPU's
11 Display VM network interfaces
12 Clear ESXi host SEL log
Q Quit
Select a task by number or Q to quit
"@
cls
start-sleep -m 250
write-host
Write-Host "*** VM Utility Menu ***" -ForegroundColor Cyan
write-host
write-host "You have selected vCenter Server: " $vServer -ForegroundColor Green
write-host
$sel = Read-Host $menu
if ($sel -isnot [int]){
write-host "**Entry is incorrect, please choose a number from the menu**" -ForegroundColor Red
show-menu
}
Switch ($sel)
{
"1" {
Write-Host "View vCenter Hosts and statistics on" $Vserver -ForegroundColor Green
$VChostsStat = get-vmhost | Select Name,ConnectionState,PowerState,NumCpu,CpuUsageMhz,@{ n="MemoryUsedGB"; e={[math]::round( $_.MemoryUsageGB )}},@{ n="TotalMemoryGB"; e={[math]::round( $_.MemoryTotalGB )}},Version | ft
$VChostsStat
start-sleep -m 250
get-decision
}
"2" {
I am not quite sure what the $menu=@" and "@ are doing for me. Obviously it creates the list of menu items displayed on the screen but what’s the FUNCTION of the @ in this case, to build an array of menu items? Please explain a little, thanks.
#This is a short query, but imagine adding more or and...and...and
$query = "Select * From SomeDatabase Where SomeValue = 'SomeValue'"
#You try to make it more manageable to read...but you have to make sure you add spaces
$query = "Select * "
$query += "From SomeDatabase "
$query += "Where SomeValue = 'SomeValue'"
#Then comes the magical here string
$query = @"
Select *
From SomeDatabase
Where SomeValue = 'SomeValue'
"@
#Another common use is html or text that is indented
$query = @"
<html>
<head>
<title>Test</test>
</head>
<body>
<p>Some paragraph</p>
</body>
</html>
"@
#The only flaw or drawback is you cannot indent the lines with the @ symbols.
Not sure if this qualifies, but you can expand strings. For instance this would have HTML outline in the here-string and dynamically get services and add the HTML fragment:
Great point Rob. If the here-string is made with double quotes ", then it will evaluate expressions following a $ as in your example, but if you use single quotes ’ then everything would be literal.
Can someone tell me why THIS code does not consider $msel an integer? It’s basically the same code as above.
$maintmenu=@"
1 Check host connection state
2 Enter Maintenance Mode"
3 Enter Normal Mode
Select a task by number or Q to quit
"@
$msel = Read-Host $maintmenu
if ($msel -isnot [int]){
write-host “Selection is : $msel”
write-host “Entry is incorrect, please choose a number from the menu” -ForegroundColor Red
}
Switch ($msel)
{
1 {‘Check host connection state’}
2 {‘Enter Maintenance Mode’}
3 {‘Enter Normal Mode’}
default {‘No Action’}
}
Read-Host ALWAYS returns a string regardless of what the user types. You can convert it by either typecasting or using the toint32() string method. You might want to error check the user input first to make sure it can be converted.
typecasting
$msel = [int]$msel
ToInt32() method
$msel = $msel.toInt32($null)
Forgot to add if you want to error check you can use regex.
"12" -match "^[1-3]$"
This will return $true for “1”, “2” or “3” but $false for anything else.
Your code in the last post wasn’t formatted so I don’t see line numbers. One thing to note about PowerShell which could be the source on confusion is that it will automatically type convert an object if possible and needed. This is why you don’t always have to put quotes around strings. Here are some examples to illustrate what I mean:
Notice “15” + 3 PS treated the 3 as a string an concatenated, but in 3 + “15” it treated “15” as an integer and performed addition. The -like operator expects this syntax <string> -like <wildcard-expression> so PS converted the process object to strings to perform the comparison which is why 2 different processes (different IDs) came up as $true. I included the ToString() results so you can see what was actually compared.
I also re-wrote your menu below. Notice I didn’t do any explicit type conversions because PS will convert if needed. i.e. 1 -eq “1” is $true.
$maintmenu=@”
1 Check host connection state
2 Enter Maintenance Mode”
3 Enter Normal Mode
Select a task by number or Q to quit
“@
$errormsg = “**Entry is incorrect, please choose a number from the menu**”
do
{
$msel = Read-Host $maintmenu
$badentry = $msel -notmatch "^[1-3q]$"
if ($badentry) {write-host $errormsg -ForegroundColor Red}
}
while ($badentry)
Switch ($msel)
{
1 {‘Check host connection state’}
2 {‘Enter Maintenance Mode’}
3 {‘Enter Normal Mode’}
default {‘No Action’}
}
write-host “Number picked is $msel”
Finally got back to my coding, was busy fixing a down server. After actually using Winmerge to compare code I found that in fact you are 100%
correct. I was going back and forth between multiple things and thought the menu I described was in the old code, thus I thought it worked before. Wrong! I guess I had slipped new code in there and got sidetracked and thought it was there all along. I tried typecasting it and that works just fine. Thank you for your suggestions, and to everyone!