I have a nested folder structure for example like this (it's a lot more for simplicity I put an example)
- folder1
- folderA
a.zip
- folderB
b.zip
I want to unzip all zip files in same folder and delete the original zip file.
so my expected output is like
- folder1
- folderA
- a
files in a.zip
- folderB
- b
files in b.zip
I can get list of all zip files by Get-ChildItem '.' -R -Filter *.zip
command
Then also I can pipe it to unzip like
Get-ChildItem '.' -R -Filter *.zip | Expand-Archive -Force -DestinationPath c:\a
which giving a fixed destination path Also I can able to get the folder name of each zip file by
Get-ChildItem '.' -R -Filter *.zip | select -ExpandProperty DirectoryName
also I tried
Get-ChildItem '.' -R -Filter *.zip | Expand-Archive -Force -DestinationPath $_.DirectoryName
and
Get-ChildItem '.' -R -Filter *.zip | Expand-Archive -Force -DestinationPath %{$_.DirectoryName}
also
Get-ChildItem '.' -R -Filter *.zip | Expand-Archive -Force -DestinationPath {$_.DirectoryName}
But I can't find a way to pass the DirectoryName to Expand-Archive command
CodePudding user response:
I found the solution in case someone else has same issue
Get-ChildItem '.' -R -Filter *.zip | ForEach-Object {
Expand-Archive $_.FullName "$($_.DirectoryName)/$($_.Basename)" -Force
Remove-Item $_.FullName
}
CodePudding user response:
You can call the Directory
property of the FileInfo
objects outputted by Get-ChildItem
to get the DirectoryInfo
object of the parent folder of these files, then you can call the FullName
property of the parents to get the destination folder.
In theory, this could work using -PipelineVariable
instead of a ForEach-Object
loop but I haven't personally tested it.
$ErrorActionPreference = 'Stop'
Get-ChildItem '.' -R -Filter *.zip | ForEach-Object {
try {
Expand-Archive -LiteralPath $_.FullName -DestinationPath $_.Directory.FullName -Force
Remove-Item -LiteralPath $_.FullName
}
catch {
Write-Warning $_.Exception.Message
}
}