2010/03/06

ホワイトボードプログラミング
反転...ですかー
ループなしで、配列の順序を逆にする

よし、おれにまかせろ!

PS C:\Users\daisuke> $array=@(1,3,5,7,9,11)
PS C:\Users\daisuke> $array=$array[($array.length-1)..0]
PS C:\Users\daisuke> $array
11
9
7
5
3
1
元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/03/06/186860.aspx

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/02/13

PowerShellは.NET Framework 2.0を利用するWindowsのシステム管理用シェルである。シェルであるためコンソールで対話的にコマンドを実行することができるのはもちろん、スクリプトファイル(*.ps1)を記述しバッチ的に実行することも可能である。ここではPowerShellスクリプトで(コンソールでも使用は可能だが)用いることのできる基礎文法を紹介する。なお、PowerShellでは文法上、大文字小文字を区別しない。

※(★2.0)の注釈があるものはPowerShell 2.0で新たに追加された要素である。

1.基礎

表示

コンソールに文字列を表示。

"Hello world" 

コマンドレット(後述)を使用した場合。

Write-Host "Hello world" 

コマンドレット

PowerShellはコマンドレットと呼ばれる100種類以上のコマンドライン・ツール群を単独で、あるいはパイプライン(後述)で連結して使用するのが基本となる。コマンドレットは原則verb-nounという命名規則にしたがっている。パラメータをつける場合は「-パラメータ名」あるいは「-パラメータ名 パラメータ値」を指定する。

# コマンドレットの一覧表示
Get-Command 

# サービスの一覧を表示
Get-Service 

# アプリケーション イベントログの最新15個のエントリを表示
Get-EventLog -logName Application -newest 15

パイプライン

コマンドレットが値を返却する場合、.NET Frameworkのオブジェクトが含まれる配列であることが多い。このオブジェクト配列がパイプラインを渡って後続のコマンドレットに入力される。

# プロセスのリスト(System.Diagnostics.Processオブジェクトの配列)を取得し、
# Where-Objectコマンドレットでハンドル数(handlesプロパティ)の値が500より大きいものだけを取り出し
# Select-Objectコマンドレットで最初の5つのオブジェクトだけを切りだして表示
Get-Process | Where-Object {$_.handles -gt 500} | Select-Object -first 5

# C:\Windows 配下のフォルダ、ファイルの一覧(System.IO.DirectoryInfo,System.IO.FileInfoオブジェクトの配列)を取得し、
# ForEach-Objectコマンドレットで配列を列挙しすべてのオブジェクトのFullNameプロパティ(フルパス)の値を表示
Get-ChildItem C:\Windows | ForEach-Object {$_.FullName} 

# 通常の配列に関してもパイプラインを使用可能。
# 重複を取り除き、ソートをかける
@(3,5,10,1,2,1,1,1,2,6,4,4)|Sort-Object|Get-Unique 

コメント

# コメント 

マルチラインコメント(★2.0)

<#
複数行に渡る
コメントです
#> 

変数の宣言

PowerShellは変数の宣言をしなくても変数を使用可能。以下のようにするとどのような型でも代入可能な変数が作られる。

$a = 1
$a = $b = $c = 1 #複数変数に一度に同じ値を代入する場合
$items = Get-ChildItem # コマンドレットの戻り値を格納 

変数の型を指定することは可能。以下のようにするとint型のみ格納可能な変数が作られる。

[int]$a = 1 

あるいは、コマンドレットを用いて$aという変数を宣言することもできる。この場合変数の型は指定できない。

New-Variable -name a 

変数のスコープ

# どのスコープからも読み書き可能
$global:a = 1

# 現在のスコープからのみ読み書き可能
$private:a = 1 

# 現在のスクリプトからのみ読み書き可能
$script:a = 1 

文法チェック

以下を実行することで未定義の変数を参照するとエラーが出るようになる。

Set-PSDebug -strict 

スクリプトの実行

