SDNExplorer.psm1


#region some IPv4 address related helper functions

function Convert-IPv4StringToInt {
    param([string] $addr)

    $ip = $null
    $valid = [System.Net.IPAddress]::TryParse($addr, [ref]$ip)
    if (!$valid -or $ip.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork) {
        throw "$addr is not a valid IPv4 address."
    }

    $sp = $addr.Split(".", 4)
    $bits = [System.Convert]::ToInt64($sp[0])
    $bits = $bits -shl 8
    $bits += [System.Convert]::ToInt64($sp[1])
    $bits = $bits -shl 8
    $bits += [System.Convert]::ToInt64($sp[2])
    $bits = $bits -shl 8
    $bits += [System.Convert]::ToInt64($sp[3])

    $bits
}

function Convert-IPv4IntToString {
    param([Int64] $addr)

    "{0}.{1}.{2}.{3}" -f (($addr -shr 24) -band 0xff), (($addr -shr 16) -band 0xff), (($addr -shr 8) -band 0xff), ($addr -band 0xff )

}

function IsIpPoolRangeValid {
    param(
        [Parameter(Mandatory=$true)][string]$startIp,
        [Parameter(Mandatory=$true)][string]$endIp
        )

    $startIpInt = Convert-IPv4StringToInt -addr $startIp
    $endIpInt = Convert-IPv4StringToInt -addr $endIp

    if( $startIpInt -gt $endIpInt) {
        return $false
    }

    return $true
}

function IsIpWithinPoolRange {
    param(
        [Parameter(Mandatory=$true)][string]$targetIp,
        [Parameter(Mandatory=$true)][string]$startIp,
        [Parameter(Mandatory=$true)][string]$endIp
        )

    $startIpInt = Convert-IPv4StringToInt -addr $startIp
    $endIpInt = Convert-IPv4StringToInt -addr $endIp
    $targetIpInt = Convert-IPv4StringToInt -addr $targetIp

    if (($targetIpInt -ge $startIpInt) -and ($targetIpInt -le $endIpInt)) {
        return $true
    }

    return $false
}

#endregion

#region Private JSON helper functions

function Invoke-WebRequestWithRetries {
    param(
        [System.Collections.IDictionary] $Headers,
        [string] $ContentType,
        [Microsoft.PowerShell.Commands.WebRequestMethod] $Method,
        [System.Uri] $Uri,
        [object] $Body,
        [Switch] $DisableKeepAlive,
        [Switch] $UseBasicParsing,
        [System.Management.Automation.PSCredential] $Credential,
        [System.Management.Automation.Runspaces.PSSession] $RemoteSession
    )

    $params = @{
        'Headers'=$headers;
        'ContentType'=$content;
        'Method'=$method;
        'uri'=$uri
        }

    if($Body -ne $null) {
        $params.Add('Body', $Body)
    }
    if($DisableKeepAlive.IsPresent) {
        $params.Add('DisableKeepAlive', $true)
    }
    if($UseBasicParsing.IsPresent) {
        $params.Add('UseBasicParsing', $true)
    }
    if($Credential -ne [System.Management.Automation.PSCredential]::Empty -and $Credential -ne $null) {
        $params.Add('Credential', $Credential)
    }

    $retryIntervalInSeconds = 30
    $maxRetry = 6
    $retryCounter = 0

    do {
        try {
            if($RemoteSession -eq $null) {
                $result = Invoke-WebRequest @params
            }
            else {
                $result = Invoke-Command -Session $RemoteSession -ScriptBlock {
                    Invoke-WebRequest @using:params
                }
            }
            break
        }
        catch {
            Write-Verbose "Invoke-WebRequestWithRetries: $($Method) Exception: $_"
            Write-Verbose "Invoke-WebRequestWithRetries: $($Method) Exception: $($_.Exception.Response)"

            if ($_.Exception.Response.statuscode -eq "NotFound") {
                    return $null
            }

            $retryCounter++
            if($retryCounter -le $maxRetry) {

                Write-verbose "Invoke-WebRequestWithRetries: retry this operation in $($retryIntervalInSeconds) seconds. Retry count: $($retryCounter)."
                sleep -Seconds $retryIntervalInSeconds
            }
            else {
                # last retry still fails, so throw the exception
                throw $_
            }
        }
    } while ($shouldRetry -and ($retryCounter -le $maxRetry))

    return $result
}

function JSONPost {
    param(
        [Parameter(position=0,mandatory=$true,ParameterSetName="WithCreds")]
        [String] $NetworkControllerRestIP=$script:NetworkControllerRestIP,
        [Parameter(position=1,mandatory=$true,ParameterSetName="WithCreds")]
        [Parameter(position=0,mandatory=$true,ParameterSetName="CachedCreds")]
        [String] $path,  #starts with object, does not include server, i.e. "/Credentials"
        [Parameter(position=2,mandatory=$true,ParameterSetName="WithCreds")]
        [Parameter(position=1,mandatory=$true,ParameterSetName="CachedCreds")]
        [Object] $bodyObject,
        [Parameter(position=3,mandatory=$true,ParameterSetName="WithCreds")]
        [Object] $credential=$script:NetworkControllerCred,
        [Parameter(position=4,mandatory=$false,ParameterSetName="WithCreds")]
        [String] $computerName=$null
    )

    if ($NetworkControllerRestIP -eq "")
    {
        write-error "Network controller REST IP not specified. You must first call Set-NCConnection."
        return
    }

    $headers = @{"Accept"="application/json"}
    $content = "application/json; charset=UTF-8"
    $uriRoot = "$($script:urlroot)$NetworkControllerRestIP/Networking/v1"
    $timeout = 10

    $method = "Put"
    $uri = "$uriRoot$path/$($bodyObject.resourceId)"
    $body = convertto-json $bodyObject -Depth 100
    $pssession = $null

    Write-Verbose "JSON Put [$path]"
    if ($path -notlike '/Credentials*') {
        Write-Verbose "Payload follows:"
        Write-Verbose $body
    }

    try {
        # $computerName is here to workaround product limitation for PUT of LoadBalancer, which is > 35KB and must be done from the REST hosting NC Vm.
        if (-not $computerName) {
            if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) {
                Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing | out-null
            } else {
                Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing -Credential $credential | out-null
            }
        }
        else {
            $pssession = new-pssession -ComputerName $computerName -Credential $credential
            Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing -Credential $credential -RemoteSession $pssession | out-null
        }
    }
    catch {
       Write-Verbose "PUT Exception: $_"
       Write-Verbose "PUT Exception: $($_.Exception.Response)"
    }
    finally {
        if($pssession -ne $null)
        {
            Remove-PSSession $pssession
        }
    }
}

function JSONGet {
    param(
        [Parameter(mandatory=$true)]
        [String] $NetworkControllerRestIP,
        [Parameter(mandatory=$true)]
        [String] $path,  #starts with object and may include resourceid, does not include server, i.e. "/Credentials" or "/Credentials/{1234-
        [Parameter(mandatory=$false)]
        [Switch] $WaitForUpdate,
        [Switch] $Silent,
        [PSCredential] $credential
    )

    if ($NetworkControllerRestIP -eq "")
    {
        write-error "Network controller REST IP not specified. You must first call Set-NCConnection."
        return
    }

    $headers = @{"Accept"="application/json"}
    $content = "application/json; charset=UTF-8"
    $uriRoot = "$($script:urlroot)$NetworkControllerRestIP/Networking/v1"

    $method = "Get"
    $uri = "$uriRoot$path"

    if (!$Silent) {
        Write-Verbose "JSON Get [$path]"
    }

    try {
        $NotFinished = $true
        do {
            if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) {
                $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing
            } else {
                $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing -Credential $credential
            }

            if($result -eq $null) {
                return $null
            }

            #Write-Verbose "JSON Result: $result"
            $toplevel = convertfrom-json $result.Content
            if ($toplevel.value -eq $null)
            {
                    $obj = $toplevel
            } else {
                    $obj = $toplevel.value
            }

            if ($WaitForUpdate.IsPresent) {
                    if ($obj.properties.provisioningState -eq "Updating")
   {
                        Write-Verbose "JSONGet: the object's provisioningState is Updating. Wait 1 second and check again."
                        sleep 1 #then retry
                    }
                    else
   {
                        $NotFinished = $false
                    }
            }
            else
            {
                $notFinished = $false
            }
      } while ($NotFinished)

      if ($obj.properties.provisioningState -eq "Failed") {
         write-error ("Provisioning failed: {0}`nReturned Object: {1}`nObject properties: {2}" -f $uri, $obj, $obj.properties)
      }
      return $obj
    }
    catch
    {
        if (!$Silent)
        {
           Write-Verbose "GET Exception: $_"
           Write-Verbose "GET Exception: $($_.Exception.Response)"
        }
        return $null
    }
}

function JSONDelete {
    param(
        [String] $NetworkControllerRestIP,
        [String] $path,
        [Parameter(mandatory=$false)]
        [Switch] $WaitForUpdate,
        [PSCredential] $credential
    )
    if ($NetworkControllerRestIP -eq "")
    {
        write-error "Network controller REST IP not specified. You must first call Set-NCConnection."
        return
    }

    $headers = @{"Accept"="application/json"}
    $content = "application/json; charset=UTF-8"
    $uriRoot = "$($script:urlroot)$NetworkControllerRestIP/Networking/v1"

    $method = "Delete"
    $uri = "$uriRoot$path"

    Write-Verbose "JSON Delete [$path]"
    try {
        if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) {
            Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing
        } else {
            Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing -Credential $credential
        }
    }
    catch {
        Write-Verbose "PUT Exception: $_"
        Write-Verbose "PUT Exception: $($_.Exception.Response)"
    }

    $maxRecheck = 100
    $currentCheck = 0
    if ($WaitForUpdate.IsPresent) {
        try {
            $NotFinished = $true
            do {
                if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) {
                        $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method "GET" -Uri $uri -DisableKeepAlive -UseBasicParsing
                }
                else {
                        $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method "GET" -Uri $uri -DisableKeepAlive -UseBasicParsing -Credential $credential
                }

                if($result -ne $null) {
                    Write-Verbose "Object still exists, check again in 1 second"
                    sleep 1 #then retry
                    $currentCheck++
                }
                else {
                    break
                }
            } while ($currentCheck -lt $maxRecheck)
        }
        catch {
            if ($_.Exception.Response.statuscode -eq "NotFound") {
                return
            }
            Write-Verbose "GET Exception: $_"
            Write-Verbose "GET Exception: $($_.Exception.Response)"
        }
    }
}

#endregion

function Get-NCNetworkInterfaceResourceId
{
    param(
        [Parameter(mandatory=$true)]
        [String] $InstanceId
        )
    if (([String]::IsNullOrEmpty($InstanceId)) -or ($InstanceId -eq "") -or ($InstanceId -eq [System.Guid]::Empty)) {
        write-verbose ("Instance id ($InstanceId) either null or empty string or empty guid")
        return $InstanceId
    }

    write-verbose ("Searching resourceId for instance id [$InstanceId]." )

    try
    {
        $interfaces = JSONGet $script:NetworkControllerRestIP "/networkinterfaces" -Credential $script:NetworkControllerCred

        if ($interfaces -ne $null)
        {
            foreach ($interface in $interfaces)
            {
                if ($interface.instanceId -eq $InstanceId)
                {
                    return $interface.resourceId
                }
            }
        }
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }

    return $null
}

function Get-NCNetworkInterfaceInstanceId
{
    param(
        [Parameter(mandatory=$true)]
        [String] $ResourceId
        )
    if (([String]::IsNullOrEmpty($ResourceId)) -or ($ResourceId -eq "") -or ($ResourceId -eq [System.Guid]::Empty)) {
        write-verbose ("Resource id ($ResourceId) either null or empty string or empty guid")
        return $ResourceId
    }

    write-verbose ("Searching Instance Id for Resource Id [$ResourceId]." )

    try
    {
        $interfaces = JSONGet $script:NetworkControllerRestIP "/networkinterfaces" -Credential $script:NetworkControllerCred

        if ($interfaces -ne $null)
        {
            foreach ($interface in $interfaces)
            {
                if ($interface.resourceId -eq $ResourceId)
                {
                    return $interface.instanceId
                }
            }
        }
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }

    return $null
}

function Set-NCConnection
{
    param(
        [Parameter(position=0,mandatory=$true,ParameterSetName="Credential")]
        [Parameter(position=0,mandatory=$true,ParameterSetName="NoCreds")]
        [string] $RestIP,
        [Parameter(mandatory=$true,ParameterSetName="Credential")]
        [PSCredential] $Credential=[System.Management.Automation.PSCredential]::Empty
        )

    $script:NetworkControllerRestIP = $RestIP
    $script:NetworkControllerCred = $Credential
}

function New-NCLogicalNetwork {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$false)]
        [object[]] $LogicalNetworkSubnets=$null,
        [Switch] $EnableNetworkVirtualization
    )

    $LogicalNetwork = @{}
    $LogicalNetwork.resourceId = $resourceId
    $logicalNetwork.properties = @{}

    if ($LogicalNetworkSubnets -eq $null)
    {
        $logicalNetwork.properties.subnets = @()
    }
    else
    {
        $logicalNetwork.properties.subnets = $LogicalNetworkSubnets
    }

    if ($EnableNetworkVirtualization.ispresent) {
        $logicalNetwork.properties.networkVirtualizationEnabled = "True"
    } else {
        $logicalNetwork.properties.networkVirtualizationEnabled = "False"
    }
    JSONPost  $script:NetworkControllerRestIP "/logicalnetworks" $logicalnetwork -Credential $script:NetworkControllerCred  | out-null
    return JSONGet $script:NetworkControllerRestIP "/logicalnetworks/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred


}
function Get-NCLogicalNetwork{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=""
     )

     return JSONGet $script:NetworkControllerRestIP "/logicalnetworks/$ResourceId" -Credential $script:NetworkControllerCred
}
function Remove-NCLogicalNetwork{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/logicalnetworks/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function Get-NCLogicalNetworkSubnet{
    param(
        [Parameter(mandatory=$true)]
        [object] $LogicalNetwork,
        [Parameter(mandatory=$false)]
        [string] $ResourceID=""
     )

     if ($resourceId -eq "") {
        $uri = "/logicalnetworks/$($LogicalNetwork.ResourceId)/subnets"
    } else {
        $uri = "/logicalnetworks/$($LogicalNetwork.ResourceId)/subnets/$ResourceId"
    }

     return JSONGet $script:NetworkControllerRestIP $uri -Credential $script:NetworkControllerCred
}

function New-NCLogicalNetworkSubnet{
#Creates an in-memory object only. Must pass it into New-NCLogicalNetwork to persist it.
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $AddressPrefix,
        [Parameter(mandatory=$false)]
        [string[]] $DNSServers = @(),
        [Parameter(mandatory=$false)]
        [int] $VLANid = 0,
        [Parameter(mandatory=$true)]
        [string[]] $defaultGateway,
        [Switch] $IsPublic
        )
    $subnet = @{}
    $subnet.resourceId = $ResourceID
    $subnet.properties = @{}
    $subnet.properties.addressPrefix = $AddressPrefix
    $subnet.properties.vlanid = "$vlanid"
    $subnet.properties.dnsServers = $dnsServers
    $subnet.properties.defaultGateways = $defaultGateway
    $subnet.properties.IsPublic = $IsPublic.IsPresent

    return $subnet
}

function New-NCCredential{
    param(
        [Parameter(mandatory=$false,parametersetname='username')]
        [Parameter(mandatory=$false,parametersetname='cert')]
        [Parameter(mandatory=$false,parametersetname='snmp')]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true,parametersetname='username')]
        [string] $Username=$null,
        [Parameter(mandatory=$true,parametersetname='username')]
        [String] $password=$null,
        [Parameter(mandatory=$true,parametersetname='snmp')]
        [String] $communitystring=$null,
        [Parameter(mandatory=$true,parametersetname='cert')]
        [string] $Thumbprint
    )

    # create credentials that will be used to talk to host

    $creds = @{}
    $creds.resourceID = $resourceID
    $creds.properties = @{}
    if ($pscmdlet.ParameterSetName -eq 'cert') {
        $creds.properties.Type = "X509Certificate"
        $creds.properties.Value = $thumbprint
    }
    elseif ($pscmdlet.ParameterSetName -eq 'username') {
        $creds.properties.Type = "UsernamePassword"
        $creds.properties.Username = $Username
        $creds.properties.Value = $password
    }
    else {
        $creds.properties.Type = "SnmpCommunityString"
        $creds.properties.Value = $communitystring
    }

    JSONPost $script:NetworkControllerRestIP "/Credentials" $creds  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/Credentials/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCCredential{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/Credentials/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCCredential         {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/Credentials/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCServerConnection      {
    #Creates an in-memory object only. Must pass it into New-NCServer to persist it.
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ComputerNames,
        [Parameter(mandatory=$true)]
        [object] $Credential
    )

    $connection = @{}
    $connection.managementAddresses = $ComputerNames
    $connection.credential = @{}
    $connection.credential.resourceRef = "/credentials/$($credential.ResourceID)"
    $connection.credentialType = $credential.properties.Type

    return $connection
}

function New-NCServerNetworkInterface{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$false)]
        [boolean] $IsBMC=$false,
        [Parameter(mandatory=$true,ParameterSetName="LogicalSubnet")]
        [object[]] $LogicalNetworkSubnets
    )

    $networkInterface = @{}
    $networkInterface.resourceId = $ResourceID
    $networkInterface.instanceId = $ResourceID
    $networkInterface.properties = @{}
    $networkInterface.properties.isBMC = $IsBMC

    $networkInterface.properties.logicalSubnets = @()
    foreach ($logicalnetworksubnet in $logicalNetworkSubnets) {
        $logicalSubnetref = @{}
        $logicalSubnetref.resourceRef = $logicalnetworksubnet.resourceRef
        $networkInterface.properties.logicalSubnets += $logicalSubnetref
    }

    return $networkInterface
}
function New-NCServer                {
#Must pass in ResourceID since it must match id of virtual switch
    param(
        [Parameter(mandatory=$true)]
        [string] $ResourceID,
        [Parameter(mandatory=$true)]
        [object[]] $Connections,
        [Parameter(mandatory=$false)]
        [string] $Certificate = $null,
        [Parameter(mandatory=$true)]
        [object[]] $PhysicalNetworkInterfaces

    )

    $server = @{}
    $server.resourceId = $ResourceID
    $server.instanceId = $ResourceID
    $server.properties = @{}

    $server.properties.connections = $Connections
    $server.properties.networkInterfaces = $PhysicalNetworkInterfaces
    if ($certificate -ne $null) {
        $server.properties.certificate = $certificate
    }

    JSONPost  $script:NetworkControllerRestIP "/Servers" $server  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/Servers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCServer                {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/Servers/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCServer             {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/Servers/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCMACPool               {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $StartMACAddress,
        [Parameter(mandatory=$true)]
        [string] $EndMACAddress
        )

    $macpool = @{}
    $macpool.resourceId = $ResourceId
    $macpool.properties = @{}
    $macpool.properties.startMacAddress = $StartMACAddress
    $macpool.properties.endMacAddress = $EndMACAddress

    JSONPost  $script:NetworkControllerRestIP "/MacPools" $macPool  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/MacPools/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCMACPool               {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/MacPools/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCMACPool            {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/MacPools/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}
function New-NCIPPool                {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object] $LogicalNetworkSubnet,
        [Parameter(mandatory=$true)]
        [string] $StartIPAddress,
        [Parameter(mandatory=$true)]
        [string] $EndIPAddress,
        [Parameter(mandatory=$true)]
        [string[]] $DNSServers,
        [Parameter(mandatory=$true)]
        [string[]] $DefaultGateways
        )

    #todo: prevalidate that ip addresses and default gateway are within subnet

    $ippool = @{}
    $ippool.resourceId = $ResourceId
    $ippool.properties = @{}
    $ippool.properties.startIpAddress = $StartIPAddress
    $ippool.properties.endIpAddress = $EndIPAddress
    $ippool.properties.dnsServers = $DNSServers
    $ippool.properties.defaultGateways = $DefaultGateways

    $refpath = "$($logicalnetworksubnet.resourceRef)/ippools"
    JSONPost  $script:NetworkControllerRestIP $refpath $ippool  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCIPPool               {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = "",
        [Parameter(mandatory=$true)]
        [object] $LogicalNetworkSubnet
    )
    $refpath = "$($logicalnetworksubnet.resourceRef)/ippools"
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCIPPool            {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs,
        [Parameter(mandatory=$true)]
        [object] $LogicalNetworkSubnet
     )
    $refpath = "$($logicalnetworksubnet.resourceRef)/ippools"
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "$refpath/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}
function New-NCAccessControlListRule {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $Protocol,
        [Parameter(mandatory=$true)]
        [string] $SourcePortRange,
        [Parameter(mandatory=$true)]
        [string] $DestinationPortRange,
        [Parameter(mandatory=$true)]
        [string] $SourceAddressPrefix,
        [Parameter(mandatory=$true)]
        [string] $DestinationAddressPrefix,
        [Parameter(mandatory=$true)]
        [string] $Action,
        [Parameter(mandatory=$true)]
        [string] $ACLType,
        [Parameter(mandatory=$true)]
        [boolean] $Logging,
        [Parameter(mandatory=$true)]
        [int] $Priority
        )

    $aclRule = @{}
    $aclRule.resourceId = $resourceId

    $aclRule.properties = @{}
    $aclRule.properties.protocol = $protocol
    $aclRule.properties.sourcePortRange = $SourcePortRange
    $aclRule.properties.destinationPortRange = $Destinationportrange
    $aclRule.properties.sourceAddressPrefix = $SourceAddressPrefix
    $aclRule.properties.destinationAddressPrefix = $destinationAddressprefix
    $aclRule.properties.action = $action
    $aclRule.properties.type = $ACLType
    if ($logging) {
        $aclRule.properties.logging = "Enabled"
    } else {
        $aclRule.properties.logging = "Disabled"
    }
    $aclRule.properties.priority = "$priority"

    return $aclRule
}
function New-NCAccessControlList     {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object[]] $AccessControlListRules
        )

    $acls = @{}
    $acls.resourceID = $resourceId
    $acls.properties = @{}
    $acls.properties.aclRules = $AccessControlListRules

    $acls.properties.ipConfigurations = @()
    $acls.properties.subnet = @()

    $refpath = "/accessControlLists"
    JSONPost  $script:NetworkControllerRestIP $refpath $acls  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCAccessControlList     {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/accessControlLists/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCAccessControlList  {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/accessControlLists/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}

function New-NCVirtualSubnet         {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $addressPrefix,
        [Parameter(mandatory=$true)]
        [object] $AccessControlList
        )

    $subnet = @{}
    $subnet.resourceId = $ResourceId
    $subnet.properties = @{}
    $subnet.properties.addressPrefix = $AddressPrefix

    $subnet.properties.accessControlList = @{}
    $subnet.properties.accessControlList.resourceRef = $AccessControlList.resourceRef

    $subnet.properties.ipConfigurations = @()

    return $subnet
}

function Get-NCVirtualSubnet       {
    param(
        [Parameter(mandatory=$true)]
        [object] $VirtualNetwork,
        [Parameter(mandatory=$false)]
        [string] $ResourceID=""
     )

     if ($resourceId -eq "") {
        $uri = "/VirtualNetworks/$($VirtualNetwork.ResourceId)/subnets"
    } else {
        $uri = "/VirtualNetworks/$($VirtualNetwork.ResourceId)/subnets/$ResourceId"
    }

     return JSONGet $script:NetworkControllerRestIP $uri -Credential $script:NetworkControllerCred
}

function New-NCVirtualNetwork        {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string[]] $addressPrefixes,
        [Parameter(mandatory=$true)]
        [object] $LogicalNetwork,
        [Parameter(mandatory=$true)]
        [object[]] $VirtualSubnets
        )

    $vnet = @{}
    $vnet.resourceId = $resourceId
    $vnet.properties = @{}
    $vnet.properties.addressSpace = @{}
    $vnet.properties.addressSpace.addressPrefixes = $AddressPrefixes
    $vnet.properties.logicalnetwork = @{}
    $vnet.properties.logicalnetwork.resourceRef = "/logicalnetworks/$($LogicalNetwork.resourceId)"
    $vnet.properties.subnets = $VirtualSubnets

    $refpath = "/virtualnetworks"
    JSONPost  $script:NetworkControllerRestIP $refpath $vnet  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}
function Get-NCVirtualNetwork        {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/VirtualNetworks/$resourceID" -Credential $script:NetworkControllerCred
}
function Remove-NCVirtualNetwork     {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/VirtualNetworks/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}

function Set-NCLoadBalancerManager   {
    param(
        [Parameter(mandatory=$false)]
        [Object[]] $VIPIPPools=$null,
        [Parameter(mandatory=$false)]
        [String[]] $OutboundNatIPExemptions=$null,
        [Parameter(mandatory=$true)]
        [String] $IPAddress

)

    $LBM = @{}
    $lbm.resourceId = "config"
    $lbm.properties = @{}
    $lbm.properties.loadbalancermanageripaddress = $IPAddress

    if ($VIPIPPools -ne $NULL) {
        $lbm.properties.vipIpPools = @()

        foreach ($ippool in $VIPIPPools) {
            $poolRef = @{}
            $poolRef.resourceRef = $ippool.resourceRef
            $lbm.properties.vipIpPools += $poolRef
        }
    }

    if ($OutboundNatIPExemptions -ne $null) {
        $lbm.properties.OutboundNatIPExemptions = $OutboundNatIPExemptions
    }

    JSONPost  $script:NetworkControllerRestIP "/loadbalancermanager" $lbm   -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/loadbalancermanager/config" -WaitForUpdate -Credential $script:NetworkControllerCred


}
function Get-NCLoadbalancerManager   {

     return JSONGet $script:NetworkControllerRestIP "/LoadBalancerManager/Config"  -Credential $script:NetworkControllerCred
}

function New-NCVirtualServer         {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object[]] $Connections,
        [Parameter(mandatory=$false)]
        [string] $Certificate,
        [Parameter(mandatory=$true)]
        [string] $vmGuid
    )

    $server = @{}
    $server.resourceId = $ResourceID
    if ($ResourceID.Length -lt 36)
    { $server.instanceId = [system.guid]::NewGuid() }
    else
    { $server.instanceId = $ResourceID }
    $server.properties = @{}

    $server.properties.connections = $Connections
    if (![string]::IsNullOrEmpty($Certificate))
    {
        $server.properties.certificate = $certificate
    }
    $server.properties.vmGuid = $vmGuid

    JSONPost  $script:NetworkControllerRestIP "/VirtualServers" $server  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/VirtualServers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}
function Get-NCVirtualServer         {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/VirtualServers/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCVirtualServer      {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/VirtualServers/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCLoadBalancerMuxPeerRouterConfiguration {
    param(
        [Parameter(mandatory=$true)]
        [string] $RouterName,
        [Parameter(mandatory=$true)]
        [string] $RouterIPAddress,
        [Parameter(mandatory=$true)]
        [int] $PeerASN,
        [Parameter(mandatory=$false)]
        [string] $LocalIPAddress
        )

    $peer = @{}
    $peer.routerName = $RouterName
    $peer.routerIPAddress = $RouterIPAddress
    $peer.PeerASN = "$PeerASN"
    $peer.localIPAddress = $LocalIPAddress

    return $peer
}
function New-NCLoadBalancerMux       {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [int] $LocalASN,
        [Parameter(mandatory=$false)]
        [object[]] $peerRouterConfigurations,
        [Parameter(mandatory=$true)]
        [object] $VirtualServer,
        [Parameter(mandatory=$false)]
        [object[]] $connections

    )

    # create credentials that will be used to talk to host

    $mux = @{}
    $mux.resourceID = $resourceID
    $mux.properties = @{}
    $mux.properties.routerConfiguration = @{}
    $mux.properties.routerConfiguration.localASN = "$LocalASN"
    $mux.properties.routerConfiguration.peerRouterConfigurations = @()
    foreach ($peerRouterConfiguration in $peerRouterConfigurations)
    {
        $mux.properties.routerConfiguration.peerRouterConfigurations += $peerRouterConfiguration
    }
    $mux.properties.virtualServer = @{}
    $mux.properties.virtualServer.resourceRef = $VirtualServer.resourceRef

    JSONPost $script:NetworkControllerRestIP "/LoadBalancerMuxes" $mux  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/LoadBalancerMuxes/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCLoadBalancerMux       {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/LoadBalancerMuxes/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCLoadBalancerMux    {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/LoadBalancerMuxes/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCLoadBalancerFrontEndIPConfiguration    {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        #[Parameter(mandatory=$true)]
        #[object] $LoadBalancer,
        [Parameter(mandatory=$true)]
        [string] $PrivateIPAddress,
        #[Parameter(mandatory=$true)]
        #[object[]] $LoadBalancingRules,
        [Parameter(mandatory=$true)]
        [object] $Subnet
        )

    $frontend= @{}
    $frontend.resourceID = $resourceID
    $frontend.properties = @{}
    $frontend.properties.privateIPAddress = $PrivateIPAddress
    $frontend.properties.privateIPAllocationMethod = "Static"
    $frontend.properties.Subnet = @{}
    $frontend.properties.Subnet.resourceRef = $subnet.resourceRef

    return $frontend
}

function New-NCLoadBalancerBackendAddressPool         {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$false)]
        [object[]] $IPConfigurations
        )

    $be= @{}
    $be.resourceID = $resourceID
    $be.properties = @{}

    $be.properties.backendIPConfigurations = @()
    if ($IPConfigurations -ne $null) {
        foreach ($nic in $IPConfigurations) {
            $newRef = @{}
            $newRef.resourceRef = $nic.resourceRef
            $be.properties.backendIPConfigurations += $newRef
        }
    }

    return $be
}
function New-NCLoadBalancerLoadBalancingRule          {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $protocol,
        [Parameter(mandatory=$true)]
        [int] $frontendPort,
        [Parameter(mandatory=$true)]
        [int] $backendPort,
        [Parameter(mandatory=$true)]
        [boolean] $enableFloatingIP,
        [Parameter(mandatory=$false)]
        [int] $IdleTimeoutInMinutes = 4,
        [Parameter(mandatory=$false)]
        [String] $LoadDistribution = "Default",
        [Parameter(mandatory=$true)]
        [object[]] $frontEndIPConfigurations = $null,
        [Parameter(mandatory=$true)]
        [object] $backendAddressPool
        )

    $rule= @{}
    $rule.resourceID = $resourceID
    $rule.properties = @{}
    $rule.properties.protocol = $protocol
    $rule.properties.frontEndPort = "$frontendPort"
    $rule.properties.backendPort = "$backendPort"

    if ($enableFloatingIP) {
        $rule.properties.enableFloatingIP = "true"
    } else {
        $rule.properties.enableFloatingIP = "false"
    }
    $rule.properties.idleTimeoutInMinutes = "$idleTImeoutInMinutes"
    $rule.properties.loadDistribution = $LoadDistribution

    $rule.properties.frontendIPConfigurations = @()

    foreach ($vip in $frontendipconfigurations) {
        $newvip = @{}
        $newvip.resourceRef = "/loadbalancers/`{0`}/frontendipconfigurations/$($vip.resourceId)"
        $rule.properties.frontendIPConfigurations += $newvip
    }
    $rule.properties.backendAddressPool = @{}
    $rule.properties.backendAddressPool.resourceRef = "/loadbalancers/`{0`}/backendaddresspools/$($backendAddressPool.resourceID)"

    return $rule
}

function New-NCLoadBalancerProbe     {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object] $LoadBalancer,
        [Parameter(mandatory=$true)]
        [string] $protocol,
        [Parameter(mandatory=$true)]
        [int] $port,
        [Parameter(mandatory=$true)]
        [int] $intervalInSeconds,
        [Parameter(mandatory=$true)]
        [int] $numberOfProbes,
        [Parameter(mandatory=$false)]
        [object[]] $loadBalancingRules = $null
        )

    $probe= @{}
    $probe.resourceID = $resourceID
    $probe.properties = @{}
    $probe.properties.protocol = $protocol
    $probe.properties.port = "$port"
    $probe.properties.intervalInSeconds= "$intervalInSeconds"
    $probe.properties.numberOfProbes = "$numberOfProbes"

    #TODO: what to do with loadbalancingrules

    $refpath = "$($loadbalancer.resourceRef)/probes"
    JSONPost  $script:NetworkControllerRestIP $refpath $probe  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function New-NCLoadBalancerOutboundNatRule            {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$false)]
        [string] $protocol="All",
        [Parameter(mandatory=$true)]
        [object[]] $frontEndIpConfigurations,
        [Parameter(mandatory=$true)]
        [object] $backendAddressPool
        )

    $natrule= @{}
    $natrule.resourceID = $resourceID
    $natrule.properties = @{}
    $natrule.properties.protocol = $protocol
    $natrule.properties.frontendIPConfigurations = @()

    foreach ($frontendIP in $frontEndIpConfigurations) {
        $NewFEIP = @{}
        $NewFEIP.resourceRef = "/loadbalancers/`{0`}/frontendipconfigurations/$($frontendIP.resourceId)"
        $natrule.properties.frontendIPConfigurations += $NewFEIP
    }

    $natrule.properties.backendAddressPool = @{}
    $natrule.properties.backendAddressPool.resourceRef = "/loadbalancers/`{0`}/backendaddresspools/$($backendAddressPool.resourceID)"

    return $natrule
}

