从 CMD/CLI 调用时的 Powershell 脚本奇怪行为

Powershell script strange behaviour when invoked from CMD/CLI

此脚本在从 Powershell 控制台执行时工作正常...
但在 CMD.exe...
中使用 Powershell.exe 执行时不起作用 (powershell.exe -file script.ps1,使用 Powershell 5.1.17763.771)

# display Windows Shell Folder propertes
$App  = New-Object -ComObject Shell.Application;
$AppNS = $App.NameSpace( "c:\windows" );
$AppNS.Self.InvokeVerb( "Properties" );

我测试了其他 GUI 对象(Winforms 和 WPF)
他们工作得很好...

?任何想法...

好像要等图形完成。 "get-childitem | out-gridview" 做了类似的事情。或者在脚本末尾添加 "sleep 120" ,或者寻找其他等待方式。杀死脚本会杀死 window.

powershell -noexit .\explorer.ps1

问题是,当调用进程退出时,您正在创建的进程内 COM 对象超出范围,在您的情况下,从 [=13] 调用时=] 通过 PowerShell 的 CLI,意味着 window 通常甚至没有机会显示或在非常短暂的出现后自动关闭。

  • interactive PowerShell 会话 中,该进程在退出脚本后继续运行 - 这就是您的代码有效的原因那里。

  • 当您通过 PowerShell 的 CLI 调用脚本时(powershell.exe for Windows PowerShellpwsh 用于 PowerShell Core,没有 -NoExit 开关以无限期保持进程活动),当脚本终止时,PowerShell 进程 退出


使用 -NoExit 充其量只是权宜之计,因为它会使 PowerShell 进程无限期 左右 ,即使您可能希望它只存在只要属性对话框 window 打开 - 只要用户选择关闭它。

因此,您需要同步等待 (a) 属性对话框 window 打开,然后 (b) 等待它关闭在退出脚本之前。

您可以在 .NET UI Automation 库的帮助下执行此操作,如下所示;请注意,该代码使用 PowerShell v5+ 语法:

using namespace System.Windows.Automation

# Load the UI Automation client assemblies.
# Requires Windows PowerShell or PowerShell Core v7+ (on Windows only).
Add-Type -AssemblyName UIAutomationClient; Add-Type -AssemblyName UIAutomationTypes

# Initiate display of the Windows folder's Properties dialog.
$App = New-Object -ComObject Shell.Application
$AppNS = $App.NameSpace('c:\windows')
$AppNS.Self.InvokeVerb('Properties')

# Comment out this line to suppress the verbose messages.
$VerbosePreference = 'Continue'

Write-Verbose 'Wating for the window''s creation...'
do {
  # Search among the current process' top-level windows for a winow
  # with class name '#32770', which is what the Properties dialog windows
  # use (don't know why, but it has been stable over time).
  $w = [AutomationElement]::RootElement.FindFirst([TreeScope]::Children, 
    [AndCondition]::new(
      [PropertyCondition]::new([AutomationElement]::ClassNameProperty, '#32770'),
      [PropertyCondition]::new([AutomationElement]::ProcessIdProperty, $PID)
    )
  )
  Start-Sleep -Milliseconds 100
} while (-not $w)

Write-Verbose 'Window has appeared, waiting for it to close...'

while ($w.Current.ProcessId) {
  Start-Sleep -Milliseconds 100
}

Write-Verbose 'Window is now closed, moving on.'

# At this point, if the script was invoked via PowerShell's CLI (powershell.exe -file ...)
# the PowerShell process terminates.

现在,从批处理文件中按如下方式调用 PowerShell 脚本将弹出“属性”对话框并在继续之前等待它关闭

@echo off

::  # ... your batch file

::  # Pop up the Properties dialog and *wait for it to close*.
powershell.exe -file script.ps1

::  # ...

相比之下,如果您只想启动属性对话框,同时继续运行您的批处理文件(请务必先禁用详细消息):

:: # Only *initiate* display of the Properties dialog and *continue execution*.
start /B powershell.exe -file script.ps1