ChatGPT解决这个技术问题 Extra ChatGPT

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

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

换句话说,脚本应该在后台安静地运行,而不需要向用户发出任何信号。

不使用第三方组件的答案的额外功劳:)

如果您有兴趣学习,请查看此问题:stackoverflow.com/questions/573623/powershell-vs-unix-shells
此解决方案也适用于任务计划程序:stackoverflow.com/a/51007810/571591
如果您需要绝对避免显示窗口,还有其他选项,例如 Windows 服务。
对于任何感兴趣的人来说,即使使用 -WindowStyle hidden 也会闪烁的窗口是 CUI 应用程序的已知 Windows 限制(它仅适用于 GUI 应用程序 - 因此其他项目实现了 pythonw.exe / javaw.exe 类型的解决方案)。它正在(相当)积极地讨论on GitHub,并就 PowerShell 或操作系统级别的潜在解决方法/修复提出了一些建议。所以,它可能会被修补,“有一天”。

w
wannaBeTheBestMe

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

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

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

已编辑:正如 Marco 所指出的,此 -WindowStyle 参数仅适用于 V2 及更高版本。


我编译了 PsRun,但是,如果我将它添加到计划任务中,它也会闪烁一个窗口......
同样在这里,也不起作用,因为仍然会弹出窗口来运行脚本。它很快退出,但我们试图在后台运行它而不会中断。
是的,这就是为什么响应中有“但这会显示一段时间的窗口”。
@ThomasBratt 对于计划任务,如果“安全选项”部分下的“常规”选项卡上的任务设置为 Run whether user is logged on or not,我发现 PowerShell 脚本在没有 -WindowStyle Hidden 的情况下静默运行。
-windowstyle hidden 并不完全有效。窗口至少会闪烁。
Y
Yusha

我遇到了同样的问题。我发现如果您转到运行 powershell.exe 脚本的任务计划程序中的任务,您可以单击“无论用户是否登录都运行”,并且在任务运行时永远不会显示 powershell 窗口。


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

您可以使用 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/

安排隐藏的 PowerShell 任务(Internet 存档)

使用预定的 PowerShell(Internet 存档)更有趣

(通过 this forum thread。)


是否有 NuGet 包,以便我可以从 Visual Studio 运行它?
A
Andy Lowry

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

将其放在脚本的前面:

$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)

谢谢,这很有帮助
A
Adam Taylor

这是一个单行:

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。
G
Garric

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

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

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

-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 文件的路径中有空格时,所有示例都有效。

https://i.stack.imgur.com/RllIS.png


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

我认为在运行后台脚本时隐藏 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”。


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

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

j
js2010

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

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"

J
John Stankievich

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


S
Sandeep Verma

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

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


作品+1。如果您需要海拔高度,用户也可以作为用户“系统”运行。如果您需要您的用户,或者我的回答。
干得好士兵!
s
stax76

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

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

示例命令行:

run-hidden powershell -command calc.exe

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

我真的厌倦了通过答案才发现它没有按预期工作。

解决方案

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

脚本名.vbs

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

脚本名称.bat

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

脚本名称.ps1

Your magical code here.

为什么不能只在计划任务中使用 .bat 文件?为什么需要使用.vbs来调用.bat?我刚刚在计划任务中使用 .BAT 文件进行了测试,它工作正常,没有任何弹出窗口
我忘记了我不使用计划任务的原因,但是我能想到很多原因,因为我忘记了,没有一个可以保证是正确的。我只记得发布我的解决方案,因为我最初尝试了其他解决方案,但它们没有用。我确实记得计划任务不是我想要的,但也许是因为它太动态了。事实上,答案可能是我使用了 vbs,因为我无法使用计划任务,无论如何它都无关紧要,如果它不在此处,只需提交你的作为另一个答案。
@shadowz1337 想通了,因为我需要再做一次。启动从调度程序隐藏的任务时会出现各种奇怪的情况,从而阻止 bat 文件实际上被隐藏。这里的vbs专门解决了这个问题,这样你就可以以管理员用户身份运行隐藏的bat,否则你必须做系统,或者以任何用户身份运行。有关详细说明,请参阅 superuser.com/questions/478052/…
我只是使用 achedule 任务调用 nircmd exec hide 来运行 .bat 文件,然后以管理员身份调用我的 Powershell 脚本,这从头到尾对用户完全隐藏。
我确定还有其他方法,但对我来说,如果我替换第一步它不会隐藏运行,可能是因为我没有登录用户我让脚本运行为?我不知道。
C
Chris

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

https://github.com/Vittel/RunHiddenConsole

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

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


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

等到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

N
Nimantha

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

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

- 运行并输入“regedit”。单击确定,然后允许它运行。

- 粘贴此路径“HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell”,然后按 Enter。

- 现在打开右侧的条目并将值更改为 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 并按 Enter 键,然后单击确定。

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


G
Garric
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 窗口由剧本,但无论如何感谢您的重播,干杯。
S
Suraj Rao
powershell.exe -windowstyle hidden -noexit -ExecutionPolicy Bypass -File <path_to_file>

然后设置运行:最小化

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


s
shadowz1337

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


J
JMax

我发现编译为 exe 是实现这一目标的最简单方法。编译脚本的方法有很多种,但您可以尝试 ISE Steroids

打开“Windows PowerShell ISE”,安装并运行 ISEStroids:

Install-Module -Name "ISESteroids" -Scope CurrentUser -Repository PSGallery -Force

Start-Steroids

然后转到工具->将代码转换为EXE,选择“隐藏控制台窗口”,然后创建应用程序。您可以直接从任务调度程序运行它,而无需包装器或 3rd 方应用程序。