Link to home
Start Free TrialLog in
Avatar of Justin Owens
Justin OwensFlag for United States of America

asked on

How do I use PowerShell to 1) telnet to a list of digis to 2) login and run a single command?

First, I have never written a single PowerShell script in my life, so if this is not the best language to use, please let me know.  I need to run a small script that will connect to about 200 Digi devices to run a reboot command.  The command is "boota=r".  It is a command which reboots the Digi.  I want to have a script that will parse through a file to extrapolate a list of IP addresses to which it should connect to perform this command.
SOLUTION
Avatar of Aard Vark
Aard Vark
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Justin Owens

ASKER

Manually, I would telnet into the box.  First prompt is for login.  We can call it DigiAdmin for scripting purposes.  Second prompt is for password.  For scripting purposes, we can call it DigiPassword.  Exact command is boota=r.  So, the input is, in this order:
  1. DigiAdmin
  2. DigiPassword
  3. boota=r
If I understand correctly, assuming the IP list is a text file with one IP address per line and located at root of C, it would look like sample below.  If that is correct, all I would need to do is know how to define "stuff".

Get-Content -Path C:\RebootIPs.csv | ForEach-Object {Do stuff}

Open in new window

That bit I'm not entirely sure about.
DrUltima,

please provide a piece of code!

This comment is more or like a question on how "far" you are already ... maybe some changes to the scripts you are currently working on will do the trick ;) ...


Best regards,
Raisor
Raisor, I appreciate the suggestion, but I have no code to submit.  I am willing to do this in PowerShell or VBS, but the reality is I am not a programmer.  I have been tasked by my boss to come up with an easy way to reboot the digis that doesn't require manually connecting to each of them by a human.  The only way to reboot them remotely is to open a telnet session to the device, login, and and then pass the reboot command.  I have no idea how to accomplish this programatically.
OK, I found a PowerShell Script on the internet that I could base some logic off of.  The code below WORKS when it can connect to the destination IP.

When the destination does not respond or a connect fails, I get this error, and then the script closes completely:

Could not connect to remote computer: Exception calling ".ctor" with "2" argument(s): "A connection attempt failed beca
use the connected party did not properly respond after a period of time, or established connection failed because conne
cted host has failed to respond 1.1.1.1:23"
At H:\Reboot-Digis.ps1:46 char:17
+     trap { throw  <<<< "Could not connect to remote computer: $_"; exit }

What I want it to do is just move on to the next IP on the list.  If it gives a "cannot connect to xx.xx.xx.xx, moving on" type of message, that is lovely, but I don't need that.  I just need it to finish.

Also, I had to hard code the text file which contained the IP list. I want that to be an input variable, but I just don't know how to do that.  Either as a command line parameter or as a requested input, it doesn't matter to me.

I also had to force it to run as though it is not being run from the shell, in otherwords, right now, to run this script, I open PowerShell and type .\reboot-digis.ps1.  I would LOVE it if I could just click an icon or type a single line from a regular command prompt.

Any pointers appreciated.

# ==============================================================================================
# 
# Microsoft PowerShell Source File -- Created with SAPIEN Technologies PrimalScript 4.1
# 
# NAME: ME
# 
# AUTHOR: COMPANY NAME HERE
# DATE  : 3/25/2009
# 
# COMMENT: Code originally found at http://www.leeholmes.com/blog/ScriptingNetworkTCPConnectionsInPowerShell.aspx
# 
# ==============================================================================================
 
## Connect-Computer.ps1 
## Interact with a service on a remote TCP port 
param( 
        ##[string] $remoteHost = "xxx.xxx.xxx.xxx", 
        [int] $port = 23, 
        [string] $inputObject, 
        [int] $commandDelay = 100
     ) 
 
[string] $output = "" 
 
$currentInput = $inputObject 
if(-not $currentInput) 
{ 
    $SCRIPT:currentInput = @($input) 
} 
##I want it to always run batched, not wait for input, so I commented out the check and forced $scriptedMode
##$scriptedMode = [bool] $currentInput 
$scriptedMode = 1
 
##Here we have to replace username, password, and command with what we want to happen once the telnet session is opened.
##$currentInput = ("username","password","command")
$currentInput = ("USER","PASSWORD","boot a=r")
 
function Main 
{ 
    ## Open the socket, and connect to the computer on the specified port 
    if(-not $scriptedMode) 
    { 
        write-host "Connecting to $remoteHost on port $port" 
    } 
 
    trap { throw "Could not connect to remote computer: $_"; exit } 
    $socket = new-object System.Net.Sockets.TcpClient($remoteHost, $port) 
 
    if(-not $scriptedMode) 
    { 
        write-host "Connected.  Press ^D followed by [ENTER] to exit.`n" 
    } 
 
    $stream = $socket.GetStream() 
    $writer = new-object System.IO.StreamWriter($stream) 
 
    ## Create a buffer to receive the response 
    $buffer = new-object System.Byte[] 1024 
    $encoding = new-object System.Text.AsciiEncoding 
 
 
    while($true) 
    { 
        ## Receive the output that has buffered so far 
        $SCRIPT:output += GetOutput 
 
        ## If we're in scripted mode, send the commands, 
        ## receive the output, and exit. 
        if($scriptedMode) 
        { 
            foreach($line in $currentInput) 
            { 
                $writer.WriteLine($line) 
                $writer.Flush() 
                Start-Sleep -m $commandDelay 
            } 
 
            $SCRIPT:output += GetOutput 
 
            break 
        } 
        ## If we're in interactive mode, write the buffered 
        ## output, and respond to input. 
        else 
        { 
            if($output)  
            { 
                foreach($line in $output.Split("`n")) 
                { 
                    write-host $line 
                } 
                $SCRIPT:output = "" 
            } 
 
            ## Read the user's command, quitting if they hit ^D 
            $command = read-host 
            if($command -eq ([char] 4)) { break; } 
 
            ## Otherwise, Write their command to the remote host      
            $writer.WriteLine($command) 
            $writer.Flush() 
        } 
    } 
 
    ## Close the streams 
    $writer.Close() 
    $stream.Close() 
 
    ## If we're in scripted mode, return the output 
    if($scriptedMode) 
    { 
        $output 
    } 
} 
 
## Read output from a remote host 
function GetOutput 
{ 
    $outputBuffer = "" 
    $foundMore = $false  
 
    ## Read all the data available from the stream, writing it to the 
    ## output buffer when done. 
    do 
    { 
        ## Allow data to buffer for a bit 
        start-sleep -m 1000 
 
        ## Read what data is available 
        $foundmore = $false 
        while($stream.DataAvailable)  
        { 
            $read = $stream.Read($buffer, 0, 1024)    
            $outputBuffer += ($encoding.GetString($buffer, 0, $read))  
            $foundmore = $true 
        } 
    } while($foundmore) 
 
    $outputBuffer 
} 
 
##I eventually want to make $Digis = Get-Content $rebootList and have $rebootList defined as an input variable.
$Digis = Get-Content h:\test.csv
foreach ($remoteHost in $Digis) {. Main}

Open in new window

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial