【问题标题】:How to catch plink failure when host not known主机未知时如何捕获 plink 失败
【发布时间】:2013-07-07 01:59:35
【问题描述】:

我的一个脚本有问题。基本上它运行得非常顺利,但它需要一些来自 excel 文件的用户输入。用户可能会导致错误,这就是我的问题。 我的脚本通过 ssh 与 plink (lil PuTTY) 连接到某些设备并向它们发送命令。

现在是真正的问题:如果有人只是拼错了 FQDN,脚本将继续执行,但我需要通过电子邮件报告一个进程已失败。如果有人完全搞砸了 Excel 表,整个脚本就会失败——我需要再次知道。我已经设计了一些参数来向我发送电子邮件。唯一的问题是错误处理。

代码:

try {
  $FQDN | foreach {
    $directory = $dir[$counter]
    $errorzahl = $error.count + [int]1

    &$process -ssh -l $loginname[$counter] -pw $pw[$counter] $FQDN[$counter] "config global execute $cmd config ftp $filename $FTPADRESS $FTPLOGIN $FTPPW"
    $names = $KN[$counter]
    if ($error.Count -gt $errorzahl) {
      $names = $KN[$counter]
      $smtp.Send("$ErrorSender", "$ErrorRecipient", "Powershell Script Error",
                 "$Emailinhaltlow, Problems: $names")
    }
    $counter = $counter + [int]1
  } 

} catch {
  $errornachricht = $_.Exception.Message
  if ($_.Exception.Message) {
    $smtp.Send("$ErrorSender", "$ErrorRecipient", "Powershell Error",
               "$Emailinhalt, Probleme mit: $names")
    unregister-scheduledjob -Name $jobname -Force
  }
}

这不能正常工作。我为数组 FQDN 中的每个字符串收到一封电子邮件,如果 excel 表中只有一个错误,并且“try and catch”也会向我发送错误邮件,如果脚本完成其工作,不应该发生什么。

如果我只是删除这个条件:

if ($error.Count -gt $errorzahl) {
  $names = $KN[$counter]
  $smtp.Send("$ErrorSender", "$ErrorRecipient", "Powershell Error",
             "$Emailinhaltlow, Problems: $names")
}

我没有收到任何电子邮件。即使foreach循环中有一些小错误。

编辑错误代码(Powershell 输出为红色) 错误 - 如果有人忘记使用 ssh 连接一次并接受证书一次 - !停止整个脚本!:

plink.exe : The server's host key is not cached in the registry. You
In C:\Users\USER\Desktop\VPNscript.ps1:10 Zeichen:1
+ &$process -ssh -l $loginname -pw $pw $FQDN "y
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (The server's ho...e registry. You:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError

have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 c2:ea:62:af:70:14:e4:f0:a0:79:88:45:85:fc:cd:cc
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n) 

主要不是主题,但如果我已经上传了错误,有人可能会修复一个,而不会提出新问题。这是其中之一。我无法将“y”发送到 plink。

另一个错误 - 如果 FQDN 错误(不存在 - Excelsheet 中的拼写错误) - 脚本将继续,但在 excelsheet 中显示一行失败:

plink.exe : Unable to open connection:
In Zeile:73 Zeichen:1
+ &$process -ssh -l $loginname[$counter] -pw $pw[$counter] $FQDN[$counter] "config ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (Unable to open connection::String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError

Host does not exist

编辑 2:

"y" | &$process -ssh -l $Loginname -pw $pw $FQDN
plink.exe : The server's host key is not cached in the registry. You
In Zeile:6 Zeichen:7
+ "y" | &$process -ssh -l $Loginname -pw $pw $FQDN
+       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (The server's ho...e registry. You:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError

have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 c2:ea:62:af:70:14:e4:f0:a0:79:88:45:85:fc:cd:cc
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n) 

