0

I am attempting to use subprocess.check_call() and netsh in order to change my computer's NIC card settings. Currently using python 2.7 and Windows7.

This command is successful when I run it in from cmd.exe:

netsh interface ip set address name="Local Area Connection" static 192.168.1.1 255.255.255.0 192.168.1.2

This python script is not successful:

import subprocess    
command = ['netsh','interface','ip','set','address','name="Local Area Connection"','static','192.168.1.1','255.255.255.0','192.168.1.2']
result = subprocess.check_call(command)

And this is the last line of the traceback output given from the python script above:

CalledProcessError: Command '['netsh', 'interface', 'ip', 'set', 'address', 'name="Local Area Connection"', 'static', '192.168.1.1', '255.255.255.0', '192.168.1.2']' returned non-zero exit status 1

So, something is obviously going wrong and I am trying to track down what. The first thing I would like to resolve is what the returncodes mean? I hope I'm not being dense, but https://python.readthedocs.org/en/v2.7.2/library/subprocess.html# doesn't seem to explain what the returncode actually means. I did find this thread, What is the return value of subprocess.call()?, but it only gives blanket statements about return codes in general. Would anybody know how to figure out the meaning of return codes specific to subprocess.check_call()?

That would help me get a start at troubleshooting, but if anybody has any ideas as to why the script is failing in the first place, that would be greatly appreciated. I have tried using "Run as administrator" to open cmd.exe, and then running the python script from there, but the result is the same. This thread seems to be the same issue but I don't see a resolution to it: Using subprocess.call() to pass commands to execute by cmd. I have tried setting command = netsh interface ip set address name="Local Area Connection" static 192.168.1.1 255.255.255.0 192.168.1.2 and subprocess.check_call(command,shell=True) as well as subprocess.check_call(shlex.split(command)), and both return code '1'.

Community
  • 1
  • 1
jeby
  • 1
  • 2

2 Answers2

1

A return code is basically a very simple way for a program to notice calling systems about the success status of the program execution. In general, a return code of 0 means that everything worked correctly. Ever other number is considered an error. Now, programs can decide to use different return codes for different problems and then provide a registry which return code means what kind of error, but there are not many applications that do this. It is a lot more common, especially for human-facing programs like netsh, to just use any erroneous return code (usually 1) and then show the error message in the program output.

You should use catch_output instead to capture the output from netsh and then also catch the exception and look at the error message from it:

import subprocess    
command = ['netsh', 'interface', 'ip', 'set', 'address', 'name="Local Area Connection"', 'static', '192.168.1.1', '255.255.255.0', '192.168.1.2']

try:
    result = subprocess.check_output(command)
except subprocess.CalledProcessError as ex:
    print(ex.returncode, ex.output)
    raise

This should print you the output from netsh before the program aborts, so netsh will probably tell you what went wrong.

If I had to make a wild guess, I would say that netsh complains about missing administrator permissions. In order to change the IP address of a network interface, you need to be elevated. So if your Python program is not running as administrator, your spawned subprocess also isn’t running at administrator.

poke
  • 369,085
  • 72
  • 557
  • 602
  • Thanks for the response. Up to this point, I have been aware of "error handling" but haven't really used it. Need to start for best practice, so it's nice to have a reason to. Unfortunately in this case, `print(ex.returncode, ex.output)` gives the output `(1, None)`....... not too helpful. Doesn't running cmd.exe as administrator and then executing the python script from there take care of the administrator thing? I'm doing some more research into this so I can be confident I am running it as administrator. – jeby Nov 27 '15 at 23:23
  • That’s very odd. It should at least give you some output. Are you sure you changed the call from `check_call()` to `check_output()`? Also, as for your actual problem, it might be the quotes around `name="Local Area Connection"`. Try just `name=Local Area Connection`. – poke Nov 28 '15 at 00:05
  • @poke, it seems your guess is correct. `subprocess.list2cmdline` escapes the double quotes as `"name=\"Local Area Connection\""`. Thus the CRT startup code in netsh.exe doesn't remove them when creating the `argv` array. They're handled as part of the interface name. – Eryk Sun Nov 28 '15 at 02:11
  • To confirm this I started the (64-bit) netsh.exe process suspended (i.e. `creationflags=CREATE_SUSPENDED`); attached a debugger with a breakpoint on `netsh!wmain`, and resumed the main thread. I checked argument 5 of `wmain` via `?? *((wchar_t **)@rdx + 5)`, which evaluated to the string `"name="Local Area Connection""`. So the quotes are definitely parsed as part of the name, at least by the C runtime. – Eryk Sun Nov 28 '15 at 02:16
  • @poke, you are right both in that I overlooked your change to `subprocess.check_output()` and in that taking out the quotes was the mistake. @eryksun, that is good to know. I am going spend some time absorbing what you said, and how the `subprocess` module is actually written. `subprocess.list2cmdline` doesn't look too difficult at first glance. – jeby Nov 28 '15 at 04:20
-1

Seems like you're missing escaping the quotes characters in your command line try using:

import subprocess    
command = ['netsh','interface','ip','set','address','name=\\"Local Area Connection\\"','static','192.168.1.1','255.255.255.0','192.168.1.2']
result = subprocess.check_call(command)
Kacper Reutt
  • 112
  • 4
  • Thanks for the suggestion. I tried the escape slashes, but it gave the same result (returncode=1). Also, I thought that by using single quotes for the string, I could use the double quotes directly without the escape slashes? I also previously had tried using double quotes for the string and definitely used the escape slashes in that case too. – jeby Nov 27 '15 at 23:30