Home > Software design >  Not able to call a function recursively in Powershell
Not able to call a function recursively in Powershell

Time:01-18

I am creating a menu driven Script for the users to perform certain actions based on the the options they choose. Just in case they select a wrong option, I am trying to display the choices again after displaying appropriate message. However, whenever any wrong choice is selected, and the function is being called from within itself, I am getting a ParseException instead. Can you please see if something is wrong here?

Class O_Manager {
      
                 [int]$val

                 ShowMenu() {                                                                                                                                           
                                Write-Host "    Please choose from below Options : "                       
                                Write-Host "                                     "                                           
                                Write-Host "       1. Option1 "
                                Write-Host "       2. Option2 "
                                Write-Host "       3. Option3 "

                                $this.val = Read-Host "    Enter your Choice here "

                                switch($this.val)
                                {
                                                1 {"ONE"}
                                                2 {"TWO"}
                                                3 {"THREE"}
                                                default {"Incorrect choice selected" 
                                                         ShowMenu()}
                                }

}
}

$obj = New-Object O_Manager
$obj.ShowMenu()

CodePudding user response:

PowerShell interprets the bareword token ShowMenu as a command name (eg. the name of a cmdlet, function, script or executable), but ShowMenu is not a command - it's a method attached to instances of the [O_Manager] class.

To invoke ShowMenu recursively, refer to the current instance via the $this variable:

default {
    "Incorrect choice selected" 
    $this.ShowMenu()
}

Rather than recursively calling ShowMenu from within itself, I'd recommend refactoring your class to have a common entry point that repeatedly calls ShowMenu in succession instead of recursively - in my experience this usually makes the code much easier to reason about and troubleshoot.

In the example below, the entry point is called REPL (because it implements a Read-Eval-Print-loop), and it just calls the ShowMenu, Eval and Print functions until the menu or eval functions tell it to stop:

enum Outcome
{
    Continue
    Quit
}

Class O_Manager {
      
    [int]$val
    [string]$result

    REPL() {
        while($this.ShowMenu() -eq 'Continue' -and $this.Eval() -eq 'Continue'){
            $this.Print()
        }
    }

    Print() {
        Write-Host $this.result -ForegroundColor Cyan
    }

    [Outcome]
    Eval() {
        # do something with $this.result here

        return [Outcome]::Continue
    }

    [Outcome]
    ShowMenu() {                                                                                                                                           
        Write-Host "    Please choose from below Options : "                       
        Write-Host "                                     "                                           
        Write-Host "       1. Option1 "
        Write-Host "       2. Option2 "
        Write-Host "       3. Option3 "

        try {
            $this.val = Read-Host "    Enter your Choice here "
        }
        catch {
            Write-Host "Error encountered: $_" -ForegroundColor Yellow
            return [Outcome]::Quit
        }
        $this.result = switch ($this.val) {
            1 { "ONE" }
            2 { "TWO" }
            3 { "THREE" }
            default {
                $this.result = "Incorrect choice selected"
                return [Outcome]::Quit
            }
        }

        return [Outcome]::Continue
    }
}
  •  Tags:  
  • Related