2012年6月28日木曜日

◆ISEのスニペットを使う(V3)

VisualStudioではおなじみのスニペットがPowerShellでも使えるようになる。

しかしVisualStudioの様に可変部分を効率的に入力したりはできないようで、あくまでも定型文の読み込みができるだけといった感じ。

また、「foreach」などと打って自動で候補が出てくるわけではなく、自分でメニューから、もしくは「Ctrl + J」で呼び出す必要がある。

しかも、「foreach」と打って「Ctrl + J」ではなく「Ctrl + J」してから「foreach」と打つのが良さそうだ。

image

 

スニペットは自分でも簡単に登録できるようになっていて「New-IseSnippet」というコマンド(関数)が用意されている。
image

「Text」パラメータに登録内容を指定すれば良いのだが、複数行になる場合はヒア文字列で指定するのが良いだろう。

001
002
003
004
005
006

$cmd = @'
Write-Host $1
Write-Host $2
'@


New-IseSnippet -Description testDes -Text $cmd -Title mySnip1

一旦登録したスニペットを削除する機能は用意されていないようなので、以下にあるスニペットの内容を保持したXMLファイルを直接削除する必要がありそうだ。

image

2012年6月26日火曜日

◆Foreachステートメントでnullオブジェクトを列挙対象外にする(V3)

PS>function f1{1,2,3}
PS>$r = f1
PS>foreach($i in $r){"Result is $i"}
Result is 1
Result is 2
Result is 3

この様な処理があったとして、「f1」が「Null」を返すとこんな感じになる。

PS>function f1{$null}
PS>$r = f1
PS>foreach($i in $r){"Result is $i"}
Result is

この結果はあまり意味がないので出力を抑止したいというケースが多いのだろう。

PS>function f1{$null}
PS>$r = f1
PS>if($r){foreach($i in $r){"Result is $i"}}
PS>

V3では自分で条件判定せずともNullに対する列挙を回避してくれるようだ。
(V3)

PS>function f1{$null}
PS>$r = f1
PS>foreach($i in $r){"Result is $i"}
PS>

ただし、使い方は若干注意が必要なようで以下の様にするとうまくいかない。(これが意図した結果なのかどうかは判らないが)
(V3)

PS>function f1{$null}
PS>foreach($i in f1){"Result is $i"}
Result is

こんな時は以下のようにしてあげると良さそうだ。
(V3)

PS>function f1{$null}
PS>foreach($i in (f1)){"Result is $i"}
PS>

2012年6月25日月曜日

◆ハッシュテーブルからカスタムオブジェクトへのキャスト(V3)

ハッシュテーブルをキャストしてカスタムオブジェクトが作れるようになった。

[PSCustomobject]@{x=1; y=2}

これまで以下の様に書いていたのと同じ事だろうか。

New-Object PSCustomobject -Property @{x=1;y=2}

◆検証属性を変数にも適用可能にする(V3)

これまでは検証属性というとパラメータにのみ適用できたのだが、V3からは変数にも適用できるらしい。

例えば、以下では「$a」の長さが「1桁~5桁」、「$x」の値の範囲が「1~10」に限定している。

PS>[ValidateLength(1,5)]$a="test"

PS>[ValidateRange(1,10)][int]$x = 1

PS>$a = "123456"
値 123456 は a 変数の有効な値ではないため、変数を検証できません。
発生場所 行:1 文字:1
+ $a = "123456"
+ ~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ValidationMetadataException
    + FullyQualifiedErrorId : ValidateSetFailure

 

PS>$x = 11
値 11 は x 変数の有効な値ではないため、変数を検証できません。
発生場所 行:1 文字:1
+ $x = 11
+ ~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ValidationMetadataException
    + FullyQualifiedErrorId : ValidateSetFailure

2012年6月22日金曜日

◆’.’と’’::’の後ろにスペースや改行を許可する(V3)

スクリプトの行が長くなってくると適度なところで改行を入れたくなる。

