PowerShell~入門~

PowerShellのインストール(for mac)

Windows, Linuxその他へのインストールについては他を参照されたし。

1
2
3
4
5
6
7
8
9
10
11
12
13
# Homebrew-Caskのインストール
$ brew tap caskroom/cask

# Homebrew-CaskからPowerShellをインストール
$ brew cask install powershell

# PowerShellのバージョン確認
$ pwsh -V
PowerShell v6.0.4

# PowerShellのアプデートの時は
$ brew update
$ brew cask upgrade powershell

PowerShellの起動

terminalでこれを打ち込むだけ。

1
2
3
4
5
6
7
8
$ pwsh
PowerShell v6.0.4
Copyright (c) Microsoft Corporation. All rights reserved.

https://aka.ms/pscore6-docs
Type 'help' to get help.

PS >

PowerShellを触ってみる

PowerShellは大文字小文字を区別しないので、$PSV + tab でも$psv + tab でも$PSVersionTableと補完される。

1
2
3
4
5
6
7
8
9
10
11
12
13
PS > $PSVersionTable

Name Value
---- -----
PSVersion 6.0.4
PSEdition Core
GitCommitId v6.0.4
OS Darwin 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT...
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0

出力内容を一時保存しておく。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
PS > $ver = $PSVersionTable
PS > $ver

Name Value
---- -----
PSVersion 6.0.4
PSEdition Core
GitCommitId v6.0.4
OS Darwin 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT...
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0

PowerShellのexit方法は以下の通り。

1
2
PS > exit
# あるいはCtr+D

Cmdlet(コマンドレット)

lsコマンドと同じようなもの(PowerShellではCmdletと呼んでいるだけ)。
Cmdletは[Verb]-[Nown]の形になっている。
例: Get-Content, Set-Location

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Get-ChildItemはPowerShellを開いているディレクトリにあるファイルとディレクトリの一覧を表示するCmdlet(= ls)
PS > Get-ChildItem


Directory: /Users/omochi


Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2018/08/24 1:08 Applications
d----- 2018/09/10 15:11 Desktop
d----- 2018/09/05 10:36 Documents
d----- 2018/09/09 21:03 Downloads
d----- 2018/09/09 18:10 Library
d----- 2018/08/24 0:07 Movies
d----- 2018/08/24 0:07 Music
d----- 2018/08/24 0:07 Pictures
d----- 2018/08/24 0:07 Public

シンタックスハイライト

PowerShellコンソール上では変数、コマンド、数字がデフォルトで色付けされていて可愛い。

実際に使っていく時に便利な開発環境

Visual Studio Codeを使って開発を行うと便利。
使いやすいので書いておく。

まず、以下から.zipファイルをダウンロードしてVSCodeをインストールする。
Visual Studio Code Download link

VSCodeにPowerShellの拡張機能をインストールする。
MarketplaceでPowerShellと検索するとPowerShellという名前の拡張機能がヒットするのでそれをinstallする。

以下のような環境でPowerShellを扱えるようになる。

ファンクションキーについて

・F5: デバッグ実行
・F9: ブレークポイントの設定(ブレークポイント解除の際はもう一度F9を押せば良い)
・F8: 部分実行

PowerShellでWebページのStatusCheckをしてみる

statusCodeを取得するCmdlet

