2014/09/09

8/23わんくま横浜勉強会で、PowerShellコマンドの書き方というセッションをしたのですが、その際、株式会社Codeerさんが公開されているFriendlyというライブラリを使ったコマンドレットを動作させるデモを行いました。

準備の時間がなくて、突貫工事で作ったサンプルで恐縮ですが、公開することにします。(一応動かしてみたら動いた、レベルのものなのであしからず…)

コード
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management.Automation;
using Codeer.Friendly.Windows;
using Codeer.Friendly.Dynamic;
using System.Windows.Forms;

namespace Winscript
{
    [Cmdlet(VerbsCommon.Get, "FormControlText")]
    public class GetFormControlTextCommand : Cmdlet
    {
        [Parameter(Mandatory = false, ValueFromPipeline = false, Position = 1)]
        public string[] ControlName { get; set; }

        [Parameter(Mandatory = true, ValueFromPipeline = true, Position = 0)]
        public Process Process { get; set; }

        protected override void ProcessRecord()
        {
            var _app = new WindowsAppFriend(this.Process);
            dynamic form = _app.Type<Control>().FromHandle(this.Process.MainWindowHandle);
            foreach (var c in form.Controls)
            {
                if (ControlName == null || ControlName.Contains((string)c.Name))
                {
                    WriteObject((string)c.Text);
                }
            }
        }
    }

    [Cmdlet(VerbsCommon.Set, "FormControlText")]
    public class SetFormControlTextCommand : Cmdlet
    {
        [Parameter(Mandatory = true, ValueFromPipeline = false, Position = 1)]
        public string ControlName { get; set; }

        [Parameter(Mandatory = true, ValueFromPipeline = false, Position = 2)]
        public string Text { get; set; }

        [Parameter(Mandatory = true, ValueFromPipeline = true, Position = 0)]
        public Process Process { get; set; }

        protected override void ProcessRecord()
        {
            var _app = new WindowsAppFriend(this.Process);
            dynamic form = _app.Type<Control>().FromHandle(this.Process.MainWindowHandle);
            foreach (var c in form.Controls)
            {
                if (ControlName == (string)c.Name)
                {
                    c.Text = Text;
                }
            }
        }
    }
}
ビルド方法
  1. Windows 8.1 SDK をインストールする。
  2. Visual Studio 2010以降でC#のクラスライブラリを新規作成する。
  3. C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0 にある.dllを参照設定する。
  4. 対象フレームワークを.NET 4.5、対象プラットフォームをx64にする。
  5. 上記のコードを貼り付ける。
  6. NuGetでFriendlyおよびFriendly.Windowsを追加する。
  7. ビルドする。
使用方法

上記をビルドして生成したDLLにはGet-FormControlTextと、Set-FormControlTextの2つのコマンドレットが含まれます。

# コマンドレットのインポート
Import-Module "dllのフルパス"

# 操作対象のプロセスオブジェクト取得
$p = Get-Process WindowsFormsApplication1 

# プロセスを指定して、すべてのコントロールのテキストを取得
Get-FormControlText -Process $p

# プロセスとコントロール名を指定して、テキストを取得
Get-FormControlText -Process $p -ControlName textBox1

# 位置パラメータなので以下のようにも書ける
Get-FormControlText $p textBox1

# パイプラインからプロセスオブジェクトを入力することもできる
$p | Get-FormControlText -ControlName textBox1 

# プロセスとコントロール名を指定して、テキストを変更する
Set-FormControlText -Process $p -ControlName textBox1 -Text Wankuma
Set-FormControlText $p textBox1 Yokohama
$p | Set-FormControlText -ControlName textBox1 -Text 6
制限事項

フォーム直下に配置されたコントロールしか取得できない(と思います)。

Windows Formアプリケーションにしか対応していない(と思います)。

x64アプリしか操作できない(と思います。x86用はアセンブリを分ける必要がある??)。(←9/9追記)

コントロール名指定はCase sensitiveでワイルドカード不可です。(この辺ただの手抜きですが)

今後の方針?

上のコードをみてもらえればわかると思いますが、ちょっと触ってみたら一応動くものができるくらい、Friendlyは分かりやすいです。皆さんもぜひ使ってみてください。

本来は、テキストじゃなくてコントロールそのものをGetしたりSetしたりInvoke(クリックとか)したりできるようにしたかったんですが、Controlはシリアル化できないオブジェクトなので、Friendlyで実物を持ってきてコマンドレットに出力する、というのは無理でした。何らかのプロキシオブジェクトみたいなのでラップしたりすれば良いかと思います。

