Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

$_ variable used in function from a module is empty (PowerShell)

One question for you is here ;)

I have this function:

function Set-DbFile {
    param(
        [Parameter(ValueFromPipeline=$true)]
        [System.IO.FileInfo[]]
        $InputObject,
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [scriptblock]
        $Properties
    )
    process {
        $InputObject | % { 
            Write-Host `nInside. Storing $_.Name
            $props = & $Properties
            Write-Host '  properties for the file are: ' -nonew
            write-Host ($props.GetEnumerator()| %{"{0}-{1}" -f $_.key,$_.Value})
        }
    }
}

Look at the $Properties. It should be evaluated for each file and then the file and the properties should be processed further.

Example how to use it might be:

Get-ChildItem c:\windows |
    ? { !$_.PsIsContainer } |
    Set-DbFile -prop { 
        Write-Host Creating properties for $_.FullName
        @{Name=$_.Name } # any other properties based on the file
    }

When I copy & paste function Set-dbFile to command line and run the example snippet, everything is fine.

However, when I store the function in a module, import it and run the example, the $_ variable is empty. Does anybody know why? And how to solve it? (other solutions are welcome as well)


Results for function defined in a script/typed in commandline:

Inside. Storing adsvw.ini
Creating properties for C:\windows\adsvw.ini
  properties for the file are: Name-adsvw.ini

Inside. Storing ARJ.PIF
Creating properties for C:\windows\ARJ.PIF
  properties for the file are: Name-ARJ.PIF
....

Results for function defined in module:

Inside. Storing adsvw.ini
Creating properties for
  properties for the file are: Name-

Inside. Storing ARJ.PIF
Creating properties for
  properties for the file are: Name- 
....
like image 845
stej Avatar asked Jun 07 '11 11:06

stej


1 Answers

The problem here is down to scope hierarchy. If you define two functions like...

function F1{
    $test="Hello"
    F2
}
function F2{
    $test
}

Then F2 will inherit the variable scope of F1 since it's called from F1's scope. If you define function F2 in a module and export the function the $test variable is not available since the module has it's own scope tree. See the Powershell Language Specification (Section 3.5.6):

In your case the current node variable is defined in the local scope and hence it will not survive into the module scope since it's in a different tree with a different scope root (apart from global variables).

To quote the text on the GetNewClosure() method in the Powershell Language Specification (Section 4.3.7):

Retrieves a script block that is bound to a module.Any local variables that are in the context of the caller will be copied into the module.

...hence GetNewClosure() works a treat since it bridges the local scope/module divide. I hope this helps.

like image 149
CosmosKey Avatar answered Oct 25 '22 16:10

CosmosKey