function F2([String]$var2)
{
.........
.........
}
function F1([String]$var1)
{
.........
F2 $var2
.........
}
..................
..................
while ($i -le $count)
{
F1 "dir$i"
Start-Job -ScriptBlock ${function:F1} -ArgumentList @($i)
$i = $i + 1
}
在下面的代码片段中,我想开始一个工作并为while循环的每次迭代运行F1。虽然在F1中定义的工作正常,但是当通过ScriptBlock完成时,F1到F2的调用似乎没有完成。
这里有什么我想念的吗?
更新1
我试图实现你的建议,以实现一些相当简单和直接的东西,使用作业同时在目录中创建文件。
$dirname = "E:\TEST3\dir_"
$filename = "file_"
$i=1
$moduledef = {
function makeFiles([String]$dirname)
{
for ($i -le 5000)
{
echo "WASSSUP !!" >> "$dirnaname\$filename$i.txt"
$i++
}
}
function makeDir([String]$dirname)
{
mkdir "$dirname$i"
makeFiles "$dirname$i"
$i++
}
} # END OF $moduledef
New-Module -Name MyFunctions -ScriptBlock $moduledef
while($i -le 10)
{
Start-Job -ScriptBlock {
param([String]$jobArg)
New-Module -Name MyFunctions -ScriptBlock $Using:moduledef
makeDir $jobArg
} -ArgumentList @("$dirname$i")
$i++
}
Get-Job | Wait-Job
这里的问题是工作失败了(我在下面贴了其中一个),不知道我在这里做错了什么?
HasMoreData : True
StatusMessage :
Location : localhost
Command :
param([String]$jobArg)
New-Module -Name MyFunctions -ScriptBlock $Using:moduledef
makeDir $jobArg
JobStateInfo : Failed
Finished : System.Threading.ManualResetEvent
InstanceId : e79a6489-cad3-47a6-b6f4-8a207d32c187
Id : 79
Name : Job79
ChildJobs : {Job80}
PSBeginTime : 4/14/2018 9:52:01 PM
PSEndTime : 4/14/2018 9:52:02 PM
PSJobTypeName : BackgroundJob
Output : {}
Error : {}
Progress : {}
Verbose : {}
Debug : {}
Warning : {}
Information : {}
State : Failed
更新2
我包含了一个Receive-Job,这只是错误的一部分。我想弄明白但是把它贴在这里,希望你能帮助我。
PSPath : Microsoft.PowerShell.Core\FileSystem::E:\TEST3\dir10
PSParentPath : Microsoft.PowerShell.Core\FileSystem::E:\TEST3
PSChildName : dir10
PSDrive : E
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : True
Mode : d-----
BaseName : dir10
Target : {}
LinkType :
RunspaceId : 434aa380-b888-4ca5-897e-75a88e1f6560
Name : dir10
FullName : E:\TEST3\dir10
Parent : TEST3
Exists : True
Root : E:\
Extension :
CreationTime : 4/14/2018 9:29:12 PM
CreationTimeUtc : 4/14/2018 3:59:12 PM
LastAccessTime : 4/14/2018 9:29:12 PM
LastAccessTimeUtc : 4/14/2018 3:59:12 PM
LastWriteTime : 4/14/2018 9:29:12 PM
LastWriteTimeUtc : 4/14/2018 3:59:12 PM
Attributes : Directory
The term 'makeFiles' 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 included, verify that the path is correct and try again.
+ CategoryInfo : ObjectNotFound: (makeFiles:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName : localhost
Cannot bind parameter 'ScriptBlock'. Cannot convert the "
function makeFiles([String]$dirname)
{
for ($i -le 5000)
{
echo "WASSSUP !!" >> "$dirnaname\$filename$i.txt"
$i++
}
}
function makeDir([String]$dirname)
答案 0 :(得分:2)
Start-Job的作用是在后端创建一个单独的线程,在线程中初始化另一个默认的Powershell会话,并运行使用参数-ScriptBlock传入的命令。
新线程中的会话是一个全新的会话,它没有加载任何非默认模块,变量或函数。它有自己的变量范围和生命周期。所以我不确定是否可以让它使用默认会话中定义的功能,但至少我不容易看到它。
我可以提供的一个解决方法是使用参数-InitializationScript定义函数F2,如下所示
function F1([String]$var1)
{
.........
F2 $var2
.........
}
..................
..................
while ($i -le $count)
{
F1 "dir$i"
Start-Job -ScriptBlock ${function:F1} -ArgumentList @($i) -InitializationScript {function F2([String]$var2){.........}}
$i = $i + 1
}
或者,如果你必须定义多个函数,比如F1,需要调用F2,并希望以某种方式重用F2的定义代码。我们可以为F2
创建一个ScriptBlock对象 $InitializationScript = [ScriptBlock]::Create('function F2([String]$var2){.........}')
function F1([String]$var1)
{
.........
F2 $var2
.........
}
..................
..................
while ($i -le $count)
{
F1 "dir$i"
Start-Job -ScriptBlock ${function:F1} -ArgumentList @($i) -InitializationScript $InitializationScript
$i = $i + 1
}
致以最诚挚的问候,
冬
答案 1 :(得分:1)
这实际上是same answer as Dong Mao's, which was here first,但是我在副本上写了它而没有意识到这就在这里。
无论如何,这种方法(使用模块)可以更好地解决代码问题的扩展和重复问题。
并非F2
超出范围,而且它甚至不存在于工作中。
作业是作为单独的进程运行的,因此除非您明确指定,否则调用进程中不会包含任何内容。
当您引用${function:F1}
时,您正在使用PSDrive形式的变量。实质上,它相当于Get-Content -LiteralPath Function:\F1
。
如果您查看返回的内容,您会看到1)它是[ScriptBlock]
(这正是Start-Job
' s所需的类型-ScriptBlock
{1}}参数),但您也会看到它是函数的内容;它甚至不包含名称。
这意味着在作业中你直接执行函数体但你实际上并没有调用函数。
您可以解决此问题,重新生成函数定义部分,定义函数,或者只在脚本块中重新定义F2
。这将很快变得混乱。
我的建议是将您的功能分解为系统中可用的模块,然后在脚本块中,只需调用Import-Module MyFunctions
即可。
如果您不想完成具有单独文件的过程,并希望将其保留,则可以动态创建模块。只需在脚本中将您的功能定义为模块,如果愿意,可以在作业中再次执行。像这样:
$moduleDefinition = {
function F2([String]$var2)
{
"~$var2~"
}
function F1([String]$var1)
{
F2 $var1
}
}
# this makes the module loaded in this context
New-Module -Name MyFunctions -ScriptBlock $moduleDefinition
while ($i -le $count)
{
F1 "dir$i"
Start-Job -ScriptBlock {
param([String]$jobArg)
$modDef = [ScriptBlock]::Create($Using:moduleDefinition)
New-Module -Name MyFunctions -ScriptBlock $modDef
F1 $jobArg
} -ArgumentList @($i)
$i = $i + 1
}