1
$statusCode = (Invoke-WebRequest -Uri https://google.com).StatusCode

statusCodeが200であることを確認するCmdlet
(200の場合はTrueを返す)

1
$statusCode -eq 200

statusCodeが200でないことを確認する

1
2
# -eq(equal演算子)を-notで否定する回りくどい書き方
-not($statusCode -eq 200)

StatusCheck.ps1 (第一形態)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 0xomochi
# StatusCheck.ps1
# 1st

$url = "https://google.com" # configure "$url"
# statusCodeを取得する
$statusCode = try {
# Invoke-WebRequestはstatusCode404ではなく例外を出力するためstatusCodeが200かどうかを確認するときに支障が出る
# 例外構文を使って例外が出た時も必ずstatusCodeを取得するようにする
(Invoke-WebRequest -Uri $url).StatusCode
}
catch {
$Error[0].Exception.GetBaseException().Response.StatusCode.Value__
}

# statusCodeが200であるかどうかを確認する
# $validStatusCode = 200
$validStatusCode = 404
if ($statusCode -ne $validStatusCode){

# ./StatusCheck.logというファイルが存在するかを確認する
if (-not(Test-Path ./StatusCheck.log)) {
# StatusCheck.logが存在しなければStatusCheck.logファイルを新しく作る
New-Item -Path ./StatusCheck.log
}

# date, statusCode, urlをjsonで保存
$json = @{
Date = Get-Date
Url = $url
StatusCode = $statusCode
}
$json | ConvertTo-Json -Compress
}

jsonファイルにOut-FileCmdletで書き込みを行う。

1
$json | Out-File -LiteralPath ./StatusCheck.log

この時点での出力結果StatusCheck.logは以下のようになる。
何回書き込みをしてもlogが上書きされてしまい、追記されない。
形式もjson形式でないので一行で表示されるようにしたい。

1
2
3
4
5
Name                           Value                                                                                                               
---- -----
Url https://google.com
StatusCode 200
Date 2019/02/18 13:03:13

先ほどと同様にjsonファイルにOut-FileCmdletを使って書き込みを行う。
-Append./StatusCheck.logに書き込む度に追記モードにするためのスイッチである。

1
$json | Out-File -LiteralPath ./StatusCheck.log -Append

追記モードに変更した後の出力結果StatusCheck.logは以下のようになる。
追記はされたがjson形式でないので見にくい。

1
2
3
4
5
6
7
8
9
10
11
Name                           Value                                                                                                               
---- -----
Url https://google.com
StatusCode 200
Date 2019/02/18 13:03:13

Name Value
---- -----
Url https://google.com
StatusCode 200
Date 2019/02/18 13:03:13

StatusCheck.ps1を改変する(第二形態)

Cmdletでファイル書き込みをしていたところもスクリプトに含め、60secごとに書き込み処理を行うように書き足した。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 0xomochi
# StatusCheck.ps1
# 2nd

while ($true) {
$url = "https://google.com"
$statusCode = try {
(Invoke-WebRequest -Uri $url).StatusCode
}
catch {
$Error[0].Exception.GetBaseException().Response.StatusCode.value__
}
# $validStatusCode = 200
$validStatusCode = 404
if ($statusCode -ne $validStatusCode) {
if (-not(Test-Path ./StatusCheck.log)) {
New-Item -Path ./StatusCheck.log
}
# "@{}"を"[ordered]@{}"とすることで出力が順序を維持した連想配列"OrderedHashTable"となる
$json = [ordered]@{
# 改変前のスクリプトだと"value":"xxxx","DisplayHint":"yyyy"と表示される
# "Date":"xxxx年y月z日 X曜日 --:--:--"という表記にしたいので(Get-Date).ToString()を使う
Date = (Get-Date).ToString("F")
url = $url
StatusCode = $statusCode
} | ConvertTo-Json -Compress
$json | Out-File -LiteralPath ./StatusCheck.log -Append
}
# 60sec sleepする
Start-Sleep -Seconds 60
}

左側の$jsonの値が$json: {"Date":"2019年2月20日 水曜日 16:00:54","url":"https://google.com","StatusCode":200}となっている。
これでjson形式でStatusCheck.logに出力できるようになった。(赤枠)

以下のようにStatusCheck.ps1を実行する。

1
2
3
PS> ./StatusCheck.ps1

# &./StatusCheck.ps1 でも実行できる

StatusCheck.ps1を実行するとStatusCheck.logに以下のように、60secごとにjson形式でログが追記されているのが確認できる。

1
2
3
4
5
6
7
{"Date":"2019年2月20日 水曜日 17:55:52","url":"https://google.com","StatusCode":200}
{"Date":"2019年2月20日 水曜日 17:56:52","url":"https://google.com","StatusCode":200}
{"Date":"2019年2月20日 水曜日 17:57:52","url":"https://google.com","StatusCode":200}
{"Date":"2019年2月20日 水曜日 17:58:52","url":"https://google.com","StatusCode":200}
{"Date":"2019年2月20日 水曜日 17:59:52","url":"https://google.com","StatusCode":200}
{"Date":"2019年2月20日 水曜日 18:00:53","url":"https://google.com","StatusCode":200}
{"Date":"2019年2月20日 水曜日 18:01:53","url":"https://google.com","StatusCode":200}

StatusCheck.ps1完成 (最終形態)

変数をまとめて定義してスクリプトをすっきりさせた。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 0xomochi
# StatusCheck.ps1
# 3rd

$url = "https://google.com"
$validStatusCode = 200
$logFile = "./StatusCheck.log"
while ($true) {
$statusCode = try {
(Invoke-WebRequest -Uri $url).StatusCode
}
catch {
$_.Exception.GetBaseException().Response.StatusCode.Value__
}
if ($statusCode -ne $validStatusCode) {
if (-not(Test-Path $logFile)) {
New-Item -Path $logFile
}
$json = [ordered]@{
Date = (Get-Date).ToString("F")
url = $url
StatusCode = $statusCode
} | ConvertTo-Json -Compress

$json | Out-File -LiteralPath $logFile -Append
}
Start-Sleep -Seconds 60
}

(to be updated)