打开PowerShell脚本并隐藏命令提示符,但不隐藏GUI界面。

7

我目前通过一个.bat文件打开我的PowerShell脚本。这个脚本有一个图形用户界面(GUI)。我试图将以下代码放入我的脚本中,但它隐藏了GUI并且一直循环执行,因为我希望我的GUI持续循环:

powershell.exe -WindowStyle Hidden -file c:\script.ps1

我们如何在不使用命令提示符的情况下运行脚本,但同时又不隐藏 GUI?如果我们使用 .bat 文件运行脚本,情况是否相同?谢谢!

2
将其放入快捷方式而不是批处理文件中。右键单击桌面或文件夹窗口上的空白处,选择“新建快捷方式”,粘贴您的命令行,点击“下一步”,命名它,完成。 - user6017774
1
谢谢Noodles,这个方法可行!我使用了 %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -file "\\location\folder1\script.ps1" - DrixlRey
6个回答

22

如果您想将控制台隐藏在GUI后面,我已经成功地使用以下本地函数:

# .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 Show-Console
{
    $consolePtr = [Console.Window]::GetConsoleWindow()

    # Hide = 0,
    # ShowNormal = 1,
    # ShowMinimized = 2,
    # ShowMaximized = 3,
    # Maximize = 3,
    # ShowNormalNoActivate = 4,
    # Show = 5,
    # Minimize = 6,
    # ShowMinNoActivate = 7,
    # ShowNoActivate = 8,
    # Restore = 9,
    # ShowDefault = 10,
    # ForceMinimized = 11

    [Console.Window]::ShowWindow($consolePtr, 4)
}

function Hide-Console
{
    $consolePtr = [Console.Window]::GetConsoleWindow()
    #0 hide
    [Console.Window]::ShowWindow($consolePtr, 0)
}

一旦上述功能已添加到您的表单中,只需在您的Form_Load事件中调用Hide-Console函数:

$OnFormLoad = 
{
    Hide-Console
}

如果您需要显示控制台,可能是为了调试,您可以通过调用 Show-Console 函数轻松地再次显示控制台:

$OnButtonClick = 
{
    Show-Console
}

有关可以传递给 ShowWindow 的数字的更多信息,请参阅此处的 MSDN 上的 ShowWindow 文档
要使用此代码隐藏控制台,您只需要调用 Hide-Console。由于您已经在 Shown 事件 ($objForm.Add_Shown) 中编写了代码,我们只需要添加另一行来调用该命令:
将此更改为:
$objForm.Add_Shown({$objForm.Activate()})

变成这样:

$objForm.Add_Shown({
    $objForm.Activate()
    Hide-Console
})

当你的表单被 展示 时,控制台将会被隐藏(如果你想要之后查看它仍然可以调用 Show-Console )。


谢谢您提供这段代码。我尝试在我的脚本中使用它,但是我应该把Hide-Console放在哪里?我的表单加载看起来像这样$objForm.Add_Shown({$objForm.Activate()}) [void] $objForm.ShowDialog() - DrixlRey
我已经更新了我的答案,包括如何在“Shown”事件块内调用“Hide-Console”命令的示例。如果这个答案对你有帮助,请点击勾选以接受答案,帮助其他人找到相同的答案。 - Bluecakes

5
如果您从一个窗口状态设置为最小化的快捷方式中运行PowerShell,则会在任务栏中短暂闪现一个cmd图标,但您几乎不会注意到它。然而,它将启动您的PowerShell GUI,而不需要在其后面有一个控制台窗口。
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -windowstyle Hidden -file "C:\path\whatever.ps1"

如果你想从whatever.ps1启动第二个GUI控制台窗口,而不会停止处理whatever.ps1,则需要使用start-process。然而,使用 -WindowStyle hidden 的start-process会防止GUI显示出来。移除 -WindowStyle 将在你的GUI后面显示一个命令行窗口。但是,如果你使用 cmd.exe /k 启动 start-process,它就可以正常工作。
$argumentlist = "/c powershell.exe -file `"c:\path\whatever2.ps1`" -param1 `"paramstring`""
Start-Process cmd.exe -WindowStyle Hidden -ArgumentList $argumentlist