デフォルトの実行ポリシーではスクリプトの実行は不許可であるため、以下のようにポリシーを変更しておく。(RemoteSignedはローカルにあるスクリプトファイルは無条件で実行可、リモートにあるスクリプトファイルは署名付きのもののみ実行可)

Set-ExecutionPolicy RemoteSigned 

スクリプト/コマンドを実行するにはコマンドラインで次のようにする。

コマンドを実行する

powershell -command {Get-ChildItem C:\} 

ファイルを実行する

powershell  .\script.ps1 

ドットソース(スクリプトの内容をグローバルスコープに読み込む)

powershell  . .\script.ps1 

ファイルを実行する(★2.0)

powershell -file script.ps1 

PowerShellスクリプトから別のスクリプトを実行する場合(関数のインクルードにも用いられる)

.\script.ps1
. .\script.ps1 # ドットソース 

デバッガの起動

Set-PSDebug -trace 2 

ステップ実行

Set-PSDebug -step 

2.数値

数値の表現

PowerShellにおける数値は.NET Frameworkの数値を表す構造体のインスタンスである。数値には整数、浮動小数点があり、変数に代入した段階で適切な型が設定される。

# int型(System.Int32型)
$int = 1

# System.Double型
$double = 1.001

四則演算

# 足し算
$i = 1 + 1

# 引き算
$i = 1 - 1 

# 掛け算
$i = 1 * 1 

# 割り算
$i = 1 / 1 

余りと商の求め方

# 割り算の余り
$mod = 7 % 3 

# 上記の場合の商
$div = (7 - 7 % 3) / 3 

べき乗

# 2の8乗
$i = [math]::Pow(2,8) 

インクリメントとデクリメント

# インクリメント
$i++ 

# デクリメント
$i-- 

3.文字列

PowerShellにおける文字列は.NET Frameworkの System.Stringクラスのインスタンスである。

文字列の表現

文字列はシングルクォーテーションかダブルクォーテーションで囲む。ダブルクォーテーションの中では`t(タブ)や`r`n(改行)などの特殊文字が使用でき、変数が展開される。

$str1 = 'abc'
$str2 = "def"
$str3 = "a`tbc`r`n" 

#変数展開(結果は abc def)
$str4 = "$str1 def" 

文字列操作

各種文字列操作

# 結合
$join1 = "aaa" + "bbb"
$join2 = [string]::Join(",",@("aaa","bbb","ccc") )

# 結合(★2.0)
$join2 = @("aaa","bbb","ccc") -join "," 

# 分割
$record1 = "aaa,bbb,ccc".Split(",") 

# 分割(★2.0)
$record2 = "aaa,bbb,ccc" -split "," 

# 長さ
$length = "abcdef".Length 

# 切り出し
$substr = "abcd".SubString(0,2) # ab

正規表現検索

# hitした場合はTrue,しなかった場合はFalse
$result = "abcd" -match "cd"

# 最初に見つかった文字列。添え字の1,2…には()内のサブ式にhitした文字列が格納。
$matches[0] 

正規表現置換

$result = "abc" -replace "c","d" 

4.配列

PowerShellにおける配列は.NET Frameworkの System.Arrayクラスのインスタンスである。

配列の参照と代入

# 5個の要素を持つ配列宣言と代入
$arr1 = @(1,3,5,7,9)
 
# 以下のようにも記述できる
$arr1 = 1,3,5,7,9 

# 型指定する場合
[int[]]$arr1 = @(1,3,5,7,9) 

# 1〜10までの要素を持つ配列宣言と代入
$arr2 = @(1..10) 

# 1要素の配列宣言と代入
$arr3 = @(1) 
$arr3 = ,1 

# 空の配列宣言と代入
$arr4 = @() 

配列の要素の参照と代入

# 4番目の要素を参照 
$ret = $arr2[3] 

# 6〜9番目の要素を含んだ配列を参照
$ret = $arr2[5..8] 

# 1〜4番目と8番目の要素を含んだ配列を参照
$ret = $arr2[0..3+7] 

# 配列の末尾の要素を取り出す
$ret = $arr2[-1] 

# 5番目の要素に値を代入
$arr2[4] = 11 

# 3より小さな要素を含んだ配列を返す
$ret = $arr2 -lt 3 

配列の個数

$arr1_num = $arr1.Length 

配列の操作

$arr1 = @(1,3,5,7,9) 
$arr2 = @(1..10) 

# 配列の末尾に要素を加える(push)
$arr2 += 50 

# 配列を結合し新しい配列を作成
$arr5 = $arr1 + $arr2 

# 配列にある要素が含まれるかどうか(ここではTrue)
$arr2 -contains 2 

5.ハッシュ

PowerShellにおけるハッシュは.NET Frameworkの System.Collections.Hashtableクラスのインスタンスである。

ハッシュ変数の宣言と代入

# 3つの要素を持つハッシュの宣言と代入
$hash1 = @{a=1;b=2;c=3}
 
# 空のハッシュの宣言と代入
$hash2 = @{} 

ハッシュの要素の参照と代入

# 要素の参照
$hash1.a 
$hash1["a"] 

#要素の代入
$hash1.b = 5
$hash1["b"] = 5 

ハッシュの操作

# ハッシュに要素を追加
$hash1.d = 4 
$hash1.Add("e",5)
 
# ハッシュの要素の削除
$hash1.Remove("a") 

# ハッシュのキーの取得
$keys = $hash1.Keys 

# ハッシュの値の取得
$values = $hash1.Values 

# ハッシュの要素を列挙
foreach ($key in $hash1.Keys)
{
    $key + ":" + $hash1[$key]
} 

# キーの存在確認
$hash1.Contains("b") 

6.制御文

if文

if (条件) {

}

if 〜 else文

if (条件) {

}
else{

}

if 〜 elsif 文

if (条件) {

}
elseif (条件) { 

} 

while/do文

while (条件) {

}

do {

} while (条件)

for文

for ($i = 0; $i -lt 5; $i++) {

} 

foreach文

foreach ($item in $items) {

} 

switch文

case を書かないのが特徴的。またスクリプトブロックを条件文に記述できる。

switch ($i) {
    1 {"1";break}
    2 {"2";break}
    {$_ -lt 5} {"5より小さい";break}
    default {"default句";break}
}
# ここで$iに配列を指定すると配列要素すべてに対してswitch文が実行される。 

比較演算子

比較演算子の一覧。PowerShellではPerlの文字列比較演算子のような記述をおこなうが、Perlとは異なり文字列も数値も同じ書式である。

$num1 -eq $num2 # $num1は$num2と等しい
$num1 -ne $num2 # $num1は$num2は等しくない
$num1 -lt $num2 # $num1は$num2より小さい
$num1 -gt $num2 # $num1は$num2より大きい
$num1 -le $num2 # $num1は$num2以下
$num1 -ge $num2 # $num1は$num2以上 

論理演算子

# 論理否定
$ret = -not $true
$ret = !$true

# 論理積
$ret = $true -and $false 

# 論理和
$ret = $true -or $false 

# 排他的論理和
$ret = $true -xor $false 

ビット演算子

# ビット単位の否定 $ret = -bnot 0x14F4 # ビット単位の積 $ret = 0x14F4 -band 0xFF00 # 上記結果を16進数で表示する場合 $ret = (0x14F4 -band 0xFF00).ToString("X") # ビット単位の和 $ret = 0x14F4 -bor 0xFF00 # ビット単位の排他的論理和 $ret = 0x14F4 -bxor 0xFF00

7.サブルーチン

PowerShellのサブルーチンには関数とフィルタがある。関数とフィルタは呼び出し行の前で宣言する必要がある。 filter構文もfunction構文と並んで独自関数を記述するものだが、filter構文はパイプラインに渡されたオブジェクトをフィルタするのに用いる。 functionとの違いは、パイプラインに渡した配列を一度に処理するか(function)個別に処理するか(filter)

