出力されるJapanesePhonemeオブジェクトは3つのプロパティを持ちます。単語の読み仮名このように、入力した文章を単語単位に分割し、それぞれの単語の読み仮名を取得することができます。これだけだと、「で、どうしろと」という感じなので、この出力結果を利用する、より実用的な関数を書いていきましょう。長くなったので次回に続く。埋め込み型のプレゼンテーションです。くま同盟大阪勉強会#63でのセッション資料を公開します。デモで使用したサンプルスクリプトも併せてご利用ください。くま同盟の勉強会は今回の大阪#63で10年目に入ったのですが、実は私も9年前の大阪#4で勉強会セッションデビューをしていたりします。DSCリソースを作成するというテーマで話しました。DSCでは管理対象ごとにロジック(リソース)と設定(Configuration)を分離でき、一貫性を持ったインフラ構成の自動化が可能になる素敵な機能です。いかんせん、ビルトインリソース(OS標準で含まれるリソース)の種類が少ないので、実際の業務で使うにはカスタムリソースを作成する必要が出てくると思います。今回のデモでは、テキストファイルの中身を自動構成するという、ごく単純なサンプルを作成して実演してみましたが、考え方や実装方法の基本はこれでカバーできるのではないかと思います。詳しくは、ぎたぱそ氏の記事を読んでいただければ良いかと思います。4.0環境でもおそらく動作すると思います。今回のConfigurationはローカルコンピュータに対しPush適用(Start-DscConfigurationコマンドレットによる手動適用)することを想定しています。Managerの設定等)を整えておいてください。スクリプトはすべて管理者権限で実行してください。xDSCResourceDesignerのインストールDSCリソースのひな形を作成するためのxDSCResourceDesignerをインストールします。KitをDLしてください。xDSCResourceDesignerの使用方法の確認xDSCResourceDesignerの使用方法を確認します。make_Foo_resource_template.ps1を実行すると、xDSCResourceDesignerを用いてDSCリソースFooのひな形が$env:ProgramFiles\WindowsPowerShell\Modules\TestResourceに作成されます。ひな形がどのように作成されるかを確認してください。Fooとして、DSCリソースがきちんと認識されているか、確認してください。今回のデモで作成したTextFileLineリソースは、make_TextFileLine_resource_template.ps1を実行してまずひな形を作成しました。作成されたひな形を用いて、TextFileLine.psm1に実際のロジックを記述し、DSCリソースを完成させました。zipに含まれるTestResourceフォルダの中身が、今回作成したDSCリソースモジュールになりますので、まずは内容を確認してみてください。Set-TargetResource関数はどのように実装すると冪等性を保持して作成できるのかを念頭に置いてみてください。TextFileLineリソースの展開zipに含まれるTestResourceフォルダを$env:ProgramFiles\WindowsPowerShell\Modules\の下にコピーしてください。TextFileLineとしてDSCリソースが認識されていることを確認してください。TextFileLineリソースを用いたConfigurationの作成start_dsc_configuration.ps1に含まれる、TextFileLineTestが、今回適用してみるConfigurationになります。start_dsc_configuration.ps1を実行すると、ドキュメントフォルダにmofファイルを生成し、Start-DscConfigurationコマンドレットにより設定を反映させます。Configurationが適用されれば、ドキュメントフォルダにlist.txtというファイルが生成し、中にプログラム言語のリストが記入されているはずです。Configurationが反映されたことを確認Test-DscConfigurationコマンドレットを実行すると、現在の状態とConfigurationに書かれた状態が一致していればTrueと表示されます。今はConfigurationを適用した直後なのでTrueになるはずです。Get-DscConfigurationコマンドレットを実行すると、現在の各プロパティの状態を表示してくれます。list.txtに含まれる行をテキストエディタで編集して上書きしたりすると、Test-DscConfigurationの結果はFalseになるはずです。list.txtを手動で変更した状態で、再度start_dsc_configuration.ps1を実行すると、再びConfiguration通りの状態に戻ると思います。その際、変更のなかったプロパティに関しては、処理がスキップされていることをログをみて確認してください。その他Configurationを色々書き換えて試してください。Ensure="Absent"にすると対象項目が存在しない状態になります。2014の24日目の記事です。位置情報プラットフォーム」をPowerShellから呼び出して、位置情報(緯度、経度)を取得してみよう、という話になります。位置情報プラットフォーム」という機能が追加され、アプリケーションから現在位置情報(緯度、経度など)をAPIで取得できるようになっています。位置情報プラットフォームでは、位置情報をGPSがあればGPSから、なければWi-Fiの位置情報あるいはIPアドレスなどから推定して取得します。GPSがない場合でも位置情報を取得できる、いわば仮想GPSの機能がデフォルトで備わっているのがミソです。センサー&ロケーションプラットフォーム」というのがありましたが、OSデフォルト機能としては仮想GPSはありませんでした。Windowsというサードパーティー製アプリを追加すると仮想GPS使えたんですけどもね。位置情報プラットフォームをPowerShellで使うには、.NET4.0以上に含まれている、System.Device.Location名前空間配下に含まれるクラスの機能を用います。アセンブリ名としてはSystem.Deviceとなります。以下のような関数Get-GeoCoordinateを定義します。System.Deviceを実行して必要なアセンブリをロードする必要があります。関数本体ではまず、System.Device.Location.GeoCoordinateWatcherオブジェクトを生成します。位置情報プラットフォームにアクセスして、位置情報の変化を監視します。位置情報の変化を感知すると、PositionChangedイベントが発生し、取得した位置情報を、イベントハンドラの引数にGeoPositionChangedEventArgs<T>オブジェクトとして返します。PowerShellでは、.NETクラスのイベントを取得するには、Register-ObjectEventコマンドレットを用い、イベントを「購読」します。{処理内容}のようにして、イベントハンドラを記述するのが一般的です。今回は位置情報の変化の最初の一回(つまり、初期値の取得)さえPositionChangedイベントを捕まえればOKなので、-Actionは使用しません。代わりにWait-Eventコマンドレットを用い、初回のイベント発生を待機するようにしています。Wait-Eventコマンドレットは、当該イベントを示すPSEventArgsオブジェクトを出力します。PSEventArgsオブジェクトのSourceEventArgsプロパティには、当該イベントのイベントハンドラ引数の値(ここではGeoPositionChangedEventArgs<T>オブジェクト)が格納されているので、あとはそこから.Position.Locationと辿ることで、位置情報を格納したGeoCoordinateオブジェクトが取得できます。(注:あとで知ったんですけど、GeoCoordinateWatcherクラスには、同期的に位置情報を取得するTryStartメソッドというのがあって、これを使えばイベント購読は実は不要でした...まぁいっか)なお、関数のパラメータとしてLatitude(緯度)、Longitude(経度)を指定すると、現在位置ではなく、指定の位置を格納したGeoCoordinateオブジェクトを生成するようにしています。位置情報プラットフォームを有効にする」にチェックを入れておきます。あとはGet-GeoCoordinateをそのまま実行するだけです。Falseこのように現在位置が表示されるかと思います。いっても、緯度、経度が表示されたところでちゃんと取得できてるのかよく分からないので、以下のような簡単な関数(フィルタ)を定義しておきます。"http://maps.google.com/maps?q=$($_.Latitude),$($_.Longitude)"}このフィルタを使うと、指定の緯度経度周辺の地図を、標準のWebブラウザで開いたGoogleマップ上に表示してくれます。位置測定に用いたソースによってはkmオーダーでズレると思いますが、それでも何となく、自分がいる場所が表示されるのではないかと思います。先ほども書いたように、パラメータで任意の緯度、経度を指定することも可能です。位置情報プラットフォーム」を使って現在位置が取れるよ、という話でした。PowerShellでSystem.Device.Locationとかを使っているサンプルを見かけないので、何かの参考になれば幸いです。あとPowerShellでのイベントの扱い方についても復習になるかと。APIを呼び出して活用しよう、というようなネタを書くつもりだったんですが、長くなったんでまたの機会としましょう。2014の11日目の記事です。Languageの略で、その名の通り音楽演奏データを記述するための言語です。BASICのPLAY文で使うあれです。MIDIファイルに変換するコンパイラもありましたよね。「ねこふんじゃった」の最初の部分をMMLで書くとこんな感じです。MMLはいろんな記法があるのですが、よくあるのはこういうのです。e-d-<g-4>g-rg-4e-d-<g-4>g-rg-4e-d-<g-4>g-4<e-4>g-4<d-4>frf4e-d-<d-4>frf4e-d-<d-4>frf4e-d-<d-4>f4<e-4>f4<g-4>g-rg-4ドの音をc、レの音をd、のように以下シの音をbまでアルファベット音階で割り当てます。半音上げる(シャープ)場合は音名のあとに+、半音下げる(フラット)場合は-を付与します。音の長さは4分音符なら4、8分音符なら8と書きます。付点は数字のあとに.を付けます。数字省略時は8分音符と解釈するのが普通のようです。オクターブを上げる場合は>、下げる場合は<と書きます(コンパイラによっては逆の解釈をする)。本物のMMLでは、音色の指定だとかトラックの割り当てだとか、もっとたくさん命令があるんですが、基本はだいたいこんなもんです。PowerShellで音を鳴らすにはPowerShellで音を鳴らすには、.NETのSystem.Console.Beepメソッドを使うのが一番手っ取り早いです。比較的古いWindowsではハードウェアのビープスピーカーから、比較的新しいWindowsではサウンドデバイス上で鳴ります。今回のMMLシーケンサーも結局はBeepメソッドです。ぎたぱそ先生がずっと以前に書いておられます。今回のはまあ、MMLシーケンサー部分を除けば二番煎じなんですけどもね。PlayerをCOM経由で実行する方法や.NET(WPF)のSystem.Windows.Media.MediaPlayerクラスを使う方法などがあります。音程の決め方Beepメソッドでは第1引数にビープ音の周波数をHzで、第2引数に再生時間をミリ秒で指定します。音程(音の高さ)はHzで指定する必要があります。ここでドの音は何ヘルツで、みたいな対応表をどこかから探してきてそのデータを使ってもいいんですが、今回はせっかくなので、PowerShellで計算して求めてみます。ある音程の一つ上のオクターブの音程の間の周波数比は、1:2です。ピアノ等の鍵盤楽器が近くにあれば、それを見てもらえば分かると思いますが、1オクターブには12の音程が含まれています。1オクターブの周波数比を12個均等に分割します(この周波数の決め方を平均律といいます)。隣り合う音程の周波数比は、1:12√2となるわけです。音程の周波数比はこれでわかりました。あとは基準となる音の周波数が分かれば、全ての音の周波数が計算できるわけです。時代や地域、演奏する楽器等によって微妙に違ってきますが、現代日本においては普通は、A(ラ)=440Hzが基準周波数です。あとは単純にかけ算して周波数を求めて連想配列に入れておくだけです。コードにすればこんな感じですね。1/12)をかけ、-で半音下がる場合は割ればいいだけです。音価というのは音の長さです。Beepメソッドの第2引数にはミリ秒で実際の時間を指定する必要があるので、これも計算で求めてやります。4分音符というのは、1小節(全音符)を4分割、つまり1/4した音価を持ちます。同様に8分音符は1/8ですね。付点がつくと音価は1.5倍になります。4分音符の具体的な音価はどうやって定めるのでしょうか。それを決めるのがテンポと拍子です。Minuteともいう)で定義されます。今回作るシーケンサーは4/4拍子、すなわち1拍=4分音符とする4拍子固定とするので、1分間に4分音符がBPM回含まれることになります。具体的なコードは...略します。単なるかけ算と割り算だけなんで。MMLのパースえっと時間がなくなってきたので、駆け足で説明します。MMLのパースとは、要するに最初の例のようなMML(テキストデータ)から、実際に演奏する音程と音価の組み合わせのデータとして組み立てる作業になります。今回のシーケンサーでは、繰り返し記号等はサポートしないので、単にMMLを一文字ずつ読み込んで、音名(cなど)を見つけたら、その後の文字を読んで、+があれば半音上げるなどして周波数を求め、その後に数字があればn分音符とみなし、先ほどの計算式から実際の音価を求めてやる。いうのを全部の音でくり返すだけです。この処理をやっているのがConvertFrom-MMLという関数です。MMLテキストを入力してやると、周波数(Frequency)や発音時間(Duration)などをプロパティとして含んだpscustomobject(Noteオブジェクト)を出力します。(Noteとは音符のことです)MMLの演奏パースしたMMLを実際に演奏するのがInvoke-Beep関数です。入力は、ConvertFrom-MMLで生成したNoteオブジェクトです。$note.Duration)するだけです(えー)。あ、あと休符の時はDuration分だけSleepを入れてやっています。MMLの>と<の意味を逆転する-Reverseスイッチ、BPMを指定する-Bpmパラメータ(デフォルト120)なんかも用意してます。実際にはMMLから直接演奏できるように、Invoke-Mmlというラッパー関数を用意しています。冒頭のねこふんじゃったのMMLを再生するにはこんな感じにします。@PSBoundParameters|Invoke-Beep}おわりに今回はMMLをパースしてBeepを演奏するスクリプトをPowerShellで作ってみました。これをシーケンサーというのはおこがましいと思いますが、まあたまにはこういう柔らかいネタもいいんじゃないでしょうか。ドレミの音がどうやって決められてるのかというのも、もしかして話のネタくらいにはなるかも。これ、シーケンサーといいつつ、入力機能がないですよね。それについては次回やります。PowerShellアドベントカレンダー2014はまだまだ残席ございます。あなたのPowerShell話を聞かせて下さい。|Tweet昨日10/11のPowerShell勉強会#4にお越しいただいた方、どうもありがとうございました。スタッフ一同、これからも定期的に開催していこうと考えておりますので、ぜひともよろしくお願い致します。私のセッション資料を公開します。くま横浜で行ったものとほとんど同じですが、v5関係のスライドを少しだけ修正しています。今回は高度な関数とコマンドレットの作り方を主に取り上げていますが、要するに、PowerShellコマンドはPowerShellスクリプトでもC#でもほぼ同じようにして同じようなものが書ける、ということなのです。基本を押さえればどちらにも対応可能です。両者は状況に応じて使い分ければOKかと思います。PowerShellよりC#が得意、というならばコマンドレットを書くと良いですし、スクリプト的なお手軽なコードで書きたい場合は高度な関数、とかですね。速度が求められる部分とか、.NETアセンブリを多用する部分だけコマンドレットにして、他を高度な関数にする、あるいは、主要部はコマンドレットにして、その他はコマンドレットのラッパー的な高度な関数を用意する、のように両者を組み合わせたモジュールもよくあります。以下はデモ用のサンプルスクリプトです。高度な関数の雛型的なものになります。使い方はスライド本文を参照してください。}}以下はデモで用いたC#のコードです。コマンドレットクラスの雛型的なものになっています。ビルドの際はSDKに含まれるPowerShell関係のdllを参照設定してください(詳しくはスライド)。実行してインポートして下さい。以下の例だとGet-Baz、Set-Bazの2コマンドレットがインポートされます。|Tweet8/23わんくま横浜勉強会で、PowerShellコマンドの書き方というセッションをしたのですが、その際、株式会社Codeerさんが公開されているFriendlyというライブラリを使ったコマンドレットを動作させるデモを行いました。準備の時間がなくて、突貫工事で作ったサンプルで恐縮ですが、公開することにします。2010以降でC#のクラスライブラリを新規作成する。ある.dllを参照設定する。4.5、対象プラットフォームをx64にする。上記のコードを貼り付ける。NuGetでFriendlyおよびFriendly.Windowsを追加する。上記をビルドして生成したDLLにはGet-FormControlTextと、Set-FormControlTextの2つのコマンドレットが含まれます。6制限事項フォーム直下に配置されたコントロールしか取得できない(と思います)。Formアプリケーションにしか対応していない(と思います)。x64アプリしか操作できない(と思います。x86用はアセンブリを分ける必要がある??)。sensitiveでワイルドカード不可です。(この辺ただの手抜きですが)今後の方針?上のコードをみてもらえればわかると思いますが、ちょっと触ってみたら一応動くものができるくらい、Friendlyは分かりやすいです。皆さんもぜひ使ってみてください。本来は、テキストじゃなくてコントロールそのものをGetしたりSetしたりInvoke(クリックとか)したりできるようにしたかったんですが、Controlはシリアル化できないオブジェクトなので、Friendlyで実物を持ってきてコマンドレットに出力する、というのは無理でした。何らかのプロキシオブジェクトみたいなのでラップしたりすれば良いかと思います。それにしてもPowerShellとFriendlyの組み合わせはものすごい可能性を秘めている予感がします。システム管理方面では...セッションでもやりましたが、PowerShellコマンドレットベースのアプリケーションを作ると、GUIとCUIのいいところどりが出来る、とはいうものの、コマンドインターフェースがなくGUIオンリーのアプリケーションはまだまだたくさんあるのが現実かと思います。いうアプリケーションも、PowerShellデフォルトの機能のみではつらいですが、上記のようにFriendlyを併用すれば、GUI操作の自動化が容易になると思います。開発方面では...C#でFriendlyを使ったGUIのテストコードを書く以外に、上記のようなFriendlyの機能をラップしたコマンドレットを用意することで、PowerShellスクリプトでもテストコードを書くことができるようになると思います。その際、Pester等のPowerShell用テストフレームワークを併用すると、より一貫したテストコードが記述できるようになるんじゃないかと思います。2013の5日目の記事です。PowerShellにはJobが完了するまで待機するWait-Jobコマンドレットというのがあります。これはその名の通り、パイプラインから入力したJobオブジェクトがすべて(あるいはどれか一つが)完了状態になるまでスクリプトの実行を待機する効果があります。当然ながらWait-JobはJobオブジェクトにしか利用できませんが、任意の入力オブジェクトに対して待機条件を指定してやれば、その条件を満たすまで実行を停止するコマンドがあると便利なんじゃないかな?と常々思っていたので書いてみました。[<CommonParameters>]パラメータ-InputObject:入力オブジェクト。-Property:変更を確認するプロパティ名。-Value:-Propertyで指定のプロパティ値が、このパラメータに指定する値になるまで待機する。-FilterScript:プロパティを指定する代わりに待機条件をスクリプトブロックで指定する。-Any:入力のどれか一つが条件を満たすまで待機するようにする。(省略時は入力が全部条件を満たすまで待機)-PassThru:入力オブジェクトが待機条件を満たした時点で、そのオブジェクトを出力する。-IgnoreImmutable:最初から条件を満たしている場合は出力しない。-PassThruと併用。-AllOutput:タイムアウトした場合や-Any指定時に一部のオブジェクトしか出力していない場合でも、最終的に未出力のすべてのオブジェクトを出力してから終了する。-PassThruと併用。-IntervalSec:プロパティ値のチェック、もしくは待機条件スクリプトの実行の間隔秒数を指定。-TimeoutSec:最大待機秒数。この時間を過ぎると条件を満たしていなくても待機を終了する。停止しているサービスがすべて開始するまで待機する。上記と同じだが、開始したサービスを逐次表示する。停止しているサービスが少なくとも1つ開始するまで待機する。プロセスのワーキングセットが100MBを超えた段階で逐次表示する。上記と同じだが、最初から100MBを超えてるものは出力しない。ディレクトリ内のファイル容量がすべて50KBを超えるまで待機し、出力のFileInfo配列を変数に代入。3600問題点プロパティ値を取得するときにリアルタイムに値が反映されないオブジェクト(要するにGetした時点のプロパティ値がずっと固定されてるもの)に対しては正しく動作しません。いうか、PowerShellで扱うオブジェクトはほとんどそうなんじゃないかと思います(汗ServiceControllerオブジェクト、Processオブジェクト、FileInfoオブジェクト、DirectoryInfoオブジェクトについては、Refreshメソッドを実行すると、プロパティ値を現在の値に更新してくれるので、それを利用してプロパティ値を監視できるようにはしています。それ以外についても監視できるようにするには、たぶんそれぞれのオブジェクトに応じた監視方法を地道に調査して実装していくしかないんじゃないかなあと思います。INotifyPropertyChangedインターフェースを実装したクラスについては、PropertyChangedイベントをSubscribeしてプロパティ値の変更を追跡できるようにしてみようとちょっと思ったんですが、PowerShellで扱うオブジェクトにINotifyPropertyChangedを実装したクラスのものってそんなにあるんだろうか?と疑問を覚えたのでやめました。WMIオブジェクトについては何か共通の方法でプロパティ値変更を監視できないかなあと思ったんですが、結局IntervalSec間隔でクエリを発行する方法になってしまい、低コストで行う方法がちょっと思いつきませんでした。“ほげ”}みたいなコードを書いてゴリ押しすることもできるかと思います。感想というわけで、なんだか微妙な成果になって恐縮ですが、なんで無いんだろうと思っていた関数を実際に書いてみると、無い理由が分かったりするものなんだなあ、と思ったりした次第です。スクリプトの解説を何もしてないですが、あえて解説する程のものでもないこともないですが、まあ長くなるのでやめときます。入力オブジェクトを一旦全部取得してから、後続パイプラインに流し込む例としていくらか参考になるかもしれません。スクリプトブロックを二重にして$_に対象オブジェクトがきちんと格納されるようにする方法、若干トリッキーな気もしますが正式にはどう書くのが良いのか不明なのでこうしてみました。|TweetPowerShellでFizzBuzz問題をいかに短く書くかというのは、人類にとっての太古からの命題であり、色々な方がチャレンジしています。時系列にまとめたものです。リンク私の現在の最短コードはこれです。3.0でしか動きませんが、51文字です。2.0でも動くバージョンは以下。1..100|%{($t="fizz"*!($_%3)+"buzz"*!($_%5))+@($_)[$t]}きっと解説は不要だと思いますが蛇足を承知で少しばかり。剰余を求める演算子%を使っているので、$_が3の倍数のとき0を返します。!(0)とすると、0はboolに型変換され$falseとなり、その論理否定なので!(0)は$trueになります。すると右辺はintに型変換されるので”fizz”*1が評価され、”fizz”を返します。PowerShellでは「文字列*整数値」で文字列を整数値回繰り返した文字列を返すことを利用しています。同じことを”buzz”に対しても行い、結果を+で連結します。このとき、”fizz”か”buzz”か”fizzbuzz”か””(空の文字列)のいずれかを返します。得られた値を�@とします。すると$tに�@の値を入れつつ、�@の値を返します。すると、$tが””(空の文字列)の場合は型変換され@($_)[0]が評価されます。よって、$tが””のときは@($_)の0番目の要素、$_、すなわち元の数値が取り出されます。最後に””と元の数値を+で連結したものが出力されるので、結果として数値のみが出力されます。$tが”fizz”か”buzz”か”fizzbuzz”の場合は@($_)[$t]は配列の範囲外なので$nullを返します。よって$t+$null、すなわち$tの文字列がそのまま出力されます。3.0だと非配列変数でも[]演算子を使用することができます。よって$_[0]は$_と等しく、$_[文字列]は$nullです。これによって@($_)のように配列化する必要がなく、3文字短縮できたわけです。@mutaguchiBooks書籍版。