【问题标题】:Powershell - Find # of nested folders in long file path of a directoryPowershell - 在目录的长文件路径中查找嵌套文件夹的数量
【发布时间】:2020-09-04 20:37:26
【问题描述】:

谁能帮助我解决 powershell 中的代码难题?我正在尝试查看多个远程服务器上的特定目录,并在该目录中找到最深的嵌套子文件夹,然后计算父文件夹的数量。伪代码如下。

  1. $servers = get-content(服务器列表)和 $path =(远程机器上的 targetdir)
  2. 对于 $servers 中的每个 $s:
  3. 找到最长的路径
  4. 计算 \ 的数量(以识别子文件夹的数量)
  5. 将输出写入文件 $Servername $countOfNestedFolders

对不起,我只是足够优秀,有点危险。

【问题讨论】:

    标签: powershell subdirectory depth


    【解决方案1】:

    这样就搞定了;再次感谢所有帮助!

    $servers = gc C:\serverlist.txt
    
    ForEach ($server in $servers){
    $folder = "\\$server\x$\share"
    $TargetTopDir = $folder
    $DirDelim = [System.IO.Path]::DirectorySeparatorChar
    $RegexDD = [regex]::Escape($DirDelim)
    
    $DirList = Get-ChildItem -LiteralPath $TargetTopDir -Directory -Recurse -ErrorAction 
    SilentlyContinue
    
    $DeepestNestedDir = ($DirList | Sort-Object {$_.FullName -replace "[^$RegexDD]"} - 
       Descending)[0]
    
    $DepthCount = '{0}' -f ($DeepestNestedDir.FullName -replace "[^$RegexDD]").Length
    
    $arrayItems = @{
        "Depth Count"      = $DepthCount - 3
        "Path Name"        = $DeepestNestedDir.FullName
        "Server Name"      = $server
    }
    
    $output= @()
    $output += New-Object -TypeName PSObject -Property $arrayItems
    $output | Export-CSV C:\Output.csv -NoTypeInformation -Append
    }
    

    【讨论】:

    • 很高兴您找到了所需的帮助。请允许我对未来的一些提示:如果问题专注于一个特定问题,那么问题对未来的读者最有用,在您的情况下,这只是最大深度计算。所有周围的任务(在服务器上循环,以特定格式保存到文件)都偶然该问题,并且可能因阅读器而异。
    • 预先完全指定要求也很重要:您的问题只提到需要计算最大值。深度,而不是获取具有该深度的特定文件夹的路径;说到:也许您只是通过选择其中 一个 来寻找最大深度路径的 example,但请注意,可以有 multiple 个(我已经为我的答案添加了一个解决方案,可以得到 all 个)。
    • 至于你的具体代码:注意@{ ... }是一个hashtable,而不是一个数组,你可以把它转换成[pscustomobject]直接构造一个自定义的对象 - 事实上,这对于保证对象的属性在导出到 CSV 文件时以哈希表中指定的顺序出现是必要的。您不需要数组即可将单个自定义对象发送到 Export-Csv,并使用 += should generally be avoided 迭代构建数组。
    • 另外,如果你使用$servers | ForEach-Object { ...; $output } | Export-Csv ... 而不是foreach 循环,你只需要一个Export-Csv 调用(没有-Append),它更干净、更高效。请注意,您需要在 ForEach-Object 脚本块 ({ ... }) 中将手头的服务器称为 $_$output 然后简单地将您的自定义对象输出 到管道,然后Export-Csv 将它接收到的所有输出对象写入目标文件。
    • @mklement0 好的,谢谢;您所说的某些内容超出了我目前对 powershell 的理解,但我会看看我是否可以深入研究您的 cmets 以获得进一步的学习机会。感谢您的跟进。
    【解决方案2】:

    这里是“计算路径部分”解决方案的一个轻微变体。 [grin] 它计算 分隔符。如果您的路径是 UNC 路径或本地路径,这仍然会为您提供最深的嵌套目录。

    但是,它不适用于混合的 UNC [\\SysName\ShareName] 和本地 [c:\] 路径。

    此外,它不会从结果中删除起始目录。

    另外,我不确定 想要count number of parent folders。所以我只是发布了分隔符计数。

    它的作用...

    • 设置工作的顶级目录
    • 获取目录分隔符字符
    • 创建该字符的正则表达式转义版本
    • 抓取目标目录树中的所有目录
    • 按删除所有内容时剩余的字符串长度[按降序排列]除了目录分隔符
    • 获取这些目录中的第一个
    • 显示该目录的.FullName
    • 在上面的字符串中显示目录分隔符的数量

    代码...

    $TargetTopDir = $env:APPDATA
    $DirDelim = [System.IO.Path]::DirectorySeparatorChar
    $RegexDD = [regex]::Escape($DirDelim)
    
    $DirList = Get-ChildItem -LiteralPath $TargetTopDir -Directory -Recurse
    
    $DeepestNestedDir = ($DirList |
        Sort-Object {$_.FullName -replace "[^$RegexDD]"} -Descending)[0]
    
    $DeepestNestedDir.FullName
    'DirDelimCount = {0}' -f ($DeepestNestedDir.FullName -replace "[^$RegexDD]").Length
    

    输出...

    C:\Users\MyUserName\AppData\Roaming\Thunderbird\Profiles\shkjhmpc.default\extensions\{e2fda1a4-762b-4020-b5ad-a41df1933103}\chrome\calendar-gd\locale\gd\calendar\dialogs
    DirDelimCount = 15
    

    【讨论】:

      【解决方案3】:

      由于您试图找到最大的计数,听起来您需要进行比较。基本上,从 0 的大小开始 - 如果您正在查看的文件夹比那个大,那么它就会变成最大的。您对所有文件夹执行此操作,直到剩下最大的文件夹。请注意,如果有任何联系,此方法将不起作用,但听起来不像您正在寻找的那样。我应该添加这是查看单台计算机的主要代码。您可以为多个服务器包装 foreach {$server in $servers}

      $folders = Get-ChildItem -Path "C:\Directory" -Directory -Recurse
      $n = 0
      $biggest = ""
      foreach ($folder in $folders)
      {
          $splitout = $folder.FullName.split("\")
          if ($splitout.count -gt $n)
          {
              $n = $splitout.count
              $biggest = $folder
          }
      }
      
      Write-host "Count $n - $biggest"
      

      【讨论】:

      • 这让我走上了正轨;非常感谢。
      【解决方案4】:

      解决你的核心问题:

      对于给定的$path,您可以在其子树中找到最大目录深度 - 表示为路径分隔符的数量(Windows 上为\,Unix 上为/)加一在$path 内嵌套最深的子目录的完整路径中 - 如下:

      # Outputs the number of path components of the most deeply nested folder in $path.
      (Get-ChildItem $path -Recurse -Directory | 
         Measure-Object -Maximum { ($_.FullName -split '[\\/]').Count }
      ).Maximum
      

      注意:如果您想知道 relative 深度 - 相对于 $path,请将 -Name 添加到 Get-ChildItem 调用并在脚本块内将 $_.FullName 替换为 $_ ({ ... }) 传递给Measure-Object0 的结果则意味着 $path 根本没有子目录,1 意味着只有直接子目录,2 意味着直接子目录本身(只有)子目录,...

      • Get-ChildItem -Recurse -Directory $path输出目录$path的(-Recurse)的整个子树中的所有子目录(-Directory);添加-Force 以包含隐藏的子目录。 - 见Get-ChildItem

      • Measure-Object -Maximum { ($_.FullName -split '[\\/]').Count } 在每个目录的完整路径 ($_.FullName) 中计算路径分隔符的数量([\\/] 是一个匹配单个 \/ 字符的正则表达式。) - 使用 脚本块 {...} 作为(隐含的)-Property 参数,其中$_ 代表手头的输入路径 - 并确定最大值(-Maximum);假设Measure-Object 输出一个Microsoft.PowerShell.Commands.GenericMeasureInfo 实例,则可以通过.Maximum 属性访问原始最大值。


      所有附带的任务 - 将此计算应用于多个服务器,将结果写入服务器特定的文件 - 可以使用常用的 cmdlet(Get-ContentForEach-ObjectSet-ContentOut-File / > )。


      更快的选择:

      上述命令简洁且符合 PowerShell 习惯,但速度有些慢。 下面是一个直接使用 LINQ 和 .NET API 的明显更快的替代方案:

      # Note: Makes sure that $path is a *full* path, because .NET's current
      #       directory usually differs from PowerShell's.
      1 + [Linq.Enumerable]::Max(
        ([System.IO.Directory]::GetDirectories(
          $path, '*', 'AllDirectories'
        ) -replace '[^\\/]').ForEach('Length')
      )
      

      注意:以上内容也总是包含隐藏目录。在 .NET Core / .NET 5+ 中,[System.IO.Directory]::GetDirectories() 现在提供了一个 additional overload,它提供了对枚举的更多控制。


      列出最大深度的目录:

      如果您不仅要计算最大深度,还想列出所有具有最大深度的目录(注意可以有多个):

      # Sample input path.
      # Note: Makes sure that $path is a *full* path, because .NET's current
      #       directory usually differs from PowerShell's.
      $path = $PWD
      
      # Extract all directories with the max. depth using Group-Object:
      # Group by the calculated depth and extract the last group, which relies on
      # Group-Object outputting the results sorted by grouping criteria.
      $maxDepthGroup = 
        [System.IO.Directory]::GetDirectories($path, '*', 'AllDirectories') | 
          Group-Object { ($_ -split '[\\/]').Count } |
            Select-Object -Last 1
      
      # Construct the output object.
      [pscustomobject] @{
        MaxDepth = $maxDepthGroup.Values[0] # The grouping criterion, i.e. the depth.
        MaxDepthDirs = $maxDepthGroup.Group # The paths comprising the group.
      }
      

      输出是一个自定义对象,具有.MaxDepth.MaxDepthDirs(具有最大深度的那些目录的完整路径的数组)属性。如果你将它通过管道发送到Format-List,你会得到类似的东西:

      MaxDepth     : 6
      MaxDepthDirs : {/Users/jdoe/Documents/Ram Dass Audio Collection/The Path of Service, /Users/jdoe/Documents/Ram Dass Audio Collection/Conscious Aging,
                     /Users/jdoe/Documents/Ram Dass Audio Collection/Cultivating the Heart of Compassion, /Users/jdoe/Documents/Cheatsheets/YAML Ain't
                     Markup Language_files}
      

      【讨论】:

        猜你喜欢
        • 2014-03-13
        • 2020-10-07
        • 2020-05-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-13
        • 2015-04-10
        相关资源
        最近更新 更多