# 関数宣言の基本
function Get-Test {
    return "test"
}
# 注:returnを付けなくても関数内で出力された値はすべて呼び出し元に返却される。返却したくない場合は出力値をを[void]にキャストするか|Out-Nullに渡す。

# 引数を指定する場合
function Get-Test {
    param($param1,$param2)
    return $param1 + $param2
}
 
# 引数を指定する場合の簡易的な記述法
function Get-Test($param1,$param2) {
    return $param1 + $param2
} 

# 引数の型を指定する場合
function Get-Test {
    param([string]$param1,[string]$param2)
    return $param1 + $param2
} 

# 関数の呼び出し方(,区切りではなくスペース区切りであることに注意)
Get-Test "引数1" "引数2"

# 引数の順序はパラメータ名(引数名)を指定すると自由に指定可能
Get-Test -param2 "引数2" -param1 "引数1" 

# フィルタ宣言の基本
filter Get-Odd {
    if($_ % 2 -eq 1){
        return $_ 
    }else{
        return
    }
} 

# フィルタの使用
@(1..10) | Get-Odd

8.テキストファイル入出力

コマンドレットで可能。エンコーディングは日本語環境のデフォルトではShift-JIS。コマンドレット出力のテキストファイルへの書き出しに関してはリダイレクトも可能。この場合エンコーディングはUnicode。

$str1 = "testテスト"
Set-Content test.txt $str1 # 書き込み
Add-Content test.txt "追記" # 追記
$str2 = Get-Content test.txt # 読み込み

Set-Content test.txt $str1 -encoding UTF8 # UTF-8で書き込み

# リダイレクト
Get-Process > test.txt # 書き込み
Get-Process >> test.txt # 追記
Get-Process | Out-File test.txt -encoding UTF8 # エンコーディングを指定する場合

9.例外

PowerShellで例外が発生すると、デフォルトではエラーメッセージを表示し次の行を実行する(シェル変数$ErrorActionPreferenceの設定により挙動の変更可能)。VBでいうとOn Error Resume Nextに近い。エラーが発生すると$Errorにエラー情報の配列が格納され、$?にFalseが格納される。エラーをトラップするには次の構文を使用する。VBでいうとOn Error Goto lineに近い。

# すべてのエラーをトラップ
trap {

}

# エラーの型名を指定してトラップ
trap [System.Management.Automation.CommandNotFoundException] {

} 

# エラーを発生させる
throw "エラー"
throw New-Object NullReferenceException 

構造化例外処理(★2.0)

# 基本
try{

}
catch{

}
finally{

} 

# エラーの型を指定してcatch
try{

}
catch [System.Net.WebException],[System.IO.IOException]{

}

10.知っておいたほうがよい文法

行継続文字

1行にすると長いコードを複数行に書くには行継続文字`を用いる。VBの_。

$items = Get-ChildItem a*,b*,c*,d*,e* `
-force -recurce 

