PowerShell Core 6 の入門メモ

# 概要

PowerShell CoreはOSSのコマンドラインシェルおよびスクリプト言語で、WindowsにインストールされているWindows PowerShellとは別エディションのソフトウェアです。

**主な特徴**

* ランタイムに[.NET Core] (https://docs.microsoft.com/ja-jp/dotnet/core/)を採用。(Windows PowerShellは.NET Framework)
* オープンソース。(ソースコードは[PowerShell/PowerShell] (https://github.com/PowerShell/PowerShell)にあります)
* Microsoftモダンライフサイクルポリシーを採用。([PowerShell Core のサポート ライフサイクル] (https://docs.microsoft.com/ja-jp/powershell/scripting/powershell-support-lifecycle?view=powershell-6))
* オブジェクト指向、コマンドの出力はオブジェクトでパイプライン経由で別のコマンドの入力として送信できます。
* クロスプラットフォーム。(Windows、macOS、Linuxのプラットフォームをサポート、(6.0より))
* デフォルトのエンコードはUTF-8。(一部例外あり(6.0より))

2019年9月現在でバージョン6.2.2がリリース、2020年3月5日にバージョン7.0.0 ~~はプレビュー版~~ がリリースされています。

**この記事**

この記事はPowerShell Coreの新機能を調べたものではなく、いままでWindows PowerShell / PowerShell Coreを使ったことがなかった人間がPowerShell Coreの特徴、使い方の基本を調べたことのメモです。なおWindows PowerShellと重なる部分が多くありますがご了承ください。

**環境**

下記の環境で動作確認を行いました。

* Windows 10 Professional 1903
* PowerShell Core 6.2.2

**参考**

* [PowerShell ドキュメント - PowerShell | MicrosoftDocs] (https://docs.microsoft.com/ja-jp/powershell/)
* [PowerShell スクリプト - PowerShell | MicrosoftDocs] (https://docs.microsoft.com/ja-jp/powershell/scripting/overview?view=powershell-6)
* [PowerShell Core 6.0 の新機能 - PowerShell | MicrosoftDocs] (https://docs.microsoft.com/ja-jp/powershell/scripting/whats-new/what-s-new-in-powershell-core-60?view=powershell-6)
* [Installing various versions of PowerShell] (https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-6)

# PowerShell Coreの初歩

## コマンドレット (cmdlet)

PowerShell Coreのネイティブコマンド(または組み込みコマンドとも)をコマンドレット(cmdlet)と呼びます。コマンドレットは`動詞(Verb)-名詞(Noun)`という命名体系を用いています。例えばシステム日付を取得するコマンドレットは`Get-Date`です。

### コマンドレットの種類を調べる

PowerShell Coreで使用できるコマンドレットの種類は`Get-Commnad`で調べることができます。

```powershell
PS > Get-Command -CommandType Cmdlet

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AppxPackage                                    2.0.1.0    Appx
Cmdlet          Add-AppxProvisionedPackage                         3.0        Dism
Cmdlet          Add-AppxVolume                                     2.0.1.0    Appx
Cmdlet          Add-Content                                        6.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Add-History                                        6.2.2.0    Microsoft.PowerShell.Core
Cmdlet          Add-LocalGroupMember                               1.0.0.0    Microsoft.PowerShell.LocalAccounts
Cmdlet          Add-Member                                         6.1.0.0    Microsoft.PowerShell.Utility
Cmdlet          Add-Type                                           6.1.0.0    Microsoft.PowerShell.Utility

# ... 省略 ...
```

PowerShell Coreはコマンドレットの他に、いくつかの種類のコマンドをサポートします。その種類はCommandTypeで判別でき、Alias、Application、Filter、Function、Script、ExternalScriptなどがあります。※（Alias、Application、Filter、Functionは後述します）

#### 条件を指定して調べる

**コマンドの種類を指定**

`-CommandType`オプションでコマンドの種類を指定します。この例はApplicationだけを出力します。

```powershell
PS > Get-Command -CommandType Application
```

**動詞(Verb)を指定**

`-Verb`オプションで動詞を指定します。この例は`Get-*`というコマンドを出力します。

```powershell
PS > Get-Command -Verb Get
```

**名詞(Noun)で指定**

`-Noun`オプションで名詞を指定します。この例は`*-Content`というコマンドを出力します。

```powershell
PS > Get-Command -Noun Content
```

### コマンドレットの使い方を調べる

`Get-Help`でコマンドレットの使い方を調べることができます。

```powershell
PS > Get-Help Get-Random
```

詳細な情報を知るには`-Full`オプションを付けます。

```powershell
PS > Get-Help Get-Random -Full
```

`-Online`オプションを付けるとHTMLページで確認できます。

```powershell
PS > Get-Help Get-Random -Online
```

それぞれのコマンドレットでも`-?`オプションで調べることができます。

```powershell
PS > Get-Random -?
```

### Get-Helpのエイリアス

`Get-Help`にエイリアスは付けられていませんが、`help`および`man`というコマンドが用意されています。（`help`はFunctionで`man`は`help`のエイリアスです。）

```powershell
PS > help Get-Random
```

## コマンドレットの出力はオブジェクト

※出力のないコマンドレットもあります。

### 例1) Get-Date

システム日付を取得する`Get-Date`を実行するとコンソール上にシステム日付が出力されますが、実際には`Get-Date`の戻り値は`DateTime`型のオブジェクトです。

```powershell
PS > Get-Date
2019年9月8日 12:54:58
```

戻り値を変数に格納しGetTypeメソッドでオブジェクトの型を確認します。（ここでは分かりやすく変数に代入していますが代入しなくても確認できます）
下記の通り$now変数のオブジェクトの型は[DateTime] (https://docs.microsoft.com/ja-jp/dotnet/api/system.datetime?view=netcore-2.0)であることが分かります。

```powershell
PS > $now = Get-Date
PS > $now.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     DateTime                                 System.ValueType
```

下記の例で分かる通りDateTime型はYear、Month、Dayなどのプロパティ、ToString、AddDaysなどのメソッドを持っています。

```powershell
PS > $now.Year
2019
PS > $now.Month
9
PS > $now.Day
8
PS > $now.ToString("yyyy-MM-dd")
2019-09-08
PS > $tomorrow = $now.AddDays(1)
PS > $tomorrow.ToString("yyyy-MM-dd")
2019-09-09
```

オブジェクトがどのようなメンバー（プロパティ、メソッド）を持っているか調べるには`Get-Member`を使用します。
ちなみに記号の縦線(`|` バーチカルライン)は、パイプ演算子といいコマンドレットの出力を次のコマンドレットの入力とします。

```powershell
PS > $now | Get-Member

   TypeName: System.DateTime
Name                 MemberType     Definition
----                 ----------     ----------
Add                  Method         datetime Add(timespan value)
AddDays              Method         datetime AddDays(double value)
AddHours             Method         datetime AddHours(double value)
AddMilliseconds      Method         datetime AddMilliseconds(double value)
AddMinutes           Method         datetime AddMinutes(double value)
AddMonths            Method         datetime AddMonths(int months)
AddSeconds           Method         datetime AddSeconds(double value)
AddTicks             Method         datetime AddTicks(long value)
AddYears             Method         datetime AddYears(int value)
CompareTo            Method         int CompareTo(System.Object value), int CompareTo(datetime value), int IComparable.CompareTo(System.Object obj), int IComparable[datetime].CompareTo(datetime other)
Equals               Method         bool Equals(System.Object value), bool Equals(datetime value), bool IEquatable[datetime].Equals(datetime other)
GetDateTimeFormats   Method         string[] GetDateTimeFormats(), string[] GetDateTimeFormats(System.IFormatProvider provider), string[] GetDateTimeFormats(char format), string[] GetDateTimeFormats(char format, System.IForm…
GetHashCode          Method         int GetHashCode()
GetObjectData        Method         void ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
GetType              Method         type GetType()
GetTypeCode          Method         System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTypeCode()
IsDaylightSavingTime Method         bool IsDaylightSavingTime()
Subtract             Method         timespan Subtract(datetime value), datetime Subtract(timespan value)
ToBinary             Method         long ToBinary()
ToBoolean            Method         bool IConvertible.ToBoolean(System.IFormatProvider provider)
ToByte               Method         byte IConvertible.ToByte(System.IFormatProvider provider)
ToChar               Method         char IConvertible.ToChar(System.IFormatProvider provider)
ToDateTime           Method         datetime IConvertible.ToDateTime(System.IFormatProvider provider)
ToDecimal            Method         decimal IConvertible.ToDecimal(System.IFormatProvider provider)
ToDouble             Method         double IConvertible.ToDouble(System.IFormatProvider provider)
ToFileTime           Method         long ToFileTime()
ToFileTimeUtc        Method         long ToFileTimeUtc()
ToInt16              Method         short IConvertible.ToInt16(System.IFormatProvider provider)
ToInt32              Method         int IConvertible.ToInt32(System.IFormatProvider provider)
ToInt64              Method         long IConvertible.ToInt64(System.IFormatProvider provider)
ToLocalTime          Method         datetime ToLocalTime()
ToLongDateString     Method         string ToLongDateString()
ToLongTimeString     Method         string ToLongTimeString()
ToOADate             Method         double ToOADate()
ToSByte              Method         sbyte IConvertible.ToSByte(System.IFormatProvider provider)
ToShortDateString    Method         string ToShortDateString()
ToShortTimeString    Method         string ToShortTimeString()
ToSingle             Method         float IConvertible.ToSingle(System.IFormatProvider provider)
ToString             Method         string ToString(), string ToString(string format), string ToString(System.IFormatProvider provider), string ToString(string format, System.IFormatProvider provider), string IFormattable.To…
ToType               Method         System.Object IConvertible.ToType(type conversionType, System.IFormatProvider provider)
ToUInt16             Method         ushort IConvertible.ToUInt16(System.IFormatProvider provider)
ToUInt32             Method         uint IConvertible.ToUInt32(System.IFormatProvider provider)
ToUInt64             Method         ulong IConvertible.ToUInt64(System.IFormatProvider provider)
ToUniversalTime      Method         datetime ToUniversalTime()
TryFormat            Method         bool TryFormat(System.Span[char] destination, [ref] int charsWritten, System.ReadOnlySpan[char] format, System.IFormatProvider provider)
DisplayHint          NoteProperty   DisplayHintType DisplayHint=DateTime
Date                 Property       datetime Date {get;}
Day                  Property       int Day {get;}
DayOfWeek            Property       System.DayOfWeek DayOfWeek {get;}
DayOfYear            Property       int DayOfYear {get;}
Hour                 Property       int Hour {get;}
Kind                 Property       System.DateTimeKind Kind {get;}
Millisecond          Property       int Millisecond {get;}
Minute               Property       int Minute {get;}
Month                Property       int Month {get;}
Second               Property       int Second {get;}
Ticks                Property       long Ticks {get;}
TimeOfDay            Property       timespan TimeOfDay {get;}
Year                 Property       int Year {get;}
DateTime             ScriptProperty System.Object DateTime {get=if ((& { Set-StrictMode -Version 1; $this.DisplayHint }) -ieq  "Date")…
```

MemberTypeの種類は、[PSMemberTypes Enum] (https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.psmembertypes?redirectedfrom=MSDN&view=pscore-6.2.0)で確認できます。

#### 配列の場合

配列自体のメンバー（メソッドやプロパティ）を取得したい場合、下記の方法だと配列のメンバーは取得できません。（配列の各要素のメンバーが表示される）

```powershell
PS > $array = @("abc", 123, $true)
PS > $array | Get-Member
```

方法は2つあり、1つ目は配列名の前にカンマを付ける方法、2つ目は`Get-Member`の`-InputObject`オプションを使う方法です。

```powershell
PS > ,$array | Get-Member
PS > Get-Member -InputObject $array
```

### 例2) Get-Location

現在のパスの情報を取得するには`Get-Location`を使用します。`Get-Location`の出力は`PathInfo`型のオブジェクトです。

```powershell
PS > Get-Location

Path
----
C:\Users\User

PS > Get-Location | Get-Member

   TypeName: System.Management.Automation.PathInfo
Name         MemberType Definition
----         ---------- ----------
Equals       Method     bool Equals(System.Object obj)
GetHashCode  Method     int GetHashCode()
GetType      Method     type GetType()
ToString     Method     string ToString()
Drive        Property   System.Management.Automation.PSDriveInfo Drive {get;}
Path         Property   string Path {get;}
Provider     Property   System.Management.Automation.ProviderInfo Provider {get;}
ProviderPath Property   string ProviderPath {get;}
```

コマンドレットを`( )`で囲むことでオブジェクトのメソッドやプロパティにアクセスできます。

```powershell
PS > (Get-Location).Path
C:\Users\User
PS > (Get-Location).Drive

Name           Used (GB)     Free (GB) Provider      Root                                                                                                                                                           CurrentLocation
----           ---------     --------- --------      ----                                                                                                                                                           ---------------
C                  85.77        510.40 FileSystem    C:\

```

#### Get-Locationのエイリアス

`Get-Location`はコマンドプロンプトの`pwd`と同じ機能を果たすので`pwd`というエイリアスが付けれられています。
コマンドレットにエイリアスが付けられているかどうかを確認するには`Get-Alias`を使用します。`-Definition`にコマンドレット名を指定するとそのコマンドレットに付けられたエイリアスを調べることができます。

```powershell
PS > Get-Alias -Definition Get-Location

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           gl -> Get-Location
Alias           pwd -> Get-Location
```

### 例3) Set-Location

現在のパスを設定するには`Set-Location`を使用します。`Set-Location`はデフォルトでは出力しません。
また、コマンドプロンプトの`cd`コマンドと同じ機能を果たすので`cd`というエイリアスが設定されています。

```powershell
PS > Get-Location

Path
----
C:\Users\User

PS > Set-Location temp
PS > Get-Location

Path
----
C:\Users\User\temp
```

#### Set-Locationの出力

オプションに`-PassThru`を付けると`Set-Location`は設定後の`PathInfo`型のオブジェクトを返します。

```powershell
PS > Set-Location temp -PassThru

Path
----
C:\Users\User\temp
```

## エイリアス (Alias)

コマンドレットにエイリアス(代替名)を付けることができます。デフォルトでよく使うコマンドレットにはエイリアスが設定されていて`Get-Alias`で確認できます。

```powershell
PS > Get-Alias

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           % -> ForEach-Object
Alias           ? -> Where-Object
Alias           ac -> Add-Content
Alias           cat -> Get-Content
Alias           cd -> Set-Location

# ... 省略 ...
```

### エイリアスを付ける

ユーザーが新しくエイリアスを付けるには`Set-Alias`を使用します。
たとえばシステム日付を取得する`Get-Date`を`now`として実行したい場合は、下記のコマンドでエイリアスを付けます。

```powershell
PS > Set-Alias -Name now -Value Get-Date
```

## アプリケーション (Application)

アプリケーションは環境変数Pathで検索できる実行可能ファイル(\*.exe、\*.cmd、\*.bat、\*.vbsなど)です。
なので実行環境によって内容は大きく変わります。

```powershell
PS > Get-Command -CommandType Application
```

プロセス一覧を表示するtasklist.exeもApplicationとして登録されています。

```powershell
PS > Get-Command tasklist

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Application     tasklist.exe                                       10.0.1836… C:\Windows\system32\tasklist.exe
```

OSにインストールしたアプリケーションもPathが通っていればApplicationとして認識されます。

```powershell
PS > Get-Command code

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Application     code.cmd                                           0.0.0.0    C:\Program Files\Microsoft VS Code\bin\code.cmd
```

## 関数 (Function)

* 参考 : [About Functions] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions?view=powershell-6)

関数は0個以上のPowerShell Coreコマンドのリストです。

```powershell
Function Get-Hello([string]$message = "World") {
  $culture = Get-Culture
  Write-Host $culture.TextInfo.ToTitleCase("Hello $message".ToLower())
}
```

```powershell
PS > Get-Hello
Hello World
PS > Get-Hello -Message "ruby tomato"
Hello Ruby Tomato
PS > Get-Hello "RUBY TOMATO"
Hello Ruby Tomato
```

## フィルター (Filter)

フィルターはパイプラインの各オブジェクトに対して実行される関数の一種です。フィルターの入力は`$_`変数です。

```powershell
Filter Get-Chrome() {
  if ($_.ProcessName -eq "chrome") {
    $_
  }
}
```

この例は`Get-Process`の出力に対しProcessNameが"chrome"のデータを抽出するフィルターです。

```powershell
PS > Get-Process | Get-Chrome

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     81   176.61     277.19     531.66     916   1 chrome
     44    72.43     104.00      13.95    4528   1 chrome
     27    30.54      47.84       1.23    4616   1 chrome
     26    26.93      43.07       0.42    6000   1 chrome
     26    27.48      45.06       0.39    6728   1 chrome
    196   829.54     934.11   4,072.17    6748   1 chrome
     59    50.74     112.45   2,435.31    7528   1 chrome
     29    36.05      54.46     537.94    8764   1 chrome
     37    56.66      84.95       2.55    9004   1 chrome
     13     4.53       9.25       0.20    9928   1 chrome
     14     4.72      11.10       0.05   10760   1 chrome
     33    44.96      70.05       1.63   11212   1 chrome
     29    34.65      52.73       0.61   12224   1 chrome
     27    28.20      40.79       1.73   12296   1 chrome
     25    23.71      36.20       0.75   12320   1 chrome
     25    25.57      38.64       0.92   12344   1 chrome
     33    41.48      58.04      21.25   12424   1 chrome
     38    67.20      88.80       5.83   12800   1 chrome
     22    15.56      24.39       0.13   12820   1 chrome
     21     9.26      18.34      91.39   13036   1 chrome
     38    55.09      88.07       2.55   13352   1 chrome
     90   181.39     191.93     329.20   14328   1 chrome
     24    22.24      35.38       0.11   15352   1 chrome
     40    56.53      89.18       2.52   16376   1 chrome
```

## パラメータを付けたコマンドレットにエイリアスを付ける場合

たとえば任意の日付フォーマットで出力する`-Format`オプションを付けた`Get-Date`には直接エイリアスを付けることができません。

```powershell
PS > Get-Date -Format "yyyy-MM-dd HH:mm:ss(z)"
2019-09-08 12:50:55(+9)
PS > Set-Alias -Name now -Value Get-Date -Format "yyyy-MM-dd HH:mm:ss(z)"
Set-Alias : A parameter cannot be found that matches parameter name 'Format'.
```

この場合、コマンドレットを一旦Functionとして作成し

```powershell
Function Get-FormattedDate {Get-Date -Format "yyyy-MM-dd HH:mm:ss(z)"}
```

そのFunctionにエイリアスを付けます。

```powershell
PS > Set-Alias -Name now -Value Get-FormattedDate
PS > now
2019-09-08 12:51:47(+9)
```

## 変数

変数名は`$`記号で始まる英数字と特殊記号からなる文字列です。Windowsでは大文字と小文字は区別されません。半角スペースも含めることができますが使わないことが推奨されていて、英数字とアンダースコアだけを使うことがベストプラクティスとされています。

PowerShell Coreの変数にはユーザーが作成する変数の他に、PowerShell Coreが作成する自動変数(Automatic Variables)、設定変数(Preference Variables)、OSの環境変数(Environment Variables)があります。

### 変数の宣言

変数を宣言するときに変数の型は不要で、同じ変数に異なる型のオブジェクトを再代入することができます。

```powershell
PS > $x = 100
PS > echo "x = $x"
x = 100
PS > $x.GetType()

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

PS > $x = "abc"
PS > $x.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object
```

しかし変数の型を明示することもでき、この場合は型が違う値を代入しようとするとエラーになります。
変数の型は変数名の前に`[型]`のように指定します。

```powershell
PS > [int]$x = 100
PS > $x.GetType()

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

PS > $x = "abc"
Cannot convert value "abc" to type "System.Int32". Error: "Input string was not in a correct format."
At line:1 char:1
+ $x = "abc"
+ ~~~~~~~~~~
+ CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException
```

#### 配列 (Array)

* 参考 : [About Arrays] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_arrays?view=powershell-6)

配列型の変数を宣言する方法はいくつかあります。

```powershell
PS > $array = "a", "b", "c"
PS > $array = "a".."c"
PS > $array = @("a", "b", "c")
PS > $array.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String[]                                 System.Array
```

要素数が0の配列は`@()`とします。ただし配列は固定サイズなので動的に要素を追加することはできません。

```powershell
PS > $array = @()
PS > $array.IsFixedSize
True
```

配列は異なる型のオブジェクトを格納することができます。

```powershell
PS > $array = "a", 1, $true, $null, (New-Guid)
PS > $array
a
1
True

Guid
----
a0535636-d62f-4fc5-9036-d851f200d315
```

配列の型を決めたい場合は変数名の前に`[型[]]`を記述します。

```powershell
PS > [string[]]$array = "a", "b", "c"
PS > $array
a
b
c
```

#### ハッシュテーブル (HashTable)

* 参考 : [About Hash Tables] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_hash_tables?view=powershell-6)
* 参考 : [Hashtable Class] (https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.hashtable?view=netcore-2.0)

ハッシュテーブル型の変数宣言は`${ }`を使用し`key = value;`の形式で値を定義します。

```powershell
PS > $hash = @{ key1 = "value1"; key2 = "value2"; key3 = "value3" }
PS > $hash.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object
```

ハッシュテーブルは動的に要素を追加していくことができます。

```powershell
PS > $hash = ${}
PS > $hash.IsFixedSize
False
PS > $hash.Add("key1", "value1")
PS > $hash.Add("key2", "value2")
PS > $hash.Count
2
```

要素の追加は+演算子でも行えます。

```powershell
PS > $hash = $hash + @{ key3 = "value3" }
```

または

```powershell
PS > $hash["key4"] = "value4"
```

#### リスト (ArrayList)

* 参考 : [ArrayList Class] (https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.arraylist?view=netcore-2.0)

動的に要素を追加できるリストもありますが変数宣言には`New-Object`を使用する必要があります。

```powershell
PS > $list = New-Object System.Collections.ArrayList
PS > $list.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     ArrayList                                System.Object
```

```powershell
PS > $list.IsFixedSize
False
PS > $list.Add("a")
0
PS > $list.Add("b")
1
PS > $list.Add("c")
2
```

#### 変数の型(一部)

|変数の型   |オブジェクトの型 |
|:---------|:--------------|
|[sbyte]   |SByte   |
|[short]   |Int16   |
|[int]     |Int32   |
|[long]    |Int64   |
|[byte]    |Byte    |
|[ushort]  |UInt16  |
|[uint]    |UInt32  |
|[ulong]   |UInt64  |
|[int16]   |Int16   |
|[int32]   |Int32   |
|[int64]   |Int64   |
|[uint16]  |UInt16  |
|[uint32]  |UInt32  |
|[uint64]  |UInt64  |
|[double]  |Double  |
|[float]   |Single  |
|[decimal] |Decimal |
|[bool]    |Boolean |
|[boolean] |Boolean |
|[char]    |Char    |
|[string]  |String  |
|[datetime]|DateTime|
|[uri]     |Uri     |
|[random]  |Random  |
|[guid]    |Guid    |

**Boolean**

真偽値のリテラル表現はないので代わりに自動変数の`$True`、`$False`を利用します。

```powershell
PS > [boolean]$b = $true
PS > $b
True
```

**DateTime**

```powershell
PS > [datetime]$dt = Get-Date
PS > $dt
2019年9月10日 14:48:57
```

**Random**

```powershell
PS > [random]$rnd = Get-Random
PS > $rnd.Next()
862740696
```

**GUID**

```powershell
PS > [guid]$id = New-Guid
PS > $id

Guid
----
7648dcde-9314-430f-a518-20068cac2b28
```

### クォートとヒアストリング (here strings)

* 参考 : [About Quoting Rules] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-6)

ダブルクォーテーション内の変数は展開されますが、

```powershell
PS > $name = "apple"
PS > "name = [$name]"
name = [apple]
```

シングルクォーテーションでは展開されません。

```powershell
PS > 'name = [$name]'
name = [$name]
```

ダブルクォーテーションをエスケープするにはダブルクォーテーションを2重にします。

```powershell
PS > "name = ""$name"""
name = "apple"
```

ヒアストリング(`@" ... "@` または `@' ... '@`)という記法を使うと簡潔に記述できます。なおヒアストリングの始まり(`@"` または `@'`)の次は必ず改行する必要があります。

```powershell
PS > @"
name = "$name"
"@
name = "apple"
```

### Automatic Variables

* 参考 : [About Automatic Variables] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_automatic_variables?view=powershell-6)

PowerShellのバージョンを調べるときによく利用される`$PSVersionTable`変数もAutomatic Variableの1つです。

```powershell
PS> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.2.2
PSEdition                      Core
GitCommitId                    6.2.2
OS                             Microsoft Windows 10.0.18362
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
```

### Preference Variables

* 参考 : [About Preference Variables] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-6)

### Environment Variables

* 参考 : [About Environment Variables] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_environment_variables?view=powershell-6)

下記のコマンドで環境変数を確認できます。

```powershell
PS > Get-ChildItem Env:
```

環境変数にアクセスするには下記の方法があります。
こちらは`DictionaryEntry`型のオブジェクトが返り、

```powershell
PS > Get-ChildItem Env:JAVA_HOME

Name                           Value
----                           -----
JAVA_HOME                      D:\openjdk\jdk-12.0.2
```

こちらの方法は文字列が返ります。

```powershell
PS > $env:JAVA_HOME
D:\openjdk\jdk-12.0.2
```

## 静的メンバーアクセサ

`::`演算子で型の静的メンバにアクセスします。
たとえばstring型の静的メンバであるjoinは以下のように使うことができます。

```powershell
PS> [string]::join(',', ('A', 'B', 'C'))
A,B,C
```

静的メンバにはメソッドの他に定数もあります。

```powershell
PS> [int]::MaxValue
2147483647
```

## プロファイル

* 参考 : [About Profiles] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_profiles?view=powershell-6)

プロファイルはPowerShell Core起動時に読み込まれるスクリプトです。プロファイルに変数、関数、エイリアスなどを追加する初期を記述することで環境のカスタマイズをすることができます。

### プロファイルの場所

|priority|description                 |path|
|:-------|:---------------------------|:---|
|High    |All Users, All Hosts        |$PsHome\Profile.ps1 |
|        |All Users, Current Host     |$PsHome\Microsoft.PowerShell_profile.ps1 |
|        |Current User, All Hosts     |$Home\[My ]Documents\PowerShell\Profile.ps1 |
|Low     |Current user, Current Host  |$Home\[My ]Documents\PowerShell\Microsoft.PowerShell_profile.ps1 |

### プロンプトのカスタマイズ

* 参考 : [About Prompts] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_prompts?view=powershell-6)

