ホスト名をテキストファイルにいれておき、nslookupを纏めて実行する。
001 002 003 004 005 | $hosts = gc d:\desktop\hostname.txt "■■■以下のホストのアドレスを照会します■■■" | tee -Variable msg $hosts "■" * $msg.length $hosts | nslookup |
ホスト名をテキストファイルにいれておき、nslookupを纏めて実行する。
001 002 003 004 005 | $hosts = gc d:\desktop\hostname.txt "■■■以下のホストのアドレスを照会します■■■" | tee -Variable msg $hosts "■" * $msg.length $hosts | nslookup |
001 002 003 004 005 | Get-WmiObject Win32_NetworkAdapter -Filter "NetConnectionID='Mylocal'" | %{ $retrn = $_.Disable().ReturnValue if(!$return){ $_.NetConnectionID + " を無効にしました。" }else { $_.NetConnectionID + " を無効にできませんでした。"} } |
有効にする時はEnableメソッドで。
汎用的に作るならNetConnectionIDの存在チェックもしたほうが良いかも。
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 |
期待通りの結果になる。
先頭にPSCustomObjectが来るとダメっぽい。
これが仕様だとすると、嵌ること請け合いの仕様だ。
思い通りに出力されないときは「Out-Host」と覚えておこうっと。
もう少しスマートな方法があるかもしれないが、とりあえずこんな感じで表示できた。
文字コードは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 |
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の場合は以下のようになる。
これでは使いづらいので、functionにするのをためらいがちだった。
今日、偶然色々と試しているうちに良い方法を見つけた。
単にドットソースで呼んであげるだけで期待通りの結果になるのである。
(ドットソースは別スクリプトを取り込むものだとばかり思っていた・・・)
以前PowerShell: ◆オブジェクトにプロパティを追加する(Add-Member)でも使用した集計プロパティ。
余り説明せずに使っていたので今一度その使い方を確認してみる。
集計プロパティはSelect-Objectだけで使えるものではないが、いちばん基本的なコマンドレットであるSelect-Objectを例に説明する。
PS>dir d:\desktop\test1
Mode Name |
こんな感じでプロパティを射影するのが基本的な使い方。SQLと同じイメージ。
ここで出力フォーマットを弄ってみる。
Mode $_.name + "です" |
本来プロパティ名を指定するところに式を指定するのでスクリプトブロックで指定する。
スクリプトブロックの中ではパイプラインオブジェクトが$_変数で参照できる。
ただし、これではタイトルがいただけない。
この様な時のためにタイトルを指定する機能を提供するのが集計プロパティと呼ばれるものである。
Mode ファイル名は |
もともとあったスクリプトブロックに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 + "です"} |
と、思っていたのだが・・・。
実際以下のようにどうみても同じに見える。
しかし、$fileprop2のほうは以下のようなエラーになる。
Select-Object : System.Management.Automation.PSObject を型 {System.String, Syst |
だいぶ悩んで$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
No ProcessName
0番目と12番目 Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName Name : BaiduJPEngine Site : |
WSHで定番のショートカット作成。
001 002 003 004 005 006 007 | $wsh = New-Object -comObject WScript.Shell $link = $wsh.CreateShortcut("D:\desktop\notepad.lnk") $link.TargetPath = "notepad.exe" $link.Description = "メモ帳" $link.WorkingDirectory = $home $link.IconLocation = "notepad.exe" $link.Save() |
Compare-Object、エイリアスはCompare
ちなみに、これまで使った限りでは、XXXX-ObjectのエイリアスはXXXXだ。
New-Objectだけ(かどうかは調べていないが)はなぜかNewではだめ。
Compare-Objectにはdiffというエイリアスもあるのでそちらのほうが通りがよいかもしれない。
で、本題だが、Compare-Objectを使って以下のありがちなコードを書いてみた。
001 002 003 004 005 | $oldps = ps notepad $newps = ps diff $oldps $newps | gm diff $oldps $newps |
まぁ、予想通りの結果だ。
説明するまでもないかもしれないが(私はよく判っていなかった)、「=>」の意味するところは、InputObjectに表示されたものが、diffの引数の右側(第2引数)にしか無いよという事。
問題なのは、このスクリプトの4行目と5行目を単純に入れ替えた時だ。
すると、結果はこうなる。
@@ Get-Memberはどこへ?
Tee-Objectなんかしても何やらおかしい。
4行目のコメントをはずすと、
GetTypeの表示の他に6行目のGet-Memberが有効になる。
果たして、BUGなのか私の知らない仕様が存在するのか・・・・。
そもそもCompare-Objectのヘルプによると、このコマンドレットのパイプライン出力は無いと書いてある。
なので、出力されるのがたまたま(BUG?)で出力されないのが正しいのかもしれない。
というわけで、Cpmpare-Objectのパイプライン出力には触れないのが得策の様だ。
Cpmpare-Objectにはパイプライン出力用のpassthruスイッチが用意されているのでそちらを使うのがまっとうな使い方なのだろう。
比較して相違のあったオブジェクト(ここではメモ帳のプロセスオブジェクト)がやって くる。
ただし、ここでもTee-Objectはダメっぽい。というか私が何か理解不足なのか。
個々のプロパティが一つのクラスとして表示されている。
ただ、そのどれもがProcessクラスというのはどう考えてもおかしいような・・・。
ん~、Teeも使わないことにする。
色々と紆余曲折し悩んだが、最後にまっとうなCompare-Objectのサンプルを。
上記のPassthruでやってくるProcessオブジェクト、型としてはProcessなのだが、Powershellが独自にプロパティを追加しているようだ。
以下でそれを表示してみる。
001 002 003 004 005 006 007 008 009 010 | $oldps = ps notepad $newps = ps diff $oldps $newps -PassThru | Set-Variable result $result | gm | Set-Variable psprocess ps | gm | Set-Variable normalprocess diff $psprocess $normalprocess -Property name,membertype $result.Kill() |
結果は以下の通り。
例の差異を表す「<=」がNotePropertyとして追加されているのが判る。
あぁー、なんか疲れた。
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 | #$arg = "" function funcArgCheck{ param($arg) trap{ "引数の範囲は" (get-variable vari -Scope script).Attributes | %{if($_ -is [Management.Automation.ValidateSetAttribute]){ $_ | select -ExpandProperty validvalues;"です";break} } } $script:vari = "one" Get-LimitedArg "One","Two","Three" $script:vari = $arg Write-host $arg "OK`n" } function Get-LimitedArg($values){ $opt = New-Object Management.Automation.ValidateSetAttribute ` -ArgumentList $values (Get-variable vari -Scope script).Attributes.Add($opt) } funcArgCheck "Two" funcArgCheck "Five" |
ValidateSetAttributeを使って変数の値範囲を制限してみた。
本質的な部分はGet-LimitedArg関数の部分だけなので簡単に実装できる。
関数分けしたりトラップしたりがベタなコードになってしまったが、とりあえずこんなこともできるよという事で。
PowershellでのIF文のTrue判定は .NET とは若干違っている。
PowerShell: ◆IPアドレスを検証するにて
if($object) のような判定を行っているが、.NETであればこの場合$objectはbool型である。
しかし、Powershellの場合$objectの型は何でもOKだ。
基本的には、その型の初期値であればFalse、それ以外であればTrueと覚えておくと覚えIやすい。(厳密には若干不正確な説明かもしれないが)
以下に例を示す。
001 002 003 004 005 006 007 008 009 010 011 012 013 | function IsTrue($para){ $result = "◆Param Type:({0}) Value:({1}) IF:({2})" $TorF = if($para){"True"}else{"False"} $type = if($para -eq $null){ "NullType"}else{$para.GetType().Name} $result -f $type , $para , $TorF } IsTrue("") IsTrue("test") IsTrue(0) IsTrue(5) IsTrue(New-Object -ComObject "shell.application") IsTrue($null) |
結果は
-- 追記(20145.1.5) --
有効なIPアドレスを検証する。
正規表現などを使って検証する例も見かけるが、こんな方法もある。
-as演算子で型変換すると変換できない場合はエラーにならずにNullになる。.NETと同じだ。
なので変換してみてOKなら正しいと判断する。
また、if($object)という使い方、ここではさしあたってNulの時にFalseになる。
(厳密にいうと以下の使い方には若干バグがある)
001 002 003 004 005 006 007 008 009 010 011 012 | function isIPAddress($object) { if($object){$object}else{"Null"} ($object -as [System.Net.IPAddress]).IPAddressToString -eq $object –and ($object -ne $null) Write-Host } isIPAddress "10.256.0.1" isIPAddress "127.0.0.1" IsIPAddress "hello" IsIPAddress "192.168.0.1.1" isIPAddress $null |
メールアドレスの検証も同様に、こんな感じで。
[System.Net.Mail.MailAddress]).Address
共有フォルダーの設定と解除を行う。
001 002 003 004 005 006 007 | "--- Tools フォルダを共有設定する ---" ([WMICLASS]"WIN32_Share").Create("c:\TOOLS","tools",0) | Out-Null net share "--- Tools フォルダを共有解除する ---" Get-WmiObject -Class "Win32_Share" -Filter "Name='tools'" | Remove-WmiObject | Out-Null net share |
結果は以下の通り。
EnvironmentクラスのGetFolderPathメソッドを使うと取得できる。
PS>[environment]::GetFolderPath("desktop")
Name MemberType Definition |