Question

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.

Was it helpful?

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 * 

OTHER TIPS

If you do not prefix your function name with keyword function, PowerShell does not know to treat it as such. As you have written your script it is basically a variable with some special text in it. Which as your output shows it is only executing the commands it recognizes within that variable's content: Write-Host "OUT:".

Using the correct syntax will tell PowerShell it is a function and that you have variables to pass into it that you need executed:


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

Then when you call it within your script you will just use Logx

Got this far. Have to run out, will try back later. PS: What is getting passed at args[1], I am getting a lot of red,

 CategoryInfo          : InvalidData: (:) [Invoke-Expression], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.InvokeExpressionCommand

here is what I've managed so far.

# 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 -ArgumentList @($_, $Logx)
}

# Get-Job

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

# Output
Get-Job | Receive-Job

# Cleanup jobs
Remove-Job * 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top