プロファイルでプロンプトをカスタマイズできます。

```powershell
Function Prompt {
  "PS " + (Get-Location) + " (" + (Get-Date).ToString("HH:mm:ss") + ") > "
}
```

### $PROFILE変数

\$PROFILE変数には"Current user, Current Host"プロファイルのパスが格納されています。
\$PROFILE変数が示すパスに実際にプロファイルが存在するかどうかは`Test-Path`で確認できます。

```powershell
> Test-Path -path $PROFILE
true
```

# PowerShell Coreの小技

## ファイルの圧縮・展開

### 圧縮

* 参考 : [Compress-Archive] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.archive/compress-archive?view=powershell-6)

```powershell
PS > Compress-Archive -Path D:\var\logs\* -DestinationPath D:\var\logs.zip
```

```powershell
PS > $zip = Compress-Archive -Path D:\var\logs\* -DestinationPath D:\var\logs.zip -PassThru
PS > $zip.FullName
D:\var\logs.zip
```

### 展開

* 参考 : [Expand-Archive] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.archive/expand-archive?view=powershell-6)

```powershell
PS > Expand-Archive -Path D:\var\logs.zip -DestinationPath D:\temp
```

## ファイルのハッシュ

* 参考 : [Get-FileHash] (https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Get-FileHash?view=powershell-6)

