##フォルダ構成を維持したままサブフォルダ内のアーカイブを連続解凍?
こういうフォルダ構成だとする
階層例
フォルダ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;
###必須環境
###使い方
- UTF-8(BOM有り)でどこかに保存。
-
$myhome
と$desthome
を指定。 - 実行
###特徴
- Unicode対応(文字化けするときはPowershellのフォントをMSゴシックにしてください)
- パスワード対応(1つのアーカイブに複数かけたマルチパスワードは非対応)
- ダイアログでパスワード入力、間違えても無限にリトライ可能
- イベント(エラー、暗号化ファイル遭遇、複合成功、ファイルを無視)ごとにログ出力(ログファイルは
$myhome
に固定出力)
ちなみに無改造で実行すると次の通り
- パスに「###Old」を含む場合無視する
- 解凍先パスに「###downloaded_archives」が含まれていたら「###downloaded_archives」の文字を削除する
- Extensionが「zip,rar,7z」の時解凍する
- それ以外のファイルだったらディレクトリを維持してコピーする
##最後に
自分用メモです
初投稿なのでお兄さん許して
こちらの記事を見て作った
https://qiita.com/LightSilver7/items/a2532cc6e33757bb9edb