function New-NCLoadBalancer
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [parameter(mandatory=$true)]
        [object[]] $FrontEndIPConfigurations,
        [parameter(mandatory=$true)]
        [object[]] $backendAddressPools,
        [parameter(mandatory=$false)]
        [object[]] $loadBalancingRules = $NULL,
        [parameter(mandatory=$false)]
        [object[]] $probes = $NULL,
        [parameter(mandatory=$false)]
        [object[]] $outboundnatrules= $NULL,
        [Parameter(mandatory=$false)]
        [string] $ComputerName=$script:NetworkControllerRestIP
    )

    $lb = JSONGet $script:NetworkControllerRestIP "/LoadBalancers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -Silent:$true
    # Note this handles Add updates ONLY for LOAD Balancing RULES (common case in MAS / PoC)
    if ($null -ne $lb)
    {
        # add the obNat, LB Rule, Inbound Rule

        $FrontEndIPConfigurations = @($FrontEndIPConfigurations)

        $lbfeIp = $lb.properties.frontendipconfigurations[0]

        if($null -ne $lbfep)
        {
            $newFeIP = @(New-NCLoadBalancerFrontEndIPConfiguration -resourceID $lbfeIp.resourceid -PrivateIPAddress $lbfeIp.properties.privateIpaddress -Subnet $lbfeIp.properties.subnet)
            $FrontEndIPConfigurations = $newFeIp
        }

        $lbbepool = $lb.properties.backendaddresspools[0]

        if($null -ne $lbbepool)
        {
            $newBePool = @(New-NCLoadBalancerBackendAddressPool -resourceID $lbbepool.resourceId -IPConfigurations $lbbepool.properties.backendIPConfigurations)
            $backendAddressPools = $newBePool
        }

        if ( ($null -ne $lb.properties.OutboundNatRules)  -and ($lb.properties.OutboundNatRules.count -ne 0))
        {
            $obNatRules =$lb.properties.OutboundNatRules[0]

            $newObNatRule = @(New-NCLoadBalancerOutboundNatRule -resourceID $obNatRules.resourceId -protocol $obNatRules.properties.protocol -frontEndIpConfigurations $FrontEndIPConfigurations -backendAddressPool $backendAddressPools)
            $outboundnatrules = $newObNatRule
        }

        $loadBalancingRules = @($loadBalancingRules)
        $newloadBalancingRules = @()

        foreach ($lbrule in $lb.properties.loadBalancingRules)
        {
            $newLbRule = @(New-NCLoadBalancerLoadBalancingRule -resourceId $lbrule.resourceId -protocol $lbrule.properties.protocol -frontendPort $lbrule.properties.frontendPort -backendport $lbrule.properties.backendPort -enableFloatingIP $lbrule.properties.enableFloatingIp -frontEndIPConfigurations $FrontEndIPConfigurations -backendAddressPool $backendAddressPools)
            $newloadBalancingRules += $newLbRule
        }

        $lbRuleCount = $newloadBalancingRules.Count

        #find new unique lb rules
        foreach ($lbrule in $loadBalancingRules)
        {
            $found = $false
            foreach ($oldrule in $lb.properties.loadBalancingRules)
            {
                if(($lbrule.properties.frontendPort -eq $oldrule.properties.frontendPort) -and ($lbrule.properties.backendPort -eq $oldrule.properties.backendPort))
                {
                    $found = $true
                }
            }

            if(-not $found)
            {
                $enableFloat = [Boolean]::Parse("$($lbrule.properties.enableFloatingIp)")
                $newLbRule = @(New-NCLoadBalancerLoadBalancingRule -resourceId $lbrule.resourceId -protocol $lbrule.properties.protocol -frontendPort $lbrule.properties.frontendPort -backendport $lbrule.properties.backendPort -enableFloatingIP $enableFloat -frontEndIPConfigurations $FrontEndIPConfigurations -backendAddressPool $backendAddressPools)
                $newloadBalancingRules += $newLbRule
            }
        }

        if($lbRuleCount -eq $newloadBalancingRules.Count)
        {
            #No change in LB required, skip the update
            return $lb
        }

        $loadBalancingRules = $newloadBalancingRules
    }
    else
    {
        $lb = @{}
        $lb.resourceID = $resourceID
        $lb.properties = @{}
    }

    #Need to populate existing refs with LB resourceID
    if ($loadbalancingrules -ne $null)
    {
        foreach ($rule in $loadbalancingrules)
        {
            foreach ($frontend in $rule.properties.frontendipconfigurations)
            {
                $frontend.resourceRef = ($frontend.resourceRef -f $resourceID)
            }
            $rule.properties.backendaddresspool.resourceRef = ($rule.properties.backendaddresspool.resourceRef -f $resourceID)
        }
        $lb.properties.loadBalancingRules = $loadbalancingrules
    }

    if ($outboundnatrules -ne $null)
    {
        foreach ($rule in $outboundnatrules)
        {
            foreach ($frontend in $rule.properties.frontendipconfigurations)
            {
                $frontend.resourceRef = ($frontend.resourceRef -f $resourceID)
            }
            $rule.properties.backendaddresspool.resourceRef = ($rule.properties.backendaddresspool.resourceRef -f $resourceID)
        }
        $lb.properties.outboundnatrules = $outboundnatrules
    }

    foreach ($frontend in $frontendipconfigurations)
    {
        $frontendref = "/loadbalancers/$resourceID/frontendipconfigurations/$($frontend.resourceId)"

        $frontend.properties.loadbalancingrules = @()
        if ($loadbalancingrules -ne $null)
        {
            foreach ($rule in $loadbalancingrules)
            {
                foreach ($rulefe in $rule.properties.frontendipconfigurations)
                {
                    if ($rulefe.resourceRef -eq $frontendref)
   {
                        $newref = @{}
                        $newref.resourceRef = "/loadbalancers/$resourceID/loadbalancingrules/$($rule.resourceId)"

                        $frontend.properties.loadbalancingrules += $newref
                    }
                }

            }
        }

        $frontend.properties.outboundNatRules = @()
        if ($oubboundNatRules -ne $null)
        {
            foreach ($rule in $outboundnatrules)
            {
                foreach ($rulefe in $rule.properties.frontendipconfigurations)
                {
                    if ($rulefe.resourceRef -eq $frontendref)
   {
                        $newref = @{}
                        $newref.resourceRef = "/loadbalancers/$resourceID/outboundnatrules/$($rule.resourceId)"

                        $frontend.properties.outboundNatRules += $newref
                    }
                }

            }
        }
    }
    $lb.properties.frontendipconfigurations = $frontendipconfigurations

    foreach ($be in $backendaddresspools)
    {
        $beref = "/loadbalancers/$resourceID/backendaddresspools/$($be.resourceId)"

        $be.properties.loadbalancingrules = @()
        if ($loadbalancingrules -ne $null)
        {
            foreach ($rule in $loadbalancingrules)
            {
                if ($rule.properties.backendaddresspool.resourceRef -eq $beref)
                {
                    $newref = @{}
                    $newref.resourceRef = "/loadbalancers/$resourceID/loadbalancingrules/$($rule.resourceId)"
                    $be.properties.loadbalancingrules += $newref
                }

            }
        }
        $be.properties.outboundnatrules = @()
        if ($outboundnatrules -ne $null)
        {
            foreach ($rule in $outboundnatrules)
            {
                if ($rule.properties.backendaddresspool.resourceRef -eq $beref)
                {
                    $newref = @{}
                    $newref.resourceRef = "/loadbalancers/$resourceID/outboundnatrules/$($rule.resourceId)"
                    $be.properties.outboundnatrules += $newref
                }

            }
        }
    }
    $lb.properties.backendaddresspools = $backendaddresspools

    # $computerName is here to workaround product limitation for PUT of LoadBalancer, which is > 35KB and must be done from the REST hosting NC Vm.
    JSONPost $script:NetworkControllerRestIP "/LoadBalancers" $lb  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/LoadBalancers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCLoadBalancer          {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/LoadBalancers/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCLoadBalancer       {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/LoadBalancers/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCNetworkInterface      {
    param(
        [Parameter(mandatory=$true,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$true,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$true,ParameterSetName="ByNoNetwork")]
        [string] $resourceID,
        [Parameter(mandatory=$true,ParameterSetName="ByVirtualNetwork")]
        [object] $VirtualSubnet = $null,
        [Parameter(mandatory=$true,ParameterSetName="ByLogicalNetwork")]
        [object] $Subnet = $null,
        [Parameter(mandatory=$false,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByNoNetwork")]
        [string] $IPAddress = $null,
        [Parameter(mandatory=$true,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$true,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$true,ParameterSetName="ByNoNetwork")]
        [string] $MACAddress,
        [Parameter(mandatory=$false,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByNoNetwork")]
        [string[]] $DNSServers = @(),
        [Parameter(mandatory=$false,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByNoNetwork")]
        [object] $acl=$null
    )

    if ($pscmdlet.ParameterSetName -eq 'ByVirtualNetwork') {
        $subnet = $virtualsubnet
    }

    $interface = @{}
    # resource Id
    $interface.resourceID = $resourceID
    $interface.properties = @{}

    # Mac Address
    $interface.properties.privateMacAddress = $macaddress
    $interface.properties.privateMacAllocationMethod = "Static"

    # IPConfigurations
    if ($Subnet -ne $null -or ![string]::IsNullOrEmpty($IPAddress) -or $acl -ne $null)
    {
        $interface.properties.ipConfigurations = @()

        $ipconfig = @{}
        $ipconfig.resourceId = [System.Guid]::NewGuid().toString()
        $ipconfig.properties = @{}

        if ($Subnet -ne $null)
        {
            $ipconfig.properties.subnet = @{}
            $ipconfig.properties.subnet.resourceRef = $Subnet.resourceRef
        }
        if (![string]::IsNullOrEmpty($IPAddress))
        {
            $ipconfig.properties.privateIPAddress = $IPAddress
            $ipconfig.properties.privateIPAllocationMethod = "Static"
        }
        if ($acl -ne $null) {
            $ipconfig.properties.accessControlList = @{}
            $ipconfig.properties.accessControlList.resourceRef = $acl.resourceRef
        }

        $interface.properties.ipConfigurations += $ipconfig
    }

    # DNS Servers
    if ($DNSServers -ne $null -and $DNSServers.count -gt 0)
    {
        $interface.properties.dnsSettings = @{}
        $interface.properties.dnsSettings.dnsServers = $DNSServers
    }

    JSONPost $script:NetworkControllerRestIP "/NetworkInterfaces" $interface  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/NetworkInterfaces/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCNetworkInterface      {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/NetworkInterfaces/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCNetworkInterface   {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/NetworkInterfaces/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function Get-ServerResourceId        {
   param (
        [Parameter(mandatory=$false)]
        [string] $ComputerName="localhost",
        [Parameter(mandatory=$false)]
        [Object] $Credential=$script:NetworkControllerCred
        )

    $resourceId = ""

    write-verbose ("Retrieving server resource id on [$ComputerName]")

    try
    {
        $pssession = new-pssession -ComputerName $ComputerName -Credential $Credential

        $resourceId = invoke-command -session $pssession -ScriptBlock {
            $VerbosePreference = 'Continue'
            write-verbose "Retrieving first VMSwitch on [$using:ComputerName]"

            $switches = Get-VMSwitch -ErrorAction Ignore
            if ($switches.Count -eq 0)
            {
                throw "No VMSwitch was found on [$using:ComputerName]"
            }

            return $switches[0].Id
        }
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }
    finally
    {
        Remove-PSSession $pssession
    }

    write-verbose "Server resource id is [$resourceId] on [$ComputerName]"
    return $resourceId
}

function Set-PortProfileId           {
   param (
        [Parameter(mandatory=$true)]
        [string] $resourceID,
        [Parameter(mandatory=$true)]
        [string] $VMName,
        [Parameter(mandatory=$false)]
        [string] $VMNetworkAdapterName,
        [Parameter(mandatory=$false)]
        [string] $ComputerName="localhost",
        [Parameter(mandatory=$false)]
        [Object] $credential=$script:NetworkControllerCred,
        [Parameter(mandatory=$false)]
        [int] $ProfileData = 1,
        [Switch] $force
        )

    #do not change these values
    write-verbose ("Setting port profile for [$vmname] on [$computername]" )

    try
    {
        $pssession = new-pssession -ComputerName $computername -Credential $credential
        $isforce = $force.ispresent

        invoke-command -session $pssession -ScriptBlock {
            $VerbosePreference = 'Continue'
            write-verbose ("Running port profile set script block on host" )

            $PortProfileFeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56"
            $NcVendorId  = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}"

            $portProfileDefaultSetting = Get-VMSystemSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId

            $portProfileDefaultSetting.SettingData.ProfileId = "{$using:resourceId}"
            $portProfileDefaultSetting.SettingData.NetCfgInstanceId = "{56785678-a0e5-4a26-bc9b-c0cba27311a3}"
            $portProfileDefaultSetting.SettingData.CdnLabelString = "TestCdn"
            $portProfileDefaultSetting.SettingData.CdnLabelId = 1111
            $portProfileDefaultSetting.SettingData.ProfileName = "Testprofile"
            $portProfileDefaultSetting.SettingData.VendorId = $NcVendorId
            $portProfileDefaultSetting.SettingData.VendorName = "NetworkController"
            $portProfileDefaultSetting.SettingData.ProfileData = $using:ProfileData
            #$portprofiledefaultsetting.settingdata

            write-verbose ("Retrieving VM network adapter $using:VMNetworkAdapterName" )
            if ([String]::IsNullOrEmpty($using:VMNetworkAdapterName))
            {
                write-verbose ("Retrieving all VM network adapters for VM $using:VMName")
                $vmNics = Get-VMNetworkAdapter -VMName $using:VMName
            }
            else
            {
                write-verbose ("Retrieving VM network adapter $using:VMNetworkAdapterName for VM $using:VMName" )
                $vmNics = @(Get-VMNetworkAdapter -VMName $using:VMName -Name $using:VMNetworkAdapterName)
            }

            foreach ($vmNic in $vmNics) {
                write-verbose ("Setting port profile on vm network adapter $($vmNic.Name)" )
                $currentProfile = Get-VMSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId -VMNetworkAdapter $vmNic

                if ( $currentProfile -eq $null)
                {
                    write-verbose ("Adding port feature for [{0}] to [{1}]" -f $using:VMName, "{$using:resourceId}")
                    Add-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature  $portProfileDefaultSetting -VMNetworkAdapter $vmNic | out-null
                    write-verbose "Adding port feature complete"

                }
                else
                {
                    if ($using:isforce) {
                        write-verbose ("Setting port feature for [{0}] to [{1}]" -f $using:VMName, "{$using:resourceId}")

                        $currentProfile.SettingData.ProfileId = "{$using:resourceId}"
                        $currentProfile.SettingData.ProfileData = $using:ProfileData
                        Set-VMSwitchExtensionPortFeature  -VMSwitchExtensionFeature $currentProfile  -VMNetworkAdapter $vmNic | out-null
                    } else {
                        write-verbose ("Port profile already set for [{0}] use -Force to override." -f $using:VMName)
                    }
                }
            }
        }
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }
    finally
    {
        Remove-PSSession $pssession
    }
}

function Remove-PortProfileId
{
   param (
        [Parameter(mandatory=$true)]
        [string] $VMName,
        [Parameter(mandatory=$false)]
        [string] $VMNetworkAdapterName="Network Adapter",
        [Parameter(mandatory=$false)]
        [string] $ComputerName="localhost"
        )

    write-verbose ("Removing port profile for Network Adapter [$VMNetworkAdapterName] on VM [$vmname] on [$computername]" )

    try
    {
        $pssession = new-pssession -ComputerName $computername

        invoke-command -session $pssession -ScriptBlock {
            param($VMName, $VMNetworkAdapterName)
            $VerbosePreference = 'Continue'
            write-verbose ("Running port profile remove script block on host" )

            #do not change these values
            $PortProfileFeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56"
            $NcVendorId  = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}"

            $portProfileCurrentSetting = Get-VMSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId -VMName $VMName -VMNetworkAdapterName $VMNetworkAdapterName

            write-verbose ("Removing port profile from vm network adapter $VMNetworkAdapterName" )
            Remove-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $portProfileCurrentSetting -VMName $VMName -VMNetworkAdapterName $VMNetworkAdapterName -Confirm:$false
        } -ArgumentList @($VMName, $VMNetworkAdapterName)
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }
    finally
    {
        Remove-PSSession $pssession
    }
}

function New-NCSwitchPort        {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid()
    )

    $server = @{}
    $server.resourceId = $ResourceID
    $server.instanceId = $ResourceID
    $server.properties = @{}

    if ($managed.ispresent)  {
        $server.properties.managementState = "Managed"
    } else
    {
        $server.properties.managementState = "unManaged"
    }
    $server.properties.roleType = "multiLayerSwitch"
    $server.properties.switchType = $switchtype

    $server.properties.connections = $Connections

    JSONPost  $script:NetworkControllerRestIP "/Switches" $server  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/Switches/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}

function New-NCSwitch        {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object[]] $Connections,
        [Parameter(mandatory=$true)]
        [string] $switchType,
        [Switch] $Managed
    )

    $server = @{}
    $server.resourceId = $ResourceID
    $server.instanceId = $ResourceID
    $server.properties = @{}

    if ($managed.ispresent)  {
        $server.properties.managementState = "Managed"
    } else
    {
        $server.properties.managementState = "Unmanaged"
    }
    $server.properties.roleType = "multiLayerSwitch"
    $server.properties.switchType = $switchtype
    $server.properties.switchPorts = @()

    $newport = @{}
    $newport.ResourceRef = "Port1"
    $newport.properties = @{}
    $server.properties.switchPorts += $newport

    $newport = @{}
    $newport.ResourceRef = "Port2"
    $newport.properties = @{}
    $server.properties.switchPorts += $newport

    $server.properties.connections = $Connections

    JSONPost  $script:NetworkControllerRestIP "/Switches" $server   -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/Switches/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}

function Get-NCSwitch         {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/Switches/$resourceID"  -Credential $script:NetworkControllerCred
}

#
# Gateway Specific Wrappers
#

function New-NCPublicIPAddress
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $PublicIPAddress)

    $publicIP = @{}
    $publicIP.resourceId = $ResourceID
    $publicIP.properties = @{}
    $publicIP.properties.ipAddress = $PublicIPAddress
    $publicIP.properties.publicIPAllocationMethod = "Static"

    JSONPost  $script:NetworkControllerRestIP "/publicIPAddresses" $publicIP  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/publicIPAddresses/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCPublicIPAddress
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/publicIPAddresses/$resourceID" -Credential $script:NetworkControllerCred
}

function Remove-NCPublicIPAddress
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/publicIPAddresses/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}

function New-NCGatewayPool
{
    param(
        [Parameter(mandatory=$true)]
        [string] $resourceID,
        [Parameter(mandatory=$true)]
        [string] $Type,
        [Parameter(mandatory=$false)]
        [string] $GreVipSubnetResourceRef,
        [Parameter(mandatory=$false)]
        [string] $PublicIPAddressId,
        [Parameter(mandatory=$false)]
        [System.UInt64] $Capacity = 10000000,
        [Parameter(mandatory=$false)]
        [System.UInt32] $RedundantGatewayCount = 0
    )

    $gwPool = @{}
    $gwPool.resourceID = $resourceID

    $gwPool.properties = @{}
    $gwPool.properties.type = $Type
    $gwPool.properties.ipConfiguration = @{}

    if (-not([String]::IsNullOrEmpty($GreVipSubnetResourceRef)))
    {
        $gwPool.properties.ipConfiguration.greVipSubnets = @()
        $greVipSubnet = @{}
        $greVipSubnet.resourceRef = $GreVipSubnetResourceRef
        $gwPool.properties.ipConfiguration.greVipSubnets += $greVipSubnet
    }

    $publicIPAddresses = @{}
    if (-not([String]::IsNullOrEmpty($PublicIPAddressId)))
    {
        $publicIPAddresses.resourceRef = "/publicIPAddresses/$PublicIPAddressId"
        $gwPool.properties.ipConfiguration.publicIPAddresses = @()
        $gwPool.properties.ipConfiguration.publicIPAddresses += $publicIPAddresses
    }
    $gwPool.properties.redundantGatewayCount = $RedundantGatewayCount
    $gwPool.properties.gatewayCapacityKiloBitsPerSecond = $Capacity

    JSONPost $script:NetworkControllerRestIP "/GatewayPools" $gwPool -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/GatewayPools/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCGatewayPool
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/GatewayPools/$ResourceID" -Credential $script:NetworkControllerCred
}

function Remove-NCGatewayPool
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
    )
    foreach ($ResourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/GatewayPools/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
    }
}

function Get-NCMacPool
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/MacPools/$ResourceID" -Credential $script:NetworkControllerCred
}
function Remove-NCMacPool
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
    )
    foreach ($ResourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/MacPools/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
    }
}
function New-NCGateway
{
    param(
        [Parameter(mandatory=$true)]
        [string] $resourceID,
        [Parameter(mandatory=$true)]
        [string] $GatewayPoolRef,
        [Parameter(mandatory=$true)]
        [string] $Type,
        [Parameter(mandatory=$false)]
        [object] $BgpConfig,
        [Parameter(mandatory=$true)]
        [string] $VirtualServerRef,
        [Parameter(mandatory=$true)]
        [string] $InternalInterfaceRef,
        [Parameter(mandatory=$true)]
        [string] $ExternalInterfaceRef
    )

    $gateway = @{}
    $gateway.resourceID = $resourceID
    $gateway.properties = @{}

    $gateway.properties.pool = @{}
    $gateway.properties.pool.resourceRef = $GatewayPoolRef

    $gateway.properties.type = $Type
    $gateway.properties.bgpConfig = @{}
    $gateway.properties.bgpConfig = $BgpConfig

    $gateway.properties.virtualserver = @{}
    $gateway.properties.virtualserver.resourceRef = $VirtualServerRef

    $gateway.properties.networkInterfaces = @{}
    $gateway.properties.networkInterfaces.externalNetworkInterface = @{}
    $gateway.properties.networkInterfaces.externalNetworkInterface.resourceRef = $ExternalInterfaceRef
    $gateway.properties.networkInterfaces.internalNetworkInterface = @{}
    $gateway.properties.networkInterfaces.internalNetworkInterface.resourceRef = $InternalInterfaceRef

    JSONPost $script:NetworkControllerRestIP "/Gateways" $gateway -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/Gateways/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCGateway
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/Gateways/$resourceID" -Credential $script:NetworkControllerCred
}

function Remove-NCGateway
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/Gateways/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}

function New-NCVpnClientAddressSpace
{
    param(
        [Parameter(mandatory=$true)]
        [string] $TenantName,
        [Parameter(mandatory=$true)]
        [System.UInt64] $VpnCapacity,
        [Parameter(mandatory=$true)]
        [string] $Ipv4AddressPool,
        [Parameter(mandatory=$true)]
        [string] $Ipv6AddressPool
    )

    $vpnClientAddressSpace = @{}
    $vpnClientAddressSpace.AddressPrefixes = @()
    $vpnClientAddressSpace.AddressPrefixes += @($Ipv4AddressPool, $Ipv6AddressPool)
    $vpnClientAddressSpace.Capacity = $VpnCapacity.ToString()
    $vpnClientAddressSpace.Realm = $TenantName

    return $vpnClientAddressSpace
}

function New-NCIPSecTunnel
{
    param(
        [Parameter(mandatory=$true)]
        [string] $ResourceId,
        [Parameter(mandatory=$true)]
        [system.uint64] $OutboundCapacity,
        [Parameter(mandatory=$true)]
        [system.uint64] $InboundCapacity,
        [Parameter(mandatory=$false)]
        [object[]] $IPAddresses,
        [Parameter(mandatory=$false)]
        [string[]] $PeerIPAddresses,
        [Parameter(mandatory=$false)]
        [string] $DestinationIPAddress,
        [Parameter(mandatory=$false)]
        [string] $SharedSecret,
        [Parameter(mandatory=$false)]
        [object[]] $IPv4Subnets
    )

    $AuthenticationMethod = "PSK"

    $ipSecVpn = @{}
    $ipsecVpn.resourceId = $ResourceId
    $ipSecVpn.properties = @{}

    $ipSecVpn.properties.connectionType = "IPSec"
    $ipSecVpn.properties.outboundKiloBitsPerSecond = $outboundCapacity
    $ipSecVpn.properties.inboundKiloBitsPerSecond = $inboundCapacity

    $routes = @()
    foreach ($IPv4Subnet in $IPv4Subnets)
    {
        $route = @{}
        $route.destinationPrefix = $IPv4Subnet.Prefix
        $route.metric = $IPv4Subnet.Metric
        $routes += $route
    }
    $ipSecVpn.properties.routes = @()
    $ipSecVpn.properties.routes = $routes

    $ipSecVpn.properties.ipSecConfiguration = @{}
    $ipSecVpn.properties.ipSecConfiguration.QuickMode = @{}
    $ipSecVpn.properties.ipSecConfiguration.MainMode = @{}

    $ipSecVpn.properties.ipSecConfiguration.authenticationMethod = $AuthenticationMethod
    if ($AuthenticationMethod -eq "PSK")
    { $ipSecVpn.properties.ipSecConfiguration.sharedSecret = $SharedSecret }

    $ipSecVpn.properties.ipSecConfiguration.quickMode.perfectForwardSecrecy                = "PFS2048"
    $ipSecVpn.properties.ipSecConfiguration.quickMode.authenticationTransformationConstant = "SHA256128"
    $ipSecVpn.properties.ipSecConfiguration.quickMode.cipherTransformationConstant         = "DES3"
    $ipSecVpn.properties.ipSecConfiguration.quickMode.saLifeTimeSeconds                    = 1233
    $ipSecVpn.properties.ipSecConfiguration.quickMode.idleDisconnectSeconds                = 500
    $ipSecVpn.properties.ipSecConfiguration.quickMode.saLifeTimeKiloBytes                  = 2000

    $ipSecVpn.properties.ipSecConfiguration.mainMode.diffieHellmanGroup  = "Group2"
    $ipSecVpn.properties.ipSecConfiguration.mainMode.integrityAlgorithm  = "SHA256"
    $ipSecVpn.properties.ipSecConfiguration.mainMode.encryptionAlgorithm = "AES256"
    $ipSecVpn.properties.ipSecConfiguration.mainMode.saLifeTimeSeconds   = 1234
    $ipSecVpn.properties.ipSecConfiguration.mainMode.saLifeTimeKiloBytes = 2000

    if ($IPAddresses -eq $null) {$IPAddresses = @()}
    if ($PeerIPAddresses -eq $null) {$PeerIPAddresses = @()}

    $ipSecVpn.properties.ipAddresses = $IPAddresses
    $ipSecVpn.properties.peerIPAddresses = $PeerIPAddresses
    $ipSecVpn.properties.destinationIPAddress = $DestinationIPAddress

    return $ipSecVpn
}

function New-NCGreTunnel
{
    param(
        [Parameter(mandatory=$true)]
        [string] $ResourceId,
        [Parameter(mandatory=$true)]
        [system.uint64] $OutboundCapacity,
        [Parameter(mandatory=$true)]
        [system.uint64] $InboundCapacity,
        [Parameter(mandatory=$false)]
        [object[]] $IPAddresses,
        [Parameter(mandatory=$false)]
        [string[]] $PeerIPAddresses,
        [Parameter(mandatory=$false)]
        [string] $DestinationIPAddress,
        [Parameter(mandatory=$false)]
        [object[]] $IPv4Subnets,
        [Parameter(mandatory=$false)]
        [string] $GreKey
    )

    $greTunnel = @{}
    $greTunnel.resourceId = $ResourceId
    $greTunnel.properties = @{}

    $greTunnel.properties.connectionType = "GRE"
    $greTunnel.properties.outboundKiloBitsPerSecond = $outboundCapacity
    $greTunnel.properties.inboundKiloBitsPerSecond = $inboundCapacity

    $greTunnel.properties.greConfiguration = @{}
    $greTunnel.properties.greConfiguration.GreKey = $GreKey

    if ($IPAddresses -eq $null) {$IPAddresses = @()}
    if ($PeerIPAddresses -eq $null) {$PeerIPAddresses = @()}

    $greTunnel.properties.ipAddresses = $IPAddresses
    $greTunnel.properties.peerIPAddresses = $PeerIPAddresses

    $routes = @()
    foreach ($IPv4Subnet in $IPv4Subnets)
    {
        $route = @{}
        $route.destinationPrefix = $IPv4Subnet.Prefix
        $route.metric = $IPv4Subnet.Metric
        $routes += $route
    }
    $greTunnel.properties.routes = @()
    $greTunnel.properties.routes = $routes

    $greTunnel.properties.destinationIPAddress = $DestinationIPAddress

    return $greTunnel
}

function New-NCL3Tunnel
{
    param(
        [Parameter(mandatory=$true)]
        [string] $ResourceId,
        [Parameter(mandatory=$true)]
        [system.uint64] $OutboundCapacity,
        [Parameter(mandatory=$true)]
        [system.uint64] $InboundCapacity,
        [Parameter(mandatory=$false)]
        [string] $VlanSubnetResourceRef,
        [Parameter(mandatory=$false)]
        [object[]] $L3IPAddresses,
        [Parameter(mandatory=$false)]
        [System.UInt16] $PrefixLength,
        [Parameter(mandatory=$false)]
        [string[]] $L3PeerIPAddresses,
        [Parameter(mandatory=$false)]
        [object[]] $IPv4Subnets
    )

    $l3Tunnel = @{}
    $l3Tunnel.resourceId = $ResourceId
    $l3Tunnel.properties = @{}

    $l3Tunnel.properties.connectionType = "L3"
    $l3Tunnel.properties.outboundKiloBitsPerSecond = $outboundCapacity
    $l3Tunnel.properties.inboundKiloBitsPerSecond = $inboundCapacity

    $l3Tunnel.properties.l3Configuration = @{}
    $l3Tunnel.properties.l3Configuration.vlanSubnet = @{}
    $l3Tunnel.properties.l3Configuration.vlanSubnet.resourceRef = $VlanSubnetResourceRef

    $l3Tunnel.properties.ipAddresses = @($L3IPAddresses)
    $l3Tunnel.properties.peerIPAddresses = @($L3PeerIPAddresses)

    $routes = @()
    foreach ($IPv4Subnet in $IPv4Subnets)
    {
        $route = @{}
        $route.destinationPrefix = $IPv4Subnet.Prefix
        $route.metric = $IPv4Subnet.Metric
        $routes += $route
    }
    $l3Tunnel.properties.routes = @()
    $l3Tunnel.properties.routes = $routes

    return $l3Tunnel
}

function New-NCBgpRoutingPolicy
{
    param(
        [Parameter(mandatory=$true)]
        [string] $PolicyName,
        [Parameter(mandatory=$true)]
        [string] $PolicyType,
        [Parameter(mandatory=$true)]
        [object[]] $MatchCriteriaList,
        [Parameter(mandatory=$false)]
        [object[]] $Actions,
        [Parameter(mandatory=$false)]
        [string] $EgressPolicyMapResourceRef
    )

    $bgpPolicy = @{}
    $bgpPolicy.policyName = $PolicyName
    $bgpPolicy.policyType = $policyType

    $bgpPolicy.matchCriteria = @()
    $bgpPolicy.setActions = @()

    foreach ($criteria in $MatchCriteriaList)
    {
        $matchCriteria = @{}
        $matchCriteria.clause = $criteria.clause
        $matchCriteria.operator = "And"
        $matchCriteria.value = $criteria.value

        $bgpPolicy.matchCriteria += $matchCriteria
    }

    $bgpPolicy.setActions += @($Actions)

    return $bgpPolicy
}

function New-NCBgpRoutingPolicyMap
{
    param(
        [Parameter(mandatory=$true)]
        [string] $PolicyMapName,
        [Parameter(mandatory=$true)]
        [object[]] $PolicyList
    )

    $bgpPolicyMap = @{}
    $bgpPolicyMap.resourceId = $PolicyMapName
    $bgpPolicyMap.properties = @{}

    $bgpPolicyMap.properties.policyList = @($PolicyList)

    return $bgpPolicyMap
}

function New-NCBgpPeer
{
    param(
        [Parameter(mandatory=$true)]
        [string] $PeerName,
        [Parameter(mandatory=$true)]
        [string] $PeerIP,
        [Parameter(mandatory=$true)]
        [string] $PeerASN,
        [Parameter(mandatory=$false)]
        [string] $IngressPolicyMapResourceRef,
        [Parameter(mandatory=$false)]
        [string] $EgressPolicyMapResourceRef
    )

    $bgpPeer = @{}
    $bgpPeer.resourceId = $PeerName
    $bgpPeer.properties = @{}

    $bgpPeer.properties.peerIPAddress = $PeerIP
    $bgpPeer.properties.peerAsNumber = $PeerASN
    $bgpPeer.properties.ExtAsNumber = "0.$PeerASN"

    $bgpPeer.properties.policyMapIn  = $null
    $bgpPeer.properties.policyMapOut = $null

    if (![string]::IsNullOrEmpty($IngressPolicyMapResourceRef))
    {
        $bgpPeer.properties.policyMapIn  = @{}
        $bgpPeer.properties.policyMapIn.resourceRef = $IngressPolicyMapResourceRef
    }
    if (![string]::IsNullOrEmpty($EgressPolicyMapResourceRef))
    {
        $bgpPeer.properties.policyMapOut = @{}
        $bgpPeer.properties.policyMapOut.resourceRef = $EgressPolicyMapResourceRef
    }

    return $bgpPeer
}

function New-NCBgpRouter
{
    param(
        [Parameter(mandatory=$true)]
        [string] $RouterName,
        [Parameter(mandatory=$true)]
        [string] $LocalASN,
        [Parameter(mandatory=$false)]
        [object[]] $BgpPeers
    )

    $bgpRouter = @{}
    $bgpRouter.resourceId = $RouterName
    $bgpRouter.properties = @{}

    $bgpRouter.properties.isEnabled = "true"
    $bgpRouter.properties.requireIGPSync = "true"
    $bgpRouter.properties.extAsNumber = "0.$LocalASN"
    $bgpRouter.properties.routerIP = @()
    $bgpRouter.properties.bgpNetworks = @()
    $bgpRouter.properties.isGenerated = $false

    $bgpRouter.properties.bgpPeers = @($BgpPeers)

    return $bgpRouter
}

function New-NCVirtualGateway
{
    param(
        [Parameter(mandatory=$true)]
        [string] $resourceID,
        [Parameter(mandatory=$true)]
        [string[]] $GatewayPools,
        [Parameter(mandatory=$true)]
        [string] $vNetIPv4SubnetResourceRef,
        [Parameter(mandatory=$false)]
        [object] $VpnClientAddressSpace,
        [Parameter(mandatory=$false)]
        [object[]] $NetworkConnections,
        [Parameter(mandatory=$false)]
        [object[]] $BgpRouters,
        [Parameter(mandatory=$false)]
        [object[]] $PolicyMaps,
        [Parameter(mandatory=$false)]
        [string] $RoutingType = "Dynamic"
    )

    $virtualGW = @{}
    $virtualGW.resourceID = $resourceID
    $virtualGW.properties = @{}

    $virtualGW.properties.gatewayPools = @()
    foreach ($gatewayPool in $GatewayPools)
    {

        $gwPool = @{}
        $gwPool.resourceRef = "/gatewayPools/$gatewayPool"
        $virtualGW.properties.gatewayPools += $gwPool
    }

    $gatewaySubnetsRef = @{}
    $gatewaySubnetsRef.resourceRef = $vNetIPv4SubnetResourceRef
    $virtualGW.properties.gatewaySubnets = @()
    $virtualGW.properties.gatewaySubnets += $gatewaySubnetsRef

    $virtualGW.properties.vpnClientAddressSpace = @{}
    $virtualGW.properties.vpnClientAddressSpace = $VpnClientAddressSpace

    $virtualGW.properties.networkConnections = @()
    $virtualGW.properties.networkConnections += @($Networkconnections)

    $virtualGW.properties.bgpRouters = @()
    $virtualGW.properties.bgpRouters += $BgpRouters

    $virtualGW.properties.policyMaps = @()
    $virtualGW.properties.policyMaps += $PolicyMaps

    $virtualGW.properties.routingType = $RoutingType

    JSONPost $script:NetworkControllerRestIP "/VirtualGateways" $virtualGW -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/VirtualGateways/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCVirtualGateway
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/VirtualGateways/$ResourceID" -Credential $script:NetworkControllerCred
}

function Remove-NCVirtualGateway
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/VirtualGateways/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}


function Get-NCLearnedIPAddress
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/LearnedIPAddresses/$ResourceID" -Credential $script:NetworkControllerCred
}
function Remove-NCLearnedIPAddress
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
    )
    foreach ($ResourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/LearnedIPAddresses/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
    }
}

function Get-NCConnectivityCheckResult     {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/diagnostics/ConnectivityCheckResults/$resourceID"  -Credential $script:NetworkControllerCred
}
function Get-NCRouteTable      {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/RouteTables/$resourceID"  -Credential $script:NetworkControllerCred
}

function New-NCBackup
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceId=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $backupPath,
        [Parameter(mandatory=$true)]
        [string] $credentialForBackupResourceId
        )

    $credForBackup = Get-NCCredential -resourceId $credentialForBackupResourceId

    $backup = @{}
    $backup.resourceId = $resourceId
    $backup.properties = @{}
    $backup.properties.backupPath = $backupPath
    $backup.properties.credential = $credForBackup.Properties.resourceRef

    $refpath = "/networkControllerBackup"
    JSONPost  $script:NetworkControllerRestIP $refpath $backup  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}
function Get-NCBackup
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/networkcontrollerbackup/$resourceID" -Credential $script:NetworkControllerCred
}
function Remove-NCBackup{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/networkcontrollerbackup/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}

function New-NCRestore
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceId=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $restorePath,
        [Parameter(mandatory=$true)]
        [string] $credentialForRestoreResourceId
        )

    $credForRestore = Get-NCCredential -resourceId $credentialForRestoreResourceId

    $restore = @{}
    $restore.resourceId = $resourceId
    $restore.properties = @{}
    $restore.properties.restorePath = $restorePath
    $restore.properties.credential = $credForRestore.Properties.resourceRef

    $refpath = "/networkcontrollerrestore"
    JSONPost  $script:NetworkControllerRestIP $refpath $restore  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}