```powershell
PS > Get-FileHash -Path chrome.json -Algorithm MD5

Algorithm       Hash                                                                   Path
---------       ----                                                                   ----
MD5             0432E5309225F577378C88B1E0D04367                                       C:\Users\User\chrome.json
```

Windowsのcertutilというコマンドでもハッシュを求めることができます。

```
> certutil -hashfile chrome.json MD5
MD5 ハッシュ (対象 chrome.json):
0432e5309225f577378c88b1e0d04367
CertUtil: -hashfile コマンドは正常に完了しました。
```

## httpリクエスト

### Webクライアント

* 参考 : [Invoke-WebRequest] (https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Invoke-WebRequest?view=powershell-6)

```powershell
PS > $Uri = "http://localhost:9000/app/memo/list"
PS > $response = Invoke-WebRequest -URI $Uri
PS > $response

StatusCode        : 200
StatusDescription : OK
Content           : [ {
                      "id" : 1,
                      "title" : "memo shopping",
                      "description" : "memo1 description",
                      "done" : false,
                      "updated" : "2018-01-04T12:01:00"
                    }, {
                      "id" : 2,
                      "title" : "memo job",
                      "descripti…
RawContent        : HTTP/1.1 200 OK
                    Transfer-Encoding: chunked
                    Date: Thu, 12 Sep 2019 10:20:13 GMT
                    Content-Type: application/json; charset=UTF-8

                    [ {
                      "id" : 1,
                      "title" : "memo shopping",
                      "description" : "me…
Headers           : {[Transfer-Encoding, System.String[]], [Date, System.String[]], [Content-Type, System.String[]]}
Images            : {}
InputFields       : {}
Links             : {}
RawContentLength  : 2879
RelationLink      : {}
```