それにしてもPowerShellとFriendlyの組み合わせはものすごい可能性を秘めている予感がします。

システム管理方面では…

セッションでもやりましたが、PowerShellコマンドレットベースのアプリケーションを作ると、GUIとCUIのいいところどりが出来る、とはいうものの、コマンドインターフェースがなくGUIオンリーのアプリケーションはまだまだたくさんあるのが現実かと思います。そういうアプリケーションも、PowerShellデフォルトの機能のみではつらいですが、上記のようにFriendlyを併用すれば、GUI操作の自動化が容易になると思います。

開発方面では…

C#でFriendlyを使ったGUIのテストコードを書く以外に、上記のようなFriendlyの機能をラップしたコマンドレットを用意することで、PowerShellスクリプトでもテストコードを書くことができるようになると思います。その際、Pester等のPowerShell用テストフレームワークを併用すると、より一貫したテストコードが記述できるようになるんじゃないかと思います。

いずれは(いつ?)、Friendlyの機能をラップしたコマンドレット群をきちんと設計、実装して、モジュールとして公開したいですね!

2012/03/06

次期Windows Server OSであるWindows Server “8”のベータ版が3/1よりWindows 8 Consumer Preview版と同時に提供が開始されました。今回のリリースでは日本語版も提供されています。

それと同時にPowerShell 3.0 betaを含むWindows Management Framework (WMF) 3.0 betaの提供も始まりました。こちらは英語版のみの提供で、日本語環境にインストールするには英語言語パッケージをダウンロードし適用する必要があります。

まだ評価を初めて間もない段階ですが、きづいた点をいくつか書いてみます。

PowerShell ISEがDeveloper Preview/CTP版から大きく変わっており、コマンドを入力する「コマンドペイン」と結果が表示される「出力ペイン」が統合され、「コンソールペイン」となりました。image

こんな感じでコンソールペインはその名の通りコンソール版のPowerShellと見た目や使用感が似ている上にISEならではの機能(インテリセンスなど)が使用可能になっており、ISEはスクリプト編集のみならずインタラクティブシェルとしてpowershell.exeの代わりに使用する場合でもより便利になったと言えるでしょう。なおISEのキーワード色分け設定は細かく指定できたりします。

Server8ではActive Directory管理センターの大幅な機能増強が目に留まります。Active Directory管理センターには「Windows PowerShell 履歴」ペインが追加され、GUIで操作した履歴がそのまま、再実行可能なPowerShellスクリプトとして表示されるようになりました。

たとえばユーザーを作成する作業をGUIでやります。

image

するとその作業内容がこのように履歴ペインに表示されます。

image

履歴はまさにPowerShellスクリプトそのままなので、これを「コピー」してISEに貼りつけるともうスクリプトファイルが完成します。

image

あとは必要に応じてパラメータを変更したり、ループを設けて繰り返し処理をしたり、自由自在に再利用ができます。ここではユーザー名を”testuser2”に変えて実行してみました。最初にGUIで作ったユーザーと同じ設定を用いて複数のユーザーを作成することが簡単に行えます。ユーザー名を記載したCSVファイルを読み込んでそのユーザーを一括作成することなどもできますね(PowerShellにはImport-CsvというCSVファイルを扱うコマンドレットもあります)。

スクリプトファイルにして保存すれば何回でも実行可能ですし、PSScheduledJobモジュールを使ってタスクスケジューラに登録すれば定期実行も可能です。

履歴スクリプトのうち、どこからどこまでが「今やった作業」なのか分かりにくいこともあると思いますが、そういうときには履歴ペインの「タスクの開始」をクリックし、今からやりたい作業名をまずメモします。

image

そしてGUIで作業を行い、終わったら「タスクの終了」をクリックします。

image

作業単位でこれを繰り返します。すべてが終わったら履歴をすべてコピーしてISEに貼りつけてみます。

image

するとこのようにタスク名がコメント行として挿入され、スクリプトのどこからどこまでが、どの作業に対応しているかが明確になるわけです。

このように管理GUIがPowerShellモジュール(コマンドレット)のフロントエンド的存在となり、GUIでの操作によりPowerShellコマンドレットが実行され、その履歴はスクリプトとして再利用が可能というMicrosoftが提唱する新しい管理方式が、ついにWindows Serverの本丸的存在Active Directoryに採用されたということになります。2008R2のActive Directory管理センターも内部的にはそういう構造だったのですが、履歴をスクリプトとして取り出す方法がなかったのですが、Server8からは可能になったということになります。

