PowerShell: connectWinRM Function to Create New-PSSession

This reusable function may be included into PoSh scripts for better connection toward Windows machines via WinRM.

function connectWinRm($computer,$adminCredential=$false,$winRmPort=5985){
    if(!$computer){
        write-warning "Computer name must be specified to initiate a WinRM connection."
        return $false
    }
    # Legacy equivalent to Test-Netconnection
    function checkNetConnection($computername,$port,$timeout=1000,$verbose=$false) {
        $tcp = New-Object System.Net.Sockets.TcpClient;
        try {
            $connect=$tcp.BeginConnect($computername,$port,$null,$null)
            $wait = $connect.AsyncWaitHandle.WaitOne($timeout,$false)
            if(!$wait){
                $null=$tcp.EndConnect($connect)
                $tcp.Close()
                if($verbose){
                    Write-Host "Connection Timeout" -ForegroundColor Red
                    }
                Return $false
            }else{
                $error.Clear()
                $null=$tcp.EndConnect($connect) # Dispose of the connection to release memory
                if(!$?){
                    if($verbose){
                        write-host $error[0].Exception.Message -ForegroundColor Red
                        }
                    $tcp.Close()
                    return $false
                    }
                $tcp.Close()
                Return $true
            }
        } catch {
            return $false
        }
    }
    function enableWinRmRemotely($remoteComputer,$winRmPort,$adminCredential){
        function Check-NetConnection($computername,$port,$timeout=1000,$verbose=$false) {
                $tcp = New-Object System.Net.Sockets.TcpClient;
                try {
                    $connect=$tcp.BeginConnect($computername,$port,$null,$null)
                    $wait = $connect.AsyncWaitHandle.WaitOne($timeout,$false)
                    if(!$wait){
                        $null=$tcp.EndConnect($connect)
                        $tcp.Close()
                        if($verbose){
                            Write-Host "Connection Timeout" -ForegroundColor Red
                            }
                        Return $false
                    }else{
                        $error.Clear()
                        $null=$tcp.EndConnect($connect) # Dispose of the connection to release memory
                        if(!$?){
                            if($verbose){
                                write-host $error[0].Exception.Message -ForegroundColor Red
                                }
                            $tcp.Close()
                            return $false
                            }
                        $tcp.Close()
                        Return $true
                    }
                } catch {
                    return $false
                }
        }
        if (!(get-command psexec -ea SilentlyContinue)){
            # Install Chocolatey
            if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
                [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
                Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
                }
            choco install sysinternals -y;  
            }            
        write-host 'Attempting to use psexec to enable WinRM remotely...'
        if(!$adminCredential){ # Enable WinRM Remotely
            $null=psexec.exe \\$remoteComputer -s C:\Windows\system32\winrm.cmd qc -quiet; 
        }else{
            $username=$adminCredential.Username
            $password=$adminCredential.GetNetworkCredential().Password
            $null=psexec.exe \\$remoteComputer -u $username -p $password -s C:\Windows\system32\winrm.cmd qc -quiet
            }
        return check-netconnection $remoteComputer $winRmPort
    }

    # If machine is not pingable, wait five minutes
    $fiveMinuteTimer=[System.Diagnostics.Stopwatch]::StartNew()
    do{
        $ping = Test-Connection $computer -quiet
        if($ping -eq $false){sleep 1}
        $pastFiveMinutes=$fiveMinuteTimer.Elapsed.TotalMinutes -ge 5
    }until ($ping -eq $true -or $pastFiveMinutes)
    $fiveMinuteTimer.stop()

    $winRmAvailable=checkNetConnection $computer $winRmPort
    if(!$winRmAvailable){
        write-host "Attempting to enable WinRM on $computer" -ForegroundColor Yellow
        $enableWinRmSuccessful=enableWinRmRemotely $computer
        if($enableWinRmSuccessful){
            write-host "WinRM enabled: $enableWinRmSuccessful"
        }else{
            write-warning "WinRM could not be enabled remotely. WinRM connection aborted."
            return $false
            }
    }
    # Wait for WinRm session prior to proceeding
    #if($session.state -eq 'Opened'){remove-pssession $session}
    do{
        $session=if($adminCredential){
            try{
                New-PSSession -ComputerName $computer -Credential $adminCredential -ea Stop
            }catch{
                New-PSSession -ComputerName $computer -Credential $adminCredential -SessionOption $(new-pssessionoption -IncludePortInSPN)
            }
        }else{
            try{
                New-PSSession -ComputerName $computer -ea Stop
            }catch{
                New-PSSession -ComputerName $computer -SessionOption $(new-pssessionoption -IncludePortInSPN)
            }
        }
        #sleep -seconds 1
        if ($session){
            write-host "Connected to $computer."
            return $session
        }
    } until ($session.state -match "Opened")    
}

Leave a Reply

Your email address will not be published. Required fields are marked *