如何运行一个不显示窗口的PowerShell脚本?

227

如何在不显示窗口或任何其他标志给用户的情况下运行PowerShell脚本?

换句话说,脚本应该在后台静默运行,用户看不到任何迹象。

额外加分答案不使用第三方组件 :)


如果您对学习感兴趣,请查看以下问题:https://dev59.com/D3RB5IYBdhLWcg3wn4UL - Thomas Bratt
这个解决方案同样适用于任务计划程序:https://stackoverflow.com/a/51007810/571591 - Hilydrow
如果您绝对需要避免显示窗口,还有其他选项,例如Windows服务。 - ryanwebjackson
对于任何感兴趣的人,即使使用“-WindowStyle hidden”,窗口闪烁也是CUI应用程序已知的Windows限制(它只能像预期的那样与GUI应用程序一起工作--因此其他项目实现了pythonw.exe / javaw.exe类型的解决方案)。 它正在GitHub上被(相当)积极地讨论,有几个关于在PowerShell或操作系统级别进行潜在解决方法/修复的建议。 因此,它可能会在“某一天”得到修补。 - desseim
请注意,在组策略中使用的PowerShell登录脚本将会以隐藏窗口的形式运行。 - undefined
26个回答

0

在我尝试的所有解决方案中,这是迄今为止最好且最容易设置的。从这里下载hiddenw.exe - https://github.com/SeidChr/RunHiddenConsole/releases

假设您想无控制台运行Powershell v5。只需将hiddenw.exe重命名为powershellw.exe。如果您想对cmd执行此操作,则将其重命名为cmdw.exe。如果您想对Powershell v7 (pwsh)执行此操作,则将其重命名为pwshw.exe。您可以创建多个hiddenw.exe的副本,并将其重命名为实际进程名称并在末尾添加字母w。然后,将该进程添加到系统环境变量PATH中,以便您可以从任何地方调用它。或者只需复制到C:\ Windows。然后,像这样调用它:

powershellw .\example.ps1


0
我所做的是使用一个很棒的应用程序 Ps1 To Exe,将 .ps1 文件转换为不可见的 .exe 文件,您可以在此处下载:https://www.majorgeeks.com/files/details/ps1_to_exe.html 也许这会有所帮助(尽管我希望在12年后您已经找到了合适的解决方案...)

0

换句话说,脚本应该在后台静默运行,对用户没有任何提示。

如果不使用第三方组件,将会得到额外的加分哦 :)

我找到了一种方法,通过将 PowerShell 脚本编译为 Windows 可执行文件来实现。构建可执行文件需要使用第三方模块,但是运行可执行文件时不需要这些模块。我的最终目标是编译一个一行 PowerShell 脚本,用于弹出我的系统上的 DVD:

(New-Object -com "WMPlayer.OCX.7").cdromcollection.item(0).eject()

我的目标系统正在运行 Windows 7。所需的 WMF 更新因 Windows 版本而异:

下载并安装 WMF 5.1 包

所需的 PowerShell 模块适用于任何 Windows 版本。以下是我用于安装必要模块和编译 exe 的确切命令。您需要根据自己的系统调整驱动器、目录和文件名等详细信息:

mkdir i:\tmp\wmf
cd i:\tmp\wmf
pkunzip ..\Win7AndW2K8R2-KB3191566-x64.zip
c:\windows\system32\windowspowershell\v1.0\powershell.exe
Set-ExecutionPolicy RemoteSigned
.\Install-WMF5.1.ps1
<click> "Restart Now"
c:\Windows\System32\WindowsPowerShell\v1.0\powershell -version 3.0
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12  
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module -Name ps2exe -RequiredVersion 1.0.5
ps2exe i:\utils\scripts\ejectDVD.ps1 -noConsole

0
c="powershell.exe -ExecutionPolicy Bypass (New-Object -ComObject Wscript.Shell).popup('Hello World.',0,'ОК',64)"
s=Left(CreateObject("Scriptlet.TypeLib").Guid,38)
GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}").putProperty s,Me
WScript.CreateObject("WScript.Shell").Run c,0,false

有趣的方法,但是你如何在不使用临时文件的情况下将PS(StdOut)的输出捕获到变量中以在vbs脚本中使用? - Safwan
据我回忆,这是我在另一条评论中提出的极为简化的方法,它返回StdOut结果。您不应该要求这个简单的代码做它不打算做的事情。 - Garric
我已经看了你在另一个评论中的那段较长的代码,它确实捕获了StdOut,但它也重新启动了一个隐藏的控制台窗口,从而有效地隐藏了很多其他东西。我只是想找到一种方法来隐藏由脚本启动的PS窗口,但还是谢谢你的回复,祝好。 - Safwan

0

我很懒,所以我使用这些 PowerShell 命令来创建包含Adam Taylor上面解决方案的定期任务。您可以稍后编辑创建的任务(例如,更改从每天运行为其他方式):

#---adjust this part---
$script = "C:\Users\user\some-script.ps1"
$time = '5:15 AM'
$user = 'user'
$title = "Some title"
#-----------------------------------
$arguments = @'
vbscript:Execute("CreateObject(""Wscript.Shell"").Run ""powershell -NoProfile -ExecutionPolicy bypass -NoLogo -Command """"& '{script}'"""""", 0 : window.close")
'@ 
$arguments = $arguments -replace "{script}",$script
$actions = (New-ScheduledTaskAction -Execute "mshta" -Argument $arguments)
$trigger = New-ScheduledTaskTrigger -Daily -At $time
$principal = New-ScheduledTaskPrincipal -UserId $user 
$settings = New-ScheduledTaskSettingsSet -RunOnlyIfNetworkAvailable 
$task = New-ScheduledTask -Action $actions -Principal $principal -Trigger $trigger -Settings $settings
Register-ScheduledTask $title -InputObject $task

0
如果你想要一个不需要任何命令行参数的版本,只需在你的PowerShell脚本中编写代码,并且适用于新的Windows终端。
我在这里找到了这个解决方案here
$ShowWindowAsyncCode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
$ShowWindowAsync = Add-Type -MemberDefinition $ShowWindowAsyncCode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru

$hwnd = (Get-Process -PID $pid).MainWindowHandle
if ($hwnd -ne [System.IntPtr]::Zero) {
  # When you got HWND of the console window:
  # (It would appear that Windows Console Host is the default terminal application)
  $ShowWindowAsync::ShowWindowAsync($hwnd, 0)
} else {
  # When you failed to get HWND of the console window:
  # (It would appear that Windows Terminal is the default terminal application)

  # Mark the current console window with a unique string.
  $UniqueWindowTitle = New-Guid
  $Host.UI.RawUI.WindowTitle = $UniqueWindowTitle
  $StringBuilder = New-Object System.Text.StringBuilder 1024

  # Search the process that has the window title generated above.
  $TerminalProcess = (Get-Process | Where-Object { $_.MainWindowTitle -eq $UniqueWindowTitle })
  # Get the window handle of the terminal process.
  # Note that GetConsoleWindow() in Win32 API returns the HWND of
  # powershell.exe itself rather than the terminal process.
  # When you call ShowWindowAsync(HWND, 0) with the HWND from GetConsoleWindow(),
  # the Windows Terminal window will be just minimized rather than hidden.
  $hwnd = $TerminalProcess.MainWindowHandle
  if ($hwnd -ne [System.IntPtr]::Zero) {
    $ShowWindowAsync::ShowWindowAsync($hwnd, 0)
  } else {
    Write-Host "Failed to hide the console window."
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接