### Rest API

* 参考 : [Invoke-RestMethod] (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-6)

```powershell
PS > $body = @"
{
  "title": "test memo title",
  "description": "test memo description",
  "done": false
}
"@
PS > $headers = @{"Content-Type" = "application/json"}
PS > $Uri = "http://localhost:9000/app/memo"
PS > $Result = Invoke-RestMethod -Uri $Uri -Method Post -Headers $headers -Body $body
```

## JSON

### JSON文字列を任意のオブジェクトへ変換する

文字列がJSONとして有効かどうかは`Test-Json`で確認できます。

```powershell
PS > $json = @"
{"id": 111, "user": "Aaa", "items": [{"name": "apple", "price": 100}, {"name": "banana", "price": 100}]}
"@
PS > $json.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

PS > Test-Json $json
True
```

`ConvertFrom-Json`でJSON文字列を任意のオブジェクトへ変換します。

```powershell
PS > $obj = ConvertFrom-Json -InputObject $json
PS > $obj.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    PSCustomObject                           System.Object

PS > $obj

 id user items
 -- ---- -----
111 Aaa  {@{name=apple; price=100}, @{name=banana; price=100}}

PS > $obj.items

name   price
----   -----
apple    100
banana   100
```

### オブジェクトをJSON文字列へ変換する

