フォルダ構成を維持したままサブフォルダ内のアーカイブを連続解凍するPowershellスクリプト

##フォルダ構成を維持したままサブフォルダ内のアーカイブを連続解凍？
こういうフォルダ構成だとする

```text:階層例
フォルダA/
    ├フォルダB/
    │    └フォルダC/
    │         ├ファイルA.zip
    │         └ファイルB.zip
    └フォルダD/
         ├ファイルC.rar
         └ファイルD.7z

```
「フォルダA」内のすべての圧縮ファイルを「フォルダ1」にこんな風に解凍
*フォルダAとフォルダ1は別のルート

```text:解凍後
フォルダ1/
    ├フォルダB/
    │    └フォルダC/
    │         ├ファイルA/   ←「ファイルA」フォルダ
    │         │    ├ ・・・ ←「ファイルA.zip」の中身
    │         │    :
    │         └ファイルB/
    │              ├ ・・・
    │              :
    └フォルダD/
         ├ファイルC/
         │    ├ ・・・
         │    :
         └ファイルD/
              ├ ・・・
              :
```
##スクリプト
```powershell
###ここからダイアログボックス作成用
Add-Type -AssemblyName System.Windows.Forms;
Add-Type -AssemblyName System.Drawing;

$PassInputBox = New-Object System.Windows.Forms.Form;
$PassInputBox.Text = 'Data Entry Form';
$PassInputBox.Size = New-Object System.Drawing.Size(300,200);
$PassInputBox.StartPosition = 'CenterScreen';

$DecryptButton = New-Object System.Windows.Forms.Button;
$DecryptButton.Location = New-Object System.Drawing.Point(70,120);
$DecryptButton.Size = New-Object System.Drawing.Size(75,25);
$DecryptButton.Text = 'Decrypt';
$DecryptButton.DialogResult = [System.Windows.Forms.DialogResult]::OK;
$PassInputBox.AcceptButton = $DecryptButton;
$PassInputBox.Controls.Add($DecryptButton);

$SkipButton = New-Object System.Windows.Forms.Button;
$SkipButton.Location = New-Object System.Drawing.Point(150,120);
$SkipButton.Size = New-Object System.Drawing.Size(75,25);
$SkipButton.Text = 'Skip';
$SkipButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel;
$PassInputBox.CancelButton = $SkipButton;
$PassInputBox.Controls.Add($SkipButton);

$label = New-Object System.Windows.Forms.Label;
$label.Location = New-Object System.Drawing.Point(10,20);
$label.Size = New-Object System.Drawing.Size(280,60);

$textBox = New-Object System.Windows.Forms.TextBox;
$textBox.Location = New-Object System.Drawing.Point(10,80);
$textBox.Size = New-Object System.Drawing.Size(260,20);
$PassInputBox.Controls.Add($textBox);

$PassInputBox.Topmost = $true;

$PassInputBox.Add_Shown({$textBox.Select()});
###ここまでダイアログボックス作成用

	###例で言う「フォルダA」
	$myhome = "E:\CMMOD\###Virus Safe Zone"
	###例で言う「フォルダ1」
	$desthome = "E:\CMMOD\###Extracted"
	
	###Home,Destチェック
	If(-not (Test-Path -Path $myhome)){
		("No home dir	<Error>	" + $myhome) | Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
		Write-Host ("No such home directory = "+$myhome);
		exit;
	}
	If(-not (Test-Path -Path $desthome)){
		("No home dir	<Error>	" + $desthome) | Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
		Write-Host ("No such destination directory = "+$desthome);
		exit;
	}
	
	###グローバル時代なのでUTF-8(BOM)に変更　(文字化けしたらPowerShellのフォントをMSゴシックに変えてください。)
	chcp 65001
	
	###怖いので移動する
	Set-Location -Path $myhome;
	
	###ログをとる
	(Get-Date).ToString() |Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
	"###スタート###" | Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
	
	###Where-Objectでフォルダーは除外する
	Get-ChildItem $myhome -Recurse | Where-Object {-not $_.PSIsContainer} | ForEach-Object -Process {
		###(必要な場合)スキップする条件設定
		If($_.Fullname.Contains("###Old")){
			("Skipped file	<Info>	" + $_.Fullname) | Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
			return;
		}
		
		###DestHomeへのフルパス作成
		$temp = Split-Path -Parent $_.Fullname
		$temp = $temp.Replace($myhome,"");
		$ExtractFullPath = Join-Path -Path $desthome -ChildPath $temp;
		
		###(必要な場合)パス調整
		$ExtractFullPath = $ExtractFullPath.Replace("###downloaded_archives","");
		
		###解凍ファイル名で解凍先フォルダを作る
		$ExtractFullPath = Join-Path -Path $ExtractFullPath -ChildPath $_.BaseName;
		
		###処理するファイルの表示
		Write-Host ("Now Processing file	= "+$_.Fullname);
		Write-Host ("Destination folder	= "+$ExtractFullPath);
		
		###拡張子でコピーと解凍の場合分け
		If($_.Extension -in @('.zip','.rar','.7z')){###拡張子がzip,rar,7zのとき
			$ArchiveInfo = Get-7Zip -ArchiveFileName $_.Fullname;
			If($?){###解凍エラーを検知(するはず)
				If($TRUE -in $ArchiveInfo.Encrypted){###Encrypted
					("Encrypted file	<Info>	" + $_.Fullname) | Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
					###ダイアログのテキストを設定
					$label.Text = 'Enter the password of ' + $_;
					$PassInputBox.Controls.Add($label);
					While(($result = $PassInputBox.ShowDialog()) -eq [System.Windows.Forms.DialogResult]::OK){###パスワードダイアログ表示
						$password = $textBox.Text;
						Write-Host ("Entered Password is "+$password);
						###テキストボックスクリア
						$textBox.Text = "";
						###解凍
						Expand-7Zip -ArchiveFileName $_.Fullname -TargetPath $ExtractFullPath -Password $password;
						If($?){###エラー無く解凍出来たら
						("Decrypt success	<Info>	" + $_.Fullname) | Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
							return;
						}
					}###パスワードダイアログでキャンセル
	   				("Decrypt failed	<Error>	" + $_.Fullname) | Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
				}Else{###Not Encrypted
					Expand-7Zip -ArchiveFileName $_.Fullname -TargetPath $ExtractFullPath;
				}
			}Else{
				Write-Host ("Archive Error");
				("Extract error	<Error>	" + $_.Fullname) | Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
			}
		}Else{###（必要な場合）圧縮ファイルじゃないときコピーする
			robocopy (Split-Path -Parent $_.Fullname) (Split-Path -Parent $ExtractFullPath) $_ /DCOPY:DAT /R:1;
			#Write-Host ("Not Archive!!!");
			#Write-Host ("ExtractFullPath = "+$ExtractFullPath);
		}
	}
	(Get-Date).ToString() |Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
	"###終わり###" | Out-File .\ExtractLog.txt -Encoding UTF8 -Append;
```
###必須環境
1. [7Zip4Powershell](https://github.com/thoemmi/7Zip4Powershell)　([リポジトリ](https://www.powershellgallery.com/packages/7Zip4Powershell/1.12.0))

###使い方
1. UTF-8(BOM有り)でどこかに保存。
2. `$myhome` と `$desthome` を指定。
3. 実行

###特徴
 - Unicode対応（文字化けするときはPowershellのフォントをMSゴシックにしてください）
 - パスワード対応（1つのアーカイブに複数かけたマルチパスワードは非対応）
 - ダイアログでパスワード入力、間違えても無限にリトライ可能
 - イベント（エラー、暗号化ファイル遭遇、複合成功、ファイルを無視）ごとにログ出力（ログファイルは`$myhome`に固定出力）

ちなみに無改造で実行すると次の通り

 - パスに「###Old」を含む場合無視する
 - 解凍先パスに「###downloaded_archives」が含まれていたら「###downloaded_archives」の文字を削除する
 - Extensionが「zip,rar,7z」の時解凍する
 - それ以外のファイルだったらディレクトリを維持してコピーする

##最後に
自分用メモです
初投稿なのでお兄さん許して

こちらの記事を見て作った
https://qiita.com/LightSilver7/items/a2532cc6e33757bb9edb