拡大鏡を最悪Windowsから徹底的に永遠に除去する

# 拡大鏡を農場へ

ご存知の方も多いと思いますが、Windowsには拡大鏡という機能があります。
あること自体はとても良いことです。きっと誰かの役に立っているのだから。

問題はただ一つ、ショートカットキー `Windows + ;`にあります。
`;` は `L`の隣にあり、私の小さな手では~~君さえ守れない~~業務においてはよく使う`Windows + L`を押そうとして頻繁に押し間違えてしまいます。
しかもロックする時は緊急事態のことも多いので余計に困ります。辛い…。

心底困り果てていた時、救世主のことき以下の記事に出会い、私は拡大鏡を農場送り[^1]にし、毎日@aokomoriutaさんに感謝の祈り~~と血~~を捧げ、幸せな生活を送ることが出来ていた――はずでした。
[^1]: http://mtgwiki.com/wiki/%E8%BE%B2%E5%A0%B4%E9%80%81%E3%82%8A

https://qiita.com/aokomoriuta/items/55f7db8712f5c35e2d0f

# 拡大鏡は滅びぬ、何度でも読るさ！
ある日のこと、いつものように`L`と`:`を押し間違えた私は、かつて倒したはずの拡大鏡が起動してきたことに、心底驚き、慌て、困惑してしまいました。
中途半端に記憶に残っているホラーゲームを再度プレイする時に、「ここは何もないだろう」と無警戒に通り抜けた通路で幽霊が出てきて、初見時よりも悲鳴をあげるのと同じ現象です。

前述の記事の手順をもう一度やろうと思いましたが、ふと「このまま拡大鏡とMicroSoftの影に怯えて暮らすのだろうか…」という気持ちも芽生えました。
とはいえ定期的に手動で確認するのもめんどくさい…。
見つけた時に同じ手順をやるのもめんどくさい…。
そうだ、機械を動かせ、機械は疲れない。
よろしい、ならば戦争だ。

というわけでC#の勉強がてら対拡大鏡最終兵器を作ってみることにしました。
これをログオン時に自動実行させましょう。

# メインシステム、戦闘モード起動します
```CSharp
	internal static void Main(string[] args)
	{
		const string Magnify = @$"C:\Windows\system32\Magnify.exe";
		if (!File.Exists(Magnify))
		{
			return;
		}

		const string TakeownCommand = @$"takeown /F {Magnify} /A";
		const string IcacisCommand = @$"icacls {Magnify} /grant Administrators:F /C";
		// 1日に何度も起こることではないので実行日付だけで一意になる想定
		var renameCommand = @$"rename {Magnify} {Path.GetFileName(Magnify)}{DateTime.Today:yyyyMMdd}";		  
		var response = RunCmd([TakeownCommand, IcacisCommand, renameCommand]);

		Console.WriteLine(response);
		Console.WriteLine("拡大鏡が勝手に復活していたため、最悪windowsから徹底的に永遠に除去しました。");
		Console.WriteLine("オールマインドはすべての開発者のためにあります。");
		Console.ReadKey();
	}

	/// <summary>
	/// コマンドプロンプトを実行する
	/// </summary>
	/// <param name="commandList“>コマンドー覧</param>
	/// <returns>標準出力内容</returns>
	private static string? RunCmd(IEnumerable<string> commandList)
	{
		var processInfo = new ProcessStartInfo()
		{
			FileName = "cmd",
			Arguments = $" /c {string.Join(" && ", commandList)}",
			// コンソールを起動しない
			CreateNoWindow = true,
			UseShellExecute = false,
			// 標準出力をリダイレクトする
			RedirectStandardOutput = true
		};

		var process = Process.Start(processInfo);
		var response = process!.StandardOutput.ReadToEnd();

		process.WaitForExit();
		process.Close();
		return response;
	}
```

それでは、史上最大の対拡大鏡最終兵器を、これからとっくりと種明かししてしんぜようか。
といってもそれほど解説することもないですが…。

### takeown

上記の記事にあるので省略。

### icacls
アクセス権をどうのこうのするコマンドです。
`grant[:r] <sid>:<pern>`でアクセス権を与えます。英単語そのままですね（`grant`は付与するという意味。余談ながら神の恩寵を表す`grace`とごっちゃになってしまいます…）。

