LoginSignup
2
3

More than 5 years have passed since last update.

[PowerShell]Start-Jobで共通の関数を使う

Last updated at Posted at 2017-01-09

問題点

Start-Jobで実行するスクリプトブロックは、呼び出し元とは別プロセスになり、外側で定義した関数(や変数)は使えません。

内側でエラー出る版
function foo($arg1){
    "foo arg1="+$arg1
}
function bar($arg1){
    "bar arg1="+$arg1
}

foo "outer"
bar "outer"

$code = {
    foo "inner"
    bar "inner"
}

$j = Start-Job -ScriptBlock $code

Wait-Job $j | Receive-Job

Remove-Job $j
output1
foo arg1=outer
bar arg1=outer
The term 'foo' is not recognized as the name of a cmdlet, function, script file
, or operable program. Check the spelling of the name, or if a path was include
d, verify that the path is correct and try again.
    + CategoryInfo          : ObjectNotFound: (foo:String) [], ParentContainsE 
   rrorRecordException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : localhost

The term 'bar' is not recognized as the name of a cmdlet, function, script file
, or operable program. Check the spelling of the name, or if a path was include
d, verify that the path is correct and try again.
    + CategoryInfo          : ObjectNotFound: (bar:String) [], CommandNotFound 
   Exception
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName        : localhost

内側のスクリプトブロックで使えるようにするには、Start-Jobの-InitializationScriptで関数を定義するスクリプトブロックを渡してやる必要があります。
しかし、そうすると今度は外側でその関数が使えなくなります。

外側でエラー出る版
$initScript = {
    function foo($arg1){
        "foo arg1="+$arg1
    }
    function bar($arg1){
        "bar arg1="+$arg1
    }
}

foo "outer"

$code = {
    foo "inner"
}

$j = Start-Job -InitializationScript $initScript -ScriptBlock $code

Wait-Job $j | Receive-Job

Remove-Job $j
output2
foo : The term 'foo' is not recognized as the name of a cmdlet, function, script file, or operable p
rogram. Check the spelling of the name, or if a path was included, verify that the path is correct a
nd try again.
At C:\Users\Owner\Desktop\powershell\astest.ps1:10 char:1
+ foo "outer"
+ ~~~
    + CategoryInfo          : ObjectNotFound: (foo:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

bar : The term 'bar' is not recognized as the name of a cmdlet, function, script file, or operable p
rogram. Check the spelling of the name, or if a path was included, verify that the path is correct a
nd try again.
At C:\Users\Owner\Desktop\powershell\astest.ps1:11 char:1
+ bar "outer"
+ ~~~
    + CategoryInfo          : ObjectNotFound: (bar:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

foo arg1=inner
bar arg1=inner

一応、解決策

これを回避するには以下のようにします。

一応解決版
$initScript = {
    function foo($arg1){
        "foo arg1="+$arg1
    }
    function bar($arg1){
        "bar arg1="+$arg1
    }
}

#全体をStart-Jobで呼び出す。
#内側で使うために、関数を定義しているScriptBlockをArgumentListで渡す
$outJob = Start-Job -InitializationScript $initScript -ArgumentList $initScript -ScriptBlock {
    param($initScriptString)

    #引数が文字列で渡されるので、ScriptBlock型に変換する
    $initScript = [ScriptBlock]::Create($initScriptString)

    foo "outer"
    bar "outer"

    $code = {
        foo "inner"
        bar "inner"
    }

    $j = Start-Job -InitializationScript $initScript -ScriptBlock $code

    Wait-Job $j | Receive-Job
    Remove-Job $j
}

Wait-Job $outJob | Receive-Job
Remove-Job $outJob
output3
foo arg1=outer
bar arg1=outer
foo arg1=inner
bar arg1=inner

あまりスマートでない気がしますね。もっといいやり方があればいいのですが。

参考

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3