function Get-NCRestore
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/networkcontrollerrestore/$resourceID" -Credential $script:NetworkControllerCred
}
function Remove-NCRestore                {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/networkcontrollerrestore/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}

Function PrettyTime()   {
    return "[" + (Get-Date -Format o) + "]"
}
Function Log($msg)   {
    Write-Verbose $( $(PrettyTime) + " " + $msg) -Verbose
}

function GetSubjectName([bool] $UseManagementAddress)   {
    if ($UseManagementAddress -eq $true)
    {
        # When IP Address is specified, we are currently looking just for IPv4 corpnet ip address
        # In the final design, only computer names will be used for subject names
        $corpIPAddresses = get-netIpAddress -AddressFamily IPv4 -PrefixOrigin Dhcp -ErrorAction Ignore
        if ($corpIPAddresses -ne $null -and $corpIPAddresses[0] -ne $null)
        {
            $mesg = [System.String]::Format("Using IP Address {0} for certificate subject name", $corpIPAddresses[0].IPAddress);
            Log $mesg
            return $corpIPAddresses[0].IPAddress
        }
        else
        {
            Log "Unable to find management IP address ";
        }
    }
    
    $hostFqdn = [System.Net.Dns]::GetHostByName(($env:computerName)).HostName;
    $mesg = [System.String]::Format("Using computer name {0} for certificate subject name", $hostFqdn);
    Log $mesg
    return $hostFqdn ;
}
function GenerateSelfSignedCertificate([string] $subjectName)   {
    $cryptographicProviderName = "Microsoft Base Cryptographic Provider v1.0";
    [int] $privateKeyLength = 1024;
    $sslServerOidString = "1.3.6.1.5.5.7.3.1";
    $sslClientOidString = "1.3.6.1.5.5.7.3.2";
    [int] $validityPeriodInYear = 5;

    $name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
    $name.Encode("CN=" + $SubjectName, 0)

    $mesg = [System.String]::Format("Generating certificate with subject Name {0}", $subjectName);
    Log $mesg


    #Generate Key
    $key = new-object -com "X509Enrollment.CX509PrivateKey.1"
    $key.ProviderName = $cryptographicProviderName
    $key.KeySpec = 1 #X509KeySpec.XCN_AT_KEYEXCHANGE
    $key.Length = $privateKeyLength
    $key.MachineContext = 1
    $key.ExportPolicy = 0x2 #X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG
    $key.Create()

    #Configure Eku
    $serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
    $serverauthoid.InitializeFromValue($sslServerOidString)
    $clientauthoid = new-object -com "X509Enrollment.CObjectId.1"
    $clientauthoid.InitializeFromValue($sslClientOidString)
    $ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
    $ekuoids.add($serverauthoid)
    $ekuoids.add($clientauthoid)
    $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
    $ekuext.InitializeEncode($ekuoids)

    # Set the hash algorithm to sha512 instead of the default sha1
    $hashAlgorithmObject = New-Object -ComObject X509Enrollment.CObjectId
    $hashAlgorithmObject.InitializeFromAlgorithmName( $ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, $ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, $AlgorithmFlags.AlgorithmFlagsNone, "SHA512")


    #Request Cert
    $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"

    $cert.InitializeFromPrivateKey(2, $key, "")
    $cert.Subject = $name
    $cert.Issuer = $cert.Subject
    $cert.NotBefore = (get-date).ToUniversalTime()
    $cert.NotAfter = $cert.NotBefore.AddYears($validityPeriodInYear);
    $cert.X509Extensions.Add($ekuext)
    $cert.HashAlgorithm = $hashAlgorithmObject
    $cert.Encode()

    $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
    $enrollment.InitializeFromRequest($cert)
    $certdata = $enrollment.CreateRequest(0)
    $enrollment.InstallResponse(2, $certdata, 0, "")

    Log "Successfully added cert to local machine store";
}
function GivePermissionToNetworkService($targetCert)   {
    $targetCertPrivKey = $targetCert.PrivateKey 
    $privKeyCertFile = Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*"  | where {$_.Name -eq $targetCertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName} 
    $privKeyAcl = Get-Acl $privKeyCertFile
    $permission = "NT AUTHORITY\NETWORK SERVICE","Read","Allow" 
    $accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission 
    $privKeyAcl.AddAccessRule($accessRule) 
    Set-Acl $privKeyCertFile.FullName $privKeyAcl
}
Function AddCertToLocalMachineStore($certFullPath, $storeName, $securePassword)    {
    $rootName = "LocalMachine"

    # create a representation of the certificate file
    $certificate = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
    if($securePassword -eq $null)
    {
        $certificate.import($certFullPath)
    }
    else 
    {
        # https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509keystorageflags(v=vs.110).aspx
        $certificate.import($certFullPath, $securePassword, "MachineKeySet,PersistKeySet")
    }
    
    # import into the store
    $store = new-object System.Security.Cryptography.X509Certificates.X509Store($storeName, $rootName)
    $store.open("MaxAllowed")
    $store.add($certificate)
    $store.close()
}
Function GetSubjectFqdnFromCertificatePath($certFullPath)    {
    # create a representation of the certificate file
    $certificate = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
    $certificate.import($certFullPath)
    return GetSubjectFqdnFromCertificate $certificate ;
}
Function GetSubjectFqdnFromCertificate([System.Security.Cryptography.X509Certificates.X509Certificate2] $certificate)    {
    $mesg = [System.String]::Format("Parsing Subject Name {0} to get Subject Fqdn ", $certificate.Subject)
    Log $mesg
    $subjectFqdn = $certificate.Subject.Split('=')[1] ;
    return $subjectFqdn;
}
function Get-Certs($path){
    $flags = [System.Security.Cryptography.X509Certificates.OpenFlags]"ReadOnly"
    $rootName = [System.Security.Cryptography.X509Certificates.StoreLocation]"LocalMachine"
    $store = New-Object System.Security.Cryptography.X509Certificates.X509Store($path, $rootName)
    $store.Open($flags)
    $certs = $store.Certificates
    $store.Close()
    return $certs
}
function New-ACL
{
    param(
        [Parameter(mandatory=$false)]
        [String] $ResourceId=[System.Guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object[]] $aclRules
    )

    $ar = @()
    foreach ($rule in $aclRules) {
        $ar += New-NCAccessControlListRule -Protocol $rule.Protocol -SourcePortRange $rule.SourcePortRange -DestinationPortRange $rule.DestinationPortRange -sourceAddressPrefix $rule.sourceAddressPrefix -destinationAddressPrefix $rule.destinationAddressPrefix -Action $rule.Action -ACLType $rule.Type -Logging $true -Priority $rule.Priority
    }
    
    $acl1 = New-NCAccessControlList -resourceId $ResourceId -AccessControlListRules $ar
    return $acl1
}

function Get-PortProfileId
{
    param(
        [Parameter(mandatory=$true)]
        [String] $VMName,
        [Parameter(mandatory=$false)]
        [String] $VMNetworkAdapterName=$null,
        [Parameter(mandatory=$false)]
        [String] $ComputerName="localhost"
        )
    write-verbose ("Getting port profile for [$vmname] on [$computername]" )
            
    try 
    {
        $pssession = new-pssession -ComputerName $computername 

        invoke-command -session $pssession -ScriptBlock {
            if ([String]::IsNullOrEmpty($using:VMNetworkAdapterName))
            {
                $vmNics = Get-VMNetworkAdapter -VMName $using:VMName 
            }
            else
            { 
                $vmNics = @(Get-VMNetworkAdapter -VMName $using:VMName -Name $using:VMNetworkAdapterName) 
            }

            $result = @()

            foreach ($vmNic in $vmNics) {
                $currentProfile = Get-VMSwitchExtensionPortFeature -FeatureId "9940cd46-8b06-43bb-b9d5-93d50381fd56" -VMNetworkAdapter $vmNic
                if ( $currentProfile -eq $null)
                {
                    $result += $null
                }        
                else
                {
                    $result += [system.guid]::parse($currentProfile.SettingData.ProfileId).tostring()
                }
            }
            return $result
        }
    }
    catch
    {
        Write-Error "Failed with error: $_" 
    }
    finally
    {
        Remove-PSSession $pssession
    }
}

function get-MacAddress
{
    param(
        [Parameter(mandatory=$true)]
        [String] $VMName,
        [Parameter(mandatory=$false)]
        [String] $VMNetworkAdapterName=$null,
        [Parameter(mandatory=$false)]
        [String] $ComputerName="localhost"
        )
    write-verbose ("Getting mac address for [$vmname] on [$computername]" )
            
    try 
    {
        $pssession = new-pssession -ComputerName $computername 

        invoke-command -session $pssession -ScriptBlock {
            if ([String]::IsNullOrEmpty($using:VMNetworkAdapterName))
            {
                $vmNics = Get-VMNetworkAdapter -VMName $using:VMName 
            }
            else
            { 
                $vmNics = @(Get-VMNetworkAdapter -VMName $using:VMName -Name $using:VMNetworkAdapterName) 
            }

            $result = @()

            foreach ($vmNic in $vmNics) {
                    $result += $VMNic.MacAddress
            }
            return $result
        }
    }
    catch
    {
        Write-Error "Failed with error: $_" 
    }
    finally
    {
        Remove-PSSession $pssession
    }
}

function Add-NetworkAdapterToNetwork
{
    param(
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [String] $VMName,
        [Parameter(mandatory=$false,ParameterSetName="ByVNIC")]
        [String] $VMNetworkAdapterName = $null,
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [String] $ComputerName,
        [Parameter(mandatory=$false,ParameterSetName="ByVNIC")]
        [Parameter(mandatory=$true,ParameterSetName="ByResourceId")]
        [String] $NetworkInterfaceResourceId="",
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [Parameter(mandatory=$true,ParameterSetName="ByResourceId")]
        [Object] $LogicalNetworkResourceId="",
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [Parameter(mandatory=$true,ParameterSetName="ByResourceId")]
        [String] $SubnetAddressPrefix="",
        [Parameter(mandatory=$false,ParameterSetName="ByVNIC")]
        [Parameter(mandatory=$false,ParameterSetName="ByResourceId")]
        [String] $ACLResourceId=$null,
        [Parameter(mandatory=$false,ParameterSetName="ByVNIC")]
        [Parameter(mandatory=$false,ParameterSetName="ByResourceId")]
        [String] $IPAddress=""
    )
    
    if ($psCmdlet.ParameterSetName -eq "ByVNIC") {
        $NetworkInterfaceInstanceId = Get-PortProfileId -vmname $vmname -vmnetworkadaptername $VMNetworkAdapterName -computername $computername
        $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $NetworkInterfaceInstanceId
    }     

    $mac = get-macaddress -vmname $vmname -VMNetworkAdapterName $VMNetworkAdapterName -ComputerName $ComputerName

    if ($mac.count -gt 1) {
        throw "More than one MACaddress found on VM. You must specify VMNetworkAdapterName if more than one network adapter is present on the VM."
    }

    $ln = Get-NCLogicalNetwork -ResourceId $LogicalNetworkResourceId 
    
    foreach ($lnsubnet in $ln.properties.subnets) {
        if ($subnetaddressprefix -eq $lnsubnet.properties.Addressprefix) {
            $subnet = $lnsubnet
        }
    }                
        
    if (([String]::IsNullOrEmpty($NetworkInterfaceResourceId)) -or ($NetworkInterfaceResourceId -eq "") -or ($NetworkInterfaceResourceId -eq [System.Guid]::Empty)) {
        $NetworkInterfaceResourceId = [System.Guid]::NewGuid()
    }
    $nic = get-ncnetworkinterface -resourceID $NetworkInterfaceResourceId

    if ($nic -ne $null -and !$Force) {
        throw "Network interface [$networkinterfaceresourceid] already exists. Use -Force to replace it."
    }

    #TODO: add acl if specified
    if (![String]::IsNullOrEmpty($ACLResourceId)) {
        $acl = Get-NCAccessControlList -resourceID $ACLResourceId
        if ($acl -eq $null) {
            throw "ACL with resource id $aclresourceid was not found on the network controller."
        }
        $nic = New-NCNetworkInterface -resourceId $NetworkInterfaceResourceId -Subnet $subnet -MACAddress $mac -acl $acl -ipaddress $ipaddress
    } else {
        $nic = New-NCNetworkInterface -resourceId $NetworkInterfaceResourceId -Subnet $subnet -MACAddress $mac -ipaddress $ipaddress
    }    
    set-portprofileid -resourceID $nic.instanceid -VMName $vmname -VMNetworkAdapterName $vmnetworkadaptername -computername $computername -Force

    return $nic

    #TODO: add virtual server for topology
}

function Unblock-NetworkAdapter
{
    param(
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [String] $VMName,
        [Parameter(mandatory=$false,ParameterSetName="ByVNIC")]
        [String] $VMNetworkAdapterName = $null,
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [String] $ComputerName
    )
    
    if ($psCmdlet.ParameterSetName -eq "ByVNIC") {
        $NetworkInterfaceInstanceId = Get-PortProfileId $vmname $VMNetworkAdapterName $computername
        $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $NetworkInterfaceInstanceId
    }     

    #if networkadapter exists, remove it
    remove-ncnetworkinterface -resourceid $NetworkInterfaceResourceId

    #remove-ncvirtualserver -resourceid $vsresourceid

    set-portprofileid -resourceID ([guid]::empty) -VMName $vmname -ComputerName $computername -Force
}


function Remove-NetworkAdapterFromNetwork
{
    param(
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [String] $VMName,
        [Parameter(mandatory=$false,ParameterSetName="ByVNIC")]
        [String] $VMNetworkAdapterName = $null,
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [String] $ComputerName,
        [Parameter(mandatory=$false,ParameterSetName="ByVNIC")]
        [Parameter(mandatory=$true,ParameterSetName="ByResourceId")]
        [String] $NetworkInterfaceResourceId=""
    )
    
    if ($psCmdlet.ParameterSetName -eq "ByVNIC") {
        $NetworkInterfaceInstanceId = Get-PortProfileId $vmname $VMNetworkAdapterName $computername
        $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $NetworkInterfaceInstanceId
    }     

    if($NetworkInterfaceResourceId)
    {
        remove-ncnetworkinterface -resourceid $NetworkInterfaceResourceId
    }
    
    $nullguid = $([System.Guid]::Empty)
    set-portprofileid -ResourceID $nullguid -vmname $vmname -VMNetworkAdapterName $VMNetworkAdapterName -ComputerName $computername -force
    #remove-ncvirtualserver -resourceid $vsresourceid
}

function Set-NetworkAdapterACL
{
    param(
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [String] $VMName,
        [Parameter(mandatory=$false,ParameterSetName="ByVNIC")]
        [String] $VMNetworkAdapterName = $null,
        [Parameter(mandatory=$true,ParameterSetName="ByVNIC")]
        [String] $ComputerName,
        [Parameter(mandatory=$true,ParameterSetName="ByResourceId")]
        [String] $NetworkInterfaceResourceId,
        [Parameter(mandatory=$true)]
        [String] $ACLResourceId
    )
    
    if ($psCmdlet.ParameterSetName -eq "ByVNIC") {
        $NetworkInterfaceInstanceId = Get-PortProfileId $vmname $VMNetworkAdapterName $computername
        if ($NetworkInterfaceInstanceId -eq $null) {
            throw "Could not find port profile id. Either $vmname does not exist on $computername, or it does not have a port profile defined which would indicate that it has not been added to the network controller."
        }

        if ($NetworkInterfaceInstanceId -ne [System.Guid]::Empty)
        {
           $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $NetworkInterfaceInstanceId
        }
    }

    $nic = get-ncnetworkinterface -resourceid $NetworkInterfaceResourceId
    
    if ($nic -eq $null) {
        throw "ACL can't be set because a network interface was not found for port profile id $NetworkInterfaceResourceId in the network controller."
    }

    $acl = Get-NCAccessControlList -resourceID $ACLResourceId
    if ($acl -eq $null) {
        throw "ACL with resource id $aclresourceid was not found on the network controller."
    }

    $nic.properties.ipConfigurations[0].properties | add-member -Name "accessControlList" -MemberType NoteProperty -Value @{ resourceRef = $acl.resourceRef }

    JSONPost -path "/NetworkInterfaces" -bodyObject $nic
}

function New-LoadBalancerVIP
{
param(
    [Parameter(mandatory=$false)]
    [Microsoft.HyperV.PowerShell.VirtualMachine[]]$VMPool = $n,
    [Parameter(mandatory=$true)]
    [string]$Vip,
    [Parameter(mandatory=$false)]
    [string]$protocol="TCP",
    [Parameter(mandatory=$true)]
    [int] $frontendPort,
    [Parameter(mandatory=$false)]
    [int] $backendPort=$frontendport,
    [Parameter(mandatory=$false)]
    [Switch] $EnableOutboundNat,
    [parameter(mandatory=$false)]
    [string] $LoadBalancerResourceID=[system.guid]::NewGuid()
)
    $slbm = get-ncloadbalancermanager 

    if ($slbm.properties.vipippools.count -lt 1) {
        throw "New-LoadBalancerVIP requires at least one VIP pool in the NC Load balancer manager."
    }

    $vipPools = $slbm.properties.vipippools
    
    # check if the input VIP is within range of one of the VIP pools
    foreach ($vippool in $vipPools) {
        # IP pool's resourceRef is in this format:
        # /logicalnetworks/f8f67956-3906-4303-94c5-09cf91e7e311/subnets/aaf28340-30fe-4f27-8be4-40eca97b052d/ipPools/ed48962b-2789-41bf-aa7b-3e6d5b247384
        $sp = $vippool.resourceRef.split("/")
        
        $ln = Get-NCLogicalNetwork -resourceId $sp[2] #LN resourceid is always the first ID (after /logicalnetwork/)
        if (-not $ln) {
            throw "Can't find logical network with resourceId $($sp[2]) from NC."
        }

        $subnet = $ln.properties.subnets | ? {$_.resourceId -eq $sp[4]}
        if (-not $subnet) {
            throw "can't find subnet with resourceId $($sp[4]) from NC."
        }
        
        $pool = $subnet.properties.ipPools | ? {$_.resourceId -eq $sp[6]}
        if (-not $pool) {
            throw "can't find IP pool with resourceId $($sp[6]) from NC."
        }
        
        $startIp = $pool.properties.startIpAddress
        $endIp = $pool.properties.endIpAddress
        if (IsIpWithinPoolRange -targetIp $Vip -startIp $startIp -endIp $endIp) {
            $isPoolPublic = $subnet.properties.isPublic
            $vipLn = $ln
            break;
        }
    }
    
    if (-not $vipLn) {
        throw "$Vip is not within range of any of the VIP pools managed by SLB manager."
    }
    
    # if the VIP is within the range of a pool whose subnet is public, we should create a PublicIPAddress in NC for the VIP
    # so that NC won't accidentially allocate same VIP for tenant use
    if ($isPoolPublic) {
        $publicIp = Get-NCPublicIPAddress | ? {$_.properties.ipaddress -eq $Vip}
        if ($publicIp -eq $null) {
            New-NCPublicIPAddress -PublicIPAddress $Vip
        }
    }
         
    $lbfe = @(New-NCLoadBalancerFrontEndIPConfiguration -PrivateIPAddress $Vip -Subnet ($vipLn.properties.Subnets[0]))
    
    $ips = @()  
    foreach ($VM in $VMPool) {
      $vm_name = $VM.Name
      $vm_computer = $VM.ComputerName
      $vm_nic = $VM.NetworkAdapters[0].Name
      $instanceid = Get-PortProfileId -VMName $vm_name -VMNetworkAdapterName $vm_nic -ComputerName $vm_computer

      #convert port profile id to from instance id to resource id
      $ppid = $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $instanceid
      
      $vnic = get-ncnetworkinterface -resourceId $ppid
      $ips += $vnic.properties.ipConfigurations[0]
    } 

    $lbbe = @(New-NCLoadBalancerBackendAddressPool -IPConfigurations $ips)
    $rules = @(New-NCLoadBalancerLoadBalancingRule -protocol $protocol -frontendPort $frontendPort -backendport $backendPort -enableFloatingIP $False -frontEndIPConfigurations $lbfe -backendAddressPool $lbbe)

    if ($EnableOutboundNat) {
        $onats = @(New-NCLoadBalancerOutboundNatRule -frontendipconfigurations $lbfe -backendaddresspool $lbbe)
        $lb = New-NCLoadBalancer -ResourceID $LoadBalancerResourceID -frontendipconfigurations $lbfe -backendaddresspools $lbbe -loadbalancingrules $rules -outboundnatrules $onats
    } else {
        $lb = New-NCLoadBalancer -ResourceID $LoadBalancerResourceID -frontendipconfigurations $lbfe -backendaddresspools $lbbe -loadbalancingrules $rules
    }
    return $lb
}


#region some IPv4 address related helper functions

function Convert-IPv4StringToInt {
    param([string] $addr)

    $ip = $null
    $valid = [System.Net.IPAddress]::TryParse($addr, [ref]$ip)
    if (!$valid -or $ip.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork) {
        throw "$addr is not a valid IPv4 address."
    }

    $sp = $addr.Split(".", 4)
    $bits = [System.Convert]::ToInt64($sp[0])
    $bits = $bits -shl 8
    $bits += [System.Convert]::ToInt64($sp[1])
    $bits = $bits -shl 8
    $bits += [System.Convert]::ToInt64($sp[2])
    $bits = $bits -shl 8
    $bits += [System.Convert]::ToInt64($sp[3])

    $bits
}

function Convert-IPv4IntToString {
    param([Int64] $addr)

    "{0}.{1}.{2}.{3}" -f (($addr -shr 24) -band 0xff), (($addr -shr 16) -band 0xff), (($addr -shr 8) -band 0xff), ($addr -band 0xff )

}

#endregion

#region Invoke command wrapper

#endregion

#region Private JSON helper functions

function Invoke-WebRequestWithRetries {
    param(
        [System.Collections.IDictionary] $Headers,
        [string] $ContentType,
        [Microsoft.PowerShell.Commands.WebRequestMethod] $Method,
        [System.Uri] $Uri,
        [object] $Body,
        [Switch] $DisableKeepAlive,
        [Switch] $UseBasicParsing,
        [System.Management.Automation.PSCredential] $Credential,
        [System.Management.Automation.Runspaces.PSSession] $RemoteSession,
        [Parameter(mandatory=$false)]
        [bool] $shouldRetry = $false
    )

    $params = @{
        'Headers'=$headers;
        'ContentType'=$content;
        'Method'=$method;
        'uri'=$uri
        }

    if($Body -ne $null) {
        $params.Add('Body', $Body)
    }
    if($DisableKeepAlive.IsPresent) {
        $params.Add('DisableKeepAlive', $true)
    }
    if($UseBasicParsing.IsPresent) {
        $params.Add('UseBasicParsing', $true)
    }
    if($Credential -ne [System.Management.Automation.PSCredential]::Empty -and $Credential -ne $null) {
        $params.Add('Credential', $Credential)
    }

    $retryIntervalInSeconds = 30
    $maxRetry = 6
    $retryCounter = 0

    do {
        try {
            if($RemoteSession -eq $null) {
                $result = Invoke-WebRequest @params
            }
            else {
                $result = Invoke-Command -Session $RemoteSession -ScriptBlock {
                    Invoke-WebRequest @using:params
                }
            }
            break
        }
        catch {
            Write-Verbose "Invoke-WebRequestWithRetries: $($Method) Exception: $_"
            Write-Verbose "Invoke-WebRequestWithRetries: $($Method) Exception: $($_.Exception.Response)"

            if ($_.Exception.Response.statuscode -eq "NotFound") {
                    return $null
            }

            $retryCounter++
            if($shouldRetry -and $retryCounter -le $maxRetry) {

                Write-verbose "Invoke-WebRequestWithRetries: retry this operation in $($retryIntervalInSeconds) seconds. Retry count: $($retryCounter)."
                sleep -Seconds $retryIntervalInSeconds
            }
            else {
                # last retry still fails, so throw the exception
                throw $_
            }
        }
    } while ($shouldRetry -and ($retryCounter -le $maxRetry))

    return $result
}

function JSONPost {
    param(
        [Parameter(position=0,mandatory=$true,ParameterSetName="WithCreds")]
        [String] $NetworkControllerRestIP=$script:NetworkControllerRestIP,
        [Parameter(position=1,mandatory=$true,ParameterSetName="WithCreds")]
        [Parameter(position=0,mandatory=$true,ParameterSetName="CachedCreds")]
        [String] $path,  #starts with object, does not include server, i.e. "/Credentials"
        [Parameter(position=2,mandatory=$true,ParameterSetName="WithCreds")]
        [Parameter(position=1,mandatory=$true,ParameterSetName="CachedCreds")]
        [Object] $bodyObject,
        [Parameter(position=3,mandatory=$true,ParameterSetName="WithCreds")]
        [Object] $credential=$script:NetworkControllerCred,
        [Parameter(position=4,mandatory=$false,ParameterSetName="WithCreds")]
        [String] $computerName=$null
    )

    if ($NetworkControllerRestIP -eq "")
    {
        write-error "Network controller REST IP not specified. You must first call Set-NCConnection."
        return
    }

    $headers = @{"Accept"="application/json"}
    $content = "application/json; charset=UTF-8"
    $uriRoot = "$($script:urlroot)$NetworkControllerRestIP/Networking/$($Global:NCApiVersion)"
    $timeout = 10

    $method = "Put"
    $uri = "$uriRoot$path/$($bodyObject.resourceId)"
    $body = convertto-json $bodyObject -Depth 100
    $pssession = $null

    Write-Verbose "JSON Put [$path]"
    if ($path -notlike '/Credentials*') {
        Write-Verbose "Payload follows:"
        Write-Verbose $body
    }

    try {
        # $computerName is here to workaround product limitation for PUT of LoadBalancer, which is > 35KB and must be done from the REST hosting NC Vm.
        if (-not $computerName) {
            if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) {
                Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing | out-null
            } else {
                Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing -Credential $credential | out-null
            }
        }
        else {
            $pssession = new-pssession -ComputerName $computerName -Credential $credential
            Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing -Credential $credential -RemoteSession $pssession | out-null
        }
    }
    catch {
       Write-Verbose "PUT Exception: $_"
       Write-Verbose "PUT Exception: $($_.Exception.Response)"
       throw
    }
    finally {
        if($pssession -ne $null)
        {
            Remove-PSSession $pssession
        }
    }
}

function JSONGet {
    param(
        [Parameter(mandatory=$true)]
        [String] $NetworkControllerRestIP,
        [Parameter(mandatory=$true)]
        [String] $path,  #starts with object and may include resourceid, does not include server, i.e. "/Credentials" or "/Credentials/{1234-
        [Parameter(mandatory=$false)]
        [Switch] $WaitForUpdate,
        [Switch] $Silent,
        [PSCredential] $credential
    )

    if ($NetworkControllerRestIP -eq "")
    {
        write-error "Network controller REST IP not specified. You must first call Set-NCConnection."
        return
    }

    $headers = @{"Accept"="application/json"}
    $content = "application/json; charset=UTF-8"
    $uriRoot = "$($script:urlroot)$NetworkControllerRestIP/Networking/$($Global:NCApiVersion)"

    $method = "Get"
    $uri = "$uriRoot$path"

    if (!$Silent) {
        Write-Verbose "JSON Get [$path]"
    }

    try {
        $NotFinished = $true
        do {
            if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) {
                $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing
            } else {
                $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing -Credential $credential
            }

            if($result -eq $null) {
                return $null
            }

            #Write-Verbose "JSON Result: $result"
            $toplevel = convertfrom-json $result.Content
            if ($toplevel.value -eq $null)
            {
                    $obj = $toplevel
            } else {
                    $obj = $toplevel.value
            }

            if ($WaitForUpdate.IsPresent) {
                    if ($obj.properties.provisioningState -eq "Updating")
   {
                        Write-Verbose "JSONGet: the object's provisioningState is Updating. Wait 1 second and check again."
                        sleep 1 #then retry
                    }
                    else
   {
                        $NotFinished = $false
                    }
            }
            else
            {
                $notFinished = $false
            }
      } while ($NotFinished)

      if ($obj.properties.provisioningState -eq "Failed") {
         write-error ("Provisioning failed: {0}`nReturned Object: {1}`nObject properties: {2}" -f $uri, $obj, $obj.properties)
      }
      return $obj
    }
    catch
    {
        if (!$Silent)
        {
           Write-Verbose "GET Exception: $_"
           Write-Verbose "GET Exception: $($_.Exception.Response)"
        }
        return $null
    }
}

function JSONDelete {
    param(
        [String] $NetworkControllerRestIP,
        [String] $path,
        [Parameter(mandatory=$false)]
        [Switch] $WaitForUpdate,
        [PSCredential] $credential
    )
    if ($NetworkControllerRestIP -eq "")
    {
        write-error "Network controller REST IP not specified. You must first call Set-NCConnection."
        return
    }

    $headers = @{"Accept"="application/json"}
    $content = "application/json; charset=UTF-8"
    $uriRoot = "$($script:urlroot)$NetworkControllerRestIP/Networking/v1"

    $method = "Delete"
    $uri = "$uriRoot$path"

    Write-Verbose "JSON Delete [$path]"
    try {
        if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) {
            Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing
        } else {
            Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing -Credential $credential
        }
    }
    catch {
        Write-Verbose "PUT Exception: $_"
        Write-Verbose "PUT Exception: $($_.Exception.Response)"
        throw
    }

    $maxRecheck = 100
    $currentCheck = 0
    if ($WaitForUpdate.IsPresent) {
        try {
            $NotFinished = $true
            do {
                if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) {
                        $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method "GET" -Uri $uri -DisableKeepAlive -UseBasicParsing
                }
                else {
                        $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method "GET" -Uri $uri -DisableKeepAlive -UseBasicParsing -Credential $credential
                }

                if($result -ne $null) {
                    Write-Verbose "Object still exists, check again in 1 second"
                    sleep 1 #then retry
                    $currentCheck++
                }
                else {
                    break
                }
            } while ($currentCheck -lt $maxRecheck)
        }
        catch {
            if ($_.Exception.Response.statuscode -eq "NotFound") {
                return
            }
            Write-Verbose "GET Exception: $_"
            Write-Verbose "GET Exception: $($_.Exception.Response)"
            throw
        }
    }
}

#endregion

function Get-NCNetworkInterfaceResourceId
{
    param(
        [Parameter(mandatory=$true)]
        [String] $InstanceId
        )
    if (([String]::IsNullOrEmpty($InstanceId)) -or ($InstanceId -eq "") -or ($InstanceId -eq [System.Guid]::Empty)) {
        write-verbose ("Instance id ($InstanceId) either null or empty string or empty guid")
        return $InstanceId
    }

    write-verbose ("Searching resourceId for instance id [$InstanceId]." )

    try
    {
        $interfaces = JSONGet $script:NetworkControllerRestIP "/networkinterfaces" -Credential $script:NetworkControllerCred

        if ($interfaces -ne $null)
        {
            foreach ($interface in $interfaces)
            {
                if ($interface.instanceId -eq $InstanceId)
                {
                    return $interface.resourceId
                }
            }
        }
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }

    return $null
}

function Get-NCNetworkInterfaceInstanceId
{
    param(
        [Parameter(mandatory=$true)]
        [String] $ResourceId
        )
    if (([String]::IsNullOrEmpty($ResourceId)) -or ($ResourceId -eq "") -or ($ResourceId -eq [System.Guid]::Empty)) {
        write-verbose ("Resource id ($ResourceId) either null or empty string or empty guid")
        return $ResourceId
    }

    write-verbose ("Searching Instance Id for Resource Id [$ResourceId]." )

    try
    {
        $interfaces = JSONGet $script:NetworkControllerRestIP "/networkinterfaces" -Credential $script:NetworkControllerCred

        if ($interfaces -ne $null)
        {
            foreach ($interface in $interfaces)
            {
                if ($interface.resourceId -eq $ResourceId)
                {
                    return $interface.instanceId
                }
            }
        }
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }

    return $null
}

function Set-NCConnection
{
    param(
        [Parameter(position=0,mandatory=$true,ParameterSetName="Credential")]
        [Parameter(position=0,mandatory=$true,ParameterSetName="NoCreds")]
        [string] $RestIP,
        [Parameter(mandatory=$true,ParameterSetName="Credential")]
        [PSCredential] $Credential=[System.Management.Automation.PSCredential]::Empty
        )

    $script:NetworkControllerRestIP = $RestIP
    $script:NetworkControllerCred = $Credential
}

function New-NCLogicalNetwork        {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$false)]
        [object[]] $LogicalNetworkSubnets=$null,
        [Switch] $EnableNetworkVirtualization
    )

    $LogicalNetwork = @{}
    $LogicalNetwork.resourceId = $resourceId
    $logicalNetwork.properties = @{}

    if ($LogicalNetworkSubnets -eq $null)
    {
        $logicalNetwork.properties.subnets = @()
    }
    else
    {
        $logicalNetwork.properties.subnets = $LogicalNetworkSubnets
    }

    if ($EnableNetworkVirtualization.ispresent) {
        $logicalNetwork.properties.networkVirtualizationEnabled = "True"
    } else {
        $logicalNetwork.properties.networkVirtualizationEnabled = "False"
    }
    JSONPost  $script:NetworkControllerRestIP "/logicalnetworks" $logicalnetwork -Credential $script:NetworkControllerCred  | out-null
    return JSONGet $script:NetworkControllerRestIP "/logicalnetworks/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred


}
function Get-NCLogicalNetwork        {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=""
     )

     return JSONGet $script:NetworkControllerRestIP "/logicalnetworks/$ResourceId" -Credential $script:NetworkControllerCred
}
function Remove-NCLogicalNetwork     {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/logicalnetworks/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function Get-NCLogicalNetworkSubnet       {
    param(
        [Parameter(mandatory=$true)]
        [object] $LogicalNetwork,
        [Parameter(mandatory=$false)]
        [string] $ResourceID=""
     )

     if ($resourceId -eq "") {
        $uri = "/logicalnetworks/$($LogicalNetwork.ResourceId)/subnets"
    } else {
        $uri = "/logicalnetworks/$($LogicalNetwork.ResourceId)/subnets/$ResourceId"
    }

     return JSONGet $script:NetworkControllerRestIP $uri -Credential $script:NetworkControllerCred
}

function New-NCLogicalNetworkSubnet  {
#Creates an in-memory object only. Must pass it into New-NCLogicalNetwork to persist it.
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $AddressPrefix,
        [Parameter(mandatory=$false)]
        [string[]] $DNSServers = @(),
        [Parameter(mandatory=$false)]
        [int] $VLANid = 0,
        [Parameter(mandatory=$true)]
        [string[]] $defaultGateway,
        [Switch] $IsPublic
        )
    $subnet = @{}
    $subnet.resourceId = $ResourceID
    $subnet.properties = @{}
    $subnet.properties.addressPrefix = $AddressPrefix
    $subnet.properties.vlanid = "$vlanid"
    $subnet.properties.dnsServers = $dnsServers
    $subnet.properties.defaultGateways = $defaultGateway
    $subnet.properties.IsPublic = $IsPublic.IsPresent

    return $subnet
}

