SnippingToolで切り抜いた画像を即保存してくれるバッチファイルを作ったよ

<!--
気が向いたらこいつらも書く
・再起の処理がどういう風に実行されるか
・$img=Get-Clipboardをした後、$imgが画像の時、そうじゃない時の中身の違い
-->

# 目次
1. 動機
2. 完成したバッチファイルの全貌
3. 解説
4. 参考文献

# 1. 動機
私は、SnippingToolで切り抜いた画像をpngファイルとして保存するとき、

- Windowsの「ペイント」を立ち上げて
- 切り抜いた画像をペーストして
- 「名前を付けて保存」を選んで
- 画像の保存場所とファイル形式を選ぶ

...という工程をいつも踏んでいました。

**地味にめんどくさい！**
**やりたくない！**

そこで、SnippingToolで切り抜いた画像を即保存してくれるバッチファイルを作ることにしました。

# 2. 完成したバッチファイルの全貌

```batchfile:SnipSavingTool.bat
rem 全コマンドを表示しないようにする
@echo off

rem バッチファイル自身を再帰的に呼び出し、最小ウィンドウで実行する
if not "%~0"=="%~dp0.\%~nx0" (
	start /min cmd /c,"%~dp0.\%~nx0" %*
	goto :eof
)

rem PowerShellスクリプトファイルを実行する
powershell -ExecutionPolicy RemoteSigned -File "SnipSavingTool.ps1"
```
```powershell:SnipSavingTool.ps1
# クリップボードに保存してあるものを $img に代入する
$img = Get-Clipboard -Format Image

# $img を名前つけて保存する
If ($img -ne $null) {
	$date_time = Get-Date -Format yyyyMMdd_HHmmss
	$img.Save("$date_time.png")
	[System.Windows.Forms.MessageBox]::Show("保存成功！","Result")
} Else {
	[System.Windows.Forms.MessageBox]::Show("たぶん画像じゃない","Result")
}
```

# 3. 解説
### 全コードをバッチファイル１つに収めなかった理由

結論から言うと、バッチファイルの見た目が汚くなるからです。

