Sha*_*har 2 powershell scope start-job scriptblock
我有一个很长的剧本。我有一个记录功能:
function Log ([string]$Content){
$Date = Get-Date
Add-Content -Path $LogPath -Value ("$Date : $Content")
}
Run Code Online (Sandbox Code Playgroud)
在脚本的某些时候,我需要并行运行作业。我有一个计算机名称列表,我需要对每个计算机名称使用 psexec。这应该作为并行运行的作业来完成
Start-Job -ScriptBlock {
Log "$line Has called"
$Program_List = gc $USERS_DB_PATH\$line.txt | select -Skip 1
if (Test-Connection $line -Quiet) {
ForEach ($program in $Program_List){
Log "$line $program"
#"line $line bot is $bot pwd is $pwd"
psexec \\"$line" -u bla.local\"$bot" -p $pwd cmd bla
}
}
else{
Log "Cannot Connect to $line"
}
}
#Remove-Item "$USERS_DB_PATH\$line.txt"
}
Run Code Online (Sandbox Code Playgroud)
我知道这与范围有关,但是如何使这个脚本块看到函数 Log 和所有必要的变量?他们都空了
太长了;博士
通过作用域引用调用者作用域中的变量$using:。
Log在后台作业的上下文中重新创建您的函数,使用
$function:Log = "$using:function:Log"
Start-Job -ScriptBlock {
# Required in Windows PowerShell only (if needed).
# Change to the same working directory as the caller.
Set-Location -LiteralPath ($using:PWD).ProviderPath
# Recreate the Log function.
$function:Log = "$using:function:Log"
# All variable values from the *caller*'s scope must be $using: prefixed.
Log "$using:line Has called"
# ...
}
Run Code Online (Sandbox Code Playgroud)
请继续阅读以获取解释。
请参阅底部部分,了解:和(仅限 PowerShell (Core) 7+)的更好替代方案Start-Job。Start-ThreadJobForEach-Object -Parallel
后台作业在不可见的 PowerShell子进程中运行,即单独的powershell.exe(Windows PowerShell) pwsh(PowerShell (Core) 7+) 进程。
这样的子进程:
$PROFILE文件。相反,这意味着默认情况下在后台作业中只有以下命令可用:
*.ps1脚本,通过环境变量中列出的目录$env:PATH。$env:PSModulePath环境变量(具有默认模块)中列出的目录中获取。将调用者状态信息传递给后台作业:
变量:
function:
类似地,您不能传递函数本身,而只能传递函数的主体,最简单的方法是通过命名空间变量表示法;例如,要获取函数体foo,请使用$function:foo; 要将其传递给后台作业(或远程调用),请使用"$using:function:foo".
由于命名空间变量表示法也可用于分配值,分配$function:foo创建或更新名为 的函数foo,以便有效地在后台会话中$function:foo = $using:function:foo重新创建函数。foo
请注意,虽然$function:foo将函数体作为[scriptblock]实例返回,$using:function:foo但 , 在序列化期间会变成字符串(请参阅GitHub 问题 #11698 ;不过,幸运的是,您也可以从字符串创建函数体。
因此,对于 ; 来说,括起来$using:function:foo并不是"..."严格必要的Start-Job。然而,它是必需的,因为在Start-ThreadJob基于线程的并行性中没有序列化的情况下,$using:function:foo 它是一个实例,但与调用者的[scriptblock]运行空间相关联,因此必须从作业上下文中的字符串重建(否则,可能会发生状态损坏) )。
即使允许此类脚本块引用也可能是一种Start-ThreadJob疏忽,并且 PowerShell v7+功能(与 共享技术基础)明确不允许它们,因此需要通过辅助变量来解决方法,该变量首先在调用者的范围内对脚本块进行字符串化 - 请参阅此答案。ForEach-Object -ParallelStart-ThreadJob
class英语
工作目录:
在Windows PowerShell后台作业中,使用固定的工作目录:usersDocuments文件夹。为了确保后台作业使用与调用者相同的目录,请将 call
Set-Location -LiteralPath ($using:PWD).ProviderPath作为传递给 的脚本块内部的第一条语句-ScriptBlock。
现在在PowerShell (Core) 7+后台作业中 - 幸运的是 - 使用与调用者相同的工作目录。
重新输入保真度的警告:
Start-ThreadJob:PowerShell (Core) 7+附带该ThreadJob模块,该模块提供Start-ThreadJobcmdlet;在Windows PowerShell中您可以按需安装它。
ForEach-Object通过参数提供与 cmdlet 扩展基本相同的功能-Parallel,该参数在每个输入对象的单独线程中执行传递给它的脚本块。Start-ThreadJob与PowerShell的其他作业管理cmdlet完全集成,但使用线程(即进程内并发)而不是子进程,这意味着:
此外,调用者的工作目录也是继承的。
$using:/的需要-ArgumentList同样适用。
ForEach-Object -Parallel考虑进行改进,以允许在选择加入的基础上将调用者的状态复制到线程脚本块 - 请参阅GitHub 问题 #12240。这个答案提供了 和 的概述ForEach-Object -Parallel、比较和Start-Job对比Start-ThreadJob。
| 归档时间: |
|
| 查看次数: |
2709 次 |
| 最近记录: |