1

So this is an unusual one, and perhaps I am simply missing the obvious, but I have the following python code that creates a powershell script and runs it.

# Create the PowerShell file 
f = open("getKey.ps1", "w")

f.write('$c = Get-BitlockerVolume -MountPoint C:\n')
f.write('$c.KeyProtector[1].RecoveryPassword | Out-File C:\\Temp\\recovery.key\n')

# Invoke Script
startPS = subprocess.Popen([r'C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe',
                                           '-ExecutionPolicy', 'Unrestricted', './getKey.ps1'], cwd=os.getcwd())

result = startPS.wait()

When this is run, it gives me the following error:

The term 'Get-BitlockerVolume' is not recognized as the name of a cmdlet, function, script file, or operable program.

However, if I then go and manually run the generated script, it works perfectly. To add to the oddity, if I run the same command exactly as above ie:

C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Unrestricted ./getKey.ps1

it also works exactly as expected.

Clearly, the above error is a powershell error, so it is successfully running the script. It almost seems like powershell somehow knows that this is being run from python and has some restricted library of commands when a script is run from a particular source. I grant that that idea makes no real sense, but it's certainly how things appear.

I don't think this is a permissions issue, because when you run the same command from an unelevated powershell prompt, you get an Access is denied type error, rather than a command doesn't exist kind of error.

Anyway, any help would be greatly appreciated!

  • Edits

Edit: New evidence to help figure this out:

It's definitely an issue of cmdlets being loaded properly. If I programmatically run a script to dump the list of all available commands to a text file, it is only about 2/3's as big as if I do so through a powershell prompt directly

3
  • Perhaps you need to f.close() the script file before trying to run it. Commented Dec 3, 2013 at 17:01
  • Are you running the python and the raw powershell in the same user context? If you are on powershell version 3 or later, then cmdlets like Get-BitLockerVolume should be auto-loaded; but if you are on V2, then you need to manually import the module before those cmdlets are available. It's possible that one user profile imports the cmdlets on startup, but if python is running under a different user, the profile script doesn't run and the module is not loaded. That's my best guess for why you're getting the 'not recognized' error. Commented Dec 3, 2013 at 18:19
  • I am using Powershell 4. I am running both the python and the script under the same command prompt window, but I'm not sure whether or not the python.exe creating a subprocess is a different user context. If I read the above correctly, with version 3 or later it is irrelevant under which context the process is run? Commented Dec 3, 2013 at 19:16

4 Answers 4

3

I bet Python is running as a 32-bit process on 64-bit Windows. In this case, you'll end up running 32-bit PowerShell, which in practice is a Bad Thing since many PowerShell modules depend on native binaries that may not have 32-bit equivalents. I hit this with IIS Manager commandlets--the commandlets themselves are registered in 32-bit PowerShell, but the underlying COM objects they rely on are not.

If you need to run 64-bit PowerShell from a 32-bit process, specify the path as %SystemRoot%\SysNative\WindowsPowerShell\v1.0\PowerShell.exe instead of System32.

System32 is actually virtualized for 32-bit processes and refers to the 32-bit binaries in %SystemRoot%\SysWow64. This is why your paths (and PSMODULEPATH) will look the same, but aren't. (SysNative is also a virtualized path that only exists in virtualized 32-bit processes.)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I was going insane, did not realize this was an issue at all! Finally got my command working.
0

Adding to what @jbsmith said in the comment, also check to make sure that the environment variable that PowerShell relies on to know where it's modules are is populated correctly when python starts the process.

%PSMODULEPATH% is the environment variable in question, and it works the same way the %PATH% variable does, multiple directories separated by ;. Based on what you say your observed behavior is, it seems that you are using PowerShell 3.0, and cmdlet autoloading is in effect.

1 Comment

Okay, so I tried the above. PSMODULEPATH is identical when printed just before the subprocess call in the python script as if I simply type echo %PSMODULEPATH% before manually running the command. I am running Windows 8.1, which I believe uses powershell 4.0
0

The solution here: Run a powershell script from python that uses Web-Administration module got me the cmdlet I needed, however there are still missing cmdlets even when using this method. I'm still at a loss as to why some are loaded and others are not, but for the time being, my script does what I need it to and I can't spend any more time to figure it out.

For reference here is the code that worked for me

startPS = subprocess.Popen([r'C:\Windows\sysnative\cmd.exe', '/c', 'powershell',
    '-ExecutionPolicy', 'Unrestricted', './getKey.ps1'], cwd=os.getcwd())

Comments

0

I had the same issue, and it was simply that the BitLocker feature was not installed, hence the module wasn't present.

I fixed it by installing the Bitlocker feature:

Windows Server:

Install-WindowsFeature BitLocker -IncludeAllSubFeature -IncludeManagementTools -Restart

Windows Desktop:

Enable-WindowsOptionalFeature -Online -FeatureName BitLocker -All

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.