一応バッチファイル１つに収めることは可能です。
しかし、クリップボード内のデータ取得にはPowerShellのコマンドを使うので<sup>[[1]](#4-参考文献)</sup>、バッチファイルの全行に`powershell -Command`と書かなくちゃいけません<sup>[[2]](#4-参考文献)</sup>。

めんどいしコードが汚くなりそうなので、「バッチファイルでPowerShellスクリプトファイルを実行する」ことにしています。

## 3.1 SnipSavingTool.bat の中身
### <span>@</span>echo off
- `echo off`・・・echo off 以降のコマンドがコマンドプロンプト上に表示されなくなる。
- `@echo off`・・・echo off 自身すらも表示されなくなる。

### if not<sup>[[3]](#4-参考文献)</sup>
- `if not A==B <command>`・・・AとBが等しくないとき、commandが実行される。

### "%~0"=="%~dp0.\%~nx0"
- `%0`<sup>[[4]](#4-参考文献)</sup>・・・（例 "C:\Users\taro\Desktop\SnipSavingTool.bat"）
- `%~0`<sup>[[4]](#4-参考文献)</sup>・・・「%0」から「""」を除く（例 C:\Users\taro\Desktop\SnipSavingTool.bat）
- `%~d0`<sup>[[4]](#4-参考文献)</sup>・・・「%~0」のドライブ名（例 C:）
- `%~p0`<sup>[[4]](#4-参考文献)</sup>・・・「%~0」のパス（例 \Users\taro\Desktop\）
- `%~dp0`・・・「%~d0」と「%~p0」を合わせたもの（例 C:\Users\taro\Desktop\）
- `%~n0`<sup>[[4]](#4-参考文献)</sup>・・・「%~0」のベース名（例 SnipSavingTool）
- `%~x0`<sup>[[4]](#4-参考文献)</sup>・・・「%~0」の拡張子（例 .bat）
- `%~nx0`・・・「%~n0」と「%~x0」を合わせたもの（例 SnipSavingTool.bat）
- `%~dp0.\%~nx0`・・・（例 C:\Users\taro\Desktop\ .\SnipSavingTool.bat）

### start /min cmd /c "%~dp0.\%~nx0"
- `start`・・・新規にコマンドプロンプトを開く。<sup>[[5]](#4-参考文献)</sup>
- `start /min`・・・新規コマンドプロンプトをウィンドウ最小化の状態で開く。<sup>[[5]](#4-参考文献)</sup>
- `start cmd`・・・新規コマンドプロンプトにおいて「cmd」を実行する。<sup>[[5]](#4-参考文献)</sup>
- `cmd /c <command>`・・・command実行後、これを実行したコマンドプロンプトは終了する。<sup>[[6]](#4-参考文献)</sup>
- `start /min cmd /c <command>`・・・新規コマンドプロンプトをウィンドウ最小化の状態で開き、command実行後、この新規コマンドプロンプトは終了する。

### goto :eof<sup>[[7]](#4-参考文献)</sup>
バッチファイルを終了する。（EOF = End Of File）

### powershell -ExecutionPolicy RemoteSigned -File "SnipSavingTool.ps1"<sup>[[8]](#4-参考文献)</sup>
管理権限を無視して "SnipSavingTool.ps1" を実行する。

## 3.2 SnipSavingTool.ps1 の中身
### $img = Get-Clipboard -Format Image
- `$img`・・・PowerShellで変数を宣言するとき、またはコマンドなどで使用するときは、変数名の頭に「$」をつける。<sup>[[9]](#4-参考文献)</sup>
- `Get-Clipboard -Format Image`<sup>[[10]](#4-参考文献)[[11]](#4-参考文献)</sup>・・・クリップボード内に保存されている画像データを取得する。
### $img -ne $null
- `A -ne B`<sup>[[12]](#4-参考文献)</sup>・・・AとB等しくないときに「$True」を返す。
### $date_time = Get-Date -Format yyyyMMdd_HHmmss
- `Get-Date -Format yyyyMMdd_HHmmss`<sup>[[13]](#4-参考文献)[[14]](#4-参考文献)</sup>・・・日付と時間を「yyyyMMdd_HHmmss」の形式で取得する。
### $img.Save("$date_time.png")
- `A.Save(B)`・・・AをBに保存する。<sup>[[15]](#4-参考文献)</sup>
### [System.Windows.Forms.MessageBox]::Show()<sup>[[16]](#4-参考文献)[[17]](#4-参考文献)</sup>
指定した形式でメッセージボックスを表示させる。
指定方法は [[17]](#4-参考文献) を参照。

# 4. 参考文献
[1] [ASCII.jp：Windowsの基本機能　クリップボードをさらに活用する](https://ascii.jp/elem/000/004/097/4097413/)
[2] [コマンドプロンプトから PowerShell を実行する - Qiita](https://qiita.com/ww24/items/7d52df13fef5bc54e149)
[3] [if（条件分岐）](https://jj-blues.com/cms/command-if/)
[4] [バッチファイルで引数を使う](https://jj-blues.com/cms/wantto-use-argument-in-bat/)
[5] [start - Windowsコマンド虎の巻](https://windows.command-ref.com/cmd-start.html)
[6] [Cmd - DOS/コマンドプロンプト コマンド一覧 - Programming Field](https://www.pg-fl.jp/program/dos/doscmd/cmd.htm)
[7] [コマンドプロンプト | ラベルの位置へ制御を移す(GOTO)](https://www.javadrive.jp/command/bat/index11.html)
[8] [管理権限を持っていないユーザーで PowerShell スクリプトを実行する](http://www.vwnet.jp/windows/PowerShell/2020072901/SetExecutionPolicy.htm)
[9] [変数について - PowerShell | Microsoft Learn](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_variables?view=powershell-7.2)
[10] [PowerShellメモ　クリップボード操作 - Qiita](https://qiita.com/Kosen-amai/items/2e92c9b1dc19fd12b6f5)
[11] [Get-Clipboard (Microsoft.PowerShell.Management) - PowerShell | Microsoft Learn](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.management/get-clipboard?view=powershell-5.1)
[12] [PowerShell で If 文を利用した条件分岐を行う  |  マイクロソフ党ブログ](https://microsoftou.com/powershell-if/)
[13] [Get-Date (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Learn](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.utility/get-date?view=powershell-7.2)
[14] [【Get-Date】PowerShellで現在の日付や時刻を取得する方法とは？フォーマットの変更は？ | チェシャわら](https://cheshire-wara.com/powershell/ps-cmdlets/system-service/get-date/)
[15] [PowerShell 使い方メモ - Qiita](https://qiita.com/opengl-8080/items/bb0f5e4f1c7ce045cc57)
[16] [PowerShellでメッセージボックスを使う４つの方法 - 適材適所](https://www.tekizai.net/entry/powershell_messagebox_1)
[17] [【PowerShell】MessageBoxを使用する | 秋拓技術学院](https://syutaku.blog/powershell-forms-messagebox/)