Reputation: 76
I have a PowerShell function that I use to generate interactive menus on the fly. I pass values to an array name $mlist and then generate the menu based on the contents of the array. The user simply selects the number associated with their desired choice. The code works fine when the array contains 9 items or less. If the array contains more than 9 items, the only selection I can choose is "1". Choosing any other selection results in the menu being displayed again. I have it encapsulated in a while statement and this is the desired function when no item is selected. So basically it ignores any entry other than "1" when the array contains more than 9 items. Here is the code:
$global:ans = $null
$global:selection = $null
While ($ans -lt 1 -or $ans -gt $mlist.count){
$mhead
Write-Host # empty line
$menu = @{}
for ($i=1;$i -le $mlist.count;$i++) {
if ($mlist.count -gt 1){
Write-Host -fore Cyan " $i." $($mlist[$i-1])
$menu.Add($i,($mlist[$i-1]))
}else{
Write-Host -fore Cyan " $i." $mlist
$menu.Add($i,$mlist)
}
}
Write-Host # empty line
$global:ans = Read-Host 'Please enter selection'
}
$global:selection = $menu.Item([int]$ans)
Upvotes: 0
Views: 2139
Reputation: 29033
Read-Host reads a string, and this line:
While ($ans -lt 1 -or $ans -gt $mlist.count){
Compares it against numbers. In that kind of comparison, PowerShell casts the thing on the right to the type of the thing on the left. $ans
is "5"
and $mlist.count
becomes "12"
and string sorting puts them in order "12","5"
so it triggers $ans -gt $mlist.count
and loops again.
Fix: cast it to an integer.
$global:ans = Read-Host 'Please enter selection'
$global:ans = $global:ans -as [int]
It's a good practise to have fixed things on the left when testing equality/greater than/less than, and variables on the right, for this reason.
If I were commenting on the whole thing, I might rewrite it as:
$mlist = ('a')#,'b','c','d','e','f','g','h','i','j','k')
# Force $mlist to always be an array, even if only 1 thing in it, to remove if/then test.
$mlist = @($mlist)
$global:selection = $null
Do
{
$mhead
Write-Host # empty line
for ($i=0; $i -lt $mlist.count; $i++)
{
Write-Host -ForegroundColor Cyan " $($i+1)." $mlist[$i]
}
Write-Host # empty line
$global:ans = (Read-Host 'Please enter selection') -as [int]
} While ((-not $ans) -or (0 -gt $ans) -or ($mlist.Count -lt $ans))
$global:selection = $mlist[$ans - 1]
$global:selection
This gets rid of the if/then, it gets rid of the $menu
dictionary, it gets rid of initialising $ans first by using do/while.
Upvotes: 3