Seth Spearman
Seth Spearman

Reputation: 6780

Powershell line of code does not run when called through function but will run directly. What could be possible causes?

I have a powershell script with the following code in it...

$appdir = Split-Path -Path $MyInvocation.MyCommand.Path
$xfrdir = $appdir + "\xfr\"
$cfgFile = "ofx_config.cfg"
$cfgPath = $appdir + "\" + $cfgFile
$configData = New-Object System.Collections.ArrayList
#  --- some other code here...
function Load-Config () 
{
    if (test-path ($cfgPath))
    {
        $configData = Import-Clixml -path "$cfgPath"
    } 
}
#  ---some other code here
load-config

When I just RUN this script in the ps ISE, load-config runs because it is at the end of script (i verified this with a breakpoint) but the $configData variable remains empty.

But if I immediately copy and past the line $configData = Import-Clixml -path "$cfgPath" into the powershell command line and run it then $configData is loaded with data. Does anyone have any ideas what might be going on?

EDIT
I think that what you are saying is that $configData in $configData = Import-Clixml -path "$cfgPath" is being treated as a whole separate variable (and is local to the function) because of scoping rules. I thought it would be more like a c# class and so would assign to the script level variable of the same name.

I am LOVING powershell but dynamic typing does make things trickier.

EDIT 2
Both answers were insightful. In such a case I usual give the answer to the person with the fewest reputation. And I did in fact Andy's second example in any case.

Seth

Upvotes: 0

Views: 2597

Answers (2)

Andy Arismendi
Andy Arismendi

Reputation: 52609

You have a scoping issue with variable $configData. When you set it's value in the function it is not available outside. You can use a scope modifier to fix it or return the value.

Check out get-help about_scopes or click here.

Scope Modifier:

$cfgPath = 'C:\Test.xml'
$script:configData = New-Object System.Collections.ArrayList

function Load-Config () 
{
    if (test-path ($cfgPath))
    {
        $script:configData = Import-Clixml -path "$cfgPath"
    }
}
load-config
$configData

Note - Your ArrayList gets overwritten using Import-Clixml and is a different type on return.

Return the new value:

$cfgPath = 'C:\Test.xml'
function Load-Config () 
{
    if (test-path ($cfgPath))
    {
        $data = Import-Clixml -path "$cfgPath"
        return $data
    }
}
$configData = load-config

Upvotes: 2

stej
stej

Reputation: 29449

You create new variable with name $configData. You have several options (depending on your environment/script/...)

The most obvious is - just return the value and assign it to config data

function Load-Config () 
{
    if (test-path ($cfgPath))
    {
        Import-Clixml -path "$cfgPath"
    } 
}
$configData = load-Config

You might also use object and its property like this:

$configData = @{Data = $null}
function Load-Config () 
{
    if (test-path ($cfgPath))
    {
        $configData.Data = Import-Clixml -path "$cfgPath"
    } 
}

Or it is possible to use script: scope:

function Load-Config () 
{
    if (test-path ($cfgPath))
    {
        $script:configData = Import-Clixml -path "$cfgPath"
    } 
}

Upvotes: 4

Related Questions