Functions/Public/EPCTestInstance.ps1

Function Get-EPCTestInstance {
    <#
        .SYNOPSIS
        Returns information about test point tests
         
        .DESCRIPTION
        Returns information about test point tests. Can be used to show any running tests
         
        .PARAMETER UUID
        The UUID of the test point to retrieve test information about
         
        .PARAMETER ExecMode
        Filter results by either normal or ad hoc tests
 
        .PARAMETER Status
        Filter results by the given status of a test.
         
        .EXAMPLE
        Get-EPCTestInstance -UUID d4a1437f-1f18-11ec-cf33-0daedf04882a -Status Running
        Shows running tests associated with the given test point UUID
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    [Alias("Get-EPCTestPointTestInstance")]
    Param (
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$UUID,
        [Parameter(Mandatory=$False)]
        [ValidateSet('Normal','AdHoc', IgnoreCase=$True)]
        [string]$ExecMode,
        [Parameter(Mandatory=$False)]
        [ValidateSet('Aborted','Cancelling','Cancelled','Completed','Pending','Running','Unknown', IgnoreCase=$True)]
        [string]$Status,
        [switch]$UseXML
    )
    
    Begin {
        Connect-EPCController
        
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCCred = New-Object -TypeName EPC.ActiveCtrl.CredentialsType
            $EPCCred.username = $Global:EPControllerCred.UserName
            $EPCCred.password = $Global:EPControllerCred.GetNetworkCredential().Password
        }
        Else {
            $ProgressPreference = 'SilentlyContinue'
        }
    }
    Process {
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCListTestInstancesParams = New-Object -TypeName EPC.ActiveCtrl.ListTestInstancesParametersType
            $EPCListTestInstancesParams.credentials = $EPCCred
        
            If ($UUID) { $EPCListTestInstancesParams.TestPTID = $UUID }
            
            If ($ExecMode) {
                $EPCListTestInstancesParams.ExecModeFilter = $ExecMode
                $EPCListTestInstancesParams.ExecModeFilterSpecified = $True
            }
            
            If ($Status) {
                $EPCListTestInstancesParams.StatusFilter = $Status
                $EPCListTestInstancesParams.StatusFilterSpecified = $True            
            }

            $TestPointInstancesResults = $Global:EPCWSDL_ActiveCtrl.ListTestInstances($EPCListTestInstancesParams)
            
            Write-Verbose $TestPointInstancesResults.result
            
            If ($TestPointInstancesResults.result -eq 'success') {
                Return $TestPointInstancesResults.TestInstanceList
            }
            Else {
                Throw $TestPointInstancesResults.result
            }        
        }
        Else {
            Write-Verbose 'Using XML to pull test instance list'
            $PwdEscaped = [System.Security.SecurityElement]::Escape($Global:EPControllerCred.GetNetworkCredential().Password)
            [xml]$SOAPReq = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'
                xmlns:urn='urn:telchemyActiveCtrl'>
                 <soapenv:Header/>
                 <soapenv:Body>
                 <urn:ListTestInstancesParameters>
                <credentials>
                <username>$($Global:EPControllerCred.UserName)</username>
                <password>$PwdEscaped</password>
                </credentials>
                 </urn:ListTestInstancesParameters>
                 </soapenv:Body>
                </soapenv:Envelope>"

            
            # Add the testpoint ID to the search if entered
            If ($UUID) {
                $NewXMLElement = $SOAPReq.Envelope.Body.ListTestInstancesParameters.AppendChild($SOAPReq.CreateElement('testptID'))
                $NULL = $NewXMLElement.AppendChild($SOAPReq.CreateTextNode($UUID))    
            }
            
            If ($ExecMode) { # WSDL uses adhoc, XML uses ad-hoc
                If ($ExecMode -eq 'AdHoc') { 
                    $ExecModeLower = 'ad-hoc' 
                }
                Else {
                    $ExecModeLower = 'normal' 
                }
                $NewXMLElement = $SOAPReq.Envelope.Body.ListTestInstancesParameters.AppendChild($SOAPReq.CreateElement('execModeFilter'))
                $NULL = $NewXMLElement.AppendChild($SOAPReq.CreateTextNode($ExecModeLower))    
            }
            
            If ($Status) {
                $NewXMLElement = $SOAPReq.Envelope.Body.ListTestInstancesParameters.AppendChild($SOAPReq.CreateElement('statusFilter'))
                $NULL = $NewXMLElement.AppendChild($SOAPReq.CreateTextNode($Status.ToLower()))    
            }

            $SOAPFQDN = "https://$Global:EPControllerFQDN/telchemywebservices/services/telchemyActiveCtrlService"
            Write-Verbose $SOAPFQDN
            Write-Verbose $SOAPReq.OuterXML

            If ($Global:EPC_UseSOAPHeader) {
                $Headers = @{'SOAPAction' = 'urn:telchemyActiveCtrl/ListTestInstancesParameters'}
            } Else {
                $Headers = @{}
            }
            
            [xml]$XMLResponse = (Invoke-WebRequest -UseBasicParsing -Method POST -URI $SOAPFQDN -Headers $Headers -Body $SOAPReq -ContentType 'text/xml').Content
            $TPTestResults = $XMLResponse.Envelope.Body.ListTestInstancesResults
            
            If ($TPTestResults.result -eq 'success') {
                Return $TPTestResults.TestInstanceList.testInstance
            }
            Else {
                Throw $TPTestResults.result
            }
        }
    }
}



