我正在阅读这篇关于将函数传递到用于作业的脚本块中的帖子:
Powershell start-job -scriptblock cannot recognize the function defined in the same file?
我通过将函数作为变量传递来得到它是如何工作的,它适用于简单的例子。然而,现实世界的解决方案呢,是否有一种更优雅的方式来处理它?</ p>
我有用于将更改部署到供应商软件的脚本。它读取一个xml,告诉它如何导航环境并执行各种任务,即:映射驱动器,停止服务,调用perl安装脚本。我想为脚本提供一个参数以允许它同时运行,这种方式如果perl脚本需要5分钟(并非罕见)而你正在推出11个服务器而你还没有等待脚本运行一小时。
我只是要发布一些片段,因为完整的脚本有点冗长。日志功能:
function Log
{
Param(
[parameter(ValueFromPipeline=$true)]
$InputObject,
[parameter()]
[alias("v")]
$verbosity = $debug
)
$messageIndex = [array]::IndexOf($verbosityArray, $verbosity)
$verbosityIndex = [array]::IndexOf($verbosityArray, $loggingVerbosity)
if($messageIndex -ge $VerbosityIndex)
{
switch($verbosity)
{
$debug {Write-Host $verbosity ": " $InputObject}
$info {Write-Host $verbosity ": " $InputObject}
$warn {Write-Host $verbosity ": " $InputObject -ForegroundColor yellow}
$error {Write-Host $verbosity ": " $InputObject -ForegroundColor red}
}
}
}
这是调用日志函数的另一个函数:
function ExecuteRollout
{
param(
[parameter(Mandatory=$true)]
[alias("ses")]
$session,
[parameter(Mandatory=$true)]
$command
)
#invoke command
Invoke-Command -session $session -ScriptBlock {$res = cmd /v /k `"$args[0]`"} -args $command
#get the return code from the remote session
$res = Invoke-Command -session $session {$res}
Log ("Command Output: "+$res)
$res = [string] $res
$exitCode = $res.substring($res.IndexOf("ExitCode:"), 10)
$exitCode = $exitCode.substring(9,1)
Log ("Exit code: "+$exitCode)
return $exitCode
}
最后是我主要的片段,这样你就可以知道发生了什么。 $ target.Destinations.Destination将包含部署将进入的所有服务器及其相关信息。我删除了一些变量设置和日志记录,以使其更紧凑,所以是的,你会看到从未定义的引用变量:
#Execute concurrently
$target.Destinations.Destination | %{
$ScriptBlock = {
$destination = $args[0]
Log -v $info ("Starting remote session on: "+$destination.Server)
$session = New-PSSession -computerName $destination.Server
$InitializeRemote -session $session -destination $destination
#Gets a little tricky here, we need to keep the cmd session so it doesn't lose the sys vars set by env.bat
#String everything together with &'s
$cmdString = $destDrive + ": & call "+$lesDestDir+"data\env.bat & cd "+$rolloutDir+" & perl ..\JDH-rollout-2010.pl "+$rollout+" NC,r:\les & echo ExitCode:!errorlevel!"
Log ("cmdString: "+$cmdString)
Log -v $info ("Please wait, executing the rollout now...")
$exitCode = $ExecuteRollout -session $session -command $cmdString
Log ("ExitCode: "+$exitCode)
#respond to return code from rollout script
$HandleExitCode -session $session -destination $destination -exitCode $exitCode
$CleanUpRemote -session $session -destination $destination
}
Start-Job $ScriptBlock -Args $_
}
因此,如果我使用链接中的方法,我将把所有函数转换为变量并将它们传递给脚本块。目前,我的日志功能默认情况下会登录DEBUG,除非将verbosity参数显式传递为不同的详细程度。如果我将我的功能转换为变量,但powershell似乎不喜欢这种语法:
$Log ("Print this to the log")
所以我想我现在需要一直使用这个参数:
$Log ("Print this to the log" -v $debug
所以底线看起来我只需要将我的所有函数作为变量传递给脚本块,并在调用它们时更改一些格式。这不是一个巨大的努力,但我想知道在我开始破解我的脚本之前是否有更好的方法。感谢您的投入和观察,我知道这是一个很长的帖子。
答案 0 :(得分:0)
我开始了另一篇关于将参数传递给存储为变量的函数的帖子,答案也解决了这个问题。那篇文章可以在这里找到:
Powershell: passing parameters to functions stored in variables
简短的回答是,如果将它们包装在一个块中并将其存储在变量中,则可以使用Start-Job的initializationscript参数来提供所有函数。
示例:
# concurrency
$func = {
function Logx
{
param(
[parameter(ValueFromPipeline=$true)]
$msg
)
Write-Host ("OUT:"+$msg)
}
}
# Execution starts here
cls
$colors = @("red","blue","green")
$colors | %{
$scriptBlock =
{
Logx $args[0]
Start-Sleep 9
}
Write-Host "Processing: " $_
Start-Job -InitializationScript $func -scriptblock $scriptBlock -args $_
}
Get-Job
while(Get-Job -State "Running")
{
write-host "Running..."
Start-Sleep 2
}
# Output
Get-Job | Receive-Job
# Cleanup jobs
Remove-Job *