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")
}
Categories: