2010年6月30日水曜日

◆ファイルオープンダイアログを使う

ファイルオープンダイアログを使うときは、Powershell –sta として、シングルスレッドアパートメントモードでPowershellを起動する必要がある。
なぜか、Powershell  .\XXX.ps1  -sta  では駄目で、Powershell  -sta  .\XXX.ps1  とする必要がある。

Add-Type -AssemblyName System.Windows.Forms
$dl = New-Object System.Windows.Forms.OpenFileDialog
$dl.Title = "ファイルの選択"
$dl.InitialDirectory = $home
$ret = $dl.ShowDialog()
if($ret -eq "OK"){
    "[{0}]が選択されました" -f $dl.FileName
}

2010年6月29日火曜日

◆switchステートメント

構文はこんな感じ、(ごく普通)
PS>$text = "bbb"
PS>
PS>switch($text){
>>     aaa{"aaaが見つかりました";break}
>>     bbb{"bbbが見つかりました";break}
>>     ccc{"cccが見つかりました";break}
>>     {$_.length -eq 3}{"3桁の文字が見つかりました";break}
>>     default{"不明な文字が見つかりました"}
>> }
>>
bbbが見つかりました
ワイルドカードも使える。
PS>$text = "bbb"
PS>
PS>switch -wildcard ($text){
>>     aaa{"aaaが見つかりました";break}
>>     b*{"bbbが見つかりました";break}
>>     ccc{"cccが見つかりました";break}
>>     default{"不明な文字が見つかりました"}
>> }
>>
bbbが見つかりました

正規表現も使える。
PS>$text = "bbb"
PS>
PS>switch -regex ($text){
>>     aaa{"aaaが見つかりました";break}
>>     "bbb$"{"bbbが見つかりました";break}
>>     ccc{"cccが見つかりました";break}
>>     default{"不明な文字が見つかりました"}
>> }
>>
bbbが見つかりました
ファイルの中身を直接判定することもできる。
次の様な内容のファイルがあったとすると

bbb
ccc
ddd
aaaa

PS>
PS>switch -file test.txt{
>>     aaa{"aaaが見つかりました";break}
>>     bbb{"bbbが見つかりました";break}
>>     ccc{"cccが見つかりました";break}
>>     {$_.length -eq 3}{"3桁の文字が見つかりました";break}
>>     default{"不明な文字が見つかりました"}
>> }
>>
bbbが見つかりました

あれ、1行目しかヒットしない。
どうやら、breakはswitchステートメント全体をbreakしてしまうようだ。
ファイルの全行を判定するには、
PS>
PS>switch -file test.txt{
>>     aaa{"aaaが見つかりました";continue}
>>     bbb{"bbbが見つかりました";continue}
>>     ccc{"cccが見つかりました";continue}
>>     {$_.length -eq 3}{"3桁の文字が見つかりました";continue}
>>     default{"不明な文字が見つかりました"}
>> }
>>
bbbが見つかりました
cccが見つかりました
3桁の文字が見つかりました
不明な文字が見つかりました

breakとcontinueの使い分けについては、通常のループ処理と同じ感じ。
switchステートメント2

2010年6月28日月曜日

◆オブジェクトにプロパティを追加する(Add-Member)

オブジェクトにプロパティを追加するには、Add-Memberコマンドレットを使う。

サンプルとして、FileオブジェクトにOwnerプロパティを追加してみる。

function Get-ChildItemAddedOwnerProp
{
    $file = Get-ChildItem
    $file | %{
      Add-Member -MemberType NoteProperty -Name Owner -Value $_.GetAccessControl().owner -InputObject $_
    }

    $file
}

Get-ChildItemAddedOwnerProp | select name,owner

結果はこんな感じ、
20100628195213

Add-Memberの代わりに集計プロパティを使っても同様の事ができる。

$file |
  select * ,@{name="Owner";expression={$_.GetAccessControl().Owner}} |
  Set-Variable file

$file | select Name,Owner

2010年6月26日土曜日

◆Get-ChildItemにフォルダーのLength表示を追加する

Dirコマンドでは、ファイルのLengthは表示されるが、フォルダーのLengthは表示されない。
20100626012819

そこで、PowerShell: ◆関数を作るで作った関数を修正し、フォルダーのLengthも表示するDirコマンド(関数)を作ってみた。

function dir3(
    [string]$Path = ".\",
    [switch]${??}){

$comment = @'
#####################################################

dirコマンドにフォルダーのサイズを追加して表示する

param(
    [string]$Path = ".\",
    [switch]${??}
)

例:
    #
    dir3  "C:\Windows"

#####################################################
'@

    Set-PSDebug -Strict

    if(${??}) {$comment;return}

    Get-ChildItem -Path $Path |
        select mode,LastWriteTime,@{
             name="length";expression={
                 if($_.PsIsContainer){
                    ($_ | Get-ChildItem -Recurse -ea silentlycontinue |
                     measure -Sum length).Sum
                  }else{
                    $_.length
                  }
             }
         },name |
        sort @{expression="mode";descending=$true},
             @{expression="name";descending=$false}
    Set-PSDebug -Off
}

