2

I need to initialize a job using the shell. The job will be a delay plus a call to a vbScript. The following code works fine. For my example, the vbScript is just a single line with a MsgBox "Hello world!"

$functions = {
    Function execute_vbs {
        param ([string]$path_VBScript, [int]$secs)
        Start-Sleep -Seconds $secs
        cscript /nologo $path_VBScript 
    }
}
$seconds = 2
Start-Job -InitializationScript $functions -ScriptBlock {execute_vbs -path_VBScript 'C:\Users\[USERNAME]\Desktop\hello_world.vbs' -secs $seconds} -Name MyJob

The problem comes the moment I want to parameterize the vbScript path. (the idea is to do several different calls to some different vbScripts). When I do this, the command seems to ignore the parameter input. I did other tests with int parameter and they work fine, the problem looks to be only with the string parameters. The following code does not work:

$functions = {
    Function execute_vbs {
        param ([string]$path_VBScript, [int]$secs)
        Start-Sleep -Seconds $secs
        cscript /nologo $path_VBScript 
    }
}
$input = 'C:\Users\[USERNAME]\Desktop\hello_world.vbs'
$seconds = 2
Start-Job -InitializationScript $functions -ScriptBlock {execute_vbs -path_VBScript $input -secs $seconds} -Name MyJob

I've also tried using the [-ArgumentList] command, but it has the same problem.

Any idea?

Palle Due
  • 5,929
  • 4
  • 17
  • 32
Joracosu
  • 309
  • 1
  • 14
  • Does this answer your question? [Passing Variables to Start-Job](https://stackoverflow.com/questions/45309600/passing-variables-to-start-job) – user692942 Sep 02 '20 at 10:13
  • not really. The solution in my case was to include `$using:`before each variable, but thanks anyway ;-) – Joracosu Sep 02 '20 at 10:18
  • Does this answer your question? [Passing arguments to Start-Job scriptblock?](https://stackoverflow.com/a/14664983/692942) – user692942 Sep 02 '20 at 10:22
  • Either way it’s a duplicate, it’s been covered multiple times before. Just need to search before posting. – user692942 Sep 02 '20 at 10:22
  • I didn't found this issue before and I've searched it. It looks similar but that question dont answer my doubt – Joracosu Sep 02 '20 at 10:33
  • It’s the exact same solution. – user692942 Sep 02 '20 at 10:43
  • ah! you sent a second link!. Now I see. Nevertheless some people are more skilled in searching than others. You look very good at that. I've spent several hours searching without results... Yes, it is the same solution. Thankyou and sorry for the inconveniences – Joracosu Sep 02 '20 at 10:52

1 Answers1

4

The problem is that the $input and $seconds variables inside your script block are in a different scope and are effectively different variables to the ones in the main script.

I've modified your script slightly to remove the call to VBScript to make it easier to reproduce here - my example code is:

$functions = {
    Function execute_vbs {
        param ([string]$path_VBScript, [int]$secs)
        Start-Sleep -Seconds $secs
        write-output "filename = '$path_VBScript'"
        write-output "secs = '$secs'"
    }
}

Here's two ways to fix it:

The Using: scope modifier

See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes?view=powershell-7#the-using-scope-modifier for the full details, but basically:

For any script or command that executes out of session, you need the Using scope modifier to embed variable values from the calling session scope, so that out of session code can access them.

$filename = 'C:\Users\[USERNAME]\Desktop\hello_world.vbs'
$seconds = 2

$job = Start-Job -InitializationScript $functions -ScriptBlock {
        execute_vbs -path_VBScript $using:filename -secs $using:seconds
    } -Name MyJob

wait-job $job

receive-job $job
# output:
# filename = 'C:\Users\[USERNAME]\Desktop\hello_world.vbs'
# secs = '2'

Note the $using before the variable names inside the script block - this allows you to "inject" the variables from your main script into the scriptblock.

ScriptBlock Parameters

You can define parameters on the script block similar to how you do it with a function, and then provide the values in the -ArgumentList parameter when you invoke Start-Job.

$filename = 'C:\Users\[USERNAME]\Desktop\hello_world.vbs'
$seconds = 2

$job = Start-Job -InitializationScript $functions -ScriptBlock {
    param( [string] $f, [int] $s )
    execute_vbs -path_VBScript $f -secs $s
} -ArgumentList @($filename, $seconds) -Name MyJob

wait-job $job

receive-job $job
# output:
# filename = 'C:\Users\[USERNAME]\Desktop\hello_world.vbs'
# secs = '2'
``
mclayton
  • 8,025
  • 2
  • 21
  • 26
  • I was so close! hehehehe. I am very new with this programming language. Thank you very much!! I spent about 14 hours before coming to the forum :P – Joracosu Sep 02 '20 at 09:19