带返回的 Powershell 递归
Posted
技术标签:
【中文标题】带返回的 Powershell 递归【英文标题】:Powershell Recursion with Return 【发布时间】:2011-06-26 17:13:35 【问题描述】:我正在尝试编写一个递归函数,该函数将返回数组中的信息,但是当我将 return 语句放入函数时,它会丢失某些条目。
我正在尝试以递归方式查看指定深度的文件夹,以获取与文件夹关联的 acl。我知道 getChildItem 有一个递归选项,但我只想逐步浏览 3 级文件夹。
下面的代码摘录是我一直用来测试的。如果在没有返回语句的情况下调用 getACLS(在下面注释掉),结果是:
文件夹 1
文件夹 12
文件夹 13
文件夹 2
当使用 return 语句时,我得到以下输出:
文件夹 1
文件夹 12
所以看起来返回语句正在退出递归循环?
我的想法是我想返回一个多维数组,例如 [文件夹名称、[acls]、[[子文件夹、[权限]、[[...]]]]] 等。
cls
function getACLS ([string]$path, [int]$max, [int]$current)
$dirs = Get-ChildItem -Path $path | Where $_.psIsContainer
$acls = Get-Acl -Path $path
$security = @()
foreach ($acl in $acls.Access)
$security += ($acl.IdentityReference, $acl.FileSystemRights)
if ($current -le $max)
if ($dirs)
foreach ($dir in $dirs)
$newPath = $path + '\' + $dir.Name
Write-Host $dir.Name
# return ($newPath, $security, getACLS $newPath $max ($current+1))
# getACLS $newPath $max ($current+1)
return getACLS $newPath $max ($current+1)
elseif ($current -eq $max )
Write-Host max
return ($path, $security)
$results = getACLS "PATH\Testing" 2 0
【问题讨论】:
【参考方案1】:问题在于退货的位置。我将它放在 foreach 循环中,这意味着它试图在一个函数中多次返回。我将它移到了 foreach 之外,而是移到了 if 语句中。
function getACLS ([string]$path, [int]$max, [int]$current)
$dirs = Get-ChildItem -Path $path | Where $_.psIsContainer
$acls = Get-Acl -Path $path
$security = @()
$results = @()
foreach ($acl in $acls.Access)
$security += ($acl.IdentityReference, $acl.FileSystemRights)
if ($current -lt $max)
if ($dirs)
foreach ($dir in $dirs)
$newPath = $path + '\' + $dir.Name
$next = $current + 1
$results += (getACLS $newPath $max $next)
else
$results = ($path, $security)
return ($path, $security, $results)
elseif ($current -eq $max )
return ($path, $security)
【讨论】:
【参考方案2】:在递归中,我只会在需要结束递归的地方使用return
语句——只是为了清楚起见。我在 PowerShell 中做了很多递归,效果很好。但是,您需要记住 PowerShell 函数的行为确实不同。以下:
return 1,2
相当于:
1,2
return
换句话说,您没有在变量中捕获或重定向到文件(或 $null)的任何内容都会被自动视为函数的输出。这是一个有效的递归函数的简单示例:
function recursive($path, $max, $level = 1)
$path = (Resolve-Path $path).ProviderPath
Write-Host "$path - $max - $level"
foreach ($item in @(Get-ChildItem $path))
if ($level -eq $max) return
recursive $item.PSPath $max ($level + 1)
recursive ~ 3
【讨论】:
【参考方案3】:更新:我将保留第一个答案并在此处添加新代码。我看到您的代码存在多个问题。这是更新的。
cls
function getACLS ([string]$path, [int]$max, [int]$current)
$dirs = Get-ChildItem -Path $path | Where $_.psIsContainer
$acls = Get-Acl -Path $path
$security = @()
foreach ($acl in $acls.Access)
$security += ($acl.IdentityReference, $acl.FileSystemRights)
if ($current -lt $max)
if ($dirs)
foreach ($dir in $dirs)
$newPath = $dir.FullName
$security
getACLS $newPath $max ($current+1)
elseif ($current -eq $max )
Write-Host max
return $security
$results = getACLS "C:\Scripts" 2 0
如果您在上面看到,我没有使用 return。我只是从 GetACLs 函数中抛出对象。此外,我将其修改为返回 $security 以进行测试。我可以在 $results 中看到所有 ACL。我将第一个 if 条件更改为 if ($current -lt $max)。不应该是 if ($current -le $max)。
如果这是您要找的,请告诉我。我可以继续优化这个。
===========================================OLD==== ========================================== Return 将退出函数。
我在这里没有提供完整的解决方案,但想告诉你如何改变它。
您可以使用 PS 自定义对象来捕获您需要的信息。例如,
function GetItem
$itemsArray = @()
Get-ChildItem C:\Scripts | ForEach-Object
$itemsObject = New-Object PSObject
Add-Member -InputObject $itemsObject -MemberType NoteProperty -Name "FullName" -Value $_.FullName
Add-Member -InputObject $itemsObject -MemberType NoteProperty -Name "Name" -Value $_.Name
$itemsArray += $itemsObject
return $itemsArray
这样,您可以在使用所需信息完全构建对象后返回该对象。
【讨论】:
不确定这是否可行,因为我需要嵌套对象。 递归函数需要能够返回不同的选项,具体取决于它是否是递归案例的基本案例。因此,如果 return 语句破坏了 powershell 中的递归,那么递归是不可能的吗?还是有不同类型的输出? 我可能误解了您的要求。让我回到剧本,再看一遍。我错过了递归部分,并给了你一个一般提示。递归可以在 PowerShell 中完成。【参考方案4】:我发现这些解决方案都没有满足我的需要,即拥有一个包含整个递归函数结果的数组。由于我们不能在函数内部初始化数组,否则每次使用递归都会重新初始化,我们必须在外部定义它并使用全局:
# Get folder contents recursively and add to an array
function recursive($path, $max, $level = 1)
Write-Host "$path" -ForegroundColor Red
$global:arr += $path
foreach ($item in @(Get-ChildItem $path))
if ($level -eq $max) return
if ($item.Length -eq "1") # if it is a folder
$newpath = "$path\$($item.Name)"
recursive $newpath $max ($level + 1)
else # else it is a file
Write-Host "$path\$($item.Name)" -ForegroundColor Blue
$global:arr +="$path\$($item.Name)"
$arr = @() # have to define this outside the function and make it global
recursive C:\temp\test2 4
write-host $arr.count
【讨论】:
以上是关于带返回的 Powershell 递归的主要内容,如果未能解决你的问题,请参考以下文章
powershell 来自https://stackoverflow.com/questions/31051103/how-to-export-a-class-in-powershell-v5-mod