function New-NCCredential            {
    param(
        [Parameter(mandatory=$false,parametersetname='username')]
        [Parameter(mandatory=$false,parametersetname='cert')]
        [Parameter(mandatory=$false,parametersetname='snmp')]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true,parametersetname='username')]
        [string] $Username=$null,
        [Parameter(mandatory=$true,parametersetname='username')]
        [String] $password=$null,
        [Parameter(mandatory=$true,parametersetname='snmp')]
        [String] $communitystring=$null,
        [Parameter(mandatory=$true,parametersetname='cert')]
        [string] $Thumbprint
    )

    # create credentials that will be used to talk to host

    $creds = @{}
    $creds.resourceID = $resourceID
    $creds.properties = @{}
    if ($pscmdlet.ParameterSetName -eq 'cert') {
        $creds.properties.Type = "X509Certificate"
        $creds.properties.Value = $thumbprint
    }
    elseif ($pscmdlet.ParameterSetName -eq 'username') {
        $creds.properties.Type = "UsernamePassword"
        $creds.properties.Username = $Username
        $creds.properties.Value = $password
    }
    else {
        $creds.properties.Type = "SnmpCommunityString"
        $creds.properties.Value = $communitystring
    }

    JSONPost $script:NetworkControllerRestIP "/Credentials" $creds  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/Credentials/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCCredential            {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/Credentials/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCCredential         {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/Credentials/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCServerConnection      {
    #Creates an in-memory object only. Must pass it into New-NCServer to persist it.
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ComputerNames,
        [Parameter(mandatory=$true)]
        [object] $Credential
    )

    $connection = @{}
    $connection.managementAddresses = $ComputerNames
    $connection.credential = @{}
    $connection.credential.resourceRef = "/credentials/$($credential.ResourceID)"
    $connection.credentialType = $credential.properties.Type

    return $connection
}

function New-NCServerNetworkInterface{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$false)]
        [boolean] $IsBMC=$false,
        [Parameter(mandatory=$true,ParameterSetName="LogicalSubnet")]
        [object[]] $LogicalNetworkSubnets
    )

    $networkInterface = @{}
    $networkInterface.resourceId = $ResourceID
    $networkInterface.instanceId = $ResourceID
    $networkInterface.properties = @{}
    $networkInterface.properties.isBMC = $IsBMC

    $networkInterface.properties.logicalSubnets = @()
    foreach ($logicalnetworksubnet in $logicalNetworkSubnets) {
        $logicalSubnetref = @{}
        $logicalSubnetref.resourceRef = $logicalnetworksubnet.resourceRef
        $networkInterface.properties.logicalSubnets += $logicalSubnetref
    }

    return $networkInterface
}
function New-NCServer                {
#Must pass in ResourceID since it must match id of virtual switch
    param(
        [Parameter(mandatory=$true)]
        [string] $ResourceID,
        [Parameter(mandatory=$true)]
        [object[]] $Connections,
        [Parameter(mandatory=$false)]
        [string] $Certificate = $null,
        [Parameter(mandatory=$true)]
        [object[]] $PhysicalNetworkInterfaces

    )

    $server = @{}
    $server.resourceId = $ResourceID
    $server.instanceId = $ResourceID
    $server.properties = @{}

    $server.properties.connections = $Connections
    $server.properties.networkInterfaces = $PhysicalNetworkInterfaces
    if ($certificate -ne $null) {
        $server.properties.certificate = $certificate
    }

    JSONPost  $script:NetworkControllerRestIP "/Servers" $server  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/Servers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCServer                {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/Servers/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCServer             {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/Servers/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCMACPool               {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $StartMACAddress,
        [Parameter(mandatory=$true)]
        [string] $EndMACAddress
        )

    $macpool = @{}
    $macpool.resourceId = $ResourceId
    $macpool.properties = @{}
    $macpool.properties.startMacAddress = $StartMACAddress
    $macpool.properties.endMacAddress = $EndMACAddress

    JSONPost  $script:NetworkControllerRestIP "/MacPools" $macPool  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/MacPools/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCMACPool               {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/MacPools/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCMACPool            {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/MacPools/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}
function Remove-SLBState {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
}

function New-NCIPPool                {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object] $LogicalNetworkSubnet,
        [Parameter(mandatory=$true)]
        [string] $StartIPAddress,
        [Parameter(mandatory=$true)]
        [string] $EndIPAddress,
        [Parameter(mandatory=$true)]
        [string[]] $DNSServers,
        [Parameter(mandatory=$true)]
        [string[]] $DefaultGateways
        )

    #todo: prevalidate that ip addresses and default gateway are within subnet

    $ippool = @{}
    $ippool.resourceId = $ResourceId
    $ippool.properties = @{}
    $ippool.properties.startIpAddress = $StartIPAddress
    $ippool.properties.endIpAddress = $EndIPAddress
    $ippool.properties.dnsServers = $DNSServers
    $ippool.properties.defaultGateways = $DefaultGateways

    $refpath = "$($logicalnetworksubnet.resourceRef)/ippools"
    JSONPost  $script:NetworkControllerRestIP $refpath $ippool  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCIPPool               {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = "",
        [Parameter(mandatory=$true)]
        [object] $LogicalNetworkSubnet
    )
    $refpath = "$($logicalnetworksubnet.resourceRef)/ippools"
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCIPPool            {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs,
        [Parameter(mandatory=$true)]
        [object] $LogicalNetworkSubnet
     )
    $refpath = "$($logicalnetworksubnet.resourceRef)/ippools"
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "$refpath/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}
function New-NCAccessControlListRule {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $Protocol,
        [Parameter(mandatory=$true)]
        [string] $SourcePortRange,
        [Parameter(mandatory=$true)]
        [string] $DestinationPortRange,
        [Parameter(mandatory=$true)]
        [string] $SourceAddressPrefix,
        [Parameter(mandatory=$true)]
        [string] $DestinationAddressPrefix,
        [Parameter(mandatory=$true)]
        [string] $Action,
        [Parameter(mandatory=$true)]
        [string] $ACLType,
        [Parameter(mandatory=$true)]
        [boolean] $Logging,
        [Parameter(mandatory=$true)]
        [int] $Priority
        )

    $aclRule = @{}
    $aclRule.resourceId = $resourceId

    $aclRule.properties = @{}
    $aclRule.properties.protocol = $protocol
    $aclRule.properties.sourcePortRange = $SourcePortRange
    $aclRule.properties.destinationPortRange = $Destinationportrange
    $aclRule.properties.sourceAddressPrefix = $SourceAddressPrefix
    $aclRule.properties.destinationAddressPrefix = $destinationAddressprefix
    $aclRule.properties.action = $action
    $aclRule.properties.type = $ACLType
    if ($logging) {
        $aclRule.properties.logging = "Enabled"
    } else {
        $aclRule.properties.logging = "Disabled"
    }
    $aclRule.properties.priority = "$priority"

    return $aclRule
}
function New-NCAccessControlList     {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object[]] $AccessControlListRules
        )

    $acls = @{}
    $acls.resourceID = $resourceId
    $acls.properties = @{}
    $acls.properties.aclRules = $AccessControlListRules

    $acls.properties.ipConfigurations = @()
    $acls.properties.subnet = @()

    $refpath = "/accessControlLists"
    JSONPost  $script:NetworkControllerRestIP $refpath $acls  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCAccessControlList     {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/accessControlLists/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCAccessControlList  {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/accessControlLists/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}

function New-NCVirtualSubnet         {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $addressPrefix,
        [Parameter(mandatory=$true)]
        [object] $AccessControlList
        )

    $subnet = @{}
    $subnet.resourceId = $ResourceId
    $subnet.properties = @{}
    $subnet.properties.addressPrefix = $AddressPrefix

    $subnet.properties.accessControlList = @{}
    $subnet.properties.accessControlList.resourceRef = $AccessControlList.resourceRef

    $subnet.properties.ipConfigurations = @()

    return $subnet
}

function Get-NCVirtualSubnet       {
    param(
        [Parameter(mandatory=$true)]
        [object] $VirtualNetwork,
        [Parameter(mandatory=$false)]
        [string] $ResourceID=""
     )

     if ($resourceId -eq "") {
        $uri = "/VirtualNetworks/$($VirtualNetwork.ResourceId)/subnets"
    } else {
        $uri = "/VirtualNetworks/$($VirtualNetwork.ResourceId)/subnets/$ResourceId"
    }

     return JSONGet $script:NetworkControllerRestIP $uri -Credential $script:NetworkControllerCred
}

function New-NCVirtualNetwork        {
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string[]] $addressPrefixes,
        [Parameter(mandatory=$true)]
        [object] $LogicalNetwork,
        [Parameter(mandatory=$true)]
        [object[]] $VirtualSubnets
        )

    $vnet = @{}
    $vnet.resourceId = $resourceId
    $vnet.properties = @{}
    $vnet.properties.addressSpace = @{}
    $vnet.properties.addressSpace.addressPrefixes = $AddressPrefixes
    $vnet.properties.logicalnetwork = @{}
    $vnet.properties.logicalnetwork.resourceRef = "/logicalnetworks/$($LogicalNetwork.resourceId)"
    $vnet.properties.subnets = $VirtualSubnets

    $refpath = "/virtualnetworks"
    JSONPost  $script:NetworkControllerRestIP $refpath $vnet  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}
function Get-NCVirtualNetwork        {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/VirtualNetworks/$resourceID" -Credential $script:NetworkControllerCred
}
function Remove-NCVirtualNetwork     {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/VirtualNetworks/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}

function Set-NCLoadBalancerManager   {
    param(
        [Parameter(mandatory=$false)]
        [Object[]] $VIPIPPools=$null,
        [Parameter(mandatory=$false)]
        [String[]] $OutboundNatIPExemptions=$null,
        [Parameter(mandatory=$true)]
        [String] $IPAddress

)

    $LBM = @{}
    $lbm.resourceId = "config"
    $lbm.properties = @{}
    $lbm.properties.loadbalancermanageripaddress = $IPAddress

    if ($VIPIPPools -ne $NULL) {
        $lbm.properties.vipIpPools = @()

        foreach ($ippool in $VIPIPPools) {
            $poolRef = @{}
            $poolRef.resourceRef = $ippool.resourceRef
            $lbm.properties.vipIpPools += $poolRef
        }
    }

    if ($OutboundNatIPExemptions -ne $null) {
        $lbm.properties.OutboundNatIPExemptions = $OutboundNatIPExemptions
    }

    JSONPost  $script:NetworkControllerRestIP "/loadbalancermanager" $lbm   -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/loadbalancermanager/config" -WaitForUpdate -Credential $script:NetworkControllerCred


}
function Get-NCLoadbalancerManager   {

     return JSONGet $script:NetworkControllerRestIP "/LoadBalancerManager/Config"  -Credential $script:NetworkControllerCred
}

function New-NCVirtualServer         {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object[]] $Connections,
        [Parameter(mandatory=$false)]
        [string] $Certificate,
        [Parameter(mandatory=$true)]
        [string] $vmGuid
    )

    $server = @{}
    $server.resourceId = $ResourceID
    if ($ResourceID.Length -lt 36)
    { $server.instanceId = [system.guid]::NewGuid() }
    else
    { $server.instanceId = $ResourceID }
    $server.properties = @{}

    $server.properties.connections = $Connections
    if (![string]::IsNullOrEmpty($Certificate))
    {
        $server.properties.certificate = $certificate
    }
    $server.properties.vmGuid = $vmGuid

    JSONPost  $script:NetworkControllerRestIP "/VirtualServers" $server  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/VirtualServers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}
function Get-NCVirtualServer         {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/VirtualServers/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCVirtualServer      {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/VirtualServers/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCLoadBalancerMuxPeerRouterConfiguration {
    param(
        [Parameter(mandatory=$true)]
        [string] $RouterName,
        [Parameter(mandatory=$true)]
        [string] $RouterIPAddress,
        [Parameter(mandatory=$true)]
        [int] $PeerASN,
        [Parameter(mandatory=$false)]
        [string] $LocalIPAddress
        )

    $peer = @{}
    $peer.routerName = $RouterName
    $peer.routerIPAddress = $RouterIPAddress
    $peer.PeerASN = "$PeerASN"
    $peer.localIPAddress = $LocalIPAddress

    return $peer
}
function New-NCLoadBalancerMux       {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [int] $LocalASN,
        [Parameter(mandatory=$false)]
        [object[]] $peerRouterConfigurations,
        [Parameter(mandatory=$true)]
        [object] $VirtualServer,
        [Parameter(mandatory=$false)]
        [object[]] $connections

    )

    # create credentials that will be used to talk to host

    $mux = @{}
    $mux.resourceID = $resourceID
    $mux.properties = @{}
    $mux.properties.routerConfiguration = @{}
    $mux.properties.routerConfiguration.localASN = "$LocalASN"
    $mux.properties.routerConfiguration.peerRouterConfigurations = @()
    foreach ($peerRouterConfiguration in $peerRouterConfigurations)
    {
        $mux.properties.routerConfiguration.peerRouterConfigurations += $peerRouterConfiguration
    }
    $mux.properties.virtualServer = @{}
    $mux.properties.virtualServer.resourceRef = $VirtualServer.resourceRef

    JSONPost $script:NetworkControllerRestIP "/LoadBalancerMuxes" $mux  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/LoadBalancerMuxes/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCLoadBalancerMux       {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/LoadBalancerMuxes/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCLoadBalancerMux    {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/LoadBalancerMuxes/$ResourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCLoadBalancerFrontEndIPConfiguration    {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        #[Parameter(mandatory=$true)]
        #[object] $LoadBalancer,
        [Parameter(mandatory=$true)]
        [string] $PrivateIPAddress,
        #[Parameter(mandatory=$true)]
        #[object[]] $LoadBalancingRules,
        [Parameter(mandatory=$true)]
        [object] $Subnet
        )

    $frontend= @{}
    $frontend.resourceID = $resourceID
    $frontend.properties = @{}
    $frontend.properties.privateIPAddress = $PrivateIPAddress
    $frontend.properties.privateIPAllocationMethod = "Static"
    $frontend.properties.Subnet = @{}
    $frontend.properties.Subnet.resourceRef = $subnet.resourceRef

    return $frontend
}

function New-NCLoadBalancerBackendAddressPool         {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid()
        )

    $be= @{}
    $be.resourceID = $resourceID
    $be.properties = @{}

    $be.properties.backendIPConfigurations = @()
    return $be
}
function New-NCLoadBalancerLoadBalancingRule          {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $protocol,
        [Parameter(mandatory=$true)]
        [int] $frontendPort,
        [Parameter(mandatory=$true)]
        [int] $backendPort,
        [Parameter(mandatory=$true)]
        [boolean] $enableFloatingIP,
        [Parameter(mandatory=$false)]
        [int] $IdleTimeoutInMinutes = 4,
        [Parameter(mandatory=$false)]
        [String] $LoadDistribution = "Default",
        [Parameter(mandatory=$true)]
        [object[]] $frontEndIPConfigurations = $null,
        [Parameter(mandatory=$true)]
        [object] $backendAddressPool
        )

    $rule= @{}
    $rule.resourceID = $resourceID
    $rule.properties = @{}
    $rule.properties.protocol = $protocol
    $rule.properties.frontEndPort = "$frontendPort"
    $rule.properties.backendPort = "$backendPort"

    if ($enableFloatingIP) {
        $rule.properties.enableFloatingIP = "true"
    } else {
        $rule.properties.enableFloatingIP = "false"
    }
    $rule.properties.idleTimeoutInMinutes = "$idleTImeoutInMinutes"
    $rule.properties.loadDistribution = $LoadDistribution

    $rule.properties.frontendIPConfigurations = @()

    foreach ($vip in $frontendipconfigurations) {
        $newvip = @{}
        $newvip.resourceRef = "/loadbalancers/`{0`}/frontendipconfigurations/$($vip.resourceId)"
        $rule.properties.frontendIPConfigurations += $newvip
    }
    $rule.properties.backendAddressPool = @{}
    $rule.properties.backendAddressPool.resourceRef = "/loadbalancers/`{0`}/backendaddresspools/$($backendAddressPool.resourceID)"

    return $rule
}

function New-NCLoadBalancerProbe     {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object] $LoadBalancer,
        [Parameter(mandatory=$true)]
        [string] $protocol,
        [Parameter(mandatory=$true)]
        [int] $port,
        [Parameter(mandatory=$true)]
        [int] $intervalInSeconds,
        [Parameter(mandatory=$true)]
        [int] $numberOfProbes,
        [Parameter(mandatory=$false)]
        [object[]] $loadBalancingRules = $null
        )

    $probe= @{}
    $probe.resourceID = $resourceID
    $probe.properties = @{}
    $probe.properties.protocol = $protocol
    $probe.properties.port = "$port"
    $probe.properties.intervalInSeconds= "$intervalInSeconds"
    $probe.properties.numberOfProbes = "$numberOfProbes"

    #TODO: what to do with loadbalancingrules

    $refpath = "$($loadbalancer.resourceRef)/probes"
    JSONPost  $script:NetworkControllerRestIP $refpath $probe  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function New-NCLoadBalancerOutboundNatRule            {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$false)]
        [string] $protocol="All",
        [Parameter(mandatory=$true)]
        [object[]] $frontEndIpConfigurations,
        [Parameter(mandatory=$true)]
        [object] $backendAddressPool
        )

    $natrule= @{}
    $natrule.resourceID = $resourceID
    $natrule.properties = @{}
    $natrule.properties.protocol = $protocol
    $natrule.properties.frontendIPConfigurations = @()

    foreach ($frontendIP in $frontEndIpConfigurations) {
        $NewFEIP = @{}
        $NewFEIP.resourceRef = "/loadbalancers/`{0`}/frontendipconfigurations/$($frontendIP.resourceId)"
        $natrule.properties.frontendIPConfigurations += $NewFEIP
    }

    $natrule.properties.backendAddressPool = @{}
    $natrule.properties.backendAddressPool.resourceRef = "/loadbalancers/`{0`}/backendaddresspools/$($backendAddressPool.resourceID)"

    return $natrule
}

function New-NCLoadBalancer
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [parameter(mandatory=$true)]
        [object[]] $FrontEndIPConfigurations,
        [parameter(mandatory=$true)]
        [object[]] $backendAddressPools,
        [parameter(mandatory=$false)]
        [object[]] $loadBalancingRules = $NULL,
        [parameter(mandatory=$false)]
        [object[]] $probes = $NULL,
        [parameter(mandatory=$false)]
        [object[]] $outboundnatrules= $NULL,
        [Parameter(mandatory=$false)]
        [string] $ComputerName=$script:NetworkControllerRestIP
    )

    $lb = JSONGet $script:NetworkControllerRestIP "/LoadBalancers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -Silent:$true
    # Note this handles Add updates ONLY for LOAD Balancing RULES (common case in MAS / PoC)
    if ($null -ne $lb)
    {
        # add the obNat, LB Rule, Inbound Rule

        $FrontEndIPConfigurations = @($FrontEndIPConfigurations)

        $lbfeIp = $lb.properties.frontendipconfigurations[0]

        if($null -ne $lbfeIp)
        {
            $newFeIP = @(New-NCLoadBalancerFrontEndIPConfiguration -resourceID $lbfeIp.resourceid -PrivateIPAddress $lbfeIp.properties.privateIpaddress -Subnet $lbfeIp.properties.subnet)
            $FrontEndIPConfigurations = $newFeIp
        }

        $lbbepool = $lb.properties.backendaddresspools[0]

        if($null -ne $lbbepool)
        {
            $newBePool = @(New-NCLoadBalancerBackendAddressPool -resourceID $lbbepool.resourceId)
            $backendAddressPools = $newBePool
        }

        if ( ($null -ne $lb.properties.OutboundNatRules)  -and ($lb.properties.OutboundNatRules.count -ne 0))
        {
            $obNatRules =$lb.properties.OutboundNatRules[0]

            $newObNatRule = @(New-NCLoadBalancerOutboundNatRule -resourceID $obNatRules.resourceId -protocol $obNatRules.properties.protocol -frontEndIpConfigurations $FrontEndIPConfigurations -backendAddressPool $backendAddressPools)
            $outboundnatrules = $newObNatRule
        }

        $loadBalancingRules = @($loadBalancingRules)
        $newloadBalancingRules = @()

        foreach ($lbrule in $lb.properties.loadBalancingRules)
        {
            $newLbRule = @(New-NCLoadBalancerLoadBalancingRule -resourceId $lbrule.resourceId -protocol $lbrule.properties.protocol -frontendPort $lbrule.properties.frontendPort -backendport $lbrule.properties.backendPort -enableFloatingIP $lbrule.properties.enableFloatingIp -frontEndIPConfigurations $FrontEndIPConfigurations -backendAddressPool $backendAddressPools)
            $newloadBalancingRules += $newLbRule
        }

        $lbRuleCount = $newloadBalancingRules.Count

        #find new unique lb rules
        foreach ($lbrule in $loadBalancingRules)
        {
            $found = $false
            foreach ($oldrule in $lb.properties.loadBalancingRules)
            {
                if(($lbrule.properties.frontendPort -eq $oldrule.properties.frontendPort) -and ($lbrule.properties.backendPort -eq $oldrule.properties.backendPort))
                {
                    $found = $true
                }
            }

            if(-not $found)
            {
                $enableFloat = [Boolean]::Parse("$($lbrule.properties.enableFloatingIp)")
                $newLbRule = @(New-NCLoadBalancerLoadBalancingRule -resourceId $lbrule.resourceId -protocol $lbrule.properties.protocol -frontendPort $lbrule.properties.frontendPort -backendport $lbrule.properties.backendPort -enableFloatingIP $enableFloat -frontEndIPConfigurations $FrontEndIPConfigurations -backendAddressPool $backendAddressPools)
                $newloadBalancingRules += $newLbRule
            }
        }

        if($lbRuleCount -eq $newloadBalancingRules.Count)
        {
            #No change in LB required, skip the update
            return $lb
        }

        $loadBalancingRules = $newloadBalancingRules
    }
    else
    {
        $lb = @{}
        $lb.resourceID = $resourceID
        $lb.properties = @{}
    }

    #Need to populate existing refs with LB resourceID
    if ($loadbalancingrules -ne $null)
    {
        foreach ($rule in $loadbalancingrules)
        {
            foreach ($frontend in $rule.properties.frontendipconfigurations)
            {
                $frontend.resourceRef = ($frontend.resourceRef -f $resourceID)
            }
            $rule.properties.backendaddresspool.resourceRef = ($rule.properties.backendaddresspool.resourceRef -f $resourceID)
        }
        $lb.properties.loadBalancingRules = $loadbalancingrules
    }

    if ($outboundnatrules -ne $null)
    {
        foreach ($rule in $outboundnatrules)
        {
            foreach ($frontend in $rule.properties.frontendipconfigurations)
            {
                $frontend.resourceRef = ($frontend.resourceRef -f $resourceID)
            }
            $rule.properties.backendaddresspool.resourceRef = ($rule.properties.backendaddresspool.resourceRef -f $resourceID)
        }
        $lb.properties.outboundnatrules = $outboundnatrules
    }

    foreach ($frontend in $frontendipconfigurations)
    {
        $frontendref = "/loadbalancers/$resourceID/frontendipconfigurations/$($frontend.resourceId)"

        $frontend.properties.loadbalancingrules = @()
        if ($loadbalancingrules -ne $null)
        {
            foreach ($rule in $loadbalancingrules)
            {
                foreach ($rulefe in $rule.properties.frontendipconfigurations)
                {
                    if ($rulefe.resourceRef -eq $frontendref)
   {
                        $newref = @{}
                        $newref.resourceRef = "/loadbalancers/$resourceID/loadbalancingrules/$($rule.resourceId)"

                        $frontend.properties.loadbalancingrules += $newref
                    }
                }

            }
        }

        $frontend.properties.outboundNatRules = @()
        if ($oubboundNatRules -ne $null)
        {
            foreach ($rule in $outboundnatrules)
            {
                foreach ($rulefe in $rule.properties.frontendipconfigurations)
                {
                    if ($rulefe.resourceRef -eq $frontendref)
   {
                        $newref = @{}
                        $newref.resourceRef = "/loadbalancers/$resourceID/outboundnatrules/$($rule.resourceId)"

                        $frontend.properties.outboundNatRules += $newref
                    }
                }

            }
        }
    }
    $lb.properties.frontendipconfigurations = $frontendipconfigurations

    foreach ($be in $backendaddresspools)
    {
        $beref = "/loadbalancers/$resourceID/backendaddresspools/$($be.resourceId)"

        $be.properties.loadbalancingrules = @()
        if ($loadbalancingrules -ne $null)
        {
            foreach ($rule in $loadbalancingrules)
            {
                if ($rule.properties.backendaddresspool.resourceRef -eq $beref)
                {
                    $newref = @{}
                    $newref.resourceRef = "/loadbalancers/$resourceID/loadbalancingrules/$($rule.resourceId)"
                    $be.properties.loadbalancingrules += $newref
                }

            }
        }
        $be.properties.outboundnatrules = @()
        if ($outboundnatrules -ne $null)
        {
            foreach ($rule in $outboundnatrules)
            {
                if ($rule.properties.backendaddresspool.resourceRef -eq $beref)
                {
                    $newref = @{}
                    $newref.resourceRef = "/loadbalancers/$resourceID/outboundnatrules/$($rule.resourceId)"
                    $be.properties.outboundnatrules += $newref
                }

            }
        }
    }
    $lb.properties.backendaddresspools = $backendaddresspools

    # $computerName is here to workaround product limitation for PUT of LoadBalancer, which is > 35KB and must be done from the REST hosting NC Vm.
    JSONPost $script:NetworkControllerRestIP "/LoadBalancers" $lb  -Credential $script:NetworkControllerCred -computerName $ComputerName| out-null
    return JSONGet $script:NetworkControllerRestIP "/LoadBalancers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCLoadBalancer          {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/LoadBalancers/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCLoadBalancer       {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/LoadBalancers/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function New-NCNetworkInterface      {
    param(
        [Parameter(mandatory=$true,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$true,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$true,ParameterSetName="ByNoNetwork")]
        [string] $resourceID,
        [Parameter(mandatory=$true,ParameterSetName="ByVirtualNetwork")]
        [object] $VirtualSubnet = $null,
        [Parameter(mandatory=$true,ParameterSetName="ByLogicalNetwork")]
        [object] $Subnet = $null,
        [Parameter(mandatory=$false,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByNoNetwork")]
        [string] $IPAddress = $null,
        [Parameter(mandatory=$true,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$true,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$true,ParameterSetName="ByNoNetwork")]
        [string] $MACAddress,
        [Parameter(mandatory=$false,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByNoNetwork")]
        [string[]] $DNSServers = @(),
        [Parameter(mandatory=$false,ParameterSetName="ByVirtualNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByLogicalNetwork")]
        [Parameter(mandatory=$false,ParameterSetName="ByNoNetwork")]
        [object] $acl=$null
    )

    if ($pscmdlet.ParameterSetName -eq 'ByVirtualNetwork') {
        $subnet = $virtualsubnet
    }

    $interface = @{}
    # resource Id
    $interface.resourceID = $resourceID
    $interface.properties = @{}

    # Mac Address
    $interface.properties.privateMacAddress = $macaddress
    $interface.properties.privateMacAllocationMethod = "Static"

    # IPConfigurations
    if ($Subnet -ne $null -or ![string]::IsNullOrEmpty($IPAddress) -or $acl -ne $null)
    {
        $interface.properties.ipConfigurations = @()

        $ipconfig = @{}
        $ipconfig.resourceId = [System.Guid]::NewGuid().toString()
        $ipconfig.properties = @{}

        if ($Subnet -ne $null)
        {
            $ipconfig.properties.subnet = @{}
            $ipconfig.properties.subnet.resourceRef = $Subnet.resourceRef
        }
        if (![string]::IsNullOrEmpty($IPAddress))
        {
            $ipconfig.properties.privateIPAddress = $IPAddress
            $ipconfig.properties.privateIPAllocationMethod = "Static"
        }
        if ($acl -ne $null) {
            $ipconfig.properties.accessControlList = @{}
            $ipconfig.properties.accessControlList.resourceRef = $acl.resourceRef
        }

        $interface.properties.ipConfigurations += $ipconfig
    }

    # DNS Servers
    if ($DNSServers -ne $null -and $DNSServers.count -gt 0)
    {
        $interface.properties.dnsSettings = @{}
        $interface.properties.dnsSettings.dnsServers = $DNSServers
    }

    JSONPost $script:NetworkControllerRestIP "/NetworkInterfaces" $interface  -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/NetworkInterfaces/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCNetworkInterface      {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/NetworkInterfaces/$resourceID"  -Credential $script:NetworkControllerCred
}
function Remove-NCNetworkInterface   {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/NetworkInterfaces/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

function Get-ServerResourceId        {
   param (
        [Parameter(mandatory=$false)]
        [string] $ComputerName="localhost",
        [Parameter(mandatory=$false)]
        [Object] $Credential=$script:NetworkControllerCred
        )

    $resourceId = ""

    write-verbose ("Retrieving server resource id on [$ComputerName]")

    try
    {
        $pssession = new-pssession -ComputerName $ComputerName -Credential $Credential

        $resourceId = invoke-command -session $pssession -ScriptBlock {
            $VerbosePreference = 'Continue'
            write-verbose "Retrieving first VMSwitch on [$using:ComputerName]"

            $switches = Get-VMSwitch -ErrorAction Ignore
            if ($switches.Count -eq 0)
            {
                throw "No VMSwitch was found on [$using:ComputerName]"
            }

            return $switches[0].Id
        }
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }
    finally
    {
        Remove-PSSession $pssession
    }

    write-verbose "Server resource id is [$resourceId] on [$ComputerName]"
    return $resourceId
}

function Set-PortProfileId           {
   param (
        [Parameter(mandatory=$true)]
        [string] $resourceID,
        [Parameter(mandatory=$true)]
        [string] $VMName,
        [Parameter(mandatory=$false)]
        [string] $VMNetworkAdapterName,
        [Parameter(mandatory=$false)]
        [string] $ComputerName="localhost",
        [Parameter(mandatory=$false)]
        [Object] $credential=$script:NetworkControllerCred,
        [Parameter(mandatory=$false)]
        [int] $ProfileData = 1,
        [Switch] $force
        )

    #do not change these values
    write-verbose ("Setting port profile for [$vmname] on [$computername]" )

    try
    {
        $pssession = new-pssession -ComputerName $computername -Credential $credential
        $isforce = $force.ispresent

        invoke-command -session $pssession -ScriptBlock {
            $VerbosePreference = 'Continue'
            write-verbose ("Running port profile set script block on host" )

            $PortProfileFeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56"
            $NcVendorId  = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}"

            $portProfileDefaultSetting = Get-VMSystemSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId

            $portProfileDefaultSetting.SettingData.ProfileId = "{$using:resourceId}"
            $portProfileDefaultSetting.SettingData.NetCfgInstanceId = "{56785678-a0e5-4a26-bc9b-c0cba27311a3}"
            $portProfileDefaultSetting.SettingData.CdnLabelString = "TestCdn"
            $portProfileDefaultSetting.SettingData.CdnLabelId = 1111
            $portProfileDefaultSetting.SettingData.ProfileName = "Testprofile"
            $portProfileDefaultSetting.SettingData.VendorId = $NcVendorId
            $portProfileDefaultSetting.SettingData.VendorName = "NetworkController"
            $portProfileDefaultSetting.SettingData.ProfileData = $using:ProfileData
            #$portprofiledefaultsetting.settingdata

            write-verbose ("Retrieving VM network adapter $using:VMNetworkAdapterName" )
            if ([String]::IsNullOrEmpty($using:VMNetworkAdapterName))
            {
                write-verbose ("Retrieving all VM network adapters for VM $using:VMName")
                $vmNics = Get-VMNetworkAdapter -VMName $using:VMName
            }
            else
            {
                write-verbose ("Retrieving VM network adapter $using:VMNetworkAdapterName for VM $using:VMName" )
                $vmNics = @(Get-VMNetworkAdapter -VMName $using:VMName -Name $using:VMNetworkAdapterName)
            }

            foreach ($vmNic in $vmNics) {
                write-verbose ("Setting port profile on vm network adapter $($vmNic.Name)" )
                $currentProfile = Get-VMSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId -VMNetworkAdapter $vmNic

                if ( $currentProfile -eq $null)
                {
                    write-verbose ("Adding port feature for [{0}] to [{1}]" -f $using:VMName, "{$using:resourceId}")
                    Add-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature  $portProfileDefaultSetting -VMNetworkAdapter $vmNic | out-null
                    write-verbose "Adding port feature complete"

                }
                else
                {
                    if ($using:isforce) {
                        write-verbose ("Setting port feature for [{0}] to [{1}]" -f $using:VMName, "{$using:resourceId}")

                        $currentProfile.SettingData.ProfileId = "{$using:resourceId}"
                        $currentProfile.SettingData.ProfileData = $using:ProfileData
                        Set-VMSwitchExtensionPortFeature  -VMSwitchExtensionFeature $currentProfile  -VMNetworkAdapter $vmNic | out-null
                    } else {
                        write-verbose ("Port profile already set for [{0}] use -Force to override." -f $using:VMName)
                    }
                }
            }
        }
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }
    finally
    {
        Remove-PSSession $pssession
    }
}

function Remove-PortProfileId
{
   param (
        [Parameter(mandatory=$true)]
        [string] $VMName,
        [Parameter(mandatory=$false)]
        [string] $VMNetworkAdapterName="Network Adapter",
        [Parameter(mandatory=$false)]
        [string] $ComputerName="localhost"
        )

    write-verbose ("Removing port profile for Network Adapter [$VMNetworkAdapterName] on VM [$vmname] on [$computername]" )

    try
    {
        $pssession = new-pssession -ComputerName $computername

        invoke-command -session $pssession -ScriptBlock {
            param($VMName, $VMNetworkAdapterName)
            $VerbosePreference = 'Continue'
            write-verbose ("Running port profile remove script block on host" )

            #do not change these values
            $PortProfileFeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56"
            $NcVendorId  = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}"

            $portProfileCurrentSetting = Get-VMSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId -VMName $VMName -VMNetworkAdapterName $VMNetworkAdapterName

            write-verbose ("Removing port profile from vm network adapter $VMNetworkAdapterName" )
            Remove-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $portProfileCurrentSetting -VMName $VMName -VMNetworkAdapterName $VMNetworkAdapterName -Confirm:$false
        } -ArgumentList @($VMName, $VMNetworkAdapterName)
    }
    catch
    {
        Write-Error "Failed with error: $_"
    }
    finally
    {
        Remove-PSSession $pssession
    }
}

function New-NCSwitchPort        {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid()
    )

    $server = @{}
    $server.resourceId = $ResourceID
    $server.instanceId = $ResourceID
    $server.properties = @{}

    if ($managed.ispresent)  {
        $server.properties.managementState = "Managed"
    } else
    {
        $server.properties.managementState = "unManaged"
    }
    $server.properties.roleType = "multiLayerSwitch"
    $server.properties.switchType = $switchtype

    $server.properties.connections = $Connections

    JSONPost  $script:NetworkControllerRestIP "/Switches" $server  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/Switches/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}

function New-NCSwitch        {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [object[]] $Connections,
        [Parameter(mandatory=$true)]
        [string] $switchType,
        [Switch] $Managed
    )

    $server = @{}
    $server.resourceId = $ResourceID
    $server.instanceId = $ResourceID
    $server.properties = @{}

    if ($managed.ispresent)  {
        $server.properties.managementState = "Managed"
    } else
    {
        $server.properties.managementState = "Unmanaged"
    }
    $server.properties.roleType = "multiLayerSwitch"
    $server.properties.switchType = $switchtype
    $server.properties.switchPorts = @()

    $newport = @{}
    $newport.ResourceRef = "Port1"
    $newport.properties = @{}
    $server.properties.switchPorts += $newport

    $newport = @{}
    $newport.ResourceRef = "Port2"
    $newport.properties = @{}
    $server.properties.switchPorts += $newport

    $server.properties.connections = $Connections

    JSONPost  $script:NetworkControllerRestIP "/Switches" $server   -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/Switches/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred

}

function Get-NCSwitch         {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/Switches/$resourceID"  -Credential $script:NetworkControllerCred
}

function Remove-NCSwitch      {
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
    JSONDelete  $script:NetworkControllerRestIP "/Switches/$resourceId" -Waitforupdate  -Credential $script:NetworkControllerCred| out-null
     }
}

