Powershell 什么';不推荐使用的wmic的cmd/batch替代方案是什么?

Powershell 什么';不推荐使用的wmic的cmd/batch替代方案是什么?,powershell,batch-file,wmic,Powershell,Batch File,Wmic,我知道自2012年起,wmic已被弃用,我现在通常使用PowerShell,因此我已经不再使用它了 但是,我经常遇到需要在批处理文件中工作而无法将解决方案迁移到PowerShell的情况 我的问题是:不推荐使用wmic时,对于从命令提示符和批处理文件继续访问Windows Management Instrumentation,建议使用什么替代方法 目前我能想到的最好的方法是: powershell -command "(Get-CimInstance Win32_Processor) | sel

我知道自2012年起,
wmic
已被弃用,我现在通常使用PowerShell,因此我已经不再使用它了

但是,我经常遇到需要在批处理文件中工作而无法将解决方案迁移到PowerShell的情况

我的问题是:不推荐使用
wmic
时,对于从命令提示符和批处理文件继续访问Windows Management Instrumentation,建议使用什么替代方法

目前我能想到的最好的方法是:

powershell -command "(Get-CimInstance Win32_Processor) | select *" | some_other_program.exe
(此示例用于获取处理器属性)

但这样做的一个主要缺点是错误级别和环境不再可访问。也就是说,powershell命令成功完成,即使该命令没有完成)。在powershell命令中对环境所做的更改不会传播到批处理文件

欢迎就如何具体解决这些问题,或就从批处理调用powershell以访问WMI的更好的替代方案提出任何建议,但我特别想知道如何运行powershell命令并访问标准输出以外的结果

但这样做的一个主要缺点是错误级别和环境不再可访问

使通过PowerShell CLI报告调用的PowerShell命令成为非零退出代码的最简单方法是抛出脚本终止(线程终止)错误,这将导致错误代码
1
-批处理文件可以测试该错误代码:

@echo off

:: # Simulate a failing CIM call
powershell -c "$ErrorActionPreference='Stop'; Get-CimInstance Win32_NoSuchClass" 

:: # Exit, if the PowerShell command failed.
if ERRORLEVEL 1 echo Error: Get-CimInstance failed>&2 & exit /b %ERRORLEVEL%

echo Moving on...
命令开始时的
$ErrorActionPreference='Stop'
确保任何后续错误都成为脚本终止错误。
要有选择地忽略非终止错误,请分别使用
-ErrorAction ignore
命令。
如果没有发生错误,退出代码将隐式地
0

PowerShell的错误处理非常复杂;有关全面的摘要,请参阅

注:

  • 本机PowerShell命令,如
    Get cimdinstance
    不设置退出代码;您最好将错误映射到退出代码
    1
    ,并将成功映射到退出代码
    0

  • 如果从PowerShell调用外部程序,其退出代码将反映在自动变量
    $LASTEXITCODE
    中;您可以使用
    exit$LASTEXITCODE
    从PowerShell命令字符串传递该退出代码;但是,您通常可以直接从批处理文件中调用外部程序,无需通过PowerShell绕道


在powershell命令中对环境所做的更改不会传播到批处理文件

确实,PowerShell命令总是在子进程中运行,其环境对调用进程没有影响

一般来说:

  • 在文件中捕获PowerShell命令的输出,或在内存中使用
    for/f
    循环(请参见下面的示例)对其进行处理,除非通过传递输出就足够了

  • 如果确实需要修改调用批处理文件的环境,请使用PowerShell命令输出这些修改的数据,并将其应用到批处理文件中

    • 例如,如果希望PowerShell命令设置环境变量,请使其输出批处理文件可用于设置这些变量的
      =
      字符串对
使用
为/f
裁剪PowerShell命令的输出以在批处理文件中进行解析的示例;请注意,报价可能会变得棘手:

@echo off

:: # Get the .Name and .MaxClockSpeed property values from the Win32_Processor instance.
for /f "tokens=1,* delims==" %%i in ('powershell -c "$ErrorActionPreference='Stop'; Get-CimInstance Win32_Processor | %% { foreach ($n in 'Name', 'MaxClockSpeed') { \""$n=$($_.$n)\"" } }"') do (
  echo [%%i]=[%%j]
)

:: # Exit, if the PowerShell command failed.
if ERRORLEVEL 1 echo Error: Get-CimInstance failed>&2 & exit /b %ERRORLEVEL%
上述结果类似于:

[Name]=[Intel(R)Core(TM)i5-7360U CPU@2.30GHz]
[MaxClockSpeed]=[2304]

当您声明它已被弃用时,您还没有扩展该声明或它如何影响您的现实世界场景
WMIC.exe
仍然是我使用过的Windows10电脑上的一个工作程序。此外,您没有理由不能从
a
中的批处理文件
运行powershell命令,以便
循环在
do
中接收其返回的输出。您能否详细说明“我经常遇到需要在批处理文件中工作而无法将解决方案迁移到powershell的情况。”为什么不呢?@Bill_Stewart我为之工作的客户有需要修改的现有批处理文件,他们根本不愿意为迁移所有东西支付时间,或者没有能力(或意愿)维护新的东西。@Compo-这是绝对公平的,目前还没有。我预计,微软反对它的举动意味着,在不久的将来,我们可以期待通过
wmic.exe
不再提供重要的功能,迫使我在需要时使用PowerShell功能。既然我更愿意遵循一个好的模式,如果它对我来说是可用的,那么我就要问一个问题——同时因为PowerShell中已经有一些函数在cmd中很难使用(比如Azure管理),所以在某些情况下,一个好的解决方案会很有用。@Compo,我如何从PowerShell命令接收输出(问题中提到的标准输出除外)在批处理文件中,即错误级别和对环境的更改或其他本地更改(如PowerShell变量).如果你知道答案,请将其作为答案发布-但从你所说的内容来看,我认为你只是在谈论标准输出。感谢你添加内容-我将接受你的回答作为答案,尽管我认为对于任何想要回答类似问题的人来说,答案应该是:没有直接的w唉-你需要实施一些相对干净的解决方案,就像你建议的那样。谢谢,@Grismar:我同意-这是最好的解决方案;PowerShell在与外部世界互动方面从来都不是很好,现在仍然不是很好-只是部分必要的