1

I am trying to start a function with start-job. For some reason, I cannot get it to work, the global variables wont pass. My question would be - how to pass global variables to the function and than to start-job without declaring them inside the function. Function example:

 $OutputDirectory=c:\test
 $zipfile="c:\1.zip"

    function 7zipextraction
{
    Set-Alias 7zip $7zip_path
    # Extracting files
    $extract = 7zip x -y $zipfile -o"$OutputDirectory"
    if ($LASTEXITCODE -ne 0)
    {
        
        write-host "7zip Error"
        
        return
    }
    else
    {
        write-host "Files extracted successfully"
    }
    Start-Sleep -s 2
    
}

Examples from start-job:

Start-Job -ScriptBlock ${Function:7zipextraction} | Wait-Job | Receive-Job
Rusty cole
  • 90
  • 9

2 Answers2

3

Start-Job dispatches the job to a separate child process, which is why it doesn't have access to the variables you've defined in the calling process.

Parameterize all variables in the function and then pass the appropriate arguments explicitly to Start-Job -ArgumentList:

function 7zipextraction
{
    param(
        [string]$ZipFile,
        [string]$OutputDirectory,
        [string]$7zipPath
    )

    Set-Alias 7zip $7zipPath -Force

    # Extracting files
    $extract = 7zip x -y $zipfile -o"$OutputDirectory"
    if ($LASTEXITCODE -ne 0)
    {
        write-host "7zip Error"
        return
    }
    else
    {
        write-host "Files extracted successfully"
    }
    Start-Sleep -s 2
}

Start-Job -ScriptBlock ${Function:7zipextraction} -ArgumentList "c:\1.zip","c:\test","c:\path\to\7zip\7z.exe" | Wait-Job | Receive-Job
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
2

You can use the using: modifier to access variables that are outside your script block:

$OutputDirectory='c:\test'
$zipfile='c:\1.zip'
$7zippath = 'C:\path\to\7zip'

function 7zipextraction
{
    Set-Alias 7zip $using:7zippath
    # Extracting files
    $extract = 7zip x -y $using:zipfile -o"${using:OutputDirectory}"
    if ($LASTEXITCODE -ne 0)
    {
        
        write-host "7zip Error"
        
        return
    }
    else
    {
        write-host "Files extracted successfully"
    }
    Start-Sleep -s 2
    
}

Start-Job -ScriptBlock ${Function:7zipextraction} | Receive-Job -Wait -AutoRemoveJob

using works with script blocks executed on remote computers or in a different thread:

  • Invoke-Command
  • Start-Job
  • Start-ThreadJob
  • ForEach-Object -Parallel
antonyoni
  • 849
  • 5
  • 11
  • Thanks!! And what if I have a variable with extension? example - $progressbar1.Name I tried - $using:progressbar1.Name – Rusty cole Jan 18 '22 at 12:10
  • 1
    No problem! Try: `($using:progressbar1).Name` – antonyoni Jan 18 '22 at 12:35
  • Thanks !! it worked. Now what about calling a global function from the 7zipextraction? Is it possible? I get function name is not recognized – Rusty cole Jan 18 '22 at 14:25
  • Start-Job fires up another instance of powershell to run the ScriptBlock passed to it. All the variables prepended with using get serialized and then passed to the new powershell instance. There's no access to the scope from which Start-Job is called. You can save your global function in a file and dot-source that file in 7zipextraction, or if it's a function from a module, you have to explicitly import that module in your 7zipextraction function. – antonyoni Jan 19 '22 at 15:09