Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Monday, July 14, 2014 8:11 PM
I've been reading and experimenting with a number for forums, solutions, and technet articles. What I haven't found yet is a method/mode to allow me to unzip an archive that has multiple files with the same filename.
I have system generated zip files that have multiple files that have the same filename. They are indeed different files though.
Some folks have provided some really great resources and examples of how to use system.io.compression, but I haven't found the answer to my problem.
I 'think' if it were possible, I would find it here.
http://msdn.microsoft.com/en-us/library/system.io.compression.zipfile_methods%28v=vs.110%29.aspx
I found this article that makes it seem like I should switch to using the cli version of 7zip.
http://social.technet.microsoft.com/Forums/windowsserver/en-US/8f98f06e-79fe-401c-92f0-a548d4304dcc/how-to-zip-files-and-folders-using-powershell?forum=winserverpowershell
Ultimately, my goal via powershell is to:
unzip the file from in a PS script
Make it non user interactive.
Have it answer 'Y' to any prompts that may be issued
rename all duplicate filename's automatically just as in a manual extraction.
It would seem that if the functionality exists in the OS, .NET 4.5 would expose it to PS 3.
The closest hint to how to do this is using vOption as referenced in this page:
http://www.howtogeek.com/tips/how-to-extract-zip-files-using-powershell/
When I tried that it did some really amazing things, just not 'good' amazing things. (That example showed for java I believe)
Thanks for any ideas, especially links to better documentation that allows me to see how this is done.
-= Bruce D. Meyer
All replies (13)
Wednesday, July 16, 2014 4:41 AM ✅Answered | 2 votes
So there are probably much more efficient ways to do this, but this seems to be working for me now:
Add-Type -AssemblyName System.IO.Compression.FileSystem
$extractDir = 'C:\Scripting\Testing\7-16-2014\TEST'
$zip = [System.IO.Compression.ZipFile]::OpenRead('C:\Scripting\Testing\7-16-2014\TEST\file.zip')
foreach ($item in $zip.Entries) {
try {
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($item,(Join-Path -Path $extractDir -ChildPath $item.FullName),$false)
} catch {
$count = 0
$extension = $item.FullName.Substring($item.FullName.LastIndexOf('.'))
$fileName = $item.FullName.Substring(0,$item.FullName.LastIndexOf('.'))
$found = $false
do {
if (!(Test-Path (Join-Path -Path $extractDir -ChildPath "$fileName ($count)$extension"))) {
$found = $true
} else {
$count++
}
} until ($found -eq $true)
$newFileName = "$fileName ($count)$extension"
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($item,(Join-Path -Path $extractDir -ChildPath $newFileName),$false)
}
}
Don't retire TechNet! - (Don't give up yet - 12,950+ strong and growing)
Wednesday, July 16, 2014 3:26 PM ✅Answered | 1 vote
Hi Bruce,
Here's the same code with some comments to explain what's going on:
# Load the required assembly.
Add-Type -AssemblyName System.IO.Compression.FileSystem
# Set the directory to extract the zip file to.
$extractDir = 'C:\Scripting\Testing\7-16-2014\TEST'
# Open the specified zip file.
$zip = [System.IO.Compression.ZipFile]::OpenRead('C:\Scripting\Testing\7-16-2014\TEST\file.zip')
# Loop through each item contained in the zip file.
foreach ($item in $zip.Entries) {
# Attempt to unzip the file. If a file with the same name already exists, jump to the catch block.
try {
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($item,(Join-Path -Path $extractDir -ChildPath $item.FullName),$false)
} catch {
# If we're here, that means that a file already exists with the same name as the file that's being unzipped.
# To work around this, we'll figure out what number can be appended to the name to make it unique.
# The new file name structure I'm using is <filename><space><open paren><number><close paren><dot><extension>.
# You can change this if desired.
# Set a counter for file naming.
$count = 0
# Get the extension of the file that is being unzipped.
$extension = $item.FullName.Substring($item.FullName.LastIndexOf('.'))
# Get the name of the file that is being unzipped.
$fileName = $item.FullName.Substring(0,$item.FullName.LastIndexOf('.'))
# Testing flag.
$found = $false
# Loop until the $found flag is set to $true.
do {
# Test if a file already exists with the new file name, based on the value currently in $count.
#
if (!(Test-Path (Join-Path -Path $extractDir -ChildPath "$fileName ($count)$extension"))) {
# File doesn't exist, so set the $found flag to $true.
$found = $true
} else {
# File does exist, so increment $count and try again.
$count++
}
} until ($found -eq $true)
# Set variable with the new file name to use.
$newFileName = "$fileName ($count)$extension"
# Unzip the file with the new name.
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($item,(Join-Path -Path $extractDir -ChildPath $newFileName),$false)
}
}
Also, you're very welcome. This was a good exercise for me to learn a few new things, as I've never actually used the ZipFileExtensions class until now.
Don't retire TechNet! - (Don't give up yet - 12,950+ strong and growing)
Monday, July 14, 2014 8:41 PM
Have you tried unzipping a file using this?
[System.IO.Compression.ZipFile]::ExtractToDirectory("C:\temp\zipfile.zip","C:\temp\extractdir")
EDIT: Oh, and that assembly isn't loaded into Powershell by default - you need to do this first:
Add-Type -AssemblyName System.IO.Compression.Filesystem
Monday, July 14, 2014 8:45 PM
Yes. It gives me this error:
WARNING: Unexpected Error. Error details: Exception calling "ExtractToDirectory" with "2" argument(s): "The file 'H:\Images\Windows\test_12345\mir.urlhistory.xml' already exists.".Except
ion.Message
Monday, July 14, 2014 8:52 PM
Are you extracting a single zip file to that directory, or more than one? I'd imagine that the ZipFile class retains folder structure when extracting an archive, so receiving that error seems a bit odd to me - an archive, as far as I know, follows the same rules as the file system, which means that a full file path must be unique.
Monday, July 14, 2014 9:00 PM
I've attached a screenshot. It is a single zip file. Inside the zip file four of the files shown have the exact same name. The way I have handled this prior to attempting to script it, is to select 'Keep Both Copies, rename, repeat for the rest.,' (Second attachments shows the options I use with windows explorer)
It is a single archive
Tuesday, July 15, 2014 3:08 AM
Hi,
It looks like you might have to stick with Shell.Application to force the automatic renaming. Try using 24 as the vOptions (8 + 16):
$shell = New-Object -ComObject Shell.Application
$zip = $shell.NameSpace('C:\Scripting\Testing\7-14-2014\TEST\file.zip')
foreach ($item in $zip) {
$shell.Namespace('C:\Scripting\Testing\7-14-2014\TEST').CopyHere($item,24)
}
This adjustment of the code you linked to above worked for me in my testing, but I wasn't actually able to create a zip file with multiple files of the same name inside of it for testing purposes.
One thing to note though - Shell.Application doesn't always (or often) play well with being scheduled.
Don't retire TechNet! - (Don't give up yet - 12,950+ strong and growing)
Tuesday, July 15, 2014 4:27 PM
I tried adapting your example to my code. and it kept making a copy of the zip file.
test_12345 - Copy.zip
test_12345.zip
I then copied and pasted your example, and deleted all preceding code so the entire prgram is nothing more than your example to rule out any of my previous stuff. I then replaced the path/name with my own with the same results.
At least I am learning quite a bit from the trial and error.
My first time through was trying to do this without using a foreach loop which at least extracted the files. The closes I cam so far was extracting the files, and popping up an offer to rename and do the same for the remaining items.
Below is how I tried to write it without a foreach which gave the same results.
Obviously I am a n00b with PS.
-= Bruce
# Get the case name which will be used for the folder names.
$caseName = Read-Host "Enter Case Name for directory to parse [Press Enter]"
$caseDrive = "H:\Images\Windows\+$caseName
if(!(Test-Path -Path $caseName))
{
Write-Host -ForegroundColor Green "`n`nDirectory name $caseName exists, Good to go."
}
else
{
Write-Host -ForegroundColor Red "`n`nDirectory name $caseName does not exist, back-up and punt."
exit;
}
Write-Host "Renaming $caseDrive\_Audit_Script_*.zip $caseDrive\caseName.zip"
Move-Item $caseDrive\_Audit_Script_*.zip $caseDrive\caseName.zip
$caseZip = "$caseDrive\caseName.zip"
Write-Host "Unzipping: $caseZip"
# UnZipper($file, $destination)
# Unzip-File -File $caseDrive\caseName.zip -Destination $caseDrive
$shell.Namespace($caseDrive).CopyHere($caseZip,24)
Write-Host -ForegroundColor Yellow " Unzipping complete.`n"
Tuesday, July 15, 2014 5:39 PM
Give this basic tester a try and see if it works on your test zip:
$zipFile = 'C:\Path\To\ZipFile.zip'
$extractTo = 'C:\Path\To\Extract\To'
$shell = New-Object -ComObject Shell.Application
$zip = $shell.NameSpace($zipFile)
foreach ($item in $zip) {
$shell.Namespace($extractTo).CopyHere($item,24)
}
Don't retire TechNet! - (Don't give up yet - 12,950+ strong and growing)
Tuesday, July 15, 2014 8:11 PM
This was interesting. The first time I ran it, no errors, nothing happened.
So I changed the extract to dir to a different one. What happened is it copies the zip file (without extracting) to the unique extract dir.
Here is what I had, and changed:
$zipFile = 'H:\Images\Windows\test_12345\test_12345.zip'
# Original
# $extractTo = 'H:\Images\Windows\test_12345'
# Changed to:
$extractTo = 'H:\Images\Windows\testout'
$shell = New-Object -ComObject Shell.Application
$zip = $shell.NameSpace($zipFile)
foreach ($item in $zip) {
$shell.Namespace($extractTo).CopyHere($item,24)
}
Tuesday, July 15, 2014 8:14 PM
If this helps any, here is the 7za -l structure of the archive I am using:
PS H:\Images\Windows\test_12345> 7za l test_12345.zip
7-Zip (A) 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18
Listing archive: test_12345.zip
--
Path = test_12345.zip
Type = zip
Physical Size = 57314008
Date Time Attr Size Compressed Name
1980-01-01 00:00:00 ..... 4777 1598 mir.w32system.xml
1980-01-01 00:00:00 ..... 2430 793 mir.w32volumes.xml
1980-01-01 00:00:00 ..... 482 321 Module Issues - issues.mir.w32volumes.xml
1980-01-01 00:00:00 ..... 4950 925 mir.w32network-dns.xml
1980-01-01 00:00:00 ..... 20162 2360 mir.w32ports.xml
1980-01-01 00:00:00 ..... 1840 521 mir.w32disks.xml
1980-01-01 00:00:00 ..... 489 322 Module Issues - issues.mir.w32disks.xml
1980-01-01 00:00:00 ..... 6111 1185 mir.w32useraccounts.xml
1980-01-01 00:00:00 ..... 8951 976 Module Issues - issues.mir.w32useraccounts.xml
1980-01-01 00:00:00 ..... 18634 2220 mir.w32network-arp.xml
1980-01-01 00:00:00 ..... 18956 1886 mir.w32network-route.xml
1980-01-01 00:00:00 ..... 1504797 135194 mir.w32prefetch.xml
1980-01-01 00:00:00 ..... 16230400 1672007 mir.w32scripting-persistence.xml
1980-01-01 00:00:00 ..... 256105 12403 Module Issues - issues.mir.w32scripting-persistence.xml
1980-01-01 00:00:00 ..... 444456795 25271008 mir.w32eventlogs.xml
1980-01-01 00:00:00 ..... 42300 3045 Module Issues - issues.mir.w32eventlogs.xml
1980-01-01 00:00:00 ..... 133391 14621 mir.w32tasks.xml
1980-01-01 00:00:00 ..... 2913 673 Module Issues - issues.mir.w32tasks.xml
1980-01-01 00:00:00 ..... 317812 44329 mir.w32services.xml
1980-01-01 00:00:00 ..... 32604 1472 C__Windows_Tasks_SCHEDLGU.TXT
1980-01-01 00:00:00 ..... 11469940 471392 C__WINDOWS_INF_SETUPAPI.APP.LOG
1980-01-01 00:00:00 ..... 1699695 144530 mir.w32apifiles.xml
1980-01-01 00:00:00 ..... 32077 3831 Module Issues - issues.mir.w32apifiles.xml
1980-01-01 00:00:00 ..... 1131 593 C__Windows_SYSTEM32_DRIVERS_ETC_HOSTS
1980-01-01 00:00:00 ..... 334 193 mir.w32systemrestore.xml
1980-01-01 00:00:00 ..... 432 273 Module Issues - issues.mir.w32systemrestore.xml
1980-01-01 00:00:00 ..... 786432 151107 C__Users_admin_NTUSER.DAT
1980-01-01 00:00:00 ..... 1048576 183146 C__Users_Administrator_NTUSER.DAT
1980-01-01 00:00:00 ..... 9437184 1981741 C__Users_bdmeyer_NTUSER.DAT
1980-01-01 00:00:00 ..... 262144 46842 C__Users_Default_NTUSER.DAT
1980-01-01 00:00:00 ..... 2621440 559772 C__Users_LocalAdmin_NTUSER.DAT
1980-01-01 00:00:00 ..... 262144 600 C__Users_Public_ntuser.dat
1980-01-01 00:00:00 ..... 262144 599 C__Users_TEMP_ntuser.dat
1980-01-01 00:00:00 ..... 262144 18774 C__Windows_System32_config_SAM
1980-01-01 00:00:00 ..... 262144 6572 C__Windows_System32_config_SECURITY
1980-01-01 00:00:00 ..... 93061120 20381660 C__Windows_System32_config_SOFTWARE
1980-01-01 00:00:00 ..... 22020096 4912283 C__Windows_System32_config_SYSTEM
1980-01-01 00:00:00 ..... 3057294 233720 mir.filedownloadhistory.xml
1980-01-01 00:00:00 ..... 12756 975 Module Issues - issues.mir.filedownloadhistory.xml
1980-01-01 00:00:00 ..... 1645822 174081 mir.cookiehistory.xml
1980-01-01 00:00:00 ..... 10784 800 Module Issues - issues.mir.cookiehistory.xml
1980-01-01 00:00:00 ..... 10942 1711 mir.formhistory.xml
1980-01-01 00:00:00 ..... 11179 833 Module Issues - issues.mir.formhistory.xml
1980-01-01 00:00:00 ..... 43965 4389 mir.urlhistory.xml
1980-01-01 00:00:00 ..... 1626 405 Module Issues - issues.mir.urlhistory.xml
1980-01-01 00:00:00 ..... 9882131 845406 mir.urlhistory.xml
1980-01-01 00:00:00 ..... 1970 405 Module Issues - issues.mir.urlhistory.xml
1980-01-01 00:00:00 ..... 14400 2918 mir.urlhistory.xml
1980-01-01 00:00:00 ..... 3545 484 Module Issues - issues.mir.urlhistory.xml
1980-01-01 00:00:00 ..... 319 190 mir.urlhistory.xml
1980-01-01 00:00:00 ..... 7026 736 Module Issues - issues.mir.urlhistory.xml
1980-01-01 00:00:00 ..... 106048 7148 bdmeyer-win7u64_ Acquisition with script DSIT_Audit_Script for bdmeyer-win7u64 - batchresults.xml
621363883 57305968 52 files, 0 folders
You'll see there are 4 files name mir.urlhistory.xml
Tuesday, July 15, 2014 8:34 PM
So I changed the extract to dir to a different one. What happened is it copies the zip file (without extracting) to the unique extract dir.
Yep, you're right about this. I missed .Items() on $zip in the foreach loop.
Seems like I'm still getting prompted to overwrite after making that adjustment, I'm poking at it to see if I can make it actually work properly now.
EDIT: Perhaps this isn't going to work, no matter what flags are set:
http://mattclingan.wordpress.com/2007/08/08/unzip-and-the-copyhere-command-with-vuseless-voptions/
0x8 works just fine. 0x10 doesn't...
Don't retire TechNet! - (Don't give up yet - 12,950+ strong and growing)
Wednesday, July 16, 2014 1:24 PM
Wow. That works.
I don't understand what is happening. Would you mind explaining what your code is doing?
I have some Get-Help exploring to do.
Thank you for your tireless help with this Sir. Is this a problem with something in powershell not exposing .net properly that makes this such an arduous task?
-= Bruce