ハッシュテーブルをJSON文字列へ変換する例です。

```powershell
PS > $hash = @{"id" = 111; "user" = "Aaa"; "items" = @(@{"name" = "apple"; "price" = 100}, @{"name" = "banana"; "price" = 100})}
PS > $hash.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Hashtable                                System.Object
```

```powershell
PS > $json = ConvertTo-Json -InputObject $hash
PS > $json.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

PS > $json
{
  "items": [
    {
      "price": 100,
      "name": "apple"
    },
    {
      "price": 100,
      "name": "banana"
    }
  ],
  "user": "Aaa",
  "id": 111
}
```

## CSV

### オブジェクトをCSV文字列へ変換する

```powershell
PS > Get-Process -Name chrome | Select-Object -Property Id, Name, CPU | ConvertTo-Csv
"Id","Name","CPU"
"916","chrome","711.21875"
"1288","chrome","3.53125"
"2636","chrome","0.140625"
"4528","chrome","15.1875"
"4536","chrome","0.71875"
"4616","chrome","1.953125"
"6404","chrome","180.265625"
"6748","chrome","5162.984375"
"7528","chrome","3247.140625"
"8340","chrome","0.46875"
"8376","chrome","3.515625"
"8764","chrome","697"
"9928","chrome","0.265625"
"10760","chrome","0.046875"
"10856","chrome","1.1875"
"11212","chrome","2.609375"
"11568","chrome","3.03125"
"11996","chrome","0.328125"
"12296","chrome","2.125"
"12320","chrome","0.9375"
"12344","chrome","1.140625"
"12424","chrome","27.84375"
"12452","chrome","0.390625"
"12800","chrome","5.90625"
"12820","chrome","7.34375"
"13036","chrome","118.46875"
"13712","chrome","16.796875"
"14328","chrome","481.59375"
"14624","chrome","11.9375"
"16116","chrome","1.046875"
"16328","chrome","10.421875"
```

