2010年12月1日水曜日

◆長いパスの指定を簡単にする(New-PsDrive)

スクリプトを書いていてデスクトップのパスを使いたいことがよくある。
そのたびに、「C:\Users\minminnana\Desktop」とか「C:\Documents and Settings\minminnana\デスクトップ」とか打ち込むのは非常に面倒だ。
そこでデスクトップのパスをPsDriveにしてあげると非常に簡単にアクセスできる。<!-

001
002
003
004
005
006
007
008
009

#デスクトップにWドライブを割り当てる。
$parm =
 @{ 
  name 
= "w"
 
  psprovider 
= "FileSystem"
 
  root 
= "d:\Desktop"
 
} 


New-PSDrive @parm | Out-Null 
Remove-Variable parm
<!-

これをProfileに追加しておけば次からは「w:」でデスクトップにアクセス可能になる。
ドライブ名は必ずしも1文字でなくてもよい。deskとかにすれば、desk: でアクセスできる。

注意点として、Powereshellの世界はこれでOKなのだが他の世界ではこのドライブは通用しない。
例えば.NETのクラスにパスを引数で渡す場合などには使用できない。
正式なパスを指定するか、Convert-Pathコマンドレットで変換して渡す必要がある。

001
002
003
004
005

# encoding設定
$encoding = [Text.Encoding]::
default
  

# テキスト読み込み
$sr = new-Object IO.StreamReader((Convert-Path w:pcname_SJIS.txt),$encoding)

2010年11月30日火曜日

◆纏めてnslookup

ホスト名をテキストファイルにいれておき、nslookupを纏めて実行する。

001
002
003
004
005

$hosts = gc d:\desktop\hostname.txt 
"■■■以下のホストのアドレスを照会します■■■" | tee -Variable msg 
$hosts 
"■" * $msg.length 
$hosts | nslookup

結果。
image

◆ネットワークアダプターを無効にする

001
002
003
004
005

Get-WmiObject Win32_NetworkAdapter -Filter "NetConnectionID='Mylocal'" | %{ 
 
$retrn = $_.Disable().
ReturnValue 
 
if(!$return){ $_.NetConnectionID + " を無効にしました。" }else
 
  { 
$_.NetConnectionID +  " を無効にできませんでした。"} 
}

有効にする時はEnableメソッドで。
汎用的に作るならNetConnectionIDの存在チェックもしたほうが良いかも。

結果はこうなる。
20101130101727

2010年11月29日月曜日

◆PSCustomObjectは難しい?(Compare-Objectは難しい改)

PowerShell: ◆Compare-Objectは難しい?で思い通りの出力結果にならず思い悩んだが、S.K.さんからコメントを頂き、問題の本質が見えてきた。

001
002
003
004
005

$oldps = ps
notepad
 
$newps = 
ps
diff
 $oldps $newps 
diff $oldps $newps | gm

此の様に書いたとき、Get-Memberの出力が表示されず悩んでいたのだが、これはPowerShell: ◆コンソール出力のオブジェクトマージ機能を回避するで書いたのと同様の問題のようだ。
以下のようにOut-Hostを追加することで期待通りの結果が得られた。

001
002
003
004
005

$oldps = ps
notepad
 
$newps = 
ps
diff
 $oldps $newps 
diff $oldps $newps | gm | Out-Host

出力オブジェクトが同じ型の時にマージされるのが本当だと思うのだが、diffの結果として出力されるPSCustomObjectはそれ以降の出力オブジェクトをすべて巻き込んでしまう。
すなわち、PSCunsomObjet以降の出力はすべて同じ型であると判定されているようだ。

試しに同じPSCunsomObjetを出力するImport-CSVコマンドレットを使って以下のように書いてみた。

結果は先頭にCSVの内容を表示した後、空白行が続く。

001
002
003
004
005
006
007
008
009
010

#"★dir表示"
#dir | select -First 2
#"★ps表示"
#ps | select -First 2

"★★★CSV表示"
Import-Csv d:\Desktop\test.csv
"★dir表示"
dir | select -First 2
"★ps表示"
ps | select -First 2
20101129110823

コメントを外すと。
20101129111112

期待通りの結果になる。
先頭にPSCustomObjectが来るとダメっぽい。

