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

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

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

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

【问题讨论】:

标签: windows powershell scripting batch-file silent


【解决方案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/

(通过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

              【讨论】:

                猜你喜欢
                • 2022-06-13
                • 1970-01-01
                • 2021-09-04
                • 2015-06-15
                • 2010-10-03
                • 1970-01-01
                • 2021-08-17
                相关资源
                最近更新 更多