如何在不显示窗口的情况下运行 PowerShell 脚本?

Posted

技术标签:

【中文标题】如何在不显示窗口的情况下运行 PowerShell 脚本?【英文标题】:How to run a PowerShell script without displaying a window? 【发布时间】:2010-12-20 14:27:36 【问题描述】:

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

换句话说,脚本应该在后台安静地运行,对用户没有任何迹象。

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

【问题讨论】:

如果您有兴趣学习,请查看此问题:***.com/questions/573623/powershell-vs-unix-shells 此解决方案也适用于任务计划程序:***.com/a/51007810/571591 如果您需要绝对避免显示窗口,还有其他选项,例如 Windows 服务。 【参考方案1】:

您可以使用PowerShell Community Extensions 并执行以下操作:

start-process PowerShell.exe -arg $pwd\foo.ps1 -WindowStyle Hidden

您也可以使用 VBScript 执行此操作:http://blog.sapien.com/index.php/2006/12/26/more-fun-with-scheduled-powershell/

Schedule Hidden PowerShell Tasks(互联网档案)

More fun with scheduled PowerShell(互联网档案)

(通过this forum thread。)

【讨论】:

是否有 NuGet 包,以便我可以从 Visual Studio 运行它?【参考方案2】:

您可以像这样运行它(但这会显示一段时间的窗口):

PowerShell.exe -windowstyle hidden  your script.. 

或者您使用我创建的帮助文件来避免执行该操作的名为 PsRun.exe 的窗口。您可以下载源代码和exe文件Run scheduled tasks with WinForm GUI in PowerShell。我将它用于计划任务。

已编辑:正如 Marco 所说,这个 -windowstyle 参数仅适用于 V2。

【讨论】:

我编译了PsRun,但是,如果我将它添加到计划任务中,它也会闪烁一个窗口...... 这里也一样,也不起作用,因为窗口仍然弹出来运行脚本。它会快速退出,但我们正在尝试在后台不间断地运行它。 是的,这就是为什么响应中有“但这会显示一段时间的窗口”。 -windowstyle hidden 并不完全有效。窗口至少会闪烁。【参考方案3】:

我在从 c# 运行时遇到了这个问题,在 Windows 7 上,以 SYSTEM 帐户运行隐藏的 powershell 窗口时弹出“交互式服务检测”服务。

使用“CreateNoWindow”参数可防止 ISD 服务弹出它的警告。

process.StartInfo = new ProcessStartInfo("powershell.exe",
    String.Format(@" -NoProfile -ExecutionPolicy unrestricted -encodedCommand ""0""",encodedCommand))

   WorkingDirectory = executablePath,
   UseShellExecute = false,
   CreateNoWindow = true
;

【讨论】:

【参考方案4】:

这是一种不需要命令行参数或单独的启动器的方法。它不是完全不可见的,因为在启动时会暂时显示一个窗口。但它很快就消失了。如果可以,我认为这是最简单的方法,如果您想通过在资源管理器中双击或通过“开始”菜单快捷方式(当然包括“启动”子菜单)来启动脚本。而且我喜欢它是脚本本身代码的一部分,而不是外部代码。

把它放在脚本的前面:

$t = '[DllImport("user32.dll")] public static extern bool ShowWindow(int handle, int state);'
add-type -name win -member $t -namespace native
[native.win]::ShowWindow(([System.Diagnostics.Process]::GetCurrentProcess() | Get-Process).MainWindowHandle, 0)

【讨论】:

谢谢,这很有帮助【参考方案5】:

这是一个单行:

mshta vbscript:Execute("CreateObject(""Wscript.Shell"").Run ""powershell -NoLogo -Command """"& 'C:\Example Path That Has Spaces\My Script.ps1'"""""", 0 : window.close")

虽然这可能会非常短暂地闪烁窗口,但这应该很少发生。

【讨论】:

在大多数情况下,如果您使用 -windowstyle hidden,在登录的用户上下文中运行 Powershell.exe 将显示一个完整的窗口或短暂闪烁。要完全删除窗口,您可以执行以下两项操作之一: 1:在不同用户的上下文中运行,例如管理员帐户(不会向已登录的用户显示任何窗口)。或者 2:使用带有隐藏窗口标志的 objshell.run 的 vbscript 来启动 cmd.exe /c powershel.exe -file c:\script.ps1。当从 cmd 调用 powershell 时,它将在已被 wscript.exe //b /nologo c:\launcher.vbs 隐藏的现有 cmd 窗口中运行。 哇,突然。起初我什至没有注意到你的回答。我用一个非常相似的脚本回答。很高兴看到知识渊博的人给出真实的答案。 这应该是公认的答案,它是一种似乎适用于各种情况的方法(包括在任务调度程序内部,这是我的问题)。 警告:PowerShell 脚本的退出代码在这里丢失并且始终为 0。【参考方案6】:

我认为在运行后台脚本时隐藏 PowerShell 控制台屏幕的最佳方法是 this code(“Bluecakes”答案)。

我将此代码添加到我需要在后台运行的所有 PowerShell 脚本的开头。

# .Net methods for hiding/showing the console in the background
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'
function Hide-Console

    $consolePtr = [Console.Window]::GetConsoleWindow()
    #0 hide
    [Console.Window]::ShowWindow($consolePtr, 0)

Hide-Console

如果这个答案对你有帮助,请投票给"Bluecakes" in his answer in this post.

【讨论】:

对我来说,控制台仍然显示大约一秒钟。 在 GPO 创建的计划任务中安排 powershell 时,这对我来说非常有用。为了踢球,我结合了“-windowstyle hidden”选项。根本没有弹出窗口。【参考方案7】:

我遇到了同样的问题。我发现如果你去Task Scheduler中运行powershell.exe脚本的Task,你可以点击“Run无论用户是否登录”,并且在任务运行时永远不会显示powershell窗口。

【讨论】:

不依赖第三方扩展、可执行文件或包装脚本的最佳解决方案。 请注意,此选项要求用户具有“作为批处理作业登录”权限 这个解决方案使我的脚本not to run properly。 如果您的脚本涉及显示任何类型的 gui,则不是解决方案。 此解决方案将阻止您向当前用户显示通知。隐藏代码并不意味着它对现在工作的人完全有用。【参考方案8】:

我创建了一个小工具,将调用传递给您想要启动无窗口的任何控制台工具到原始文件:

https://github.com/Vittel/RunHiddenConsole

编译后只需将可执行文件重命名为“w.exe”(附加一个“w”),并将其放在原始可执行文件旁边。 然后,您可以致电 e.G. powershellw.exe 使用常用参数,不会弹出窗口。

如果有人知道如何检查创建的进程是否正在等待输入,我很乐意提供您的解决方案:)

【讨论】:

如果您想在启动时使用MessageBox 运行powershell 脚本而没有任何 窗口闪烁(需要将EXE 编译为Winexe,而不是控制台应用程序,并要求将任务计划程序设置为“仅在用户登录时运行”,以便在当前桌面会话中显示对话框。)感谢您实现这一点,powershellw.exe 多年来一直在我的愿望清单上! PS:我刚才已经包含了“等待输入”的解决方案(以及一些错误修复)! @CarlWalsh 我假设你的意思是它不是一个控制台应用程序,而是一个赢取表单应用程序,这是正确的。只是它不包括任何窗口。但是项目类型应该在csproj文件中定义,用visual studio打开后不需要设置特定的输出类型【参考方案9】:

这是一个有趣的演示,用于控制控制台的各种状态,包括最小化和隐藏。

Add-Type -Name ConsoleUtils -Namespace WPIA -MemberDefinition @'
   [DllImport("Kernel32.dll")]
   public static extern IntPtr GetConsoleWindow();
   [DllImport("user32.dll")]
   public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'@

$ConsoleMode = @
 HIDDEN = 0;
 NORMAL = 1;
 MINIMIZED = 2;
 MAXIMIZED = 3;
 SHOW = 5
 RESTORE = 9
 

$hWnd = [WPIA.ConsoleUtils]::GetConsoleWindow()

$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.MAXIMIZED)
"maximized $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.NORMAL)
"normal $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.MINIMIZED)
"minimized $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.RESTORE)
"restore $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.HIDDEN)
"hidden $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.SHOW)
"show $a"

【讨论】:

【参考方案10】:

ps1 也隐藏在任务计划程序和快捷方式中

    mshta vbscript:Execute("CreateObject(""WScript.Shell"").Run ""powershell -ExecutionPolicy Bypass & 'C:\PATH\NAME.ps1'"", 0:close")

【讨论】:

它也可以在链接中用作“目标:”。我希望这个答案在页面上更高,会为我节省很多时间。谢谢! 工作完美。正是我想要的【参考方案11】:

这是 Windows 10 中不包含任何第三方组件的有效解决方案。它通过将 PowerShell 脚本包装到 VBScript 中来工作。

第 1 步:我们需要更改一些 windows 功能,以允许 VBScript 运行 PowerShell,并默认使用 PowerShell 打开 .ps1 文件。

-去运行并输入“regedit”。点击确定,然后让它运行。

-粘贴此路径“HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell”并按回车键。

-现在打开右侧的条目并将值更改为0。

-以管理员身份打开PowerShell并输入“Set-ExecutionPolicy -ExecutionPolicy RemoteSigned”,回车并用“y”确认更改,然后回车。

第 2 步:现在我们可以开始包装我们的脚本了。

-将您的 Powershell 脚本保存为 .ps1 文件。

-创建一个新的文本文档并粘贴此脚本。

Dim objShell,objFSO,objFile

Set objShell=CreateObject("WScript.Shell")
Set objFSO=CreateObject("Scripting.FileSystemObject")

'enter the path for your PowerShell Script
 strPath="c:\your script path\script.ps1"

'verify file exists
 If objFSO.FileExists(strPath) Then
   'return short path name
   set objFile=objFSO.GetFile(strPath)
   strCMD="powershell -nologo -command " & Chr(34) & "&" &_
    objFile.ShortPath & "" & Chr(34)
   'Uncomment next line for debugging
   'WScript.Echo strCMD

  'use 0 to hide window
   objShell.Run strCMD,0

Else

  'Display error message
   WScript.Echo "Failed to find " & strPath
   WScript.Quit

End If

-现在将文件路径更改为 .ps1 脚本的位置并保存文本文档。

-现在右键单击文件并转到重命名。然后将文件扩展名更改为.vbs并按回车,然后单击确定。

完成!如果您现在打开 .vbs,当您的脚本在后台运行时,您应该看不到控制台窗口。

如果这对你有用,请务必投票!

【讨论】:

【参考方案12】:

我真的厌倦了浏览答案却发现它没有按预期工作。

解决方案

制作一个 vbs 脚本来运行一个隐藏的批处理文件,该文件会启动 powershell 脚本。为这个任务制作 3 个文件似乎很愚蠢,但至少总大小小于 2KB,它可以从 tasker 或手动运行完美(你什么都看不到)。

scriptName.vbs

Set WinScriptHost = CreateObject("WScript.Shell")
WinScriptHost.Run Chr(34) & "C:\Users\leathan\Documents\scriptName.bat" & Chr(34), 0
Set WinScriptHost = Nothing

scriptName.bat

powershell.exe -ExecutionPolicy Bypass C:\Users\leathan\Documents\scriptName.ps1

scriptName.ps1

Your magical code here.

【讨论】:

为什么不能只在计划任务中使用.bat文件?为什么需要使用.vbs来调用.bat?我刚刚在计划任务中使用 .BAT 文件进行了测试,它工作正常,没有任何弹出窗口 我忘记了我不使用计划任务的原因,但是我能想到的原因有很多,但没有一个可以保证是正确的,因为我忘记了。我只记得发布我的解决方案,因为我最初尝试了其他解决方案,但它们没有用。我确实记得计划任务不是我想要的,但也许是因为它太动态了。事实上,答案可能是我使用了 vbs,因为我不能使用计划任务,无论如何它都无关紧要,如果它不在此处,只需提交你的作为另一个答案。 @shadowz1337 想通了,因为我需要再做一次。启动从调度程序隐藏的任务时会出现各种奇怪的情况,从而阻止 bat 文件实际被隐藏。这里的vbs专门解决了这个问题,这样你就可以以管理员用户身份运行隐藏的bat,否则你必须做系统,或者以任何用户身份运行。详细解释见superuser.com/questions/478052/…。 我只是使用 achedule 任务调用 nircmd exec hide 来运行 .bat 文件,然后它以管理员身份调用我的 Powershell 脚本,这从头到尾对用户完全隐藏。 我确定还有其他方法,但对我来说,如果我替换第一步它不会隐藏运行,可能是因为我没有登录用户我让脚本运行为?我不知道。【参考方案13】:
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 脚本中使用? 我记得,这是我在其他评论中提出的一种极其简化的方法,它返回 StdOut 结果。你不应该从这个简单的代码中要求它不适合的东西。 我在您的其他评论中查看了较长的代码,它确实捕获了 StdOut,但它也在隐藏的控制台中重新启动了脚本,有效地隐藏了很多其他的东西,我只是在寻找一种方法只是隐藏脚本启动的 PS 窗口,但无论如何感谢您的重播,干杯。【参考方案14】:

等到Powershell执行完毕,在vbs中得到结果

这是 Omegastripes 代码 Hide command prompt window when using Exec() 的改进版

将来自 cmd.exe 的混淆响应拆分为一个数组,而不是将所有内容都放入一个难以解析的字符串中。

此外,如果在执行 cmd.exe 期间发生错误,将在 vbs 中知道发生错误的消息。

Option Explicit
Sub RunCScriptHidden()
    strSignature = Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
    GetObject("new:C08AFD90-F2A1-11D1-8455-00A0C91F3880").putProperty strSignature, Me
    objShell.Run ("""" & Replace(LCase(WScript.FullName), "wscript", "cscript") & """ //nologo """ & WScript.ScriptFullName & """ ""/signature:" & strSignature & """"), 0, True
End Sub
Sub WshShellExecCmd()
    For Each objWnd In CreateObject("Shell.Application").Windows
        If IsObject(objWnd.getProperty(WScript.Arguments.Named("signature"))) Then Exit For
    Next
    Set objParent = objWnd.getProperty(WScript.Arguments.Named("signature"))
    objWnd.Quit
    'objParent.strRes = CreateObject("WScript.Shell").Exec(objParent.strCmd).StdOut.ReadAll() 'simple solution
    Set exec = CreateObject("WScript.Shell").Exec(objParent.strCmd)
    While exec.Status = WshRunning
        WScript.Sleep 20
    Wend
    Dim err
    If exec.ExitCode = WshFailed Then
        err = exec.StdErr.ReadAll
    Else
        output = Split(exec.StdOut.ReadAll,Chr(10))
    End If
    If err="" Then
        objParent.strRes = output(UBound(output)-1) 'array of results, you can: output(0) Join(output) - Usually needed is the last
    Else
        objParent.wowError = err
    End If
WScript.Quit
End Sub
Const WshRunning = 0,WshFailed = 1:Dim i,name,objShell
Dim strCmd, strRes, objWnd, objParent, strSignature, wowError, output, exec

Set objShell = WScript.CreateObject("WScript.Shell"):wowError=False
strCmd = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass Write-Host Hello-World."
If WScript.Arguments.Named.Exists("signature") Then WshShellExecCmd
RunCScriptHidden
If wowError=False Then
    objShell.popup(strRes)
Else
    objShell.popup("Error=" & wowError)
End If

【讨论】:

【参考方案15】:

当您计划任务时,只需在“常规”选项卡下选择“无论用户是否登录都运行”

另一种方法是让任务以另一个用户身份运行。

【讨论】:

作品 +1。如果您需要海拔高度,用户也可以以用户“系统”身份运行。如果您需要您的用户,或者我的回答。【参考方案16】:
powershell.exe -windowstyle hidden -noexit -ExecutionPolicy Bypass -File <path_to_file>

然后设置运行:最小化

应该可以按预期工作而无需添加隐藏窗口闪烁的代码 只是稍微延迟了执行。

【讨论】:

【参考方案17】:

-WindowStyle Hidden 的答案很好,但窗口仍然会闪烁。

通过cmd /c start /min "" 调用它时,我从未见过窗口闪烁。

您的机器或设置可能不同,但对我来说效果很好。

1。调用文件

cmd /c start /min "" powershell -WindowStyle Hidden -ExecutionPolicy Bypass -File "C:\Users\username\Desktop\test.ps1"

2。调用带参数的文件

cmd /c start /min "" powershell -WindowStyle Hidden -ExecutionPolicy Bypass -Command ". 'C:\Users\username\Desktop\test me.ps1' -Arg1 'Hello' -Arg2 'World'"ps1'; -Arg1 'Hello' -Arg2 ' World'"

2 的 Powershell 内容。调用带参数的文件是:

Param
(
  [Parameter(Mandatory = $true, HelpMessage = 'The 1st test string parameter.')]
  [String]$Arg1,
  [Parameter(Mandatory = $true, HelpMessage = 'The 2nd test string parameter.')]
  [String]$Arg2
  )

Write-Host $Arg1
Write-Host $Arg2

3。使用函数和参数调用文件

cmd /c start /min "" powershell -WindowStyle Hidden -ExecutionPolicy Bypass -Command ". 'C:\Users\username\Desktop\test me.ps1'; Get-Test -stringTest 'Hello World'"

3 的 Powershell 内容。使用函数和参数调用文件是:

function Get-Test() 
  [cmdletbinding()]
  Param
  (
    [Parameter(Mandatory = $true, HelpMessage = 'The test string.')]
    [String]$stringTest
    )
  Write-Host $stringTest
  return

如果您需要在任务计划程序中运行它,则调用%comspec% 作为程序/脚本,然后调用上述文件的代码作为参数。

注意:当 PS1 文件的路径中有空格时,所有示例都有效。

【讨论】:

这很有趣,但我实际上发现你可以看到窗口。它只是比其他时间闪烁得快得多,但如果你密切注意,窗口仍然会弹出。如果你想看看我在说什么,然后打开一个窗口窗口(如资源管理器),你会看到它在短时间内失去焦点,因为另一个窗口获得焦点 这不是一个完美的解决方法,但它适用于我的所有用例,而且我从未见过它闪烁。它会失去文件资源管理器的焦点,不管它不会看到调用 PS 脚本会这样做吗? 只有在窗口前面弹出某些东西(无论多么简短)时,它才会失去对窗口的关注。当然,一旦焦点消失,焦点就会恢复,但重点仍然存在。我确实必须非常非常仔细地看才能看到闪光灯(它可能只出现了几帧),因为如果我不是在寻找它,我就看不到它,所以它比其他闪光灯(闪光) 方法。我最终使用了 run-hidden 中的代码,它实际上是隐藏的(也没有失去焦点或任何东西),尽管我没有测试其他答案。至少你的回答肯定比其他闪光的侵入性更小 对于“调用带有参数的文件”,分号似乎是多余的,因为它会阻止脚本执行。 @Peter,感谢您指出这一点。为了清楚起见,我已经修复了这个问题并添加了 ps1 内容。【参考方案18】:

创建一个调用 PowerShell 脚本的快捷方式并将运行选项设置为最小化。这将防止窗口闪烁,尽管您仍会在任务栏上看到正在运行的脚本的瞬间。

【讨论】:

【参考方案19】:

为了方便命令行使用,有一个简单的包装应用程序:

https://github.com/stax76/run-hidden

命令行示例:

run-hidden powershell -command calc.exe

【讨论】:

这实际上很有帮助,因为许多其他解决方案有点麻烦和/或不理想。这个很快。我也将其修改为以管理员身份运行模式,因为这就是我来这里的目的(没有闪烁的窗口+以管理员身份运行)。 github.com/cherryleafroad/run-hidden 当您在其中一个参数中使用“%USERPROFILE%”时,这似乎不起作用。 @jamie 我认为这是正常行为!我相信,Process 类不会扩展环境变量,并且像 run-hidden 这样的用户应用程序通常也不会这样做。 嗯,我明白了。谢谢你解释。【参考方案20】:

在我尝试过的所有解决方案中,这是迄今为止最好且最容易设置的。从这里下载 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

【讨论】:

以上是关于如何在不显示窗口的情况下运行 PowerShell 脚本?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不点击标记的情况下在 iOS 谷歌地图中显示信息窗口?

如何在不关闭 GUI 窗口的情况下停止运行 PyQt5 程序?

如何在不连接 Powershell 的情况下传递参数? [复制]

如何在不显示文本的情况下分配 Win32 EDIT 控件的窗口名称?

如何在不将焦点转移到另一个窗口的情况下显示 MFC 对话框

在不提示的情况下在 Powershell 中获取当前用户的凭据对象