首页 > 解决方案 > 基于嵌套循环中的 if 语句中断完整脚本

问题描述

我有一个很长的脚本,在这个脚本中,我正在对从 csv 文件收集的一些输入进行一些验证。因此脚本将首先导入 CSV 文件,然后读取它们,并根据某些条件激发脚本的一部分。这部分脚本将执行一些验证并正确执行它们,我必须在循环中执行循环。如果此验证不成功,则脚本将打印错误然后中断。

问题是脚本没有中断。

我知道如果您已经确定了外部循环的标签并在 break 命令中调用了此标签,则 Break 只会中断当前循环或外部循环。

我需要的是,如果此验证在嵌套循环中不成功,那么整个脚本应该中断并且也不会退出,因为我需要让控制台保持运行。

例如,在下面,您会发现针对名为 vSphereNSXEnvironmentInfo 的变量中的值运行的循环。此变量保存从 CSV 文件之一导入的信息。这些信息与 NSX、vCenter 服务器和托管 vCenter Server 的 FQDN、用户名和密码有关(PS 你可以在这里忽略 NSX 位,我只专注于 vCenter 信息),这个 CSV 文件将保存每个站点的这些信息.

此变量中包含的信息的示例是:

SiteName                              : CGSM-Site
NsxManagerFqdn                        : CGSM-NSX.nfv.gss
NsxManagerUser                        : admin
NsxManagerPassword                    : VMware1!
vCenterFqdn                           : CGSM-VCSA.nfv.gss
vCenterUser                           : administrator@vsphere.local
vCenterPassword                       : VMware1!
vCenterHostingNsxFqdn                 : CGSM-VCSA.nfv.gss
vCenterHostingNsxUser                 : administrator@vsphere.local
vCenterHostingNsxPassword             : VMware1!
vCenterHostingvCenterFqdn             : CGSM-VCSA.nfv.gss
vCenterHostingvCenterUser             : administrator@vsphere.local
vCenterHostingvCenterPassword         : VMware1!
PrimaryNsxManagerFQDN                 : NotUsed
PrimaryNsxManagerUser                 : NotUsed
PrimaryNsxManagerPassword             : NotUsed
vCenterRegisteredToPrimaryNsxFQDN     : NotUsed
vCenterRegisteredToPrimaryNsxUser     : NotUsed
vCenterRegisteredToPrimaryNsxPassword : NotUsed
NsxController1IP                      : 192.168.4.61
NsxController2IP                      : 192.168.4.62
NsxController3IP                      : 192.168.4.63
NsxControllersPassword                : VMware1!VMware1!

SiteName                              : CGSR-Site
NsxManagerFqdn                        : CGSR-NSX.nfv.gss
NsxManagerUser                        : admin
NsxManagerPassword                    : VMware1!
vCenterFqdn                           : CGSR-VCSA.nfv.gss
vCenterUser                           : administrator@vsphere.local
vCenterPassword                       : VMware1!
vCenterHostingNsxFqdn                 : CGSM-VCSA.nfv.gss
vCenterHostingNsxUser                 : administrator@vsphere.local
vCenterHostingNsxPassword             : VMware1!
vCenterHostingvCenterFqdn             : CGSM-VCSA.nfv.gss
vCenterHostingvCenterUser             : administrator@vsphere.local
vCenterHostingvCenterPassword         : VMware1!
PrimaryNsxManagerFQDN                 : CGSM-NSX.nfv.gss
PrimaryNsxManagerUser                 : admin
PrimaryNsxManagerPassword             : VMware1!
vCenterRegisteredToPrimaryNsxFQDN     : CGSM-VCSA.nfv.gss
vCenterRegisteredToPrimaryNsxUser     : administrator@vsphere.local
vCenterRegisteredToPrimaryNsxPassword : VMware1!
NsxController1IP                      : 192.168.4.61
NsxController2IP                      : 192.168.4.62
NsxController3IP                      : 192.168.4.63
NsxControllersPassword                : VMware1!VMware1!

在下面的脚本中,您将找到如下过程:

1- 为变量中的每组信息运行一个 For 循环。

2-第一次验证将检查连接性,为此我正在为创建的 PS 对象创建另一个 For 循环,添加所需的目标以检查连接性。如果连接测试失败,那么它将中断

3- 第二次验证将检查用户名和密码,为此我正在为创建的 PS 对象创建另一个 For 循环,添加所需的目标以检查连接。如果用户名和密码不正确,则会中断

4- 第三次验证将检查注册。

