001 002 003 | dir d: -recurse | ? { $_.PSIsContainer -and !$_.GetFiles().Count -and !$_.GetDirectories().Count} | %{ $_.FullName } |
上記サンプルではDドライブ配下のファイルとフォルダーを再帰しながら検索し、フォルダーだったらGetFilesメソッドとGetDirectoriesメソッドで中身があるかを判定しているだけ。
001 002 003 | dir d: -recurse | ? { $_.PSIsContainer -and !$_.GetFiles().Count -and !$_.GetDirectories().Count} | %{ $_.FullName } |
上記サンプルではDドライブ配下のファイルとフォルダーを再帰しながら検索し、フォルダーだったらGetFilesメソッドとGetDirectoriesメソッドで中身があるかを判定しているだけ。
テキストファイルを読み込むには言わずと知れたGet-Contentコマンドレットを使う。
通常はこれで全く問題ないと思うが、特別性能を要求されるような処理では、System.IO.FileクラスのReadAllTextメソッドを使うと良い。
ただし、このメソッドは排他されているファイルの読み込みが出来ない。
そんな時は、StreamReaderクラスを使い、アクセスモードを指定する。
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 | #Measure-Command{ # [System.IO.File]::ReadAllText("$env:windir\windowsupdate.log") #} Measure-Command{ gc $env:windir\windowsupdate.log } Measure-Command{ $mode = [System.IO.FileMode]::Open $access = [System.IO.FileAccess]::Read $fileshare = [System.IO.FileShare]::ReadWrite $file = [System.IO.File]::Open( "$env:windir\windowsupdate.log",$mode,$access,$fileshare) $reader = New-Object System.IO.StreamReader($file) $reader.ReadToEnd() $reader.Close() $file.Close() } |
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 | function funcArgCheck{ [cmdletbinding()] param( [ValidateSet("min","minmin","minminnana")] $name, [ValidateRange(10,40)] $age, [ValidateScript({Test-Path $_})] $path ) Write-Verbose "以下のパラメータが指定されました" Write-Verbose ("name = {0}" -f $name) Write-Verbose ("age = {0}" -f $age) Write-Verbose ("path = {0}" -f $path) "チェック終了" } funcArgCheck "min" 12 "c:\Windows" -verbose |
Write-Verboseコマンドレットで情報を書きこんでおくと、-verbose スイッチで情報を出力させることが出来る様になる。
この機能を有効にするには、cmdletbinding属性の指定も必要なようだ。
recurseパラメータを持つコマンドレットを表示するにはこんな感じ。
PS>Get-Help * -Parameter recurse Name Category Synopsis |
コマンド名を求めるだけならばこれでOKなのだが、実際このコマンドを使って何かをしたいとなるとこれでは不十分。
コマンド自体を取得したい場合は以下のようにすると良い。
PS>Get-Command -CommandType cmdlet | ?{$_.parameters.keys -contains "recurse"} CommandType Name Definition |
parametersはDictionaryオブジェクトのようなので、そのメソッドであるContainsKeyを使っても良いかもしれない。
PS>Get-Command -CommandType cmdlet | ?{$_.parameters.ContainsKey("recurse")} CommandType Name Definition |
Windows7ではデフォルトで各ドライブのデフラグを自動的に行うようになっている。
その自動で行われたデフラグのイベントログを表示するサンプルがあったので紹介しておく。
転載するとこんな感じ。
001 002 003 004 | get-eventlog -LogName Application -InstanceId 258 | ForEach-Object {$i=1|Select-Object Date, Type, Drive;` $i.Date = $_.TimeWritten; $i.Type,` $i.Drive = $_.ReplacementStrings; $i } |
-- 20150412 改行がむちゃくちゃでわかりづらいので修正--
001 002 003 004 005 006 007 | get-eventlog -LogName Application -InstanceId 258 | % { $i=1|Select-Object Date, Type, Drive $i.Date = $_.TimeWritten $i.Type,$i.Drive = $_.ReplacementStrings $i } |
------------------------------------------------------------------------------
ちょっと分かりづらいので若干補足。
$i=1|Select-Object Date, Type, Drive
は、オブジェクトを作ってプロパティ(Date,Type,Drive)を追加し、$i
変数に格納している。
普通に(正統に?)やるならばPowerShell: ◆カスタムオブジェクト(PsObject)を使う(New-Object)2のようにPsObjectを使うのかと思うが、ここでは簡略的にint32オブジェクト(1)にプロパティを追加して使っている。
また、3,4行目では、$i.Type,$i.Drive = $_.ReplacementStrings
でTypeプロパティとDriveプロパティにReplacementStringsの配列の値をそれぞれ格納している。
これは、$a,$b = 1,2
とやって、$aには1、$bには2が代入されるのと同じだ。
結果はこんな感じになる。
IISがインストールされている環境でWebAdministrationモジュールをインポートする。
Get-Commandでコマンドの一覧を見ると*-Web*という名前でコマンドが用意されていることが判る。
PS>ipmo WebAdministration CommandType Name |
私自身はIISの管理とかはしないのであまり使い道は無いが、管理者の方は便利に使えるのではないしょうか。
PowerShell: ◆パラメータ属性の補足(追記)
上記のほかにパラメータチェックで頻繁に使われそうな属性。
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 | function funcArgCheck{ param( [ValidateSet("min","minmin","minminnana")] $name, [ValidateRange(10,40)] $age, [ValidateScript({Test-Path $_})] $path ) "以下のパラメータが指定されました" "name = {0}" -f $name "age = {0}" -f $age "path = {0}" -f $path } funcArgCheck "min" 12 "c:\Windows" "-" * 10 funcArgCheck "hoge" 12 "c:\Windows" "-" * 10 funcArgCheck "minmin" 8 "c:\Windows" "-" * 10 funcArgCheck "minminnana" 15 "c:\Windows2" |
001 002 003 004 005 006 007 008 009 010 | "10進2進変換 255" [Convert]::ToString(255,2) "10進16進変換 255" [Convert]::ToString(255,16) "2進10進変換 11111111" [Convert]::ToInt32("11111111",2) "16進10進変換 FF" [Convert]::ToInt32("FF",16) "16進定数" "0xFF={0}" -f 0xFF |
前回のスクリプトを修正して、各イベントログから直近のエラーを表示してみる。
001 002 003 | Get-EventLog -List | ? {$_.entries.count} | %{$_.log;Get-EventLog $_.log -Newest 10 -After (Get-Date).AddDays(-15) ` -EntryType Error -ea 0 | Out-Host } |
とりあえず、直近15日のMAX10件を表示させている。
イベントログの一覧は以下のような形で取得できる。
PS>Get-EventLog -List Max(K) Retain OverflowAction Entries Log |
この結果から、Entriesがゼロのログを除外するには、普通に考えると以下のようになる。
PS>Get-EventLog -List | ?{$_.Entries} Max(K) Retain OverflowAction Entries Log |
結果は期待通りのものが取得できているのだが、何かがおかしい。
試してみると分かるがやけに時間がかかるのである。最初の一覧表示がノータイムで帰ってきていることを思えば、そこからEntriesがゼロの4行をフィルターするだけの処理もノータイムで返ってきて然るべき。
そこで、その原因を調べてみた。
PS>Get-EventLog -List | gm Entries
Name MemberType Definition |
これを見ると判るように、そもそもEntriesプロパティは
EventLogEntryCollectionを返してきている。
にも関わらず単純に画面出力したときは、その数が表示されているということはそこに何かが介在していることになる。
PowershellではdotNETのオブジェクトを出力するときにDotNetTypes.format.ps1xmlというファイルの定義に従って表示する仕掛けになっている。(パスは通常C:\WINDOWS\system32\WindowsPowerShell\v1.0)
そこでこの中身を確認してみると
Diagnostics.EventLogクラスは以下のように定義されている。
<View> <TableControl> </TableHeaders> </TableColumnItems> |
Entriesプロパティは、そのCountを表示する仕掛けになっていることが解る。
そこで先のフィルターを以下のように書き換える。
PS>get-eventlog -List | ? {$_.entries.count} Max(K) Retain OverflowAction Entries Log |
すると期待通り、ノータイムで結果が帰ってきた。(最初のやり方では各Entrieの中身を全件なめて抽出が行われているのだろう)
5分以内に起動されたプロセスを取得するサンプル。
PS>ps | ?{$_.starttime} | ?{(New-TimeSpan $_.starttime).TotalMinutes -le 5} Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName |
Starttimeを持っていないプロセスもあるようなのでフィルターして除外している。
New-TimeSpanコマンドレットは開始時間だけ指定すると、現在時刻までのTimeSpanオブジェクトを返してくれるようだ。
エクスプローラの検索ボックスで探せばすぐ見つかる。
と、思ったのだがこれがまた見つからない。
どうもファイル名だけで検索している感じだ。
中身を検索するときどうするの?
っと検索オプションなどを探してみたが見つからない。
???
まぁ良いか。とも思ったが気を取り直して調べてみると、どうやらINDEXを作っていない場所では中身まで検索しないのがデフォルトっぽい。
フォルダのオプションで中身まで検索する指定にすれば良いらしいがなんとなく面倒。
INDEXを作れば何も問題ないのだろうが、めったに検索しないのにいつもINDEX化しておくのもちょっと気が引ける。
(しかもINDEXが必要なほど範囲を広げた検索はめったにやらない。)
という事でやっぱりここはPowershellで。
dir D:\MyTest\DHTMLサンプル\part2\* -Recurse | |
なんてことはないが、Encodingを意識する必要があるのはちょっと面倒かな。
エクスプローラならきっと自動で判別するんだろうな・・・。
(暇があったら自動判定しながら検索するなんてのもやってみたい)
ちなみに、今回検索するファイルは以下のように階層が決まった構成になっているので再帰するまでもないかも。
こんな感じのほうが効率的かもしれない。
Resolve-Path D:\MyTest\DHTMLサンプル\part2\*\*.htm | |