## haedとtail

`Select-Object`の`-First`または`-Last`オプションでhead、tailと同じことができます。

```powershell
PS > Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 5

 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
    200   830.51     921.40   5,613.31    6748   1 chrome
     52    42.75      86.23   3,647.77    7528   1 chrome
     81   191.60     294.03     754.11     916   1 chrome
     35    38.29      56.90     739.66    8764   1 chrome
    127   248.90     225.36     571.64   14328   1 chrome
```

エイリアス版

`Get-Process` → `ps`、`Sort-Object` → `sort`、`Select-Object` → `select`

```powershell
PS > ps | sort -Property CPU -Descending | select -First 5
```

`Sort-Object`の`-Top`および`-Bottom`オプションでも同じ結果が得られます。

```powershell
PS > ps | sort -Property CPU -Descending -Top 5
```


# 補足

## PowerShell Core 6のインストール

Windows 10ではデフォルトでWindows PowerShell 5.0 (or 5.1)がインストールされていますが、PowerShell Coreは別エディションなので5.xとは別にインストールされます。
インストールは[GitHub] (https://github.com/powershell/powershell)よりインストーラをダウンロードしてインストーラを実行するだけです。（msiとは別にzip版もあります）

### インストール先

インストール先もバージョン5.xと変わっていて下記のようにデフォルトではProgram Files下にインストールされます。(Core 6.1で変更)
またバイナリ名も`powershell.exe`から`pwsh.exe`に変更されています。

|バージョン |インストール先              |
|:---------|:--------------------------|
|5.x       |C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe |
|6.2       |C:\Program Files\PowerShell\6\pwsh.exe                    |

### バージョンの確認

**バージョン5.1**

```powershell
PS > $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.18362.145
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.18362.145
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
```

**バージョン6.2.2**

```powershell
PS > $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.2.2
PSEdition                      Core
GitCommitId                    6.2.2
OS                             Microsoft Windows 10.0.18362
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
```

## PowerShell Core 7へのアップグレード

* 参考 : [Windows への PowerShell のインストール] (https://docs.microsoft.com/ja-jp/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-7)

インストーラーでPowerShell Core 6がインストールされている環境では、インストーラーでPowerShell Core 7をインストールすると、PowerShell Core 6は削除され新しくPowerShell Core 7がインストールされます。

PowerShell Core 6を残したい場合は、改めてzipファイルからのインストールを行う必要があります。


## モジュール

> [PowerShell Module Browser] (https://docs.microsoft.com/ja-jp/powershell/module/?view=powershell-6)
> Search all PowerShell modules and cmdlets from Microsoft – just start typing in the box below.

## PowerShell Gallery

> [PowerShell ギャラリー] (https://docs.microsoft.com/ja-jp/powershell/gallery/overview)
> PowerShell ギャラリーは、PowerShell コンテンツの中央リポジトリです。 ここには、PowerShell コマンドと Desired State Configuration (DSC) リソースを含む、便利な PowerShell モジュールがあります。

### [posh-git] (https://github.com/dahlbyk/posh-git)

GitとPowerShellを統合するposh-gitというモジュールがあり、PowerShell ギャラリーからインストールできます。
インストール要件は

* Windows PowerShell 5.x or PowerShell Core 6.0以上
* スクリプトの実行ポリシーが`RemoteSigned` or `Unrestricted`
* Gitクライアントがインストール済み (gitへのパスが通っていること)

**インストールコマンド**

新規にインストールする場合

```
> PowerShellGet\Install-Module posh-git -Scope CurrentUser -AllowPrerelease -Force
```

インストール済みの場合

```
> PowerShellGet\Update-Module posh-git
```

**インストール後**

インストール後は以下のコマンドでposh-gitを有効にします。（このコマンドを実行すると`Microsoft.PowerShell_profile.ps1`というプロファイルに`Import-Module posh-git`という行が追加されます）

```
> Add-PoshGitToProfile
```

これでPowerShellのプロンプトにGitリポジトリのステータスが表示されるようになりました。