powershellpowershell-jobs

Powershell: passing parameters to functions stored in variables


I'm trying to get a simple working example of using functions inside of jobs. I've managed to pass my function into the scriptblock used for my job, but I can't seem to get parameters to the function.

# concurrency
$Logx = 
{
    param(
    [parameter(ValueFromPipeline=$true)]
    $msg
    )    
    Write-Host ("OUT:"+$msg)
}

# Execution starts here
cls
$colors = @("red","blue","green")
$colors | %{
    $scriptBlock = 
    {   
        Invoke-Expression -Command $args[1]
        Start-Sleep 3        
    } 

    Write-Host "Processing: " $_
    Start-Job -scriptblock $scriptBlock -args $_, $Logx
}

Get-Job

while(Get-Job -State "Running")
{
    write-host "Running..."
    Start-Sleep 2
}

# Output
Get-Job | Receive-Job

# Cleanup jobs
Remove-Job * 

Here's the output:

Processing:  red
Id              Name            State      HasMoreData     Location             Command  
--              ----            -----      -----------     --------             -------  
175             Job175          Running    True            localhost               ...   
Processing:  blue
177             Job177          Running    True            localhost               ...   
Processing:  green
179             Job179          Running    True            localhost               ...   
179             Job179          Running    True            localhost               ...   
177             Job177          Running    True            localhost               ...   
175             Job175          Running    True            localhost               ...   
Running...
Running...
OUT:
OUT:
OUT:

So as evidenced by the OUT: x3 in the output my function is getting called, but I haven't found any syntax that allows me to get the parameter to the function. Thoughts?

EDIT:

Note in Shawn's observation below and my response I tried using functions as variables because using a traditional function does not seem to work. If there is a way to get that working I'd be more than happy to not have to pass my functions around as variables.


Solution

  • The answer is to use the initializationscript parameter of Start-Job. If you define all your functions in a block and pass the block they become available.

    Solution was found in this post:

    How do I Start a job of a function i just defined?

    Here is my example from before, now working:

    # concurrency
    $func = {
        function Logx 
        {
            param(
            [parameter(ValueFromPipeline=$true)]
            $msg
            )    
            Write-Host ("OUT:"+$msg)
        }
    }
    
    # Execution starts here
    cls
    $colors = @("red","blue","green")
    $colors | %{
        $scriptBlock = 
        {   
            Logx $args[0]
            Start-Sleep 9        
        } 
    
        Write-Host "Processing: " $_
        Start-Job -InitializationScript $func -scriptblock $scriptBlock -args $_
    }
    
    Get-Job
    
    while(Get-Job -State "Running")
    {
        write-host "Running..."
        Start-Sleep 2
    }
    
    # Output
    Get-Job | Receive-Job
    
    # Cleanup jobs
    Remove-Job *