ひとり情シスに役立つPowerShellコードのサンプル

Windows10から **Windows Subsystem for Linux** が使えるようになり、**CLI** 使いには有りがたい限りだが、標準ではインストールされないため、お客様先のPCでは使えないことが多い。
**PowerShell** であればどのPCでも最初から入っているし、Windows標準シェルとして今後も生き残る気配に変わりは無いので、よく使うワンライナーに厳選してサンプルを示していく。

# 前提条件
## 動作環境

```powershell:バージョン情報
PS C:\> $PSVersiontable.PSVersion
Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      17134  590
```

## エイリアス名
自分だけが使うならタイプ文字数が少ない方がラクなので、本記事では全て標準エイリアス名で記載していることをご容赦いただきたい。

|エイリアス名|コマンドレット名   |説明|
|:----------|:-----------------|:--------------------------------------------|
|%、foreach |ForEach-Object    |ループ（foreachステートメントと混同なきよう）|
|?、where   |Where-Object      |フィルタ|
|select     |Select-Object     |選択 |
|sort       |Sort-Object       |ソート   |
|group      |Group-Object      |グルーピング|
|measure    |Measure-Object    |統計情報   |
|echo       |Write-Output      |bash/バッチの同名コマンドと同じ|
|ls         |Get-ChildItem     |ディレクトリ情報の取得   |
|ren        |Rename-Item       |ファイル名のリネーム   |
|mv         |Move-Item         |ファイルの移動   |
|rm         |Remove-Item       |ファイルの削除   |
|sls        |Select-String     |ファイルから文字列を検索   |
|oss        |Out-String -Stream|オブジェクトを文字列の配列に変換   |
|ft         |Format-Table      |表形式で整形   |
|fl         |Format-List       |リスト形式で整形   |

下記を実行すると、すべての標準エイリアスのリストがクリップボードにコピーされる。

```powershell
Alias | oss | Set-Clipboard
```

# 演算子一覧
サンプルコードの中で演算子の解説はしないので、ここにまとめて置く。
真偽値を返すものはwhereブロックで良く使う。

|演算子     |説明   |
|:----------|:-----------------|
|-eq        |等しい（文字列の比較では大文字小文字を区別しない）|
|-ne        |等しくない  |
|-gt        |>  |
|-ge        |>=  |
|-lt        |<  |
|-le        |<=  |
|-and       |AND  |
|-or        |OR  |
|!          |NOT  |
|-replace   |大文字小文字を区別しないで置換。正規表現可|
|-creplace  |大文字小文字を区別して置換。正規表現可|
|-like      |ワイルドカード|
|-match	    |正規表現。結果は $Matches 自動変数に入る|
|-contains  |配列に指定の要素が含まれるか|
|-split     |区切り文字で分割した配列を返す|
|-f         |文字列のフォーマットを行う|


# サンプルコード

## テキストファイルの一括置換

```powershell
cat foo.txt | %{$_ -replace 'ABC', 'XYZ'}   # ABC を XYZ に
ls "入力フォルダ" | %{cat $_ | %{$_ -creplace 'foo', 'bar'} > "出力フォルダ\$_" }   # フォルダ内を一括
```

## grepもどき

```powershell
sls "pattern" *.txt
ls -r *.txt | sls "pattern"   # サブディレクトリを含める
sls 'ほげほげ' *.txt -Encoding oem   # Shift-JISの場合
Alias | oss | sls "set"   # オブジェクト型を渡すなら oss を介す
```
- 正規表現扱いにしたくなければ `-SimpleMatch` を追加。
- 大文字小文字を区別するなら `-CaseSensitive` を追加。
- 最後に `ft` や `Out-GridView` へ渡すと画面で見易い場合がある。
- 最後に `Export-Csv foo.csv -Encoding oem -NoTypeInformation` へ渡すとExcelで編集し易い場合がある。

## find、xargsもどき
```powershell
ls -r "*.txt" | select Fullname   # ファイルのフルパス一覧
ls -r "*.txt" | ft -a Fullname,Length   # フルパスとサイズを表形式で表示
ls -r "*.txt" | ?{$_.LastWriteTime -gt "2018-11-01"} | select Fullname,LastWriteTime | ConvertTo-Csv   # 指定日以降に更新されたファイルの一覧をCSVファイルに出力
ls -r "*.txt" | rm   # テキストファイルを削除
```