【问题讨论】:

    标签: powershell error-handling try-catch


    【解决方案1】:

    plink 失败不会引发 (PowerShell) 错误,因此不会增加 $error 计数。如果要检测命令是成功还是失败,请检查$LastExitCode

    至于有人“弄乱了 Excel 工作表”:在这种情况下,脚本究竟是如何失败的?处理此错误将很大程度上取决于实际错误。


    主机密钥问题可以通过在命令中回显“y”来处理:

    "y" | &$process -ssh -l $loginname[$counter] ...
    

    或在运行命令之前将密钥写入注册表:

    $key = "HKCU:\Software\SimonTatham\PuTTY\SshHostKeys"
    $val = "0x23,0x3857aee9..."
    Set-ItemProperty $key "rsa2@22:$($FQDN[$counter])" $val
    
    &$process -ssh -l $loginname[$counter] ...
    

    针对不存在的 FQDN 运行 plink 并没有在我的测试中引发终止错误:

    PS C:\> $process = "plink.exe" PS C:\> $fqdn = "correct.intern.example.org", "fail.intern.example.org" PS C:\> nslookup $fqdn[1] 服务器:ns.intern.example.org 地址:10.42.23.1 DNS 请求超时。 超时为 2 秒。 DNS 请求超时。 超时为 2 秒。 *** ns.intern.example.org 找不到 fail.intern.example.org:不存在的域 PS C:\> &$process -ssh -l 用户名 $fqdn[1] "echo foo" 无法打开连接: 主机不存在

    即使我设置了$ErrorActionPreference = "stop"

    但是,如果您确实收到终止错误,它也应该增加 $error.Count。但是,您的检查不会起作用,因为您记得之前的错误计数加一

    $errorzahl = $error.Count + [int]1
    

    然后检查新的错误计数是否大于

    if ($error.Count -gt $errorzahl) {
      ...
    

    试试这个:

    $errorzahl = $error.Count
    ...
    if ($error.Count -gt $errorzahl) {
      ...
    

    【讨论】:

    • 如果@plink 没有抛出 PowerShell 错误,我很困惑为什么我会得到例如。来自内部 $errormessage 的 5 条消息(考虑到我只是输入了一个错误)。起初我的脚本读取 excel 文件。如果一个 FQDN 搞砸了,什么也不会发生,除了 foreach 的一部分不起作用。但是,如果有人删除添加单元格或搞砸了订单。没有一个命令会起作用。如果有人忘记将 ssl 证书加载到 Windows 注册表中 - plink.exe 将卡住并抛出错误 - 脚本将无法继续。
    • 我不知道您遇到的任何错误,因为您选择不披露它们。如果您希望有人提供帮助,请使用实际的错误消息更新您的问题。
    • 我上传了 2 个错误以使一切变得更容易 - 希望已经足够了。
    • 有帮助,但我没有得到“回声”。你到底在做什么?如果我只是用“y”替换我的整个 &$process ... &$process ...错误保持不变。 - - - 关于$errorzahl;谢谢你,我无法弄清楚这个逻辑错误:)
    • 消息仍在显示,因为主机密钥(尚未)存储在注册表中。然而,"y" | ...y 确认了问题Store key in cache? (y/n)(即它本质上是在输入y 来代替用户)。如果你想摆脱这条消息,你可以简单地将它重定向到$null:"y" | &$process ... 2>$null。 PowerShell 错误(红色消息)是因为您设置了$ErrorActionPreference = "Stop"。将其更改回默认值 ($ErrorActionPreference = "Continue"),该错误也将消失。
    【解决方案2】:

    您可能想要使用这样的函数 (from psake):

    function Exec
    {
        [CmdletBinding()]
        param(
            [Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
            [Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd)
        )
        & $cmd
        if ($lastexitcode -ne 0) {
            throw ("Exec: " + $errorMessage)
        }
    }
    

    现在您可以调用外部程序,例如:

    Exec { external.exe } "Failed!"
    

    【讨论】:

    • 在本例中,我将整个工作代码打包到 $cmd 变量中;我理解对了吗?
    • @XXInvidiaXX - 我已经给出了如何运行它的例子。
    【解决方案3】:

    我认为是 4.0 中的 Powershell 2.0 的问题,返回错误。 要强制抛出错误,请将 2>&1 附加到外部命令。

    & $process -ssh -l username $fqdn "echo foo" 2>&1
    

    【讨论】:

      猜你喜欢
      • 2020-03-08
      • 2022-01-23
      • 2016-05-28
      • 1970-01-01
      • 1970-01-01
      • 2018-11-11
      • 2023-04-10
      • 1970-01-01
      • 2017-10-27
      相关资源
      最近更新 更多