仕事でいろいろなことをスクリプトで自動化することがある。「これやらなきゃ」と思ってスクリプトを実行して、そのスクリプトがしばらくかかるものならメールをチェックしたり、他の作業を同時進行することが多いのだ。そんな状況でよくあるのが、そのスクリプトを実行したことさえも忘れてしまい、いろいろなウィンドウの後ろにコンソールウィンドウがひっそりと我慢強く待っていてくれたのを一時間ぐらい後に発見する。

こんなことが起きるのはスクリプトにはあまり目立ったお知らせ機能がないからだ。Outlookだと「ダディディン!」という音と共にポップアップウィンドウで会議があと何分後にあることを知らせてくれる。スクリプトだってそのプロセスが終わったことを知らせてくれるもっと目立つ機能があってもいいのではないかと考えてPowerShellでやってみた。次に紹介するのも.NET Frameworkのおかげなのだ。

まずはバルーン機能からやってみる。そもそもバルーンとは何か。下の画像を見ていただければ一目瞭然だ。

image

Windowsを使いなら一度は見たことがあるだろう。

まず最初に、矢印のアイコンに注目する。標準のアイコンというものはなく自分で指定してやらなければいけない。スクリプトが自分のコンピュータのみで動作するのだったらいいが、そのスクリプトが他のコンピュータにも配布されるということを想定して、アイコンをBase64の文字列に変換しスクリプト内に埋め込んでみる。まずはBase64文字列に変換する作業から。

まずはファイルをByte配列としてメモリに読み込む。それをBase64文字列に変換。ちなみに今回の記事でPowerShellらしいところといえばGet-Contentのみだろう。あとは.NET Frameworkを直接使っている。

image

このBase64文字列をスクリプト内に埋め込むことにする。

もう一度確認するが、このスクリプトの目的はバルーンを使ってスクリプトの実行が終了することをより視覚的に知らせることである。それをするために次のようなスクリプトを書いてみた。

#デフォルトではSystem.Windows.Formsは読み込まれていないので、それを初めに読み込む。
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
 
#NotifyIconクラスを使うので、インスタンスを作成。
$NotifyIcon = New-Object System.Windows.Forms.NotifyIcon
 
# アイコンを表すBase64文字列を変数に格納しておく。このようにしてアイコンやいろいろなバイナ
# リデータをBase64文字列としてスクリプト内に格納することも可能だが、データのサイズが大きい
# と文字列も長くなってしまうので注意。
$iconString = "AAABAAIAEBAAAAAAAABoAwAAJgAAABAQEAAAAAAAKAEAAI4DAAAoAAAAEAAAACAAA(HTMLの関係上略)"
 
# Base64文字列をByte配列に変換。
$binaryData = [System.Convert]::FromBase64String($iconString)
 
# 次の4行でByte配列に格納されていたアイコンをSystem.Drawing.Iconにして使えるようにする。
$memStream = New-Object System.IO.MemoryStream
$memStream.Write($binaryData, 0, $binaryData.Length)
$memStream.Position = 0
$icon = New-Object System.Drawing.Icon($memStream)
 
$memStream.Close()
 
# 最終的にIconプロパティを上で作ったIconオブジェクトにセットし、ShowballoonTipメソッドを
# 実行する。
$NotifyIcon.Icon = $icon
$NotifyIcon.Visible = $true
$NotifyIcon.ShowBalloonTip(100000, "俺のスクリプト", "スクリプトは終了しましたよ!", "Info")
 

これをファイルに格納してPowerShell上で実行すると、下のようにPowerShellからバルーンを使うことができる。

image

ちなみにSystem.Media.SoundPlayerを使えば音を鳴らすことだって可能だ。音を使えばより効果的であることは容易に想像できる。あまり詳しく説明しないが次のように音を鳴らすこともできるのだ。

$SoundPlayer = New-Object System.Media.SoundPlayer("$env:SystemRoot\Media\chimes.wav")
1..3 | foreach{$SoundPlayer.Play();[System.Threading.Thread]::Sleep(1000)}

Posted in:   Tags:

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

PowerShellのスクリプトをPowerGUIで編集していたらコピペができない事態が生じたので、秀丸で編集しようと思ったら強調表示定義ファイルがない・・・ということで作ってみました。キーワードが文字列内で強調されないようにしたかったけど、正規表現がちょっとめんどかったのでそのままにしてしまいました。

ファイルはここからダウンロードできます。

一応秀丸サイトにも投稿しておきます。


Posted in: PowerShell  Tags:

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Team Foundation Serverを使うようになってからもうかれこれ2年ぐらいが経つ。その間にだんだんソリューションファイルが多くなってきたり、一つの製品の開発環境を作るのにあっちをいじったりこっちをいじったりしなきゃいけなくなってきたので、自動化を試みている。その一環としてPowerShellを使ってTeam Foundation Serverから最新バージョンのコードをダウンロードするコードを書いてみた。

param
(
    $tfsServerName = $(Throw "TFSのサーバ名を入力してください。"),
    $localFolderPath = $(Throw "ローカルのフォルダパスを入力してください。"),
    $Domain = "",
    $Username = "",
    $Password = "",
    [String[]] $getPaths = $(Throw "サーバ側から最新コードをダウンロードするパスを配列として渡してください。")
)
 
[void] [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
[void] [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.VersionControl.Client")
 
$credential = $null
 
if (($Username -eq "") -or ($Password -eq ""))
{
    $credential = Get-Credential
}
else
{
    $credential = New-Object System.Net.NetworkCredential($Username, $Password, $Domain)
}
 
#TeamFoundationServerオブジェクトを作成。
$tfs = New-Object Microsoft.TeamFoundation.Client.TeamFoundationServer($tfsServerName, $credential)
$tfs.Authenticate()
 
# VersionControlServerを使ってWorkspaceオブジェクトを取得。
$vcs = $tfs.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
$ws = $vcs.GetWorkspace($localFolderPath)
 
$ws.Get($getPaths, [Microsoft.TeamFoundation.VersionControl.Client.VersionSpec]::Latest, "Full", "GetAll")
 

Posted in: PowerShell  Tags:

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
入海 posted on 9月 18, 2008 02:08

これは以前にdevslife.comに書いた記事です。

Get-CommandでCmdletを眺めていたらMeasure-ObjectというCmdletに出くわした。なかなか面白いCmdletで使えそうである。例えば・・・

image

上のコマンドを解説すると、10,11,12…100までの配列がMeasure-Objectによって処理されてデフォルトでCountつまり配列がいくつあるかというのを表示してくれた。他にもAverage(平均)やSum(合計)やMaximum(最大値)そしてMinimum(最小値)も計算させることができそうだ。パラメータを追加すると他の値も計算してくれる。

image

日本語のテキスト(文字列)についても使える。下の例は-charのパラメータを使うことで変数内にある文字数を数えてくれるのだ。

image

テキストファイルに入っている文字列に関しても同じように使える。

image

さらに、他のオブジェクトに関しても-Propertyパラメータを使えばこんなことができる。

image

上のコマンドはどういうことかというと、Get-Processのコマンドレットで返されたプロセスのVMつまりバーチャルメモリに関しての統計である。つまりこのマシン上には50のプロセスが存在していて平均、合計、最大、最小がそれぞれの値であるということを表している。

Measure-Objectはちょっと統計を見てみたいというときに使えるコマンドレットだ。


Posted in:   Tags:

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
入海 posted on 8月 14, 2008 05:13

この記事は以前にdevslife.comに掲載したものです。

 

ある日「PowerShellで独自の結果を返すにはどうすればいいのだろう?」と考えていた。もちろんカスタムコマンドレットを作成すればアセンブリ内でクラスを作ってそれをWriteObjectを使って返してやればいいのだろうけど、スクリプト内でできないものだろうか?と疑問に思った。

そこでPSObjectの登場だ。PSObjectはSystem.Management.Automation名前空間に存在し、いわば.NET FrameworkのSystem.Objectと同じような位置づけである。非常に汎用的なオブジェクトなのだ。PSObjectをインスタンス化してそのメンバーを見てみると・・・

PSObject

それだけでは使えるものがほとんどない。このオブジェクトにプロパティやメソッドを追加して使えるものにしていこうという魂胆である。

すでにメモリ内に存在するオブジェクトにプロパティやメソッドを追加することは.NETプログラミングではあまり頻繁に行われることではないが、 JavaScriptだとPrototypeとして、.NET Frameworkで言うならばSystem.Reflection.Emitの名前空間に存在するクラスを使って動的にクラス、プロパティ、メソッド、そして最終的にはアセンブリまで作れてしまうのがある。PowerShellで動的にメンバーを追加するにはAdd-Memberというコマンドレットを使用する。ためしに上でインスタンス化したPSObjectにCustomerIDというプロパティを追加してみよう。

image

すると・・・

image

一つのインスタンスのPSObjectでは複数の結果を返すことができない。そこでArrayListを使ってみよう。

$Result = New-Object System.Collections.ArrayList 
 
foreach ($i in 1..15)
{
    $Cust = New-Object PSObject
    $Cust | Add-Member -Name "CustomerID" -MemberType NoteProperty -Value $i
    [void] $Result.Add($Cust)
} 
 
$Result | ft -AutoSize

上のスクリプトを.ps1ファイルに保存して実行すると・・・

結果

上の例にはもちろん複数のプロパティを追加すると複数の列の結果が得られる。この結果をパイプを使って次のコマンドレットに渡すことも可能だ。

今回は触れないが-memberTypeにはNotePropertyの他にAliasProperty, CodeProperty, Property, ScriptProperty, Properties, PropertySet, Method, CodeMethod, ScriptMethod, Methods, ParameterizedProperty, MemberSet, Allがある。help Add-Member -detailedで詳細を読んでみてほしい。


Posted in: PowerShell  Tags:

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
入海 posted on 7月 30, 2008 00:38

PowerShellのコンソールを起動すると普通のコマンドラインに比べて起動が遅いなと感じる。これは.NETの性質に由来するもので、MSIL(中間言語)を実行時にJIT(Just in Time)コンパイルするためである。実行時に機械言語へのコンパイルを行っているのだ。このJITコンパイル方式はあらゆるCPUやOSに対応させるためにインタプリタの利点を生かしたまま実行時には機械言語の処理速度を保てるという利点がある。

でも考えても見るとPowerShellが必要な環境では多種のOSで動く必要が今のところはない。速く起動してくれるに越したことはないのだ。それを実現するためにはMSILをすでに機械言語にコンパイルさせていればその実行時にその過程が不必要になるために速くなる。.NET Frameworkにはngenというのがあってこれを使うと事前コンパイルを可能にしてくれる。

ネイティブ イメージ ジェネレータ (Ngen.exe) は、マネージ アプリケーションのパフォーマンスを向上するツールです。Ngen.exe は、コンパイルされたプロセッサ固有のマシン コードを含むファイルであるネイティブ イメージを作成してローカル コンピュータのネイティブイメージ キャッシュにインストールします。ランタイムは、JIT (Just-In-Time) コンパイラを使用してオリジナルのアセンブリをコンパイルする代わりに、キャッシュにあるネイティブ イメージを使用できます。(MSDNより

 

そのngenを使って実際に起動を速くするスクリプトがPowerShell Team Blogに載っていたので下に抜粋しておく。

Set-Alias ngen @(
dir (join-path ${env:\windir} "Microsoft.NET\Framework") ngen.exe -recurse |
sort -descending lastwritetime
)[0].fullName
[appdomain]::currentdomain.getassemblies() | %{ngen $_.location}

上のスクリプトを.ps1ファイルに保存してPowerShellから実行してPowerShellのコンソールを起動してみると、起動が数倍速くなっている。ぜひ試してみてほしい。


Posted in: PowerShell  Tags:

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

この記事は以前にdevslife.comで公開したものです。

 

よくファイルをダウンロードするときにファイルの情報に関して表示されているところにMD5というのを目にすることがある。そしてその近くに数字とアルファベットの暗号のような文字列が並んでいるのを目にすることがあるだろう。技術系の方ならご存知だろうと思うが、それぞれのファイルには「指紋」があり、1バイトのデータが違っただけでもその指紋が変わってしまう。これを英語でハッシュ(Hash)という。ハッシュをファイルから取り出すにはいくつかのアルゴリズムがありMD5やSHA1やSHA256などというのがある。

つい最近Sunによって買収されたMySQLのダウンロードページにはそれぞれのファイルにMD5のハッシュ記号が書かれている。

image

例えばWindows ZIP/Setup.EXE (x86)をダウンロードしてそのファイルにMD5のアルゴリズムでハッシュを生成してやると809e1efe69dc1ed255d0e24421f0d096という文字列が得られるという意味なのだ。逆に言えばMD5でハッシュを生成してその文字列にならなければダウンロードされたファイルがサーバ側にあったファイルとは違い問題があるということになる。さらにダウンロードしているときに悪意のある人がそのファイルにウィルスを入れたかもしれないということも考えられる。そういった意味でハッシュを使ってファイルの整合性を確認することは大切である。

そこでPowerShellを使ってそれをやってみようと思う。

param
(
    $filePath,
    [string] $hash
)
 
$h = [System.Security.Cryptography.MD5]::Create()
 
$inputStream = New-Object IO.StreamReader $filePath
$hashBytes = $h.ComputeHash($inputStream.BaseStream)
$inputStream.Close()
 
$builder = New-Object System.Text.StringBuilder
$hashBytes | Foreach-Object { [void] $builder.Append($_.ToString("X2")) }
 
if ($builder.ToString().ToLower() -eq $hash.ToLower())
{
    return "Good!"
}
else
{
    return "Bad!"
}

上のコードをファイルに保存して下のようにして実行してみよう。(set-executionpolicyを忘れずに。)

image

こうしてファイルの整合性が確認された。もちろんMD5や他のアルゴリズムでファイルの整合性を確認するツールはあちこちにあるが、PowerShellが使えるのだから別にそういうのをダウンロードする必要もないと思う。上のコードをちょっと変えればSHA1やSHA256のようなアルゴリズムでの整合性の確認はすぐにできてしまう。逆にコンピュータに存在するファイルのハッシュの生成にも使える。dirを使ってファイルをリストしその結果に対してMD5のハッシュを一気に生成するということも簡単にできてしまいそうだ。


Posted in: PowerShell  Tags:

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
入海 posted on 7月 11, 2008 09:09

Quest Softwareから無料のPowerShellコマンドレット群が提供されています。それで何ができるかというとActive Directoryの管理のほとんどができてしまうそうです。一度試したことがありますが、かなりOOでいけてます。勤務している会社では私はネットワークの管理者ではありませんので、大層なことはできませんが、基本的なユーザアカウントの情報やネットワーク上にあるコンピュータについて、それを使って検索もできてしまいます。

例えば・・・

Get-QADComputer -DisplayName "vm*"

とすると、vmで始まるコンピュータがコンソール上に表示されます。ユーザカウントを検索したい場合は・・・

Get-QADUser -DisplayName "*John*"

などとするとJohnという文字列を含んだユーザアカウントをリストしてくれます。

上のコマンドレットの結果を変数に格納していろいろすることができるかもしれませんね。ただ実際にやる場合は犠牲者を出さないように気をつけてくださいね。w


Posted in: PowerShell  Tags:

最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

この記事は以前にdevslife.comで紹介したものです。

 

ビルドプロセスがとんでもなく巨大なテキストファイルを吐き出した。これは何かが無限ループしていると思うのだがその原因を突き止めなければいけない。なのでファイルの最後の方を何とかして読む必要がある。600MBもあるテキストファイルの最後のほうだけをどうやって読むことができるだろうか。PowerShellを使ってやってみようと思う。

Get-Contentではどうだろうかと初め考えた。次のようなコードを書いてみた。

$FilePath = "D:\Temp\Test.txt"
$Text = Get-Content -Path $FilePath -TotalCount 1
$Text
 

これだと初めの一行を読むということだもんね。このログファイルはXMLなのですべてのデータが一行に収まってるから使えない。試しに-TotalCountを-1とか-2とかにしたら後ろから読んでくれるかな?と思ってやってみたら全部読み込まれてしまった。ヘルプを読んでみると-1はデフォルトの値ですべてを読み込むという意味らしい。-2にしても無駄だった。まあできたとしても今回の問題については意味のないことだ。

ちなみに-ReadCountというパラメータもあるのだがこれも使えない。これは何行読んだら画面に表示してくれというのに使うらしい。大きなファイルを読むには使えそうだが、結局は早すぎて読めんだろ。これで既存のCmdletを使用した方法はあきらめることにした。

試行錯誤の末、下のようなPowerShellスクリプトで最後の1024バイトを読み込むことに成功。

$TextFilePath = "D:\Temp\MechaDekaFairu.txt"
$BytesToRead = 1024
 
$fs = [System.IO.File]::OpenRead($TextFilePath)
$fs.Position = $fs.Length - $BytesToRead
 
$sr = New-Object System.IO.StreamReader($fs)
 
$text = $sr.ReadToEnd()
 
$sr.Close()
$fs.Close()
 
$text

 

適当に$TextFilePathと$BytesToReadの値を変えると表示されるテキストファイルやその量を調節できます。もっと変えるといろんなところをのぞけそうです。一応PowerShell.exeのメモリが肥大することなく無事終了しました。

更新:使えると思ったのでニュースグループにも英語で書いておきました。ここから


最新のブログ

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
入海 posted on 7月 7, 2008 13:12

お初です。入海と申します。HIROさんからお誘いがありまして一緒に日本でPowerShellを盛り上げていかないかと。その心意気に賛同いたしましてこの初投稿に至りました。

私はシアトル在住のソフトウェアエンジニアです。主にマイクロソフトの技術を使って臨床試験のデータ収集に関するソフトウェアの開発に携わっております。

ore

個人のブログDev's Lifeと平行して日本のコミュニティに貢献できたら幸いだと考えています。過去に書いたPowerShell関連の記事も徐々にここに紹介していく予定です。

よろしくお願いします。


Posted in: お知らせ  Tags:

現在のレート 5.0 (1人)

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Calendar

«  1月 2009  »
月曜火曜水曜木曜金曜土曜日曜
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678
View posts in large calendar

Recent Posts

Recent Comments

Banners

Theme Grabber
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2009 PowerShell from Japan!!