`:r`をつければ追加する代わりに置換します。今回はどうせフルコントロールなので同じことです。

`<sid>`はアクセス権を追加したいユーザーのセキュリティ識別子です（セキュリティ識別子は`whoami`コマンドで確認できます）。`Administrators`とか`Everyone`みたいなエイリアスも使えます。今回は`Administrators`を指定してあげます。

`<perm>`は与える権限です。基本的なのは以下の通り。
```
F ：フルコントロール
M ：変更アクセス
RX：読み取りと実行アクセス
R ：読み取り専用アクセス
W ：書き込み専用アクセス
```

ちなみに`grant`を`deny`に変えればアクセス権を拒否できます（`:r`は使えない）。

`/C`はエラーが発生しても処理続行（エ、エラーメッセージは表示してあげるんだからね！///）というオプションです。

他にもいろいろあるので詳しくは公式ドキュメントを見てね！

https://learn.microsoft.com/ja-jp/windows-server/administration/windows-commands/icacls

### rename

文字通りファイル名を変更するコマンドです。
リネーム後は`Magnify.exe.yyyyMMdd`となります。秒まで入れればより確実に一意になりますが、美しくないので却下。

### Process.Start

プロセスを起動します。
`ProcessStartInfo`でコマンドライン引数とかを設定します。
別のコンソールが起動しないようにしてすべてが終わったらC#側のコンソールに流します。

# 拡大鏡「その大砲で私と勝負するかね」
さて、準備は出来ました。デバッグしてみましょう。
**焼き払え！**

![焼き払え.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115881/1f475309-76b5-8b71-e67d-66af412a1e88.png)

おや？効いているように見えません。
**どうした、それでもこの世で最も邪悪な一族の末裔か！**

![どうした.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115881/33405e11-8f8c-0075-ce5c-f4c93d22c233.png)

やはり効いていません。
どうして…。
**助けて…真乃…めぐる…！**

# より高く飛ぶのは...私だ！

*――ホームズ「初歩的なことだよ、ワトスン君」*[^Holmes]
[^Holmes]: 正典では言ってない台詞。しかし解像度は高い。私がコードレビューする時や質問に答える時によく使うフレーズでもある。

さて、もう一度@aokomoriutaさんの記事を確認すると

> **管理者権限**でコマンドプロンプトを起動

(太字は筆者)

とあります。そういえばそうでした…。
こんな簡単なことを見落とすなんて、私としたことが。

ここで取るべき方法は2つあります。

1. Visual Studioを管理者権限で起動する
1. C#からコマンドプロンプトを起動するときに管理者権限で起動する

一見すると後者の方が良さげに見えますが、コマンドプロンプトが起動される度に手動で許可を与えなければなりません。それはめんどくさい。
ログオン時に勝手に走って、除去したら事後報告を聞けばよいのです。なので1を採用。

管理者権限で起動してデバッグすると…。

**100…110…115… レールキャノン最大出力
これで決める…！**

![これで決める.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115881/7300dcf5-abdf-c382-1414-07347ae52321.png)

![これで決める2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115881/be3d921b-477f-c716-0ad6-95a428f90556.png)


無事決まりましたね。流石は戦友。
あとはこれをタスクスケジューラーでログオン時に走るようにするだけです。
`最上位の特権で実行する`をチェックしておくのを忘れずに。

~~別に最悪Windowsから徹底的に永遠に除去[^awol]してなくない？~~
~~まああれだってゲームが終わったら使えるようになるんだし…~~

[^awol]: http://mtgwiki.com/wiki/%E6%9C%80%E6%82%AA%E3%82%B2%E3%83%BC%E3%83%A0%E3%81%8B%E3%82%89%E5%BE%B9%E5%BA%95%E7%9A%84%E3%81%AB%E6%B0%B8%E9%81%A0%E3%81%AB%E9%99%A4%E5%8E%BB

# 冬の心はのどけからまし[^spring]
[^spring]: 「なきさの院にてさくらを見てよめる／世中にたえてさくらのなかりせは春の心はのとけからまし（古今和歌集53番、在原業平朝臣）」

さよなら、拡大鏡。
さよなら、Magnify.exe。
もう二度と会うことはないでしょう。

いま私は、とても幸福だ。

とても。

とても。