0

I have the following code which reads an XML file, outputs the nodes and presents the user with a prompt to input a choice. For some reason, no matter what I put in, it always says "Invalid Choice". What am I doing wrong?

$buildsFile = [System.Xml.XmlDocument](Get-Content "$($config.remotebuildspath)/builds.xml");
$builds = $buildsFile.builds;

$i = 0
$buildHash = @{}
Write-Host "Available Builds: " -ForeGroundColor Green
ForEach ($buildVersion in $builds.ChildNodes) {
    $i++
    Write-Host "(" -NoNewline  -ForeGroundColor Green
    Write-Host $i -NoNewline
    Write-Host ") $($buildVersion.LocalName)"  -ForeGroundColor Green
    $buildHash.add($i, $buildVersion.LocalName)
}
$isValid = $false
do {
    Write-Host "Choose: " -NoNewline -ForeGroundColor Green
    $choice = Read-Host
    if ($buildHash.ContainsKey($choice)) {
        $isValid = $true
    } else {
        Write-Host "Invalid Choice!" -ForeGroundColor Red
        $isValid = $false
    }
} while ($isValid -eq $false)
Write-Host "You picked ${$buildHash[$choice]}"

Debugger screenshots:

enter image description here

enter image description here

  • 2
    You read `String` choices but have `Int32` keys; these will never compare equal as objects. PowerShell's flexible typing isn't actually helping here. You'll need an explicit `[int]` or `[string]` cast. – Jeroen Mostert Dec 18 '19 at 14:13
  • Out of curiosity, why did you not make that an answer? –  Dec 18 '19 at 14:13
  • 1
    I don't like writing trivial answers, even if they're perfectly apt for the question. A complete answer shows the fixed code, explains the problem more precisely, yada yada, too much work. Anyone else (including you) is free to use my comment to put in the legwork and score the points. (Also, there may well be a duplicate question that covers this as it seems like the kind of problem that other people have hit before -- which I'm also too lazy to search for.) – Jeroen Mostert Dec 18 '19 at 14:15

1 Answers1

0

Based on @Jeroen Mostert's comment, I added [int]$choice to the if statement. To avoid throwing an error on non-numerical input, I also incorporated the helper function Is-Numeric from this answer.

Here is my final code:

function Is-Numeric ($Value) {
    return $Value -match "^[\d\.]+$"
}

$buildsFile = [System.Xml.XmlDocument](Get-Content "$($config.remotebuildspath)/builds.xml");
$builds = $buildsFile.builds;

$i = 0
$buildHash = @{}
Write-Host "Available Builds: " -ForeGroundColor Green
ForEach ($buildVersion in $builds.ChildNodes) {
    $i++
    Write-Host "(" -NoNewline  -ForeGroundColor Green
    Write-Host $i -NoNewline
    Write-Host ") $($buildVersion.LocalName)"  -ForeGroundColor Green
    $buildHash.add($i, $buildVersion.LocalName)
}
$isValid = $false
do {
    Write-Host "Choose: " -NoNewline -ForeGroundColor Green
    $choice = Read-Host
    if (Is-Numeric $choice) {
        if ($buildHash.ContainsKey([int]$choice)) {
            $isValid = $true
        } else {
            Write-Host "Invalid Choice!" -ForeGroundColor Red
            $isValid = $false
        }
    } else {
        $isValid = $false
        Write-Host "Please enter a number!" -ForegroundColor Red
    }
} while ($isValid -eq $false)
Write-Host "You picked ${$buildHash[$choice]}"