How to expand ZIP archive using PowerShell (UTF-8 filenames) - windows

My zip archive has a single file:
Père-Noël.txt
The zip expands nicely with Windows File Explorer, 7-Zip or any other tool I've tried. But I cannot figure out how to do it from PowerShell. Obviously I've tried Expand-Archive but it cannot handle the file name and garbles it into PŠre-N”el.txt. Note: The problem isn't specifically with this example, but indeed with any file name which uses characters outside of the ASCII-127 range. Or so it seems.
Any solution which uses PowerShell and which doesn't rely on an external tool - whose presence cannot be guaranteed - will be accepted. Windows 10 is the platform. I cannot do system-level changes and cannot rely on users of the script having any specific global setting on their system. It has to be a solution within the script.
Is there another way, besides Expand-Archive ? Or is there a setting in PowerShell which will magically do the trick?
Steps to reproduce:
On your Windows 10 host:
Create an empty file named Père-Noël.txt.
ZIP the file using Windows Explorer ("Compressed Folders" feature) into an ZIP archive of your choice, say myarchive.zip.
Delete the Père-Noël.txt file.
Now try to unpack the myarchive.zip using PowerShell. This operation should create the file Père-Noël.txt again.
Compressing using PowerShell Compress-Archive cmdlet
True, if the ZIP was originally created using Compress-Archive cmdlet then it actually works as intended when decompressing using Expand-Archive. So you can say that PowerShell is compatible with itself. It is just not compatible with Windows Explorer ZIPs.

You'll likely need to check the encoding [System.Text.Encoding]::GetEncodings() but the below works with your example Père-Noël
$zipfile = 'C:\test\Père-Noël.zip' #Contains Père-Noël.txt
$outpath = 'C:\test\out'
$enc = [System.Text.Encoding]::GetEncoding(29001) #29001, x-Europa, Europa
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath, $enc)
Hope this helps,

Although we arrived in 2021 I stumbled upon the same problem.
Like the accepted answer my solution is based on the System.IO.Compression namespace.
The expand-archive command accepts pipeline-input and a -Force switch.
I had the same goals for my implementation - still in work and not thoroughly tested.
$encoding = [System.Text.Encoding]::GetEncoding(437)
Write-Output $encoding
Get-ChildItem -Path ".\*.zip" | Unzip -target "C:\unzipped" -f -encoding $encoding -v
Find unzip function here