ただし以下のような場合は`を使用しなくてもよい

$items =
    Get-ChildItem a*,b*,c*,d*,e* -force –recurse
    
Get-Process | 
    Where-Object {$_.handles -gt 500} |
    Select-Object -first 5 

ステートメント分割

ステートメントを分割するには改行コードもしくは;を使用する。VBの:。JavaScriptと同様、文末に;はつけてもつけなくてもよい。

$i = 1; $j = 5; $k = $i + $j 

ヒア文字列

複数行の文字列を記述する方法。

$str = @"
aaaaaa
bbbbb
cccc
ddd
ee
"@ 

.NET Frameworkクラスの利用

.NET Frameworkに含まれているクラスのプロパティやメソッドを使用できる。基本的に完全修飾名を指定しなければいけないが、"System."は省略可能。また、intなど型エイリアスがいくつか定義されている。

# スタティックメンバの使用
[System.Math]::Pow(2,8) 

# インスタンスの生成とメソッドの実行
$arrayList = New-Object System.Collections.ArrayList
$arrayList.Add("a") 

# コンストラクタがある場合。複数ある場合は配列として指定
$message = New-Object System.Net.Mail.Message from@example.com,to@example.com

# COMオブジェクトの生成
$wshShell = New-Object -com WScript.Shell 

# デフォルトで読み込まれていないアセンブリを読み込む
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("hello!") 

# クラスにどんなメンバがあるかの確認
# インスタンスメンバ
Get-ChildItem | Get-Member 

# スタティックメンバ
[math] | Get-Member -static 

キャスト

-asを使った場合はキャスト失敗時もエラーにならずNullが格納される。

$dt = [System.DateTime]"2010/02/13"
$dt = "2010/02/13" -as [System.DateTime] 

ユーザー定義オブジェクト

PowerShellにはクラスを定義する構文はないが、空のオブジェクト(PSObject)を生成し、任意のプロパティ(ノートプロパティ)を付加することができる。

$obj = New-Object PSObject
$property = New-Object System.Management.Automation.PSNoteProperty "Name","名前"
$obj.PSObject.Members.Add($property) 

シェル変数

あらかじめ定義されている変数。シェル変数には自動変数(変更不可能)とユーザー定義変数(変更すると挙動を変更することができる)がある。自動変数の例を挙げる。

$_ :現在パイプラインにわたっているオブジェクト
$args :関数やスクリプトに与えられたパラメータの配列
$pshome :PowerShellがインストールされているフォルダのフルパス
$MyInvocation :スクリプトの実行情報。$myInvocation.ScriptNameでスクリプトのフルパス取得(★2.0)。$myInvocation.MyCommand.Path(1.0の場合)
$true :true。
$false :false。
$null :null。

 

サブ式

$()内には複数行のコードが記述できる。

$arr = $(1;2;1+4)

式モードとコマンドモード

PowerShellの構文解析は式モードとコマンドモードがある。式モードは通常のモード。コマンドモードは引用符がなくても文字列を文字列として扱う。コマンドレットのパラメータなどはコマンドモードで扱われる。ただしコマンドモードになるところでも()もしくは$()もしくは@()をつけるとその中身は式モードとして解釈、実行される。

$i = 1 + 1 # 式モード
Write-Host aaa # コマンドモード(表示:aaa)
Write-Host aaa bbb # コマンドモード(表示:aaa bbb)
Write-Host 1+1 # コマンドモード(表示:1+1)
Write-Host (1+1) # 式モード(表示:2)
$itemCount = @(Get-ChildItem).Length # 式モード

実行演算子とスクリプトブロック

&演算子を用いるとスクリプトブロック{}の内容を実行できる。この場合、スクリプトブロック内のコードは別スコープになる。

$script = {$i = 1+6; Write-Host $i}
&$script
& 'C:\Program Files\Internet Explorer\iexplore.exe' # パスにスペースの含まれるファイルを実行したりするのにも使える

フォーマット演算子

-f演算子を使うと、.NET Frameworkのカスタム書式が使用可能。

"{0:#,##0}Bytes" -f 38731362 # 表示:38,731,362Bytes

バイト数の簡易表記

$i = 1KB # 1024が代入される
$i = 1MB # 1048576が代入される
$i = 1GB # 1073741824が代入される

そのほかの基礎文法最速マスターへのリンク

プログラミング基礎文法最速マスターまとめ - ネットサービス研究室
http://d.hatena.ne.jp/seikenn/20100203/programmingMaster

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/02/13/186034.aspx

2010/01/20

第 19 回 Admintech.jp 勉強会(2/6,東京)でPowerShell 2.0についてしゃべります。東京でPowerShell 2.0を話すのは初めてです。ご興味のある方はぜひお越しください!(前回、大阪でしゃべったのと同様の内容です)

他にも、最近猛威をふるっているガンブラーについてのセッションや、Hyper-Vのセッションもあります。皆様、ぜひぜひお誘い合わせのうえふるってご参加ください!

2/6は名古屋ではわんくま勉強会があり、ここでもPowerShellセッションがあります。なんと全国2箇所で同日にPowerShellセッションがあるというめずらしい日なのです。こちらもぜひどうぞ。

なお、むたぐちの今後の予定ですが、3/13名古屋わんくま勉強会でPowerShellネタをしゃべります。5/29大阪わんくま勉強会ではWindows デスクトップ/サイドバー ガジェットの話をやろうかなと思っています。全国展開です。よろしくどうぞ。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/01/20/185203.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

2010/01/01

あけましておめでとうございます!

ついに10年代の到来です。今まで以上にプログラミングもできるライターとして躍進していきたいですね。

読者のみなさま、わんくま同盟のみなさま、編集者のみなさま、お客様、どうぞよろしくお願いいたします。

2.0になって進化したPowerShellもよろしく!

元記事:http://blogs.wankuma.com/mutaguchi/archive/2010/01/01/184483.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/12/03

PowerShellには色々な演算子がありますが、その中のひとつに、ある文字列が正規表現にマッチするかどうかを判定する-match演算子というのがあります。使い方は、

"文字列" -match "正規表現"

です。たとえば、文字列にGUIDが含まれるかどうかを調べるには

"これはGUIDを含む文字列です。771d8236-9cc9-46d0-b78c-571746f81393とかね!" -match "[A-Fa-f0-9]{8}\-[A-Fa-f0-9]{4}\-[A-Fa-f0-9]{4}\-[A-Fa-f0-9]{4}\-[A-Fa-f0-9]{12}"

とすると、Trueと表示されます。

ちなみに、一度-match演算子を使うと$matchesというHashtable型のシェル変数に、マッチ情報が入ります。この場合、$matches[0]にGUIDが入ります。サブ式を定義してある場合、$matches[1],$matches[2]...にそれらの値が入ります。ただし$matchesには最初のマッチ情報しか入らないので複数のマッチがある場合はあまり使えないです。素直に

$regex=[regex]"a" 
$regex.Matches("aaa")|ForEach{$_.value}

とかしたほうがいいです。

ところで、-match演算子の左辺には実は配列も指定できます。たとえば、

 "aa1","aaa","2","b" -match "\d"

とすると、

aa1
2

と表示されます。\dは数字が含まれるという正規表現ですが、これを配列に対してかけると、True/Falseではなくマッチした配列要素を返します。これ、私知らなかったんです!なかなか便利だと思うのでぜひつかってみてください。なおこの場合$matchesには何も入りません。

元記事:http://blogs.wankuma.com/mutaguchi/archive/2009/12/03/183512.aspx

TwitterはRESTなAPIを備えているので、httpの通信ができれば基本的にどんな言語でもクライアントを作ることができるのがいいです。そこで私もPSTweetsというPowerShell版Twitterクライアントを作っているのですが、認証周りで問題が発生しています。

Twitterの認証には標準認証とOAuthが使えるのですが、現在はセキュリティ上の理由で標準認証は非推奨です。標準認証がなぜまずいかというと、マッシュアップサービスでTwitterに対して認証が必要な操作をする場合、ユーザーがその第三者のサービスにTwitterのIDとパスワードを送らなければならないためです。そのサービスがユーザーの認証情報を安全に保持してくれる保証はありません。

そこで考えられたのがOAuthという認証方法です。OAuthはとてもややこしいプロセスを含んでいますが、実質はそんなに難しいものではないです。要は、Twitterというサービス(これをサービスプロバイダという)にアクセスするための権限を、マッシュアップやクライアントを提供する第三者(これをコンシューマという)に委譲する仕組みです。ユーザーが「コンシューマを使いたい!」と思ったら、コンシューマは「じゃあついったーのページに飛ばしますから、あなたのアカウントを私が自由に使うことを許可してね」と言います。それでユーザーがTwitterのOAuth承認ページで「許可」すると、コンシューマはユーザーのアカウント情報を使ってTwitterのAPIを叩けるようになり、ユーザーはコンシューマにTwitterのパスワードを知らせることなくコンシューマの提供するサービスを利用することができるわけです。

さて、このOAuthをコンシューマが利用するには、Twitterにあらかじめ申請する必要があります。といっても登録ページでクライアント/サービス名などを入力するだけです。そうすると、コンシューマキーとコンシューマシークレットという文字列をもらえます。これはクライアントを特定するためのユーザー名とパスワードみたいなものです。ちなみにこの情報はコンシューマを提供する人のTwitterのユーザーアカウントに紐づいています。

コンシューマを通じてユーザーがTwitterのサービスを使うには、コンシューマを通じてTwitterからアクセストークンというものを貰う必要があります。このとき、コンシューマはTwitterに毎回コンシューマキーとコンシューマシークレットを送らなければなりません。

ここでコンシューマが独立したサーバーで運営されているサービスならば何も問題ありません。ユーザーがコンシューマキーとコンシューマシークレットを知る必要もユーザーに知られる危険性もありません。ところが、デスクトップクライアントだとどうなるかというと、コンシューマはデスクトップクライアントそのものです。なので、デスクトップクライアントはコンシューマキーとシークレットを何らかの方法で取得し、Twitterに送る機構が必要になります。

ここで、いくつかの方法があると思います。コンシューマキーとシークレットをデスクトップクライアントに暗号化して埋め込むのも一つの方法でしょう。ですが、結局は復号してTwitterに送らなければならないので、その通信をキャプチャすればユーザーは知ることができます。

なぜコンシューマキーとシークレットをユーザーに知られるとまずいかというと、それらを使うとまったく別のクライアントやサービスを、そのサービス名を詐称して作ることができてしまうからです。これがどうして問題なのかというと、そうなるとOAuthの承認が有名無実化してしまうためです。ユーザーがOAuthの承認ページで承認するサービスが本物かどうか調べるすべがありません。

メール登録制にしてコンシューマキーとシークレットを配布するとか考えましたが、なんだか大昔のシェアウェアのようで、なんとかシリアル集がはびこったように誰かが漏らしてしまう危険性を考えると難しいです。

コンシューマキーとシークレットを自分で取得してもらうというのも考えましたが、それはユーザーにとってかなり敷居が高いうえ、クライアント名がみんなバラバラになってしまいます(Twitterクライアント名はユニークであるため)。

コンシューマキーとシークレットを保持し、ユーザーからのリクエストに応じてアクセストークンを発行するサーバーを立てるというのも考えましたが、それってもうデスクトップTwitterクライアントじゃなくて、Twitterマッシュアップのデスクトップクライアントになってしまいます。

なので、デスクトップクライアントでOAuthを使うのは事実上無理なんじゃないかというのが私の結論です。

標準認証でもいいんですが、現在は標準認証は非推奨であり、そのため今からクライアントを作る場合は標準認証だとクライアント名をTwitterに登録することができなくなっています(タイムラインには「APIで」という表示になってしまう)。昔はメールでクライアント名を申請できたんですが、今はできません(この体制になる前に申請されたクライアントなら、今でも標準認証でもクライアント名を名乗れます)。これから作るクライアントで、クライアント名を名乗るにはOAuth必須です。ボット作者など、コンシューマ=ユーザーの場合はそれでもいいんですが…。これはぜひなんとか改善してもらいたいところですね。といっても、Twitter側からみると、それがコンシューマからのアクセスなのか、ユーザーからのアクセスなのか、区別をするのは難しいでしょうから、デスクトップアプリに限り標準認証でもクライアント名を名乗れるようにする、というのは難しいんじゃないかという気はします。

最近、新しいデスクトップクライアントがあまり登場せず、一方でやたらTwitterのマッシュアップサイトが増えたと思いませんか?中には、それデスクトップアプリでいいじゃないというものもちらほら。もしかして、この制限ができたためなんじゃないかと邪推までしています。うーむ、なんとかならないですかねー?

元記事:http://blogs.wankuma.com/mutaguchi/archive/2009/12/03/183506.aspx

次のページへ

Copyright © 2005-2009 Daisuke Mutaguchi All rights reserved

mailto: mutaguchi at roy.hi-ho.ne.jp