Попробуйте поймать — как поймать ошибку, но продолжить?

#powershell #loops #foreach #try-catch

#powershell #циклы #foreach #попробуйте-поймать

Вопрос:

У меня есть этот скрипт, который выполняет цикл foreach для каждого компьютера, и для каждого компьютера он выполняет цикл через каждый сетевой адаптер. В настоящее время блок Catch не запущен. Что я хочу сделать, это поймать ошибку (обычно потому, что get-wmi не может подключиться к компьютеру), что-то сделать (добавить некоторую информацию в PSCustomObject), но затем перейти к следующей итерации. Как мне поймать ошибку, но также продолжить цикл foreach?

     param (
        [Alias('Hostname')]
        [string[]]$ComputerName = @('pc1','pc2'),
        
        $OldDNSIP = '7.7.7.7',

        $NewDNSIP = @('9.9.9.9','8.8.8.8')
    )

    $FailedArray = @()
    $DHCPArray = @()

    Foreach ($Computer in $ComputerName){
        $NICList = Get-WmiObject Win32_NetworkAdapterConfiguration -computername $Computer | where{$_.IPEnabled -eq "TRUE"}
            Foreach($NIC in $NICList){
                If($NIC.DHCPEnabled -eq $false){

                    Try{
                        $DNSIPs = $NIC.DNSServerSearchOrder
                        if($DNSIPs -contains $OldDNSIP){
                            
                            $NewDNS = $DNSIPs | foreach {$_ -replace $OldDNSIP,$NewDNSIP[0]}
                            $null = $NIC.SetDNSServerSearchOrder($NewDNS)
                        }
                        else{
                            write-host " - Old DNS server IP not found... ignoring"
                        }


                    }
                    Catch{
                        write-host " - Something went wrong... logging to a CSV for review later" -ForegroundColor Red
                        $FailedArray  = [PSCustomObject]@{
                        'Computer' = $Nic.pscomputername
                        'NIC_ID' = $nic.index
                        'NIC_Descrption' = $nic.description}
                    }

                }
                ElseIf($NIC.DHCPEnabled -eq $true){
                    write-host " - DHCP is enabled. Adding this IP, Hostname, Nic Index and DHCP Server to a CSV for reviewing."
                    #add pscomputer, nic id, refernece and dhcp server to DHCPNICArray
                    $DHCPArray  = [PSCustomObject]@{
                    'Computer' = $Nic.pscomputername
                    'NIC_ID' = $nic.index
                    'NIC_Descrption' = $nic.description
                    'DHCPEnabled' =$nic.dhcpenabled
                    'DHCPServer' = $nic.dhcpserver}
                }
            }
    }


$DHCPArray | export-csv c:tempdhcp.csv -NoTypeInformation
$FailedArray | export-csv c:tempfailed.csv -NoTypeInformation
  

Ответ №1:

Если ошибки WMI вызваны сбоем соединения, они возникнут до того, как будут обработаны какие-либо сетевые адаптеры. Если вы хотите перехватить их, а затем продолжить на следующем компьютере, вам нужно переместить try-catch до уровня этого цикла. Если вы также хотите перехватить ошибки, относящиеся к сетевой карте, вам потребуется 2-я попытка-перехват на этом уровне.

Кроме того, рассмотрите возможность использования -ErrorAction Stop параметра или указания $ErrorActionPreference = 'Stop' , чтобы убедиться, что все ошибки завершаются (это означает, что переходите прямо к блоку catch).

Вот пример с комментариями для объяснения:

 $ErrorActionPreference = 'Stop'

foreach ($Computer in $ComputerName) {
    # add a try-catch per computer,
    # to catch WMI errors
    # and then continue with the next computer afterwards
    try {
        # if errors occur here,
        # execution will jump right to the catch block the bottom
        $NICList = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $Computer -ErrorAction Stop | where {
            $_.IPEnabled -eq "TRUE"
        }
        foreach ($NIC in $NICList) {
            # add a try-catch per NIC,
            # to catch errors with this specific NIC and then
            # continue with the next nic
            try {
                if ($NIC.DHCPEnabled -eq $false){
                    $DNSIPs = $NIC.DNSServerSearchOrder
                    if ($DNSIPs -contains $OldDNSIP) {
                        $NewDNS = $DNSIPs | foreach {$_ -replace $OldDNSIP,$NewDNSIP[0]}
                        $null = $NIC.SetDNSServerSearchOrder($NewDNS)
                    }
                    else {
                        write-host " - Old DNS server IP not found... ignoring"
                    }
                }
                elseif ($NIC.DHCPEnabled -eq $true){
                    write-host " - DHCP is enabled. Adding this IP, Hostname, Nic Index and DHCP Server to a CSV for reviewing."
                    $DHCPArray  = [PSCustomObject]@{
                        'Computer' = $Nic.pscomputername
                        'NIC_ID' = $nic.index
                        'NIC_Descrption' = $nic.description
                        'DHCPEnabled' =$nic.dhcpenabled
                        'DHCPServer' = $nic.dhcpserver
                    }
                }
            }
            catch {
                write-host " - Configuring a NIC went wrong... logging to a CSV for review later" -ForegroundColor Red
                # add nic-specific entry
                $FailedArray  = [PSCustomObject]@{
                    'Computer' = $Nic.pscomputername
                    'NIC_ID' = $nic.index
                    'NIC_Descrption' = $nic.description
                }
            }
            # continue with next nic...
        } # foreach nic
    }
    catch {
        write-host " - Something else went wrong... logging to a CSV for review later" -ForegroundColor Red
        # add entry for current computer
        # (we don't know about nics, because wmi failed)
        $FailedArray  = [PSCustomObject]@{
            'Computer' = $Computer
        }
    }
    # continue with next computer...
} # foreach computer
  

Комментарии:

1. Аааа, это имеет смысл! Теперь я понимаю, как и почему try / catch был в неправильном месте в скрипте. Большое спасибо, я попробую