これが仕様だとすると、嵌ること請け合いの仕様だ。

思い通りに出力されないときは「Out-Host」と覚えておこうっと。

2010年11月28日日曜日

◆文字コードを表示する

もう少しスマートな方法があるかもしれないが、とりあえずこんな感じで表示できた。
文字コードはUNICODE 。

001
002
003
004
005
006
007
008

function ConvertChar2Code($char){
$cArray=[char[]]$char 
$iArray = [int[]]
$cArray
$iArray
 = $iArray | %{[Convert]::ToString($_,16)}
0..$cArray.Count | %{Write-Host $cArray[$_] $iArray[$_]
}
}


. ConvertChar2Code("今日は犬と散歩に行きました")
結果。

今 4eca
日 65e5
は 306f
犬 72ac
と 3068
散 6563
歩 6b69
に 306b
行 884c
き 304d
ま 307e
し 3057
た 305f

<!--EndFragme

◆スコープ2

PowerShell: ◆スコープを書いた時には気付いていなかった方法があったので書いておく。

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

$a = 1
function fncA{
$a
$a
 += 1
}
function fncB{
$a
$a
 += 1
}
fncA
fncB
Write-Host
 $a

こんな風に書いたときC#などの感覚でいえば、$aはメンバー変数なので結果は1,2,3となっていくはずだ。
しかしPowershellの場合は以下のようになる。

20101128132910

これでは使いづらいので、functionにするのをためらいがちだった。
今日、偶然色々と試しているうちに良い方法を見つけた。
単にドットソースで呼んであげるだけで期待通りの結果になるのである。
(ドットソースは別スクリプトを取り込むものだとばかり思っていた・・・)

20101128133550

2010年11月27日土曜日

◆集計プロパティ(Select-Object)

以前PowerShell: ◆オブジェクトにプロパティを追加する(Add-Member)でも使用した集計プロパティ。

余り説明せずに使っていたので今一度その使い方を確認してみる。
集計プロパティはSelect-Objectだけで使えるものではないが、いちばん基本的なコマンドレットであるSelect-Objectを例に説明する。

PS>dir d:\desktop\test1


    ディレクトリ: D:\desktop\test1


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2010/11/25     15:28          0 test1.txt
-a---        2010/11/25     15:28          0 test2.txt


PS>dir d:\desktop\test1 | select mode,name

Mode                                                        Name
----                                                        ----
-a---                                                       test1.txt
-a---                                                       test2.txt

こんな感じでプロパティを射影するのが基本的な使い方。SQLと同じイメージ。

ここで出力フォーマットを弄ってみる。


PS>dir d:\desktop\test1 | select mode,{$_.name + "です"}

Mode                                                        $_.name + "です"
----                                                        ----------------
-a---                                                       test1.txtです
-a---                                                       test2.txtです


本来プロパティ名を指定するところに式を指定するのでスクリプトブロックで指定する。
スクリプトブロックの中ではパイプラインオブジェクトが$_変数で参照できる。
ただし、これではタイトルがいただけない。
この様な時のためにタイトルを指定する機能を提供するのが集計プロパティと呼ばれるものである。


PS>dir d:\desktop\test1 | select mode,@{name="ファイル名は";expression={$_.name + "です"}}

Mode                                                        ファイル名は
----                                                        ------------
-a---                                                       test1.txtです
-a---                                                       test2.txtです

もともとあったスクリプトブロックにexpressionというキーを付け、加えてnameというキーでタイトルを追加している。キーと値のセットなので指定形式は@{}がついた連想配列形式になる。2個のキーと値の設定を1行で書いているので間にセミコロンを入れている。コマンドラインからではなくスクリプトファイルとして書くのならば以下のように書くのも良いかも。

001
002
003
004
005

$fileprop = @{
name
="ファイル名は"
expression={$_.name + "です"
}
}

dir d:\desktop\test1 | select mode,$fileprop

ちなみに、上記のハッシュテーブルは以下のように書いても良い。

001
002
003

$fileprop2 = @{}
$fileprop2.name="ファイル名は"
$fileprop2.expression={$_.name + "です"}

と、思っていたのだが・・・。
実際以下のようにどうみても同じに見える。
20101128003238

