zvm_netdiag_scripts_utils.ps1


function Invoke-ZvmaNetDiagnostics {
    <#
    .SYNOPSIS
        Performs Azure resources connectivity diagnostics for ZVMA
    #>

    Write-Host "Starting $($MyInvocation.MyCommand)..."

    $urlsToDiagnose = @(
        'https://management.azure.com',
        'https://login.microsoftonline.com',
        'https://management.core.windows.net'
    )

    foreach ($targetUrl in $urlsToDiagnose) {

        Write-Host "### Executing connectivity diagnostics for '$targetUrl'"

        $uri = [System.Uri]$targetUrl
        $hostname = $uri.Host

        Write-Host "## DNS lookup result:`n$(Invoke-ZvmaNsLookup -TargetHost $hostname)" #TODO Improve DNS server diagnostics on Netcat where local DNS stub returned 127.0.0.53
        Write-Host "## DNS dig lookup result:`n$(Invoke-ZvmaDigLookup -TargetHost $hostname)"

        Write-Host "## Network traceroute result:`n$(Invoke-ZvmaTraceroute -TargetHost $hostname)"
        Write-Host "## TCP netcat connectivity result:`n$(Invoke-ZvmaNetcat -TargetHost $hostname)"

        Write-Host "## TLS connectivity result:`n$(Invoke-ZvmaOpenSslCheck -TargetHost $hostname)"

        Write-Host "## HTTP connectivity result:`n$(Invoke-ZvmaCurl -TargetUrl $targetUrl)"
    }
}

