PowerShell中获取-DiskUsage的cmdlet:如何从不同的驱动器/目录清单?(Pow

2019-08-31 23:16发布

我在PowerShell中的相对新手,想知道多一点功能,cmdlet,但人类可读的值。 通常对于学习新的东西,看着别人怎么做效果很好。

所以我去寻找并撞到源的获取,DiskUsage cmdlet的。

我可以 。 源此为PowerShell中,然后调用该函数。

不知何故,它总是使用当前目录得到的结果,无论我怎么称呼它。

我在想什么,它不会采取给-Path参数?

PS D:\bin> . .\DiskUsage.ps1
PS D:\bin> Get-DiskUsage -Path D:\ -h

Size Folder
---- ------
405M


PS D:\bin> Get-DiskUsage -Path C:\ -h

Size Folder
---- ------
405M


PS D:\bin> C:
PS C:\> Get-DiskUsage -Path C:\ -h

Size Folder
---- ------
 18G


PS C:\>

脚本输出是不正确的,因为这是对的Sysinternals DiskUsage工具都显示:

D:\bin>du C:\

Du v1.4 - report directory disk usage
Copyright (C) 2005-2011 Mark Russinovich
Sysinternals - www.sysinternals.com

Files:        93367
Directories:  22541
Size:         21.817.875.778 bytes
Size on disk: 22.127.992.832 bytes


D:\bin>du D:\

Du v1.4 - report directory disk usage
Copyright (C) 2005-2011 Mark Russinovich
Sysinternals - www.sysinternals.com

Files:        132832
Directories:  15125
Size:         130.137.231.457 bytes
Size on disk: 54.992.396.288 bytes


D:\bin>du D:\bin

Du v1.4 - report directory disk usage
Copyright (C) 2005-2011 Mark Russinovich
Sysinternals - www.sysinternals.com

Files:        3118
Directories:  222
Size:         424.866.944 bytes
Size on disk: 288.858.112 bytes

Answer 1:

Get-DiscUsage C:\ # NOT RECOMMENDED

Get-DiskUsage -Path C:\Users\JBennett\SkyDrive\WindowsPowershell\Scripts\IO\

Size Folder
---- ------
223424B C:\Users\JBennett\SkyDrive\WindowsPowershell\Scripts\IO\DU

无论哪种方式,对我的作品(第一点采购的剧本后,像你说的)。

我不得不说虽然,我不会使用...它做一次迭代的PowerShell的扫描,生成(千)的DirectoryInfo对象,然后它做的是另递归目录扫描在每个文件夹,创建一个新的对象,总结性......这是可怕慢,而且会消耗大量的内存和IO相比du.exe

稍微好一点的办法

如果你想在一棵树的每个文件夹的大小,递归,做到这一点的算法正确的方式不涉及对GET-ChildItem的-Recurse标志。 你可能会做这样的事情:

function Get-Size {
  #.Synopsis
  #  Calculate the size of a folder on disk
  #.Description
  #  Recursively calculate the size of a folder on disk,
  #  outputting it's size, and that of all it's children,
  #  and optionally, all of their children
  param(
    [string]$root,
    # Show the size for each descendant recursively (otherwise, only immediate children)
    [switch]$recurse
  )
  # Get the full canonical FileSystem path:
  $root = Convert-Path $root

  $size = 0
  $files = 0
  $folders = 0

  $items = Get-ChildItem $root
  foreach($item in $items) {
    if($item.PSIsContainer) {
      # Call myself recursively to calculate subfolder size
      # Since we're streaming output as we go, 
      #   we only use the last output of a recursive call
      #   because that's the summary object
      if($recurse) {
        Get-Size $item.FullName | Tee-Object -Variable subItems
        $subItem = $subItems[-1]
      } else {
        $subItem = Get-Size $item.FullName | Select -Last 1
      }

      # The (recursive) size of all subfolders gets added
      $size += $subItem.Size
      $folders += $subItem.Folders + 1
      $files += $subItem.Files
      Write-Output $subItem
    } else {
      $files += 1
      $size += $item.Length
    }
  }

  # in PS3, use the CustomObject trick to control the output order
  if($PSVersionTable.PSVersion -ge "3.0") {
    [PSCustomObject]@{ 
      Folders = $folders
      Files = $Files
      Size = $size
      Name = $root
    }
  } else {
    New-Object PSObject -Property @{ 
      Folders = $folders
      Files = $Files
      Size = $size
      Name = $root
    }
  }
}

这样一来,你不是什么上市不止一次。 不利的一面是,你必须添加了一切自己,因为你不能只使用测量-对象。

在OP中引用的脚本实际上不过很多时候它是深列出每个项目。 也就是说,如果一个文件位于C:\用户\ Jaykul \文档\ WindowsPowerShell \ Scripts中......它会在显示gci -recurse每个父文件夹-五次如果调用根的脚本。

当然,你还为每个文件和每个目录一个DirectoryInfo,再加上我的手在脚本创建的总结PSObject创建一个FileInfo,因此,即使这是几乎一样快du.exe,那就得显著更多对记忆的影响。

然而,这是固有的权衡在PowerShell中:这是容易做到的事......因为我们有重物。 我们高兴地贸易的易用性存储器,有时甚至影响性能。 这就是说:是的,du.exe会更快,但它是一招的小马,有人专门写一个目的。 它仍然是最好的方式,如果你想要做的一切都运行它,并读取输出。 但它产生你要解析,如果你想使用它在脚本输出文本输出,这真的很难收集信息作为整体仪表板风格的监控脚本输出的一部分...



Answer 2:

我将Get-DiskUsage脚本的创作者。 我诚实地不知道为什么它不走-Path你。 对我来说工作正常。 真是奇怪。 快速的问题虽然 - 你尝试输入路径为d:而不是d:\?

@Jaykul - 这样做的很不错的替代方式。 我必须承认,我不知道在recusion使用递归的内存命中。 我总是记缓慢的事实,即$结果没有得到输出直到所有其他caclulations齐全。 我之所以做了递归,然后再很简单 - 第一递归列出了从ROOTPATH所有文件夹(会使列表),第二个我注意到,我需要的,因为如果我不结果将是一个大小并不总是准确



Answer 3:

我喜欢Jaykul的答案,但它在PS 2.0中的错误,当一个目录是空的,它返回错误的答案。 我还修改了它支持力控开关和深度交换机而不是递归的,类似于原来的获取,DiskUsage脚本。

function Get-Size {
    #.Synopsis
    #  Calculate the size of a folder on disk
    #.Description
    #  Recursively calculate the size of a folder on disk,
    #  outputting it's size, and that of all it's children,
    #  and optionally, all of their children
    param(
        [string]$root=$PWD,
        # Show the size for each descendant recursively (otherwise, only immediate children)
        [Int]$Depth=1,
        [Switch]$Force
    )
    # Get the full canonical FileSystem path:
    $root = Convert-Path $root
    $DetailDepth = $Depth - 1
    $size = 0
    $files = 0
    $folders = 0
    $items = Get-ChildItem $root -Force:$Force
    foreach($item in $items) {
        if($item.PSIsContainer) {

            # Clear subItem in case the directory is empty.
            $subItem = @{ Folders = 0
                Files = 0
                Size = 0
                Name = $item.FullName }


            # Call myself recursively to calculate subfolder size
            # Since we're streaming output as we go, 
            #   we only use the last output of a recursive call
            #   because that's the summary object
            if($DetailDepth -ge 1) {
                Get-Size $item.FullName -Depth $DetailDepth -Force:$Force | Tee-Object -Variable subItems
                if($subItems.GetType().FullName -eq "System.Management.Automation.PSCustomObject") {
                    $subItem = $subItems
                } else {
                    $subItem = $subItems[-1]
                }
            } else {

                $subItem = Get-Size $item.FullName -Force:$Force | Select -Last 1
            }
            # The (recursive) size of all subfolders gets added
            $size += $subItem.Size
            $folders += $subItem.Folders + 1
            $files += $subItem.Files
            # avoid duplication by letting the parent report the summary values, except at the lowest detail depth
            if( $DetailDepth -lt 1) { 
                Write-Output $subItem
            }
        } else {
            $files += 1
            $size += $item.Length
        }
    }

    # in PS3, use the CustomObject trick to control the output order
    if($PSVersionTable.PSVersion -ge "3.0") {
        [PSCustomObject]@{ 
            Folders = $folders
            Files = $files
            Size = $size
            Name = $root
        }
    } else {
        New-Object PSObject -Property @{ 
            Folders = $folders
            Files = $files
            Size = $size
            Name = $root
        } 
    }
}


文章来源: PowerShell Get-DiskUsage CmdLet: how to list from a different drive/directory?