Powershell - 在目录的长文件路径中查找嵌套文件夹的数量

Powershell - Find # of nested folders in long file path of a directory

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

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

抱歉,我只是足够好,有点危险。

解决你的核心问题:

对于给定的 $path,您可以在其子树中找到 最大目录深度 - 表示为路径分隔符的数量(\ Windows, / on Unix) 在 full 路径中最深嵌套的子目录里面 $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

注意:如果您想知道 相对 深度 - 相对于 $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 outputs a Microsoft.PowerShell.Commands.GenericMeasureInfo 实例,通过 .Maximum 属性.

    访问原始最大值

所有附带任务 - 将此计算应用于多个服务器,将结果写入 server-specific 文件 - 可以使用常用的 cmdlet (Get-Content, ForEach-Object, Set-Content or Out-File / >) 完成。


更快的选择:

上面的命令简洁PowerShell-idiomatic,但是有点慢。 这是一个明显更快的替代方法,它直接使用 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,可以更好地控制枚举。


也列出 maximum-depth 目录:

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

# 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}

由于您要查找最大计数,因此您似乎需要进行比较。基本上,从大小 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"

这是“计算路径部分”解决方案的一个细微变体。 [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

这就完成了;再次感谢大家的帮助!

$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
}