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

# 対象

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

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

## コマンドレットとは

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

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

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

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

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

## 実行ポリシー

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

* Restricted
* AllSigned
* RemoteSigned
* Unrestricted

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

```
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```

※ 追記: ~~下でコメントしてくださっているように、スコープをきちんと限定してやるのがより適切だと思われます。また、実行ポリシーについて詳しく載った記事もそのコメントで紹介していただいているのでご参考ください。~~
※ 2019/10/22 更新: コメント頂いたものに上記のコマンドを修正しました。 @nukie_53 さんありがとうございます。実行ポリシーについて詳しく知りたい場合は、下のコメントの記事などご参照ください。

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

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

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

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

### grep
　**`grep`はありません！！** 代わりに`Select-String`というコマンドレットがあってそれを使うことでほぼ代替可能のようです。ファイルからの検索では、かなり便利に使えるようです(参考: [grepコマンドとPowerShellのsls (Select-String)の比較](http://tech.sanwasystem.com/entry/2016/07/05/185717))。しかし、パイプを通してひとつ前の結果を加工するケースで使う場合には、`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`などあります。[このページ](https://qiita.com/cd01/items/da9a36582372e7d0a7f6)はクックブック的で便利だと思います。

# まとめ

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

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