function Invoke-ZvmaVraHostNetDiagnostics {
    <#
    .SYNOPSIS
        Performs VRAs and Hosts connectivity diagnostics for ZVMA
        The expected output sample is:
        * Connection to 10.180.195.200 4009 port [tcp/*] succeeded!
        * Connection to esx11[...].avs.azure.com (10.180.197.8) 33072 port [tcp/*] succeeded!
    #>

    Write-Host "Starting $($MyInvocation.MyCommand)..."

    $vraVMs = Get-VM -Name $VRA_VM_PATTERN
    $vraIPs = $vraVMs |
    ForEach-Object { $_.Guest.IPAddress } |
    Where-Object {
        # Filter to get only IPv4 addresses
        $parsedIp = $null
        [System.Net.IPAddress]::TryParse($_, [ref]$parsedIp) -and $parsedIp.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork
    }

    foreach ($vraIP in $vraIPs) {

        Write-Host "### Executing connectivity diagnostics for VRA '$vraIP'"

        $hostname = $vraIP
        $ports = '4001-4009'

        Write-Host "## VRA '$vraIP' netcat connectivity result:`n$(Invoke-ZvmaNetcat -TargetHost $hostname -Ports $ports)"
    }

    $allEsxiHosts = Get-Cluster | Get-VMHost

    foreach ($esxiHost in $allEsxiHosts) {

        Write-Host "### Executing connectivity diagnostics for ESXi Host '$($esxiHost.Name)'"

        $hostname = $esxiHost.Name
        $ports = '33072-33073'

        Write-Host "## ESXi Host '$($esxiHost.Name)' netcat connectivity result:`n$(Invoke-ZvmaNetcat -TargetHost $hostname -Ports $ports)"
    }
}

function Invoke-ZvmaNsLookup {
    <#
    .SYNOPSIS
        Executes nslookup command on the ZVMA to test DNS resolution
    #>

    param (
        [ValidateNotNullOrEmpty()]
        [string]$TargetHost
    )
    Write-Host "Starting $($MyInvocation.MyCommand)..."
    return Invoke-ZvmaNetDiagnosticCommand -Command "nslookup" -TargetHost $TargetHost -CommandDescription "DNS lookup"
}

function Invoke-ZvmaDigLookup {
    <#
    .SYNOPSIS
        Executes dig command on the ZVMA for DNS resolution and detailed diagnostics
    #>

    param (
        [ValidateNotNullOrEmpty()]
        [string]$TargetHost
    )
    Write-Host "Starting $($MyInvocation.MyCommand)..."
    return Invoke-ZvmaNetDiagnosticCommand -Command "dig" -TargetHost $TargetHost -CommandDescription "DNS dig lookup"
}

function Invoke-ZvmaTraceroute {
    <#
    .SYNOPSIS
        Executes traceroute command on the ZVMA to trace network path
    #>

    param (
        [ValidateNotNullOrEmpty()]
        [string]$TargetHost,

        [bool]$UseTcp = $true,

        [int]$Port = 443
    )
    Write-Host "Starting $($MyInvocation.MyCommand)..."

    $commandArgs = "-p $Port"
    if ($UseTcp) {
        $commandArgs += " -T "
    }

    return Invoke-ZvmaNetDiagnosticCommand -Command "sudo traceroute" -TargetHost $TargetHost -CommandArgs $commandArgs -CommandDescription "Network traceroute"
}

function Invoke-ZvmaNetcat {
    <#
    .SYNOPSIS
        Executes netcat command on the ZVMA to test TCP port connectivity
    #>

    param (
        [ValidateNotNullOrEmpty()]
        [string]$TargetHost,

        [string]$Ports = 443
    )
    Write-Host "Starting $($MyInvocation.MyCommand)..."

    $commandArgs = "$Ports -zv -w 3"

    return Invoke-ZvmaNetDiagnosticCommand -Command "nc" -TargetHost $TargetHost -CommandArgs $commandArgs -CommandDescription "TCP netcat connectivity test"
}

function Invoke-ZvmaOpenSslCheck {
    <#
    .SYNOPSIS
        Executes openssl s_client command on the ZVMA to test TLS connectivity
    #>

    param (
        [ValidateNotNullOrEmpty()]
        [string]$TargetHost,

        [int]$Port = 443,

        [int]$TimeoutSeconds = 10,

        [ValidateSet("tls1", "tls1_1", "tls1_2", "tls1_3")]
        [string]$TlsVersion = "tls1_3"
    )
    Write-Host "Starting $($MyInvocation.MyCommand)..."
    return Invoke-ZvmaNetDiagnosticCommand -Command "timeout $TimeoutSeconds openssl s_client -connect" -TargetHost "$($TargetHost):$Port" -CommandArgs "-$TlsVersion" -CommandDescription "TLS connectivity test"
}

function Invoke-ZvmaCurl {
    <#
    .SYNOPSIS
        Executes curl command on the ZVMA to test HTTP connectivity and verbose output
    #>

    param (
        [ValidateNotNullOrEmpty()]
        [string]$TargetUrl,

        [bool]$IsVerbose = $true
    )
    Write-Host "Starting $($MyInvocation.MyCommand)..."

    $commandText = "curl"
    if ($IsVerbose) {
        $commandText += " -v"
    }

    return Invoke-ZvmaNetDiagnosticCommand -Command $commandText -TargetHost $TargetUrl -CommandDescription "HTTP connectivity test"
}

function Invoke-ZvmaNetDiagnosticCommand {
    <#
    .SYNOPSIS
        Executes a network diagnostics command on the ZVMA
    #>

    param (
        [ValidateNotNullOrEmpty()]
        [string]$Command,

        [ValidateNotNullOrEmpty()]
        [string]$TargetHost,

        [string]$CommandArgs = "",

        [ValidateNotNullOrEmpty()]
        [string]$CommandDescription
    )
    Write-Host "Starting Invoke-ZvmaNetDiagnosticCommand for $CommandDescription..."

    try {

        $fullCommand = "$Command $TargetHost $CommandArgs"
        Write-Host "Executing command: $fullCommand"
        $res = Invoke-ZVMLScript -ScriptText $fullCommand

        Write-Host "$CommandDescription for $TargetHost completed."
        return $res.ScriptOutput
    }
    catch {
        $errorMessage = "Failed to perform $CommandDescription on ZVM. Problem: $_"
        Write-Error $errorMessage
        return "Error: $errorMessage"
    }
}