【问题标题】:Run Powershell script to show a form without Powershell screen at the back运行 Powershell 脚本以在后面显示没有 Powershell 屏幕的表单
【发布时间】:2020-06-03 06:38:52
【问题描述】:

我有一个 powershell 脚本,它可以在工作站上本地运行或使用 PSEXEC 工具远程运行,它会显示一个对话框来控制台用户 PC 将在 X 时间和计时器内重新启动。对话框不能关闭,只能最小化(这是按照代码)。但是,当我运行它时,它还会在对话框的后面显示 Powershell 屏幕,关闭它也会关闭表单。

我尝试了 Powershell 开关 [-NoLogo]、[-NonInteractive]、[-WindowStyle Hidden],它不起作用。

这是自定义重启脚本:

Function Create-GetSchedTime {   
Param(   
$SchedTime   
)
      $script:StartTime = (Get-Date).AddSeconds($TotalTime)
      $RestartDate = ((get-date).AddSeconds($TotalTime)).AddMinutes(-5)
      $RDate = (Get-Date $RestartDate -f 'dd.MM.yyyy') -replace "\.","/"      # 16/03/2016
      $RTime = Get-Date $RestartDate -f 'HH:mm'                                    # 09:31
      #&schtasks /delete /tn "Post Maintenance Restart" /f
      #&schtasks /create /sc once /tn "Post Maintenance Restart" /tr "'C:\Windows\system32\cmd.exe' /c shutdown -r -f -t 300" /SD $RDate /ST $RTime /f
}
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName( "Microsoft.VisualBasic") | Out-Null
$Title = "Computer Reboot Notification"
$Message = "Your computer will automatically restart in :"
$Button1Text = "Restart now"
$Button2Text = "Postpone for 1 hour"
$Button3Text = "Postpone for 4 hours"
$Form = $null
$Button1 = $null
$Button2 = $null
$Label = $null
$TextBox = $null
$Result = $null
$timerUpdate = New-Object 'System.Windows.Forms.Timer'
#$TotalTime = 14400 #in seconds
$TotalTime = 60 #in seconds
Create-GetSchedTime -SchedTime $TotalTime
$timerUpdate_Tick={
      # Define countdown timer
      [TimeSpan]$span = $script:StartTime - (Get-Date)
      # Update the display
      $hours = "{0:00}" -f $span.Hours
      $mins = "{0:00}" -f $span.Minutes
    $secs = "{0:00}" -f $span.Seconds
    $labelTime.Text = "{0}:{1}:{2}" -f $hours, $mins, $secs
      $timerUpdate.Start()
      if ($span.TotalSeconds -le 0)
      {
            $timerUpdate.Stop()
            &schtasks /delete /tn "Post Maintenance Restart" /f
            shutdown -r -f /t 0
      }
}
$Form_StoreValues_Closing=
      {
            #Store the control values
      }

$Form_Cleanup_FormClosed=
      {
            #Remove all event handlers from the controls
            try
            {
                  $Form.remove_Load($Form_Load)
                  $timerUpdate.remove_Tick($timerUpdate_Tick)
                  #$Form.remove_Load($Form_StateCorrection_Load)
                  $Form.remove_Closing($Form_StoreValues_Closing)
                  $Form.remove_FormClosed($Form_Cleanup_FormClosed)
            }
            catch [Exception]
            { }
      }

# Form
$Form = New-Object -TypeName System.Windows.Forms.Form
$Form.Text = $Title
$Form.Size = New-Object -TypeName System.Drawing.Size(407,205)
$Form.StartPosition = "CenterScreen"
$Form.Topmost = $true
$Form.KeyPreview = $true
$Form.ShowInTaskbar = $Formalse
$Form.FormBorderStyle = "FixedDialog"
$Form.MaximizeBox = $Formalse
$Form.MinimizeBox = $true
$Icon = [system.drawing.icon]::ExtractAssociatedIcon("c:\Windows\System32\UserAccountControlSettings.exe")
$Form.Icon = $Icon

