1. 文字コード
2018年現在、PowerShell Coreが登場してPowerShellはクロスプラットフォームなアプリケーションとなっているが、元々はWindowsの.NET Framework上で動作するアプリケーションだった。
このためPowerShellで取り扱える文字コードは.NET FrameworkおよびWindowsの影響を大きく受けている。
リダイレクト演算子やファイル操作に関わるコマンドレットの既定のエンコーディングがBOM付きUTF-16であることやUTF-8がBOM付きなのは、基本的には.NET Frameworkにおけるエンコーディングがそうである影響。
また、非英語圏におけるエンコーディングは俗にANSIエンコーディングとも呼ばれ、OSのロケール設定に依存し日本語環境であればSHIFT-JIS(CP932)。
PowerShellではコンソール上で扱える文字種に影響を及ぼしている。SHIFT-JISではないしBOM無しUTF-8でもないことに注意すべき。
2. -Pathパラメーターにおけるワイルドカード
PowerShellはコマンドプロンプトからの影響を受け、パラメーターに*、?、[、]の4種の文字をワイルドカードとして使用できる。
それぞれ、 となっている。
各コマンドレットがワイルドカード検索に対応するかどうかは一応任意なのだが、開発ガイドラインとしては となっており、Microsoft製のコマンドレットであれば-Name、-Pathパラメーターはほぼ100%ワイルドカード検索をサポートしている。
ここで-Pathパラメーターが大問題で、Windowsの仕様では[、]がディレクトリ・ファイル名として使用可能。
またディレクトリ・ファイルを扱うコマンドレットにおいて-Pathパラメーターが既定となっており、例えば
mkdir .\[Test]cd[Test]
なんてことをすると、ディレクトリ名にある[.]を正しく認識できずエラーになってしまう。
(ワイルドカードとして扱われてしまう)
f:id:stknohg:20180531205356p:plain
この場合は
cd -LiteralPath[test]
の様に-LiteralPathを使うか
cd'.\`[Test`]\'
の様にワイルドカード文字をエスケープする必要がある。
f:id:stknohg:20180531205723p:plain
この点に関しては、
ディレクトリ・ファイルを扱うコマンドレットでは原則 -LiteralPath パラメーターを使う。
3. 配列の平坦化 (パイプライン文)
PowerShellではコマンドレットなどの実行結果を変数に代入する際、実行結果のオブジェクトが複数ある場合はオブジェクトの配列(Object[])として扱われ、単一のオブジェクトの場合は配列ではなくそのオブジェクト自身を取得する。
挙動だけ見ると配列を期待した処理に対して平坦化が行われている様に見え、非常に直感的でない挙動に感じてしまう。
この挙動はパイプライン文(Pipeline statements)と呼ばれるPowerShell独自の構文に依るもの。
パイプライン文は名前の通りパイプライン(|)を扱うために用意された文なのだが、PowerShellのパイプラインは.NET Frameworkのオブジェクトを扱うオブジェクトパイプラインであり、他のシェルのそれとは完全に異質のもの。
わかりやすい表現をすると、これは厳密には間違っているのだが、PowerShellにおいてコマンドレットなどの実行結果は最終的にパイプライン文に行きつき、このパイプライン文は評価されたオブジェクトを一つずつストリーム(他のシェルの標準出力に近いもの)に放流する動作をする。
ストリームに放流されたオブジェクトはパイプライン演算子(|)でパイプすることができる。
放流されたオブジェクトは、途中で代入やパイプされなかった場合は最終的にPowerShell内部で| Out-Defaultと暗黙的にパイプされコンソールにその結果を表示する様になっている。
オブジェクトの取得(代入)はストリームに放流されたオブジェクトを途中で浚うイメージ。
(あくまでイメージであり正確な動作ではない)
浚ったオブジェクトが単一であればそのまま扱い、複数個あれば配列(Object[])になる配列化が実際の挙動に近く、このため、必ず配列が欲しいといった場合は配列部分式演算子(@())などによる明示的なキャストが必要になる。
ただ、パイプライン文やストリームといったものがあることを認識するだけでもPowerShellに対する理解はかなり変わると思う。
4. 配列に対する-eq演算子 配列に対して-eq演算子はフィルターとして動作する。
これを回避するには
if ($null -eq$array) {# do something}
の様にヨーダ記法にする必要がある。

PowerShellで、いわゆる三項演算子いうところの条件演算子を書きたい、と思ったところで、そもそもif文が値を返すことに気づく。
しかし、if は文であって式でない。代入文の右辺には文が置けるので上記は問題ないが、当然、式を置くべきところに文は置けない。
ではどうするか。文を括って式にすればよく、それには部分式演算子$() が使える。
すなわち、PowerShellにおける三項条件演算子は、if を$() で括った$(if (bool) { expr1 } else { expr2 }) の形をとる。目標は達せられた。 inserted by FC2 system