脚本一直在继续。因此,当我故意在 CSV 文件中输入错误的用户名和密码时,代码会达到此级别并按预期出错,但它会从内部循环中断并进入外部循环,这也是预期的。

我需要的是打破整个脚本。

代码:

#region ######### - 2nd Sub-Sub-Section - SubSubSectionName: CheckIfNoNsxIsInUse.

###########################################
#######    Start of SubSubSection    ######
###########################################

#SubSection Description:    This SubSubsection will check and validate the info gathered from the vSphere-NSX-Required-Info.csv file with respect to the IP/FQDN connectivity as well as the credentials if the NSX is Not in use.
#--------------------------------------------------------------------------------------------------------

    Write-Host -BackgroundColor:Black -ForegroundColor:Gray "           NSX-v is not used, Checking credentials and connection to vCenter Server only."     

    Foreach ($Line in $vSphereNSXEnvironmentInfo) {                     

        Write-Host -BackgroundColor:Black -ForegroundColor:Gray "           Working on Site " $Line.SiteName " For " $Line.vCenterFqdn "."

        #region ££££££££££££ - 1st Sub-Sub-Sub-Section - SubSubSubSectionName: CheckConnectivity.

            ###########################################
            #######    Start of SubSubSection    ######
            ###########################################

            #SubSubSubSection Description:  This SubSubSubsection will check Connectivity.
            #-------------------------------------------------------------------------

            #Check Connectivity for vCenter Servers in each provided site in the vSphere-NSX-Required-Info.csv


            #Test Connection for the endpoint and the hosting endpoint over port 22 and 443.
            Write-Host -BackgroundColor:Black -ForegroundColor:Gray "           Checking connection over port 22 and 443."      

            #Create an array and add 22 and 443 in it to loop over it to make it easier for the code instead of writing the code twice once for 22 and another for 443
            $RequiredPorts = @("22","443")
            Foreach ($Port in $RequiredPorts) {
                #Create an array with the FQDN of the End point and check of the hosting vCenter is the same and if not then add it to the array.
                #Reason of creating this array is to minimize the code by running a loop for this array rather than writing the code 4 times once for each endpoint.
                $EndPoints = @()
                $EndPoints += $Line.vCenterFqdn
                If ($Line.vCenterFqdn -NE $Line.vCenterHostingvCenterFqdn) {$EndPoints += $Line.vCenterHostingvCenterFqdn}                      
                Foreach ($Target in $EndPoints) {
                    $TestConnection = Test-NetConnection -Port $Port -ComputerName $Target
                    If ($TestConnection.PingSucceeded -Eq "True") {
                    Write-Host -BackgroundColor:Black -ForegroundColor:DarkYellow "             Connection to "$Target " over port " $Port " is successful."
                    }
                        Else {
                            Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Connection to "$Target " over port " $Port " is not successful."
                            Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Please check connectivity to endpoints and try again."
                            start-sleep 5
                            Break
                        }               
                    }
            }


        ###########################################
        #######   End of SubSubSubSection     #####
        ########################################### 

        #---------------------------------------------- 

    #endregion

    #-----------------------------------------

    #region ££££££££££££ - 2nd Sub-Sub-Sub-Section - SubSubSubSectionName: CheckValidityOfUsername&Password.

        ###########################################
        #######    Start of SubSubSection    ######
        ###########################################

        #SubSubSubSection Description:  This SubSubSubsection will check Validity of Username and Passwords.
        #-------------------------------------------------------------------------

        #Check validity of usernames and passwords for each NSX/vCneter EndPoint in each provided site in the vSphere-NSX-Required-Info.csv

        Write-Host -BackgroundColor:Black -ForegroundColor:Gray "           Checking gathered Username and Passwords for all vCenter Servers."  


        #Create an HashTable with the FQDN, Username and Password for each Endpoint and then add the HashTable to an Array Variable to have all Endpoints info.
        #Reason of creating this array is to minimize the code by running a loop for this array rather than writing the code once for each endpoint.

        #Create the Variable, Note that the Hashtable will be created each time the tool go to another endpoint to delete the priviouse info of the priviouse endpoint.
        $EndPointsArray = @()

        #1- Add Working vCenter Server to the HashTable
        $EndPointsHashTable = @{}
        $URL = "https://" + $Line.vCenterFqdn + "/rest/com/vmware/cis/session"
        $EndPointsHashTable.add("Description", "vCenter")
        $EndPointsHashTable.add("EndPoint", $Line.vCenterFqdn)
        $EndPointsHashTable.add("URI", $URL)
        $Header = vCenterAuthurization -Username $Line.vCenterUser -Password $Line.vCenterPassword
        $EndPointsHashTable.add("Header", $Header)
        $EndPointsArray += $EndPointsHashTable

        #2- Add vCneter Server VM Hosting vCenter Server to the HashTable if exists.
        If ($Line.vCenterFqdn -NE $Line.vCenterHostingvCenterFqdn) {
            $URL = "https://" + $Line.vCenterHostingvCenterFqdn + "/rest/com/vmware/cis/session"
            $EndPointsHashTable.add("Description", "vCenter")
            $EndPointsHashTable.add("EndPoint", $Line.vCenterHostingvCenterFqdn)
            $EndPointsHashTable.add("URI", $URL)
            $Header = vCenterAuthurization -Username $Line.vCenterHostingvCenterUser -Password $Line.vCenterHostingvCenterPassword
            $EndPointsHashTable.add("Header", $Header)
            $EndPointsArray += $EndPointsHashTable
        }


        #Run the llop for the gathered info in the EndPointsArray Array Variable and validate the Username and Password.
        Foreach ($EndPoint in $EndPointsArray) {

            #Check if it is a Controller and if yes then use the Push-SSH.
            If ($EndPoint.Description -Eq "Controller") {
            $TestCredentials = New-SSHSession -ComputerName $EndPoint.URI -Credential $EndPoint.Header -AcceptKey
                If ($TestCredentials) {Write-Host -BackgroundColor:Black -ForegroundColor:DarkYellow "              Username and Password for " $EndPoint.URI " are successful."}
                Else {
                    Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Provided Username and Password for " $EndPoint.URI " are incorrect."
                    Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Please check Username and Password and try again."
                    start-sleep 5
                    Break
                }
            }

            #Run the validation for the rest normally as there will be nothing else that will need to use Push-SSH rathere than Invoke-WebRequest.
            $TestCredentials = Invoke-WebRequest -Uri $EndPoint.URI -Method Post -Headers $head
            If ($TestCredentials.StatusCode -Eq 200) {Write-Host -BackgroundColor:Black -ForegroundColor:DarkYellow "               Username and Password for " $EndPoint.URI " are successful."}
                Else {
                    Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Provided Username and Password for " $EndPoint.URI " are incorrect."
                    Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Please check Username and Password and try again."
                    start-sleep 5
                    Break
                }
            }


        ###########################################
        #######   End of SubSubSubSection     #####
        ########################################### 

    #---------------------------------------------- 

#endregion

#-----------------------------------------                      

#region ££££££££££££ - 3rd Sub-Sub-Sub-Section - SubSubSubSectionName: CheckHostingvCenterServers.

    ###########################################
    #######    Start of SubSubSection    ######
    ###########################################

    #SubSubSubSection Description:  This SubSubSubsection will Check and validate the hosting vCenterServer.
    #-------------------------------------------------------------------------              

    #Check if the Hosting vCenter Server are correct.

    Write-Host -BackgroundColor:Black -ForegroundColor:Gray "           Validating Hosting vCenter for vCenter VM"  

    #Second will check if vCenterHostingvCenterFqdn field is not set to NotUsed which would indicate that there are are a Hosting vCenter.
    #If vCenterHostingvCenterFqdn is set to a value other than NotUsed, Connect and try to locate the NSX Manager VM.
    #If vCenterHostingvCenterFqdn is set to NotUsed then Connect to the Working vCenter and Locate the NSX Manaver VM.
    If ($Line.vCenterHostingvCenterFqdn -NE "NotUsed") {

        Write-Host -BackgroundColor:Black -ForegroundColor:Gray "           Another hosting vCenter for vCenter is detected in csv file, confirmting info." 

        #At this point there is a hosting vCenter to the NSX, Connect and try to locate.
        $HostingvCenterforWorkingvCenterConnection = Connect-VIServer -Server $Line.vCenterHostingvCenterFqdn -User $Line.vCenterHostingvCenterUser -Password $Line.vCenterHostingvCenterPassword -Force -WarningAction SilentlyContinue -InformationAction Ignore -ErrorAction SilentlyContinue
        If ($HostingvCenterforWorkingvCenterConnection) {
            #Convert Working NSX Manager FQDN to IP to be used in locating the VM.
            $vCenterIpConverted = [System.Net.Dns]::GetHostAddresses($Line.vCenterFqdn)
            $LocatevCenterVM = Get-VM -Server $HostingvCenterforWorkingvCenterConnection | Where-Object -FilterScript { $_.Guest.Nics.IPAddress -contains "$vCenterIpConverted" } 
            Disconnect-VIServer -Server $HostingvCenterforWorkingvCenterConnection -Force -WarningAction SilentlyContinue -InformationAction SilentlyContinue -ErrorAction SilentlyContinue -Confirm:$false
            If ($LocatevCenterVM) {
                Write-Host -BackgroundColor:Black -ForegroundColor:DarkYellow "             " $Line.vCenterFqdn " is confirmed to be Hosted on " $Line.vCenterHostingvCenterFqdn "."
            }
                Else {
                    Write-Host -BackgroundColor:Black -ForegroundColor:Red "                " $Line.vCenterFqdn " VM could not be found on " $Line.vCenterHostingvCenterFqdn "."
                    Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Data Provided are incorrect, please check and try again."
                    start-sleep 5
                    Break
                }
            }
                Else {
                    Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Unable to connect to " $Line.vCenterHostingvCenterFqdn "."
                    Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Please check and try again."
                    start-sleep 5
                    Break
                }
            }
                Else {

                    Write-Host -BackgroundColor:Black -ForegroundColor:Gray "           No additional hosting vCenter is detected in csv file, confirmting info."   

                    #At this point there are no additional hosting vCenter are detected, which means that the NSX is hosted on vCenterFqdn, Connect and try to locate..
                    $HostingvCenterforWorkingvCenterConnection = Connect-VIServer -Server $Line.vCenterFqdn -User $Line.vCenterUser -Password $Line.vCenterPassword -Force -WarningAction SilentlyContinue -InformationAction Ignore -ErrorAction SilentlyContinue
                    If ($HostingvCenterforWorkingvCenterConnection) {
                        #Convert Working NSX Manager FQDN to IP to be used in locating the VM.
                        $vCenterIpConverted = [System.Net.Dns]::GetHostAddresses($Line.vCenterFqdn)
                        $LocateNsxVM = Get-VM -Server $HostingvCenterforWorkingvCenterConnection | Where-Object -FilterScript { $_.Guest.Nics.IPAddress -contains "$vCenterIpConverted" } 
                        Disconnect-VIServer -Server $HostingvCenterforWorkingvCenterConnection -Force -WarningAction SilentlyContinue -InformationAction SilentlyContinue -ErrorAction SilentlyContinue -Confirm:$false
                        If ($LocateNsxVM) {
                            Write-Host -BackgroundColor:Black -ForegroundColor:DarkYellow "             " $Line.vCenterFqdn " is confirmed to be Hosted on " $Line.vCenterFqdn "."
                        }
                            Else {
                                Write-Host -BackgroundColor:Black -ForegroundColor:Red "                " $Line.vCenterFqdn " VM could not be found on " $Line.vCenterFqdn "."
                                Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Data Provided are incorrect, please check and try again."
                                start-sleep 5
                                Break
                            }
                    }
                        Else {
                            Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Unable to connect to " $Line.vCenterFqdn "."
                            Write-Host -BackgroundColor:Black -ForegroundColor:Red "                Please check and try again."
                            start-sleep 5
                            Break
                        }

                }
                #----------------------------------------------------------------               


    ###########################################
    #######   End of SubSubSubSection     #####
    ########################################### 

    #---------------------------------------------- 

#endregion

#-----------------------------------------


} #End of rht Foreach Loop started at the begining.

    Write-Host -BackgroundColor:Black -ForegroundColor:DarkGreen "                  All dtat in vSphere-NSX-Required-Info.csv file was validated."  

    ###########################################
    #######    End of SubSubSection      ######
    ########################################### 

    #---------------------------------------------- 

#endregion

标签: powershell

解决方案


PowerShell 中的流控制语句(如foreach循环)支持标签,格式为:labelname,如下所示:

:outer
foreach($Array in @(@(1,2),@(3,4),@(5,6))){
    :inner
    foreach($Value in $Array){
        Write-Host $Value
        if($Value -eq 1){
            break inner
        }
        if($Value -eq 4){
            break outer
        }
    }    
}

在上面的示例if中,内部循环中的第一个条件将仅跳过 value 2,而第二个if条件将跳过其他所有内容,因为该break指令适用于outer循环。

请注意,这不是:标签名称的一部分,因此会中断前面的循环(感谢mklement0 指出它break inner:inner


推荐阅读