【问题标题】:Powershell "Exit" not behaving like it shouldPowershell“退出”的行为不像它应该的那样
【发布时间】:2015-03-17 04:49:30
【问题描述】:

今天我的一个 PowerShell 脚本中出现了一个奇怪的问题:

环境信息:我所说的 PowerShell 脚本正在被 VBScript 调用。

if($VM -eq "Yes") {
    Add-PSSnapin VMware.VimAutomation.Core
    Connect-VIServer -Server $VMHost -User $VMUser -Password $VMPassword
    $Snapshot = $null
    Try {
        $Snapshot = New-Snapshot -Name $NameofSnapshot -VM $ServerName -Memory
        $CurrentPatchingState = "1;$Servername;Status=1;$(Get-Date -format 'dd.MM.yyyy hh:mm:ss') Created Snapshot" | Out-File -Filepath  "C:\$Servername.txt" -Append -encoding ASCII 
    } Catch [system.exception] {
        $CurrentPatchingState = "2;$Servername;Status=2;$(Get-Date -format 'dd.MM.yyyy hh:mm:ss') Wasnt able to take a Snapshot - Aborting" | Out-File -Filepath  "C:\$Servername.txt" -Append -encoding ASCII 
        Disconnect-VIServer -Server $VMHost -Confirm:$false
        exit
    }

    if ($Snapshot -eq $null) {
        $CurrentPatchingState = "2;$Servername;Status=2;$(Get-Date -format 'dd.MM.yyyy hh:mm:ss') Wasnt able to get a Clean Snapshot - Aborting" | Out-File -Filepath  "C:\$Servername.txt" -Append -encoding ASCII 
        Disconnect-VIServer -Server $VMHost -Confirm:$false
        exit
    }
}

今天脚本在这部分失败了。日志文件显示:

2;xxxxxxxxxxxxxxx;Status=2;18.01.2015 11:01:51 Wasnt able to take a Snapshot - Aborting
2;xxxxxxxxxxxxxxx;Status=2;18.01.2015 11:01:51 Wasnt able to get a Clean Snapshot - Aborting

这怎么会发生,因为脚本应该在第一次捕获时停止?

【问题讨论】:

  • 你应该在 try 块中使用 break,exit 不是 powershell 关键字。请参阅相关帖子:stackoverflow.com/a/23703056/381149
  • 也许我没有让自己足够清楚,我想让hole脚本停止这就是我使用Exit的原因:这将“退出”当前运行的上下文。如果您从脚本调用此命令,它将退出脚本。脚本终止,但在第二个出口不是第一个。
  • 退出在 [scriptblock] 内,这是它自己的上下文 exit '早期'离开该脚本块并返回到父上下文,脚本本身......第二个退出在脚本的上下文,因此正确终止。

标签: powershell exception-handling exit


【解决方案1】:

AFAICS 代码应该符合您的预期。要缓解此问题,您可以将内部 if 语句移动到 try 块内。我还将断开连接语句移动到 finally 块。

if($VM -eq "Yes") {
    Add-PSSnapin VMware.VimAutomation.Core
    Connect-VIServer -Server $VMHost -User $VMUser -Password $VMPassword
    $Snapshot = $null
    Try {
        $Snapshot = New-Snapshot -Name $NameofSnapshot -VM $ServerName -Memory
        $CurrentPatchingState = "1;$Servername;Status=1;$(Get-Date -format 'dd.MM.yyyy hh:mm:ss') Created Snapshot" | Out-File -Filepath  "C:\$Servername.txt" -Append -encoding ASCII 
        if ($Snapshot -eq $null) {
            $CurrentPatchingState = "2;$Servername;Status=2;$(Get-Date -format 'dd.MM.yyyy hh:mm:ss') Wasnt able to get a Clean Snapshot - Aborting" | Out-File -Filepath  "C:\$Servername.txt" -Append -encoding ASCII 
            exit
        }
    } Catch [system.exception] {
        $CurrentPatchingState = "2;$Servername;Status=2;$(Get-Date -format 'dd.MM.yyyy hh:mm:ss') Wasnt able to take a Snapshot - Aborting" | Out-File -Filepath  "C:\$Servername.txt" -Append -encoding ASCII 
        exit
    } finally {
        Disconnect-VIServer -Server $VMHost -Confirm:$false
    }
}

【讨论】:

  • true 会迁移问题。我对解决方案的问题是,如果这里出现问题,我想肯定地确定脚本退出,走这条路线是否更有可能脚本继续运行(因为 catch 退出之前没有工作)?对我来说幸运的是,如果退出了脚本,否则我会做很多事情而没有快照来从服务器上发生的任何错误中恢复。让我害怕的是 if 块甚至被触动了
  • 一个大学提出的想法。可能是这种情况,断开连接的 VIServer 引发了异常(服务器在大约 20 秒内无法访问)。所以 Disconnect-Vi 服务器可能产生了一个错误并且没有设置 Erroractionpreference。因此它以非终端错误退出了 Catch 块并跳过了退出。然后继续并(成功地)断开 if 块中的 Vi 服务器,然后退出。这听起来合理吗?
  • @Ceuse 嗯...如果Disconnect-VIServer 在错误操作设置为SilentlyContinue 时导致终止错误,这将解释观察到的行为。建议的更改应该可以缓解这种情况。
  • 我会将此标记为答案,并希望它永远不会再发生。虽然我只添加了 finaly 块并将 if 语句保留在 try 块之外。
【解决方案2】:

试试这个:

    Try {
            $Snapshot = New-Snapshot -Name $NameofSnapshot -VM $ServerName -Memory -ErrorAction Stop
            $CurrentPatchingState = "1;$Servername;Status=1;$(Get-Date -format 'dd.MM.yyyy hh:mm:ss') Created Snapshot" | Out-File -Filepath  "C:\$Servername.txt" -Append -encoding ASCII 
        }
Catch {
            $CurrentPatchingState = "2;$Servername;Status=2;$(Get-Date -format 'dd.MM.yyyy hh:mm:ss') Wasnt able to take a Snapshot - Aborting" | Out-File -Filepath  "C:\$Servername.txt" -Append -encoding ASCII 
            Disconnect-VIServer -Server $VMHost -Confirm:$false
            exit
        }

只有在 Try 块中发生终止错误时才会执行 Catch 块。 添加“-ErrorAction Stop”确保快照创建过程中的任何错误都将被视为终止错误。

其次,删除 Catch 块开头的“[system.exception]”。这样可以确保 Catch 块适用于任何类型的异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-03
    • 2018-08-28
    相关资源
    最近更新 更多