作为额外的福利,如果你在 whatever2.ps1 中使用 param() 语句,你可以传递命名、必需参数。只需要确保它是 ps1 文件中的第一件事,甚至在装配之前。
param (
  [Parameter(Mandatory=$true)]
  [string]$var1
)
$argumentlist = "/c powershell.exe -file `"C:\path\whatever2.ps1`" -param1 `"param1string`""

1
在提出的解决方案中,建议将其放入快捷方式而不是批处理文件中。右键单击桌面或文件夹窗口上的空白处,选择“新建快捷方式”,粘贴您的命令行,点击“下一步”,命名,完成。为了彻底隐藏命令提示符,我在快捷方式属性中设置了“运行=最小化”选项。

1

简化了显示/隐藏函数的一点内容

function Show-Console
{
    param ([Switch]$Show,[Switch]$Hide)
    if (-not ("Console.Window" -as [type])) { 

        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);
        '
    }

    if ($Show)
    {
        $consolePtr = [Console.Window]::GetConsoleWindow()

        # Hide = 0,
        # ShowNormal = 1,
        # ShowMinimized = 2,
        # ShowMaximized = 3,
        # Maximize = 3,
        # ShowNormalNoActivate = 4,
        # Show = 5,
        # Minimize = 6,
        # ShowMinNoActivate = 7,
        # ShowNoActivate = 8,
        # Restore = 9,
        # ShowDefault = 10,
        # ForceMinimized = 11

        $null = [Console.Window]::ShowWindow($consolePtr, 5)
    }

    if ($Hide)
    {
        $consolePtr = [Console.Window]::GetConsoleWindow()
        #0 hide
        $null = [Console.Window]::ShowWindow($consolePtr, 0)
    }
}

显示控制台 -显示

显示控制台 -隐藏


0
我遇到了完全相同的问题。我需要一个Winform窗体在不显示控制台窗口的情况下显示。 最简单的方法是打开另一个非隐藏的窗口来运行Winform,并将其隐藏起来。例如:
start-process powershell.exe -windowstyle normal C:\SomePathToScript.ps1
上述script.ps1文件将充当您实际的Winform脚本的"启动器"。
在这个"启动"脚本中: powershell.exe -windowstyle hidden C:\Path\To\Winform\Script.ps1
在启动脚本中,请确保在powershell.exe之前省略"start-process"。 这就像是一种内置的隐藏效果。 你会看到一个瞬间出现的PowerShell窗口,然后它立即消失。

0

虽然Bluecakes的答案很好,但可以简化一下。没有必要使用kernel32.dll中的GetConsoleWindow()函数来获取控制台窗口句柄。可以通过Process类的MainWindowHandle属性获取,而进程本身是由Get-Process命令返回的,其中传递了自动变量$pid作为参数。以下是一个示例,仅隐藏当前控制台窗口:

add-type -name user32 -namespace win32 -memberDefinition '[DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);'
[win32.user32]::showWindow((get-process -id $pid).mainWindowHandle, 0)

请注意,上述方法仅适用于在加载GUI表单之前隐藏控制台。否则,该表单将成为进程的主窗口,并且MainWindowHandle将返回表单的句柄。如果您需要在加载表单后操作控制台窗口并仍然避免使用kernel32.dll,则可以在最开始时将其句柄保存在变量中:
add-type -name user32 -namespace win32 -memberDefinition '[DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);'
$consoleHandle = (get-process -id $pid).mainWindowHandle

# load your form or whatever ...

# hide console
[win32.user32]::showWindow($consoleHandle, 0)
# show console
[win32.user32]::showWindow($consoleHandle, 5)

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