1
1

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

Last updated at Posted at 2020-06-16

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

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

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

解凍後
フォルダ1/
    ├フォルダB/
    │    └フォルダC/
    │         ├ファイルA/   ←「ファイルA」フォルダ
    │         │    ├ ・・・ ←「ファイルA.zip」の中身
    │         │    :
    │         └ファイルB/
    │              ├ ・・・
    │              :
    └フォルダD/
         ├ファイルC/
         │    ├ ・・・
         │    :
         └ファイルD/
              ├ ・・・
              :

##スクリプト

###ここからダイアログボックス作成用
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 (リポジトリ)

###使い方

  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

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1