【问题标题】:Powershell Recursion with Return带返回的 Powershell 递归
【发布时间】: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

【问题讨论】:

    标签: function powershell recursion return


    【解决方案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
        

        【讨论】:

          猜你喜欢
          • 2016-08-03
          • 2014-07-14
          • 2022-01-03
          • 2017-05-09
          • 2012-06-16
          • 1970-01-01
          • 2011-02-05
          • 2018-12-27
          相关资源
          最近更新 更多