2010/03/04

PowerShell 2.0ではscriptblockにGetNewClosure()メソッドが追加され、クロージャを記述することができるようになりました。

クロージャを作るには、まず関数の中に変数(レキシカル変数)と関数(PowerShellではスクリプトブロック)を定義します。外側の関数内に定義された変数(レキシカル変数)を関数内に定義された内側の関数から操作するようにしておきます。そして外側の関数は内側の関数そのものを返却するようにしておきます。これでクロージャができました。

クロージャを使用するには、まず外部から外側の関数の戻り値(これは内側の関数です)を変数に代入します。そしてこの変数に含まれる関数(内側の関数)を実行すると、レキシカル変数に何らかの変化を及ぼしつつ結果が返却されます。ポイントは、レキシカル変数の値が保持されることです。その結果、内側の関数を実行するたびにその時のレキシカル変数の値に基づいた結果を返却するようにできるわけです。

とまあ書いても何のことかよくわからないかと思いますので実例を示します。よくある例題なのですが、「呼び出すたびに1が加算された結果を返す関数。すなわち、呼び出すと結果が、1,2,3,4…と続いていく関数」を考えます。

function counter()
{
	$x=0
	return {$script:x++;return $x}.GetNewClosure()
}

これがクロージャの本体です。ポイントは、scriptスコープを使用することで内側のスクリプトブロックからレキシカル変数(ここでは$x)の値を変更している点です。

使用法は次のようになります。変数$fにcounter関数の内側のスクリプトブロックを代入し、&演算子で実行しています。

PS C:\Users\daisuke> $f=counter
PS C:\Users\daisuke> &$f
1
PS C:\Users\daisuke> &$f
2
PS C:\Users\daisuke> &$f
3
PS C:\Users\daisuke> &$f
4
PS C:\Users\daisuke>

見事、お題を実現することができました。

さて、GetNewClosure()メソッドが追加されたことで、関数のカリー化も可能になります。カリー化とは、たとえばf(x,y)という関数があった場合、g(x)(y)という、f(x,y)と常に同じ値を返却する関数を作ることです。一般には、複数の引数をとる関数fを、fの最初の引数だけを引数にとり、「fの残りの引数をとり結果を返す関数」が戻り値であるgという関数に変換することです。これまた何のことかわかりにくいですね。

たとえば一番簡単な例。引数同士を加算する関数sumをカリー化してcurried_sumという関数を作ってみます。

function sum([int]$x,[int]$y)
{
	return [int]($x+$y)
}

function curried_sum([int]$x)
{
	return {param([int]$y);return sum $x $y}.GetNewClosure()
}

これでsumのカリー化ができました。実行してみます。

PS C:\Users\daisuke> &$(curried_sum 3) 4
7
PS C:\Users\daisuke> &$(curried_sum -6) 14
8
PS C:\Users\daisuke> &$(curried_sum -2) -3
-5
PS C:\Users\daisuke> $sum5 = curried_sum 5
PS C:\Users\daisuke> &$sum5 11
16
PS C:\Users\daisuke> &$sum5 -4
1
PS C:\Users\daisuke> $sum2 = curried_sum 2
PS C:\Users\daisuke> &$sum2 8
10
PS C:\Users\daisuke> &$sum2 1
3

PowerShellの関数の呼び出し方がわりと特殊であるため、少々分かりにくいですがサブ式$()と呼び出し演算子&をつかってカリー化されたsum関数を実行して目的通りの結果を得ています。たとえば最初の例は3+4を実行していることになり、結果はsum 3 4と同じ7になります。以下同様です。$sum5は、「引数に5を加える関数」になります。

いかがでしたでしょうか。PowerShellでも(なんか文法とか奇妙ですが)クロージャやカリー化ができて楽しいですね。というか私は本記事を書くにあたってクロージャとカリー化がなんぞやということを勉強しました…。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/03/04/186768.aspx

2010/02/22

PowerShell 2.0では標準コマンドレットの数が1.0の129個から236個へと、107個増えています。また、既存のコマンドレットの一部にパラメータが増えています。そこで、2.0で新しく加わったコマンドレットと、新しく追加されたパラメータを列挙するスクリプトを作ってみました。

まず、1.0がインストールされている環境で、コマンドレットのリストをXMLに書き出します。次のコマンドを実行してください。

 get-command -type cmdlet|export-clixml cmdlets1.xml -depth 3

同様に、2.0の環境でも実行してください。

 get-command -type cmdlet|export-clixml cmdlets2.xml -depth 3

出来上がった二つのxmlファイルをカレントディレクトリに置いて、次のスクリプトを実行すると、新しく追加されたコマンドレットとパラメータが列挙されます。(必要なら適宜リダイレクトするなどしてファイルに落とし込んでください)