# Button One (Reboot/Shutdown Now)
$Button1 = New-Object -TypeName System.Windows.Forms.Button
$Button1.Size = New-Object -TypeName System.Drawing.Size(90,25)
$Button1.Location = New-Object -TypeName System.Drawing.Size(10,135)
$Button1.Text = $Button1Text
$Button1.Font = 'Tahoma, 10pt'
$Button1.Add_Click({
      &schtasks /delete /tn "Post Maintenance Restart" /f
      shutdown -r -f /t 0
      $Form.Close()
})
$Form.Controls.Add($Button1)
# Button Two (Postpone for 1 Hour)
$Button2 = New-Object -TypeName System.Windows.Forms.Button
$Button2.Size = New-Object -TypeName System.Drawing.Size(133,25)
$Button2.Location = New-Object -TypeName System.Drawing.Size(105,135)
$Button2.Text = $Button2Text
$Button2.Font = 'Tahoma, 10pt'
$Button2.Add_Click({
      $Button2.Enabled = $False
      $timerUpdate.Stop()
      #$TotalTime = 3600
      $TotalTime = 30
      Create-GetSchedTime -SchedTime $TotalTime
      $timerUpdate.add_Tick($timerUpdate_Tick)
      $timerUpdate.Start()
})
$Form.Controls.Add($Button2)

# Button Three (Postpone for 4 Hours)
$Button3 = New-Object -TypeName System.Windows.Forms.Button
$Button3.Size = New-Object -TypeName System.Drawing.Size(140,25)
$Button3.Location = New-Object -TypeName System.Drawing.Size(243,135)
$Button3.Text = $Button3Text
$Button3.Font = 'Tahoma, 10pt'
$Button3.Add_Click({
      $Button2.Enabled = $False
      $timerUpdate.Stop()
      $TotalTime = 14400
      Create-GetSchedTime -SchedTime $TotalTime
      $timerUpdate.add_Tick($timerUpdate_Tick)
      $timerUpdate.Start()
})
$Form.Controls.Add($Button3)
$Button3.Enabled = $False

# Label
$Label = New-Object -TypeName System.Windows.Forms.Label
$Label.Size = New-Object -TypeName System.Drawing.Size(330,25)
$Label.Location = New-Object -TypeName System.Drawing.Size(10,15)
$Label.Text = $Message
$label.Font = 'Tahoma, 10pt'
$Form.Controls.Add($Label)

# Label2
$Label2 = New-Object -TypeName System.Windows.Forms.Label
$Label2.Size = New-Object -TypeName System.Drawing.Size(355,30)
$Label2.Location = New-Object -TypeName System.Drawing.Size(10,100)
$Label2.Text = $Message2
$label2.Font = 'Tahoma, 10pt'
$Form.Controls.Add($Label2)

# labelTime
$labelTime = New-Object 'System.Windows.Forms.Label'
$labelTime.AutoSize = $True
$labelTime.Font = 'Arial, 26pt, style=Bold'
$labelTime.Location = '120, 60'
$labelTime.Name = 'labelTime'
$labelTime.Size = '43, 15'
$labelTime.TextAlign = 'MiddleCenter'
$labelTime.ForeColor = "Red"
$Form.Controls.Add($labelTime)

#Start the timer
$timerUpdate.add_Tick($timerUpdate_Tick)
$timerUpdate.Start()
# Show
$Form.Add_Shown({$Form.Activate()})
#Clean up the control events
$Form.add_FormClosed($Form_Cleanup_FormClosed)
#Store the control values when form is closing
#$Form.add_Closing($Form_StoreValues_Closing)
$Form.Add_Closing({$_.cancel = $true})
#Show the Form
$Form.ShowDialog() | Out-Null
#$Form.Focused
#return $Form.ShowDialog()

#$Form.Add_Closing({$_.cancel = $false})
#Show the Form
#return $Form.ShowDialog()

【问题讨论】:

  • 你也试过-WindowStyle Minimized吗?
  • 似乎与 this 重复。
  • 还考虑使用 PS2EXE 来处理这种事情——它将你的脚本编译成可执行文件,并有一个专门用于隐藏 PS 窗口的开关。 gallery.technet.microsoft.com/scriptcenter/…
  • 谢谢,当我在 Powershell 之后放置“-WindowStyle Hidden”开关时,它起作用了。感谢你的回复。 @DevX,实际上我正在尝试做相反的事情。
  • 谢谢@Sceptalist,会检查的。

标签: winforms powershell modal-dialog psexec reboot


【解决方案1】:

您需要为此使用 .NET。这是一个函数:

# .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()
    $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 事件中调用它。

$OnFormLoad = 
{
    Hide-Console
}

要再次显示,请使用 Show-Console。

署名:Opening PowerShell Script and hide Command Prompt, but not the GUI

