【问题标题】:How to run a PowerShell script without displaying a window?如何在不显示窗口的情况下运行 PowerShell 脚本?
【发布时间】:2023-12-02 07:20:01
【问题描述】:

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

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

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

【问题讨论】:

标签: windows powershell scripting batch-file silent


【解决方案1】:

-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 内容。
【解决方案2】:

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

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

命令行示例:

run-hidden powershell -command calc.exe

【讨论】:

  • 这实际上很有帮助,因为许多其他解决方案有点麻烦和/或不理想。这个很快。我也将其修改为以管理员身份运行模式,因为这就是我来这里的目的(没有闪烁的窗口+以管理员身份运行)。 github.com/cherryleafroad/run-hidden
【解决方案3】:

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

【讨论】:

    【解决方案4】:
    powershell.exe -windowstyle hidden -noexit -ExecutionPolicy Bypass -File <path_to_file>
    

    然后设置运行:最小化

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

      • 作品 +1。如果您需要海拔高度,用户也可以以用户“系统”身份运行。如果您需要您的用户,或者我的回答。
      【解决方案6】:
      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 窗口,但无论如何感谢您的重播,干杯。
      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

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

        解决方案

        制作一个 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 脚本,这从头到尾对用户完全隐藏。
        • 我确定还有其他方法,但对我来说,如果我替换第一步它不会隐藏运行,可能是因为我没有登录用户我让脚本运行为?我不知道。
        【解决方案9】:

        这是 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,当您的脚本在后台运行时,您应该看不到控制台窗口。

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

        【讨论】:

          【解决方案10】:

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

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

          【讨论】:

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

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

          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"
          

          【讨论】:

            【解决方案12】:

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

            【讨论】:

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

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

            https://github.com/Vittel/RunHiddenConsole

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

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

            【讨论】:

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

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

            (通过this forum thread。)

            【讨论】:

            • 是否有 NuGet 包,以便我可以从 Visual Studio 运行它?
            【解决方案15】:

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

            【讨论】:

              【解决方案16】:

              我认为在运行后台脚本时隐藏 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”选项。根本没有弹出窗口。
              【解决方案17】:

              这是一个单行:

              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。
              【解决方案18】:

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

              把它放在脚本的前面:

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

              【讨论】:

                【解决方案19】:

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

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

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

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

                【讨论】:

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