LoginSignup
3

More than 3 years have passed since last update.

posted at

Powershellと7zipで拡張子を明示しタイムスタンプを継承してパスワード付き圧縮/解凍をする

今更7-zipのコマンドラインのVBScript
これと同じことをPowershellでもできないか悩んでいたのですが
Powershellでファイルの拡張子をドット抜きで取得する方法 get extensionname without dot /Period
これができたので、VBSと比較的近い形でPowershellで圧縮することができるようになりました。

VBSにはない付加機能 zipファイルのタイムスタンプ承継

このスクリプトは1つのファイルを圧縮することを前提にしています。
このため圧縮するファイルのタイムスタンプを取得して、できあがったzipファイルのタイムスタンプが同一になるようにしています。
このためいちいちファイルを開かなければいつのファイルかわからない、ということがなくなります。

Compress.ps1
#Ver 20190109
$strFileName ="C:\hoge\hoge.txt" # 圧縮する対象のzipファイル
$strPassWord ='Password' #呪文
$7zip="C:\Program Files\7-Zip\7z.exe" #7zipのある場所
if((Test-Path $strFileName) -eq $true){
$ofile = Get-childItem -Path $strFileName #ファイルの存在をテスト
if($ofile.PSIsContainer-eq $false){ #ファイルかフォルダか確認
if([string]::IsNullOrEmpty($ofile.extension)){Write-Host "no extention";$strExtension='' #拡張子がなければNullStringを返す
}Else{
$strExtension = ( $ofile.extension.Substring(1,$ofile.extension.Length-1)) ;
Write-Host $strExtension
}
$strBasename= $ofile.BaseName
$strParent= $ofile.DirectoryName
$strNewFileName =(Join-Path $strParent $strBasename)
$strNewFileName += "_"
$strNewFileName += $strextension
$strNewFileName += ".zip"
#Get File timestamp
$DTCr = $ofile.CreationTime
$DTMd = $ofile.LastWriteTime
$DTAc = $ofile.LastAccessTime
Write-Host $strNewFileName
#すでにzipファイルがあるときはskipする
if((Test-Path $strNewFileName) -eq $False){
# 7-Zipのコマンドライン引数を生成
$Arg=" a -y  -p" + $strPassWord + " "+ $strNewFileName +" "+ $ofile.FullName

# 7-zipで圧縮
Start-Process -Wait $7zip -Verb runas -ArgumentList $Arg -WindowStyle Minimized
$ofile = (get-childitem $strNewFileName)
# Set zip file timestamp
$(get-childitem $ofile.FullName).CreationTime=$DTCr
$(get-childitem $ofile.FullName).LastWriteTime=$DTMd
$(get-childitem $ofile.FullName).LastAccessTime=$DTAc
}
} #if($ofile.PSIsContainer-eq $false)
} #if((Test-Path $strFileName) -eq $true)

参考先との埋めがたい実力差

PowerShellと7zipでファイルを圧縮
ここを参考にしているのだが、うまく動かない。

動かない点その1 圧縮オプション

これの

-mem=AES256 

というのはなぜか有効ではなかった。64bitだからだろうか?

動かない点その2 7z.exeの場所の取得


$path=Split-Path ( & { $myInvocation.ScriptName } ) -parent

これもダメだった。このため上記コードでは直接実行ファイルのフルパスを書いている。

動かない点その3 管理者モード

Start-Process $7zip -Verb runas -ArgumentList $Arg

これは絶対わからない... -Verb runas が管理者として実行になります。しかしこれはなくても動きます。

解凍

ps_Extractwith7zip.ps1
#Ver 20190109
$strFileName ="C:\hoge\hoge_txt.zip" # 解凍する対象のzipファイル
$strPass = "Password" #呪文
$7zip ="C:\Program Files\7-Zip\7z.exe" #7z.exeのフルパスを記載してください
if((Test-Path $strFileName) -eq $true){
$ofile = Get-childItem -Path $strFileName #ファイルの存在をテスト
#$strParent = $ofile.PSParentPath.Replace("Microsoft.PowerShell.Core\FileSystem::","")
$strParent=$ofile.DirectoryName
$commandstring = " x -y -p" + $strPass + " " + $strFileName + " -o" +"""" + $strParent +"""" + " -aoa" #問答無用で同名のファイルを上書きする。
Start-Process $7zip -Wait -Verb runas -ArgumentList $commandstring -WindowStyle Minimized
}

-aoスイッチ

-ao (Overwrite mode) switch
-aos Overwrite All existing files without prompt.問答無用で上書き -yスィッチもいれると問答無用度が増す
-aos Skip extracting of existing files. 上とは逆で同名のファイルがあればスキップ。
-aou aUto rename extracting file (for example, name.txt will be renamed to name_1.txt).
同名のファイルがあれば既存のファイルに枝番を付す
-aot auto rename existing file (for example, name.txt will be renamed to name_1.txt).
同名のファイルがあればいまから解凍しようとするファイルに枝番を付す。
普通の枝番をつける方法はこれ。 -aouはちょっと珍しいし、既存のファイルの方をいじるのは感心しない。

-oについて

この後ろが出力先フォルダですが、どこにも書いていないけど、スペースが入っているフォルダの場合はダブルクォーテーションで囲んだ方がよいようです。

参考

17.ファイルの存在するディレクトリパスを取得する

VBS版

こちらに記載しています。
https://qiita.com/Q11Q/items/0d0d41fb858407a74212

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
What you can do with signing up
3