## 最初の3行を取得
```powershell
cat foo.txt | select -first 3
```

- 最後を取得するなら`-last`、読み飛ばすなら`-skip` を使う。

## 3行目から8行目を取得

```powershell
(cat foo.txt)[2..7]
```

- 改行で分割されたString型の配列であることを利用している。

## 行数を取得（wc -l もどき）

```powershell
(cat foo.txt).Length
(cat foo.txt | measure).Count
```

## ファイル名を一括変更

### ファイル名のネーミングルールを変更
```powershell
ls | ren -NewName {$_.Name -replace '2019-(\d+)-(\d+)\.', '令和元年$1月$2日'}
```

- `-WhatIf`を追加すると、実際には変更しないのでテストに使える。
- `-Confirm`を追加すると、その名前で変更して良いかを都度確認してくれる。

### すべてのファイル名の先頭に "old" を付ける

```powershell
ls | ren -NewName {"old$_"}
```

### ファイル名に連番を付ける

```powershell
ls | sort Name | % {$i = 1} { $NewName = "{0:00}_{1}" -f $i, $_.Name ; mv $_.Name $NewName; $i++ }
```

## 半年以上更新されていないファイルを削除

```powershell
ls | ?{$_.LastWriteTime -lt (Get-Date).AddMonths(-6)} | %{$_.Delete()}
```

## touchもどき

```powershell
Set-ItemProperty foo.txt -Name LastWriteTime -Value $(Get-Date)   # 最終更新日時を現在日時に変更
New-Item -Type file foo.txt   # サイズ0 のファイルを作成
ls | %{$_.LastWriteTime = '2019-04-20 09:30:00'}   # 日時指定
```

- `LastWriteTime`なら最終更新日時、`CreationTime`なら作成日時。

## CSVファイルの加工
１行目にヘッダー（項目名）があることが前提。

### 指定した列が条件に一致する行を抽出
```powershell
cat foo.csv | ConvertFrom-Csv | ?{$_.郵便番号 -eq "241-0005"} | ConvertTo-Csv -NoTypeInformation
cat foo.csv | ConvertFrom-Csv | ?{$_.住所 -like "埼玉*"} | ConvertTo-Csv -NoTypeInformation
```

### "社員番号" の列をゼロパディング
```powershell
cat foo.csv | ConvertFrom-Csv | %{$_.社員番号=$_.社員番号.PadLeft(6,"0"); $_} | ConvertTo-Csv
```

CSVファイルをExcelで更新してしまい、先頭のゼロが消えてしまった場合によく使う。

```powershell:文字列操作で他によく使うもの
$str.ToString("0000")
$str.PadLeft(20)
$str.PadRight(20)+"!"
$str.PadLeft(20,"-")
$str.SubString(スタート値,取り出す文字数)
$str.Trim
```

### 5行目にある "金額" の列をゼロにする
```powershell
cat foo.csv | ConvertFrom-Csv | %{ $i=0 }{ if(++$i -eq 5){$_.金額=0 }$_} | ConvertTo-Csv
```

## おまけ（小ネタ集）

```powershell
ls | measure -Property length -sum   # ファイルサイズと合計行を表示
'0192.010.000.105' -replace '\b0+\B'   # ゼロサプレス（頭の余計なゼロを取り除く）
ii .   # カレントフォルダをエクスプローラで開く
ii memo.txt   # ファイルを開く
ii (Get-PSReadlineOption).HistorySavePath   # 入力履歴ファイルを開く
history   # Linuxのhistoryコマンドと同じ
Start-Transcript script.txt   # Linuxのscriptコマンドと同じ。停止はStop-Transcript
(gcm notepad).Definition   # Linuxのwhichコマンドと同じ。
Invoke-WebRequest https://www.example.com    # Linuxのcurlコマンドと同じ
Set-PSReadlineOption -BellStyle None   # BackSpaceのビープ音を消す
[Console]::Beep(494,500)   # 周波数と再生時間を指定してビープ音を鳴らす
```