Function Start-EPCTestInstance {
    <#
        .SYNOPSIS
        Starts an EPC test
         
        .DESCRIPTION
        Starts an EPC test
         
        .PARAMETER SrcTestPointID
        The UUID of the originating test point
         
        .PARAMETER SrcInterface
        The name of the originating network interface
         
        .PARAMETER SrcIPAddress
        The orginating test point's IP address
         
        .PARAMETER SrcResourceGroup
        The originating test point's resource group
 
        .PARAMETER DstTestPointID
        The UUID of the target test point
 
        .PARAMETER DstInterface
        The name of the target network interface
         
        .PARAMETER DstIPAddress
        The orginating test point's IP address
         
        .PARAMETER DstResourceGroup
        The target test point's resource group
 
        .PARAMETER Service
        The service name that contains the test to run
         
        .PARAMETER TestPlan
        The test plan name of the test to run
         
        .EXAMPLE
        Start-EPCTestInstance -SrcTestPointID d4a1437f-1f18-11ec-cf33-0daedf04882a -SrcInterface Ethernet -SrcIPAddress 192.168.1.100 -DstTestPointID b4a4437f-4f48-440c-cf33-0ba0bf04882a -DstInterface Wifi -DstIPAddress 192.168.0.43 -Service Contoso -TestPlan P2P_short
        Stops the given EPC test
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$SrcTestPointID,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$SrcTestPointName,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$DstTestPointID,
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$False)]
        [string]$DstTestPointName,
        [switch]$UseXML
    )
    DynamicParam {
        # Create the dictionary
        $RuntimeParamDict = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
        
        $ParamList = @()
        $Params = [pscustomobject][ordered]@{'ParamName' = 'SrcInterface'; 'Prefix' = 'SIF'; 'ParamRequired' = $FALSE; 'Position' = 2}
        $ParamList += $Params
        $Params = [pscustomobject][ordered]@{'ParamName' = 'SrcIPAddress'; 'Prefix' = 'SIP'; 'ParamRequired' = $FALSE; 'Position' = 3}
        $ParamList += $Params
        $Params = [pscustomobject][ordered]@{'ParamName' = 'SrcResourceGroup'; 'Prefix' = 'SRG'; 'ParamRequired' = $FALSE; 'Position' = 4}
        $ParamList += $Params
        $Params = [pscustomobject][ordered]@{'ParamName' = 'DstInterface'; 'Prefix' = 'DIF'; 'ParamRequired' = $FALSE; 'Position' = 5}
        $ParamList += $Params
        $Params = [pscustomobject][ordered]@{'ParamName' = 'DstIPAddress'; 'Prefix' = 'DIP'; 'ParamRequired' = $FALSE; 'Position' = 6}
        $ParamList += $Params
        $Params = [pscustomobject][ordered]@{'ParamName' = 'DstResourceGroup'; 'Prefix' = 'DRG'; 'ParamRequired' = $FALSE; 'Position' = 7}
        $ParamList += $Params
        $Params = [pscustomobject][ordered]@{'ParamName' = 'TestPlan'; 'Prefix' = 'TP'; 'ParamRequired' = $FALSE; 'Position' = 8}
        $ParamList += $Params
        $Params = [pscustomobject][ordered]@{'ParamName' = 'Service'; 'Prefix' = 'SRV'; 'ParamRequired' = $FALSE; 'Position' = 9}
        $ParamList += $Params
        
        # Initialize parameter list
        ForEach ($Param In $ParamList) { 
            New-DynamicParam -ParamName $Param.ParamName -Prefix $Param.Prefix -ParamRequired $Param.ParamRequired -Position $Param.Position 
        }
        
        If ($SrcTestPointID) {
            # Generate and set the ValidateSet
            $SrcTestPointIFList = Get-EPCTestPointInterface -UUID $SrcTestPointID | Where-Object {$_.Status -Contains 'ready' -And ($_.Status -Contains 'hasroute' -Or $_.Status -Contains 'has route')}
            $ValidateSetAttrib_SIF = New-Object System.Management.Automation.ValidateSetAttribute($SrcTestPointIFList.name)
            
            If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
                $SrcTestPointIPList = Get-EPCTestPointInterface -UUID $SrcTestPointID | Where-Object {$_.Status -Contains 'ready' -And ($_.Status -Contains 'hasroute' -Or $_.Status -Contains 'has route')} | ForEach-Object { $_.IFDetail | Select-Object -ExpandProperty Item }
            }
            Else {
                $SrcTestPointIPList = Get-EPCTestPointInterface -UUID $SrcTestPointID | Where-Object {$_.Status -Contains 'ready' -And ($_.Status -Contains 'hasroute' -Or $_.Status -Contains 'has route')} | ForEach-Object { ($_.IFDetail | Select-Object IPAddress).IPAddress } 
            }    
            
            $ValidateSetAttrib_SIP = New-Object System.Management.Automation.ValidateSetAttribute($SrcTestPointIPList)

            $SrcTestPointRGList = (Get-EPCTestPoint | Where-Object {$_.testptID -eq $SrcTestPointID} | Select-Object RGList).RGList
            If ($SrcTestPointRGList.GetType().FullName -eq 'System.Xml.XmlElement') { $SrcTestPointRGList = $SrcTestPointRGList.rg } # Account for differences in XML vs WSDL
            $ValidateSetAttrib_SRG = New-Object System.Management.Automation.ValidateSetAttribute($SrcTestPointRGList)
        }
        
        If ($DstTestPointID) {
            # Generate and set the ValidateSet
            $DstTestPointIFList = Get-EPCTestPointInterface -UUID $DstTestPointID | Where-Object {$_.Status -Contains 'ready' -And ($_.Status -Contains 'hasroute' -Or $_.Status -Contains 'has route')}
            $ValidateSetAttrib_DIF = New-Object System.Management.Automation.ValidateSetAttribute($DstTestPointIFList.name)
                        
            If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
                $DstTestPointIPList = Get-EPCTestPointInterface -UUID $DstTestPointID | Where-Object {$_.Status -Contains 'ready' -And ($_.Status -Contains 'hasroute' -Or $_.Status -Contains 'has route')} | ForEach-Object { $_.IFDetail | Select-Object -ExpandProperty Item }
            }
            Else {
                $DstTestPointIPList = Get-EPCTestPointInterface -UUID $DstTestPointID | Where-Object {$_.Status -Contains 'ready' -And ($_.Status -Contains 'hasroute' -Or $_.Status -Contains 'has route')} | ForEach-Object { ($_.IFDetail | Select-Object IPAddress).IPAddress } 
            }    
            
            $ValidateSetAttrib_DIP = New-Object System.Management.Automation.ValidateSetAttribute($DstTestPointIPList)

            $DstTestPointRGList = (Get-EPCTestPoint | Where-Object {$_.testptID -eq $DstTestPointID} | Select-Object RGList).RGList
            If ($DstTestPointRGList.GetType().FullName -eq 'System.Xml.XmlElement') { $DstTestPointRGList = $DstTestPointRGList.rg } # Account for differences in XML vs WSDL
            $ValidateSetAttrib_DRG = New-Object System.Management.Automation.ValidateSetAttribute($DstTestPointRGList)

            $TestPlanList = Get-EPCTestPlan
            $ValidateSetAttrib_PT = New-Object System.Management.Automation.ValidateSetAttribute($TestPlanList.name)

            $ServiceList = Get-EPCService
            $ValidateSetAttrib_SRV = New-Object System.Management.Automation.ValidateSetAttribute($ServiceList.name)
        }
        
        # Add the ValidateSet to the attributes collection
        $AttribColl_SIF.Add($ValidateSetAttrib_SIF)
        $AttribColl_SIP.Add($ValidateSetAttrib_SIP)
        $AttribColl_SRG.Add($ValidateSetAttrib_SRG)
        $AttribColl_DIF.Add($ValidateSetAttrib_DIF)
        $AttribColl_DIP.Add($ValidateSetAttrib_DIP)
        $AttribColl_DRG.Add($ValidateSetAttrib_DRG)
        $AttribColl_TP.Add($ValidateSetAttrib_PT)
        $AttribColl_SRV.Add($ValidateSetAttrib_SRV)
                
        # Create and return the dynamic parameter
        $RunTimeParam_SIF = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_SIF, [string], $AttribColl_SIF)
        $RunTimeParam_SIP = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_SIP, [string], $AttribColl_SIP)
        $RunTimeParam_SRG = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_SRG, [string], $AttribColl_SRG)
        $RunTimeParam_DIF = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_DIF, [string], $AttribColl_DIF)
        $RunTimeParam_DIP = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_DIP, [string], $AttribColl_DIP)
        $RunTimeParam_DRG = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_DRG, [string], $AttribColl_DRG)
        $RunTimeParam_TP = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_TP, [string], $AttribColl_TP)
        $RunTimeParam_SRV = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_SRV, [string], $AttribColl_SRV)
        $RuntimeParamDict.Add($ParamName_SIF, $RunTimeParam_SIF)
        $RuntimeParamDict.Add($ParamName_SIP, $RunTimeParam_SIP)
        $RuntimeParamDict.Add($ParamName_SRG, $RunTimeParam_SRG)
        $RuntimeParamDict.Add($ParamName_DIF, $RunTimeParam_DIF)
        $RuntimeParamDict.Add($ParamName_DIP, $RunTimeParam_DIP)
        $RuntimeParamDict.Add($ParamName_DRG, $RunTimeParam_DRG)
        $RuntimeParamDict.Add($ParamName_TP, $RunTimeParam_TP)
        $RuntimeParamDict.Add($ParamName_SRV, $RunTimeParam_SRV)
        
        Return $RuntimeParamDict
    }

    Begin {
        Connect-EPCController
        
        # If no parameters were entered, then bring up the UI
        If ($PSBoundParameters.Count -eq 0 -Or $SrcTestPointName -Or $DstTestPointName) {
            [bool]$Script:SubmitClicked = $False
            $Script:SrcIPAddress = $NULL
            $Script:DstIPAddress = $NULL
            
            # Check to see if the module was installed to determine the location of the gui.xaml file
            $N10Path = (Get-Module -Name Nectar10 -ErrorAction:SilentlyContinue).Path
            If ($N10Path) {
                $N10Path = (Get-Item $N10Path).DirectoryName
            }
            Else {
                $N10Path = '.'
            }
            
            $inputXML = Get-Content "$N10Path\epc_starttest_gui.xaml"

            $inputXML = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
            [void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework')
            [xml]$XAML = $inputXML

            #Read XAML
            $Reader=(New-Object System.Xml.XmlNodeReader $xaml)
            Try {
                $Form=[Windows.Markup.XamlReader]::Load( $Reader )
            }
            Catch {
                Throw "Unable to parse XML, with error: $($Error[0])`n Ensure that there are NO SelectionChanged or TextChanged properties in your textboxes (PowerShell cannot process them)"
            }
             
            #===========================================================================
            # Load XAML Objects In PowerShell
            #===========================================================================
              
            $xaml.SelectNodes("//*[@Name]") | ForEach-Object {
                Try { Set-Variable -Name "$($_.Name)" -Value $Form.FindName($_.Name) -ErrorAction Stop }
                Catch { Throw }
                }

            # Populate the Test Plan List
            $TestPlanList = Get-EPCTestPlan | Select-Object Name, testPlanID | Sort-Object Name
            ForEach ($TestPlan in $TestPlanList) {
                [void] $TP_DropBox.Items.Add($TestPlan.name)
            }

            # Grab the default value
            $Script:TestPlanID = $TestPlanList[0].testPlanID

            # Populate the Resource Group List
            Try {
                $RGList = Get-EPCResourceGroup | Select-Object RGName, RGID | Sort-Object RGName
                ForEach ($RG in $RGList) {
                    [void] $RG_DropBox.Items.Add($RG.RGName)
                }
            }
            Catch { # Hide the RG list dropdown if user doesn't have permission to view
                $RG_Label.Visibility = 'Hidden'
                $RG_DropBox.Visibility = 'Hidden'            
            }

            # Grab the default value
            $Script:TestPlanID = $TestPlanList[0].testPlanID

            $IPRegEx = "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"

            # Populate the Testpoint list
            $Script:TPList = Get-EPCTestPoint | Where-Object {$_.status -eq 'Connected'} | Select-Object Name, testptID, RGList | Sort-Object -Property Name

            ForEach ($TestPoint in $Script:TPList) {
                [void] $SrcEndpoint_ListBox.Items.Add($TestPoint.name)
                [void] $DstEndpoint_ListBox.Items.Add($TestPoint.name)
            }

            ########################
            #Add Event Handlers
            ########################
            $TP_DropBox.add_SelectionChanged({
                # Get the selected Test Plan
                $SelectedTPIndex = $TP_DropBox.SelectedIndex
                $Script:TestPlanID = $TestPlanList[$SelectedTPIndex].testPlanID
            })

            $RG_DropBox.add_SelectionChanged({
                # Get the selected Resource Group and set the test point list
                $SelectedRGIndex = $RG_DropBox.SelectedIndex
                $Script:ResourceGroupID = $RGList[$SelectedRGIndex].RGID
                $Script:TPList = Get-EPCTestPoint -RGID $Script:ResourceGroupID | Where-Object {$_.status -eq 'Connected'} | Select-Object Name, testptID, RGList | Sort-Object -Property Name
                $SrcEndpoint_ListBox.Items.Clear()
                $DstEndpoint_ListBox.Items.Clear()
                $SrcInterface_ListBox.Items.Clear()
                $DstInterface_ListBox.Items.Clear()
                $SrcIPAddress_ListBox.Items.Clear()
                $DstIPAddress_ListBox.Items.Clear()
                
                ForEach ($TestPoint in $Script:TPList) {
                    [void] $SrcEndpoint_ListBox.Items.Add($TestPoint.name)
                    [void] $DstEndpoint_ListBox.Items.Add($TestPoint.name)
                }
            })

            $SrcEndpoint_TextBox.add_LostFocus({
                $Script:TPList = Get-EPCTestPoint -RGID $Script:ResourceGroupID -Name $($SrcEndpoint_TextBox.text) | Where-Object {$_.status -eq 'Connected'} | Select-Object Name, testptID, RGList | Sort-Object -Property Name
                $SrcEndpoint_ListBox.Items.Clear()
                $SrcInterface_ListBox.Items.Clear()
                $SrcIPAddress_ListBox.Items.Clear()
                
                ForEach ($TestPoint in $Script:TPList) {
                    [void] $SrcEndpoint_ListBox.Items.Add($TestPoint.name)
                }
            })


            $SrcEndpoint_ListBox.add_SelectionChanged({
                # Get the selected endpoint
                $SelectedEPIndex = $SrcEndpoint_ListBox.SelectedIndex
                $Script:SrcTestPointID = $Script:TPList[$SelectedEPIndex].testPtID
                $Script:SrcResourceGroupList = $Script:TPList[$SelectedEPIndex].RGList
                
                # Ensure RGList object is a PSObject instead of XML
                If ($Global:EPC_UseWSDL -eq $False -Or $UseXML) { $Script:SrcResourceGroupList = ForEach($Item in $Script:SrcResourceGroupList.RG) { $Item } }
                
                Try {
                    # Populate interface list
                    $SrcInterface_ListBox.Items.Clear()
                    $SrcIPAddress_ListBox.Items.Clear()
                    $SrcInterface_ListBox.IsEnabled = $True

                    $Script:SrcTestPointIFList = Get-EPCTestPointInterface -UUID $Script:SrcTestPointID | Where-Object {$_.Status -Contains 'ready' -And ($_.Status -Contains 'hasroute' -Or $_.Status -Contains 'has route') -And $_.ifID -notlike 'Teredo*'} 

                    ForEach ($Interface in $Script:SrcTestPointIFList) {
                        $SrcInterface_ListBox.Items.Add($Interface.name)
                    }

                    # Auto-select the interface if there is only one
                    If (($Script:SrcTestPointIFList | Measure-Object).Count -eq 1) {
                        $SrcInterface_ListBox.SelectedIndex = 0
                    }
                    
                    # Auto-select the 'Any' interface if available
                    If ($Script:SrcTestPointIFList.Name.Contains('Any')) {
                        $SrcInterface_ListBox.SelectedIndex = $Script:SrcTestPointIFList.Name.IndexOf('Any')
                    }
                    
                }
                Catch {
                    $SrcInterface_ListBox.Items.Clear()
                    $SrcIPAddress_ListBox.Items.Clear()
                    $SrcInterface_ListBox.Items.Add("ERROR CONNECTING TO ENDPOINT")
                    $SrcInterface_ListBox.IsEnabled = $False
                }
            })


            $SrcInterface_ListBox.add_SelectionChanged({
                # Get the selected interface
                $SelectedIFIndex = $SrcInterface_ListBox.SelectedIndex
                
                If ($SelectedIFIndex -ge 0) {
                    $Script:SrcInterfaceID = $Script:SrcTestPointIFList[$SelectedIFIndex].IFID

                    # Populate the IP address list
                    If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
                        $SrcTestPointIPList = Get-EPCTestPointInterface -UUID $Script:SrcTestPointID | Where-Object {$_.IFID -eq $Script:SrcInterfaceID} | ForEach-Object { $_.IFDetail } | Select-Object Item | Where-Object {$_.Item -match $IPRegEx -Or $_.Item -like 'Any*'}
                    }
                    Else {
                        $SrcTestPointIPList = Get-EPCTestPointInterface -UUID $Script:SrcTestPointID | Where-Object {$_.IFID -eq $Script:SrcInterfaceID} | ForEach-Object { $_.IFDetail } | Select-Object @{Name='Item';Expression={$_.IPAddress}} | Where-Object {$_.Item -match $IPRegEx -Or $_.Item -like 'Any*'}
                    }
                    
                    $SrcIPAddress_ListBox.Items.Clear()

                    ForEach ($IPAddress in $SrcTestPointIPList) {
                        $SrcIPAddress_ListBox.Items.Add($IPAddress.Item)
                    }

                    # Auto-select the IP address if there is only one (usual case)
                    If (($SrcTestPointIPList | Measure-Object).Count -eq 1 -Or $Script:SrcInterfaceID -eq 'Any') {
                       $SrcIPAddress_ListBox.SelectedIndex = 0
                    }
                }
            })


            $SrcIPAddress_ListBox.add_SelectionChanged({
                # Get the selected IP address
                $Script:SrcIPAddress = $SrcIPAddress_ListBox.SelectedValue
                
                If ($Script:SrcIPAddress -and $Script:DstIPAddress) { 
                    $bSubmit.IsEnabled = $True 
                }
                Else {
                    $bSubmit.IsEnabled = $False
                }
            })
            
            $DstEndpoint_TextBox.add_LostFocus({
                $Script:TPList = Get-EPCTestPoint -RGID $Script:ResourceGroupID -Name $($DstEndpoint_TextBox.text) | Where-Object {$_.status -eq 'Connected'} | Select-Object Name, testptID, RGList | Sort-Object -Property Name
                $DstEndpoint_ListBox.Items.Clear()
                $DstInterface_ListBox.Items.Clear()
                $DstIPAddress_ListBox.Items.Clear()
                
                ForEach ($TestPoint in $Script:TPList) {
                    [void] $DstEndpoint_ListBox.Items.Add($TestPoint.name)
                }
            })

            $DstEndpoint_ListBox.add_SelectionChanged({
                # Get the selected endpoint
                $SelectedEPIndex = $DstEndpoint_ListBox.SelectedIndex
                $Script:DstTestPointID = $Script:TPList[$SelectedEPIndex].testPtID
                $Script:DstResourceGroupList = $Script:TPList[$SelectedEPIndex].RGList

                # Ensure RGList object is a PSObject instead of XML
                If ($Global:EPC_UseWSDL -eq $False -Or $UseXML) { $Script:DstResourceGroupList = ForEach($Item in $Script:DstResourceGroupList.RG) { $Item } }
                
                # Populate interface list
                Try {
                    $DstInterface_ListBox.Items.Clear()
                    $DstIPAddress_ListBox.Items.Clear()
                    $DstInterface_ListBox.IsEnabled = $True

                    $Script:DstTestPointIFList = Get-EPCTestPointInterface -UUID $Script:DstTestPointID | Where-Object {$_.Status -Contains 'ready' -And ($_.Status -Contains 'hasroute' -Or $_.Status -Contains 'has route') -And $_.ifID -notlike 'Teredo*'} 

                    ForEach ($Interface in $Script:DstTestPointIFList) {
                        $DstInterface_ListBox.Items.Add($Interface.name)
                    }

                    # Auto-select the interface if there is only one
                    If (($Script:DstTestPointIFList | Measure-Object).Count -eq 1) {
                       $DstInterface_ListBox.SelectedIndex = 0
                    }
                    
                    # Auto-select the 'Any' interface if available
                    If ($Script:DstTestPointIFList.Name.Contains('Any')) {
                        $DstInterface_ListBox.SelectedIndex = $Script:DstTestPointIFList.Name.IndexOf('Any')
                    }                    
                }
                Catch {
                    $DstInterface_ListBox.Items.Clear()
                    $DstIPAddress_ListBox.Items.Clear()
                    $DstInterface_ListBox.Items.Add("ERROR CONNECTING TO ENDPOINT")
                    $DstInterface_ListBox.IsEnabled = $False
                }
            })

            $DstInterface_ListBox.add_SelectionChanged({
                # Get the selected interface
                $SelectedIFIndex = $DstInterface_ListBox.SelectedIndex
                
                If ($SelectedIFIndex -ge 0) {    
                    $Script:DstInterfaceID = $Script:DstTestPointIFList[$SelectedIFIndex].IFID

                    #Populate the IP address list
                    If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
                        $DstTestPointIPList = Get-EPCTestPointInterface -UUID $Script:DstTestPointID | Where-Object {$_.IFID -eq $Script:DstInterfaceID} | ForEach-Object { $_.IFDetail } | Select-Object Item | Where-Object {$_.Item -match $IPRegEx -Or $_.Item -like 'Any*'}
                    }
                    Else {
                        $DstTestPointIPList = Get-EPCTestPointInterface -UUID $Script:DstTestPointID | Where-Object {$_.IFID -eq $Script:DstInterfaceID} | ForEach-Object { $_.IFDetail } | Select-Object @{Name='Item';Expression={$_.IPAddress}} | Where-Object {$_.Item -match $IPRegEx -Or $_.Item -like 'Any*'}
                    }
                    
                    $DstIPAddress_ListBox.Items.Clear()

                    ForEach ($IPAddress in $DstTestPointIPList) {
                        $DstIPAddress_ListBox.Items.Add($IPAddress.Item)
                    }

                    # Auto-select the IP address if there is only one (usual case)
                    If (($DstTestPointIPList | Measure-Object).Count -eq 1 -Or $Script:DstInterfaceID -eq 'Any') {
                       $DstIPAddress_ListBox.SelectedIndex = 0
                    }
                }
            })


            $DstIPAddress_ListBox.add_SelectionChanged({
                # Get the selected IP address
                $Script:DstIPAddress = $DstIPAddress_ListBox.SelectedValue

                If ($Script:DstIPAddress -and $Script:SrcIPAddress) { 
                    $bSubmit.IsEnabled = $True 
                    $bSubmit.Background = 'PaleGreen'
                }
                Else {
                    $bSubmit.IsEnabled = $False
                }
            })


            $bSubmit.Add_Click({
                [bool]$Script:SubmitClicked = $True
                $form.Close()
            })

            # Select endpoint if it was entered on the command line
            If ($SrcTestPointName) {
                $SrcEndpoint_TextBox.Text = $SrcTestPointName  # Populate the search box with the name
                # Limit the listbox to show only entries that match the above text
                $Script:TPList = Get-EPCTestPoint -RGID $Script:ResourceGroupID -Name $($SrcEndpoint_TextBox.text) | Where-Object {$_.status -eq 'Connected'} | Select-Object Name, testptID, RGList | Sort-Object -Property Name
                $SrcEndpoint_ListBox.Items.Clear()
                $SrcInterface_ListBox.Items.Clear()
                $SrcIPAddress_ListBox.Items.Clear()
                
                ForEach ($TestPoint in $Script:TPList) {
                    [void] $SrcEndpoint_ListBox.Items.Add($TestPoint.name)
                }

                Try {
                    $SrcEndpoint_ListBox.SelectedIndex = $SrcEndpoint_ListBox.Items.IndexOf($SrcTestPointName)
                    $SrcEndpoint_ListBox.SelectionChanged
                    $SrcEndpoint_ListBox.ScrollIntoView($SrcEndpoint_ListBox.Items.GetItemAt($SrcEndpoint_ListBox.SelectedIndex))
                }
                Catch {}
            }    

            If ($DstTestPointName) {
                $DstEndpoint_TextBox.Text = $DstTestPointName # Populate the search box with the name
                # Limit the listbox to show only entries that match the above text
                $Script:TPList = Get-EPCTestPoint -RGID $Script:ResourceGroupID -Name $($DstEndpoint_TextBox.text) | Where-Object {$_.status -eq 'Connected'} | Select-Object Name, testptID, RGList | Sort-Object -Property Name
                $DstEndpoint_ListBox.Items.Clear()
                $DstInterface_ListBox.Items.Clear()
                $DstIPAddress_ListBox.Items.Clear()
                
                ForEach ($TestPoint in $Script:TPList) {
                    [void] $DstEndpoint_ListBox.Items.Add($TestPoint.name)
                }

                Try {
                    $DstEndpoint_ListBox.SelectedIndex = $DstEndpoint_ListBox.Items.IndexOf($DstTestPointName)
                    $DstEndpoint_ListBox.SelectionChanged
                    $DstEndpoint_ListBox.ScrollIntoView($DstEndpoint_ListBox.Items.GetItemAt($DstEndpoint_ListBox.SelectedIndex))
                }
                Catch {}
            }    

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

            If ($Script:SubmitClicked) {
                $SrcTestPointID = $Script:SrcTestPointID
                $DstTestPointID = $Script:DstTestPointID
                
                # Set the Resource Group for source and target if it was specified
                If ($Script:ResourceGroupID) {
                    $SrcRG = $Script:ResourceGroupID
                    $DstRG = $Script:ResourceGroupID
                }
                Else { # Find a common resource group and use that for the test
                    $CommonRG = Compare-Object -IncludeEqual -ExcludeDifferent $Script:SrcResourceGroupList $Script:DstResourceGroupList
                    $SrcRG = $CommonRG[0].InputObject
                    $DstRG = $CommonRG[0].InputObject
                }
            }
            Else { Break }
        }
        
        # Write-Host "TestPlanID: $Script:TestPlanID"
        # Write-Host "SrcTPID: $Script:SrcTestPointID"
        # Write-Host "SrcIFID: $Script:SrcInterfaceID"
        # Write-Host "SrcIPID: $Script:SrcIPAddress"
        # Write-Host "DstTPID: $Script:DstTestPointID"
        # Write-Host "DstIFID: $Script:DstInterfaceID"
        # Write-Host "DstIPID: $Script:DstIPAddress"
        # Write-Host "SrcRG: $SrcRG"
        # Write-Host "DstRG: $DstRG"
        
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCCred = New-Object -TypeName EPC.ActiveCtrl.CredentialsType
            $EPCCred.username = $Global:EPControllerCred.UserName
            $EPCCred.password = $Global:EPControllerCred.GetNetworkCredential().Password
        }
        Else {
            $ProgressPreference = 'SilentlyContinue'
        }
    
        If ($PSBoundParameters.Count -gt 0 -And -Not ($SrcTestPointName -Or $DstTestPointName)) {
            # Get the array position of the selected environment
            $SrcIFPos = $SrcTestPointIFList.Name.IndexOf($PsBoundParameters[$ParamName_SIF])
            $DstIFPos = $DstTestPointIFList.Name.IndexOf($PsBoundParameters[$ParamName_DIF])
            $TPPos = $TestPlanList.Name.IndexOf($PsBoundParameters[$ParamName_TP])
            $SRVPos = $ServiceList.Name.IndexOf($PsBoundParameters[$ParamName_SRV])
            
            $SrcInterfaceID = $SrcTestPointIFList[$SrcIFPos].IFID
            Write-Verbose "Src InterfaceID: $SrcInterfaceID"
            $SrcIPAddress = $PsBoundParameters[$ParamName_SIP]
            Write-Verbose "Src IPAddress: $SrcIPAddress"
            $SrcRG = $PsBoundParameters[$ParamName_SRG]
            Write-Verbose "Src RG: $SrcRG"            
            $DstInterfaceID = $DstTestPointIFList[$DstIFPos].IFID
            Write-Verbose "Dst InterfaceID: $DstInterfaceID"
            $DstIPAddress = $PsBoundParameters[$ParamName_DIP]
            Write-Verbose "Dst IPAddress: $DstIPAddress"
            $DstRG = $PsBoundParameters[$ParamName_DRG]
            Write-Verbose "Dst RG: $DstRG"
            $TestPlanID = $TestPlanList[$TPPos].TestPlanID
            Write-Verbose "TestPlanID: $TestPlanID"
            $ServiceID = $ServiceList[$SRVPos].ServiceID
            Write-Verbose "ServiceID: $ServiceID"
        }
    }
    Process {
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {        
            $EPCSource = New-Object -TypeName EPC.ActiveCtrl.TestPointTargetType
            $EPCTarget = New-Object -TypeName EPC.ActiveCtrl.TestPointTargetType
            
            $EPCSource.TestPointID = $SrcTestPointID
            $EPCSource.ifID = $SrcInterfaceID
            $EPCSource.IPAddress = $SrcIPAddress
            $EPCSource.RG = $SrcRG

            $EPCTarget.TestPointID = $DstTestPointID
            $EPCTarget.ifID = $DstInterfaceID
            $EPCTarget.IPAddress = $DstIPAddress
            $EPCTarget.RG = $DstRG

            $EPCStartTestPlanTPtoTPParams = New-Object -TypeName EPC.ActiveCtrl.startTestPlanParamsTPtoTPType
            $EPCStartTestPlanTPtoTPParams.TestPlanID = $TestPlanID
            $EPCStartTestPlanTPtoTPParams.Originator = $EPCSource
            $EPCStartTestPlanTPtoTPParams.TPTarget = $EPCTarget
            
            If ($Service) { Write-Verbose "Selected Service: $ServiceID"; $EPCStartTestPlanTPtoTPParams.ServiceID = $ServiceID }    
            
            $EPCStartTestPlanParams = New-Object -TypeName EPC.ActiveCtrl.startTestPlanParametersType
            $EPCStartTestPlanParams.credentials = $EPCCred
            $EPCStartTestPlanParams.Items = $EPCStartTestPlanTPtoTPParams
            $EPCStartTestPlanParams.ItemsElementName = 'tp2tptest'
            
            $StartTestPlanResults = $Global:EPCWSDL_ActiveCtrl.startTestPlan($EPCStartTestPlanParams)
            Write-Verbose $StartTestPlanResults.result
        }
        Else {
            Write-Verbose "Using XML SOAP Request to start test plan"
            $PwdEscaped = [System.Security.SecurityElement]::Escape($Global:EPControllerCred.GetNetworkCredential().Password)
            [xml]$SOAPReq = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'
                xmlns:urn='urn:telchemyActiveCtrl'>
                 <soapenv:Header/>
                 <soapenv:Body>
                 <urn:startTestPlanParameters>
                 <credentials>
                 <username>$($Global:EPControllerCred.UserName)</username>
                 <password>$PwdEscaped</password>
                 </credentials>
                 <tp2tpTest>
                 <testplanID>$TestPlanID</testplanID>
                 <originator>
                 <testpointID>$SrcTestPointID</testpointID>
                 <ifID>$SrcInterfaceID</ifID>
                 <ipAddress>$SrcIPAddress</ipAddress>
                 <RG>$SrcRG</RG>
                 </originator>
                 <tpTarget>
                 <testpointID>$DstTestPointID</testpointID>
                 <ifID>$DstInterfaceID</ifID>
                 <ipAddress>$DstIPAddress</ipAddress>
                 <RG>$DstRG</RG>
                 </tpTarget>
                 </tp2tpTest>
                 </urn:startTestPlanParameters>
                 </soapenv:Body>
                </soapenv:Envelope>"

                
            $SOAPFQDN = "https://$Global:EPControllerFQDN/telchemywebservices/services/telchemyActiveCtrlService"
            Write-Verbose $SOAPFQDN
            Write-Verbose $SOAPReq.OuterXML

            If ($Global:EPC_UseSOAPHeader) {
                $Headers = @{'SOAPAction' = 'urn:telchemyActiveCtrl/startTestPlanParameters'}
            } Else {
                $Headers = @{}
            }
            
            [xml]$XMLResponse = (Invoke-WebRequest -UseBasicParsing -Method POST -URI $SOAPFQDN -Headers $Headers -Body $SOAPReq -ContentType 'text/xml').Content
            $StartTestPlanResults = $XMLResponse.Envelope.Body.StartTestPlanResults
        }
        
        If ($StartTestPlanResults.result -eq 'success') {
            Return "Successfully started test`n`rTestPointID: $SrcTestPointID`n`rInstance ID: $($StartTestPlanResults.instanceID)"
        }
        Else {
            Return $StartTestPlanResults.result
        }
    }
}