#
# iDNS Specific Wrappers
#
function Add-iDnsConfiguration
{
    param(
        [Parameter(mandatory=$true)]
        [object[]] $connections,
        [Parameter(mandatory=$true)]
        [string] $zoneName
    )

    $iDnsObj = @{}
    # resource Id configuration is fixed
    $iDnsObj.resourceID = "configuration"
    $iDnsObj.properties = @{}

    $iDnsObj.properties.connections=$connections
    $iDnsObj.properties.zone=$zoneName


    JSONPost $script:NetworkControllerRestIP "/iDnsServer" $iDnsObj -Credential $script:NetworkControllerCred| out-null
    return JSONGet $script:NetworkControllerRestIP "/iDnsServer/Configuration" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-iDnsConfiguration
{
    return JSONGet $script:NetworkControllerRestIP "/iDnsServer/configuration"  -Credential $script:NetworkControllerCred
}


#
# Gateway Specific Wrappers
#

function New-NCPublicIPAddress
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID=[system.guid]::NewGuid(),
        [Parameter(mandatory=$true)]
        [string] $PublicIPAddress)

    $publicIP = @{}
    $publicIP.resourceId = $ResourceID
    $publicIP.properties = @{}
    $publicIP.properties.ipAddress = $PublicIPAddress
    $publicIP.properties.publicIPAllocationMethod = "Static"

    JSONPost  $script:NetworkControllerRestIP "/publicIPAddresses" $publicIP  -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/publicIPAddresses/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCPublicIPAddress
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/publicIPAddresses/$resourceID" -Credential $script:NetworkControllerCred
}

function Remove-NCPublicIPAddress
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
     )
     foreach ($resourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/publicIPAddresses/$resourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
     }
}

function New-NCGatewayPool
{
    param(
        [Parameter(mandatory=$true)]
        [string] $resourceID,
        [Parameter(mandatory=$true)]
        [string] $Type,
        [Parameter(mandatory=$false)]
        [string] $GreVipSubnetResourceRef,
        [Parameter(mandatory=$false)]
        [string] $PublicIPAddressId,
        [Parameter(mandatory=$false)]
        [System.UInt64] $Capacity = 10000000,
        [Parameter(mandatory=$false)]
        [System.UInt32] $RedundantGatewayCount = 0
    )

    $gwPool = @{}
    $gwPool.resourceID = $resourceID

    $gwPool.properties = @{}
    $gwPool.properties.type = $Type
    $gwPool.properties.ipConfiguration = @{}

    if (-not([String]::IsNullOrEmpty($GreVipSubnetResourceRef)))
    {
        $gwPool.properties.ipConfiguration.greVipSubnets = @()
        $greVipSubnet = @{}
        $greVipSubnet.resourceRef = $GreVipSubnetResourceRef
        $gwPool.properties.ipConfiguration.greVipSubnets += $greVipSubnet
    }

    $publicIPAddresses = @{}
    if (-not([String]::IsNullOrEmpty($PublicIPAddressId)))
    {
        $publicIPAddresses.resourceRef = "/publicIPAddresses/$PublicIPAddressId"
        $gwPool.properties.ipConfiguration.publicIPAddresses = @()
        $gwPool.properties.ipConfiguration.publicIPAddresses += $publicIPAddresses
    }
    $gwPool.properties.redundantGatewayCount = $RedundantGatewayCount
    $gwPool.properties.gatewayCapacityKiloBitsPerSecond = $Capacity

    JSONPost $script:NetworkControllerRestIP "/GatewayPools" $gwPool -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/GatewayPools/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCGatewayPool
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/GatewayPools/$ResourceID" -Credential $script:NetworkControllerCred
}

function Remove-NCGatewayPool
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
    )
    foreach ($ResourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/GatewayPools/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
    }
}


function New-NCGateway
{
    param(
        [Parameter(mandatory=$true)]
        [string] $resourceID,
        [Parameter(mandatory=$true)]
        [string] $GatewayPoolRef,
        [Parameter(mandatory=$true)]
        [string] $Type,
        [Parameter(mandatory=$false)]
        [object] $BgpConfig,
        [Parameter(mandatory=$true)]
        [string] $VirtualServerRef,
        [Parameter(mandatory=$true)]
        [string] $InternalInterfaceRef,
        [Parameter(mandatory=$true)]
        [string] $ExternalInterfaceRef
    )

    $gateway = @{}
    $gateway.resourceID = $resourceID
    $gateway.properties = @{}

    $gateway.properties.pool = @{}
    $gateway.properties.pool.resourceRef = $GatewayPoolRef

    $gateway.properties.type = $Type
    $gateway.properties.bgpConfig = @{}
    $gateway.properties.bgpConfig = $BgpConfig

    $gateway.properties.virtualserver = @{}
    $gateway.properties.virtualserver.resourceRef = $VirtualServerRef

    $gateway.properties.networkInterfaces = @{}
    $gateway.properties.networkInterfaces.externalNetworkInterface = @{}
    $gateway.properties.networkInterfaces.externalNetworkInterface.resourceRef = $ExternalInterfaceRef
    $gateway.properties.networkInterfaces.internalNetworkInterface = @{}
    $gateway.properties.networkInterfaces.internalNetworkInterface.resourceRef = $InternalInterfaceRef

    JSONPost $script:NetworkControllerRestIP "/Gateways" $gateway -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/Gateways/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}

function Get-NCGateway
{
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/Gateways/$resourceID" -Credential $script:NetworkControllerCred
}

function Remove-NCGateway
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
    )
    foreach ($ResourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/Gateways/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
    }
}

function Get-NCMacPool
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/MacPools/$ResourceID" -Credential $script:NetworkControllerCred
}
function Remove-NCMacPool
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
    )
    foreach ($ResourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/MacPools/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
    }
}
function New-NCVpnClientAddressSpace
{
    param(
        [Parameter(mandatory=$true)]
        [string] $TenantName,
        [Parameter(mandatory=$true)]
        [System.UInt64] $VpnCapacity,
        [Parameter(mandatory=$true)]
        [string] $Ipv4AddressPool,
        [Parameter(mandatory=$true)]
        [string] $Ipv6AddressPool
    )

    $vpnClientAddressSpace = @{}
    $vpnClientAddressSpace.AddressPrefixes = @()
    $vpnClientAddressSpace.AddressPrefixes += @($Ipv4AddressPool, $Ipv6AddressPool)
    $vpnClientAddressSpace.Capacity = $VpnCapacity.ToString()
    $vpnClientAddressSpace.Realm = $TenantName

    return $vpnClientAddressSpace
}

function New-NCIPSecTunnel
{
    param(
        [Parameter(mandatory=$true)]
        [string] $ResourceId,
        [Parameter(mandatory=$true)]
        [system.uint64] $OutboundCapacity,
        [Parameter(mandatory=$true)]
        [system.uint64] $InboundCapacity,
        [Parameter(mandatory=$false)]
        [object[]] $IPAddresses,
        [Parameter(mandatory=$false)]
        [string[]] $PeerIPAddresses,
        [Parameter(mandatory=$false)]
        [string] $DestinationIPAddress,
        [Parameter(mandatory=$false)]
        [string] $SharedSecret,
        [Parameter(mandatory=$false)]
        [object[]] $IPv4Subnets
    )

    $AuthenticationMethod = "PSK"

    $ipSecVpn = @{}
    $ipsecVpn.resourceId = $ResourceId
    $ipSecVpn.properties = @{}

    $ipSecVpn.properties.connectionType = "IPSec"
    $ipSecVpn.properties.outboundKiloBitsPerSecond = $outboundCapacity
    $ipSecVpn.properties.inboundKiloBitsPerSecond = $inboundCapacity

    $routes = @()
    foreach ($IPv4Subnet in $IPv4Subnets)
    {
        $route = @{}
        $route.destinationPrefix = $IPv4Subnet.Prefix
        $route.metric = $IPv4Subnet.Metric
        $routes += $route
    }
    $ipSecVpn.properties.routes = @()
    $ipSecVpn.properties.routes = $routes

    $ipSecVpn.properties.ipSecConfiguration = @{}
    $ipSecVpn.properties.ipSecConfiguration.QuickMode = @{}
    $ipSecVpn.properties.ipSecConfiguration.MainMode = @{}

    $ipSecVpn.properties.ipSecConfiguration.authenticationMethod = $AuthenticationMethod
    if ($AuthenticationMethod -eq "PSK")
    { $ipSecVpn.properties.ipSecConfiguration.sharedSecret = $SharedSecret }

    $ipSecVpn.properties.ipSecConfiguration.quickMode.perfectForwardSecrecy                = "PFS2048"
    $ipSecVpn.properties.ipSecConfiguration.quickMode.authenticationTransformationConstant = "SHA256128"
    $ipSecVpn.properties.ipSecConfiguration.quickMode.cipherTransformationConstant         = "DES3"
    $ipSecVpn.properties.ipSecConfiguration.quickMode.saLifeTimeSeconds                    = 1233
    $ipSecVpn.properties.ipSecConfiguration.quickMode.idleDisconnectSeconds                = 500
    $ipSecVpn.properties.ipSecConfiguration.quickMode.saLifeTimeKiloBytes                  = 2000

    $ipSecVpn.properties.ipSecConfiguration.mainMode.diffieHellmanGroup  = "Group2"
    $ipSecVpn.properties.ipSecConfiguration.mainMode.integrityAlgorithm  = "SHA256"
    $ipSecVpn.properties.ipSecConfiguration.mainMode.encryptionAlgorithm = "AES256"
    $ipSecVpn.properties.ipSecConfiguration.mainMode.saLifeTimeSeconds   = 1234
    $ipSecVpn.properties.ipSecConfiguration.mainMode.saLifeTimeKiloBytes = 2000

    if ($IPAddresses -eq $null) {$IPAddresses = @()}
    if ($PeerIPAddresses -eq $null) {$PeerIPAddresses = @()}

    $ipSecVpn.properties.ipAddresses = $IPAddresses
    $ipSecVpn.properties.peerIPAddresses = $PeerIPAddresses
    $ipSecVpn.properties.destinationIPAddress = $DestinationIPAddress

    return $ipSecVpn
}

function New-NCGreTunnel
{
    param(
        [Parameter(mandatory=$true)]
        [string] $ResourceId,
        [Parameter(mandatory=$true)]
        [system.uint64] $OutboundCapacity,
        [Parameter(mandatory=$true)]
        [system.uint64] $InboundCapacity,
        [Parameter(mandatory=$false)]
        [object[]] $IPAddresses,
        [Parameter(mandatory=$false)]
        [string[]] $PeerIPAddresses,
        [Parameter(mandatory=$false)]
        [string] $DestinationIPAddress,
        [Parameter(mandatory=$false)]
        [object[]] $IPv4Subnets,
        [Parameter(mandatory=$false)]
        [string] $GreKey
    )

    $greTunnel = @{}
    $greTunnel.resourceId = $ResourceId
    $greTunnel.properties = @{}

    $greTunnel.properties.connectionType = "GRE"
    $greTunnel.properties.outboundKiloBitsPerSecond = $outboundCapacity
    $greTunnel.properties.inboundKiloBitsPerSecond = $inboundCapacity

    $greTunnel.properties.greConfiguration = @{}
    $greTunnel.properties.greConfiguration.GreKey = $GreKey

    if ($IPAddresses -eq $null) {$IPAddresses = @()}
    if ($PeerIPAddresses -eq $null) {$PeerIPAddresses = @()}

    $greTunnel.properties.ipAddresses = $IPAddresses
    $greTunnel.properties.peerIPAddresses = $PeerIPAddresses

    $routes = @()
    foreach ($IPv4Subnet in $IPv4Subnets)
    {
        $route = @{}
        $route.destinationPrefix = $IPv4Subnet.Prefix
        $route.metric = $IPv4Subnet.Metric
        $routes += $route
    }
    $greTunnel.properties.routes = @()
    $greTunnel.properties.routes = $routes

    $greTunnel.properties.destinationIPAddress = $DestinationIPAddress

    return $greTunnel
}

function New-NCL3Tunnel
{
    param(
        [Parameter(mandatory=$true)]
        [string] $ResourceId,
        [Parameter(mandatory=$true)]
        [system.uint64] $OutboundCapacity,
        [Parameter(mandatory=$true)]
        [system.uint64] $InboundCapacity,
        [Parameter(mandatory=$false)]
        [string] $VlanSubnetResourceRef,
        [Parameter(mandatory=$false)]
        [object[]] $L3IPAddresses,
        [Parameter(mandatory=$false)]
        [System.UInt16] $PrefixLength,
        [Parameter(mandatory=$false)]
        [string[]] $L3PeerIPAddresses,
        [Parameter(mandatory=$false)]
        [object[]] $IPv4Subnets
    )

    $l3Tunnel = @{}
    $l3Tunnel.resourceId = $ResourceId
    $l3Tunnel.properties = @{}

    $l3Tunnel.properties.connectionType = "L3"
    $l3Tunnel.properties.outboundKiloBitsPerSecond = $outboundCapacity
    $l3Tunnel.properties.inboundKiloBitsPerSecond = $inboundCapacity

    $l3Tunnel.properties.l3Configuration = @{}
    $l3Tunnel.properties.l3Configuration.vlanSubnet = @{}
    $l3Tunnel.properties.l3Configuration.vlanSubnet.resourceRef = $VlanSubnetResourceRef

    $l3Tunnel.properties.ipAddresses = @($L3IPAddresses)
    $l3Tunnel.properties.peerIPAddresses = @($L3PeerIPAddresses)

    $routes = @()
    foreach ($IPv4Subnet in $IPv4Subnets)
    {
        $route = @{}
        $route.destinationPrefix = $IPv4Subnet.Prefix
        $route.metric = $IPv4Subnet.Metric
        $routes += $route
    }
    $l3Tunnel.properties.routes = @()
    $l3Tunnel.properties.routes = $routes

    return $l3Tunnel
}

function New-NCBgpRoutingPolicy
{
    param(
        [Parameter(mandatory=$true)]
        [string] $PolicyName,
        [Parameter(mandatory=$true)]
        [string] $PolicyType,
        [Parameter(mandatory=$true)]
        [object[]] $MatchCriteriaList,
        [Parameter(mandatory=$false)]
        [object[]] $Actions,
        [Parameter(mandatory=$false)]
        [string] $EgressPolicyMapResourceRef
    )

    $bgpPolicy = @{}
    $bgpPolicy.policyName = $PolicyName
    $bgpPolicy.policyType = $policyType

    $bgpPolicy.matchCriteria = @()
    $bgpPolicy.setActions = @()

    foreach ($criteria in $MatchCriteriaList)
    {
        $matchCriteria = @{}
        $matchCriteria.clause = $criteria.clause
        $matchCriteria.operator = "And"
        $matchCriteria.value = $criteria.value

        $bgpPolicy.matchCriteria += $matchCriteria
    }

    $bgpPolicy.setActions += @($Actions)

    return $bgpPolicy
}

function New-NCBgpRoutingPolicyMap
{
    param(
        [Parameter(mandatory=$true)]
        [string] $PolicyMapName,
        [Parameter(mandatory=$true)]
        [object[]] $PolicyList
    )

    $bgpPolicyMap = @{}
    $bgpPolicyMap.resourceId = $PolicyMapName
    $bgpPolicyMap.properties = @{}

    $bgpPolicyMap.properties.policyList = @($PolicyList)

    return $bgpPolicyMap
}

function New-NCBgpPeer
{
    param(
        [Parameter(mandatory=$true)]
        [string] $PeerName,
        [Parameter(mandatory=$true)]
        [string] $PeerIP,
        [Parameter(mandatory=$true)]
        [string] $PeerASN,
        [Parameter(mandatory=$false)]
        [string] $IngressPolicyMapResourceRef,
        [Parameter(mandatory=$false)]
        [string] $EgressPolicyMapResourceRef
    )

    $bgpPeer = @{}
    $bgpPeer.resourceId = $PeerName
    $bgpPeer.properties = @{}

    $bgpPeer.properties.peerIPAddress = $PeerIP
    $bgpPeer.properties.peerAsNumber = $PeerASN
    $bgpPeer.properties.ExtAsNumber = "0.$PeerASN"

    $bgpPeer.properties.policyMapIn  = $null
    $bgpPeer.properties.policyMapOut = $null

    if (![string]::IsNullOrEmpty($IngressPolicyMapResourceRef))
    {
        $bgpPeer.properties.policyMapIn  = @{}
        $bgpPeer.properties.policyMapIn.resourceRef = $IngressPolicyMapResourceRef
    }
    if (![string]::IsNullOrEmpty($EgressPolicyMapResourceRef))
    {
        $bgpPeer.properties.policyMapOut = @{}
        $bgpPeer.properties.policyMapOut.resourceRef = $EgressPolicyMapResourceRef
    }

    return $bgpPeer
}

function New-NCBgpRouter
{
    param(
        [Parameter(mandatory=$true)]
        [string] $RouterName,
        [Parameter(mandatory=$true)]
        [string] $LocalASN,
        [Parameter(mandatory=$false)]
        [object[]] $BgpPeers
    )

    $bgpRouter = @{}
    $bgpRouter.resourceId = $RouterName
    $bgpRouter.properties = @{}

    $bgpRouter.properties.isEnabled = "true"
    $bgpRouter.properties.requireIGPSync = "true"
    $bgpRouter.properties.extAsNumber = "0.$LocalASN"
    $bgpRouter.properties.routerIP = @()
    $bgpRouter.properties.bgpNetworks = @()
    $bgpRouter.properties.isGenerated = $false

    $bgpRouter.properties.bgpPeers = @($BgpPeers)

    return $bgpRouter
}

function New-NCVirtualGateway
{
    param(
        [Parameter(mandatory=$true)]
        [string] $resourceID,
        [Parameter(mandatory=$true)]
        [string[]] $GatewayPools,
        [Parameter(mandatory=$true)]
        [string] $vNetIPv4SubnetResourceRef,
        [Parameter(mandatory=$false)]
        [object] $VpnClientAddressSpace,
        [Parameter(mandatory=$false)]
        [object[]] $NetworkConnections,
        [Parameter(mandatory=$false)]
        [object[]] $BgpRouters,
        [Parameter(mandatory=$false)]
        [object[]] $PolicyMaps,
        [Parameter(mandatory=$false)]
        [string] $RoutingType = "Dynamic"
    )

    $virtualGW = @{}
    $virtualGW.resourceID = $resourceID
    $virtualGW.properties = @{}

    $virtualGW.properties.gatewayPools = @()
    foreach ($gatewayPool in $GatewayPools)
    {

        $gwPool = @{}
        $gwPool.resourceRef = "/gatewayPools/$gatewayPool"
        $virtualGW.properties.gatewayPools += $gwPool
    }

    $gatewaySubnetsRef = @{}
    $gatewaySubnetsRef.resourceRef = $vNetIPv4SubnetResourceRef
    $virtualGW.properties.gatewaySubnets = @()
    $virtualGW.properties.gatewaySubnets += $gatewaySubnetsRef

    $virtualGW.properties.vpnClientAddressSpace = @{}
    $virtualGW.properties.vpnClientAddressSpace = $VpnClientAddressSpace

    $virtualGW.properties.networkConnections = @()
    $virtualGW.properties.networkConnections += @($Networkconnections)

    $virtualGW.properties.bgpRouters = @()
    $virtualGW.properties.bgpRouters += $BgpRouters

    $virtualGW.properties.policyMaps = @()
    $virtualGW.properties.policyMaps += $PolicyMaps

    $virtualGW.properties.routingType = $RoutingType

    JSONPost $script:NetworkControllerRestIP "/VirtualGateways" $virtualGW -Credential $script:NetworkControllerCred | out-null
    return JSONGet $script:NetworkControllerRestIP "/VirtualGateways/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred
}
function Get-NCVirtualGateway
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/VirtualGateways/$ResourceID" -Credential $script:NetworkControllerCred
}
function Remove-NCVirtualGateway
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
    )
    foreach ($ResourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/VirtualGateways/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
    }
}

function Remove-NCGateway
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
    )
    foreach ($ResourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/Gateways/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
    }
}