しかし、$fileprop2のほうは以下のようなエラーになる。

Select-Object : System.Management.Automation.PSObject を型 {System.String, Syst
em.Management.Automation.ScriptBlock} のいずれかに変換することはできません。
発生場所 D:\temp\b4b9f59f-3638-4969-9a96-d4d07f915788.ps1:16 文字:30
+ dir d:\desktop\test1 | select <<<<  mode,$fileprop2
    + CategoryInfo          : InvalidArgument: (:) [Select-Object]、NotSupporte
    dException
    + FullyQualifiedErrorId : DictionaryKeyUnknownType,Microsoft.PowerShell.Co
   mmands.SelectObjectCommand

だいぶ悩んで$fileprop1と$fileprop2の違いを調べたがどうにもわからない。
個人的にはバグ(bug)にしか思えないのだが・・・・。
とりあえず1の書き方をすればよいだけなので放置。

最後にSelect-Objectの使い方(オプション)を。集計プロパティを使っているが、コメントにしてあるAdd-Memberのほうを使ったも結果は同じになる。

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017

$ps = Get-Process
$script:i = 0
#$ps | %{$i=0}{
#Add-Member -MemberType NoteProperty -Name No -Value (++$i) -InputObject $_
#}

$no = @{name="No";expression={(++$script:i)}}
$ps = $ps | select * ,$no
"先頭から3件"
$ps | select No,processname -First 3 | ft -AutoSize
"最後から3件"
$ps | select No,processname -Last 3 | ft -AutoSize
"0番目と12番目"
$ps | select No,processname -index 0,12
"0番目と12番目"
$ps | select -index 0,12
"modulesを展開"
$ps | select $name -ExpandProperty modules -First 1
</

結果は以下の通りなのだが、またしても色々と嵌った。(嵌ってばかりだ・・・)
まず、Indexパラメータ。なぜかエラーになる・・・。
どうやらPropertyパラメータと一緒に使えないらしい。
それじゃSelectじゃないと思うのだが・・・。

プロパティが連想配列の時(だけかは?)にExpandPropertyを指定すると中身を展開してくれる。これもPropertyとは併用できないようだ。(こちらはエラーにはならずに無視される)

今日もやけに疲れた・・・。

先頭から3件

No ProcessName
-- -----------
1 BaiduJPEngine
2 BWH32S
3 cmvMain


最後から3件

No ProcessName
-- -----------
65 WLIDSVC
66 WLIDSVCM
67 wmpnetwk


0番目と12番目
Select-Object : 引数 'System.Object[]' を受け入れる位置指定パラメーターが見つかりません。
発生場所 行:9 文字:13
+ $ps | select <<<<  No,processname -index 0,12
    + CategoryInfo          : InvalidArgument: (:) [Select-Object]、ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.Selec

0番目と12番目

Handles NPM(K)  PM(K)  WS(K) VM(M) CPU(s)   Id ProcessName
------- ------  -----  ----- ----- ------   -- -----------
     77      4  12884  69044   136  97.06 3180 BaiduJPEngine
    513     37 114288 130776   310 273.75 2936 firefox
modulesを展開

Name              : BaiduJPEngine
ModuleName        : BaiduJPEngine.exe
FileName          : C:\Program Files\Baidu\Type\BaiduJPEngine.exe
BaseAddress       : 4194304
ModuleMemorySize  : 86016
EntryPointAddress : 4201966
FileVersionInfo   : File:             C:\Program Files\Baidu\Type\BaiduJPEngine.exe
                    InternalName:     BaiduJPEngine
                    OriginalFilename: BaiduJPEngine.exe
                    FileVersion:      1, 0, 0, 20
                    FileDescription:  BaiduJP IME Engine
                    Product:          BaiduJP IME Engine
                    ProductVersion:   1, 0, 0, 20
                    Debug:            False
                    Patched:          False
                    PreRelease:       False
                    PrivateBuild:     False
                    SpecialBuild:     False
                    Language:         日本語 (日本)

Site              :
Container         :
Size              : 84
Company           : Baidu Inc.
FileVersion       : 1, 0, 0, 20
ProductVersion    : 1, 0, 0, 20
Description       : BaiduJP IME Engine
Product           : BaiduJP IME Engine