◆ コマンドプロンプトや bash の考えは捨てる
◆ devtools のコンソールや python, node, csi コマンドみたいなものとして考えるとわかりやすい

PowerShell って使い方がよくわからないしコマンドプロンプトのほうが使いやすいというスタイルでしたが あることに気づくとけっこう使いやすいものになりました

PowerShell ってコマンドプロンプトに近いもので Windows 10 ではコマンドプロンプトが PowerShell に置き換えられてます
さらに Shell という名前からも Linux などで使える bash や fish とかそういう系統のツールの仲間って感じがします
なので それらと同じようにプログラムの名前とそれに渡すオプションを書いたコマンドを実行するものって思っていました

しかし PowerShell はそういった Shell の仲間ではなくプログラミング言語の REPL です
JavaScript のコンソールとか C# の csi と同じものと思うと理解しやすくなります

.NET ということもあって csi がすごく近いです
わかりやすいのがこれ
四則演算とか文字列結合とかメソッド呼び出しが使えます

PS C:\Users\winuser> 1 + 3
4
PS C:\Users\winuser> 3 / 2
1.5
PS C:\Users\winuser> "foo" + "bar"
foobar
PS C:\Users\winuser> "abcd".SubString(2)
cd

これを見るだけで親近感が一気にわきました
コマンドプロンプトや bash みたいなものとして扱おうとしたので意味不明だったんです
.NET の新しいプログラミング言語の 1 つと考えるだけですごく印象が変わりました


変数も使えます
PHP みたいに $ を付ける必要がありますけど

PS C:\Users\winuser> $foo = 1
PS C:\Users\winuser> $bar = $foo * 10
PS C:\Users\winuser> $bar
10

パースの仕方が C# などに近いので bash みたいに = の前後でスペースいれるとダメみたいな制限はないです

文字列は "" と '' があって変数展開の有無が違います
これは bash ぽいですね

PS C:\Users\winuser> "[$bar]"
[10]
PS C:\Users\winuser> '[$bar]'
[$bar]

変数には大文字小文字の区別がありません

PS C:\Users\winuser> $BAR
10
PS C:\Users\winuser> $Bar
10

数値や文字列はリテラルで書けますが true/false/null はそのままリテラルでは書けません
$true や $false と言った変数に入ってるのでそれを使うことになります
true/false がリテラルじゃなくて最初から用意されてる変数を参照してるだけって何かの言語でみた気がするのですがなんだっけ……

PS C:\Users\winuser> $true
True
PS C:\Users\winuser> $false
False
PS C:\Users\winuser> $null

null は何も表示されません
空文字の場合は空行が出るので判別は可能です

$true を上書きしたらどうなるの?と思いましたが読み取り専用になっていました

PS C:\Users\winuser> $true = "a"
変数 true は読み取り専用または定数であるため、上書きできません。

ただ null は特殊で代入できるのに変化しないという挙動です
strict じゃない JavaScript でよく見るやつです

PS C:\Users\winuser> $null = 10
PS C:\Users\winuser> $null

また 初期化してない変数へのアクセスはエラーではなく null になっています

PS C:\Users\winuser> $UNDEFINED_VALUE
PS C:\Users\winuser> $UNDEFINED_VALUE -eq $null
True

if に使いそうな == や < や && はちょっと C# とは違います
-eq や -lt や -and になります

PS C:\Users\winuser> 3 -gt 2
True
PS C:\Users\winuser> -1 -gt 1
False
PS C:\Users\winuser> 3 -lt 2
False
PS C:\Users\winuser> -1 -lt 1
True
PS C:\Users\winuser> "a" -eq "a"
True
PS C:\Users\winuser> "0" -eq 0
True
PS C:\Users\winuser> $true -and $true
True
PS C:\Users\winuser> $true -and $false
False
PS C:\Users\winuser> $true -or $false
True
PS C:\Users\winuser> $false -or $false
False

boolean 値の反転はおなじみの ! でできます
if 文はこんな感じです

PS C:\Users\winuser> if ($true) { 1 } else { 2 }
1
PS C:\Users\winuser> if ($false) { 1 } else { 2 }
2

C# と違って 条件式のあとは複文の {} が必須です

さらに嬉しいことにこの if は式になっていて結果を代入できます

PS C:\Users\winuser> $a = if ($true) { 10 }
PS C:\Users\winuser> $a
10

関数呼び出しはメソッドなら C# と同じように .MethodName() 形式です
プロパティも同様に . とプロパティ名でアクセスできます
ここも大文字小文字の区別はありません

PS C:\Users\winuser> "abcd".Length
4
PS C:\Users\winuser> "abcd".EndsWith("d")
True
PS C:\Users\winuser> $true.GetType()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Boolean System.ValueType

PS C:\Users\winuser> 10L.gettype()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int64 System.ValueType

static 関数の場合は [] の中にクラス名を指定してその後で :: をつけてメソッド名を呼び出します

PS C:\Users\winuser> [Console]::WriteLine("text")
text
PS C:\Users\winuser> [Math]::Pow(2, 1024)
+∞
PS C:\Users\winuser> [Math]::Pow(2, 16)
65536
PS C:\Users\winuser> [String]::Empty -eq ""
True

