7

Alright. I'm attempting to complete a school assignment and cannot for the life of me figure this out. I'm trying to use powershell to pass values from one function to another making a "modular" type script. I can't seem to figure out how to move the values out of the scope of the function without using the $script:xxxxx. Is there another way to move the values in powershell as a regular argument parameter pass by reference?

Here's what I have:

function main
{
inputGrams($carbGrams, $fatGrams)
$carbGrams
$carbGrams
calcGrams
displayInfo
}

function inputGrams([ref]$carbGrams, [ref]$fatGrams)
{
    $carbGrams = read-host "Enter the grams of carbs per day"
    $fatGrams = read-host "Enter the grams of fat per day"
}

function calcGrams
{
    $carbCal = $carbGrams * 4
    $fatCal = $fatGrams * 9
}

function displayInfo 
{
    write-host "The total amount of carb calories is $carbCal" 
    write-host "The total amount of fat calories is $fatCal"
}

main

The two values right after the inputGrams function should change each time the script is run but they don't because of scope issues and passing the values. Anyone know how to properly pass those values back to the main function?

Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
Bionic
  • 93
  • 1
  • 1
  • 4
  • What part is homework, calculating nutrition information or writing a PowerShell script? If the latter I like your school :-) – Andy Arismendi Feb 10 '12 at 05:37

2 Answers2

15

There are a few problems. First here's a working example:

function main
{
    # 1. Create empty variable first.
    New-Variable -Name carbGrams
    New-Variable -Name fatGrams

    # 2. Spaces in between parameters. Not enclosed in parens.
    # 3. Put REF params in parens.
    inputGrams ([ref]$carbGrams) ([ref]$fatGrams)

    $carbGrams
    $fatGrams
}

function inputGrams( [ref]$carbGrams, [ref]$fatGrams )
{
    # 4. Set the Value property of the reference variable.
    $carbGrams.Value = read-host "Enter the grams of carbs per day"
    $fatGrams.Value = read-host "Enter the grams of fat per day"
}

main

And explanation:

  1. You'll need to create the variable before passing it by REF.
  2. Don't enclose PowerShell function params in parens, just separate them with spaces.
  3. Put the REF arguments in parens.
  4. To set the REF variable's value, you'll need to set the Value property.
Andy Arismendi
  • 50,577
  • 16
  • 107
  • 124
0

Andy is on the right path but [Ref] are tricky and it is recommended to avoid them if you can.

As you said, the problem is scope. All your functions —except main— are called from main, therefore you need to make the variables available to these functions by setting them in main's scope, i.e. their parent scope, with Set-Variable or New-Variable.

Same point is valid when retrieving their values with Get-Variable.

function main
{
    inputGrams
    $carbGrams
    $fatGrams
    calcGrams
    displayInfo
}

function inputGrams
{
    # type constrain as Single because Read-Host returns a String
    [single]$carbs = read-host "Enter the grams of carbs per day"
    [single]$fat = read-host "Enter the grams of fat per day"

    # scope 1 is the parent scope, i.e. main's scope
    Set-Variable -Name carbGrams -Value $carbs -Scope 1
    Set-Variable -Name fatGrams -Value $fat -Scope 1
}

function calcGrams
{
    # scope 1 is the parent scope, i.e. main's scope
    Set-Variable -Name carbCal -Value ($carbGrams * 4) -Scope 1
    Set-Variable -Name fatCal -Value ($fatGrams * 9) -Scope 1
}

function displayInfo 
{
    # scope 1 is the parent scope, i.e. main's scope
    $_carbCal = Get-Variable -Name carbCal -Scope 1 -ValueOnly
    $_fatCal = Get-Variable -Name fatCal -Scope 1 -ValueOnly

    write-host "The total amount of carb calories is $_carbCal" 
    write-host "The total amount of fat calories is $_fatCal"
}

main

PS: I hope I did not spoil your school assignment, just wanted to help out ;)

zx38
  • 114
  • 2
  • Reference to avoidance recommendation? – Andy Arismendi Feb 10 '12 at 05:26
  • Bruce's example behaved liked I would of expected... I wouldn't of chosen REF myself however I think it's fine for the OP's scenario. I on the other hand typically try to have a function return values if it's expected to produce something so easy to see what scope the data is in. – Andy Arismendi Feb 10 '12 at 06:13
  • True, I only use [ref] in COM such as Office's APIs and only when is necesary do I use them in function/scripts, e.g. tokenizing. Hopefully the OP has a better grasp in two of the most thorny issues in PowerShell, [ref] and scoping. – zx38 Feb 10 '12 at 06:57
  • Working with COM can be pretty thorny too :-( Check [this](http://stackoverflow.com/questions/8743122/how-to-find-msi-product-version-number-using-powershell) out. – Andy Arismendi Feb 10 '12 at 17:49
  • A couple of other ways to aviod using [ref] is to use a hash table in the parent scope to store the values, an write the function to work with the hashtable keys instead of discrete variables, or run the fuction in the current scope using dot-sourcing (. function) – mjolinor Feb 10 '12 at 19:06
  • Thanks for the help guys. All those ways actually worked. Looks like I was forgetting to declare the variables first in the main function. :p That would cause scope issues. Why is it in powershell we try to avoid using the [ref] so much? – Bionic Feb 11 '12 at 23:45
  • Writing code that changes the value of variables outside the scope of the function or parameters is REALLY bad software engineering. – spongyryno May 15 '22 at 20:26