function Get-CmdletHash
{
    param([string]$path)
    $cmdlets = Import-Clixml $path
    $cmdletsHash = @{}
    $cmdlets|
        %{
            $parameters = @()
            $_.ParameterSets|
                %{
                    $_.Parameters|
                        %{
                            $parameters += $_.Name
                        }
                }
            $parameters = $parameters|Sort-Object|Get-Unique|?{"WarningAction","WarningVariable" -notcontains $_}
            $cmdletsHash.Add($_.Name,$parameters)
        }
    return $cmdletsHash
}

$ver1 = Get-CmdletHash cmdlets1.xml
$ver2 = Get-CmdletHash cmdlets2.xml

$ver2.Keys|
    %{
        if($ver1.ContainsKey($_))
        {
            $result = Compare-Object $ver1[$_] $ver2[$_]
            if($result)
            {
                "[Update] $_"  
                $result | Format-Table
            }
        }
        else
        {
            "[New] $_  `r`n" 
        }
    }

出力結果を置いておきます。こちら

このスクリプトではGet-CommandコマンドレットがSystem.Management.Automation.CmdletInfoというコマンドレットの情報を格納したオブジェクトを返すことを利用し、Export-Clixmlコマンドレットでシリアライズ化してXMLファイルに落とし込むことにより異なるバージョンのPowerShell同士を比較しています。ここで-depthパラメータを3にしているのは、パラメータ情報を格納するParametersプロパティがルートから3階層下にあるためです。(デフォルトは2階層下までを出力。PS2.0ではCmdletInfoにParametersプロパティというのがあって2階層でたどれるのですが1.0にこのプロパティはないのでParameterSetsプロパティからたどる必要があります)

また、WarningActionとWarningVariableという共通パラメータが増えているので、これらはすべてのコマンドレットに共通して追加されているパラメータなので除外しておきます。

あとはパラメータをコマンドレットごとに配列化して、Compare-Objectで比較しています。新しく追加されたコマンドレットは[New]のマークをつけ、既存のコマンドレットでパラメータに変化があるものは[Update]をつけて追加されたパラメータを列挙するようにしています。

かなりたくさんのコマンドレットでパラメータが増えたことが分かりますね。また、Get-CommandコマンドレットのPSSnapinパラメータが廃止され、Moduleパラメータに変更されたことなどが分かったりします。

1.0ユーザーだった方にお勧めのスクリプトです。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/02/22/186334.aspx

2010/01/10

こんなビルドイベントはいかがでしょうか?

copy "$(TargetPath)" C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSTweets\
start powershell -NoExit -command "Import-Module PSTweets"

PSプロバイダやコマンドレットが含まれるdll(PSモジュール)をモジュールフォルダにコピーし、モジュールを読み込んだ状態でPowerShellを起動してくれます。ただし、systemフォルダに書き込む手順があるのでVisual Studioは管理者権限で起動してください。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/01/10/184828.aspx

2009/12/09

PowerShell 2.0では新しい演算子-splitと-joinがサポートされました。-splitは「文字列を特定の文字で切り分けて配列を作る」演算子、-join演算子は「配列を特定の文字列を使って繋いで一つの文字列にする」演算子です。

使い方です

$a="a,b,c,d,e" -split ","
$a[1]

これは-split演算子を使って、a,b,c,d,eという文字列を、,(カンマ)で切り分けて配列にし、2つ目の要素を取り出す例です。結果は次のようになります。

b

配列は-joinを使って一つの文字列にすることができます。先ほど作った配列を&という文字で繋げるには次のようにします。

$a -join "&"

結果は以下のようになります。

a&b&c&d&e

このように、PowerShellでもVBScriptのSplit関数やJoin関数を使った場合と同様の文字列配列操作が可能になりました。

なお、PowerShell 1.0ではこのようにします。

-split演算子の代わり。string型のインスタンスに対し、Splitメソッドを実行する。

$b="a,b,c,d,e".Split(",")

-join演算子の代わり。stringクラスのスタティックメソッドJoin()を使用。

[string]::Join("&",$b)
元記事:http://blogs.wankuma.com/mutaguchi/archive/2009/12/09/183685.aspx

2009/10/06

PowerShell v2のバックグラウンドジョブ機能は便利ですが、

$job=Start-Job {Start-Sleep -sec 10;”done”}

などとした場合、このジョブが終了したかどうかをまず

$job

で調べ、終了していたら

Receive-Job $job

のようにしないと結果を表示できません。これはわりかし不便なので、ジョブが終了したらダイアログを出すように工夫してみました。

