我是PowerShell的相对新手,想要了解更多关于函数,CmdLet和人类可读值的信息。通常用于学习新事物,看看其他人做得好的事情。
所以我去寻找并碰到Get-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工具du显示的内容:
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
答案 0 :(得分:3)
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对象,然后它再做一个递归目录扫描ON EACH FOLDER,创建一个新对象并对属性求和......它的速度非常慢,与du.exe相比会占用大量内存和IO
当你想要树中每个文件夹的SIZE时,递归地,以算法正确的方式执行该操作并不涉及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
}
}
}
这样,您就不会多次列出任何内容。不好的一面是你必须自己添加所有东西,因为你不能只使用Measure-Object。
OP中引用的脚本实际上列出了每个项目,但很多时候它都很深。也就是说,如果文件位于C:\ Users \ Jaykul \ Documents \ WindowsPowerShell \ Scripts ...中,它将显示在每个父文件夹的gci -recurse
中 - 如果您在根目录上调用脚本,则会出现五次
当然,您仍然为每个目录创建一个FileInfo,为每个目录创建一个DirectoryInfo,以及我在脚本中手动创建的摘要PSObject,所以即使这是几乎与du.exe一样快,它对内存的影响会更大。
然而,这是PowerShell的固有权衡:它更容易做事......因为我们有重物。我们很乐意将易用性用于记忆,有时甚至会影响性能。也就是说:是的,du.exe会更快,但它是一个单一的小马,有人必须专门为一个目的写。它仍然是最好的方法,如果你想做的就是运行它并读取输出。但如果你想在脚本中使用它的输出,它会生成你必须解析的文本输出,并且很难将这些信息收集作为整个仪表板式监视脚本输出的一部分...
答案 1 :(得分:1)
我是Get-DiskUsage脚本的创建者。我老实说不知道为什么它不会为你带走-Path。对我来说很好。真的很奇怪。但是快速问题 - 您是否尝试将路径键入D:而不是D:\?
@Jaykul - 非常好的替代方式。我必须承认,我不知道在重复使用递归的内存命中。我总是认为,在所有其他的计算完成之前,$ results不会输出这一事实的速度很慢。 我做一个递归然后再次的原因很简单 - 第一个递归列出了根路径中的所有文件夹(将列表)和第二个我注意到我需要的文件夹因为如果我没有,结果将是一个大小并不总是准确的
答案 2 :(得分:1)
我喜欢Jaykul的回答,但它在PS 2.0中有一个错误,当目录为空时它会返回错误的答案。我还修改了它以支持强制切换和深度切换而不是递归,类似于原始的Get-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
}
}
}