new でオブジェクトを作りたいときは New-Object を使います
クラス名と引数をスペース区切りで書きます

PS C:\Users\winuser> New-Object DateTime

0001年1月1日 0:00:00


PS C:\Users\winuser> $uri = New-Object System.Uri "http://example.com/foo/bar.html"
PS C:\Users\winuser> $uri


AbsolutePath : /foo/bar.html
AbsoluteUri : http://example.com/foo/bar.html
Authority : example.com
Host : example.com
HostNameType : Dns
IsDefaultPort : True
IsFile : False
IsLoopback : False
IsUnc : False
LocalPath : /foo/bar.html
PathAndQuery : /foo/bar.html
Port : 80
Query :
Fragment :
Scheme : http
OriginalString : http://example.com/foo/bar.html
DnsSafeHost : example.com
IsAbsoluteUri : True
Segments : {/, foo/, bar.html}
UserEscaped : False
UserInfo :



PS C:\Users\winuser> $uri.Port
80
PS C:\Users\winuser> $uri.LocalPath
/foo/bar.html
PS C:\Users\winuser> $r = New-Object System.Random
PS C:\Users\winuser> $r.Next()
200661696
PS C:\Users\winuser> $r.Next()
1485192138
PS C:\Users\winuser> $r.Next()
886792691

ジェネリック型を使うときは [] で型を指定します

PS C:\Users\winuser> $nums = New-Object System.Collections.Generic.List[int]
PS C:\Users\winuser> $nums.Add(1)
PS C:\Users\winuser> $nums.Add(2)
PS C:\Users\winuser> $nums.Add(3)
PS C:\Users\winuser> $nums
1
2
3

New-Object のような機能はコマンドレットと呼ばれていて PowerShell には多くのコマンドレットが用意されています

時刻取得なら Get-Date です
結果の代入も可能です

PS C:\Users\winuser> get-date

2020年2月23日 22:37:02

PS C:\Users\winuser> $a = Get-Date
PS C:\Users\winuser> $a

2020年2月23日 22:37:52

ファイルの作成には New-Item です

PS C:\Users\winuser> new-item "test123.txt" -type file


ディレクトリ: C:\Users\winuser


Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2020/02/23 22:36 0 test123.txt

コマンドレットなどのコマンド一覧は get-command で見れます

PS C:\Users\winuser> Get-Command

CommandType Name Definition
----------- ---- ----------
Alias % ForEach-Object
Alias ? Where-Object
Function A: Set-Location A:
Alias ac Add-Content
Cmdlet Add-Computer Add-Computer [-DomainName] <String> [-Credential...
Cmdlet Add-Content Add-Content [-Path] <String[]> [-Value] <Object[...
Cmdlet Add-History Add-History [[-InputObject] <PSObject[]>] [-Pass...
Cmdlet Add-Member Add-Member [-MemberType] <PSMemberTypes> [-Name]...
Cmdlet Add-PSSnapin Add-PSSnapin [-Name] <String[]> [-PassThru] [-Ve...
Cmdlet Add-Type Add-Type [-TypeDefinition] <String> [-Language <...
Alias asnp Add-PSSnapIn
Function B: Set-Location B:
Function C: Set-Location C:
Alias cat Get-Content
Alias cd Set-Location
Function cd.. Set-Location ..
Function cd\ Set-Location \
Alias chdir Set-Location
(略)

Alias, Function, Cmdlet があります
コマンドプロンプトと同じように cd でディレクトリを移動できますが これはエイリアスで cd を使うと Set-Location コマンドレットを実行しています

同じように dir や ls では Get-ChildItem コマンドレットが実行されています

PS C:\Users\winuser> get-command dir,ls

CommandType Name Definition
----------- ---- ----------
Alias dir Get-ChildItem
Alias ls Get-ChildItem


Get-Help を使えばコマンドレットの使い方の表示ができます

PS C:\Users\winuser> get-help set-location

名前
Set-Location

概要
現在の作業場所を、指定された場所に設定します。


構文
Set-Location [-LiteralPath] <string> [-PassThru] [-UseTransaction] [<CommonParameters>]

Set-Location [[-Path] <string>] [-PassThru] [-UseTransaction] [<CommonParameters>]

Set-Location [-StackName <string>] [-PassThru] [-UseTransaction] [<CommonParameters>]
(略)

他にも関数やクラスを定義したり パイプを使ったり C# で作った dll をロードしたり色々できるのですが この辺までにしておきます
用途的に C# でするような複雑なことはしないと思いますし 変数の扱いや関数・メソッドの呼び出しがわかれば十分かもしれません
せっかく .NET なので複雑なことをしたいなら無理に PowerShell で頑張るよりも使い慣れた C# で書いてその関数を呼び出すだけってこともできますし

C# と連携を考えてると使えるのは .NET Framework だけで .NET Core で作った dll はダメなのかなって思いましたが最近は PowerShell も .NET Core 版が出てたのでした
https://github.com/PowerShell/PowerShell

しかもこっちに移行で古い方はもう更新されないとか
コマンドプロンプトから PowerShell メインに移るのならこっちを入れておいたほうがいいかもしれませんね
Core のほうはバージョン 7 が rc3 まででてるので 7 のリリースが近そうです
それに対して Windows7 の標準のものは 2.0 なのでかなり差があります