Scripting Guys が皆さんの質問にお答えします

関連情報
Hey, Scripting Guys! のその他の記事もチェックしてください。
Hey, Scripting Guy! コンピューターで多くの領域を占有しているフォルダーを確認する方法はありますか

-- EC

100 年の歴史を持つ褐色砂岩の建物へ続く路地にはウイスキーのボトルが散らばり、暗い青色の空が重々しく覆い被さっています。影がゆっくりと壁を這い、自由の女神の頂上に向かう狭い階段を案内する 70 歳の男のような私の背筋に、ある予感が走りました。チリンという音が、切れないバター ナイフでベーグルを切り分けるように、スモッグで覆われた空気を切り裂きました。Windows Vista を搭載した新しいラップトップ コンピューターが夕方の宅配便で私のもとへ届いたのが、つい去年のことのようです。ディスク領域は、アオスケ、アカベエ、ピンキー、グズタ


今週は、先日開催された
2009 年夏季スクリプト競技大会中に提出されたスクリプトのいくつかを紹介します。2009 年夏季スクリプト競技大会の説明
(英語) では、すべてのイベントの詳細が示されています。それぞれのイベントには、各分野で世界的に認められた専門家が解答してくれました。いくつかのすてきな賞品が提供され、世界中から当選者が出ました。また、多くのことが行われていたので、"本当のオリンピック"
と同様に、迷った方のためのページ (英語) が作成されました。参加者とのコミュニケーションは、Twitter
(英語)
、Facebook (英語)
、および専用のフォーラムを通じて行われました(専用のフォーラムは既になくなりましたが、私たちは引き続き Twitter と Facebook を使用して Hey, Scripting Guy! ファンの方々とコミュニケーションをとっています)。Windows PowerShell を使用した解答を重点的に取り上げる予定です。Windows PowerShell
の概要について説明した、皆さんのお役に立ちそうな優れた Hey, Scripting Guy! コラム (英語) がいくつかあります。
2009 年夏季スクリプト競技大会の初心者向けのイベント 8 は棒高跳びで、ディスク領域の多くを占有しているフォルダーを特定するスクリプトを記述するという課題でした。Tojo2000 さんは初心者向けのイベント 8 の解答として、Windows PowerShell 2.0 を使用した関数を提出してくれました。その関数を次に示します。
(注: PoshCode から取得した Tojo2000 さんが記述した関数は、Windows PowerShell 2.0 の RTM 版で実行すると、help タグで問題が発生しました。これは、Community Technology Preview 3 以降では、returnvalue タグの名前が outputs に変更されたためです。そのため、次の関数には若干修正を加えてあります)。
Get-DirSizeFunction.ps1
function Get-DirSize {
<#
概要:
ディレクトリおよびサイズの一覧を取得します。
説明:
この関数では再帰的にディレクトリ ツリーを処理し、
検出された各ディレクトリのサイズを返します。
パラメーターのパス:
スキャンを開始するルート フォルダーのパス。
例:
(Get-DirSize $env:userprofile | sort Size)[-2]
ユーザー プロファイルの下で最も大きいフォルダーを取得します。
例:
Get-DirSize -path "c:\data" | Sort-Object -Property size -Descending
c:\data 配下のフォルダーとサブフォルダーを、サイズが大きい方から順に表示します。
出力:
[PSObject]
メモ:
名前: Get-DirSize
作成者: ToJo2000
最終更新日: 2009 年 8 月 12 日
キーワード: 2009 年夏季スクリプト競技大会、初心者向けのイベント 8 、Get-ChildItem、ファイルとフォルダー
リンク:
http://technet.microsoft.com/ja-jp/scriptcenter/default.aspx
#Requires -Version 2.0
#>
param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string]$path)
BEGIN {}
PROCESS{
$size = 0
$folders = @()
foreach ($file in (Get-ChildItem $path -Force -ea SilentlyContinue)) {
if ($file.PSIsContainer) {
$subfolders = @(Get-DirSize $file.FullName)
$size += $subfolders[-1].Size
$folders += $subfolders
} else {
$size += $file.Length
}
}
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name Folder `
-Value (Get-Item $path).FullName
$object | Add-Member -MemberType NoteProperty -Name Size -Value $size
$folders += $object
Write-Output $folders
}
END {}
} # Get-DirSize 関数の終わり
function Get-DirSize {
<#
概要:
ディレクトリおよびサイズの一覧を取得します。
説明:
この関数では再帰的にディレクトリ ツリーを処理し、
検出された各ディレクトリのサイズを返します。
パラメーターのパス:
スキャンを開始するルート フォルダーのパス。
例:
(Get-DirSize $env:userprofile | sort Size)[-2]
ユーザー プロファイルの下で最も大きいフォルダーを取得します。
例:
Get-DirSize -path "c:\data" | Sort-Object -Property size -Descending
c:\data 配下のフォルダーとサブフォルダーを、サイズが大きい方から順に表示します。
出力:
[PSObject]
メモ:
名前: Get-DirSize
作成者: ToJo2000
最終更新日: 2009 年 8 月 12 日
キーワード: 2009 年夏季スクリプト競技大会、初心者向けのイベント 8 、Get-ChildItem、ファイルとフォルダー
リンク:
http://technet.microsoft.com/ja-jp/scriptcenter/default.aspx
#Requires -Version 2.0
#>
param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string]$path)
BEGIN {}
PROCESS{
$size = 0
$folders = @()
foreach ($file in (Get-ChildItem $path -Force -ea SilentlyContinue)) {
if ($file.PSIsContainer) {
$subfolders = @(Get-DirSize $file.FullName)
$size += $subfolders[-1].Size
$folders += $subfolders
} else {
$size += $file.Length
}
}
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name Folder `
-Value (Get-Item $path).FullName
$object | Add-Member -MemberType NoteProperty -Name Size -Value $size
$folders += $object
Write-Output $folders
}
END {}
} # Get-DirSize 関数の終わり
関数のすばらしいところは、柔軟性が非常に高いことです。関数の問題点は、何かしらの方法で読み込まなければ使用できないことです。これは問題というよりも手順が 1 つ増えるだけですが、VBScript を使用している多くの方は、この処理に馴染みがないでしょう。関数を個別のファイルに保存して、Windows PowerShell コンソール セッションに含めるのが、最も簡単に関数を処理する方法かもしれません。Windows PowerShell セッションに関数を含めるには、ファイルのパスの前にピリオドを付けます。こうすると、コマンドレットと同様に、関数を処理できるようになります (実際、Windows PowerShell 2.0 の高度な関数は、当初 "スクリプト コマンドレット" と呼ばれていました)。関数を Windows PowerShell コンソールに読み込むと、Get-Help コマンドレットを使用して関数のヘルプ情報を参照できます。また、関数を直接使用したり、関数の出力を Sort-Object コマンドレットなどの別のコマンドレットにパイプライン処理することもできます。Windows PowerShell 2.0 と関数で 1 つすばらしいのは、対話的に使用している場合でもタブ補完機能を実行できることです。その証拠を以下に示します。
Windows PowerShell コンソールから直接関数を使用する以外に、Windows PowerShell プロファイル、関数ライブラリ、またはモジュールに関数を含めることもできます (モジュールは Windows PowerShell 2.0 の機能です)。もちろん、スクリプトに関数を配置することもできるので、私はそうすることにしました。
Windows PowerShell を使用した ScriptingGamesBeginnerEvent8.ps1 スクリプトでは、Tojo2000 さんの Get-DirSize 関数を利用し、コマンドライン パラメーター、並べ替え、および書式設定を行う機能を追加しています。Tojo2000 さんは、既に Windows PowerShell 2.0 の help タグ (これは Windows PowerShell 1.0 では機能しません) をスクリプトに組み込んでいたので、勝手ながらスクリプトと数値の形式を設定する関数にさらに詳細なヘルプ情報を追加させていただくことにしました。多くのコンピューターでは、まだ Windows PowerShell 1.0 を実行している可能性があります。Windows PowerShell 2.0 の機能を使用する場合は、requires -version 2.0 タグを含めることをお勧めします。どのような機能か定かでない場合、Windows PowerShell 2.0 を使用して作成したスクリプトは Windows PowerShell 1.0 で十分にテストを行うか、すべてのスクリプトに requires -version 2.0 タグを含めることを推奨します。このコマンドの構文は、次のとおりです。
#requires -version 2.0
#requires -version 2.0
ScriptingGamesBeginnerEvent8.ps1 スクリプト全体を以下に示します。
ScriptingGamesBeginnerEvent8.ps1
<#
概要:
最も大きいフォルダーから 5 番目に大きいフォルダーまでと、それぞれのサイズを一覧表示します。
説明:
このスクリプトでは、最も大きいフォルダーから 5 番目に大きいフォルダーまでと、それぞれのサイズを一覧表示します。
例:
ScriptingGamesBeginnerEvent8.ps1 -path C:\fso -first 3
C:\fso 親ディレクトリ内で最も大きいフォルダーから 3 番目に大きいフォルダーまでを返します。
入力:
[string]
出力:
[string]
メモ:
名前: ScriptingGamesBeginnerEvent8.ps1
作成者: Ed Wilson
最終更新日: 2009 年 5 月 20 日
キーワード: 2009 年夏季スクリプト競技大会、初心者向けのイベント 8 、Get-ChildItem、ファイルとフォルダー
リンク:
http://technet.microsoft.com/ja-jp/scriptcenter/default.aspx
#Requires -Version 2.0
#>
Param(
[string]$path = "c:\data1",
[int]$first = 5
)# Param ステートメントの終わり
# *** 関数の始まり ***
function Get-DirSize {
<#
概要:
ディレクトリとサイズの一覧を取得します。
説明:
この関数では再帰的にディレクトリ ツリーを処理し、
検出された各ディレクトリのサイズを返します。
パラメーターのパス:
スキャンを開始するルート フォルダーのパス。
例:
(Get-DirSize $env:userprofile | sort Size)[-2]
ユーザー プロファイルの下で最も大きいフォルダーを取得します。
例:
Get-DirSize -path "c:\data" | Sort-Object -Property size -Descending
c:\data 配下のフォルダーとサブフォルダーを、サイズが大きい方から順に表示します。
出力:
[PSObject]
メモ:
名前: Get-DirSize
作成者: ToJo2000
最終更新日: 2009 年 8 月 12 日
キーワード: 2009 年夏季スクリプト競技大会、初心者向けのイベント 8 、Get-ChildItem、ファイルとフォルダー
リンク:
http://technet.microsoft.com/ja-jp/scriptcenter/default.aspx
#Requires -Version 2.0
#>
param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string]$path)
BEGIN {}
PROCESS{
$size = 0
$folders = @()
foreach ($file in (Get-ChildItem $path -Force -ea SilentlyContinue)) {
if ($file.PSIsContainer) {
$subfolders = @(Get-DirSize $file.FullName)
$size += $subfolders[-1].Size
$folders += $subfolders
} else {
$size += $file.Length
}
}
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name Folder `
-Value (Get-Item $path).FullName
$object | Add-Member -MemberType NoteProperty -Name Size -Value $size
$folders += $object
Write-Output $folders
}
END {}
} # Get-DirSize 関数の終わり
Function Get-FormattedNumber($size)
{
<#
概要:
数値の形式を GB、MB、または KB 単位に設定します。
説明:
この関数ではバイト単位で渡された数値の形式を、
必要に応じて、GB、MB、または KB 単位に設定します。
また、小数点以下 2 桁までの数値と適切な文字列の修飾子を表示します。
出力される文字列の書式設定のみに使用します。
この関数では、技術的精度は維持されず、数値は小数第 3 位で四捨五入されます。
例:
Get-FormattedNumber -size 1025
1.00 KiloBytes と表示されます。
例:
Get-FormattedNumber -size 1026
9.79 MegaBytes と表示されます。
例:
Get-FormattedNumber -size 10261024
1.00 KiloBytes と表示されます。
入力:
[int32]
出力:
[string]
メモ:
名前: Get-FormattedNumber
作成者: Ed Wilson
最終更新日: 2009 年 8 月 12 日
キーワード: 数値の形式を設定する、管理用の定数、if/elseif/else、
.NET Framework の形式指定子、.NET Framework
リンク:
http://technet.microsoft.com/ja-jp/scriptcenter/default.aspx
#Requires -Version 2.0
#>
IF($size -ge 1GB)
{
"{0:n2}" -f ($size / 1GB) + " GigaBytes"
}
ELSEIF($size -ge 1MB)
{
"{0:n2}" -f ($size / 1MB) + " MegaBytes"
}
ELSE
{
"{0:n2}" -f ($size / 1KB) + " KiloBytes"
}
} # Get-FormattedNumber 関数の終わり
# *** スクリプトのエントリ ポイント ***
if(-not(Test-Path -Path $path))
{
Write-Host -ForegroundColor red "Unable to locate $path"
Help $MyInvocation.InvocationName -full
exit
}
Get-DirSize -path $path |
Sort-Object -Property size -Descending |
Select-Object -Property folder, size -First $first |
Format-Table -Property Folder,
@{ Label="Size of Folder" ; Expression = {Get-FormattedNumber($_.size)} }
<#
概要:
最も大きいフォルダーから 5 番目に大きいフォルダーまでと、それぞれのサイズを一覧表示します。
説明:
このスクリプトでは、最も大きいフォルダーから 5 番目に大きいフォルダーまでと、それぞれのサイズを一覧表示します。
例:
ScriptingGamesBeginnerEvent8.ps1 -path C:\fso -first 3
C:\fso 親ディレクトリ内で最も大きいフォルダーから 3 番目に大きいフォルダーまでを返します。
入力:
[string]
出力:
[string]
メモ:
名前: ScriptingGamesBeginnerEvent8.ps1
作成者: Ed Wilson
最終更新日: 2009 年 5 月 20 日
キーワード: 2009 年夏季スクリプト競技大会、初心者向けのイベント 8 、Get-ChildItem、ファイルとフォルダー
リンク:
http://technet.microsoft.com/ja-jp/scriptcenter/default.aspx
#Requires -Version 2.0
#>
Param(
[string]$path = "c:\data1",
[int]$first = 5
)# Param ステートメントの終わり
# *** 関数の始まり ***
function Get-DirSize {
<#
概要:
ディレクトリとサイズの一覧を取得します。
説明:
この関数では再帰的にディレクトリ ツリーを処理し、
検出された各ディレクトリのサイズを返します。
パラメーターのパス:
スキャンを開始するルート フォルダーのパス。
例:
(Get-DirSize $env:userprofile | sort Size)[-2]
ユーザー プロファイルの下で最も大きいフォルダーを取得します。
例:
Get-DirSize -path "c:\data" | Sort-Object -Property size -Descending
c:\data 配下のフォルダーとサブフォルダーを、サイズが大きい方から順に表示します。
出力:
[PSObject]
メモ:
名前: Get-DirSize
作成者: ToJo2000
最終更新日: 2009 年 8 月 12 日
キーワード: 2009 年夏季スクリプト競技大会、初心者向けのイベント 8 、Get-ChildItem、ファイルとフォルダー
リンク:
http://technet.microsoft.com/ja-jp/scriptcenter/default.aspx
#Requires -Version 2.0
#>
param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string]$path)
BEGIN {}
PROCESS{
$size = 0
$folders = @()
foreach ($file in (Get-ChildItem $path -Force -ea SilentlyContinue)) {
if ($file.PSIsContainer) {
$subfolders = @(Get-DirSize $file.FullName)
$size += $subfolders[-1].Size
$folders += $subfolders
} else {
$size += $file.Length
}
}
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name Folder `
-Value (Get-Item $path).FullName
$object | Add-Member -MemberType NoteProperty -Name Size -Value $size
$folders += $object
Write-Output $folders
}
END {}
} # Get-DirSize 関数の終わり
Function Get-FormattedNumber($size)
{
<#
概要:
数値の形式を GB、MB、または KB 単位に設定します。
説明:
この関数ではバイト単位で渡された数値の形式を、
必要に応じて、GB、MB、または KB 単位に設定します。
また、小数点以下 2 桁までの数値と適切な文字列の修飾子を表示します。
出力される文字列の書式設定のみに使用します。
この関数では、技術的精度は維持されず、数値は小数第 3 位で四捨五入されます。
例:
Get-FormattedNumber -size 1025
1.00 KiloBytes と表示されます。
例:
Get-FormattedNumber -size 1026
9.79 MegaBytes と表示されます。
例:
Get-FormattedNumber -size 10261024
1.00 KiloBytes と表示されます。
入力:
[int32]
出力:
[string]
メモ:
名前: Get-FormattedNumber
作成者: Ed Wilson
最終更新日: 2009 年 8 月 12 日
キーワード: 数値の形式を設定する、管理用の定数、if/elseif/else、
.NET Framework の形式指定子、.NET Framework
リンク:
http://technet.microsoft.com/ja-jp/scriptcenter/default.aspx
#Requires -Version 2.0
#>
IF($size -ge 1GB)
{
"{0:n2}" -f ($size / 1GB) + " GigaBytes"
}
ELSEIF($size -ge 1MB)
{
"{0:n2}" -f ($size / 1MB) + " MegaBytes"
}
ELSE
{
"{0:n2}" -f ($size / 1KB) + " KiloBytes"
}
} # Get-FormattedNumber 関数の終わり
# *** スクリプトのエントリ ポイント ***
if(-not(Test-Path -Path $path))
{
Write-Host -ForegroundColor red "Unable to locate $path"
Help $MyInvocation.InvocationName -full
exit
}
Get-DirSize -path $path |
Sort-Object -Property size -Descending |
Select-Object -Property folder, size -First $first |
Format-Table -Property Folder,
@{ Label="Size of Folder" ; Expression = {Get-FormattedNumber($_.size)} }
ScriptingGamesBeginnerEvent8.ps1 スクリプトのエントリ ポイントでは、Test-Path コマンドレットを使用して、スクリプトで指定されたパスが存在するかどうかを確認しています。存在しない場合、パスが見つからないというメッセージを画面に表示します。そして、スクリプトのヘルプ情報がコンソールに表示され、スクリプトは終了します。その結果を次に示します。
ディレクトリの存在が確認されると、Get-DirSize 関数が呼び出され、Get-ChildItem コマンドレットを使用してディレクトリ サイズの情報を取得します。ディレクトリ サイズを取得したら、カスタムの PSObject を作成して、呼び出しコードに返します。PSObject は、サイズを並べ替える Sort-Object コマンドレットと最も大きいフォルダーを選択する Select-Object コマンドレットにパイプライン処理されます。コードは次のとおりです。
Get-DirSize -path $path |
Sort-Object -Property size -Descending |
Select-Object -Property folder, size -First $first |
Get-DirSize -path $path |
Sort-Object -Property size -Descending |
Select-Object -Property folder, size -First $first |
フォルダーのサイズはバイト単位で返されるので、サイズをもう少し読みやすい単位に変換する関数を記述することにしました。Get-FormattedNumber 関数では、数値の大きさによって、KB、MB、または GB のどの単位に変換するかを判断します。新しく形式が設定された数値は、カスタム プロパティとして Format-Table コマンドレットに返します。コードは次のとおりです。
Format-Table -Property Folder,
@{ Label="Size of Folder" ; Expression = {Get-FormattedNumber($_.size)} }
Format-Table -Property Folder,
@{ Label="Size of Folder" ; Expression = {Get-FormattedNumber($_.size)} }
スクリプトを実行すると、次のような出力が表示されます。
PS C:\Users\edwils> C:\data\ScriptingGuys\HSG_8_17_09\ScriptingGamesBeginnerEvent8.ps1
Folder Size of Folder
------ --------------
C:\data 64.55 GigaBytes
C:\data\VM 28.60 GigaBytes
C:\data\vmzip 9.43 GigaBytes
C:\data\DELL_Data 5.84 GigaBytes
C:\data\DELL_Data\data 5.83 GigaBytes
PS C:\Users\edwils> C:\data\ScriptingGuys\HSG_8_17_09\ScriptingGamesBeginnerEvent8.ps1
Folder Size of Folder
------ --------------
C:\data 64.55 GigaBytes
C:\data\VM 28.60 GigaBytes
C:\data\vmzip 9.43 GigaBytes
C:\data\DELL_Data 5.84 GigaBytes
C:\data\DELL_Data\data 5.83 GigaBytes
EC さん、ScriptingGamesBeginnerEvent8.ps1 スクリプトが、Windows 7 への移行計画のお役に立てばさいわいです。データのバックアップを作成する際には、(念のために) コピーを 2 つ作ることをお勧めします。また、重要なデータは Live Mesh (英語) で同期することもおすすめします。Live Mesh は無料で使用できる優れたツールです。私はコンピューター間でスクリプトを同期するのに使用しています。Tojo2000 さん、2009 年夏季スクリプト競技大会にご参加いただき、すばらしい関数を記述してくださって、ありがとうございました。
スクリプト センターで今後行われることをいち早く知りたい方は、私たちの
Twitter (英語)
や
Facebook (英語)
をチェックしてください。スクリプトに関するサポートが必要な場合は、公式の
Scripting Guys フォーラム (英語) に質問を投稿するか、scripter@microsoft.com (英語のみ) まで電子メールをお送りください。2009 年夏季スクリプト競技大会の最終セッションは、明日も続きます。それまでの間、スクリプトを書き続けましょう。
Scripting Guys (Ed Wilson、Craig Liebendorfer)
* このコンテンツは、Hey, Scripting Guy! Blog (英語) の日本語版です。