PowerShell

Windows使うことになったので、PowerShellが使えるようになりたい

対象

  • bashやらzshやらは使ったことある人
  • PowerShell初心者
  • PowerShellを毎回ググって使ってる人

ググる回数を減らすための基本

コマンドレットとは

 コマンドレットとは、シェルでいうコマンドに似た概念です。名前の問題はどうでもよいのですが、一つだけわかっておいた方がよいことは、

  • Do-Somethingの形式になっている

という点です。例えば、設定されているエイリアスを確認したい場合には、Get-Aliasと打てばその一覧が表示されますし、逆にエイリアスを設定したい場合にはSet-Alias show Get-ChildItemと打つことでshowというエイリアスを作ることができます。この場合、SetDo(=セットする、変数に代入する)にあたり、AliasSomething(=エイリアスを)ということになります。このことを認識しておくと、何かの一覧を取得するためのコマンドレットがわからなくても、Get-Somethingの形になることが予想されるなど、コマンドレットを思い出す/探す際のきっかけになります。

 また、大文字と小文字を区別しないことも一応確認しておいた方がよいかもしれません。コマンドレットはコマンドに比べて長いので、実践的には適当に小文字で入力してタブ補完をするかエイリアスをきちんと貼っていくことになると思われます。

※ 以下ではコマンドレットをあえてエイリアスを使わずに紹介していますが、実際には、Where-Object -> ?など便利で短くかけるようになっているので「PowerShellは長い!」って言ってあげないでください。。。

実行ポリシー

 有名な話かもしれませんが、PowerShellは実行ポリシーを適切に設定しないと自分で書いたスクリプトですら実行できなくて残念な気持ちになることになります。実行ポリシーには次の4つがあり、デフォルトでは、一番厳しいRestrictedになっています。

  • Restricted
  • AllSigned
  • RemoteSigned
  • Unrestricted

「とりあえずローカルにある自分のスクリプトが動けばOK」のケースが多いと思うので、RemoteSignedにしておけば十分かと思われます。管理者権限でPowerShellを起動して以下を実行でスクリプトの実行ができるようになります。

Set-ExecutionPolicy RemoteSigned

※ 追記: 下でコメントしてくださっているように、スコープをきちんと限定してやるのがより適切だと思われます。また、実行ポリシーについて詳しく載った記事もそのコメントで紹介していただいているのでご参考ください。

コマンドレットはオブジェクトをパイプする

 Linuxなどでのシェルでは、文字列をパイプすることになっていたと思いますが、PowerShellではオブジェクトをパイプします。この辺が少し勝手が違うところになってくるわけですが、個人的にはこの点がとても好きです。なんかおしゃれな気がしてします。この辺りは下のgrepの項目で少し触れます。このポイントが一番大切かもしれません。

シェルでよく使ってたコマンドと同じ感じのコマンドレットを使いたい人へ

cd / ls

 cdlsもデフォルトでエイリアスが貼られているので同じような感覚で使えます。実際この辺は、このエイリアスを使っている人が多いのではないかと予想しています。ちなみにそれぞれ、cd -> Set-Location,ls -> Get-ChildItemになっています。

grep

 grepはありません!! 代わりにSelect-Stringというコマンドレットがあってそれを使うことでほぼ代替可能のようです。ファイルからの検索では、かなり便利に使えるようです(参考: grepコマンドとPowerShellのsls (Select-String)の比較)。しかし、パイプを通してひとつ前の結果を加工するケースで使う場合には、grep<=>Select-Stringの図式を持ち込まない方が良さそうです。例えば、「Select-Objectにデフォルトで貼られているエイリアスはないかな~?」と思って探す場合には、次のようなコマンドでその存在を確かめることができます。間に挟まっているOut-Stringはパイプされてきたオブジェクトを文字列にするために入れる必要があります。

Get-Alias | Out-String -Stream |Select-String ".*Select.*"

 実はもっとPowerShellらしい方法があって、

Get-Alias | Where-Object {$_.Name -like "*Select*"}

とすることで見つけることができます。これは、Get-Aliasが返すオブジェクトのNameプロパティに検索をかけていることになります。このあたりは、「オブジェクトを渡すパイプ」を活用している感じがします。
 しかし、これはこれで「Nameなんてどこから知ることができるの?」ってなってしまいそうです。実は、PowerShellは実行結果のところにこのプロパティの名前が表示されています。例えば、Get-Aliasと打つと、

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           % -> ForEach-Object
Alias           ? -> Where-Object
Alias           ac -> Add-Content
Alias           asnp -> Add-PSSnapin
Alias           cat -> Get-Content
Alias           cd -> Set-Location
Alias           CFS -> ConvertFrom-String                          3.1.0.0    Microsoft.PowerShell.Utility
Alias           chdir -> Set-Location
Alias           clc -> Clear-Content
Alias           clear -> Clear-Host
Alias           clhy -> Clear-History
.
.

と表示されます。これがちょうど、ヘッダーがプロパティ名となったテーブルのような形になっています。このことは、きちんと覚えていくと使いやすくなってくると思います。
 さらに、パイプで渡されてくるプロパティの名前などをすべて知りたいときには、Get-Memberというコマンドレットが便利で

PS > Get-Alias | Get-Member

   TypeName: System.Management.Automation.AliasInfo

Name                MemberType     Definition
----                ----------     ----------
Equals              Method         bool Equals(System.Object obj)
GetHashCode         Method         int GetHashCode()
GetType             Method         type GetType()
ResolveParameter    Method         System.Management.Automation.ParameterMetadata ResolveParameter(string
ToString            Method         string ToString()
CommandType         Property       System.Management.Automation.CommandTypes CommandType {get;}
Definition          Property       string Definition {get;}
Description         Property       string Description {get;set;}
Module              Property       psmoduleinfo Module {get;}
ModuleName          Property       string ModuleName {get;}
Name                Property       string Name {get;}
Options             Property       System.Management.Automation.ScopedItemOptions Options {get;set;}
OutputType          Property       System.Collections.ObjectModel.ReadOnlyCollection[System.Management.Aut
Parameters          Property       System.Collections.Generic.Dictionary[string,System.Management.Automati
ParameterSets       Property       System.Collections.ObjectModel.ReadOnlyCollection[System.Management.Aut
ReferencedCommand   Property       System.Management.Automation.CommandInfo ReferencedCommand {get;}
RemotingCapability  Property       System.Management.Automation.RemotingCapability RemotingCapability {get
ResolvedCommand     Property       System.Management.Automation.CommandInfo ResolvedCommand {get;}
Source              Property       string Source {get;}
Version             Property       version Version {get;}
Visibility          Property       System.Management.Automation.SessionStateEntryVisibility Visibility {ge
DisplayName         ScriptProperty System.Object DisplayName {get=if ($this.Name.IndexOf('-') -lt 0)...
HelpUri             ScriptProperty System.Object HelpUri {get=$oldProgressPreference = $ProgressPreference
ResolvedCommandName ScriptProperty System.Object ResolvedCommandName {get=$this.ResolvedCommand.Name;}

と表示され、メソッドなどと一緒にすべてのプロパティを確認することができます。

その他

 ps -> Get-Processなどあります。このページはクックブック的で便利だと思います。

まとめ

 上記をまとめると次のようになるかと思います。「とにかくコマンドレットを覚えよう」とするよりも幾分か見通しがよくなるのではないかと思います。

  • コマンドレットはDo-Somethingの形
  • PowerShellのパイプはオブジェクトを渡す
  • 結果表示は、プロパティがヘッダーになっているテーブルになっている
  • パイプを受け取るgrepには、Select-Stringが対応しないこともある