1

私は 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
4

3 に答える 3

4
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オブジェクトを生成してから、各フォルダーで別の再帰的なディレクトリスキャンを実行し、新しいオブジェクトを作成してプロパティを合計します... 恐ろしく遅く、du.exe に比べて大量のメモリと IO を消費します。

少し良い方法

ツリー内のすべてのフォルダーのサイズが再帰的に必要な場合、それを行うアルゴリズム的に正しい方法は、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親フォルダーごとに表示されます。ルートでスクリプトを呼び出すと、5 回表示されます。

もちろん、すべてのファイルに対して FileInfo を作成し、すべてのディレクトリに対して DirectoryInfo を作成しているだけでなく、スクリプトで手動で作成した要約 PSObject も作成しているため、これがdu.exe とほぼ同じ速さであったとしても、はるかに多くの情報が必要になります。メモリへの影響。

ただし、これは PowerShell 固有のトレードオフです。オブジェクトが重いため、操作が簡単になります。使いやすさとメモリの交換は喜んで行いますが、場合によってはパフォーマンス ヒットさえも犠牲にします。つまり、はい、du.exe の方が高速ですが、これは、誰かが 1 つの目的のために特別に作成しなければならなかったワントリック ポニーです。実行して出力を読み取るだけであれば、これが最善の方法です。しかし、スクリプトで出力を使用したい場合は解析しなければならないテキスト出力が生成され、ダッシュボード スタイルの監視スクリプト全体の出力の一部としてその情報を収集するのは非常に困難です...

于 2013-04-25T00:52:38.623 に答える
1

私は Get-DiskUsage スクリプトの作成者です。なぜ -Path を使用しないのか、正直なところわかりません。私にとってはうまくいきます。本当に変です。簡単な質問ですが、パスを D:\ ではなく D: と入力しようとしましたか?

@ Jaykul - それを行うための非常に素晴らしい代替方法。再帰で再帰を使用することによるメモリ ヒットについては知らなかったことを認めなければなりません。私は常に、他のすべての計算が完了するまで $results が出力されないという事実に遅さを認めました。私が再帰を行った理由は簡単です.最初の再帰はルートパスからのすべてのフォルダをリストし(リストを作成します)、2番目の再帰は必要であることに気付きました。常に正確ではなかった

于 2013-05-23T04:55:36.397 に答える