function Get-NCLearnedIPAddress
{
    param(
        [Parameter(mandatory=$false)]
        [string] $ResourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/LearnedIPAddresses/$ResourceID" -Credential $script:NetworkControllerCred
}
function Remove-NCLearnedIPAddress
{
    param(
        [Parameter(mandatory=$true)]
        [string[]] $ResourceIDs
    )
    foreach ($ResourceId in $ResourceIDs) {
        JSONDelete  $script:NetworkControllerRestIP "/LearnedIPAddresses/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null
    }
}

function Add-LoadBalancerToNetworkAdapter
{
    param(
        [parameter(mandatory=$false)]
        [string] $LoadBalancerResourceID,
        [parameter(mandatory=$false)]
        [string[]] $VMNicResourceIds
    )
    $loadBalancer = Get-NCLoadBalancer -resourceId $LoadBalancerResourceID
    $lbbeResourceRef = $loadBalancer.Properties.backendAddressPools.resourceRef
    foreach($nicResourceID in $VMNicResourceIds)
    {
        $nicResource = Get-NCNetworkInterface -resourceid $nicResourceID
        $loadBalancerBackendAddressPools = @{}
        $loadBalancerBackendAddressPools.resourceRef = $lbbeResourceRef
        if(-not $nicResource.properties.ipConfigurations[0].properties.loadBalancerBackendAddressPools)
        {
            $nicResource.properties.ipConfigurations[0].properties.loadBalancerBackendAddressPools= @()
        }
        else
        {
            $found = $false
            foreach ($backendAddressPool in $nicResource.properties.ipConfigurations[0].properties.loadBalancerBackendAddressPools)
            {
                $resourceRef = $backendAddressPool.resourceRef
                if ($resourceRef -eq $lbbeResourceRef)
                {
                    $found = $true
                    break
                }
            }

            if ($found -eq $true)
            {
                continue
            }
        }
        $nicResource.properties.ipConfigurations[0].properties.loadBalancerBackendAddressPools += $loadBalancerBackendAddressPools
        JSONPost $script:NetworkControllerRestIP "/NetworkInterfaces" $nicResource -Credential $script:NetworkControllerCred | out-null
    }
}

function Remove-LoadBalancerFromNetworkAdapter
{
    param(
        [parameter(mandatory=$false)]
        [string[]] $VMNicResourceIds
    )
    foreach($nicResourceID in $VMNicResourceIds)
    {
        $nicResource = Get-NCNetworkInterface -resourceid $nicResourceID
        $nicResource.properties.ipConfigurations[0].loadBalancerBackendAddressPools.resourceRef = ""
        JSONPost $script:NetworkControllerRestIP "/NetworkInterfaces" $nicResource -Credential $script:NetworkControllerCred | out-null
    }
}

function Get-NCRouteTable      {
    param(
        [Parameter(mandatory=$false)]
        [string] $resourceID = ""
    )
    return JSONGet $script:NetworkControllerRestIP "/RouteTables/$resourceID"  -Credential $script:NetworkControllerCred
}


function GenerateMainForm {

    param(
            [Parameter(mandatory=$true)]
            [object[]] $DataArr
        )
    
        [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
        [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
        #endregion
    
        #region Generated Form Objects
        $ExplorerForm = New-Object System.Windows.Forms.Form
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        #endregion Generated Form Objects
    
    
        $OnLoadForm_StateCorrection=
        {#Correct the initial state of the form to prevent the .Net maximized form issue
        $ExplorerForm.WindowState = $InitialFormWindowState
        }
    
        #———————————————-
        #region Generated Form Code
        $ExplorerForm.Text = "SDN Explorer NC:$NCIP"
        $ExplorerForm.Name = "SDN Explorer NC:$NCIP"
        $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0
    
        # panel to have scroll bar
        $panel = New-Object System.Windows.Forms.Panel
        $panel.BackColor = [System.Drawing.Color]::Silver
        $panel.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $panel.Location = New-Object System.Drawing.Point (5,5)
    
    
        $System_Drawing_Point = New-Object System.Drawing.Point
        $System_Drawing_Point.X = 80
        $System_Drawing_Point.Y = 20
        for ($it = 0; $it -lt $DataArr.Count ;$it++)
        {
            if($DataArr[$it].Name -eq "Rest ApiVersion")
            {
    
                $objLabel = New-Object System.Windows.Forms.Label
                $objLabel.Location = $System_Drawing_Point
                $objLabel.Size = New-Object System.Drawing.Size(240,20)
                $objLabel.Text = "Rest Api Version"
                $panel.Controls.Add($objLabel)
    
                $objTextBox = New-Object System.Windows.Forms.TextBox
                $objTextBox.Location = New-Object System.Drawing.Size(340,$System_Drawing_Point.Y)
                $objTextBox.Size = New-Object System.Drawing.Size(60,23)
                $objTextBox.Text = $Global:NCApiVersion
                $panel.Controls.Add($objTextBox)
    
                $okButton = New-Object System.Windows.Forms.Button
                $System_Drawing_SizeButton = New-Object System.Drawing.Size
                $System_Drawing_SizeButton.Width = 60
                $System_Drawing_SizeButton.Height = 23
                $okButton.TabIndex = 0
                $okButton.Name = "Submit"
                $okButton.Size = $System_Drawing_SizeButton
                $okButton.UseVisualStyleBackColor = $True
                $okButton.Text = "OK"
                $okButton.Location = New-Object System.Drawing.Size(420,$System_Drawing_Point.Y)
                $okButton.DataBindings.DefaultDataSourceUpdateMode = 0
                $scriptBlock = {$Global:NCApiVersion=$objTextBox.Text;}
                $okButton.add_Click({$Global:NCApiVersion=$objTextBox.Text;})
                $panel.Controls.Add($okButton)
            }
            else
            {
    
            $button = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 240
            $System_Drawing_SizeButton.Height = 23
            $button.TabIndex = 0
            $button.Name = "UnlockAccountButton"
            $button.Size = $System_Drawing_SizeButton
            $button.UseVisualStyleBackColor = $True
            $button.Text = $DataArr[$it].Name
            $button.Location = $System_Drawing_Point
            $button.DataBindings.DefaultDataSourceUpdateMode = 0
            $scriptBlock = $DataArr[$it].Value[0]
            $button.add_Click($scriptBlock)
            $panel.Controls.Add($button)
    
    
            $putButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 60
            $System_Drawing_SizeButton.Height = 23
            $putButton.TabIndex = 0
            $putButton.Name = "Put"
            $putButton.Size = $System_Drawing_SizeButton
            $putButton.UseVisualStyleBackColor = $True
            $putButton.Text = "Put"
            $putButton.Location = New-Object System.Drawing.Size(340,$System_Drawing_Point.Y)
            $putButton.DataBindings.DefaultDataSourceUpdateMode = 0
            if($DataArr[$it].Value.Count -gt 1)
            {
                $scriptBlock = $DataArr[$it].Value[1]
            }
            else
            {
                $putButton.Enabled = $false
            }
            $putButton.add_Click($scriptBlock)
            $panel.Controls.Add($putButton)
    
    
            $DeleteButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 60
            $System_Drawing_SizeButton.Height = 23
            $DeleteButton.TabIndex = 0
            $DeleteButton.Name = "Delete"
            $DeleteButton.Size = $System_Drawing_SizeButton
            $DeleteButton.UseVisualStyleBackColor = $True
            $DeleteButton.Text = "Delete"
            $DeleteButton.Location = New-Object System.Drawing.Size(420,$System_Drawing_Point.Y)
            $DeleteButton.DataBindings.DefaultDataSourceUpdateMode = 0
            if($DataArr[$it].Value.Count -gt 2)
            {
                $scriptBlock = $DataArr[$it].Value[2]
            }
            else
            {
                $DeleteButton.Enabled = $false
            }
            $DeleteButton.add_Click($scriptBlock)
            $panel.Controls.Add($DeleteButton)
    
            }
            $System_Drawing_Point.Y += 33
    
        }
    
    
        if($System_Drawing_Point.Y -ge 700)
        {
            $yPoint = 700
        }
        else
        {
            $yPoint = $System_Drawing_Point.Y + 50
        }
    
        $System_Drawing_Size = New-Object System.Drawing.Size
        $System_Drawing_Size.Width = 560
        $System_Drawing_Size.Height = $yPoint
        $ExplorerForm.ClientSize = $System_Drawing_Size
    
        $System_Drawing_Size.Width -= 10
        $System_Drawing_Size.Height -= 10
        $panel.Size = $System_Drawing_Size
        $panel.AutoScroll = $true
        $ExplorerForm.Controls.Add($panel)
    
        #endregion Generated Form Code
    
        #Save the initial state of the form
        $InitialFormWindowState = $ExplorerForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $ExplorerForm.add_Load($OnLoadForm_StateCorrection)
        #Show the Form
        $ExplorerForm.ShowDialog()| Out-Null
    }
    
    
function GenerateArrayFormHelper {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $HandlerFunc,
    
            [Parameter(mandatory=$true)]
            [string] $RemoveFunc,
    
            [Parameter(mandatory=$true)]
            [string] $NCIP,
    
            [Parameter(mandatory=$false)]
            [object]
            $NCCredential=  [System.Management.Automation.PSCredential]::Empty,
    
            [Parameter(mandatory=$true)]
            [bool]
            $EnableMultiWindow=$true,
    
            [Parameter(mandatory=$false)]
            [object]
            $NCVMCredential=  [System.Management.Automation.PSCredential]::Empty
    )
    
        #. .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential
    
        [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
        [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
        #endregion
    
        $instanceIdBoxWidth = 210
        $systemDrawingPointWidth = 215
        $SystemDrawingSizeWidth = 600
        $showInstanceId = $true
    
        #region Generated Form Objects
        $ExplorerForm = New-Object System.Windows.Forms.Form
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        #endregion Generated Form Objects
    
    
        $OnLoadForm_StateCorrection=
        {#Correct the initial state of the form to prevent the .Net maximized form issue
        $ExplorerForm.WindowState = $InitialFormWindowState
        }
    
        #———————————————-
        #region Generated Form Code
        $ExplorerForm.Text = "$HandlerFunc NC:$NCIP"
        $ExplorerForm.Name = "$HandlerFunc NC:$NCIP"
        $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0
    
        # panel to have scroll bar
        $panel = New-Object System.Windows.Forms.Panel
        $panel.BackColor = [System.Drawing.Color]::Silver
        $panel.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $panel.Location = New-Object System.Drawing.Point (5,5)
    
        $extraSpace = 0
    
        $dataArr = @()
        $dataArr += &$HandlerFunc
    
        $failed = $false
        foreach ($data in $dataArr)
        {
            if ($data.PSobject.Properties.name -match "nextLink")
            {
                $failed = $true
                break;
            }
        }
    
        $System_Drawing_Point = New-Object System.Drawing.Point
        $System_Drawing_Point.X = 80
        $System_Drawing_Point.Y = 20
    
        if ($HandlerFunc -eq "Get-NCConnectivityCheckResult")
        {
            $diagButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 240
            $System_Drawing_SizeButton.Height = 23
            $diagButton.TabIndex = 0
            $diagButton.Name = $data.resourceRef
            $diagButton.Size = $System_Drawing_SizeButton
            $diagButton.UseVisualStyleBackColor = $True
            $diagButton.Text = "PUT=>/diagnostics/networkcontrollerstate"
            $diagButton.Location = $System_Drawing_Point
            $diagButton.DataBindings.DefaultDataSourceUpdateMode = 0
            $diagButton_add = $diagButton.add_Click
            $diagButton_add.Invoke({
    
                try
                {
                    $verify = VerifyUserAction -String "Do you want to Put networkcontrollerstate?"
    
                    if ($verify -eq $true)
                    {
                        $object = @{}
                        $object.properties = @{}
                        JSONPost -path "/diagnostics/networkcontrollerstate" -bodyObject $object
                        [System.Windows.Forms.MessageBox]::Show("Posted!!!")
                    }
                }
                catch
                {
                    [System.Windows.Forms.MessageBox]::Show($_)
                }
                })
            $panel.Controls.Add($diagButton)
            $System_Drawing_Point.Y += 33
    
    
            # Adding network controller statistics button
            $ncStatsButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 240
            $System_Drawing_SizeButton.Height = 23
            $ncStatsButton.TabIndex = 1
            $ncStatsButton.Name = $data.resourceRef
            $ncStatsButton.Size = $System_Drawing_SizeButton
            $ncStatsButton.UseVisualStyleBackColor = $True
            $ncStatsButton.Text = "GET=>/monitoring/networkcontrollerstatistics"
            $ncStatsButton.Location = $System_Drawing_Point
            $ncStatsButton.DataBindings.DefaultDataSourceUpdateMode = 0
            $ncStatsButton_add = $ncStatsButton.add_Click
    
            $ncStatsButton_add.Invoke({
                    param([object]$sender)
    
                    if($EnableMultiWindow)
                    {
                        $ps = [powershell]::create()
    
                        $script = {
                            param(
                            [string] $ResourceRef,
    
                            [string] $NCIP,
    
                            [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty,
    
                            [string]$CurWorDir,
    
                            [bool]$EnableMultiWindow,
    
                            [string]$RestApiVersion
    
                            )
                                try{
    
                                    Set-Location $CurWorDir
                                    # Import-Module -Force -Name .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                                    # $Global:NCApiVersion = $RestApiVersion

                                    Ipmo .\SdnExplorer.psm1
                                    Init-SdnExplorer -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true -IsModule $false

                                    JsonForm -ResourceRef $ResourceRef -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true
                                }
                                catch{
                                    [System.Windows.Forms.MessageBox]::Show($_)
                                }
                            }
                            $parameters = @{}
                            $parameters.ResourceRef = "/monitoring/networkcontrollerstatistics"
                            $parameters.NCIP = $NCIP
                            $parameters.NCCredential = $NCCredential
                            $parameters.CurWorDir = $pwd
                            $parameters.EnableMultiWindow = $EnableMultiWindow
    
                            $parameters.RestApiVersion = $Global:NCApiVersion
    
                            $ps.AddScript(
                                $script
                            )
    
                        $ps.AddParameters($parameters)
                        $ps.BeginInvoke()
                    }
                    else
                    {
                        JsonForm -ResourceRef $sender.Text -NCIP $NCIP -NCCredential $NCCredential
                    }
    
                    })
            $panel.Controls.Add($ncStatsButton)
            $System_Drawing_Point.Y += 33
    
            $debugSFNSButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 240
            $System_Drawing_SizeButton.Height = 23
            $debugSFNSButton.TabIndex = 0
            $debugSFNSButton.Name = "Debug-ServiceFabricNodeStatus"
            $debugSFNSButton.Size = $System_Drawing_SizeButton
            $debugSFNSButton.UseVisualStyleBackColor = $True
            $debugSFNSButton.Text = "Debug-ServiceFabricNodeStatus"
            $debugSFNSButton.Location = $System_Drawing_Point
            $debugSFNSButton.DataBindings.DefaultDataSourceUpdateMode = 0
            $debugSFNSButton_add = $debugSFNSButton.add_Click
            $debugSFNSButton.Enabled = $false
            $debugSFNSButton_add.Invoke({
    
                if ($EnableMultiWindow)
                {
                    $ps = [powershell]::create()
    
                    $script = {
                        param(
    
                        [string]$Cmdlet,
    
                        [object]$NCVMCredential=  [System.Management.Automation.PSCredential]::Empty,
    
                        [string] $NCIP,
    
                        [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty,
    
                        [string]$CurWorDir,
    
                        [bool]$EnableMultiWindow,
    
                        [string]$RestApiVersion
                        )
    
                        try{
                                Set-Location $CurWorDir
    
                                #Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                                Ipmo .\SdnExplorer.psm1
                                Init-SdnExplorer -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true -IsModule $false

                                $Global:NCApiVersion = $RestApiVersion
                                RunNCCMDLet -CmdLet $Cmdlet -NCVMCred $NCVMCredential -NCIP $NCIP
                        }
                            catch{
                                [System.Windows.Forms.MessageBox]::Show($_)
                            }
                        }
                        $parameters = @{}
                        $parameters.Cmdlet = "Debug-ServiceFabricNodeStatus"
                        $parameters.NCVMCredential = $NCVMCredential
                        $parameters.NCIP = $NCIP
                        $parameters.NCCredential = $NCCredential
                        $parameters.CurWorDir = $pwd
                        $parameters.EnableMultiWindow = $EnableMultiWindow
                        $parameters.RestApiVersion = $Global:NCApiVersion
                        $ps.AddScript(
                            $script
                        )
                    $ps.AddParameters($parameters)
                    $ps.BeginInvoke()
                }
                else
                {
                    RunNCCMDLet -CmdLet "Debug-ServiceFabricNodeStatus" -NCVMCred $NCVMCredential -NCIP $NCIP
                }
            })
            $panel.Controls.Add($debugSFNSButton)
            $System_Drawing_Point.Y += 33
    
            $debugNCCSButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 240
            $System_Drawing_SizeButton.Height = 23
            $debugNCCSButton.TabIndex = 0
            $debugNCCSButton.Name = "Debug-NetworkControllerConfigurationState"
            $debugNCCSButton.Size = $System_Drawing_SizeButton
            $debugNCCSButton.UseVisualStyleBackColor = $True
            $debugNCCSButton.Text = "Debug-NetworkControllerConfigurationState"
            $debugNCCSButton.Location = $System_Drawing_Point
            $debugNCCSButton.DataBindings.DefaultDataSourceUpdateMode = 0
            $debugNCCSButton_add = $debugNCCSButton.add_Click
            $debugNCCSButton_add.Invoke({
    
                if ($EnableMultiWindow)
                {
                    $ps = [powershell]::create()
    
                    $script = {
                        param(
    
                        [string]$Cmdlet,
    
                        [object]$NCVMCredential=  [System.Management.Automation.PSCredential]::Empty,
    
                        [string] $NCIP,
    
                        [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty,
    
                        [string]$CurWorDir,
    
                        [bool]$EnableMultiWindow,
    
                        [string]$RestApiVersion
                        )
    
                        try{
                                Set-Location $CurWorDir
    
                                # Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                                Ipmo .\SdnExplorer.psm1
                                Init-SdnExplorer -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true -IsModule $false

                                $Global:NCApiVersion = $RestApiVersion
                                RunNCCMDLet -CmdLet $Cmdlet -NCVMCred $NCVMCredential -NCIP $NCIP
                        }
                            catch{
                                [System.Windows.Forms.MessageBox]::Show($_)
                            }
                        }
                        $parameters = @{}
                        $parameters.Cmdlet = "Debug-NetworkControllerConfigurationState"
                        $parameters.NCVMCredential = $NCVMCredential
                        $parameters.NCIP = $NCIP
                        $parameters.NCCredential = $NCCredential
                        $parameters.CurWorDir = $pwd
                        $parameters.EnableMultiWindow = $EnableMultiWindow
                        $parameters.$RestApiVersion = $Global:NCApiVersion
                        $ps.AddScript(
                            $script
                        )
                    $ps.AddParameters($parameters)
                    $ps.BeginInvoke()
                }
                else
                {
                    RunNCCMDLet -CmdLet "Debug-NetworkControllerConfigurationState" -NCVMCred $NCVMCredential -NCIP $NCIP
                }
            })
            $panel.Controls.Add($debugNCCSButton)
            $System_Drawing_Point.Y += 33
    
            $debugNCButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 240
            $System_Drawing_SizeButton.Height = 23
            $debugNCButton.TabIndex = 0
            $debugNCButton.Name = "Debug-NetworkController"
            $debugNCButton.Size = $System_Drawing_SizeButton
            $debugNCButton.UseVisualStyleBackColor = $True
            $debugNCButton.Text = "Debug-NetworkController"
            $debugNCButton.Location = $System_Drawing_Point
            $debugNCButton.DataBindings.DefaultDataSourceUpdateMode = 0
            $debugNCButton_add = $debugNCButton.add_Click
            $debugNCButton_add.Invoke({
    
                if ($EnableMultiWindow)
                {
                    $ps = [powershell]::create()
    
                    $script = {
                        param(
    
                        [string]$Cmdlet,
    
                        [object]$NCVMCredential=  [System.Management.Automation.PSCredential]::Empty,
    
                        [string] $NCIP,
    
                        [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty,
    
                        [string]$CurWorDir,
    
                        [bool]$EnableMultiWindow,
    
                        [string]$RestApiVersion
                        )
    
                        try{
                                Set-Location $CurWorDir
    
                                # Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                                Ipmo .\SdnExplorer.psm1
                                Init-SdnExplorer -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true -IsModule $false

                                $Global:NCApiVersion = $RestApiVersion
                                RunNCCMDLet -CmdLet $Cmdlet -NCVMCred $NCVMCredential -NCIP $NCIP
                        }
                            catch{
                                [System.Windows.Forms.MessageBox]::Show($_)
                            }
                        }
                        $parameters = @{}
                        $parameters.Cmdlet = "Debug-NetworkController"
                        $parameters.NCVMCredential = $NCVMCredential
                        $parameters.NCIP = $NCIP
                        $parameters.NCCredential = $NCCredential
                        $parameters.CurWorDir = $pwd
                        $parameters.EnableMultiWindow = $EnableMultiWindow
                        $parameters.RestApiVersion = $Global:NCApiVersion
                        $ps.AddScript(
                            $script
                        )
                    $ps.AddParameters($parameters)
                    $ps.BeginInvoke()
                }
                else
                {
                    RunNCCMDLet -CmdLet "Debug-NetworkController" -NCVMCred $NCVMCredential -NCIP $NCIP
                }
    
                [System.Windows.Forms.MessageBox]::Show("Started your request in background!!")
            })
    
            $panel.Controls.Add($debugNCButton)
            $System_Drawing_Point.Y += 33
    
            $getNCReplicaButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 240
            $System_Drawing_SizeButton.Height = 23
            $getNCReplicaButton.TabIndex = 0
            $getNCReplicaButton.Name = "Get-NetworkControllerReplica"
            $getNCReplicaButton.Size = $System_Drawing_SizeButton
            $getNCReplicaButton.UseVisualStyleBackColor = $True
            $getNCReplicaButton.Text = "Get-NetworkControllerReplica"
            $getNCReplicaButton.Location = $System_Drawing_Point
            $getNCReplicaButton.DataBindings.DefaultDataSourceUpdateMode = 0
            $getNCReplicaButton_add = $getNCReplicaButton.add_Click
            $getNCReplicaButton_add.Invoke({
    
                if ($EnableMultiWindow)
                {
                    $ps = [powershell]::create()
    
                    $script = {
                            param(
                            [string]$Cmdlet,
                            [object]$NCVMCredential=  [System.Management.Automation.PSCredential]::Empty,
                            [string] $NCIP,
                            [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty,
                            [string]$CurWorDir,
                            [bool]$EnableMultiWindow
                            )
    
                            try
                            {
                                Set-Location $CurWorDir
                                # Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                                Ipmo .\SdnExplorer.psm1
                                Init-SdnExplorer -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true -IsModule $false

                                RunNCCMDLet -CmdLet $Cmdlet -NCVMCred $NCVMCredential -NCIP $NCIP
                            }
                            catch
                            {
                                [System.Windows.Forms.MessageBox]::Show($_)
                            }
                        }
                        $parameters = @{}
                        $parameters.Cmdlet = "Get-NetworkControllerReplica -AllReplicas"
                        $parameters.NCVMCredential = $NCVMCredential
                        $parameters.NCIP = $NCIP
                        $parameters.NCCredential = $NCCredential
                        $parameters.CurWorDir = $pwd
                        $parameters.EnableMultiWindow = $EnableMultiWindow
                        $ps.AddScript(
                            $script
                        )
                        $ps.AddParameters($parameters)
                        $ps.BeginInvoke()
                }
                else
                {
                    RunNCCMDLet -CmdLet "Get-NetworkControllerReplica -AllReplicas" -NCVMCred $NCVMCredential -NCIP $NCIP
                }
    
            })
            $panel.Controls.Add($getNCReplicaButton)
            $System_Drawing_Point.Y += 33
    
            # slb state dump button
            $slbStateDumpButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 240
            $System_Drawing_SizeButton.Height = 23
            $slbStateDumpButton.TabIndex = 0
            $slbStateDumpButton.Name = "Get SlbStateDump"
            $slbStateDumpButton.Size = $System_Drawing_SizeButton
            $slbStateDumpButton.UseVisualStyleBackColor = $True
            $slbStateDumpButton.Text = "Get SlbStateDump"
            $slbStateDumpButton.Location = $System_Drawing_Point
            $slbStateDumpButton.DataBindings.DefaultDataSourceUpdateMode = 0
            $global:button = $slbStateDumpButton
            $slbStateDumpButton_add = $slbStateDumpButton.add_Click
            $slbStateDumpButton_add.Invoke({ 
                
                #$buttonRef.Text = "Loading..."
                $global:button.Text = "Loading..."
                if ($EnableMultiWindow)
                {
                    $ps = [powershell]::create()
    
                    $script = {
                            param(    
                            [string]$Cmdlet,
                            [object]$NCVMCredential=  [System.Management.Automation.PSCredential]::Empty,
                            [string] $NCIP,
                            [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty,    
                            [string]$CurWorDir,
                            [bool]$EnableMultiWindow
                            )
    
                            try
                            {
                                $headers = @{"Accept"="application/json"}
                                $content = "application/json; charset=UTF-8"
                                $network = "$NCIP/Networking/v1"
                                $slbStateRetry = 5
                                $maxRetryCount = 20
                                $method = "Put"
                                $uri = "https://$network/diagnostics/slbstate"
                                $body = '{"properties": { }}'
    
                                $result = Invoke-WebRequest -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing -Credential $NCCredential
                                #$result.Content
                                $resultObject = ConvertFrom-Json  $result.Content
                                $resultsUri = "https://$network/$($resultObject.properties.slbStateResult.resourceRef)"
                                $totalWait=0
                                do
                                {
                                    $totalWait += $slbStateRetry
                                    Start-Sleep -Seconds $slbStateRetry
                                    $tempResult = Invoke-WebRequest -Headers $headers -Method GET -Uri $resultsUri -UseBasicParsing -Credential $NCCredential
                                    $tempResultObject = ConvertFrom-Json  $tempResult.Content
                                }
                                until (($tempResultObject.properties.provisioningState) -ne "Updating" -or $totalWait -gt $slbStateRetry * $maxRetryCount)
    
                                Set-Location $CurWorDir
                                # Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                                Ipmo .\SdnExplorer.psm1
                                Init-SdnExplorer -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true -IsModule $false

                                JsonForm -ResourceRef $resultObject.properties.slbStateResult.resourceRef  -NCIP $NCIP -NCCredential $NCCredential  -EnableMultiWindow $EnableMultiWindow
                            }
                            catch
                            {
                                [System.Windows.Forms.MessageBox]::Show($_)
                            }
                        }
                        $parameters = @{}
                        $parameters.Cmdlet = "Get-NetworkControllerReplica -AllReplicas"
                        $parameters.NCVMCredential = $NCVMCredential
                        $parameters.NCIP = $NCIP
                        $parameters.NCCredential = $NCCredential
                        $parameters.CurWorDir = $pwd
                        $parameters.EnableMultiWindow = $EnableMultiWindow
                        $ps.AddScript(
                            $script
                        )
                        $ps.AddParameters($parameters)
                        $ps.BeginInvoke()
                        $global:button.Text = "Get SLBState"
                }
                else
                {
                    #RunNCCMDLet -CmdLet "Get-NetworkControllerReplica -AllReplicas" -NCVMCred $NCVMCredential -NCIP $NCIP
                    [System.Windows.Forms.MessageBox]::Show("SLB State not supported without multi window support");
                }
    
            })

            $panel.Controls.Add($slbStateDumpButton)
            $System_Drawing_Point.Y += 33
    
        }
        elseif ($HandlerFunc -eq "Get-NCServer")
        {
            $runButton = New-Object System.Windows.Forms.Button
            $System_Drawing_SizeButton = New-Object System.Drawing.Size
            $System_Drawing_SizeButton.Width = 280
            $System_Drawing_SizeButton.Height = 23
            $runButton.TabIndex = 0
            $runButton.Name = $data.resourceRef
            $runButton.Size = $System_Drawing_SizeButton
            $runButton.UseVisualStyleBackColor = $True
            $runButton.Text = "--Run Script Block--"
            $locationY = $System_Drawing_Point.Y + 1
            $runButton.Location = New-Object System.Drawing.Size(10,$locationY)
            $runButton.DataBindings.DefaultDataSourceUpdateMode = 0
            $runButton_add = $runButton.add_Click
            $runButton_add.Invoke({
                if ($EnableMultiWindow)
                {
                    $ps = [powershell]::create()
    
                    $script = {
                        param(
    
                        [object[]]$jsonObject,
    
                        [string]$CurWorDir,
    
                        [bool]$EnableMultiWindow,
    
                        [string]$RestApiVersion
                        )
    
                        try{
                                Set-Location $CurWorDir
    
                                # Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                                Ipmo .\SdnExplorer.psm1
                                Init-SdnExplorer -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true -IsModule $false

                                $Global:ApiVersion = $RestApiVersion
                                RunScriptForm -Servers $jsonObject
                        }
                            catch{
                                [System.Windows.Forms.MessageBox]::Show($_)
                            }
                        }
                        $parameters = @{}
                        $parameters.jsonObject = $dataArr
                        $parameters.CurWorDir = $pwd
                        $parameters.EnableMultiWindow = $EnableMultiWindow
                        $parameters.RestApiVersion = $Global:NCApiVersion
                        $ps.AddScript(
                            $script
                        )
                    $ps.AddParameters($parameters)
                    $ps.BeginInvoke()
                }
                else
                {
                    RunScriptForm -Servers $dataArr
                }
            })
            $panel.Controls.Add($runButton)
            $System_Drawing_Point.Y += 33
        }
    
        if ($dataArr -ne $null -and $dataArr.Count -gt 0 -and $failed -eq $false)
        {
            if ($dataArr.Count -ge 1)
            {
                if ($DataArr[0].resourceRef.Contains("networkInterfaces") -or $DataArr[0].resourceRef.Contains("loadBalancers"))
                {
                    $extraSpace = 40
                }
            }
    
            foreach ($data in $dataArr)
            {
                $System_Drawing_Point.X = 10
                $button = New-Object System.Windows.Forms.Button
                $button.TabIndex = 0
                $button.Name = $data.resourceRef
                $button.Size = New-Object System.Drawing.Size(280,23)
                $button.UseVisualStyleBackColor = $True
                $button.Text = $data.resourceRef
                $locationY = $System_Drawing_Point.Y + 1
                $button.Location = New-Object System.Drawing.Size(10,$locationY)
                $button.DataBindings.DefaultDataSourceUpdateMode = 0
                $button_add = $button.add_Click
                $button_add.Invoke({
    
                    param([object]$sender,[string]$message)
    
                    if($EnableMultiWindow)
                    {
                        $ps = [powershell]::create()
    
                        $script = {
                            param(
                            [string] $ResourceRef,
    
                            [string] $NCIP,
    
                            [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty,
    
                            [string]$CurWorDir,
    
                            [bool]$EnableMultiWindow,
    
                            [string]$RestApiVersion
    
                            )
                                try{
    
                                    Set-Location $CurWorDir
                                    # Import-Module -Force -Name .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                                    Ipmo .\SdnExplorer.psm1
                                    Init-SdnExplorer -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true -IsModule $false
    
                                    $Global:NCApiVersion = $RestApiVersion
    
                                    JsonForm -ResourceRef $ResourceRef -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true
                                }
                                catch{
                                    [System.Windows.Forms.MessageBox]::Show($_)
                                }
                            }
                            $parameters = @{}
                            $parameters.ResourceRef = $sender.Text
                            $parameters.NCIP = $NCIP
                            $parameters.NCCredential = $NCCredential
                            $parameters.CurWorDir = $pwd
                            $parameters.EnableMultiWindow = $EnableMultiWindow
                            $parameters.RestApiVersion = $Global:NCApiVersion
    
                            $ps.AddScript(
                                $script
                            )
                        $ps.AddParameters($parameters)
                        $ps.BeginInvoke()
                    }
                    else
                    {
                        JsonForm -ResourceRef $sender.Text -NCIP $NCIP -NCCredential $NCCredential
                    }
    
                    })
                $panel.Controls.Add($button)
                $System_Drawing_Point.X += 285
    
                if ($HandlerFunc -eq "Get-NCMacPool")
                {
                    $showInstanceId = $false
                    $SystemDrawingSizeWidth = 700
    
                    $macBox = New-Object System.Windows.Forms.TextBox
                    $locationY = $System_Drawing_Point.Y + 1
                    $locationX = $System_Drawing_Point.X + 1
                    $macBox.Location = New-Object System.Drawing.Size($locationX,$locationY)
                    $macBox.Multiline = $false
                    $macBox.WordWrap = $false
                    $macBox.Size = New-Object System.Drawing.Size(100,23)
    
                    try
                    {
                        $macBox.Text = $data.properties.startMacAddress
                    }
                    catch
                    {
                        $macBox.Text = "NULL"
                    }
                    $macBox.Enabled = $false
                    $panel.Controls.Add($macBox)
                    $System_Drawing_Point.X += 105
    
                    $macBox = New-Object System.Windows.Forms.TextBox
                    $locationY = $System_Drawing_Point.Y + 1
                    $locationX = $System_Drawing_Point.X + 1
                    $macBox.Location = New-Object System.Drawing.Size($locationX,$locationY)
                    $macBox.Multiline = $false
                    $macBox.WordWrap = $false
                    $macBox.Size = New-Object System.Drawing.Size(100,23)
    
                    try
                    {
                        $macBox.Text = $data.properties.endMacAddress
                    }
                    catch
                    {
                        $macBox.Text = "NULL"
                    }
                    $macBox.Enabled = $false
                    $panel.Controls.Add($macBox)
                    $System_Drawing_Point.X += 105
                }
    
                if ($data.resourceRef.Contains("networkInterfaces"))
                {
                    $ipBox = New-Object System.Windows.Forms.TextBox
                    $locationY = $System_Drawing_Point.Y + 1
                    $locationX = $System_Drawing_Point.X + 1
                    $ipBox.Location = New-Object System.Drawing.Size($locationX,$locationY)
                    $ipBox.Multiline = $false
                    $ipBox.WordWrap = $false
                    $ipBox.Size = New-Object System.Drawing.Size(80,23)
    
                    try
                    {
                        $ipBox.Text = $data.properties.ipConfigurations[0].properties.privateIPAddress
                    }
                    catch
                    {
                        $ipBox.Text = "NULL"
                    }
                    $ipBox.Enabled = $false
                    $panel.Controls.Add($ipBox)
                    $System_Drawing_Point.X += 85
                }
                elseif ($data.resourceRef.Contains("loadBalancers"))
                {
                    $ipBox = New-Object System.Windows.Forms.TextBox
                    $locationY = $System_Drawing_Point.Y + 1
                    $locationX = $System_Drawing_Point.X + 1
                    $ipBox.Location = New-Object System.Drawing.Size($locationX,$locationY)
                    $ipBox.Multiline = $false
                    $ipBox.WordWrap = $false
                    $ipBox.Size = New-Object System.Drawing.Size(80,23)
    
                    try
                    {
                        $ipBox.Text = $data.properties.frontendIPConfigurations[0].properties.privateIPAddress
                    }
                    catch
                    {
                        $ipBox.Text = "NULL"
                    }
                    $ipBox.Enabled = $false
                    $panel.Controls.Add($ipBox)
                    $System_Drawing_Point.X += 85
                }
                elseif ($data.resourceRef.Contains("servers"))
                {
                    $serverBox = New-Object System.Windows.Forms.TextBox
                    $locationY = $System_Drawing_Point.Y + 1
                    $locationX = $System_Drawing_Point.X + 1
                    $serverBox.Location = New-Object System.Drawing.Size($locationX,$locationY)
                    $serverBox.Multiline = $false
                    $serverBox.WordWrap = $false
                    $serverBox.Size = New-Object System.Drawing.Size(310,23)
    
                    $text = $data.properties.connections[0].managementAddresses -join ","
                    foreach ($address in $data.properties.connections[0].managementAddresses)
                    {
                        try
                        {
                            [ipaddress]$address
                        }
                        catch
                        {
                            # Move ServerName to beginning of list
                            $TempArray = $data.properties.connections[0].managementAddresses | Where-Object {$_ -notmatch $address}
                            $text = @($address,$TempArray) -join ","
                        }
                        $instanceIdBoxWidth = 55
                        $systemDrawingPointWidth = 60
                        $SystemDrawingSizeWidth = 650
                    }
    
                    $serverBox.Text = $text
                    $serverBox.Enabled = $false
                    $panel.Controls.Add($serverBox)
                    $System_Drawing_Point.X += 315
                }
    
                if ($showInstanceId)
                {
                    $instanceidbox = New-Object System.Windows.Forms.TextBox
                    $locationY = $System_Drawing_Point.Y + 1
                    $locationX = $System_Drawing_Point.X + 1
                    $instanceidbox.Location = New-Object System.Drawing.Size($locationX,$locationY)
                    $instanceidbox.Multiline = $false
                    $instanceidbox.WordWrap = $false
                    $instanceidbox.Size = New-Object System.Drawing.Size($instanceIdBoxWidth,23)
                    $instanceidbox.Text = $data.instanceid
                    $instanceidbox.Enabled = $false
                    $panel.Controls.Add($instanceidbox)
                    $System_Drawing_Point.X += $systemDrawingPointWidth
                    $extraSpace = 100
                }
    
                $ProvisioningStateLabel = New-Object System.Windows.Forms.Label
                $System_Drawing_SizeButton = New-Object System.Drawing.Size
                $System_Drawing_SizeButton.Width = 80
                $System_Drawing_SizeButton.Height = 21
                $ProvisioningStateLabel.TabIndex = 0
                $ProvisioningStateLabel.Name = "Provisioning State"
                $ProvisioningStateLabel.Size = $System_Drawing_SizeButton
                $ProvisioningStateLabel.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
    
                $provisioningState = ""
                if ($data.resourceRef.Contains("connectivityCheckResults"))
                {
                    $provisioningState = $data.properties.result.status
                    switch($data.properties.result.status)
    {
                        "Success" { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Green }
                        "Failure" { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Red }
                        default { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Yellow }
                    }
                }
                else
                {
                    $provisioningState = $data.properties.provisioningState
                    switch($data.properties.provisioningState)
    {
                        "Succeeded" { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Green }
                        "Failed" { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Red }
                        default { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Yellow }
                    }
                }
                $ProvisioningStateLabel.BackColor = [System.Drawing.Color]::Silver;
                $ProvisioningStateLabel.Text = $provisioningState
                $ProvisioningStateLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
                $locationX = $System_Drawing_Point.X + 5
                $ProvisioningStateLabel.Location = New-Object System.Drawing.Size($locationX,($System_Drawing_Point.Y + 1))
                $ProvisioningStateLabel.DataBindings.DefaultDataSourceUpdateMode = 0
                $panel.Controls.Add($ProvisioningStateLabel)
                $System_Drawing_Point.X += 85
    
                $DeleteButton = New-Object System.Windows.Forms.Button
                $System_Drawing_SizeButton = New-Object System.Drawing.Size
                $System_Drawing_SizeButton.Width = 60
                $System_Drawing_SizeButton.Height = 23
                $DeleteButton.TabIndex = 0
                $DeleteButton.Name = $data.resourceId
                $DeleteButton.Size = $System_Drawing_SizeButton
                $DeleteButton.UseVisualStyleBackColor = $True
                $DeleteButton.Text = "Delete"
                $locationX = $System_Drawing_Point.X + 5
                $DeleteButton.Location = New-Object System.Drawing.Size($locationX,$System_Drawing_Point.Y)
                $DeleteButton.DataBindings.DefaultDataSourceUpdateMode = 0
    
                $DeleteButton_add = $DeleteButton.add_Click
                $DeleteButton_add.Invoke({
                    param([object]$sender,[string]$message)
    
                    $verify = VerifyUserAction
    
                    if ($verify -eq $true)
    {
                        &$RemoveFunc -ResourceIDs $sender.Name
                        $ExplorerForm.Close()
                    }
                    })
                $panel.Controls.Add($DeleteButton)
                $System_Drawing_Point.Y += 33
            }
        }
    
        elseif ($HandlerFunc -ne "Get-NCConnectivityCheckResult")
        {
    
            [System.Windows.Forms.MessageBox]::Show("Not Configured!!!!")
            return;
        }
    
        if($System_Drawing_Point.Y -ge 700)
        {
            $yPoint = 700
        }
        else
        {
            $yPoint = $System_Drawing_Point.Y + 50
        }
    
        $System_Drawing_Size = New-Object System.Drawing.Size
        $System_Drawing_Size.Width = $SystemDrawingSizeWidth + ( 2 * $extraSpace)
        $System_Drawing_Size.Height = $yPoint
        $ExplorerForm.ClientSize = $System_Drawing_Size
    
        $System_Drawing_Size.Width -= 10
        $System_Drawing_Size.Height -= 10
        $panel.Size = $System_Drawing_Size
        $panel.AutoScroll = $true
        $ExplorerForm.Controls.Add($panel)
    
        #endregion Generated Form Code
    
        #Save the initial state of the form
        $InitialFormWindowState = $ExplorerForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $ExplorerForm.add_Load($OnLoadForm_StateCorrection)
        #Show the Form
        $ExplorerForm.ShowDialog()| Out-Null
    
}


function JsonForm {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $ResourceRef,
    
            [Parameter(mandatory=$true)]
            [string] $NCIP,
    
            [Parameter(mandatory=$true)]
            [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty,
    
            [Parameter(mandatory=$false)]
            [bool] $EnableMultiWindow=$true
        )
    
        #. .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential
    
        [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
        [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
        #endregion
    
        #region Generated Form Objects
        $ExplorerForm = New-Object System.Windows.Forms.Form
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        $objTextBoxVFP = $null
        #endregion Generated Form Objects
    
    
        $OnLoadForm_StateCorrection=
        {#Correct the initial state of the form to prevent the .Net maximized form issue
            $ExplorerForm.WindowState = $InitialFormWindowState
        }
    
        #———————————————-
        #region Generated Form Code
        $ExplorerForm.Text = "$ResourceRef NC:$NCIP $pwd"
        $ExplorerForm.Name = "$ResourceRef NC:$NCIP"
        $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0
    
        $ExplorerForm.ClientSize = New-Object System.Drawing.Size(700,800)
    
        $jsonObject = JSONGet -NetworkControllerRestIP $NCIP -path $ResourceRef -credential $NCCredential
    
        $getBox = New-Object System.Windows.Forms.TextBox
        $getBox.Location = New-Object System.Drawing.Size(40,20)
        $getBox.Multiline = $true
        $getBox.ScrollBars = [System.Windows.Forms.ScrollBars]::Both
    
        $getBox.WordWrap = $false
        $getBox.Size = New-Object System.Drawing.Size(250,60)
        $getBox.Text = "Any Resource reference"
        $getBox.add_Click({
                $getBox.Text = ""
        })
        $ExplorerForm.Controls.Add($getBox)
    
    
        $button1 = New-Object System.Windows.Forms.Button
        $button1.TabIndex = 0
        $button1.Name = "Get"
        $button1.Size = New-Object System.Drawing.Size(80,60)
        $button1.UseVisualStyleBackColor = $True
        $button1.Text = "Get"
        $button1.Location = New-Object System.Drawing.Size(310,20)
        $button1.DataBindings.DefaultDataSourceUpdateMode = 0
    
        $scriptBlock = {
    
            if ($EnableMultiWindow)
            {
                $ps = [powershell]::create()
    
                $script = {
                    param(
                    [string] $ResourceRef,
    
                    [string] $NCIP,
    
                    [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty,
    
                    [string]$CurWorDir,
    
                    [bool]$EnableMultiWindow,
    
                    [string]$RestApiVersion
                    )
                        try{
                            Set-Location $CurWorDir
                            Import-Module -Force -Name .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                            $Global:NCApiVersion = $RestApiVersion
                            JsonForm -ResourceRef $ResourceRef -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true
                        }
                        catch{
                            [System.Windows.Forms.MessageBox]::Show($_)
                        }
                    }
                    $parameters = @{}
                    $parameters.ResourceRef = $getBox.Text
                    $parameters.NCIP = $NCIP
                    $parameters.NCCredential = $NCCredential
                    $parameters.CurWorDir = $pwd
                    $parameters.EnableMultiWindow = $EnableMultiWindow
                    $parameters.RestApiVersion = $Global:NCApiVersion
                    $ps.AddScript(
                        $script
                    )
                $ps.AddParameters($parameters)
                $ps.BeginInvoke()
            }
            else
            {
                JsonForm -ResourceRef $getBox.Text -NCIP $NCIP -NCCredential $NCCredential
            }
        }
    
        $button1.add_Click($scriptBlock)
        $ExplorerForm.Controls.Add($button1)
    
        $buttonPost = New-Object System.Windows.Forms.Button
        $buttonPost.TabIndex = 0
        $buttonPost.Name = "Post"
        $buttonPost.Size = New-Object System.Drawing.Size(80,60)
        $buttonPost.UseVisualStyleBackColor = $True
        $buttonPost.Text = "Post"
        $buttonPost.Location = New-Object System.Drawing.Size(410,20)
        $buttonPost.DataBindings.DefaultDataSourceUpdateMode = 0
        $scriptBlockPost = {
            $body = ConvertFrom-Json $objTextBox.Text
            $parse = $ResourceRef.Split("/")
            $rid = ""
    
            for($it = 0 ;$it -lt $parse.Count -1; $it++)
            {
                if( -not [string]::IsNullOrEmpty($parse[$it]))
                {
                    $rid += "/"
                    $rid += $parse[$it]
                }
            }
    
            try
            {
                JSONPost -path $rid -bodyObject $body
                $donePopup = New-Object -ComObject Wscript.Shell
                $donePopup.Popup("Done!!!", 1)
            }
            catch
            {
                [System.Windows.Forms.MessageBox]::Show("$_")
            }
        }
        $buttonPost.add_Click($scriptBlockPost)
        $ExplorerForm.Controls.Add($buttonPost)
        $objTextBox = New-Object System.Windows.Forms.RichTextBox
        $objTextBox.Location = New-Object System.Drawing.Size(40,120)
        $objTextBox.Multiline = $true
        $objTextBox.ScrollBars = [System.Windows.Forms.ScrollBars]::Both
    
        # Formats JSON in a nicer format than the built-in ConvertTo-Json does.
        function Format-Json([Parameter(Mandatory, ValueFromPipeline)][String] $json) {
            $indent = 2;
            ($json -Split "`n" | % {
                if ($_ -match '[\}\]]\s*,?\s*$') {
                    # This line ends with ] or }, decrement the indentation level
                    $indent--
                }
                $line = (' ' * $indent) + $($_.TrimStart() -replace '": (["{[])', '": $1' -replace ': ', ': ')
                if ($_ -match '[\{\[]\s*$') {
                    # This line ends with [ or {, increment the indentation level
                    $indent++
                }
                $line
            }) -Join "`n"
        }
    
        $objTextBox.WordWrap = $false
        $objTextBox.Size = New-Object System.Drawing.Size(600,630)
        $objTextBox.Text = $jsonObject | ConvertTo-Json -Depth 20 | Format-Json
        $objTextBox.ReadOnly = $false
        $objTextBox.Enabled = $true
    
        $ExplorerForm.Controls.Add($objTextBox)
    
        $SearchBox1 = New-Object System.Windows.Forms.RichTextBox
        $SearchBox1.Location = New-Object System.Drawing.Size(40,100)
        $SearchBox1.Multiline = $false
    
        $SearchBox1.WordWrap = $false
        $SearchBox1.Size = New-Object System.Drawing.Size(500,20)
        $SearchBox1.Text = "Enter Text to search here..."
        $SearchBox1.ForeColor = [Drawing.Color]::Gray
        $SearchBox1.add_Click({
            $SearchBox1.Text = ""
        })
        $SearchBox1.add_KeyPress({
    
        #Event Argument: $_ = [System.Windows.Forms.KeyEventArgs]
            if($_.KeyChar -eq 13)
            {
                &$scriptBlockfindButton
            }
            elseif ($SearchBox1.Text -eq "Enter Text to search here...")
            {
                $SearchBox1.Text = ""
            }
        })
        $ExplorerForm.Controls.Add($SearchBox1)
    
        $findButton = New-Object System.Windows.Forms.Button
        $findButton.TabIndex = 0
        $findButton.Name = "Find"
        $findButton.Size = New-Object System.Drawing.Size(100,20)
        $findButton.UseVisualStyleBackColor = $True
        $findButton.Text = "Find"
        $findButton.Location = New-Object System.Drawing.Size(540,100)
        $findButton.DataBindings.DefaultDataSourceUpdateMode = 0
        $scriptBlockfindButton = {
            $textBoxes = @()
            $textBoxes += $objTextBox
    
            if ($objTextBoxVFP -ne $null)
            {
                $textBoxes += $objTextBoxVFP
            }
            $searchStr = $SearchBox1.Text
            $found = $false
            foreach ( $textBox in $textBoxes)
            {
                $i = 0
                $textBox.Text -Split '\n' | % {
                $textBox.SelectionStart = $i
                $line = $_
                $textBox.SelectionLength = $line.Length
                if (Select-String -Pattern $searchStr -InputObject $line)
                {
                    $textBox.SelectionColor = [Drawing.Color]::DarkGreen
                    $textBox.SelectionBackColor = [Drawing.Color]::White
    
                    if (-not $found)
   {
                        $textBox.ScrollToCaret()
                        $found = $true
                    }
                }
                else
                {
                    $textBox.SelectionColor = [Drawing.Color]::Black
                    $textBox.SelectionBackColor = [System.Drawing.Color]::FromArgb(240,240,240)
                }
                $i += $line.Length + 1
                }
            }
    
            $searchBox1.ForeColor = [Drawing.Color]::Black
    
            if ($found)
            {
                $SearchBox1.ForeColor = [Drawing.Color]::DarkGreen
            }
            else
            {
                $SearchBox1.ForeColor = [Drawing.Color]::Red
                $SearchBox1.Text += " <-- NOT FOUND"
            }
    
        }
        $findButton.add_Click($scriptBlockfindButton)
        $ExplorerForm.Controls.Add($findButton)
    
        #endregion Generated Form Code
    
        #Save the initial state of the form
        $InitialFormWindowState = $ExplorerForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $ExplorerForm.add_Load($OnLoadForm_StateCorrection)
    
    
        if ($ResourceRef.Contains("virtualServers"))
        {
            $runCommand = New-Object System.Windows.Forms.Button
            $runCommand.TabIndex = 0
            $runCommand.Name = "Run Command"
            $runCommand.Size = New-Object System.Drawing.Size(80,60)
            $runCommand.UseVisualStyleBackColor = $True
            $runCommand.Text = "Run Command"
            $runCommand.Location = New-Object System.Drawing.Size(510,20)
            $runCommand.DataBindings.DefaultDataSourceUpdateMode = 0
            $scriptBlock = {
    
                foreach ($address in $jsonObject.properties.connections[0].managementAddresses)
                {
                    try
   {
                        [ipaddress]$address
    
                        try
       {
                            $ServerName = ([System.Net.Dns]::GetHostByAddress($address)).hostname
                        }
                        catch
       {
                            [System.Windows.Forms.MessageBox]::Show("GetHostByAddress failed!!!!")
                            return
                        }
                    }
                    catch
   {
                        $ServerName = $address
                        break;
                    }
                }
    
                if([string]::IsNullOrEmpty($ServerName))
                {
                    [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!")
                    return
                }
    
                start-process -FilePath powershell -ArgumentList @('-NoExit',"-command etsn $ServerName -Credential Get-Credential")
            }
            $runCommand.add_Click($scriptBlock)
            $ExplorerForm.Controls.Add($runCommand)
        }
        elseif ($ResourceRef.Contains("server"))
        {
            $ExplorerForm.ClientSize = New-Object System.Drawing.Size(900,800)
    
            $ovsdb = New-Object System.Windows.Forms.Button
            $ovsdb.TabIndex = 0
            $ovsdb.Name = "OVSDB Policies"
            $ovsdb.Size = New-Object System.Drawing.Size(100,40)
            $ovsdb.UseVisualStyleBackColor = $True
            $ovsdb.Text = "OVSDB Policies"
            $ovsdb.Location = New-Object System.Drawing.Size(700,100)
            $ovsdb.DataBindings.DefaultDataSourceUpdateMode = 0
            $scriptBlock1 = {
    
                if ($EnableMultiWindow)
                {
                    $ps = [powershell]::create()
    
                    $script = {
                        param(
    
                        [object]$jsonObject,
    
                        [string]$CurWorDir,
    
                        [bool]$EnableMultiWindow,
                        [string]$RestApiVersion
                        )
    
                        try{
                                Set-Location $CurWorDir
                                ipmo .\SdnExplorer.psm1
                                $Global:NCApiVersion = $RestApiVersion
                                OvsdbForm -Server $jsonObject -EnableMultiWindow $true
                        }
                            catch{
                                [System.Windows.Forms.MessageBox]::Show($_)
                            }
                        }
                        $parameters = @{}
                        $parameters.jsonObject = $jsonObject
                        $parameters.CurWorDir = $pwd
                        $parameters.EnableMultiWindow = $EnableMultiWindow
                        $parameters.RestApiVersion = $Global:NCApiVersion
                        $ps.AddScript(
                            $script
                        )
                    $ps.AddParameters($parameters)
                    $ps.BeginInvoke()
                }
                else
                {
                    OvsdbForm -Server $jsonObject
                }
            }
            $ovsdb.add_Click($scriptBlock1)
            $ExplorerForm.Controls.Add($ovsdb)
    
            $vfp = New-Object System.Windows.Forms.Button
            $vfp.TabIndex = 0
            $vfp.Name = "VFP Policies"
            $vfp.Size = New-Object System.Drawing.Size(100,40)
            $vfp.UseVisualStyleBackColor = $True
            $vfp.Text = "VFP Policies"
            $vfp.Location = New-Object System.Drawing.Size(700,160)
    
            $vfp.DataBindings.DefaultDataSourceUpdateMode = 0
            $scriptBlock2 = {
                if ($EnableMultiWindow)
                {
                    $ps = [powershell]::create()
    
                    $script = {
                        param(
                        [object]$jsonObject,
                        [string]$CurWorDir,
                        [string]$RestApiVersion
                        )
    
                        try{
                                Set-Location $CurWorDir
                                Import-Module .\SdnExplorer.psm1
                                $Global:NCApiVersion = $RestApiVersion
                                GetAllVFPPolices -Server $jsonObject -EnableMultiWindow $true
                            }
                            catch{
                                [System.Windows.Forms.MessageBox]::Show($_)
                            }
                        }
                        $parameters = @{}
                        $parameters.jsonObject = $jsonObject
                        $parameters.CurWorDir = $pwd
                        $parameters.RestApiVersion = $Global:NCApiVersion
                        $ps.AddScript(
                            $script
                        )
                    $ps.AddParameters($parameters)
                    $ps.BeginInvoke()
                }
                else
                {
                    GetAllVFPPolices -Server $jsonObject
                }
            }
            $vfp.add_Click($scriptBlock2)
            $ExplorerForm.Controls.Add($vfp)
    
            $runCommand = New-Object System.Windows.Forms.Button
            $runCommand.TabIndex = 0
            $runCommand.Name = "Run Command"
            $runCommand.Size = New-Object System.Drawing.Size(100,40)
            $runCommand.UseVisualStyleBackColor = $True
            $runCommand.Text = "Run Command"
            $runCommand.Location = New-Object System.Drawing.Size(700,220)
            $runCommand.DataBindings.DefaultDataSourceUpdateMode = 0
            $scriptBlock3 = {
    
                foreach ($address in $jsonObject.properties.connections[0].managementAddresses)
                {
                    try
   {
                        [ipaddress]$address
                    }
                    catch
   {
                        $ServerName = $address
                        break;
                    }
                }
    
                if([string]::IsNullOrEmpty($ServerName))
                {
                    [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!")
                    return
                }
    
                start-process -FilePath powershell -ArgumentList @('-NoExit',"-command etsn $ServerName")
            }
            $runCommand.add_Click($scriptBlock3)
            $ExplorerForm.Controls.Add($runCommand)
    
    
            $RDMA = New-Object System.Windows.Forms.Button
            $RDMA.TabIndex = 0
            $RDMA.Name = "Verify RDMA"
            $RDMA.Size = New-Object System.Drawing.Size(100,40)
            $RDMA.UseVisualStyleBackColor = $True
            $RDMA.Text = "Verify RDMA"
            $RDMA.Location = New-Object System.Drawing.Size(700,280)
            $RDMA.DataBindings.DefaultDataSourceUpdateMode = 0
            $scriptBlock4 = {
    
    
                foreach ($address in $jsonObject.properties.connections[0].managementAddresses)
                {
                    try
   {
                        [ipaddress]$address
                    }
                    catch
   {
                        $ServerName = $address
                        break;
                    }
                }
    
    
                RDMAValidation -ServerName $ServerName
            }
            $RDMA.add_Click($scriptBlock4)
            $ExplorerForm.Controls.Add($RDMA)
    
            $Cert = New-Object System.Windows.Forms.Button
            $Cert.TabIndex = 0
            $Cert.Name = "Verify Certs"
            $Cert.Size = New-Object System.Drawing.Size(100,40)
            $Cert.UseVisualStyleBackColor = $True
            $Cert.Text = "Verify Certs"
            $Cert.Location = New-Object System.Drawing.Size(700,340)
            $Cert.DataBindings.DefaultDataSourceUpdateMode = 0
            $scriptBlock5 = {
    
                foreach ($address in $jsonObject.properties.connections[0].managementAddresses)
                {
                    try
   {
                        [ipaddress]$address
                    }
                    catch
   {
                        $ServerName = $address
                        break;
                    }
                }
    
                VerifyCerts -NCIP $NCIP -ServerName $ServerName -ServerObject $jsonObject -NCCredential $NCCredential
            }
            $Cert.add_Click($scriptBlock5)
            $ExplorerForm.Controls.Add($Cert)
    
            $jumboPkt = New-Object System.Windows.Forms.Button
            $jumboPkt.TabIndex = 0
            $jumboPkt.Name = "Verify Jumbo pkt"
            $jumboPkt.Size = New-Object System.Drawing.Size(100,40)
            $jumboPkt.UseVisualStyleBackColor = $True
            $jumboPkt.Text = "Verify Jumbo pkt"
            $jumboPkt.Location = New-Object System.Drawing.Size(700,400)
            $jumboPkt.DataBindings.DefaultDataSourceUpdateMode = 0
            $scriptBlock6 = {
    
                foreach ($address in $jsonObject.properties.connections[0].managementAddresses)
                {
                    try
   {
                        [ipaddress]$address
                    }
                    catch
   {
                        $ServerName = $address
                        break;
                    }
                }
    
                VerifyJumboPkt -ServerName $ServerName -NCCredential $NCCredential
            }
            $jumboPkt.add_Click($scriptBlock6)
            $ExplorerForm.Controls.Add($jumboPkt)
        }
        elseif($ResourceRef.Contains("networkInterfaces"))
        {
            $ExplorerForm.ClientSize = New-Object System.Drawing.Size(1400,800)
    
            $scriptBlockVfpRules = {
    
                $objTextBoxVFP.text = "Extracting VFP Rules..."
    
                $ServerResource = $jsonObject.properties.server.resourceRef
    
                if(-not [string]::IsNullOrEmpty($ServerResource))
                {
                    $server = JSONGet -NetworkControllerRestIP $NCIP -path $ServerResource -credential $NCCredential
    
                    foreach ($address in $server.properties.connections[0].managementAddresses)
                    {
                        try
                        {
                            [ipaddress]$address
                        }
                        catch
                        {
                            $ServerName = $address
                            break;
                        }
                    }
    
                    if(-not [string]::IsNullOrEmpty($ServerName))
                    {
    
                        $mac = $jsonObject.properties.privateMacAddress
                        $mac = $mac -replace "-"
                        $mac = $mac -replace ":"
    
                        $scriptBlockVFP = {
    
                            param(
                                [Parameter(mandatory=$true)]
                                [string] $Mac
                            )
                            $vms = gwmi -na root\virtualization\v2 msvm_computersystem  | Where Description -Match "Virtual"
                            $port = $null
                            $vms | foreach {
                                $vm=$_; $vm.GetRelated("Msvm_SyntheticEthernetPort") |  foreach {
                                    $vma = $_;
                                    if($vma.PermanentAddress -eq $Mac)
                                    {
                                        $port = $vma.GetRelated("Msvm_SyntheticEthernetPortSettingData").GetRelated("Msvm_EthernetPortAllocationSettingData").GetRelated("Msvm_EthernetSwitchPort");
                                    }
                                }
                             }
    
                            $portGuid = $port.Name
                            $vfpCtrlExe = "vfpctrl.exe"
                            echo "Policy for port : " $portGuid
                            & $vfpCtrlExe /list-space  /port $portGuid
                            & $vfpCtrlExe /list-mapping  /port $portGuid
                            & $vfpCtrlExe /list-rule  /port $portGuid
                            & $vfpCtrlExe /port $portGuid /get-port-state
                        }
    
                        $text = @()
                        $text = RunServerCommand -ServerName $ServerName -scriptBlock $scriptBlockVFP -argumentList $mac
    
                        $objTextBoxVFP.Enabled = $true
    
                        $objTextBoxVFP.text = ""
    
                        foreach ($line in $text) {
                            $objTextBoxVFP.Appendtext($line)
                            $objTextBoxVFP.AppendText("`n")
                        }
                    }
                    else
                    {
                        [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!")
                    }
                }
                else
                {
                    [System.Windows.Forms.MessageBox]::Show("Server Resource Missing!!!!")
                }
            }
    
            $buttonVfpRule = New-Object System.Windows.Forms.Button
            $buttonVfpRule.TabIndex = 0
            $buttonVfpRule.Name = "VFP Rules"
            $buttonVfpRule.Size = New-Object System.Drawing.Size(80,60)
            $buttonVfpRule.UseVisualStyleBackColor = $True
            $buttonVfpRule.Text = "VFP Rules"
            $buttonVfpRule.Location = New-Object System.Drawing.Size(800,20)
            $buttonVfpRule.DataBindings.DefaultDataSourceUpdateMode = 0
            $buttonVfpRule.add_Click($scriptBlockVfpRules)
            $ExplorerForm.Controls.Add($buttonVfpRule)
    
            $buttonVfpRule = New-Object System.Windows.Forms.Button
            $buttonVfpRule.TabIndex = 0
            $buttonVfpRule.Name = "Start-CAPing"
            $buttonVfpRule.Size = New-Object System.Drawing.Size(80,60)
            $buttonVfpRule.UseVisualStyleBackColor = $True
            $buttonVfpRule.Text = "Start-CAPing"
            $buttonVfpRule.Location = New-Object System.Drawing.Size(700,20)
            $buttonVfpRule.DataBindings.DefaultDataSourceUpdateMode = 0
            $buttonVfpRule.add_Click(
            {
                CAPing -NCIP $NCIP -Source $jsonObject -NCCredential $NCCredential
            })
            $ExplorerForm.Controls.Add($buttonVfpRule)
    
            $objTextBoxVFP = New-Object System.Windows.Forms.RichTextBox
            $objTextBoxVFP.Location = New-Object System.Drawing.Size(700,100)
            $objTextBoxVFP.Multiline = $true
            $objTextBoxVFP.ScrollBars = [System.Windows.Forms.ScrollBars]::Both
    
            $objTextBoxVFP.WordWrap = $false
            $objTextBoxVFP.Size = New-Object System.Drawing.Size(600,650)
            $objTextBoxVFP.font = "lucida console"
            $objTextBoxVFP.Enabled = $false
            $objTextBoxVFP.ReadOnly = $true
            $ExplorerForm.Controls.Add($objTextBoxVFP)
        }
    
    
        #Show the Form
        $ExplorerForm.ShowDialog()| Out-Null
    
} #End Function JsonForm
    
    function GenerateArrayForm {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $HandlerFunc,
    
            [Parameter(mandatory=$true)]
            [string] $RemoveFunc,
    
            [Parameter(mandatory=$true)]
            [string] $NCIP,
    
            [Parameter(mandatory=$false)]
            [object]
            $NCCredential=  [System.Management.Automation.PSCredential]::Empty,
    
            [Parameter(mandatory=$true)]
            [bool]
            $EnableMultiWindow=$true
        )
    
        if ($HandlerFunc -eq "Get-NCConnectivityCheckResult" -and $script:ncVMCredentials -eq [System.Management.Automation.PSCredential]::Empty)
        {
            $script:ncVMCredentials = Get-Credential -Message "Please give administrator credential of NC" -UserName "Administrator"
        }
    
        Write-Host "Here! $NCIP $EnableMultiWindow"
        if($EnableMultiWindow)
        {
            $progress = [powershell]::create()
    
            $progressScript = {
                param(
                [string] $HandlerFunc,
                [string] $RemoveFunc,
                [string] $NCIP,
                [object] $NCCredential=  [System.Management.Automation.PSCredential]::Empty,
                [bool]   $EnableMultiWindow=$true,
                [string] $CurWorDir,
                [object] $NCVMCredential=  [System.Management.Automation.PSCredential]::Empty,
                [string] $RestApiVersion
                )
    
                try{
    
                    Set-Location $CurWorDir
    
    
                    # Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true
                    Ipmo .\SdnExplorer.psm1
                    Write-Host "Here! $NCIP"
                    Init-SdnExplorer -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true -IsModule $false

                    $Global:NCApiVersion = $RestApiVersion
    
                    GenerateArrayFormHelper -HandlerFunc $HandlerFunc -RemoveFunc $RemoveFunc -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $EnableMultiWindow -NCVMCredential $NCVMCredential
                }
                catch
                {
                     [System.Windows.Forms.MessageBox]::Show($_)
                }
            }
    
            $parameters = @{}
            $parameters.HandlerFunc = $HandlerFunc
            $parameters.RemoveFunc = $RemoveFunc
            $parameters.NCIP = $NCIP
            $parameters.NCCredential = $NCCredential
            $parameters.EnableMultiWindow = $EnableMultiWindow
            $parameters.CurWorDir = $pwd
            $parameters.NCVMCredential = $script:ncVMCredentials
            $parameters.RestApiVersion = $Global:NCApiVersion
    
            $progress.AddScript($progressScript)
            $progress.AddParameters($parameters)
            $progress.BeginInvoke()
    
        }
        else{
            GenerateArrayFormHelper -HandlerFunc $HandlerFunc -RemoveFunc $RemoveFunc -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $EnableMultiWindow -NCVMCredential $script:ncVMCredentials
        }
    
    }
    
    
    function RemoveObjForm {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $HandlerFunc,
    
            [Parameter(mandatory=$true)]
            [string] $GetFunc,
    
            [Parameter(mandatory=$true)]
            [string] $NCIP,
    
            [Parameter(mandatory=$false)]
            [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty
        )
    
        #. .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential
    
        try
        {
            $Allobjects = &$GetFunc
    
            $resourceIds = @()
            $resourceIds += "None"
            foreach ($obj in $Allobjects)
            {
                $resourceIds += $obj.resourceId
            }
    
            $selectedResource = RadioForm -Name "$HandlerFunc" -Values $resourceIds
    
            if ($selectedResource -ne "None")
            {
                &$HandlerFunc -ResourceIDs $selectedResource
            }
    
        }
        catch
        {
            [System.Windows.Forms.MessageBox]::Show($_)
        }
    
    }
    
    function PutNetworkInterface {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $HandlerFunc,
    
            [Parameter(mandatory=$true)]
            [string] $NCIP,
    
            [Parameter(mandatory=$false)]
            [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty
        )
    
        #. .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential
    
    
        try{
            $value = RadioForm -Name "Network type" -Values "Logical Network","Virtual Network"
    
            if ($value -eq "Logical Network")
            {
                $networks = Get-NCLogicalNetwork
            }
            else
            {
                $networks = Get-NCVirtualNetwork
            }
    
            $networkRefArray = @()
            foreach ($network in $networks)
            {
                $networkRefArray += $network.resourceId
            }
    
            $selectedNetworkId = RadioForm -Name "Network" -Values $networkRefArray
    
            if ($value -eq "Logical Network")
            {
                $network = Get-NCLogicalNetwork -ResourceID $selectedNetworkId
            }
            else
            {
                $network = Get-NCVirtualNetwork -resourceID $selectedNetworkId
            }
    
            $subnets = @()
            foreach ($subnet in $network.properties.subnets)
            {
                $subnets += $subnet.resourceId
            }
    
            $selectedSubnetId = RadioForm -Name "Subnet" -Values $subnets
    
            foreach ($snet in $network.properties.subnets)
            {
                if($snet.resourceId -eq $selectedSubnetId)
                {
                    $subnet = $snet
                    #break
                }
            }
    
            $ip = GetValueForm -Name "IP Address"
            if ([string]::IsNullOrEmpty($ip))
            {
                throw "Missing IP!!!!"
            }
    
            $mac = GetValueForm -Name "Mac Address"
            if ([string]::IsNullOrEmpty($mac))
            {
                throw "Missing Mac!!!!"
            }
    
            $DNSServer = GetValueForm -Name "DNS Server"
    
            $acls = Get-NCAccessControlList
    
            $aclRes = @()
            $aclRes += "None"
            foreach ( $aclObj in $acls)
            {
                $aclRes += $aclObj.resourceId
            }
            $selectedAclId = RadioForm -Name "Acl" -Values $aclRes
    
            $acl = $null
            foreach ( $aclObj in $acls)
            {
                if ($aclObj.resourceId -eq $selectedAclId)
                {
                    $acl = $aclObj
                }
            }
    
            $resId = [system.guid]::NewGuid()
            if ($value -eq "Logical Network")
            {
                $networkInterface = New-NCNetworkInterface -Subnet $subnet -IPAddress $ip -MACAddress $mac -DNSServers $DNSServer -acl $acl -resourceID $resId
            }
            else
            {
                $networkInterface = New-NCNetworkInterface -VirtualSubnet $subnet -IPAddress $ip -MACAddress $mac -DNSServers $DNSServer -acl $acl -resourceID $resId
            }
    
            $donePopup = New-Object -ComObject Wscript.Shell
            $donePopup.Popup("Done!!!", 1)
    
            JsonForm -ResourceRef $networkInterface.resourceRef  -NCIP $NCIP -NCCredential $NCCredential
    
        }
        catch
        {
            [System.Windows.Forms.MessageBox]::Show($_)
        }
    
    }
    
    function PutLoadBalancer {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $HandlerFunc,
    
            [Parameter(mandatory=$true)]
            [string] $NCIP,
    
            [Parameter(mandatory=$false)]
            [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty
        )
    
        Import-Module .\NetworkControllerWorkloadHelpers.psm1 -Force
        #. .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential
    
    
        try{
    
            $vip = GetValueForm -Name "VIP Address"
            if ([string]::IsNullOrEmpty($vip))
            {
                throw "Missing VIP!!!!"
            }
    
            $protocol = RadioForm -Name "Protocol" -Values "Tcp","Udp"
    
            $frontendPort = [int](GetValueForm -Name "Front End Port")
    
            $backendPort = [int](GetValueForm -Name "Front End Port")
    
            $enableOutboundNatstr = RadioForm -Name "Enable Outbound Nat" -Values "true","false"
    
            $enableOutboundNat = $false
            if ($enableOutboundNatstr -eq "true")
            {
                $enableOutboundNat = $true
            }
    
            #just to load all dependencies
            $slbm = get-ncloadbalancermanager
    
            if ($slbm.properties.vipippools.count -lt 1) {
                throw "New-LoadBalancerVIP requires at least one VIP pool in the NC Load balancer manager."
            }
    
            $vipPools = $slbm.properties.vipippools
    
            # check if the input VIP is within range of one of the VIP pools
            foreach ($vippool in $vipPools) {
                # IP pool's resourceRef is in this format:
                # /logicalnetworks/f8f67956-3906-4303-94c5-09cf91e7e311/subnets/aaf28340-30fe-4f27-8be4-40eca97b052d/ipPools/ed48962b-2789-41bf-aa7b-3e6d5b247384
                $sp = $vippool.resourceRef.split("/")
    
                $ln = Get-NCLogicalNetwork -resourceId $sp[2] #LN resourceid is always the first ID (after /logicalnetwork/)
                if (-not $ln) {
                    throw "Can't find logical network with resourceId $($sp[2]) from NC."
                }
    
                $subnet = $ln.properties.subnets | ? {$_.resourceId -eq $sp[4]}
                if (-not $subnet) {
                    throw "can't find subnet with resourceId $($sp[4]) from NC."
                }
    
                $pool = $subnet.properties.ipPools | ? {$_.resourceId -eq $sp[6]}
                if (-not $pool) {
                    throw "can't find IP pool with resourceId $($sp[6]) from NC."
                }
    
                $startIp = $pool.properties.startIpAddress
                $endIp = $pool.properties.endIpAddress
                if (IsIpWithinPoolRange -targetIp $vip -startIp $startIp -endIp $endIp) {
                    $isPoolPublic = $subnet.properties.isPublic
                    $vipLn = $ln
                    break;
                }
            }
    
            if (-not $vipLn) {
                throw "$vip is not within range of any of the VIP pools managed by SLB manager."
            }
    
            $lbfe = @(New-NCLoadBalancerFrontEndIPConfiguration -PrivateIPAddress $vip -Subnet ($vipLn.properties.Subnets[0]))
    
            $ips = @()
    
            $lbbe = @(New-NCLoadBalancerBackendAddressPool -IPConfigurations $ips)
            $rules = @(New-NCLoadBalancerLoadBalancingRule -protocol $protocol -frontendPort $frontendPort -backendport $backendPort -enableFloatingIP $False -frontEndIPConfigurations $lbfe -backendAddressPool $lbbe)
    
            $LoadBalancerResourceID = [system.guid]::NewGuid()
    
            if ($enableOutboundNat) {
                $onats = @(New-NCLoadBalancerOutboundNatRule -frontendipconfigurations $lbfe -backendaddresspool $lbbe)
                $lb = New-NCLoadBalancer -ResourceID $LoadBalancerResourceID -frontendipconfigurations $lbfe -backendaddresspools $lbbe -loadbalancingrules $rules -outboundnatrules $onats
            } else {
                $lb = New-NCLoadBalancer -ResourceID $LoadBalancerResourceID -frontendipconfigurations $lbfe -backendaddresspools $lbbe -loadbalancingrules $rules
            }
    
            $donePopup = New-Object -ComObject Wscript.Shell
            $donePopup.Popup("Done!!!", 1)
    
            JsonForm -ResourceRef $lb.resourceRef  -NCIP $NCIP -NCCredential $NCCredential
    
        }
        catch
        {
            [System.Windows.Forms.MessageBox]::Show($_)
        }
    
    }
    
    function RadioForm {
    
    [OutputType([string])]
    param(
            [string] $Name,
            [string[]] $Values
        )
    
    
        [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
        [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
        #endregion
    
        #region Generated Form Objects
        $ExplorerForm = New-Object System.Windows.Forms.Form
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        #endregion Generated Form Objects
    
    
        $OnLoadForm_StateCorrection=
        {#Correct the initial state of the form to prevent the .Net maximized form issue
        $ExplorerForm.WindowState = $InitialFormWindowState
        }
    
        #———————————————-
        #region Generated Form Code
        $ExplorerForm.Text = "Please select $Name"
        $ExplorerForm.Name = "$Name"
        $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0
    
        # panel to have scroll bar
        $panel = New-Object System.Windows.Forms.Panel
        $panel.BackColor = [System.Drawing.Color]::Silver
        $panel.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
        $panel.Location = New-Object System.Drawing.Point (5,5)
    
        $System_Drawing_Point = New-Object System.Drawing.Point
        $System_Drawing_Point.X = 80
        $System_Drawing_Point.Y = 20
        $radioButtons = @()
    
        for ($it = 0; $it -lt $Values.Count ;$it++)
        {
            $radioButton = New-Object System.Windows.Forms.RadioButton
            $radioButton.Location = $System_Drawing_Point
            $radioButton.Name = $Values[$it]
            $radioButton.TabIndex = 5
            $radioButton.Text = $Values[$it]
            $radioButton.Size = New-Object System.Drawing.Size(500, 20)
            $radioButtons += $radioButton
    
            if ([string]::IsNullOrEmpty($selectedValue))
            {
                $selectedValue = $Values[$it]
                $radioButton.Checked = $true
            }
    
            $System_Drawing_Point.Y += 33
        }
    
        $groupBox1 = New-Object System.Windows.Forms.GroupBox
        $groupBox1.Location = New-Object System.Drawing.Point(60, 10)
        $groupBox1.Name = "groupBox1 $Name"
        $groupBox1.Size = New-Object System.Drawing.Size(500, $System_Drawing_Point.Y)
        $groupBox1.TabIndex = 0
        $groupBox1.TabStop = $false
        $groupBox1.Text = "Select $Name"
        $groupBox1.Controls.AddRange($radioButtons)
        $panel.Controls.Add($groupBox1)
        $System_Drawing_Point.Y += 33
    
        $button = New-Object System.Windows.Forms.Button
        $System_Drawing_SizeButton = New-Object System.Drawing.Size
        $System_Drawing_SizeButton.Width = 240
        $System_Drawing_SizeButton.Height = 23
        $button.TabIndex = 0
        $button.Name = "Select"
        $button.Size = $System_Drawing_SizeButton
        $button.UseVisualStyleBackColor = $True
        $button.Text = "Select $Name"
        $button.Location = $System_Drawing_Point
        $button.DataBindings.DefaultDataSourceUpdateMode = 0
        #$scriptBlock = $DataArr[$it].Value
    
    
        $button.add_Click(
        {
            $ExplorerForm.Close()
        })
        $panel.Controls.Add($button)
    
        $System_Drawing_Point.Y += 33
    
        if($System_Drawing_Point.Y -ge 700)
        {
            $yPoint = 700
        }
        else
        {
            $yPoint = $System_Drawing_Point.Y + 50
        }
    
        $System_Drawing_Size = New-Object System.Drawing.Size
        $System_Drawing_Size.Width = 600
        $System_Drawing_Size.Height = $yPoint
        $ExplorerForm.ClientSize = $System_Drawing_Size
    
        $System_Drawing_Size.Width -= 10
        $System_Drawing_Size.Height -= 10
        $panel.Size = $System_Drawing_Size
        $panel.AutoScroll = $true
        $ExplorerForm.Controls.Add($panel)
    
        #endregion Generated Form Code
    
        #Save the initial state of the form
        $InitialFormWindowState = $ExplorerForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $ExplorerForm.add_Load($OnLoadForm_StateCorrection)
        #Show the Form
        $ExplorerForm.ShowDialog()| Out-Null
    
        foreach ($radioButton in $radioButtons)
        {
            if ($radioButton.Checked)
            {
                $selectedValue = $radioButton.Text
            }
        }
    
      return $selectedValue
    
    } #End Function RadioForm
    
    function GetValueForm {
    
    param(
            [string] $Name
        )
    
        [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
        [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
        #endregion
    
        #region Generated Form Objects
        $ExplorerForm = New-Object System.Windows.Forms.Form
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        $selectedValue = $null
        #endregion Generated Form Objects
    
    
        $OnLoadForm_StateCorrection=
        {#Correct the initial state of the form to prevent the .Net maximized form issue
        $ExplorerForm.WindowState = $InitialFormWindowState
        }
    
        #———————————————-
        #region Generated Form Code
        $ExplorerForm.Text = "Please select $Name"
        $ExplorerForm.Name = "$Name"
        $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0
    
        $System_Drawing_Point = New-Object System.Drawing.Point
        $System_Drawing_Point.X = 80
        $System_Drawing_Point.Y = 20
    
    
        $getBox = New-Object System.Windows.Forms.TextBox
        $getBox.Location = $System_Drawing_Point
        $getBox.Multiline = $false
        $getBox.WordWrap = $false
        $getBox.Size = New-Object System.Drawing.Size(240,23)
        $getBox.Text = ""
        $ExplorerForm.Controls.Add($getBox)
    
        $System_Drawing_Point.Y += 33
    
        $button = New-Object System.Windows.Forms.Button
        $System_Drawing_SizeButton = New-Object System.Drawing.Size
        $System_Drawing_SizeButton.Width = 240
        $System_Drawing_SizeButton.Height = 23
        $button.TabIndex = 0
        $button.Name = "Select"
        $button.Size = $System_Drawing_SizeButton
        $button.UseVisualStyleBackColor = $True
        $button.Text = "Select $Name"
        $button.Location = $System_Drawing_Point
        $button.DataBindings.DefaultDataSourceUpdateMode = 0
        $scriptBlock = $DataArr[$it].Value
        $button.add_Click(
        {
            $ExplorerForm.Close()
        })
        $ExplorerForm.Controls.Add($button)
    
        $System_Drawing_Point.Y += 33
    
        $System_Drawing_Size = New-Object System.Drawing.Size
        $System_Drawing_Size.Width = 600
        $System_Drawing_Size.Height = $System_Drawing_Point.Y + 50
        $ExplorerForm.ClientSize = $System_Drawing_Size
    
        #endregion Generated Form Code
    
        #Save the initial state of the form
        $InitialFormWindowState = $ExplorerForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $ExplorerForm.add_Load($OnLoadForm_StateCorrection)
        #Show the Form
        $ExplorerForm.ShowDialog()| Out-Null
    
        return $getBox.Text
    
    } #End Function GetValueForm
    
    function VerifyUserAction {
        param(
            [string] $String
        )
    
        [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
        [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
        #endregion
    
        #region Generated Form Objects
        $ExplorerForm = New-Object System.Windows.Forms.Form
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        $ret = $false
        #endregion Generated Form Objects
    
    
        $OnLoadForm_StateCorrection=
        {#Correct the initial state of the form to prevent the .Net maximized form issue
        $ExplorerForm.WindowState = $InitialFormWindowState
        }
    
        #———————————————-
        #region Generated Form Code
        if ([string]::IsNullOrEmpty($String))
        {
            $String = "DO YOU WANT TO CONTINUE???"
        }
        $ExplorerForm.Text = $String
        $ExplorerForm.Name = "Verify!!!"
        $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0
    
        $System_Drawing_Point = New-Object System.Drawing.Point
        $System_Drawing_Point.X = 80
        $System_Drawing_Point.Y = 20
    
        $Stop = New-Object System.Windows.Forms.Button
        $System_Drawing_SizeButton = New-Object System.Drawing.Size
        $System_Drawing_SizeButton.Width = 200
        $System_Drawing_SizeButton.Height = 23
        $Stop.TabIndex = 0
        $Stop.Name = "Stop"
        $Stop.Size = $System_Drawing_SizeButton
        $Stop.UseVisualStyleBackColor = $True
        $Stop.Text = "Stop"
        $Stop.Location = $System_Drawing_Point
        $Stop.DataBindings.DefaultDataSourceUpdateMode = 0
        $Stop.add_Click(
        {
            $ret = $false
            $ExplorerForm.Close()
        })
        $ExplorerForm.Controls.Add($Stop)
    
        $System_Drawing_Point.X += 210
    
        $Continue = New-Object System.Windows.Forms.Button
        $System_Drawing_SizeButton = New-Object System.Drawing.Size
        $System_Drawing_SizeButton.Width = 200
        $System_Drawing_SizeButton.Height = 23
        $Continue.TabIndex = 0
        $Continue.Name = "Continue"
        $Continue.Size = $System_Drawing_SizeButton
        $Continue.UseVisualStyleBackColor = $True
        $Continue.Text = "Continue"
        $Continue.Location = $System_Drawing_Point
        $Continue.DataBindings.DefaultDataSourceUpdateMode = 0
        $Continue.add_Click(
        {
            $Continue.Text = "true"
            $ExplorerForm.Close()
        })
        $ExplorerForm.Controls.Add($Continue)
    
        $System_Drawing_Point.Y += 33
    
        $System_Drawing_Size = New-Object System.Drawing.Size
        $System_Drawing_Size.Width = 570
        $System_Drawing_Size.Height = $System_Drawing_Point.Y + 50
        $ExplorerForm.ClientSize = $System_Drawing_Size
    
        #endregion Generated Form Code
    
        #Save the initial state of the form
        $InitialFormWindowState = $ExplorerForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $ExplorerForm.add_Load($OnLoadForm_StateCorrection)
        #Show the Form
    
        $ExplorerForm.ShowDialog()| Out-Null
    
        if ($Continue.Text -eq "true")
        {
            $ret = $True
        }
    
        return $ret
    
    } #End Function VerifyUserAction
    
    function RunNCCMDLet {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $Cmdlet,
            [Parameter(mandatory=$true)]
            [object] $NCVMCred,
            [Parameter(mandatory=$true)]
            [string] $NCIP
        )
        try
        {
            # Generate Random names for prefix
            $rand = New-Object System.Random
            $prefixLen = 8
            [string]$namingPrefix = ''
            for($i = 0; $i -lt $prefixLen; $i++)
            {
                $namingPrefix += [char]$rand.Next(65,90)
            }
    
    
            $ip = ([System.Net.Dns]::GetHostAddresses("$NCIP"))[0].IPAddressToString
            $cmdstring += " echo `"`n`r$ip $NCIP`" > C:\Windows\System32\drivers\etc\hosts;"
    
    
            if ($Cmdlet -eq "Debug-NetworkController")
            {
                $copyfolder = "Debug-NetworkController_$namingPrefix"
                $cmdstring += "$Cmdlet -NetworkController $ip -OutputDirectory c:\temp\Debug-NetworkController_$namingPrefix -RestURI https://$NCIP/networking/v1"
            }
            elseif ($Cmdlet -eq "Debug-NetworkControllerConfigurationState")
            {
                $cmdstring += "$Cmdlet -NetworkController $NCIP"
            }
    
            $output = @()
            if ($Cmdlet -eq "Get-NetworkControllerReplica -AllReplicas")
            {
                Invoke-Command -ComputerName $NCIP -FilePath .\getreplica.ps1 -Credential $NCVMCred
    
                $copyfolder = 'replica.txt'
                $psDriver = New-PSDrive -Name Y -PSProvider filesystem -Root \\$ip\c$ -Credential $NCVMCred
    
                Copy-Item Y:\$copyfolder $copyfolder -Recurse -Force
    
            }
            else
            {
                $scriptBlock = ([scriptblock]::Create($cmdstring))
    
                $result = Invoke-Command -ComputerName $NCIP -ScriptBlock $scriptBlock -Credential $NCVMCred
    
                if ($copyfolder)
                {
                    $psDriver = New-PSDrive -Name Y -PSProvider filesystem -Root \\$ip\c$\temp -Credential $NCVMCred
    
                    Copy-Item Y:\$copyfolder $copyfolder -Recurse -Force
                }
    
            }
    
            if ($Cmdlet -eq "Get-NetworkControllerReplica -AllReplicas")
            {
                $result = Get-Content $copyfolder
                DisplayTextForm -FormName $Cmdlet -Text $result
            }
            else
            {
                [System.Windows.Forms.MessageBox]::Show("$Cmdlet completed")
    
                if ($copyfolder)
                {
                    start .\$copyfolder
                }
                else
                {
                    DisplayTextForm -FormName $Cmdlet -Text $result
                }
            }
        }
        catch
        {
            [System.Windows.Forms.MessageBox]::Show($_)
        }
        finally
        {
            if ($psDriver)
            {
                Remove-PSDrive -Name Y
            }
        }
    
    }
    
function OvsdbForm {
    
    param(
            [Parameter(mandatory=$true)]
            [object] $Server,
            [Parameter(mandatory=$false)]
            [bool] $EnableMultiWindow=$true
        )
    
        [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
        [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
        #endregion
    
        if($EnableMultiWindow)
        {
            $progress = [powershell]::create()
    
            $progressScript = {
                    [System.Windows.Forms.MessageBox]::Show("Fetching Policies, it will take a few seconds to complete")
            }
            $progress.AddScript($progressScript)
    
            $progressObj = $progress.BeginInvoke()
        }
    
        foreach ($address in $Server.properties.connections[0].managementAddresses)
        {
            try
            {
                [ipaddress]$address
            }
            catch
            {
                $ServerName = $address
                break;
            }
        }
    
        if([string]::IsNullOrEmpty($ServerName))
        {
            [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!")
            return
        }
    
        #region Generated Form Objects
        $ExplorerForm = New-Object System.Windows.Forms.Form
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        #endregion Generated Form Objects
    
    
        $OnLoadForm_StateCorrection=
        {#Correct the initial state of the form to prevent the .Net maximized form issue
        $ExplorerForm.WindowState = $InitialFormWindowState
        }
    
        #———————————————-
        #region Generated Form Code
        $ExplorerForm.Text = $ServerName
        $ExplorerForm.Name = $ServerName
        $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0
    
        $ExplorerForm.ClientSize = New-Object System.Drawing.Size(900,800)
    
        $vtep = @()
        $vtep = GetOvsDBVtep -ServerName $ServerName
    
        $firewall = @()
        $firewall = GetOvsDBfirewall -ServerName $ServerName
    
    
        $objTextBoxVtep = New-Object System.Windows.Forms.RichTextBox
        $objTextBoxVtep.Location = New-Object System.Drawing.Size(40,100)
        $objTextBoxVtep.Multiline = $true
        $objTextBoxVtep.ScrollBars = [System.Windows.Forms.ScrollBars]::Both
    
        $objTextBoxVtep.WordWrap = $false
        $objTextBoxVtep.Size = New-Object System.Drawing.Size(390,650)
        $objTextBoxVtep.font = "lucida console"
        foreach ($line in $vtep) {
            $objTextBoxVtep.Appendtext($line)
            $objTextBoxVtep.AppendText("`n")
        }
        $ExplorerForm.Controls.Add($objTextBoxVtep)
    
        $objTextBoxFirewall = New-Object System.Windows.Forms.TextBox
        $objTextBoxFirewall.Location = New-Object System.Drawing.Size(470,100)
        $objTextBoxFirewall.Multiline = $true
        $objTextBoxFirewall.ScrollBars = [System.Windows.Forms.ScrollBars]::Both
    
        $objTextBoxFirewall.WordWrap = $false
        $objTextBoxFirewall.Size = New-Object System.Drawing.Size(390,650)
        foreach ($line in $firewall) {
            $objTextBoxFirewall.Appendtext($line)
            $objTextBoxFirewall.AppendText("`n")
        }
        $ExplorerForm.Controls.Add($objTextBoxFirewall)
    
        #endregion Generated Form Code
    
        #Save the initial state of the form
        $InitialFormWindowState = $ExplorerForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $ExplorerForm.add_Load($OnLoadForm_StateCorrection)
    
        #Show the Form
        $ExplorerForm.ShowDialog()| Out-Null
        if($EnableMultiWindow)
        {
            $progress.Dispose()
        }
    
    } #End Function OvsdbForm
    
    function RunScriptForm {
    
    param(
            [Parameter(mandatory=$false)]
            [object[]] $Servers
        )
    
        [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
        [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
        #endregion
    
        #region Generated Form Objects
        $ExplorerForm = New-Object System.Windows.Forms.Form
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        #endregion Generated Form Objects
    
    
        $OnLoadForm_StateCorrection=
        {#Correct the initial state of the form to prevent the .Net maximized form issue
        $ExplorerForm.WindowState = $InitialFormWindowState
        }
    
        #———————————————-
        #region Generated Form Code
        $ExplorerForm.Text = "Run Script Block on all Servers"
        $ExplorerForm.Name = $ServerName
        $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0
    
        $ExplorerForm.ClientSize = New-Object System.Drawing.Size(900,800)
    
    
        $runScript = New-Object System.Windows.Forms.Button
        $System_Drawing_SizeButton = New-Object System.Drawing.Size
        $System_Drawing_SizeButton.Width = 240
        $System_Drawing_SizeButton.Height = 23
        $runScript.TabIndex = 0
        $runScript.Name = "Select"
        $runScript.Size = $System_Drawing_SizeButton
        $runScript.UseVisualStyleBackColor = $True
        $runScript.Text = "--Run Script Block--"
        $runScript.Location = New-Object System.Drawing.Size(50,50)
        $runScript.DataBindings.DefaultDataSourceUpdateMode = 0
        $scriptBlock = {
            $objTextBoxOutPut.text = ""
            $objTextInput.ReadOnly = $true
    
                foreach ($server in $Servers)
                {
                    try
   {
                        foreach ($address in $server.properties.connections[0].managementAddresses)
       {
                            try
           {
                                [ipaddress]$address
                            }
                            catch
           {
                                $ServerName = $address
                                break;
                            }
                        }
    
                        $line = "==============================`n"
                        $objTextBoxOutPut.text += $line
                        $line = "Running Command on $ServerName `n"
                        $objTextBoxOutPut.text += $line
                        $line = "==============================`n"
                        $objTextBoxOutPut.text += $line
    
                        $command = "try{"
                        $command += $objTextInput.text
                        $command += "}catch {return `$_}"
    
                        $data = RunServerCommand -ServerName $ServerName -scriptBlock $command
    
                        foreach ($line in $data) {
                            if ($line.Length -ne 0)
           {
                                $formattedData =  $line | Format-Table
                                $formattedData = $formattedData | Out-String
                                $objTextBoxOutPut.Appendtext($formattedData)
                                $objTextBoxOutPut.ScrollToCaret()
                            }
                        }
                    }
                    catch
   {
                        [System.Windows.Forms.MessageBox]::Show($_)
                    }
                }
    
                $i = 0
                $objTextBoxOutPut.Text -Split '\n' | % {
                $objTextBoxOutPut.SelectionStart = $i
                $line = $_
                $searchStr1 = "Running Command on "
                $searchStr2 = "===================="
                $objTextBoxOutPut.SelectionLength = $line.Length
                if (Select-String -Pattern $searchStr1 -InputObject $line)
                {
                    $objTextBoxOutPut.SelectionColor = [Drawing.Color]::Blue
                }
                elseif (Select-String -Pattern $searchStr2 -InputObject $line)
                {
                    $objTextBoxOutPut.SelectionColor = [Drawing.Color]::DarkBlue
                }
                else
                {
                    $objTextBoxOutPut.SelectionColor = [Drawing.Color]::Black
                }
                $i += $line.Length + 1
                }
    
            $objTextInput.ReadOnly = $false
        }
        $runScript.add_Click($scriptBlock)
        $ExplorerForm.Controls.Add($runScript)
    
        $objTextInput = New-Object System.Windows.Forms.RichTextBox
        $objTextInput.Location = New-Object System.Drawing.Size(50,100)
        $objTextInput.Multiline = $true
        $objTextInput.ScrollBars = [System.Windows.Forms.ScrollBars]::Both
    
        $objTextInput.WordWrap = $false
        $objTextInput.Size = New-Object System.Drawing.Size(800,300)
        $objTextInput.font = "lucida console"
        foreach ($line in $vtep) {
            $objTextInput.Appendtext($line)
            $objTextInput.AppendText("`n")
        }
        $ExplorerForm.Controls.Add($objTextInput)
    
        $objTextBoxOutPut = New-Object System.Windows.Forms.RichTextBox
        $objTextBoxOutPut.Location = New-Object System.Drawing.Size(50,450)
        $objTextBoxOutPut.Multiline = $true
        $objTextBoxOutPut.ScrollBars = [System.Windows.Forms.ScrollBars]::Both
        $objTextBoxOutPut.ReadOnly = $true
    
        $objTextBoxOutPut.WordWrap = $false
        $objTextBoxOutPut.Size = New-Object System.Drawing.Size(800,300)
        foreach ($line in $firewall) {
            $objTextBoxOutPut.Appendtext($line)
            $objTextBoxOutPut.AppendText("`n")
        }
        $ExplorerForm.Controls.Add($objTextBoxOutPut)
    
        #endregion Generated Form Code
    
        #Save the initial state of the form
        $InitialFormWindowState = $ExplorerForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $ExplorerForm.add_Load($OnLoadForm_StateCorrection)
    
        #Show the Form
        $ExplorerForm.ShowDialog()| Out-Null
    
    } #End Function RunScriptForm
    
    function GetOvsDBVtep {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $ServerName
        )
    
    
        return RunServerCommand -ServerName $ServerName -scriptBlock {C:\windows\system32\ovsdb-client.exe dump tcp:127.0.0.1:6641 ms_vtep}
    
    } #End Function GetOvsDBVtep
    
    function GetOvsDBfirewall {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $ServerName
        )
    
        return RunServerCommand -ServerName $ServerName -scriptBlock {C:\windows\system32\ovsdb-client.exe dump tcp:127.0.0.1:6641 ms_firewall}
    
    } #End Function GetOvsDBfirewall
    
    function GetAllVFPPolices {
    
    param(
            [Parameter(mandatory=$true)]
            [object] $Server,
            [Parameter(mandatory=$false)]
            [object] $EnableMultiWindow=$true
    
    
        )
    
        if($EnableMultiWindow)
        {
            $progress = [powershell]::create()
    
            $progressScript = {
                    [System.Windows.Forms.MessageBox]::Show("Fetching Policies, it will take a few seconds to complete")
            }
            $progress.AddScript($progressScript)
    
            $progressObj = $progress.BeginInvoke()
        }
    
        foreach ($address in $Server.properties.connections[0].managementAddresses)
        {
            try
            {
                [ipaddress]$address
            }
            catch
            {
                $ServerName = $address
                break;
            }
        }
    
        if([string]::IsNullOrEmpty($ServerName))
        {
            [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!")
            return
        }
    
        $scriptBlock = {
    
            $switches = Get-WmiObject -Namespace root\virtualization\v2 -Class Msvm_VirtualEthernetSwitch
            foreach ($switch in $switches) {
                $vfpCtrlExe = "vfpctrl.exe"
                $ports = $switch.GetRelated("Msvm_EthernetSwitchPort", "Msvm_SystemDevice", $null, $null, $null, $null, $false, $null)
                foreach ($port in $ports) {
                    $portGuid = $port.Name
                    echo "Policy for port : " $portGuid
                    & $vfpCtrlExe /list-space  /port $portGuid
                    & $vfpCtrlExe /list-mapping  /port $portGuid
                    & $vfpCtrlExe /list-rule  /port $portGuid
                    & $vfpCtrlExe /port $portGuid /get-port-state
                }
            }
        }
    
        $text = @()
        $text = RunServerCommand -ServerName $ServerName -scriptBlock $scriptBlock
    
        DisplayTextForm -FormName $ServerName -Text $text
    
        if($EnableMultiWindow)
        {
            $progress.Dispose()
        }
    
    } #End Function GetAllVFPPolices
    
    function RunServerCommand {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $ServerName,
    
            [Parameter(mandatory=$false)]
            [string] $scriptBlock,
    
            [Parameter(mandatory=$false)]
            [object[]] $argumentList = $null
        )
    
    
        $text = @()
        $script = ([scriptblock]::Create($scriptBlock))
    
        if (-not $argumentList)
        {
            $text = Invoke-Command -ComputerName $ServerName -ScriptBlock $script
        }
        else
        {
            $text = Invoke-Command -ComputerName $ServerName -ScriptBlock $script -ArgumentList $argumentList
        }
    
        return $text
    } #End Function RunServerCommand
    
    function DisplayTextForm {
    
    param(
            [Parameter(mandatory=$true)]
            [string] $FormName,
    
            [Parameter(mandatory=$false)]
            [string[]] $Text
        )
    
        [reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
        [reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
        #endregion
    
        try
        {
            foreach ($address in $Server.properties.connections[0].managementAddresses)
            {
                try
                {
                    [ipaddress]$address
                }
                catch
                {
                    $ServerName = $address
                    break;
                }
            }
    
            if([string]::IsNullOrEmpty($ServerName))
            {
                [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!")
            }
    
            $FormName = $ServerName
        }
        catch
        {
        }
    
        #region Generated Form Objects
        $ExplorerForm = New-Object System.Windows.Forms.Form
        $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
        #endregion Generated Form Objects
    
    
        $OnLoadForm_StateCorrection=
        {#Correct the initial state of the form to prevent the .Net maximized form issue
        $ExplorerForm.WindowState = $InitialFormWindowState
        }
    
        #———————————————-
        #region Generated Form Code
        $ExplorerForm.Text = $FormName
        $ExplorerForm.Name = $FormName
        $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0
    
        $ExplorerForm.ClientSize = New-Object System.Drawing.Size(700,800)
    
    
        $objTextBoxVtep = New-Object System.Windows.Forms.RichTextBox
        $objTextBoxVtep.Location = New-Object System.Drawing.Size(40,100)
        $objTextBoxVtep.Multiline = $true
        $objTextBoxVtep.ScrollBars = [System.Windows.Forms.ScrollBars]::Both
    
        $objTextBoxVtep.WordWrap = $false
        $objTextBoxVtep.Size = New-Object System.Drawing.Size(600,650)
        $objTextBoxVtep.font = "lucida console"
        foreach ($line in $Text) {
            $objTextBoxVtep.Appendtext($line)
            $objTextBoxVtep.AppendText("`n")
        }
        $ExplorerForm.Controls.Add($objTextBoxVtep)
    
        #endregion Generated Form Code
    
        #Save the initial state of the form
        $InitialFormWindowState = $ExplorerForm.WindowState
        #Init the OnLoad event to correct the initial state of the form
        $ExplorerForm.add_Load($OnLoadForm_StateCorrection)
    
        #Show the Form
        $ExplorerForm.ShowDialog()| Out-Null
    
    } #End Function DisplayTextForm
    
    function CAPing
    {
        param($NCIP, $Source, $NCCredential=  [System.Management.Automation.PSCredential]::Empty)
    
        #. .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential
    
        $headers = @{"Accept"="application/json"}
        $content = "application/json; charset=UTF-8"
        $network = "https://$NCIP/Networking/v1"
        $retry = 30
    
        $method = "Put"
        $uri = "$network/diagnostics/ConnectivityCheck"
        $body = $caJson
    
        $networkInterfaces = Get-NCNetworkInterface
    
        $selectIps = @()
    
        foreach ($ni in $networkInterfaces)
        {
            try
            {
                if($Source.properties.ipConfigurations[0].properties.privateIPAddress -ne $ni.properties.ipConfigurations[0].properties.privateIPAddress)
                {
                    $selectIps += $ni.properties.ipConfigurations[0].properties.privateIPAddress
                }
            }
            catch
            {
                #skip
            }
        }
    
        $selectedIp = RadioForm -Name "Dest IP" -Values $selectIps
    
        foreach ($ni in $networkInterfaces)
        {
            try
            {
                if ( $selectedIp -eq $ni.properties.ipConfigurations[0].properties.privateIPAddress)
                {
                    $destination = $ni
                }
            }
            catch
            {
                #skip
            }
        }
    
        $caJson = @{}
        $caJson.resourceId = ""
        $caJson.properties = @{}
        $caJson.properties.senderIpAddress = $Source.properties.ipConfigurations[0].properties.privateIPAddress
        $caJson.properties.receiverIpAddress = $destination.properties.ipConfigurations[0].properties.privateIPAddress
    
    
        $parse = $Source.properties.ipConfigurations[0].properties.subnet.resourceRef.Split("/")
        $Vnet = ""
        for($it = 0 ;$it -lt 3; $it++)
        {
            if( -not [string]::IsNullOrEmpty($parse[$it]))
            {
                $Vnet += "/"
                $Vnet += $parse[$it]
            }
        }
        $caJson.properties.sendervirtualNetwork = @{}
        $caJson.properties.sendervirtualNetwork.resourceRef = $Vnet
        $caJson.properties.receivervirtualNetwork = @{}
        $caJson.properties.receivervirtualNetwork.resourceRef = $Vnet
        $caJson.properties.disableTracing = $false
        $caJson.properties.protocol = "Icmp"
        $caJson.properties.icmpProtocolConfig = @{}
        $caJson.properties.icmpProtocolConfig.sequenceNumber = 1
        $caJson.properties.icmpProtocolConfig.length = 0
    
        $body = ConvertTo-Json -Depth 20 $caJson
        try
        {
            $result = Invoke-WebRequest -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing
    
            $body = ConvertFrom-Json $result.Content
    
            $operationId = $body.properties.operationId
    
            [System.Windows.Forms.MessageBox]::Show("CAPing started:$operationId")
        }
        catch
        {
          [System.Windows.Forms.MessageBox]::Show("$_")
        }
    } #End Function CAPing
    
    function RDMAValidation
    {
        Param(
          [Parameter(Mandatory=$True, Position=1, HelpMessage="Interface index of the adapter for which RDMA config is to be verified")]
          [string] $ServerName
        )
    
        $vnics = Invoke-Command -ComputerName $ServerName -ScriptBlock { Get-NetAdapter | Where-Object {$_.DriverName -eq "\SystemRoot\System32\drivers\vmswitch.sys" }  }
    
    
        $vnicNames = @()
    
        foreach ($vnic in $vnics)
        {
            $vnicNames += $vnic.Name
        }
        try{
             $selectedVName = RadioForm -Name "Adapter Name" -Values $vnicNames
        }
        catch{
            [System.Windows.Forms.MessageBox]::Show("Main error" + $_)
            return
        }
    
        foreach ($vnic in $vnics)
        {
            if ($selectedVName -eq $vnic.Name)
            {
                $selectedVNic= $vnic
                break
            }
        }
    
        $IsRoceStr =  RadioForm -Name "IsRoce" -Values "true","false"
    
        $IsRoce = $false
        if ($IsRoceStr -eq "true")
        {
            $IsRoce = $true
        }
    
    
        $scriptBlock = {
    
            Param(
              [string] $IfIndex,
              [bool] $IsRoCE
            )
    
            $rdmaAdapter = Get-NetAdapter -IfIndex $IfIndex
    
            if ($rdmaAdapter -eq $null)
            {
                Write-Host "ERROR: The adapter with interface index $IfIndex not found"
                return
            }
    
            $rdmaAdapterName = $rdmaAdapter.Name
            $virtualAdapter = Get-VMNetworkAdapter -ManagementOS | where DeviceId -eq $rdmaAdapter.DeviceID
    
            if ($virtualAdapter -eq $null)
            {
                $isRdmaAdapterVirtual = $false
                Write-Host "VERBOSE: The adapter $rdmaAdapterName is a physical adapter"
            }
            else
            {
                $isRdmaAdapterVirtual = $true
                Write-Host "VERBOSE: The adapter $rdmaAdapterName is a virtual adapter"
            }
    
            $rdmaCapabilities = Get-NetAdapterRdma -InterfaceDescription $rdmaAdapter.InterfaceDescription
    
            if ($rdmaCapabilities -eq $null -or $rdmaCapabilities.Enabled -eq $false)
            {
                return "ERROR: The adapter $rdmaAdapterName is not enabled for RDMA"
            }
    
            if ($rdmaCapabilities.MaxQueuePairCount -eq 0)
            {
                return "ERROR: RDMA capabilities for adapter $rdmaAdapterName are not valid : MaxQueuePairCount is 0"
    
            }
    
            if ($rdmaCapabilities.MaxCompletionQueueCount -eq 0)
            {
                return "ERROR: RDMA capabilities for adapter $rdmaAdapterName are not valid : MaxCompletionQueueCount is 0"
    
            }
    
            $smbClientNetworkInterfaces = Get-SmbClientNetworkInterface
    
            if ($smbClientNetworkInterfaces -eq $null)
            {
                return  "ERROR: No network interfaces detected by SMB (Get-SmbClientNetworkInterface)"
            }
    
            $rdmaAdapterSmbClientNetworkInterface = $null
            foreach ($smbClientNetworkInterface in $smbClientNetworkInterfaces)
            {
                if ($smbClientNetworkInterface.InterfaceIndex -eq $IfIndex)
                {
                    $rdmaAdapterSmbClientNetworkInterface = $smbClientNetworkInterface
                }
            }
    
            if ($rdmaAdapterSmbClientNetworkInterface -eq $null)
            {
                return "ERROR: No network interfaces found by SMB for adapter $rdmaAdapterName (Get-SmbClientNetworkInterface)"
            }
    
            if ($rdmaAdapterSmbClientNetworkInterface.RdmaCapable -eq $false)
            {
                return "ERROR: SMB did not detect adapter $rdmaAdapterName as RDMA capable. Make sure the adapter is bound to TCP/IP and not to other protocol like vmSwitch."
            }
    
            $rdmaAdapters = $rdmaAdapter
            if ($isRdmaAdapterVirtual -eq $true)
            {
                Write-Host "VERBOSE: Retrieving vSwitch bound to the virtual adapter"
                $switchName = $virtualAdapter.SwitchName
                Write-Host "VERBOSE: Found vSwitch: $switchName"
                $vSwitch = Get-VMSwitch -Name $switchName
                $rdmaAdapters = Get-NetAdapter -InterfaceDescription $vSwitch.NetAdapterInterfaceDescriptions
                $vSwitchAdapterMessage = "VERBOSE: Found the following physical adapter(s) bound to vSwitch: "
                $index = 1
                foreach ($qosAdapter in $rdmaAdapters)
                {
                    $qosAdapterName = $qosAdapter.Name
                    $vSwitchAdapterMessage = $vSwitchAdapterMessage + [string]$qosAdapterName
                    if ($index -lt $rdmaAdapters.Length)
   {
                            $vSwitchAdapterMessage = $vSwitchAdapterMessage + ", "
                    }
                    $index = $index + 1
                }
                Write-Host $vSwitchAdapterMessage
            }
    
    
            if ($IsRoCE -eq $true)
            {
                Write-Host "VERBOSE: Underlying adapter is RoCE. Checking if QoS/DCB/PFC is configured on each physical adapter(s)"
                foreach ($qosAdapter in $rdmaAdapters)
                {
                    $qosAdapterName = $qosAdapter.Name
                    $qos = Get-NetAdapterQos -Name $qosAdapterName
                    if ($qos.Enabled -eq $false)
                    {
                        return "ERROR: QoS is not enabled for adapter $qosAdapterName"
                    }
    
                    if ($qos.OperationalFlowControl -eq "All Priorities Disabled")
                    {
                        return "ERROR: Flow control is not enabled for adapter $qosAdapterName"
                    }
                }
                Write-Host "VERBOSE: QoS/DCB/PFC configuration is correct."
            }
    
            return " RDMA configuration on the host is correct, please check switch configuration for E2E RDMA to work."
        }
    
        $strOutput = Invoke-Command -ComputerName $ServerName -ScriptBlock $scriptBlock -ArgumentList $selectedVNic.ifIndex,$IsRoce
    
        [System.Windows.Forms.MessageBox]::Show("$strOutput")
    } #End Function RDMAValidation
    
function VerifyJumboPkt
{
    Param(
        [string] $ServerName,
        [object]$NCCredential=  [System.Management.Automation.PSCredential]::Empty
    )
    try
    {
        $allServers = Get-NCServer

        $serverNames = @()

        foreach ($server in $allServers)
        {
            foreach ($address in $server.properties.connections[0].managementAddresses)
            {
                try
                {
                        [ipaddress]$address
                    }
                    catch
                    {
                        if ($address -ne $ServerName)
                        {
                            $serverNames += $address
                        }
                        break;
                    }
                }
            }
    
            $destServer = RadioForm -Name "Dest Server" -Values $serverNames
    
            if ($NCCredential -eq [System.Management.Automation.PSCredential]::Empty)
            {
                $cred = Get-Credential -Message "Enter Server Creds"
            }
            else
            {
                $cred = $NCCredential
            }
    
            $result = Test-LogicalNetworkSupportsJumboPacket -SourceHost $ServerName -DestinationHost $destServer -SourceHostCreds $cred -DestinationHostCreds $cred
    
            $result = $result | ConvertTo-Json -Depth 10
    
            [System.Windows.Forms.MessageBox]::Show($result)
    }
    catch
    {
        [System.Windows.Forms.MessageBox]::Show($_)
    }
}

function VerifyCerts
{
    Param(
        [string] $NCIP,
        [string] $ServerName,
        [object] $ServerObject,
        [object] $NCCredential=  [System.Management.Automation.PSCredential]::Empty
    )
    #. .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential

    $NCCertHash = $null
    foreach ($conn in $ServerObject.properties.connections)
    {
        $cred =  JSONGet -path $conn.credential.resourceRef -NetworkControllerRestIP $NCIP -credential $NCCredential

        if ($cred.properties.type -eq "X509Certificate")
        {
            $NCCertHash = $cred.properties.value
        }
    }

    if ([string]::IsNullOrEmpty($NCCertHash))
    {
        [System.Windows.Forms.MessageBox]::Show("NC Cert is not configured in Server($ServerName) Json.")
    }

    $ServerCert = $ServerObject.properties.certificate

    $scriptBlock =
    {
        Param(
            [string] $NCCertHash,
            [string] $ServerCert
        )

        $rootCerts = dir Cert:\LocalMachine\Root

        $NCCert = $null
        foreach ($cert in $rootCerts)
        {
            if ($cert.Thumbprint -eq $NCCertHash)
            {
                $NCCert = $cert
            }
        }

        if (-not $NCCert)
        {
            return "NC Cert is Missing"
        }

        $myCerts = dir Cert:\LocalMachine\my
        $serverCertificate = $null
        foreach ($cert in $myCerts)
        {
            $base64 = [System.Convert]::ToBase64String($cert.RawData)
            if ($base64 -eq $ServerCert)
            {
                $serverCertificate = $cert
            }
        }

        if (-not $serverCertificate)
        {
            return "Server Cert is Missing"
        }

        $certToVerify = @()
        $certToVerify += $NCCert
        $certToVerify += $serverCertificate

        foreach ($cert in $certToVerify)
        {

            $server = $false
            $client = $false
            foreach ($eku in $cert.EnhancedKeyUsageList)
            {
                if ($eku.FriendlyName -eq "Server Authentication")
{
                    $server = $true
                }

                if ($eku.FriendlyName -eq "Client Authentication")
{
                    $client = $true
                }
            }

            $thumbprint = $cert.Thumbprint

            if ($server -eq $false)
            {
                return "Server EKU is missing on NC Cert($thumbprint) on Server."
            }

            if ($client -eq $false)
            {
                return "Client EKU is missing on NC Cert($thumbprint) on Server."
            }
        }

        $key = 'HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\'
        $peerCertificateCName = "CN="
        $peerCertificateCName += (Get-ItemProperty -Path $key -Name PeerCertificateCName).PeerCertificateCName

        if ($peerCertificateCName -ne $NCCert.Subject)
        {
            $subject = $NCCert.Subject
            return "NCHostAgent has wrong PeerCertificateCName($peerCertificateCName) instead of $subject"
        }

        $hostAgentCertificateCName = "CN="
        $hostAgentCertificateCName += (Get-ItemProperty -Path $key -Name HostAgentCertificateCName).HostAgentCertificateCName

        if ($hostAgentCertificateCName -ne $serverCertificate.Subject)
        {
            $subject = $serverCertificate.Subject
            return "NCHostAgent has wrong PeerCertificateCName($hostAgentCertificateCName) instead of $subject"
        }

        return "Certificates are configured correctly!!"
    }

    $strOutput = Invoke-Command -ComputerName $ServerName -ScriptBlock $scriptBlock -ArgumentList $NCCertHash,$ServerCert

    [System.Windows.Forms.MessageBox]::Show("$strOutput")

}  #End Function VerifyCerts
function Init-SdnExplorer {
    param(
        [string]
        $NCIP = "",
        [object]
        $NCCredential=  [System.Management.Automation.PSCredential]::Empty,
        [bool]
        $EnableMultiWindow = $true,
        [bool]
        $IsModule = $false
    )

    $Global:NCApiVersion = "v1"
    $script:urlroot = "https://"
    $script:NCCredential =  $NCCredential
    $script:NetworkControllerCred = $NCCredential
    $script:EnableMultiWindow = $EnableMultiWindow

    if($true -eq [string]::IsNullOrEmpty($NCIP)) {
        # attempt to get the NC IP from the registry
        try { 
            $NCIP = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\').Connections[0].Trim("ssl:").TrimEnd(":6640")
        } catch {
            Write-Error "Failed to get the NC IP from the registry. Please provide the NC IP."
            return
        }
    }
    $script:NetworkControllerRestIP = $NCIP
}
function Start-SdnExplorer {

    param(
        [string]
        $NCIP = "",
        [object]
        $NCCredential=  [System.Management.Automation.PSCredential]::Empty,
        [bool]
        $EnableMultiWindow = $true,
        [bool]
        $IsModule = $false
    )

    $Global:NCApiVersion = "v1"
    $script:urlroot = "https://"
    $script:NCCredential =  $NCCredential
    $script:NetworkControllerCred = $NCCredential
    $script:EnableMultiWindow = $EnableMultiWindow

    if($true -eq [string]::IsNullOrEmpty($NCIP)) {
        # attempt to get the NC IP from the registry
        try { 
            $NCIP = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\').Connections[0].Trim("ssl:").TrimEnd(":6640")
        } catch {
            Write-Error "Failed to get the NC IP from the registry. Please provide the NC IP."
            return
        }
    }

    $script:NetworkControllerRestIP = $NCIP

    # Import-Module .\NetworkControllerWorkloadHelpers.psm1 -Force
    # #. .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential

    $ncVMCredentials = [System.Management.Automation.PSCredential]::Empty

    $InputData = @()

    $ApiVersion = @{}
    $ApiVersion.Name = "Rest ApiVersion"
    $ApiVersion.Value = @()
    $InputData += $ApiVersion

    $LNs = @{}
    $LNs.Name = "Logical Networks"
    $LNs.Value = @()
    $LNs.Value += {GenerateArrayForm -HandlerFunc "Get-NCLogicalNetwork" -RemoveFunc "Remove-NCLogicalNetwork" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $LNs

    $VNs = @{}
    $VNs.Name = "VirtualNetworks"
    $VNs.Value = @()
    $VNs.Value += {GenerateArrayForm -HandlerFunc "Get-NCVirtualNetwork" -RemoveFunc "Remove-NCVirtualNetwork" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $VNs


    $VSs = @{}
    $VSs.Name = "Virtual Servers"
    $VSs.Value = @()
    $VSs.Value += {GenerateArrayForm -HandlerFunc "Get-NCVirtualServer" -RemoveFunc "Remove-NCVirtualServer" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $VSs

    $NIs = @{}
    $NIs.Name = "Network Interfaces"
    $NIs.Value = @()
    $NIs.Value += {GenerateArrayForm -HandlerFunc "Get-NCNetworkInterface" -RemoveFunc "Remove-NCNetworkInterface" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $NIs.Value += {PutNetworkInterface -HandlerFunc "New-NCNetworkInterface" -NCIP $NCIP -NCCredential $Script:NCCredential}
    $NIs.Value += {RemoveObjForm -HandlerFunc "Remove-NCNetworkInterface" -GetFunc "Get-NCNetworkInterface" -NCIP $NCIP -NCCredential $Script:NCCredential}
    $InputData += $NIs


    $NS = @{}
    $NS.Name = "Servers"
    $NS.Value = @()
    $NS.Value = {GenerateArrayForm -HandlerFunc "Get-NCServer" -RemoveFunc "Remove-NCServer" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $NS

    $LB = @{}
    $LB.Name = "Load Balancer"
    $LB.Value = @()
    $LB.Value += {GenerateArrayForm -HandlerFunc "Get-NCLoadBalancer" -RemoveFunc "Remove-NCLoadBalancer" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $LB.Value += {PutLoadBalancer -HandlerFunc "New-LoadBalancerVIP" -NCIP $NCIP -NCCredential $Script:NCCredential}
    $InputData += $LB

    $Acls = @{}
    $Acls.Name = "Access Control List"
    $Acls.Value = @()
    $Acls.Value += {GenerateArrayForm -HandlerFunc "Get-NCAccessControlList" -RemoveFunc "Remove-NCAccessControlList" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $Acls

    $Credentials = @{}
    $Credentials.Name = "NC Credentials"
    $Credentials.Value = @()
    $Credentials.Value += {GenerateArrayForm -HandlerFunc "Get-NCCredential" -RemoveFunc "Remove-NCCredential" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $Credentials

    $LBM = @{}
    $LBM.Name = "Load Balancer Manager"
    $LBM.Value = @()
    $LBM.Value += {GenerateArrayForm -HandlerFunc "Get-NCLoadbalancerManager" -RemoveFunc "null" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $LBM

    $LBMUX = @{}
    $LBMUX.Name = "Load Balancer Mux"
    $LBMUX.Value = @()
    $LBMUX.Value += {GenerateArrayForm -HandlerFunc "Get-NCLoadbalancerMux" -RemoveFunc "Remove-NCLoadBalancerMux" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $LBMUX

    $CR = @{}
    $CR.Name = "Diagnostics Panel"
    $CR.Value = @()
    $CR.Value += {GenerateArrayForm -HandlerFunc "Get-NCConnectivityCheckResult" -RemoveFunc "null" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $CR

    $Publicip = @{}
    $Publicip.Name = "Public IP Addresses"
    $Publicip.Value = @()
    $Publicip.Value += {GenerateArrayForm -HandlerFunc "Get-NCPublicIPAddress" -RemoveFunc "null" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $Publicip

    $RT = @{}
    $RT.Name = "Route Tables"
    $RT.Value = @()
    $RT.Value += {GenerateArrayForm -HandlerFunc "Get-NCRouteTable" -RemoveFunc "null" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $RT

    $Gateways = @{}
    $Gateways.Name = "Gateways"
    $Gateways.Value = @()
    $Gateways.Value += {GenerateArrayForm -HandlerFunc "Get-NCGateway" -RemoveFunc "Remove-NCGateway" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $Gateways

    $GatewayPools = @{}
    $GatewayPools.Name = "Gateway Pools"
    $GatewayPools.Value = @()
    $GatewayPools.Value += {GenerateArrayForm -HandlerFunc "Get-NCGatewayPool" -RemoveFunc "Remove-NCGatewayPool" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $GatewayPools

    $VirtualGateway = @{}
    $VirtualGateway.Name = "Virtual Gateway"
    $VirtualGateway.Value = @()
    $VirtualGateway.Value += {GenerateArrayForm -HandlerFunc "Get-NCVirtualGateway" -RemoveFunc "Remove-NCVirtualGateway" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $VirtualGateway

    $LearnedIP = @{}
    $LearnedIP.Name = "Learned IP Addresses"
    $LearnedIP.Value = @()
    $NIs.Value += {PutLearnedIpAddress -HandlerFunc "New-NCLearnedIPAddress" -NCIP $NCIP -NCCredential $Script:NCCredential}
    $LearnedIP.Value += {GenerateArrayForm -HandlerFunc "Get-NCLearnedIPAddress" -RemoveFunc "Remove-NCLearnedIPAddress" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $LearnedIP

    $MacPools = @{}
    $MacPools.Name = "MAC Pools"
    $MacPools.Value = @()
    $MacPools.Value += {GenerateArrayForm -HandlerFunc "Get-NCMacPool" -RemoveFunc "Remove-NCMacPool" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow}
    $InputData += $MacPools

    if(-not $script:IsModule)
    {
        #Call the Function
        GenerateMainForm -DataArr $InputData
    }
}

Export-ModuleMember -Function Start-SdnExplorer
Export-ModuleMember -Function Init-SdnExplorer
Export-ModuleMember -Function GenerateArrayFormHelper
Export-ModuleMember -Function JsonForm
Export-ModuleMember -Function OvsdbForm
Export-ModuleMember -Function GetAllVFPPolices