为什么从任务栏关闭时,PowerShell脚本会卡住?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么从任务栏关闭时,PowerShell脚本会卡住?相关的知识,希望对你有一定的参考价值。

我正在尝试编写一个小脚本,通过它我可以将文件中的关键字更改为我在文本框中键入的内容。我制作了一个包含文件的目录副本,并将它们使用唯一的目录名称复制到名为temp的映射中。它还会启动一个文件。关闭脚本或按Cancel时,关闭启动的程序,并再次删除文件。

一切正常,但是每当我通过Windows任务栏关闭表单,并且想再次启动脚本时,即使最小化,表单也不会显示,而PowerShell控制台也会显示,即使完全最小化,也无法编辑任何内容。我可以用Ctrl + C将其关闭,但是下次启动脚本时,它将再次卡住。

这是我编写的第一个脚本,不确定如何解决此问题。

如果停止进程时有一种方法可以删除该唯一随机目录中的文件,那就更好了。例如,如果我关闭通过脚本打开的文件settings.txt,则删除所有文件。

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")  
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
[void] [System.Windows.Forms.Application]::EnableVisualStyles() 

# Hide PowerShell Console
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);
'
$consolePtr = [Console.Window]::GetConsoleWindow()
[Console.Window]::ShowWindow($consolePtr, 0)


# makes form
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Data Entry Form'
$form.Size = New-Object System.Drawing.Size(200,180)
$form.StartPosition = 'CenterScreen'

$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = New-Object System.Drawing.Point(10,70)
$okButton.Size = New-Object System.Drawing.Size(160,20)
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)


$cancelButton = New-Object System.Windows.Forms.Button
$cancelButton.Location = New-Object System.Drawing.Point(10,100)
$cancelButton.Size = New-Object System.Drawing.Size(160,20)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(170,20)
$label.Text = 'Please enter the Server name:'
$form.Controls.Add($label)

$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(160,20)
$form.Controls.Add($textBox)

$form.Topmost = $true

$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()

if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
    $server = $textBox.Text
    $server

    $folder = [System.IO.Path]::GetRandomFileName()

    Copy-Item -Path C:powershellmain  -Destination c:powershell	emp –Recurse

    Rename-Item -Path "C:powershell	empmain" -NewName $folder

    (Get-Content -Path "C:powershell	emp$foldersettings.txt" -raw) -replace '<SERVERNAME>',"$server" | Set-Content "C:powershell	emp$foldersettings.txt"

    $app = (Start-Process "C:powershell	emp$foldersettings.txt" -passthru).ID


$form.Size = New-Object System.Drawing.Size(250,100)
$form.StartPosition = 'CenterScreen'

$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(200,20)
$label.Text = "Click 'cancel' to close Server $server"


$cancelButton.Location = New-Object System.Drawing.Point(10,40)
$cancelButton.Size = New-Object System.Drawing.Size(180,20)
$cancelButton.Text = 'Cancel'


    $result = $form.ShowDialog()

    if($result -eq [System.Windows.Forms.DialogResult]::cancel)
    {
        Stop-Process $app
        Remove-Item –path "C:powershell	emp$folder" –recurse
    }


}
答案

重新启动计算机以清除内存泄漏,然后测试此代码。

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")  
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
[void] [System.Windows.Forms.Application]::EnableVisualStyles() 

# The reason that your form does not open sometime is caused by a memory leak.  The code below should resolve the issue.
# If you add to the GUI them add that control below. If a variable does not have a .dispose() then .NET will clean it up.
# These are Events and will fire when the window closes.
# These will fix the memory leak issue.

$Form.Add_FormClosing({  
    $form.Dispose()
    $okButton.Dispose()
    $cancelButton.Dispose()
    $label.Dispose()
    $textBox.Dispose()
})

$Form2.Add_FormClosing({  
    $form2.Dispose()
    $label2.Dispose()
    $cancelButton2.Dispose()
})

# Hide PowerShell Console
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);
'
$consolePtr = [Console.Window]::GetConsoleWindow()
[Console.Window]::ShowWindow($consolePtr, 0)


# makes form
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Data Entry Form'
$form.Size = New-Object System.Drawing.Size(200,180)
$form.StartPosition = 'CenterScreen'

$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = New-Object System.Drawing.Point(10,70)
$okButton.Size = New-Object System.Drawing.Size(160,20)
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)


$cancelButton = New-Object System.Windows.Forms.Button
$cancelButton.Location = New-Object System.Drawing.Point(10,100)
$cancelButton.Size = New-Object System.Drawing.Size(160,20)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(170,20)
$label.Text = 'Please enter the Server name:'
$form.Controls.Add($label)

$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(160,20)
$form.Controls.Add($textBox)

$form.Topmost = $true

# Is this line needed
#$form.Add_Shown({$textBox.Select()}) # this sometimes will not let me type in the textbox
$result = $form.ShowDialog()

if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
    $server = $textBox.Text
    $server

    $folder = [System.IO.Path]::GetRandomFileName()

    Copy-Item -Path C:powershellmain  -Destination c:powershell	emp –Recurse

    Rename-Item -Path "C:powershell	empmain" -NewName $folder

    (Get-Content -Path "C:powershell	emp$foldersettings.txt" -raw) -replace '<SERVERNAME>',"$server" | Set-Content "C:powershell	emp$foldersettings.txt"

    $app = (Start-Process "C:powershell	emp$foldersettings.txt" -passthru).ID

# This is winform.  They work on comobjects and you not reuse the variable name because it will not
# free up memory resource when the are reused.  I rename your variables to get around this issue.
$form2 = New-Object System.Windows.Forms.Form
$form2.Size = New-Object System.Drawing.Size(350,250)    
$form2.StartPosition = 'CenterScreen'


$label2 = New-Object System.Windows.Forms.Label
$label2.Location = New-Object System.Drawing.Point(10,20)
$label2.Size = New-Object System.Drawing.Size(350,20)
$label2.Text = "Click 'cancel' to close Server $server"
$form2.Controls.Add($label2)

$cancelButton2 = New-Object System.Windows.Forms.Button
$cancelButton2.Location = New-Object System.Drawing.Point(10,80)
$cancelButton2.Size = New-Object System.Drawing.Size(180,40)
$cancelButton2.Text = 'Cancel'
$form2.CancelButton = $cancelButton2
$form2.Controls.Add($cancelButton2)


    $result = $form2.ShowDialog()

    if($result -eq [System.Windows.Forms.DialogResult]::cancel)
    {
        Stop-Process $app
        Remove-Item –path "C:powershell	emp$folder" –recurse
    }


}

以上是关于为什么从任务栏关闭时,PowerShell脚本会卡住?的主要内容,如果未能解决你的问题,请参考以下文章

如何在powershell 运行bat

电脑上不管开啥窗口最小化,关闭都会卡在屏幕上。

Chocolatey 和 powershell:从任务栏和文件关联中固定和取消固定程序

从屏幕底部滑动时,任务栏应该可见 - UWP [关闭]

仅在非交互式运行时如何从 Powershell 脚本返回退出代码

未从任务栏关闭事件正确关闭