【讨论】:

    【解决方案2】:

    最终我发现了这个问题。我将“-WindowStyle Hidden”放在命令末尾,而不是在 Powershell 之后。所以这不起作用。

    Powershell -File CustomRestart.ps1 -WindowStyle Hidden
    

    这也适用于 PSEXEC。

    Powershell -WindowStyle Hidden -File CustomRestart.ps1
    

    现在我在用户单击“立即重启”按钮后添加了一个是/否确认对话框,如果单击是,它将重新启动,如果不是,则什么都没有,只是确认框消失。如果你看一下 $Button1.Add_Click 事件,就会有代码。

    问题是:当我在 Pwershell ISE 上运行它时,它运行良好(确认框显示并工作),但是从命令或运行菜单运行时,它不会显示确认框,因此单击后没有效果“立即重启”按钮。

    完整代码如下:

    Function Create-GetSchedTime {   
    Param(   
    $SchedTime   
    )
          $script:StartTime = (Get-Date).AddSeconds($TotalTime)
          $RestartDate = ((get-date).AddSeconds($TotalTime)).AddMinutes(-5)
          $RDate = (Get-Date $RestartDate -f 'dd.MM.yyyy') -replace "\.","/"      # 16/03/2016
          $RTime = Get-Date $RestartDate -f 'HH:mm'                                    # 09:31
          #&schtasks /delete /tn "Post Maintenance Restart" /f
          #&schtasks /create /sc once /tn "Post Maintenance Restart" /tr "'C:\Windows\system32\cmd.exe' /c shutdown -r -f -t 300" /SD $RDate /ST $RTime /f
    }
    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
    [System.Reflection.Assembly]::LoadWithPartialName( "Microsoft.VisualBasic") | Out-Null
    $Title = "Computer Reboot Notification"
    #$Message = "Your computer will automatically restart in :"
    $Message = "Your computer has been updated with latest software and requires a reboot. Please save your work and click ""Restart now"" to reboot it now.`nYour computer will automatically reboot in :"
    $Button1Text = "Restart now"
    $Button2Text = "Postpone for 1 hour"
    $Button3Text = "Postpone for 4 hours"
    $Form = $null
    $Button1 = $null
    $Button2 = $null
    $Label = $null
    $TextBox = $null
    $Result = $null
    $timerUpdate = New-Object 'System.Windows.Forms.Timer'
    $TotalTime = 14400 #in seconds
    #$TotalTime = 60 #in seconds
    Create-GetSchedTime -SchedTime $TotalTime
    $timerUpdate_Tick={
          # Define countdown timer
          [TimeSpan]$span = $script:StartTime - (Get-Date)
          # Update the display
          $hours = "{0:00}" -f $span.Hours
          $mins = "{0:00}" -f $span.Minutes
        $secs = "{0:00}" -f $span.Seconds
        $labelTime.Text = "{0}:{1}:{2}" -f $hours, $mins, $secs
          $timerUpdate.Start()
          if ($span.TotalSeconds -le 0)
          {
                $timerUpdate.Stop()
                #&schtasks /delete /tn "Post Maintenance Restart" /f
                shutdown -r -f /t 0
          }
    }
    $Form_StoreValues_Closing=
          {
                #Store the control values
          }
    
    $Form_Cleanup_FormClosed=
          {
                #Remove all event handlers from the controls
                try
                {
                      $Form.remove_Load($Form_Load)
                      $timerUpdate.remove_Tick($timerUpdate_Tick)
                      #$Form.remove_Load($Form_StateCorrection_Load)
                      $Form.remove_Closing($Form_StoreValues_Closing)
                      $Form.remove_FormClosed($Form_Cleanup_FormClosed)
                }
                catch [Exception]
                { }
          }
    
    # Form
    $Form = New-Object -TypeName System.Windows.Forms.Form
    $Form.Text = $Title
    $Form.Size = New-Object -TypeName System.Drawing.Size(407,205)
    $Form.StartPosition = "CenterScreen"
    $Form.Topmost = $true
    $Form.KeyPreview = $true
    $Form.ShowInTaskbar = $Formalse
    $Form.FormBorderStyle = "FixedDialog"
    $Form.MaximizeBox = $Formalse
    $Form.MinimizeBox = $true
    $Icon = [system.drawing.icon]::ExtractAssociatedIcon("c:\Windows\System32\UserAccountControlSettings.exe")
    $Form.Icon = $Icon
    
    # Button One (Reboot/Shutdown Now)
    $Button1 = New-Object -TypeName System.Windows.Forms.Button
    $Button1.Size = New-Object -TypeName System.Drawing.Size(90,25)
    #$Button1.Location = New-Object -TypeName System.Drawing.Size(10,135)
    $Button1.Location = New-Object -TypeName System.Drawing.Size(10,145)
    $Button1.Text = $Button1Text
    $Button1.Font = 'Tahoma, 10pt'
    $Button1.Add_Click({
    
        $msgBoxInput =  [System.Windows.MessageBox]::Show('Are you sure you want to reboot now?','Computer Reboot Confirmation','YesNo','Warning')
        switch  ($msgBoxInput) {
            'Yes' {
                shutdown -r -f /t 0
                $Form.Close() 
                  }
    
            'No' {
              ## Do something
                }
                                }
    
    })
    $Form.Controls.Add($Button1)
    # Button Two (Postpone for 1 Hour)
    $Button2 = New-Object -TypeName System.Windows.Forms.Button
    $Button2.Size = New-Object -TypeName System.Drawing.Size(133,25)
    #$Button2.Location = New-Object -TypeName System.Drawing.Size(105,135)
    $Button2.Location = New-Object -TypeName System.Drawing.Size(105,145)
    $Button2.Text = $Button2Text
    $Button2.Font = 'Tahoma, 10pt'
    $Button2.Add_Click({
          $Button2.Enabled = $False
          $timerUpdate.Stop()
          $TotalTime = 3600
          #$TotalTime = 30
          Create-GetSchedTime -SchedTime $TotalTime
          $timerUpdate.add_Tick($timerUpdate_Tick)
          $timerUpdate.Start()
    })
    $Form.Controls.Add($Button2)
    
    # Button Three (Postpone for 4 Hours)
    $Button3 = New-Object -TypeName System.Windows.Forms.Button
    $Button3.Size = New-Object -TypeName System.Drawing.Size(140,25)
    #$Button3.Location = New-Object -TypeName System.Drawing.Size(243,135)
    $Button3.Location = New-Object -TypeName System.Drawing.Size(243,145)
    $Button3.Text = $Button3Text
    $Button3.Font = 'Tahoma, 10pt'
    $Button3.Add_Click({
          $Button2.Enabled = $False
          $timerUpdate.Stop()
          $TotalTime = 14400
          Create-GetSchedTime -SchedTime $TotalTime
          $timerUpdate.add_Tick($timerUpdate_Tick)
          $timerUpdate.Start()
    })
    $Form.Controls.Add($Button3)
    $Button3.Enabled = $False
    
    # Label
    $Label = New-Object -TypeName System.Windows.Forms.Label
    $Label.Size = New-Object -TypeName System.Drawing.Size(380,65)
    $Label.Location = New-Object -TypeName System.Drawing.Size(10,15)
    $Label.Text = $Message
    $label.Font = 'Tahoma, 10pt'
    $Form.Controls.Add($Label)
    
    # Label2
    #$Label2 = New-Object -TypeName System.Windows.Forms.Label
    #$Label2.Size = New-Object -TypeName System.Drawing.Size(355,30)
    #$Label2.Location = New-Object -TypeName System.Drawing.Size(10,100)
    #$Label2.Text = $Message2
    #$label2.Font = 'Tahoma, 10pt'
    #$Form.Controls.Add($Label2)
    
    # labelTime
    $labelTime = New-Object 'System.Windows.Forms.Label'
    $labelTime.AutoSize = $True
    $labelTime.Font = 'Arial, 26pt, style=Bold'
    #$labelTime.Location = '120, 60'
    $labelTime.Location = '120, 90'
    $labelTime.Name = 'labelTime'
    $labelTime.Size = '43, 15'
    $labelTime.TextAlign = 'MiddleCenter'
    $labelTime.ForeColor = "Red"
    $Form.Controls.Add($labelTime)
    
    #Start the timer
    $timerUpdate.add_Tick($timerUpdate_Tick)
    $timerUpdate.Start()
    # Show
    $Form.Add_Shown({$Form.Activate()})
    #Clean up the control events
    $Form.add_FormClosed($Form_Cleanup_FormClosed)
    #Store the control values when form is closing
    #$Form.add_Closing($Form_StoreValues_Closing)
    $Form.Add_Closing({$_.cancel = $true})
    #Show the Form
    $Form.ShowDialog() | Out-Null
    #$Form.Focused
    #return $Form.ShowDialog()
    
    #$Form.Add_Closing({$_.cancel = $false})
    #Show the Form
    #return $Form.ShowDialog()
    

    【讨论】:

    • 这太棒了。我一直在用我的 Windows Forms PowerShell 脚本来寻找它,但是从注册表的 Run 键运行它。我不敢相信它就像将-WindowStyle Hidden 放在powershell.exe 之后一样简单。
    最近更新 更多