あまり変わったところはないが、PsIsContainerプロパティでフォルダーかどうか判定しフォルダーに対してのみlengthを追加している。
(ファイルの場合はそのままlengthを返している)

Sortコマンドでは、昇順と降順の組み合わせを連想配列形式で指定している。

結果はこんな感じ。
20100626015546 
Selectすると表示書式が若干変わってしまう(クラスが変わるので仕方がない)。
また、Cドライブ直下などでやると若干時間がかかる。(だから標準ではlength表示しないのだろう)

結果でちょっと気になるのがPerfLogsフォルダ。
lengthが表示されていない。
中身を見てみるとファイルが存在していないためNullとなっている。
こんな時はif(SumがNullだったら)とかやりたくなるが以下のようにすると簡単に0表示できる。

                     measure -Sum length).Sum  +  0


ん~、Null + 0 は 0 なんですね。
Powershellっておもしろい。

◆関数を作る

PowerShell: ◆サブフォルダーの容量を求めるで作ったスクリプトを関数にしてみた。

function dir2(
    [string]$Path = ".\",
    [switch]${??}){

$comment = @'
#####################################################

指定されたフォルダーのサブフォルダーのディスク容量を表示する
(FunctionLib.ps1)

param(
    [string]$Path = ".\",
    [switch]${??}
)

例:
    #
    MGet-FolderSizes.ps1 -Path "C:\Windows"

#####################################################
'@

    Set-PSDebug -Strict

    if(${??}) {$comment;return}

    Get-ChildItem -Path $Path | ?{$_.PsIsContainer} |
        select name,@{
             name="Size(MB)";expression={
                "{0,10:n2}" -f
                (($_ | Get-ChildItem -Recurse -ea silentlycontinue |
                 measure -Sum length).Sum / 1mb)
             }
         } |
        sort "Size(MB)" -des
    Set-PSDebug -Off
}

ほとんどそのままだ。
使うときは、$profileに書いておくかドットソースで読み込む。

.  FunctionLib.ps1
dir2

◆サブフォルダーの容量を求める

PowerShell: ◆スクリプトファイルを作るで決めた形式でサンプルを一つ作ってみた。

フォルダーの容量を求めたいことはよくあるので、指定されたフォルダーにあるサブフォルダーの容量を求める。

param(
    [string]$Path = ".\",
    [switch]${??}
)

$comment = @'
#####################################################

指定されたフォルダーのサブフォルダーのディスク容量を表示する
  (MGet-FolderSizes.ps1)

param(
    [string]$Path = ".\",
    [switch]${??}
)

例:
    #
    MGet-FolderSizes.ps1 -Path "C:\Windows"

#####################################################
'@

Set-PSDebug -Strict

if(${??}) {$comment;return}

Get-ChildItem -Path $Path | ?{$_.PsIsContainer} |
    select name,@{
         name="Size(MB)";expression={
            "{0,10:n2}" -f
            (($_ | Get-ChildItem -Recurse -ea silentlycontinue |
             measure -Sum length).Sum / 1mb)
         }
     } |
    sort “Size(MB)” -des
Set-PSDebug –Off


指定されたパスの子供を取得。
PsIsContainerプロパティでフォルダーだけを抽出。
NameとSizeプロパティをSelect
Sizeプロパティはもともと存在しないので自分で求める。
  配下のファイルをRecurse指定で全てとってくる。(アクセスできないファイルは無視)
  Measure-Objectコマンドレットでlengthプロパティをサマリ。
  余計なプロパティもくっついてくるのでSumプロパティを使用。
  1mbで割ってMB表示に。
  フォーマット演算子でフォーマット設定。
結果をSizeプロパティで降順にソート

2010年6月25日金曜日

◆スクリプトファイルを作る

汎用的な処理はスクリプトファイルにしておきたい。(関数でも良いが)
適当に作っていくと後でわけがわからなくなるので、ある程度書式を決めておく。

一応こんなひな形を考えてみた、

param(
    [string]$Path = ".\",
    [switch]${??}
)

$comment = @'
#####################################################

指定されたフォルダーのサブフォルダーのディスク容量を表示する
  (MGet-FolderSizes.ps1)

param(
    [string]$Path = "C:\",
    [switch]${??}
)

例:
    #
    MGet-FolderSizes.ps1 -Path "C:\Windows"

#####################################################
'@

Set-PSDebug -Strict

if(${??}) {$comment;return}


パラメータの受け取り方は何種類かあるが、Paramステートメントを使うことにする。(これは先頭に書く必要があるようだ)
次に、簡単な機能とパラメータ及び使用例をコメントとして入れておく。

Set-PSDebug –Strict

これは未設定変数の参照をエラーとする定義。タイプミスを早めに見つけられるので入れておきたい。

if(${??}) {$comment;return}


これはヘルプ表示用。
コマンドレット  -?  でヘルプ表示されるのをまねている。
$?としたいところだが、これは既に自動変数で使われているので$??としてみた。
コマンドレット -?? でもヒットしてしまうが実害はないだろう。
ただし、?は変数に使えない文字なので{}で囲んでいる。
ここでは単純にコメントをそのまま出力している。

もっと正当な書き方があるのかもしれないがこれでも十分だろう。