powershell - 在 ForEach-Object -Parallel 块内从自身递归调用函数 - 在并行块内无法识别函数
问题描述
第一次在这里提问。请善待:)
我试图以并行方式递归获取所有目录,以期减少遍历驱动器所需的时间。下面是我尝试过的代码。基本上我要做的是输入一个文件夹并对其子文件夹及其子文件夹等并行执行相同的操作,但是在并行块内无法识别该功能
function New-RecursiveDirectoryList {
[CmdletBinding()]
param (
# Specifies a path to one or more locations.
[Parameter(Mandatory = $true,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = 'Path to one or more locations.')]
[Alias('PSPath')]
[ValidateNotNullOrEmpty()]
[string[]]
$Path
)
process {
foreach ($aPath in $Path) {
Get-Item $aPath
Get-ChildItem -Path $aPath -Directory |
# Recursively call itself in Parallel block not working
# Getting error "The term 'New-RecursiveDirectoryList' is not recognized as a name of a cmdlet"
# Without -Parallel switch this works as expected
ForEach-Object -Parallel {
$_ | New-RecursiveDirectoryList
}
}
}
}
错误:
New-RecursiveDirectoryList:
Line |
2 | $_ | New-RecursiveDirectoryList
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
| The term 'New-RecursiveDirectoryList' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
我也尝试在这里使用 mklement0 提供的解决方案,但没有运气。以下是我对此的尝试:
function CustomFunction {
[CmdletBinding()]
param (
# Specifies a path to one or more locations.
[Parameter(Mandatory = $true,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = 'Path to one or more locations.')]
[Alias('PSPath')]
[ValidateNotNullOrEmpty()]
[string[]]
$Path
)
begin {
# Get the function's definition *as a string*
$funcDef = $function:CustomFunction.ToString()
}
process {
foreach ($aPath in $Path) {
Get-Item $aPath
Get-ChildItem -Path $aPath -Directory |
# Recursively call itself in Parallel block not working
# Getting error "The term 'New-RecursiveDirectoryList' is not recognized as a name of a cmdlet"
# Without -Parallel switch this works as expected
ForEach-Object -Parallel {
$function:CustomFunction = $using:funcDef
$_ | CustomFuction
}
}
}
}
错误
CustomFuction:
Line |
3 | $_ | CustomFuction
| ~~~~~~~~~~~~~
| The term 'CustomFuction' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
有谁知道这可能是如何实现的或以不同的方式做到这一点?
解决方案
所以,这对我有用,它显然看起来不漂亮。需要注意的一件事是,foreach ($aPath in $Path) {...}
脚本上的 是不必要的,process {...}
当您传递多个路径时,该块将为您处理。
代码:
function Test {
[CmdletBinding()]
param (
# Specifies a path to one or more locations.
[Parameter(Mandatory)]
[Alias('PSPath')]
[string[]]$Path
)
begin {
$scriptblock = $MyInvocation.MyCommand.ScriptBlock.ToString()
}
process {
# Get-Item $Path <= This will slow down the script
Get-ChildItem -Path $Path -Directory | ForEach-Object -Parallel {
$_ # You can do this instead
$i = $using:scriptblock
$thisIsNotPretty = [scriptblock]::Create($i)
& $thisIsNotPretty -Path $_
}
}
}
您还可以执行类似这样的操作来显示文件夹层次结构非常酷(我在为AD Groups制作的功能上使用了非常相似的功能):
function Test {
[CmdletBinding()]
param (
# Specifies a path to one or more locations.
[Parameter(Mandatory)]
[Alias('PSPath')]
[string[]]$Path,
[int]$Nesting = 0
)
begin {
$scriptblock = $MyInvocation.MyCommand.ScriptBlock.ToString()
}
process {
Get-ChildItem -Path $Path -Directory | ForEach-Object -Parallel {
function Indent{
param(
[String]$String,
[Int]$Indent
)
$x='_';$y='|';$z=' '
switch($Indent)
{
{$_ -eq 0}{return $String}
{$_ -gt 0}{return "$($z*$_)$y$x $string"}
}
}
$z = $using:Nesting
[pscustomobject]@{
Nesting = $z
Path = Indent -String $_.FullName -Indent $z
}
$z++
$i = $using:scriptblock
$thisIsNotPretty = [scriptblock]::Create($i)
& $thisIsNotPretty -Path $_ -Nesting $z
}
}
}
[System.Collections.ArrayList]$result = Test -Path /home/user/Documents
function Draw-Hierarchy{
param(
[System.Collections.ArrayList]$Array
)
$Array.Reverse()
for($i=0;$i -lt $Array.Count;$i++){
if(
$Array[$i+1] -and
$Array[$i].Path.IndexOf('|_') -lt $Array[$i+1].Path.IndexOf('|_')
){
$z=$i+1
$ind=$Array[$i].Path.IndexOf('|_')
while($Array[$z].Path[$ind] -ne '|'){
$string=($Array[$z].Path).ToCharArray()
$string[$ind]='|'
$string=$string -join ''
$Array[$z].Path=$string
$z++
if($Array[$z].Path[$ind] -eq '|'){break}
}
}
}
$Array.Reverse()
return $Array
}
Draw-Hierarchy $result
结果看起来像这样:
Nesting Path
------- ----
0 /home/user/Documents/...
1 |_ /home/user/Documents/...
1 |_ /home/user/Documents/...
1 |_ /home/user/Documents/...
2 | |_ /home/user/Documents/...
1 |_ /home/user/Documents/...
1 |_ /home/user/Documents/...
2 | |_ /home/user/Documents/...
1 |_ /home/user/Documents/...
1 |_ /home/user/Documents/...
3 | |_ /home/user/Documents/...
1 |_ /home/user/Documents/...
3 |_ /home/user/Documents/...
3 |_ /home/user/Documents/...
4 |_ /home/user/Documents/...
5 |_ /home/user/Documents/...
推荐阅读
- windows - Jenkins 是否需要管理员权限才能作为 Windows 代理运行?
- python - Apache Beam 中的状态类
- node.js - 使用节点 js SOAP 或任何其他的 Soap API 调用?
- node.js - 用 post 设置 cookie 不让我登录
- ios - 专辑中的Livephoto问题:没有先播放片段
- c# - 如何将请求标头输出到C#中的字符串
- ios - 将 MKCircle 添加到地图上的注释 - 设置 CLLocationCoordinate2D 时出现问题
- jwt - 为什么要向 JWO 添加标头?
- python - docker alpine image里面的python
- javascript - Javascript中的累积和数组,一个有效,一个无效