It's similar to the accepted answer but I like this answer better:
[System.IO.Compression.ZipFile]::ExtractToDirectory("$pwd/test.zip", "$pwd", [System.Text.Encoding]::GetEncoding((Get-Culture).TextInfo.OEMCodePage)
source

Related

How to use short-cut paths to Compress-Archive to zip current folder into same destination

I am using Compress-Archive and want to zip the current directory into the same path. However I do not want to have to type out the entire file path both times. Is there an easy way to do this?
I am using windows 10 pro.
This works for the most part Compress-Archive . test.zip but I want it to be on the same level as the current directory so I need to put it back one spot.
Something like this is what I want:
path/test
path/test.zip
What I am getting:
path/test
path/test/test.zip
It is going inside the actual folder which is not what I want
You propably want that:
Compress-Archive * ..\test.zip
The wildcard * avoids that the name of the folder is put inside the zip.
Using .. for the output path we go one level up in the directory tree.
This command will fail if test.zip already exists. Either add parameter -update to update the archive or add -force to overwrite the archive. Both can be used even if the archive does not already exist.
If the current working directory is "t", it can be included using the following command. I would note that I do not think putting the destination .zip file in the directory being compressed is a good idea.
Compress-Archive -Path $(Get-ChildItem -Recurse -Exclude t.zip) -DestinationPath .\t.zip -Force
It is shorter if you are willing to use aliases and cryptic switches.
Compress-Archive $(gci -r -e t.zip) .\t.zip -Force
If I have misinterpreted your situation, please leave a comment or improve the information provided by editing the question.

How to search through folders for a certain file using Powershell

I am writing an uninstall script for Office using Powershell. I need the script to search through:
C:\windows\ccmcache\
There are a number of folders in there. Is there a way to find which folder has the contents that I am looking for? So let's say I am looking for a folder that contains:
office.en-us
office64.en-us
and so on. How can I return that exact path? Because that is where I am running the uninstall from but the catch is I don't know what folder Office is in the ccmcahce folder.
Thank you all in advance.
No loop needed.
dir "C:\windows\ccmcache\*\Office.en-us" -Directory
Note that dir is an alias for Get-ChildItem.
#Tomalak when running the code you posted it works if there aren't a large number of files and folders to sort through, but if you really have no idea where the file or folder you're looking for lives at then specifying a -recurse parameter would be helpful
Get-Childitem "C:\*\Office.en-us" -Recurse
While this is sometimes necessary (in this case it doesn't seem to be), it can take an extended amount of time to run if there are large folders to sort through...

Windows 10 - how to compress file without creating a parent folder

In Windows 10,
from power shell, I want to compress a folder without it creating a parent folder inside the zip file
currently I use:
Compress-Archive -Path . ../abc.zip
Is it possible to create the archive without the parent folder?
You might try this (didn't test it and I don't even have any window installed, so might not work):
gci c:\folder\* | Compress-Archive -DestinationPath c:\abc.zip

Advice on script to mklink to NAS directory, copy system restore files over, and then rmdir on Win 7 Pro 64 (language and syntax)

I'm in a small business environment (Win 7 Pro 64 workgroup, single LAN) where I would like to be able to run a script that would make a link on the local machine to a folder on our NAS, copy system restore files, then remove the link. The objective is to isolate system restores as an added layer of protection, this process ideally includes severing direct links to the NAS from any user machine unless copying these files.
I have already allowed access to the System Volume Information folder for my account.
Searches have found a lot of posts about scripts with mklink, but I couldn't find a solid example of what I wanted and the languages I've seen used range from bash to Powershell.
I have scripted a lot in VBA but not with Powershell or even much in VBScript, which language is most appropriate for this? If Powershell I'm going to have to install it on the Win 7 machines, not a huge deal. VBScript or batch would be the easiest for me to write and distribute. I also have perl installed on my machine but would have to install it on a handful of other machines.
My first question is: which language would be best in this situation? I would prefer VBScript or batch if possible, or Powershell. perl if necessary.
Second question: can someone give me an example script? Typical mklink command looks like this (from what I understand):
mklink /d :name: :target:
Should I use the /j flag instead of /d ? Should I mount the drive (I'm unclear on how to do this with Windows CLI or Powershell)?
Also if this will not work in the first place feel free to let me know. Thanks.
So you could do this with PowerShell easily enough. You would not use MKLink, but would create a temporary mapping to the NAS location (been several years since I worked with a real NAS, I'm hoping that I remember right and that they do in fact have a UNC path such as \NAS01\Share). So you would use New-PSDrive, and just not use the -Persistent parameter, so the connection would end when the script ended and the PowerShell session exited. Then you can copy files as needed. In fact, you could set it to check all the files in both locations and only upload files that are updated locally. So assuming you have a folder for each computer to be backed up created on the share you could do this:
New-PSDrive -Name NAS -Root \\NAS01\Share\$env:COMPUTERNAME -PSProvider FileSystem
$Source = 'C:\System Volume Information'
Compare-Object (Get-ChildItem $Source -Recurse) (Get-ChildItem 'NAS' -Recurse) -PassThru |
Where{$_.SideIndicator -eq "<="} | ForEach{Copy-Item $_.FullName -Destination ($_.FullName -Replace [regex]::escape($source), 'NAS:')}
That essentially creates a drive named NAS that's mapped to the network path described, and then pulls a directory listing for both locations, and for items that are in the source that are not in the destination it copies it to the destination. Once the script is finished running PowerShell should exit and remove the link to the NAS when it does.

Renaming a file and remove 'dot' and replace it with' _'

I have set of files in a folder with name like abcd.15678
I want to remove the . and replace it with _
Pls suggest the windows command to do this
This solution is reposted from How to Batch Rename Files in Windows: 4 Ways to Rename Multiple Files by Chris Hoffman
PowerShell offers much more flexibility for renaming files in a command-line environment. Using PowerShell, you can pipe the output of one command – known as a “commandlet” in PowerShell terms — to another command, just like you can on Linux and other UNIX-like systems.
First of all, open Powershell ISE and then navigate to the directory (folder) that has the files and folders you'd like to rename by using this command:
cd "C:\your\directory\"
The two important commands you’ll need are Dir, which lists the files in the current directory, and Rename-Item, which renames an item (a file, in this case). Pipe the output of Dir to Rename-Item and you’re in business.
After you launch PowerShell ISE, use the cd command to enter the directory containing your files. You should put the files in their own directory so you don’t accidentally rename other files.
For example, let’s say we don’t want the dot character in our file names – we’d rather have an underscore instead.
The following command lists the files in the current directory and pipes the list to Rename-Item. Rename-Item replaces each dot character with an underscore.
Dir | Rename-Item –NewName { $_.name –replace ".","_" }
Consult Microsoft’s documentation on the Rename-Item commandlet if you want help performing other, more advanced operations.
There isn't a windows command to do this. You should consider writing a script of some sort that obtains a directory listing and enumerates through each entry: changes the dot to an underscore, and calls the windows rename command appropriately.
Actually this should work :
Dir | Rename-Item –NewName { $_.Name.Replace(".","_") }

Resources