使用PowerShell计算文件夹深度

问题描述 投票:3回答:1

1.代码说明别名如何工作

用户在PowerShell中输入目录的路径。代码检查声明的目录中的任何文件夹是否根本不包含任何数据。如果是这样,任何空文件夹的路径将显示在用户的提示上,并最终从系统中删除。


2.问题别名我正在努力解决的问题

我刚写的代码没有像我期望的那样计算文件夹层次结构的深度(输出表中的列是空白的)。除此之外,程序运行正常 - 我仍然需要解决我的代码首先删除空父目录和子目录的问题,这当然会在PowerShell中导致错误;例如,拿走

C:\Users\JohnMiller\Desktop\Homework

其中HomeworkHomework\Math\School ProjectHomework\Computer Science\PowerShell Code组成。请注意,除PowerShell Code(包含此脚本的文件夹)外,所有目录都应为空。 (旁注:当没有文件驻留在内部时,文件夹被认为是空的。至少这是我的代码现在所基于的。)


3.守则

# Delete all empty (sub)folders in [$path]

[Console]::WriteLine("`n>> Start script for deleting all empty (sub)folders.")
$path = Read-Host -prompt ">> Specify a path"

if (test-path $path)
{
  $allFolders = Get-ChildItem $path -recurse | Where {$_.PSisContainer -eq $True}
  $allEmptyFolders = $allFolders | Where-Object {$_.GetFiles().Count -eq 0}
  $allEmptyFolders | Select-Object FullName,@{Name = "FolderDepth"; Expression = {$_.DirectoryName.Split('\').Count}} | Sort-Object -descending FolderDepth,FullName

  [Console]::WriteLine("`n>> Do you want do remove all these directories? Validate with [True] or [False].") #'#
  $answer = Read-Host -prompt ">> Answer"

  if ([System.Convert]::ToBoolean($answer) -eq $True)
  {
    $allEmptyFolders | Remove-Item -force -recurse
  } 

  else
  {
    [Console]::WriteLine(">> Termination confirmed.`n")
    exit
  }
}

else
{
  [Console]::WriteLine(">> ERROR: [$($path)] is an invalid directory. Program terminates.`n")
  exit
}
powershell calculated-columns powershell-v4.0
1个回答
2
投票

The depth-count problem:

您的代码引用传递给.DirectoryName的计算属性中的Select-Object属性,但[System.IO.DirectoryInfo]输出的Get-ChildItem实例没有此类属性。请改用.FullName属性:

$allEmptyFolders | 
  Select-Object FullName,@{Name='FolderDepth'; Expression={$_.FullName.Split('\').Count}} |
    Sort-Object -descending FolderDepth,FullName

Eliminating nested empty subfolders:

用一个简单的例子来回顾你的问题:

如果c:\foo为空(没有文件)但是有空子目录。 c:\foo\bar,你的代码输出它们两个,如果你然后删除c:\foo,删除c:\foo\bar接下来失败(因为删除c:\foo也删除了c:\foo\bar)。

如果消除所有嵌套的空子目录。在前面,您不仅要将您呈现的内容整理到用户,还可以安全地迭代输出并逐个删除。

使用您的方法,您需要第二步来消除嵌套的空目录。但这是一个深度优先的递归函数,它省略了嵌套的空文件夹。要使其行为与隐藏文件的代码相同,请传递-Force

function Get-RecursivelyEmptyDirectories {

  [cmdletbinding()]
  param(
    [string] $LiteralPath = '.', 
    [switch] $Force, 
    [switch] $DoNotValidatePath
  )

  $ErrorActionPreference = 'Stop'

  if (-not $DoNotValidatePath) {
    $dir = Get-Item -LiteralPath $LiteralPath
    if (-not $dir.PSIsContainer) { Throw "Not a directory path: $LiteralPath" }
    $LiteralPath = $dir.FullName
  }

  $haveFiles = [bool] (Get-ChildItem -LiteralPath $LiteralPath -File -Force:$Force | Select-Object -First 1)

  $emptyChildDirCount = 0
  $emptySubdirs = $null

  if ($childDirs = Get-ChildItem -LiteralPath $LiteralPath -Directory -Force:$Force) {

    $emptySubDirs = New-Object System.Collections.ArrayList
    foreach($childDir in $childDirs) {
      if ($childDir.LinkType -eq 'SymbolicLink') { 
        Write-Verbose "Ignoring symlink: $LiteralPath"
      } else {
        Write-Verbose "About to recurse on $($childDir.FullName)..."
        try { # If .AddRange() fails due to exceeding the array list's capacity, we must fail too.
          $emptySubDirs.AddRange(@(Get-RecursivelyEmptyDirectories -DoNotValidatePath -LiteralPath $childDir.FullName -Force:$Force))        
        } catch {
          Throw
        }
        # If the last entry added is the child dir. at hand, that child dir.
        # is by definition itself empty.
        if ($emptySubDirs[-1] -eq $childDir.FullName) { ++$emptyChildDirCount }
      }
    } # foreach ($childDir ...

  } # if ($childDirs = ...)

  if (-not $haveFiles -and $emptyChildDirCount -eq $childDirs.Count) {
    # There are no child files and all child dirs., if any, are themselves
    # empty, so we only output the input path at hand, as the highest
    # directory in this subtree that is empty (save for empty descendants).
    $LiteralPath
  } else {
    # This directory is not itself empty, so output the (highest-level)
    # descendants that are empty.
    $emptySubDirs
  }

}

有关您的代码的提示:

  • Get-ChildItem -Directory可以在PSv3 +中使用,它不仅更短,而且比Get-ChildItem | .. Where { $_.PSisContainer -eq $True }更有效。
  • 使用Write-Host而不是[Console]::WriteLine
  • [System.Convert]::ToBoolean($answer)仅适用于文化不变的字符串文字'True''False'[bool]::TrueString[bool]::FalseString,尽管允许使用案例变体和前导和尾随空格)。
© www.soinside.com 2019 - 2024. All rights reserved.