public/interface/portproxy/Add-PortProxy.ps1

#Requires -RunAsAdministrator
function Add-PortProxy {
    <#
    .SYNOPSIS
        Adds a new v4tov4 portproxy entry using 'netsh interface portproxy'
    .DESCRIPTION
        Adds a new portproxy using netsh. The portproxy feature in Windows enables you to accept
        TCP connections on a specific interface (or all interfaces) and a specific port, then
        redirect that connection to another IP and optionally a different port. Effectively this
        turns your Windows PC into a very simple proxy server. It's important to note that there
        is no authentication or security associated with the portproxy feature, so all inbound
        TCP traffic will be sent out to the supplied ConnectAddress unless you have created
        firewall rules to limit the allowed sources for inbound connections.
    .EXAMPLE
        PS C:\> Add-PortProxy -ListenPort 8000 -ConnectAddress 10.1.1.101
        Sets up a portproxy in Windows so all connections to all local interfaces on TCP port 8000
        will be proxied to 10.1.1.101 on port 8000.
    .EXAMPLE
        PS C:\> Add-PortProxy -ListenPort 8000 -ConnectAddress 10.1.1.101 -ConnectPort 8001 -ListenAddress 10.1.1.100
        Sets up a portproxy in Windows so all connections to the local interface 10.1.1.100 on TCP
        port 8000 will be proxied to 10.1.1.101 on port 8001.
    .EXAMPLE
        PS C:\> Add-PortProxy -ListenPort 25 -ConnectAddress mail.example.com -ConnectPort 587 -ListenAddress 127.0.0.1
        Sets up a portproxy in Windows so all connections to localhost on TCP port 25 will be
        proxied to mail.example.com on TCP port 587.
    .OUTPUTS
        When supplying the PassThru parameter switch, the output will be [PortProxy] with
        properties 'InternetProtocol', 'ListenAddress', 'ListenPort', 'ConnectAddress', 'ConnectPort'
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([PortProxy])]
    param(
        # Specifies the TCP port on which to listen for incoming connections.
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [ValidateRange(0,65535)]
        [int]
        $ListenPort,

        # Specifies the IP or hostname to which incoming connections should be proxied.
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [string]
        $ConnectAddress,

        # Specifies the TCP port to which connections should be proxied. The default will match ListenPort.
        [Parameter(ValueFromPipelineByPropertyName)]
        [ValidateRange(0,65535)]
        [int]
        $ConnectPort,

        # Specifies the IP or hostname on which incoming connections should be accepted. The default is '*' which is effectively 0.0.0.0, meaning "listen on all interfaces".
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]
        $ListenAddress,

        # Pass the newly added portproxy parameters into the pipeline as a [PortProxy]
        [Parameter()]
        [switch]
        $PassThru
    )

    process {
        if ([string]::IsNullOrWhiteSpace($ListenAddress)) {
            $ListenAddress = "*"
        }
        if (!$PSBoundParameters.ContainsKey('ConnectPort')) {
            $ConnectPort = $ListenPort
        }
        Write-Verbose "Checking existing portproxy entries. . ."
        foreach ($entry in Get-PortProxy) {
            if ($entry.ListenAddress -eq $ListenAddress -and $entry.ListenPort -eq $ListenPort) {
                Write-Error "PortProxy already configured for ListenAddress=$ListenAddress, ListenPort=$ListenPort"
                return
            }
        }

        Write-Verbose "Checking whether the socket is already in use by another application. . ."
        $netTcpConnection = Get-NetTCPConnection -LocalAddress $ListenAddress -LocalPort $ListenPort -State Listen -ErrorAction SilentlyContinue
        if ($null -ne $netTcpConnection) {
            Write-Error "The socket $($ListenAddress):$($ListenPort) is already in use by PID $($netTcpConnection.OwningProcess)"
        }

        $command = "netsh.exe interface portproxy add v4tov4 listenport=$ListenPort connectaddress=$ConnectAddress" 
        if ($PSBoundParameters.ContainsKey("ListenAddress")){
            $command += " listenaddress=$ListenAddress"
        }
        if ($PSBoundParameters.ContainsKey("ConnectPort")){
            $command += " connectport=$ConnectPort"
        }
        Write-Verbose "Executing the command '$command'"
        if ($PSCmdlet.ShouldProcess((hostname), $command)) {
            $output = Invoke-Expression -Command $command
            $success = $LASTEXITCODE -eq 0
            $output = [string]::Join("`r`n", $output).Trim()
            if ($success) {
                Write-Information $output
                if ($PassThru) {
                    [PortProxy]@{
                        InternetProtocol = "v4tov4"
                        ListenAddress = $ListenAddress
                        ListenPort = $ListenPort
                        ConnectAddress = $ConnectAddress
                        ConnectPort = $ConnectPort
                    }
                }
            }
            else {
                Write-Error "Error: $output"
            }
        }
    }
}