function StartAndNotify-Job
{
	param([scriptblock]$ScriptBlock)
	$jobId = "JobWatcher"
	$global:job = Start-Job $ScriptBlock
	
	$global:watcherJob = Register-ObjectEvent -EventName StateChanged -InputObject $job -SourceIdentifier $jobId -Action `
	{
		[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
		$recievedString = Receive-Job $job
		if($recievedString -eq $null){$recievedString = ""}
		if($job.State -eq "Completed")
		{
			[System.Windows.Forms.MessageBox]::Show($recievedString,$job.Command,"OK","Asterisk")
		}
		else
		{
			[System.Windows.Forms.MessageBox]::Show($job.Command + "は失敗しました。`r`n詳細はReceive-Job -id " + $job.Id  + " を実行し確認してください。",$job.Command,"OK","Error")
		}
		Unregister-Event "JobWatcher"
		Remove-Job $global:watcherJob
	}
}

使用例

StartAndNotify-Job {Start-Sleep -sec 10;”done”}

このように、スクリプトブロックを渡しておくとバックグラウンド処理が走り、終わるとメッセージボックスが出て、出力結果があるとそれを表示します。エラーが発生した場合はその旨を表示します。便利です。

本当はエラーが出た場合はエラー内容を表示させたいんですがやり方がわかりませんでした。なので、エラーを表示させる方法のみ表示します。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2009/10/06/181919.aspx

2009/10/04

リモート(ローカルでもいいですが)のPSSessionに入る(ファンインする)ためには、まずNew-PSSessionでPSSessionを作成し、Enter-PSSessionでそのセッションに入ります。面倒なので関数化してみました。

function Enter-ServerSession()
{
	$encryptedString="中略"
	$credential = New-Object System.Management.Automation.PSCredential "ユーザー名@ドメイン名",(ConvertTo-SecureString $encryptedString)
	$session = New-PSSession サーバー名 -Credential $credential
	Enter-PSSession $session
}

ここで、パスワードを毎回入力するのは面倒なので、関数の中に暗号化したものを直書きしてしまいます(もちろん、見てはいけない人に見られないところに関数を保存してくださいね)。

$encryptedStringにはパスワードの暗号化文字列を入れます。この文字列の取得方法は、

PS C:\> ConvertFrom-SecureString (Get-Credential).Password

と入力すると認証ダイアログが出るので、そこにユーザー名とパスワードを入れると、パスワードが暗号化された文字列を得ることができます。

なお、もちろん、PSSessionを張るサーバーへの認証が必要ない場合は、-Credentialの指定は要らないです。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2009/10/04/181825.aspx

2009/07/20

こんにちは、むたぐちです。

PowerShellによるWindowsサーバ管理術(永尾 幸夫、小鮒 通成、国井 傑、竹島 友理、牟田口 大介 著)という書籍が、ソフトバンク クリエイティブから2009/07/30に発売予定です。私は1章と2章を執筆させていただきました。

おそらく国内では初の、PowerShell ver.2を使ったスクリプトベースでのWindowsサーバー管理ノウハウの書籍です。ぜひ本屋さんでお手に取ってみてください!

PowerShell ver.2はまだCTP3ですが、いずれWindows Server 2008をはじめ各種OS用のモジュールが提供される予定です。Windows Server 2008 R2とWindows 7ではPSv2が標準機能となっており、現在これらは製品版に近いRC版が公開されていますが、これに含まれるPSv2はほぼ完成しています。そのため、このバージョンのPSv2でも本初収録のスクリプトは動作することを確認しています。そのため、PSv2正式版が公開されてもこの本は問題なく使用できると思います。

# ただ一点だけ、Enable-PSRemotingというコマンドレットがCTPでは関数だったりps1ファイルだったり何となくまだ仕様が謎だったので、winrm quickconfigを使ってありますw

目次はこのような感じです。

第1章 Wndows PowerShellという環境
第2章 PowerShellの基礎知識
第3章 プロセスの管理
第4章 ActiveDirectoryとユーザー管理
第5章 システム情報の管理
第6章 サービスの管理
第7章 イベントログの管理
第8章 ExchangeServerの管理

元記事:http://blogs.wankuma.com/mutaguchi/archive/2009/07/20/178462.aspx

2009/06/30

Windows Server 2008 R2ではPowerShell v2が標準機能ですが、v2の目玉の一つとしてリモートでサーバーのPSを実行できる機能があります。

詳しくは、7/4の大阪のセッションでデモを交えてお話しできると思いますが、http://technet.microsoft.com/ja-jp/magazine/2008.08.windowspowershell.aspxを読んで予習しておくのもいいかと思います。

なお、この記事が書かれたときの最新バージョンのCTP2から変更点があり、コマンドレット名が若干変わっています。

New-RunSpace→New-PSSession

push-runspace→Enter-PSSession

pop-runspace→Exit-PSSession

さて、PSRemotingはWinRM2.0を用いたリモート通信なのですが、WinRM2.0は認証にKerberos認証を用います。Active Directoryにログオンしたクライアントから

New-PSSession ServerName

のようにすると、ログオン時の認証情報が用いられ、認証され、通信が始まります。しかし、ログオン時とは異なる認証情報を送る必要がある場合もあるので、そのときは-credentialパラメータを使います。

New-PSSession ServerName -credential (Get-Credential)

のようにすると、認証ダイアログが表示されるので、ユーザー名とパスワードを入れて認証情報を送りログオンすることができます。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2009/06/30/176828.aspx


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

Twitter

Books