PATH以下のファイルに対する操作
path-childitemというCmdletを使う。
MSH> get-childitem C:\TEMP\ -Include *.cs -Recurse Directory: FileSystem::C:\TEMP\BLL\Properties Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 8 10 16:37 1637 AssemblyInfo.cs Directory: FileSystem::C:\TEMP\BLL Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 8 11 10:30 2044 AContext.cs -a--- 8 11 10:30 2619 CManager.cs -a--- 8 10 21:54 3580 Cryptograph.cs -a--- 8 10 14:25 531 Localization.cs -a--- 8 10 15:47 487 Logging.cs -a--- 8 10 20:24 574 Login.cs -a--- 8 10 14:41 438 PCounter.cs -a--- 8 10 15:47 916 RManager.cs -a--- 8 10 15:47 556 SConfiguration.cs -a--- 8 10 14:06 521 Usage.cs -a--- 8 10 14:34 394 UInfo.cs -a--- 8 10 14:42 402 UPreference.cs -a--- 8 10 14:31 381 Utility.cs
ちょっとこれじゃ使いにくいので、フルパスの文字列を出力するように整形する。
MSH> get-childitem C:\TEMP -Include *.cs -Recurse|foreach{combi ne-path $_.Directory $_.Name} C:\TEMP\BLL\Properties\AssemblyInfo.cs C:\TEMP\BLL\Properties\AssemblyInfo.cs C:\TEMP\BLL\ApplicationContext.cs C:\TEMP\BLL\CacheManager.cs C:\TEMP\BLL\Cryptograph.cs C:\TEMP\BLL\Localization.cs C:\TEMP\BLL\Logging.cs C:\TEMP\BLL\Login.cs C:\TEMP\BLL\PerformanceCounter.cs C:\TEMP\BLL\RoleManager.cs C:\TEMP\BLL\SystemConfiguration.cs C:\TEMP\BLL\Usage.cs C:\TEMP\BLL\UserInfo.cs C:\TEMP\BLL\UserPreference.cs C:\TEMP\BLL\Utility.cs MSH>
コマンドの実行結果が、どんなプロパティを持ったオブジェクトなのか見たい、という時は、format-listというCmdletを使うと見やすく整形してくれる。
MSH> $a=get-childitem C:\TEMP -Include *.cs -Recurse MSH> $a[0]|format-list Directory: FileSystem::C:\TEMP\BLL\Properties Name : AssemblyInfo.cs Length : 1637 CreationTime : 2005/08/10 11:34:37 LastWriteTime : 2005/08/10 16:37:08 LastAccessTime : 2005/08/11 10:30:23 VersionInfo :
で、パイプラインで必要なプロパティだけに間引きたい時には、select-objectを使う。
MSH> get-childitem C:\TEMP -Include *.cs -Recurse|select-object Name Name ---- AssemblyInfo.cs AContext.cs CManager.cs Cryptograph.cs Localization.cs Logging.cs Login.cs PCounter.cs RManager.cs SConfiguration.cs Usage.cs UInfo.cs UPreference.cs Utility.cs
コマンドの調べ方
.NET Frameworkに関して調べたい時は、MSDNのリファレンスなり、TIPSのサイトをぐぐるなり、何とでもなる。
Monad固有のCmdletはどうやって調べるかという話。
get-commandというCmdletを使うと、どんなCmdletがあるか、簡単な使い方が分かる。
MSH> get-command get-help Command Type Name Definition ------------ ---- ---------- Cmdlet get-help get-help [[-Name] String] [-Catego...
Definitionが見たいんだけど、というような時は、select-objectを使うと、パイプで渡されたレコードのうち、選択したプロパティだけを返してくれる。SQLの射影みたいな操作。
MSH> get-command get-help|select-object Definition Definition
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
または、format-listを使うと、下記のように1レコードを複数行に表示してくれる。
MSH> get-command get-help|format-list Name : get-help CommandType : Cmdlet Definition : get-help [[-Name] String] [-Category String[]] [-Component Stri ng] [-Functionality String] [-Role String] [-Verbose] [-Debug] [-ErrorAction ActionPreference] [-ErrorVariable String] [-OutVa riable String] [-OutBuffer Int32] Path : AssemblyInfo : DLL : C:\Program Files\Microsoft Command Shell\System.Management.Auto mation.DLL HelpFile : System.Management.Automation.dll-Help.xml ParameterSets : {__AllParameterSets} Type : System.Management.Automation.Commands.GetHelpCommand Verb : get Noun : help
詳しい説明が表示されるのは、get-helpというCmdlet。UNIXでいうmanみたいな感じ。
get-help [Cmdlet]というように使う。
ループの簡単な書き方
You normally would use a counted for loop:
MSH:19 C:\temp\monad > for($x = 0; $x -lt 5; $x++) { do-something }
But here's a neat little trick to save some typing, if you don't care which iteration of the loop you're in:
MSH:19 C:\temp\monad > 1..5 | foreach { do-something }
This is a bloated and slow way to do a for loop, though, so don't use it in scripts.
forループを使うより、配列をパイプに渡してforeachを使ったほうがシンプルだし速い、という事かな?
例えば、こんな感じでIrvineなどに頼らずに自力でダウンロードするとか。
MSH:19 C:\temp\monad > $url="http://www.hoge.com/aaa/bbb/ccc/" MSH:19 C:\temp\monad > 1..50|foreach {$f=[String]::Format("{0:00}.jpg", $_); $c.DownloadFile($url + $f, $f)}
こういうのをモヒカン族って言うのじゃろか?
プロンプトの変更
http://www.leeholmes.com/blog/default,date,2005-06-12.aspx
を参考に、プロンプトを変更してみた。
一目瞭然だと思うが、無理やり説明すると。
カレントディレクトリだけの名前を取得するのにswitch文で正規表現を使った。
ドライブ直下の時はそれだとうまく行かないので、その時はdefaultで対処。
文字列のフォーマッティングはStringのFormat関数を使った。
MSH>function prompt {
>> switch -regex ((get-location).path) {
>> "(?<current>[^\\]+$)" {
>> $c = $matches.current
>> }
>> default {
>> $c = $_
>> }
>> }
>> [String]::Format("[{0}] {1} >", $c, (get-history -count 1).id)
>> }
>>
[C:\] 0 >cd windows
[WINDOWS] 1 >cd system32
[system32] 2 >
サンプル:ファイルのSHA1ハッシュを計算する。
MSH> function GetSha1 {
>> $path = $args[0]
>> $bytes = [System.IO.File]::ReadAllBytes($path)
>> $sha1 = new-object System.Security.Cryptography.SHA1Managed
>> $hash = $sha1.ComputeHash($bytes)
>> $retval = ""
>> foreach ($b in $hash) {$retval += $b.ToString("x2")}
>> $retval
>> }
>>
MSH> GetSha1("C:\TEMP\Console1\bin\Debug\Console1.exe")
2c0371c737f9785fc6db4f35ba0973eaa29e1fd0
従来の環境では、ライブラリのインターフェースとコマンドラインのインターフェースが著しく異なっていたために、コマンドラインのプログラムという形でライブラリをラップする必要があった。
このため、コマンドを作らないとライブラリが呼び出せなかったし、ライブラリとは異なるコマンドの使い方を別途覚える必要が生じた。
Monad Shellの場合、いきなりシェルから.NET Frameworkが使える。
コンソールアプリを作る時も、シェルスクリプトを書くときも、同じように.NET Frameworkを使う。
すばらしい。
この環境から始めた人は、UNIXの混沌には耐えられないだろうな。
.NET関連の操作
Microsoft Command Shell(Monad Shell)で遊んだ続き。
.NET Frameworkがそのまま使えるってのを試してみた。
かなり面白い。rubyでいう所のirbみたい。気に入りました。
サンプル:ファイルのダウンロード
New-ObjectというCmdletを使うとインスタンスを作成できる。
MSH> $c = new-object System.Net.WebClient
MSH> $c.DownloadFile("http://www.google.com/", "c:/temp.html")
サンプル:メール送信
これも同様。
MSH> $cl = new-object System.Net.Mail.SmtpClient
MSH> $cl.Host = "smtp"
MSH> $msg = new-object System.Net.Mail.MailMessage
MSH> $from = new-object System.Net.Mail.MailAddress("hoge@fuga")
MSH> $to = $from
MSH> $msg = new-object System.Net.Mail.MailMessage($from, $to)
MSH> $msg.Body = "aaaaa"
MSH> $msg.Subject = "test subject"
MSH> $cl.Send($msg)
staticなMethodを呼ぶ
[クラス名]::メソッド名()って感じで呼び出せる。
MSH> [System.Enum]::GetValues([System.IO.FileAccess])
Read
Write
ReadWrite
MSH>
Enumにアクセス
これもStatic Methodと同様で、[クラス名]::Enum名。
ちなみにプロパティの場合も同じ感じ。
MSH> $out = new-object System.IO.FileStream("C:/temp.txt",
>> [System.IO.FileMode]::Create,
>> [System.IO.FileAccess]::Write)
>>
MSH> $c = new-object System.Net.WebClient
MSH> $a = $c.DownloadData("http://www.yahoo.co.jp/")
MSH> $out.Write($a, 0, $a.Length)
MSH> $out.Close()
MSH>
アセンブリのLoad
[Reflection.Assembly]::LoadWithPartialName("System.Web")
Cmdletを試す
引き続きMicrosoft Command Shell(Monad Shell)で遊ぶ。
sh等の既存のシェルで言う所のbuiltin Commandに該当するのがCmdletだ。
verb-nounという形式に命名法が統一されているのに感心した。
もちろん、普通使いたいコマンドにはaliasが切ってあるので、cdとかlsできる。
まぁ、まずは触ってみようということで、とりあえずレジストリをいじってみた。
まずは目的の位置に移動。
MSHのプロンプトを起動した後、まずは移動して、Get-Itemで現在の内容を見る。
MSH> cd hkcu:\software\microsoft\windows\currentversion MSH> get-item run Hive: Registry::HKEY_CURRENT_USER\software\microsoft\windows\currentversion SKC VC Name Property --- -- ---- -------- 0 1 run {ctfmon.exe}
New-Propertyで新しい項目を登録する。
Windowsの起動時に電卓が立ち上がるようにしてみた。
MSH> new-property -path run -property "calc.exe" -value "C:\windows\system32\cal c.exe" MshPath : Registry::HKEY_CURRENT_USER\software\microsoft\windows\currentv ersion\run MshParentPath : Registry::HKEY_CURRENT_USER\software\microsoft\windows\currentv ersion MshChildName : run MshDrive : HKCU MshProvider : System.Management.Automation.ProviderInfo calc.exe : C:\windows\system32\calc.exe
値が変わって、calc.exeが増えているのがわかる。
MSH> get-item run Hive: Registry::HKEY_CURRENT_USER\software\microsoft\windows\currentversion SKC VC Name Property --- -- ---- -------- 0 2 run {ctfmon.exe, calc.exe}
実際に登録されているかどうか、Get-Propertyで確認する。
MSH> get-property -path run -property calc.exe MshPath : Registry::HKEY_CURRENT_USER\software\microsoft\windows\currentv ersion\run MshParentPath : Registry::HKEY_CURRENT_USER\software\microsoft\windows\currentv ersion MshChildName : run MshDrive : HKCU MshProvider : System.Management.Automation.ProviderInfo calc.exe : C:\windows\system32\calc.exe
はい、確かにcalc.exeがレジストリに登録されています。
Remove-Propertyで削除する。
本当に起動時に電卓が立ち上がってもジャマなので。
MSH> remove-property -path run -property calc.exe MSH> get-item run Hive: Registry::HKEY_CURRENT_USER\software\microsoft\windows\currentversion SKC VC Name Property --- -- ---- -------- 0 1 run {ctfmon.exe}
.NETのオブジェクトも扱えるようだが、ちょっとまだ良くやり方が分からない。
っていうか、本当にドキュメントが無い。