简体   繁体   English

一些powershell cmd - 如果从python运行则不可用?

[英]Some powershell cmd-lets not available if run from python?

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. 所以这是一个不寻常的,也许我只是错过了显而易见的,但我有以下python代码创建一个powershell脚本并运行它。

# 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. 显然,上述错误是一个PowerShell错误,因此它成功运行了脚本。 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. 看起来好像PowerShell以某种方式知道这是从python运行的,并且当从特定源运行脚本时,它具有一些受限制的命令库。 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. 我不认为这是一个权限问题,因为当你从一个无法升级的PowerShell提示符运行相同的命令时,会得到一个Access被拒绝的类型错误,而不是一个命令不存在的那种错误。

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. 这绝对是正确加载cmdlet的问题。 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 如果我以编程方式运行脚本以将所有可用命令的列表转储到文本文件中,那么它只有大约2/3的大小,就像我直接通过powershell提示一样

I bet Python is running as a 32-bit process on 64-bit Windows. 我敢打赌Python在64位Windows上作为32位进程运行。 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. 在这种情况下,您最终将运行32位PowerShell,这实际上是一件坏事,因为许多PowerShell模块依赖于可能没有32位等效的本机二进制文件。 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. 我使用IIS管理器命令行开关 - 命令行程序本身在32位PowerShell中注册,但它们依赖的基础COM对象不是。

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. 如果需要从32位进程运行64位PowerShell,请将路径指定为%SystemRoot%\\ SysNative \\ WindowsPowerShell \\ v1.0 \\ PowerShell.exe而不是System32。

System32 is actually virtualized for 32-bit processes and refers to the 32-bit binaries in %SystemRoot%\\SysWow64. System32实际上是针对32位进程虚拟化的,并且是指%SystemRoot%\\ SysWow64中的32位二进制文​​件。 This is why your paths (and PSMODULEPATH) will look the same, but aren't. 这就是你的路径(和PSMODULEPATH)看起来相同但不是这样的原因。 (SysNative is also a virtualized path that only exists in virtualized 32-bit processes.) (SysNative也是仅存在于虚拟化32位进程中的虚拟化路径。)

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. 添加@jbsmith在评论中所说的内容,还要确保在python启动进程时正确填充PowerShell依赖的环境变量来知道模块的位置。

%PSMODULEPATH% is the environment variable in question, and it works the same way the %PATH% variable does, multiple directories separated by ; %PSMODULEPATH%是有问题的环境变量,它的工作方式与%PATH%变量相同,多个目录分隔; . Based on what you say your observed behavior is, it seems that you are using PowerShell 3.0, and cmdlet autoloading is in effect. 根据您所说的观察到的行为,您似乎正在使用PowerShell 3.0,并且cmdlet自动加载已生效。

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. 这里的解决方案: 从python运行一个使用Web管理模块的powershell脚本,为我提供了我需要的cmdlet,但即使使用此方法,仍然缺少cmdlet。 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())

I had the same issue, and it was simply that the BitLocker feature was not installed, hence the module wasn't present. 我有同样的问题,只是没有安装BitLocker功能,因此模块不存在。

I fixed it by installing the Bitlocker feature: 我通过安装Bitlocker功能修复了它:

Windows Server: Windows Server:

Install-WindowsFeature BitLocker -IncludeAllSubFeature -IncludeManagementTools -Restart

Windows Desktop: Windows桌面:

Enable-WindowsOptionalFeature -Online -FeatureName BitLocker -All

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM