如何运行一个不显示窗口的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个回答

205

你可以这样运行它(但是这会显示一个窗口一段时间):

PowerShell.exe -WindowStyle hidden { your script.. }

或者您可以使用我创建的辅助文件来避免调用 PsRun.exe 窗口,该文件能够准确地实现这一点。您可以从 运行 PowerShell 中带有 WinForm GUI 的定时任务 下载源代码和可执行文件。我将其用于定时任务。

编辑:正如 Marco 所指出的那样,-WindowStyle 参数仅适用于版本 2 及以上。


12
我编译了PsRun,但是如果我将其添加到计划任务中,它也会闪现一个窗口... - Ciantic
5
我也一样,因为弹出窗口要运行脚本,所以无法工作。虽然窗口很快就关闭了,但我们想在后台运行而不被打扰。 - Nathan McKaskle
48
对于预定任务而言,我发现如果在“安全选项”部分的“常规”选项卡下将任务设置为“无论用户是否已登录都运行”,PowerShell脚本将不需要添加-WindowStyle Hidden参数就可以静默运行。 - adam
16
“-windowstyle hidden”并不能完全隐藏窗口,至少会出现一次闪烁。 - js2010
5
您可以通过运行 cmd /c start /min "" powershell -WindowStyle Hidden -ExecutionPolicy Bypass -File "C:\Users\username\Desktop\test.ps1" 命令来避开窗口闪烁。 - Ste
显示剩余8条评论

78

我发现,如果你去任务计划程序中的任务,并且该任务正在运行powershell.exe脚本,你可以点击“无论用户是否登录都运行”,这样任务运行时将不会显示powershell窗口。


缺点: 脚本无法与已登录用户的屏幕交互(例如显示通知或任何图形用户界面元素)。

前提条件: 用户必须具备"作为批处理作业登录"特权。


5
最佳方案不依赖于第三方扩展、可执行文件或包装脚本。 - invert
2
请注意,此选项要求用户具有“作为批处理作业登录”的特权。 - gb96
4
这个解决方案导致我的脚本无法正常运行 - Martin Argerami
7
如果你的脚本涉及显示任何类型的 GUI,那么这不是一个解决方案。 - letmaik
这个解决方案将防止您向当前用户显示通知。隐藏代码并不意味着它对正在工作的人有任何用处。 - Garric
此外,如果您的脚本启动其他后台程序,它们也将没有窗口。 - Jesse Chisholm

29
答案中使用-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'"

Powershell内容为2. 调用带参数的文件是:
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'"

Powershell内容为3. 调用带有函数和参数的文件是:
function Get-Test() {
  [cmdletbinding()]
  Param
  (
    [Parameter(Mandatory = $true, HelpMessage = 'The test string.')]
    [String]$stringTest
    )
  Write-Host $stringTest
  return
}

如果您需要在任务计划程序中运行此操作,请将%comspec%作为程序/脚本调用,并将上述文件的调用代码作为参数。

注意:所有示例都适用于PS1文件路径中包含空格的情况。

enter image description here


7
这很有趣,但事实上我发现你确实可以看到这个窗口。它只是闪得比其他时间快得多,但是如果你非常注意,仍然可以看到弹出的窗口。如果想要看到我所说的,请打开一个窗口(如资源管理器)并观察,你会看到它在其他窗口获得焦点时短暂失去焦点。 - Kobato
这不是一个完美的解决方案,但在我所有的使用情况下都有效,并且我从未见过它闪烁。失去文件资源管理器的焦点无论如何都会发生,因为调用PS脚本本身就会这样做,不是吗? - Ste
1
在“调用带参数的文件”中,分号似乎是多余的,因为它会阻止脚本执行。 - Peter
@Peter,感谢您指出这一点。我已经修正了它并添加了ps1的内容以便更加清晰。 - Ste
@Ste 也许你还是不小心留下了一些东西,或者我只是没有理解这部分代码的作用 ps1'; -Arg1 'Hello' -Arg2 ' World'" - Peter
显示剩余3条评论

25

这个有没有NuGet包,这样我就可以在Visual Studio中运行它? - Piotr Kula

18

这是一个一行代码:

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

虽然这可能会短暂地闪烁窗口,但这应该是一个罕见的情况。


1
在大多数情况下,以已登录用户的上下文运行Powershell.exe将显示一个完整的窗口,如果使用-windowstyle hidden,则会短暂闪烁。要完全删除窗口,您可以采取以下两种方法之一:1:以不同用户的上下文(例如管理员帐户)运行(不会向已登录用户显示任何窗口)。或2:使用具有隐藏窗口标志的vbscript启动cmd.exe /c powershel.exe -file c:\script.ps1。当从cmd调用powershell时,它将在已经被wscript.exe //b /nologo c:\launcher.vbs隐藏的现有cmd窗口中运行。 - Iconiu
哇,突然间。我一开始甚至没有注意到你的回答。我用了一个非常类似的脚本来回答。很高兴看到有知识渊博的人给出真正的答案。 - Garric
2
这应该是被接受的答案,因为这种方法似乎在任何情况下都能够工作(包括我的问题所在,即任务计划程序内部)。 - Martin Argerami
1
注意事项:PowerShell脚本的退出代码在此处丢失,始终为0。 - letmaik

17
这里提供一种不需要命令行参数或单独启动器的方法。虽然在启动时会短暂地显示一个窗口,但它很快就会消失,如果可以接受这一点,在资源管理器中通过双击启动脚本或通过“开始”菜单快捷方式(当然包括“启动”子菜单)启动脚本是最简单的方法。我喜欢它作为脚本代码的一部分,而不是外部工具。将以下内容放在脚本的前面:
$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)

谢谢,这很有帮助。 - Shivam Anand

15

隐藏ps1文件,使其在任务计划程序和快捷方式中均不可见。

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

1
它也可以像链接中的“目标(Target)”一样工作。但愿这个答案在页面上更靠前,那就可以省下我很多时间了。谢谢! - FHC
1
运行完美。正是我所需要的。 - Capgros

8
我认为在运行后台脚本时,隐藏PowerShell控制台屏幕的最佳方法是使用此代码(“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"的回答投票。


2
对我来说,控制台仍然显示大约一秒钟。 - thdoan
当我在由GPO创建的计划任务中安排PowerShell时,这对我非常有效。为了好玩,我还结合了“-windowstyle hidden”选项。完全没有弹出窗口。 - Chris

7
当我从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
};

6
当您安排任务时,只需在“常规”选项卡下选择“无论用户是否登录都运行”。另一种方法是让任务作为其他用户运行。

工作 +1。如果需要提升权限,用户以“system”用户身份运行也可以正常工作。或者如果您需要使用自己的用户,则使用我的答案。 - Leathan
干得好,士兵! - Esperento57

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