在工作流旁边使用递归函数
Using a recursive function beside a workflow
我有一个 PowerShell 脚本,其目的是获取文件列表,然后对每个文件执行一些操作。
文件列表是由这样的递归函数生成的:
function Recurse($path)
{
.. create $folder
foreach ($i in $folder.files) {
$i
}
foreach ($i in $folder.subfolders) {
Recurse($i.path)
}
}
与此功能分开,我执行一个工作流,该工作流获取文件列表并对每个文件执行(并行)工作。代码看起来像这样:
workflow Do-Work {
param(
[parameter(mandatory)][object[]]$list
)
foreach -parallel ($f in $list) {
inlinescript {
.. do work on $Using:f
}
}
}
这两部分再结合以下逻辑:
$myList = Recurse($myPath)
Do-Work -list $myList
问题是这会产生错误:
A workflow cannot use recursion.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : RecursiveWorkflowNotSupported
当递归函数和工作流分开时,为什么会发生这种情况?
有什么办法可以解决这个问题吗?
工作流中不允许递归调用。
直接给出路径:
而不是这个:
Recurse($myPath)
这样做:
Recurse $myPath
可以参考这篇文章:
我最终(当然是在发布问题后几分钟)通过将函数提取到它自己的模块中解决了这个问题:
get-files.psm1:
function Recurse()
{
params(
[parameter(mandatory)][string]$path
)
.. create $folder
foreach ($i in $folder.files) {
$i
}
foreach ($i in $folder.subfolders) {
Recurse($i.path)
}
}
Export-ModuleMember -Function Recurse
get-files.psd1:
@{
...
FunctionsToExport = @(Recurse)
...
}
脚本.ps1:
workflow do-work {
params(
[parameter(mandatory)][object[]]$files
)
...
}
Import-Module -Name "path\to\module\get-files.psm1"
$files = Recurse -path $myPath
do-work -files $files
这似乎让主脚本错过了 Recurse 使用递归并且它有效。
对于那些希望在模块中使用“并行”工作流(无递归)的人,解决方案类似但略有不同。
例如,此工作流可用于start/stop并行服务
Workflow Invoke-ServiceInParallelWF
{
<#
.SYNOPSIS
Workflow to stop/start services in parallel on a server.
.DESCRIPTION
Utilizes a workflow to start/stop services running on a server in parallel to shorten the start/stop duration.
#>
Param(
[Parameter(Mandatory=$true)]
[string[]]$Name,
[Parameter(Mandatory=$true)]
[ValidateSet("Start","Stop")]
[string]$Action
)
if (!($Name.Count -gt 0))
{
throw "No services provided!"
}
# run parrallel on services argument
foreach -parallel ($svc in $Name){
InlineScript{
#build object first for consistency
$props=[ordered]@{
Service=$using:svc;
Action=$using:action
Result=$null
Error=$null
}
# Wrap in exception handler
Try{
#Perform the desired service action
if ($using:action -eq 'stop') {
Stop-Service -name $using:svc -ErrorAction stop
} elseif ($using:action -eq 'start') {
Start-Service -name $using:svc -ErrorAction stop
} else {
$Action='unknown'
}
$props.Result='Success'
}
Catch{
$props.Result='Fail'
$props.Error="$_"
}
# generate object back to workflow
New-Object -TypeName PSCustomObject -Property $props
}
}
}
如果将其放入 psm1 文件并尝试导入它,它将失败并出现以下错误:
At C:\Source\Powershell\Common\Modules\MyModule\MyModule.psm1:1 char:1
+ #
+ ~
A workflow cannot use recursion.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : RecursiveWorkflowNotSupported
要将其嵌入到模块中,请勿将其放入 .psm1 文件中,创建一个单独的 ps1 文件并将其放入模块文件夹中。
例如调用 ServiceInParallelWF.ps1
然后在您的清单 (psd1) 文件中,修改 ScriptsToProcess 以包含 ps1 文件。
@{
# Script module or binary module file associated with this manifest.
RootModule = 'MyModule.psm1'
# Version number of this module.
ModuleVersion = '1.47.1'
# ID used to uniquely identify this module
GUID = 'bd4390dc-a8ad-4bce-8d69-f53ccf8e4163'
# Author of this module
Author = 'Justin Marshall'
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
ScriptsToProcess = @('Invoke-ServiceInParallelWF.ps1')
}
最后,导入您的模块并测试功能:
PS C:\source\powershell> Import-Module MyModule -force
PS C:\source\powershell> Invoke-ServiceInParallelWF -Action Start -Name w3svc
Service : w3svc
Action : Start
Result : Success
Error :
PSComputerName : localhost
PSSourceJobInstanceId : 1a564d5d-f363-44b7-a27e-88670764de2d
我有一个 PowerShell 脚本,其目的是获取文件列表,然后对每个文件执行一些操作。
文件列表是由这样的递归函数生成的:
function Recurse($path)
{
.. create $folder
foreach ($i in $folder.files) {
$i
}
foreach ($i in $folder.subfolders) {
Recurse($i.path)
}
}
与此功能分开,我执行一个工作流,该工作流获取文件列表并对每个文件执行(并行)工作。代码看起来像这样:
workflow Do-Work {
param(
[parameter(mandatory)][object[]]$list
)
foreach -parallel ($f in $list) {
inlinescript {
.. do work on $Using:f
}
}
}
这两部分再结合以下逻辑:
$myList = Recurse($myPath)
Do-Work -list $myList
问题是这会产生错误:
A workflow cannot use recursion.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : RecursiveWorkflowNotSupported
当递归函数和工作流分开时,为什么会发生这种情况? 有什么办法可以解决这个问题吗?
工作流中不允许递归调用。
直接给出路径:
而不是这个:
Recurse($myPath)
这样做:
Recurse $myPath
可以参考这篇文章:
我最终(当然是在发布问题后几分钟)通过将函数提取到它自己的模块中解决了这个问题:
get-files.psm1:
function Recurse()
{
params(
[parameter(mandatory)][string]$path
)
.. create $folder
foreach ($i in $folder.files) {
$i
}
foreach ($i in $folder.subfolders) {
Recurse($i.path)
}
}
Export-ModuleMember -Function Recurse
get-files.psd1:
@{
...
FunctionsToExport = @(Recurse)
...
}
脚本.ps1:
workflow do-work {
params(
[parameter(mandatory)][object[]]$files
)
...
}
Import-Module -Name "path\to\module\get-files.psm1"
$files = Recurse -path $myPath
do-work -files $files
这似乎让主脚本错过了 Recurse 使用递归并且它有效。
对于那些希望在模块中使用“并行”工作流(无递归)的人,解决方案类似但略有不同。
例如,此工作流可用于start/stop并行服务
Workflow Invoke-ServiceInParallelWF
{
<#
.SYNOPSIS
Workflow to stop/start services in parallel on a server.
.DESCRIPTION
Utilizes a workflow to start/stop services running on a server in parallel to shorten the start/stop duration.
#>
Param(
[Parameter(Mandatory=$true)]
[string[]]$Name,
[Parameter(Mandatory=$true)]
[ValidateSet("Start","Stop")]
[string]$Action
)
if (!($Name.Count -gt 0))
{
throw "No services provided!"
}
# run parrallel on services argument
foreach -parallel ($svc in $Name){
InlineScript{
#build object first for consistency
$props=[ordered]@{
Service=$using:svc;
Action=$using:action
Result=$null
Error=$null
}
# Wrap in exception handler
Try{
#Perform the desired service action
if ($using:action -eq 'stop') {
Stop-Service -name $using:svc -ErrorAction stop
} elseif ($using:action -eq 'start') {
Start-Service -name $using:svc -ErrorAction stop
} else {
$Action='unknown'
}
$props.Result='Success'
}
Catch{
$props.Result='Fail'
$props.Error="$_"
}
# generate object back to workflow
New-Object -TypeName PSCustomObject -Property $props
}
}
}
如果将其放入 psm1 文件并尝试导入它,它将失败并出现以下错误:
At C:\Source\Powershell\Common\Modules\MyModule\MyModule.psm1:1 char:1
+ #
+ ~
A workflow cannot use recursion.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : RecursiveWorkflowNotSupported
要将其嵌入到模块中,请勿将其放入 .psm1 文件中,创建一个单独的 ps1 文件并将其放入模块文件夹中。 例如调用 ServiceInParallelWF.ps1
然后在您的清单 (psd1) 文件中,修改 ScriptsToProcess 以包含 ps1 文件。
@{
# Script module or binary module file associated with this manifest.
RootModule = 'MyModule.psm1'
# Version number of this module.
ModuleVersion = '1.47.1'
# ID used to uniquely identify this module
GUID = 'bd4390dc-a8ad-4bce-8d69-f53ccf8e4163'
# Author of this module
Author = 'Justin Marshall'
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
ScriptsToProcess = @('Invoke-ServiceInParallelWF.ps1')
}
最后,导入您的模块并测试功能:
PS C:\source\powershell> Import-Module MyModule -force
PS C:\source\powershell> Invoke-ServiceInParallelWF -Action Start -Name w3svc
Service : w3svc
Action : Start
Result : Success
Error :
PSComputerName : localhost
PSSourceJobInstanceId : 1a564d5d-f363-44b7-a27e-88670764de2d