I'm trying to unzip a file with 7z.exe
and the password contains special characters on it
EX. &)kra932(lk0¤23
By executing the following command:
subprocess.call(['7z.exe', 'x', '-y', '-ps^&)kratsaslkd932(lkasdf930¤23', 'file.zip'])
7z.exe
launches fine but it says the password is wrong.
This is a file I created and it is driving me nuts.
If I run the command on the windows command line it runs fine
7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip
How can I make python escape the &
character?
@Wim the issue occurs & on the password, because when i execute
7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip
it says invalid command ')kratsaslkd932(lkasdf930¤23'
im using python 2.76, cant upgrade to 3.x due to company tools that only run on 2.76
There is a big security risk in passing the password on the command line. With administrative rights, it is possible to retrieve that information (startup info object) and extract the password. A better solution is to open 7zip as a process, and feed the password into its standard input.
Here is an example of a command line that compresses "source.txt" into "dest.7z":
CMD = ['c:\\Program Files\\7-Zip\\7z.exe', 'a', '-t7z', '-p', 'c:\\source.txt', 'd:\\dest.7z']
PASSWORD = "Nj@8G86Tuj#a"
First you need to convert the password into an input string. Please note that 7-zip expects the password to by typed into the terminal. You can use special characters as long as they can be represented in your terminal. The encoding of the terminal matters! For example, on Hungarian Windows, you might want to use "cp1250" encoding. In all cases, the standard input is a binary file, and it expects a binary string ("bytes" in Python 3). If you want to be on the safe side, you can restrict passwords to plain ascii and create your input like this:
input = (PASSWORD + "\r\n").encode("ascii")
If you know the encoding of your terminal, then you can convert the password to that encoding. You will also be able to detect if the password cannot be used with the system's encoding. (And by the way, it also means that it cannot be used interactively either.)
(Last time I checked, the terminal encoding was different for different regional settings on Windows. Maybe there is a trick to change that to UTF-8, but I'm not sure how.)
This is how you execute a command:
import subprocess
import typing
def execute(cmd : typing.List[str], input: typing.Optional[bytes] = None, verbose=False, debug=False, normal_priority=False):
if verbose:
print(cmd)
creationflags = subprocess.CREATE_NO_WINDOW
if normal_priority:
creationflags |= subprocess.NORMAL_PRIORITY_CLASS
else:
creationflags |= subprocess.BELOW_NORMAL_PRIORITY_CLASS
if debug:
process = subprocess.Popen(cmd, shell=False, stdout=sys.stdout, stderr=sys.stderr, stdin=subprocess.PIPE,
creationflags=creationflags)
else:
process = subprocess.Popen(cmd, shell=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
stdin=subprocess.PIPE, creationflags=creationflags)
if input:
process.stdin.write(input)
process.stdin.flush()
returncode = process.wait()
if returncode:
raise OSError(returncode)
CMD = ['c:\\Program Files\\7-Zip\\7z.exe', 'a', '-t7z', '-p', 'c:\\source.txt', 'd:\\dest.7z']
PASSWORD = "Nj@8G86Tuj#a"
input = (PASSWORD + "\r\n").encode("ascii")
execute(CMD, input)
This also shows how to lower process priority (which is usually a good idea when compressing large amounts of data), and it also shows how to forward standard output and standard error to the console.
The absolute correct solution would be to load 7-zip DLL and use its API. (I did not check but that can probably use 8 bit binary strings for passwords.)
Note: this example is for Python 3 but the same can be done with Python 2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With