これまではこの構造が完全に組み込まれていたのはExchange Serverなど限られた製品のみでしたが、今後はこちらの構造が主流になると思われます。GUIとCUIの「いいとこどり」ができるこの構造はなかなか理想的なシステムなんじゃないかと思います。

PowerShellは3.0になってますますWindows OS管理の中核として重要度が高まっており、それに答えるように様々な機能増強が行われています。今回紹介したのはその一面ですが、特にServer8においてPowerShellがいかに重要かはWindows Server "8" に関するテクニカル プレビューの各項目の記述内容の多くにPowerShellに関する記載があることでも分かるかと思います。

2011/10/09

WindowsサイドバーガジェットはWindows Vistaの登場で追加されたプログラムで、デスクトップ上にガジェットと呼ばれるミニプログラムを貼り付けることができます。ガジェットはHTML/CSS/J(ava)Script (+VBScript)で記述することができます。Windows7の登場で名称が「Windowsデスクトップガジェット」と変更され、一部仕様に変更が加えられたものの現役でした。

ところが先月末(2011/09)頃に、サードパーティー製のものを含む多数の追加ガジェットのWindows Live Galleryでの公開が中止されました。現在は登録されたガジェットのリストは表示されるものの、ダウンロードができない状態です。まもなくサイト自体が閉鎖されるものと思われます。

現時点でWindows7で「ガジェット」を実行し、そこに表示される「オンラインで追加のガジェットを取得」リンクをクリックするとデスクトップ ガジェット - Microsoft Windowsというページに飛ばされますが、ここでは(おそらく人気上位であった)ガジェットが数点のみダウンロードできるという状態です。

この措置に対するMicrosoftの公式コメントがこちらになります。Looking for gadgets? - Downloads - Microsoft Windows

この記事を要約すると

  • MicrosoftはWindows Live Galleryを閉鎖し、今後、新しいガジェットの開発およびアップロードをサポートしない
  • ただし人気ガジェットはまだダウンロードできるようにしておくよ
  • ガジェット製作者はよりリッチなプラットフォームであるMetro Style Appにシフトしてね
  • でもまだガジェットに興味がある人もいるだろうから一応開発ドキュメントは残しておくよ
  • まだガジェットを公開したいのならCodePlexでどうぞ

という感じになるかと思います。まだPreview版しか出てない次期Windowsでしか動かないMetro Style Appを移行先に指定するのはかなり無理があるように思いますが、どうもMicrosoftはMetroと技術的にかぶるガジェットをさっさと亡きものにしたいようです。Windows 8のDeveloper Previewのクラシックデスクトップでは一応、今のところはデスクトップガジェットの機能は削除されていませんが、これからの開発の過程で削除されてしまう可能性も十分にありそうです。

ちなみにデスクトップガジェットはたとえIE9をインストールしてもHTML5コンテンツは動きませんし、JavaScriptもチャクラではなくJScript5.8で動きます。この時点でガジェットの未来はなさそうだと踏んでいましたが、思ったより早い終焉を迎えるようです。

Metro Style AppはたしかにWinRT上でJavaScript+HTML5+CSS3で開発することができ、ガジェットで培われたノウハウの一部は流用できる可能性はあるものの、ガジェットから単純に移行というのは難しそうです。利用者にとってもガジェットをデスクトップに常時複数表示させておき、作業中にもほかの情報を参照できるメリットが失われるのは厳しいものがあるように思います(Metro Style Appは一つだけクラシックデスクトップと同時に表示できる)。

告知も私の知るかぎりなかったですし、気づけばいきなり消滅していたという感じで、お困りの方も今後増えそうです(たしかにガジェットはいまいち流行ってなかったですがいきなりはヒドイ)。とりあえず現在追加インストールしているガジェットは、今後入手困難になる可能性が高いので、各自でバックアップを取っておくことをお勧めします。

.gadgetファイルそのものを保存していなくても、C:\Users\ユーザー名\AppData\Local\Microsoft\Windows Sidebar\Gadgetsの各サブフォルダがガジェット一つ一つに対応しているので、これをバックアップしておけば問題ありません。再インストールも単にこれらのファイルを同じ場所に書き戻すだけでOKです。

また、.gadgetファイルは単に関連ファイルをzipで固めたものなので、ご自分でこれらの各サブフォルダをzipにして.gadgetにリネームすればインストーラーを復元することもできます。

これらの措置は自己責任にてお願いします。各ガジェット作者のアナウンスがある場合はそちらに従ってください。

