【问题标题】:Try.. catch.. finally fails during Read-HostTry.. catch.. 最终在 Read-Host 期间失败
【发布时间】:2020-08-22 23:37:04
【问题描述】:

当脚本执行Read-Host cmdlet 时,关闭窗口不会激活finally 块。下面是一个任意但功能最少的示例。我正在使用 PowerShell 5.0。 Beep() 只是为了让 finally 块的执行显而易见。

try {
    $value= Read-Host -Prompt "Input"
    sleep 5
} finally {
    [Console]::Beep(880,1000)
}
  1. 如果在Read-Host 期间单击红色 X 关闭窗口 finally 块不会执行。
  2. 如果在sleep 期间单击红色 X 关闭窗口 finally 块将执行。
  3. 如果您在任何时候使用 Ctrl-C 中断,finally 块将执行。

关于为什么在Read-Host 期间关闭窗口时finally 块没有执行,我是否缺少一些基本的东西?

完整的案例涉及在 Amazon Snowball 设备上启动服务,如果脚本关闭则需要停止服务。完整的案例行为反映了上面的示例案例。

编辑:由于 cmets 说 $input 是保留变量,将变量从 $input 更改为 $value。不会改变行为。

【问题讨论】:

  • [1] $Input 是保留的自动变量。除非您完全确定您了解副作用,否则不要写信给它。 [grin] [2] 您可能会看到“主机”方式与各种 PoSh 流交互的结果。我认为在控制台直接操作中杀死控制台会完全绕过 powershell。
  • [1] 我将代码 sn-p 更新为没有 $input。即使使用不同的变量,行为也是相同的。 [2] 我确信有区别。奇怪的是在sleep DOES 激活finally 期间杀死控制台窗口。
  • 这可能是因为您不再直接在主机中操作 ...您回到了 PoSh 中。
  • 在这种情况下有没有办法执行finally 块?即使用户只是关闭窗口,我也想运行一些清理代码。
  • CRTL+C 表示停止运行代码并返回提示。 “X”,表示现在退出会话。如果用户关闭“x”以关闭控制台窗口框并且不响应读取主机,则无论您做什么,都不会发生任何代码。无论您使用哪种语言. 这样做的唯一方法是创建自己的表单以收集用户信息,并在表单关闭/处置事件上采取行动。您可以禁用表单中的“X”并强制使用关闭按钮和因此触发代码形式。

标签: powershell try-catch-finally read-host


【解决方案1】:

继续我的评论。

控制台主机有点不灵活,这取决于您在本机上所做的事情。该“X”与 PowerShell 会话/进程有关,而不是与其中运行的代码有关。因此,为什么 CRTL+C 有效,因为您要停止代码运行,而不是 PowerShell 会话/进程。

这里有几种方法可以让您思考您的选择。

###############################################################################
#region Begin initialize environment                                          #
###############################################################################
    
    # Initialize GUI resources
    Add-Type -AssemblyName  System.Drawing,
                            PresentationCore,
                            PresentationFramework,
                            System.Windows.Forms,
                            microsoft.VisualBasic
    [System.Windows.Forms.Application]::EnableVisualStyles()
    
###############################################################################
#endregion End initialize environment                                         #
###############################################################################

# Prevent the MessageBox UI from closing until an entry is made
while (
    ($UserEntry = [Microsoft.VisualBasic.Interaction]::
    InputBox('Enter a Host/User', 'Add Item')) -eq ''
)
{
    [System.Windows.Forms.MessageBox]::
    Show(
        'Entry cannot be empty', 
        "Error on close" , 
        0, 
        [System.Windows.MessageBoxImage]::Error
    )
}
"You entered $UserEntry"

或完整的自定义表单以进行更精细的控制

# Initialize the form object
$form = New-Object System.Windows.Forms.Form

# Define form elements
$form.Text = 'Data Entry'

$txtUserInput           = New-Object system.Windows.Forms.TextBox
$txtUserInput.multiline = $false
$txtUserInput.width     = 120
$txtUserInput.height    = 20
$txtUserInput.location  = New-Object System.Drawing.Point(40,29)
$txtUserInput.Font      = 'Microsoft Sans Serif,10'

$form.controls.AddRange(@(
    $txtUserInput
    )
)

# Evaluate form events
$form.Add_Closing(
{
    param
    (
        $Sender,$Event
    )

    $result = [System.Windows.Forms.MessageBox]::Show(
                'Are you sure you want to exit?', 
                'Close', 
                [System.Windows.Forms.MessageBoxButtons]::YesNo
            )

    if ($result -ne [System.Windows.Forms.DialogResult]::Yes)
    {$Event.Cancel = $true}
})

# Start the form
$form.ShowDialog() | Out-Null

# Resource disposal
$form.Dispose()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-16
    • 1970-01-01
    • 2023-01-25
    • 2015-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多