Function Stop-EPCTestInstance {
    <#
        .SYNOPSIS
        Stops a running EPC test
         
        .DESCRIPTION
        Stops a running EPC test
         
        .PARAMETER InstanceID
        The InstanceID of the test to stop
         
        .EXAMPLE
        Stop-EPCTestInstance -InstanceID MDNkMGQxZGQ4YzVjY2VlYmRkZTBlYjA2MWRlLTg3MjI=<
        Stops the given EPC test
 
        .NOTES
        Version 1.0
    #>

    
    [cmdletbinding()]
    Param (
        [Parameter(ValueFromPipelineByPropertyName, Mandatory=$True)]
        [string]$InstanceID,
        [switch]$UseXML
    )
    
    Begin {
        Connect-EPCController
        
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCCred = New-Object -TypeName EPC.ActiveCtrl.CredentialsType
            $EPCCred.username = $Global:EPControllerCred.UserName
            $EPCCred.password = $Global:EPControllerCred.GetNetworkCredential().Password
        }
        Else {
            $ProgressPreference = 'SilentlyContinue'
        }
    }
    Process {
        If ($Global:EPC_UseWSDL -And $UseXML -eq $False) {
            $EPCStopTestPlanParams = New-Object -TypeName EPC.ActiveCtrl.StopTestPlanParametersType
            $EPCStopTestPlanParams.credentials = $EPCCred
            $EPCStopTestPlanParams.instanceID = $InstanceID

            $StopTestPlanResult = $Global:EPCWSDL_ActiveCtrl.stopTestPlan($EPCStopTestPlanParams)
        }
        Else {
            Write-Verbose "Using XML SOAP Request to stop test plan"
            $PwdEscaped = [System.Security.SecurityElement]::Escape($Global:EPControllerCred.GetNetworkCredential().Password)
            [xml]$SOAPReq = "<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'
                xmlns:urn='urn:telchemyActiveCtrl'>
                 <soapenv:Header/>
                 <soapenv:Body>
                 <urn:stopTestPlanParameters>
                <credentials>
                 <username>$($Global:EPControllerCred.UserName)</username>
                 <password>$PwdEscaped</password>
                </credentials>
                 <instanceID>$InstanceID</instanceID>
                 </urn:stopTestPlanParameters>
                 </soapenv:Body>
                </soapenv:Envelope>"

                
            $SOAPFQDN = "https://$Global:EPControllerFQDN/telchemywebservices/services/telchemyActiveCtrlService"
            Write-Verbose $SOAPFQDN
            Write-Verbose $SOAPReq.OuterXML

            If ($Global:EPC_UseSOAPHeader) {
                $Headers = @{'SOAPAction' = 'urn:telchemyActiveCtrl/stopTestPlanParameters'}
            } Else {
                $Headers = @{}
            }
            
            [xml]$XMLResponse = (Invoke-WebRequest -UseBasicParsing -Method POST -URI $SOAPFQDN -Headers $Headers -Body $SOAPReq -ContentType 'text/xml').Content
            $StopTestPlanResult = $XMLResponse.Envelope.Body.stopTestPlanResults
        }
        
        If ($StopTestPlanResult.result -eq 'success') { 
            Return 'Test stopped successfully'
        }
        Else {
            Throw $StopTestPlanResult.result
        }
    }
}