それにしても、WindowsデスクトップにHTML+スクリプトで記述されたミニプログラムを配置するといえば古くは「アクティブデスクトップ」まで遡ることになると思いますが、「ガジェット」で安定するかと思ったら二世代しか持ちませんでしたね。競合するGoogleデスクトップも終了しましたし、あまりウケがよろしくないんでしょうか。Metro Style Appはその点どうなんでしょうね?

元記事:http://blogs.wankuma.com/mutaguchi/archive/2011/10/09/204219.aspx

2009/08/15

イマイチ注目度の低いガジェットですが、Windows Vista→7でかなり変更があります。まだ開発までは追いきれてないのですが、とりあえず使用方法について気付いたことをメモ。

  Windows サイドバー ガジェット Windows デスクトップ ガジェット
OS Windows Vista Windows 7
デフォルト表示位置 デスクトップの左右どちらか(マルチディスプレイ環境ではいずれか一つのディスプレイ) デスクトップの任意の場所。ただし、デスクトップの左右には目に見えないグリッドがあり、マウスでD&Dすると位置補正がかかる。(シフトキーを押しながらだと補正はかからない)
整列 左右に格納(Docked)時は自動整列 自動整列なし
マルチページ 左右に格納時、はみ出したガジェットは2ページ目以降に表示される マルチページ機能なし
ショートカットキー

Windowsキー+スペースキーで手前に表示
Windowsキー+Gでガジェットの選択

Windowsキー+Gでガジェットの選択
のみ (8/19修正。JZ5さん komvoyさんありがとうございます)

ガジェットの大きさ Docked時は小さいサイズ、unDocked(デスクトップの任意の場所に配置)時は大きいサイズ ガジェットの右上に表示されるボタンで小さいサイズと大きいサイズのいずれかを選択できる
ガジェットの最小サイズ 130 x 55px なし?
起動方法 スタートメニュー→「すべてのプログラム」→「アクセサリ」→「Windows サイドバー」から起動 デスクトップを右クリックし、「表示」→「デスクトップ ガジェットの表示」にチェック
終了方法 通知領域(タスクトレイ)のアイコンの右クリックメニュー デスクトップを右クリックし、「表示」→「デスクトップ ガジェットの表示」のチェックをはずす
ガジェットの追加 サイドバーの上の+ボタンクリック デスクトップを右クリックして「ガジェット」をクリック
なんか、微妙に機能が削られてるというかなんというか…あと、デスクトップ右に並べた時に右にできるスペースが妙に広い。まぁアイコンが大きくなったせいなんでしょうが… 元記事:http://blogs.wankuma.com/mutaguchi/archive/2009/08/15/180164.aspx

2007/10/04

・.で始まるタイトルのファイルが同期されない

例) .NETのサイトです.url

これは.で始まるファイルをUNIX風にhiddenとみなすためと思われます。個人的にはシェルがちゃんとurlファイルと認識してるんだから例外として扱ってほしかったですね。どこかに設定あります?

 

・アクセスするたびにお気に入りバーの順序が変わる

最終アクセス日時が変わるのでお気に入りをクリックするたびに、ほかのPCと同期してしまうため順序が狂う。

これはちょっと・・・

 

結論:Groove2007をIEのお気に入り同期に使うのは微妙かな。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2007/10/04/99806.aspx

2007/07/28

窓の杜 - 【NEWS】Windows Vista用ガジェットパック「nDigiGadgets」v0.11が公開、計16本を収録
http://www.forest.impress.co.jp/article/2006/09/21/ndigigadgets011.html

というガジェットシリーズの中に、nDigiTVProgramという、ライブドアのテレビ番組表RSSを取得して表示するガジェットがあり愛用しています。このガジェットの中でMicrosoft.XMLDOMを同期処理(xml.async = false;)で呼び出しているのですが、たまによくloadメソッド実行時に固まります。やっかいなのはガジェットは一つがフリーズすると全体を巻き込むところですね。非同期化するとこの問題は解消します。で、やり方は、

ローカルの XML ドキュメントをロードする (hPod)
http://hwat.sakura.ne.jp/hpod/200612/22-220000/

に載っています。

asyncプロパティをtrueにし、onreadystatechangeイベントに匿名関数を割り当てます。

...
	var xml = new ActiveXObject("Microsoft.XMLDOM");
	//xml.async = false;
	xml.async = true;
	xml.onreadystatechange = function (){
		if( xml.readyState == 4 ){
			// ロード完了時に、何かする
			var rdf;
....この中にもともとloadの後にあった処理を移動させる...
			statustext.title = "次のデータ取得は"+ mindate.getHours() + "時" + mindate.getMinutes() + "分\n今すぐ取得するにはクリック"
		}
	}
	xml.load(uri);


}

