Drism
Drism

Reputation: 309

Passing arguments to Start-Job scriptblock?

I'd like to setup a cmdlet to start and stop mysql, and I'm trying to do so with Start-Job. the I've got the following in my Powershell profile:

$mysqlpath = "C:\Program Files\MySQL\MySQL Server 5.5\bin"
Function Start-Mysql
{
    Start-Job -ScriptBlock { & "$mysqlpath\mysqld.exe" }
}

The variable doesn't seem to be expanding in the job command however? I must be missing some sort of scoping rule. Could someone please advise? Thanks!

Upvotes: 8

Views: 11456

Answers (2)

codewario
codewario

Reputation: 21418

Loïc MICHEL's answer is correct, but if you find it becomes difficult to deal with remembering which positional argument is which within the ScriptBlock, I'd like to offer a trick using the param keyword. Within the ScriptBlock, begin the body with param like you would for an advanced function, and put your code after also as if it were a function:

Note: The ScriptBlock param name does not need to be the same in the ScriptBlock and current session, it can be the same or something totally different. The important thing is you match the correct argument positionally in the -ArgumentList.

Start-Job { param( $mysqlpath ) & "$mysqlpath\mysqld.exe" } -ArgumentList $mysqlpath

This works because a ScriptBlock is just an unnamed function, so you can define parameters in mostly the same way you can when defining a proper function. The arguments in -ArgumentList are passed to the ScriptBlock as positional arguments in the order provided, so by default the order the arguments are passed is the same order they will be bound to named parameters in.

While the $using: scope is syntactically easier to work with, this method gets you the best of all worlds here, as the $using: scope cannot be used within the current session. This is incredibly useful you have a ScriptBlock that needs to be able to execute in any context and it's complicated enough that referencing the arguments by index becomes difficult to manage. This approach allows you to name your parameters and works with any ScriptBlock in all execution contexts, whether it's Start-Job, Invoke-Command, powershell.exe, or executing a ScriptBlock with the call operator &.

This is one of (if not the) most portable solution if you want to use named variables instead of referencing $args[i] for every variable.

Upvotes: 2

Loïc MICHEL
Loïc MICHEL

Reputation: 26120

you have to use the -argumentlist parameter see get-help start-job :

 start-job  -ScriptBlock { & $args[0] } -ArgumentList @($mysqlpath )

note that in V3 you just have to use the prefix using: before your varname ex:

  Start-Job -ScriptBlock { & "$using:mysqlpath\mysqld.exe" }

Upvotes: 12

Related Questions