2011-02-14 124 views
5

我想寫一個遞歸函數,它將返回數組中的信息,但是當我將一個return語句放入函數中時,它會遺漏某些條目。Powershell遞歸返回

我想通過指定深度的文件夾遞歸地查看獲取與文件夾相關的acl文件夾。我知道getChildItem有一個遞歸選項,但我只想穿過3級文件夾。

下面的代碼片段是我一直用來測試的。當getACLS被不帶return語句(下面註釋)的結果是:

文件夾1

文件夾12

文件夾13

文件夾2

當返回語句是使用我得到以下輸出:

文件夾1

文件夾12

因此它看起來像return語句退出遞歸循環?

的想法是,我想返回多維數組如[文件夾名稱,[訪問控制列表],[子文件夾,[權限],[[...]]]]]等

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 

回答

7

問題是返回的位置。我把它放在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

更新:我正在離開第一個答案,並在此處添加新代碼。我發現你的代碼存在多個問題。這裏是更新的一個。

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)。它不應該是如果($ current -le $ max)。

讓我知道這是你在找什麼。我可以繼續優化這一點。

========================================== OLD === ========================================== 返回將退出該功能。

我不是在這裏提供完整的解決方案,但想給你一個關於如何改變這個問題的想法。

您可以使用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 
} 

通過這種方式,您可以在完全按照需要的信息構建完成後返回對象。

+0

不確定這是否會工作,因爲我需要嵌套對象。 – Rumpleteaser 2011-02-14 06:16:36

3

在遞歸中,我只會使用return語句,我需要結束遞歸 - 只是爲了清楚起見。我在PowerShell中做了很多遞歸,效果很好。但是,您需要記住PowerShell函數的行爲有所不同。以下:

return 1,2 

等同於:

1,2 
return 

換句話說,任何你不變量捕獲或重定向到文件(或$空)被自動視爲輸出功能。下面是一個簡單的遞歸函數示例:

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