PowerShellのFormat-Hexコマンドレットでバイナリファイルを16進ダンプする

# 環境
-  PowerShell 5.1
-  PowerShell 6.0

# Format-Hexコマンドレット
odコマンドのようなファイル等の16進数ダンプ表示ができるFormat-HexがPowerShellバージョン5で追加された。ただし今のところ16進数専用でオプションはあまりなく、odコマンドのエイリアスではないようだ。

# バイナリファイルをダンプ
ヘルプ例にあるようにファイルタイプ判別でファイル先頭のヘッダ部分を表示したい用途等で使える。

```powershell:powershell
PS C:\temp> Format-Hex -Path ".\pngfile.dat"


           パス: C:\temp\pngfile.dat

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52  ?PNG........IHDR
00000010   00 00 01 8C 00 00 00 E6 08 02 00 00 00 49 43 25  ...?...a.....IC%
... (以下略)
```

他のプロセスでファイルを開いていると例外エラーになってしまう。
また、試した限り、右の文字列部分に日本語等のマルチバイト文字コードを正しく表示する方法はわかならかった。

# ファイルサイズが大きい場合の注意
ファイルが小さければ、このまま問題なく使えるが、ファイルが大きい場合に出力をmoreに食わせるとメモリ消費や実行時間が増え、表示し始めるまでに時間がかかってしまう現象があった。
ページャを使わなければそのようなことはないが、出力が大量に出てしまう。ctrl-cで止められるが、使いにくい。
試した結果、moreを使うよりSelect-Objectのほうが表示し始めるまでの時間が速いことがわかった。
どうやらmoreは前段の処理結果をすべて一旦メモリに蓄えてから表示しはじめるようで、Select-Objectならばすぐにパイプライン処理が始まる点が違う模様。


## moreを使う
```powershell:powershell
PS C:\temp> Format-Hex .\bitmap100KB.dat | more


           パス: C:\temp\bitmap100KB.dat

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   42 4D C6 90 01 00 00 00 00 00 36 00 00 00 28 00  BMA?......6...(.
00000010   00 00 91 02 00 00 34 00 00 00 01 00 18 00 00 00  ..?...4.........
... (以下略)
```


## Select-Objectを使う
```powershell:powershell
# 先頭256バイトを表示(16バイト単位のByteCollectionのため16で割る)
PS C:\temp> Format-Hex .\bitmap100KB.dat | Select-Object -First (256/16)


           パス: C:\temp\bitmap100KB.dat

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   42 4D C6 90 01 00 00 00 00 00 36 00 00 00 28 00  BMÆ......6...(.
00000010   00 00 91 02 00 00 34 00 00 00 01 00 18 00 00 00  .....4.........
... (以下略)


# 8KBスキップして256バイトを表示
PS C:\temp> Format-Hex .\bitmap100MB.dat | Select-Object -Skip (8KB/16) -First (256/16)


           Path: C:\temp\bitmap100MB.dat

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00002000   0A 2D 4E 0A 2D 4E 0A 2D 4E 0A 2D 4E 0A 2D 4F 0A  .-N.-N.-N.-N.-O.
00002010   2D 4F 0A 2D 4F 0A 2C 4F 09 2C 4F 09 2C 4F 09 2C  -O.-O.,O.,O.,O.,
... (以下略)


# アドレス0x1C00から256バイト表示
PS C:\temp> Format-Hex .\bitmap1MB.dat | Select-Object -Skip (0x1C00/16) -First (256/16)


           パス: C:\temp\bitmap1MB.dat

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00001C00   4C 08 28 4C 07 28 4C 06 28 4D 06 28 4D 06 28 4C  L.(L.(L.(M.(M.(L
00001C10   06 29 4D 07 2A 4E 08 2B 4E 09 2A 4E 08 29 4E 07  .)M.*N.+N.*N.)N.
... (以下略)
```

ただしSelect-Objectを使っても、skipがMB単位とか大きくなるほど、やはり時間がかかってしまいどうしようもなかった。基本的にファイル先頭付近を見るのに使うしかなさそう。Format-Hexにskipオプションができればいいのだが。


## 表示し始める時間の比較結果

### PowerShell 5.1

| ファイルサイズ      |  more(最初の表示まで) |  select(先頭1KBを表示) |
|-------------------:|-------------------------:|---------------------:|
| 100KB         |        5.1秒 |     0.16秒     |
| 1MB           |       49.5秒 |     0.16秒      |
| 10MB          |      202.1秒 |     0.14秒    |
| 100MB         |        未計測|     0.16秒     |
| 300MB         |        未計測|     0.13秒     |



### PowerShell 6.0

| ファイルサイズ      |  more(最初の表示まで) |  select(先頭1KBを表示) |
|-------------------:|-------------------------:|---------------------:|
| 100KB         |        0.3秒 |     0.050秒     |
| 1MB           |      0.3秒 |     0.047秒      |
| 10MB          |     0.9秒 |     0.054秒    |
| 100MB         |     5.2秒   |     0.066秒     |
| 300MB         |    22.4秒  |     0.068秒     |

5.1と6.0では実装が変わっているせいなのか違いが大きい模様。