var lastLoadText = "";
...

てな感じで。

すべて他の方のネタでごめんなさいですー。私もガジェット作成続きしなきゃ・・・

ちなみにこのガジェットの作者さん、MSMVPを受賞されたそうです。おめでとうございますー。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2007/07/28/87488.aspx

2006/12/08

前のブログを閉鎖するので、これから元記事を一気にコピーします。

元記事はこちらですhttp://winscript.s41.xrea.com/mt/archives/2005/09/post_4.html

.NET FrameworkのSystem.Windows.Formsに含まれるコントロールを利用して、簡易ファイラをつくってみました。テキストボックスにパスを入れて「移動」ボタンを押すとそのフォルダの中身をリストボックスに表示します。リストボックスのファイルをダブルクリックすると実行、フォルダをダブルクリックすると移動します。イベントハンドラの使い方に注目してください。

function InvokeItem {
    Param($path)
    
    # 現在のパス+選択したファイル/フォルダ名を組み立てる
    $path2 = $(get-location).ToString() +"\" + $path
    
    if ([System.IO.Directory]::Exists($path2) ){
    # フォルダなら移動
        ChDirectory($path2)
    }else{
    #ファイルなら実行
        invoke-item $path
    }
}
 
function ChDirectory {
    Param($path)
    
    set-location $path #ディレクトリ移動
    $listBox1.Items.Clear() #リストボックスを空にする
    
    # get-childitem Cmdletの戻り値をパイプラインに渡し、
    # foreachしてリストボックスに追加する
    get-childitem | foreach{$r = $listBox1.Items.Add($_)}
}
 
 
[void] [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
[void] [System.Windows.Forms.Application]::EnableVisualStyles()
$form = new-object System.Windows.Forms.Form
$form.Size = new-object System.Drawing.Size(300, 400)
 
$textbox1 = new-object System.Windows.Forms.TextBox
$textbox1.Size = new-object System.Drawing.Size(250, 20)
$textbox1.Location = new-object System.Drawing.Point(0, 0)
$textbox1.Text = get-location
 
$button1 = new-object System.Windows.Forms.Button
$button1.Size = new-object System.Drawing.Size(40, 20)
$button1.Location = new-object System.Drawing.Point(250, 0)
$button1.Text = "移動"
# ButtonのClickイベント
$button1.Add_Click({ChDirectory($textbox1.Text)})
 
$listbox1 = new-object System.Windows.Forms.ListBox
$listBox1.Size = new-object System.Drawing.Size(250, 300)
$listBox1.Location = new-object System.Drawing.Point(0, 50)
# ListBoxのDoubleClickイベント
$listBox1.Add_DoubleClick({InvokeItem($listBox1.SelectedItem)})
 
# 初期ディレクトリの設定
ChDirectory($textbox1.Text)
 
# コントロールをフォームに配置して表示
$form.Controls.Add($textbox1)
$form.Controls.Add($button1)
$form.Controls.Add($listBox1)
$form.showDialog()
元記事:http://blogs.wankuma.com/mutaguchi/archive/2006/12/09/49648.aspx

2006/11/01

PowerShellのコマンドレットのヘルプを引くには、get-help コマンド名 -detailなどとしますが、コマンドラインでいちいち打つのは邪魔くさい、一覧のヘルプファイルが欲しい、という場合に便利なワンライナーを書いてみました。

カレントにファイルが作成されますので、適宜cdで移動してください。

コマンドレットのヘルプのHTMLを作成するワンライナー

get-command -commandtype cmdlet|%{"

" + (get-help $_.Name -detail|out-string).Replace("&","&").Replace("<","<").Replace(">",">").Replace("`n","
") +"

"|out-file($_.name + ".html")}

HTMLのインデックスを作成するワンライナー

$temp="";out-file index.html -inputobject $temp

これを実行すると、カレントディレクトリに、コマンドレットのヘルプが記述された「コマンドレット名.html」というファイルが、登録されている数だけ作成され、インデックスとなるファイルが「index.html」として作成されます。

あとはindex.htmlを開いて読みたいコマンドレットのリンクをクリックしてください。
関連リンクに実際にリンクを張るなど、改造しだすといろいろできると思いますが、まずはワンライナーとしてここに載せておきます。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2006/11/01/43172.aspx


Copyright © 2005-2018 Daisuke Mutaguchi All rights reserved
mailto: mutaguchi at roy.hi-ho.ne.jp
プライバシーポリシー

Books

Twitter