PowerShellは継続サイン「`」を入れなくても改行できる場所があったりするのだが、’.’と’’::’の後ろでも改行が可能になったらしい。

"◆フルネーム"
(dir).
    FullName
"◆int最大値"
[int]::
    MaxValue

image

 

しかし、普段スクリプトを書いていて改行できなくて困るのはコマンドレットのパラメータの数が多くて長くなってしまう時なのだが、今のところそのケースでは有効な改行手段は見つけられなかった。

◆PSItem(V3)

dir | %{$_.FullName}

このようなスクリプトの時に、「$_」が何か判り辛いという意見が多かったので「$_」のエイリアスとして「$PSItem」を定義しました。

という事の様だ。

なんとなく通常とは逆の発想のエイリアス。
自分で使うことはなさそうだが、読めるようにはしておかないと・・・。

2012年6月21日木曜日

◆リダイレクト演算子の追加(V3)

これまではエラーまでしかリダイレクトできなかったのがWarningとかも可能になったようです。

function Write-Message
{
    "Normal Infomation" #1
    Write-Error "Error Infomation" #2
    Write-Warning "Warning Infomation" #3
    Write-Verbose "Verbose Infomation" -Verbose #4
    Write-Debug "Debug Infomation" -Debug #5
}

Write-Message  *> a.txt
notepad a.txt

image

単独でリダイレクト、全部をリダイレクトはこれで良いのですが、何かと何かを合わせてリダイレクトはどうするんですかね。

Write-Message  3>&1> a.txt

こんな感じですかね。

2012年6月20日水曜日

◆単数と複数を同一に扱う(V3)

New V3 Language Features - Windows PowerShell Blog - Site Home - MSDN Blogsで説明されていたV3の機能をちょっと試してみました。

まずはちょっと便利になった単数と複数を同一視してくれる機能。

PS>dir


    ディレクトリ: C:\Users\minminnana\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2012/06/20     11:18         10 a.txt

上記のようなディレクトリで以下のようなコマンドを実行すると、

PS>(dir).fullname
C:\Users\minminnana\test\a.txt

となります。

しかし、これがうまくいくのはどちらかというと「たまたま」で、誰かがここにファイルを追加したりすると突然機能しなくなります。

PS>"aaa" > b.txt
PS>dir


    ディレクトリ: C:\Users\minminnana\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2012/06/20     11:18         10 a.txt
-a---        2012/06/20     11:33         12 b.txt


PS>(dir).fullname
PS>

これは、(dir)で返ってくるオブジェクトが単数の場合はファイルオブジェクト、複数の場合はオブジェクト配列になることが原因です。

PS>dir


    ディレクトリ: C:\Users\minminnana\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2012/06/20     11:18         10 a.txt


PS>(dir).gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     FileInfo                                 System.IO.FileSystemInfo


PS>"aaa" > b.txt
PS>(dir).gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

この単数と複数の挙動の違いは誰しもが一度は嵌る道のように思います。

これまでは、この単数と複数の挙動の違いを吸収するために@()などで変数を定義して単数でも配列扱いとする方法が使われましたが、V3ではPowerShell側がこの違いを良きに計らってくれるようです。

V3ではこんな感じになります。

PS>dir


    ディレクトリ: C:\Users\minminnana\test


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2012/06/20     11:45         12 a.txt
-a---        2012/06/20     11:45         12 b.txt


PS>(dir).fullname
C:\Users\minminnana\test\a.txt
C:\Users\minminnana\test\b.txt

これまでは、複数オブジェクトの場合は自分でループして個々のプロパティを参照する必要がありました。

PS>dir | %{$_.fullname}
C:\Users\minminnana\test\a.txt
C:\Users\minminnana\test\b.txt
PS>dir | % fullname
C:\Users\minminnana\test\a.txt
C:\Users\minminnana\test\b.txt

(最初の例はこれまでのV2の書き方、2つ目はV3での書き方。)

パイプを使った書き方も簡略化されているので、

> (dir).fullname
> dir | % fullname

どちらもタイプ量的には似たようなものですが、Blogによると前者のほうが(内部的にパイプ処理に展開しているわけではないので)高速だと書いてあるように読めました。

他にもCountプロパティが参照できたり添え字付きで参照できたりといった感じになっているようです。

V2

PS>$a = 1
PS>$a.count
PS>$a[0]
型 System.Int32 のオブジェクトにインデックスを付けることはできません。
発生場所 行:1 文字:4
+ $a[ <<<< 0]
    + CategoryInfo          : InvalidOperation: (0:Int32) []、RuntimeException
    + FullyQualifiedErrorId : CannotIndex

V3

PS>$a = 1
PS>$a.count
1
PS>$a[0]
1


また、もともとオブジェクト配列に持っているプロパティの場合はそちらが優先されるようです。

PS>$a = "aaa","b","cc","ddd"
PS>$a.length
4
PS>$a | % length
3
1
2
3

2012年6月16日土曜日

◆イベントログを削除する

コマンドレットは用意されていないようだが.Netのクラスを使うと簡単に削除できる。

[System.Diagnostics.Eventing.Reader.EventLogSession]::GlobalSession.ClearLog("system")

当然「System」以外も「Security」とか「Application」とか「Windows PowerShell」とかを指定すればOK

2012年6月15日金曜日

◆レジストリ (規定)のPropertyType(種類)を変更する

SharePointの作業をしていて、手順書に以下のような作業が載っていた。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\14.0\Search\Setup\ContentIndexCommon\Filters\Extension\.pdf
値が ”{E8978DA6-047F-4E3D-9C78-CDBE46041603}”である必要があります。違う値が入っている場合は、この決められた値に変更します。

まずは、該当の場所に「.pdf」キーを作成する。
すると以下の様なデフォルト値が作成される。
image

この値に”{E8978DA6-047F-4E3D-9C78-CDBE46041603}”を指定してあげれば良さそうだが、他の拡張子の設定値を見るとどれも「種類」が「REG_SZ」ではなく「REG_MULTI_SZ」になっている。
そこで、なんとかこれを「REG_MULTI_SZ」にしようと思ったのだが、どうにもこうにもやり方が見つからない。(もしかするとGUIではできないのかも)

仕方がないのでPowerShellで更新することに。

(既定)の更新の仕方や、種類の指定の仕方を調べて以下のような感じになった。

New-Itemproperty "HKLM:\SOFTWARE\Microsoft\Office Server\14.0\Search\Setup\ContentIndexCommon\Filters\Extension\.pdf" "(default)" -propertytype MultiString -value {E8978DA6-047F-4E3D-9C78-CDBE46041603}

(既定)はそのまま(default)で良いようだ。
また、「種類」はGUIでは以下の様になっているが、
image

PropertyTypeとしては以下から対応する値を指定する。
image

2012年6月11日月曜日

◆コンソールへのオルタネイト(alternate)表示

PowerShell: ◆svchostプロセスのサービスを纏めて表示するでの結果表示はプロセス毎なので、それぞれで色が変わったりすると見やすいと思い、ちょっと変更してみました。

001
002
003
004
005
006
007
008
009
010
011
012
013

$fgColors = "Cyan","Yellow"
$color = $fgColors[0]
$oldPid = 0

Get-WmiObject -Class Win32_Service | sort ProcessID | %
{
 
if((Get-Process -Id $_.ProcessID).ProcessName -eq "svchost"
){
 
if($oldPid -ne $_.
ProcessID){
   
$color = $fgColors[($color -eq $fgColors[0])]
    $oldPid = $_.
ProcessID
  }
   
Write-Host $_.ProcessID $_.displayname -ForegroundColor $color
  }
}

image

いい感じ。

ちなみに、グルーピングせずに単純にオルタネイト表示する場合は、こんな感じでしょうか。

001
002
003
004
005
006
007

$fgColors = "DarkCyan","Gray"
$color = $fgColors[0]

Get-Process | Out-String -Stream | %
{
   
$color = $fgColors[($color -eq $fgColors[0])]
    Write-Host $_ -BackgroundColor $color -ForegroundColor Blue
}

image

◆svchostプロセスのサービスを纏めて表示する

タスクマネージャでプロセスタブを見ていると「svchost」なるプロセスをたくさん見かける。

image

説明を見ると「Windowsサービスのホストプロセス」とある。
即ち、これらのプロセスが各種Windowsのサービスをホストしているという事になる。

それぞれのプロセスがどんなサービスをホストしているかは、該当プロセスを右クリックして表示されたコンテキストメニューから「サービスの表示」を選んであげると以下の様に表示される。
image

image

これを見ると、1つのプロセスが複数のサービスをホストしていることが判る。

 

次に、これらを纏めてPowerShellで表示させてみたのが以下のスクリプトである。

001
002
003
004
005

Get-WmiObject -Class Win32_Service | sort ProcessID | %{
 
if((Get-Process -Id $_.ProcessID).ProcessName -eq "svchost"
){
   
Write-Host $_.ProcessID $_.displayname 
  }
}

「Get-Service」コマンドレットではプロセスIDが見当たらなかったので、「Win32_Service」を使っている。
それ以外は特別なところは無い。

image

2012年6月8日金曜日

◆ActiveDirectoryオブジェクトのプロパティを比較する

以下のやり取りを見ていてActiveDirectoryオブジェクトのプロパティを調べてみたくなりちょっと試してみました。
LastlogonDate

「Get-ADObject」で返ってくるのは「Microsoft.ActiveDirectory.Management.ADObject」

「Get-ADUser」で返ってくるのは「Microsoft.ActiveDirectory.Management.ADUser」

この2つのオブジェクトのプロパティが比較的できればOK

AD関連のオブジェクトはサイズが大きいせいか明示的に「Property」パラメータで指定しないと返ってこないプロパティが多い。
全プロパティはどうなっているのか。
MSDNをちょっと探してみたが見つからない・・・。
仕方がないので適当にやってみたら「Property」パラメータに「*」を指定すると全部返ってくるみたい。ラッキー。

全プロパティが取ってこれればあとは比較するだけ。

こんな感じだろうか。

001
002
003
004
005
006
007
008

Import-Module ActiveDirectory

$adobject = Get-ADObject -filter {name -eq 'Administrator'} -property *  |
 
 
gm | ?{$_.MemberType -eq "Property"} | select -ExpandProperty name
$aduser = Get-ADUser administrator -property * |
 
 
gm | ?{$_.MemberType -eq "Property"} | select -ExpandProperty name
 
Compare-Object $aduser $adobject

image

2012年6月5日火曜日

◆Windows8RPのPowerShellヘルプ2

PowerShell: ◆Windows8RPのPowerShellヘルプの続き。

あまりに使いづらいのでもう少し調べてみました。

どうやら、ヘルプをダウンロードした時にローカルのヘルプファイルを更新する権限が無いような感じです。

「管理者として実行する」で一旦「Get-Help」を実行してダウンロードしておけばその後はダウンロードを要求されなくなるようです。
自分から取りに行く場合は「Update-Help」を実行するのかな。
オンライン側のHELPが更新されたのを知らせる仕組みがあるのかどうかは今のところ判りませんが・・・。

ちなみに、Windows7では「ユーザーアカウント制御の設定」を「通知しない」にするとPowerShellは通常でも管理者権限で起動するように思うのですが、Windows8ではそうならないようです。

2012年6月1日金曜日

◆Windows8RPのPowerShellヘルプ

Windows8RPがリリースされました。
それほど興味はないのですがPowerShellの最新版が使ってみたいのでインストールしてみました。

ヘルプファイルが追加されているか興味があったので早速Get-Help

すると以下のような問い合わせが表示され、「Y」をこたえると何やらダウンロードが始まった風。
キャプチャ1

キャプチャ2

これでやっと新コマンドの使い方が解るのかと期待したのもつかの間、表示されたヘルプ自体はDetailではない風。

残念。

しかもどうしたことかこのヘルプ君、どのコマンドをヘルプしても毎回ダウンロードを訪ねてくる。
コマンドごとにダウンロードファイルが違うのかと一瞬思ったが、プログレスを見ていると同じものっぽい。

とりあえず毎回「N]を答えるしかないのか・・・

--追記
PowerShell: ◆Windows8RPのPowerShellヘルプ2