How to get telnet output on PowerShell? - powershell

I thought I could run the command as below on PowerShell.
$output = & echo quit | telnet localhost 22
echo $output
However,
$output has nothing in it.
I'm trying to verify ssh or telnet connection.
Could you please tell me how to get output from above command ?

It is not possible. MS telnet doesn't use stdin/out. See here: C# + telnet process w/ redirected standard streams quits immediately
For redirecting the output of a telnet session you can use the -f logfile argument and then importing it into a variable after you are done with it: $output = get-contents logfile
For sending keycommands to telnet you could use $wshell = new-object -com wscript.shell and then:
start-process telnet -argumentlist "-f w:\tmp\log.txt";
sleep 1;
$wshell.SendKeys("quit{ENTER}")
Yes I know... not what you would expect, but it is the only way afaik with the MS builtin telnet console. If you know any better way, I would be glad to hear about it.
If you only want to check open ports, then why not just query them instead of telnetting? See here.

try this script and add it at start and end of your command to capture every logs
$ipV4 = (Test-Connection -ComputerName (hostname) -Count 1).IPV4Address.IPAddressToString -- this
Start-Transcript -Path .\TraceLogs_$ipV4.txt
<**Add your code here**>
Stop-Transcript
Here $ipV4 will capture the source host and logs will be generated in as file name .\TraceLogs_$ipV4.txt

Trying to adapt this for collecting Telnet output from APC PDUs (reading current load). The specified keys are successfully entered and the output is generated in the telnet session window, but the window doesn't close once the telnet session is ended. It stays open with "Connection to host lost."
I can press any key to close the window, but PS script execution does not continue, so no code following the SendKeys statement is executed.
Am I missing something simple? Code below.
$wshell = new-object -com wscript.shell
start-process telnet -argumentlist "pdu1-a6.domain.local -f c:\temptelnet.log"
sleep 1
$wshell.SendKeys("username{ENTER}password{ENTER}current{ENTER}quit{ENTER}")
$telnetoutput = get-content c:\temptelnet.log
$telnetoutput

Related

Powershell Script cycles through machines but hangs if one loses network temporarily

I have a powershell script that parses a txt file which is full of machine names, then one by one, it creates a session to the system, runs a few commands, and moves to the next system. The script usually take about 10-30 seconds to run on each system depending on the case encountered in the script.
Once in a while the system that is currently being checked will lose the network connection for some various reason. When this happens the console starts writing yellow warning messages about attempting to reconnect for 4 minutes and then disconnects the session when it cannot reconnect.
Even if it establishes the connection again within the 4 minutes, it doesn't do anything after that, it's like the script just freezes. It won't move on to the next system and it doesn't stop the script, I have to manually stop it, or if i manually run the script, i can hit control+c to break out of the current loop, and it then moves on to the next machine in the list.
Is there any way to break out of the current loop if a warning is encountered so it can move on to the next machine? That would be my ideal solution. thanks!
Script is simple..
foreach($server in Get-Content .\machines.txt) {
if($server -match $regex){
invoke-command $server -ErrorAction SilentlyContinue -ScriptBlock{
command1
command2
command3
}
}
this is what happens
PS C:\temp> .\script.ps1
machine1
machine2
machine3
machine4
machine5
WARNING: The network connection to machine5 has been interrupted. Attempting to reconnect for up to 4 minutes...
WARNING: Attempting to reconnect to machine5 ...
WARNING: Attempting to reconnect to machine5 ...
WARNING: Attempting to reconnect to machine5 ...
WARNING: The network connection to machine5 has been restored.
But it never goes on to machine6
When i work remotely with multiple machines i usually start the processes on the machines in parallel. So i have less impact when single machines are timing out. I use powershell 7 ForEach-Object -Parallel Feature for this https://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel-
feature/
Try something like this:
$Credential=Get-Credential
#all Necessary parameters must be in the Object i give to ForEach Object
$myHosts = #(
#Hosts i want to connect to with values i want to use in the loop
#{Name="probook";cred=$Credential;param1="one_1";param2="two_1"}
#{Name="probook";cred=$Credential;param1="one_2";param2="two_2"}
)
$var1="one"
$var2="two"
$myHosts | ForEach-Object -Parallel {
#Variables outside of this "Parallel" Loop are not available. Because this is startet as separate SubProcess
#All Values come from the Object i piped in the ForEach-Object
$myHost=$_
#This is written to your local Shell
Write-Host ("Computer: "+ $env:Computername)
Write-Host $myHost.param1
Write-Host $myHost.param2
Write-Host $myHost.cred.UserName
Invoke-Command -ComputerName $myHost.Name -Credential $myHost.cred -ArgumentList #($myHost.param1,$myHost.param2) -ScriptBlock {
#Variables outside of of this Invoke Command Script Block are not available because this is a new Remote-Shell on the remote Host
#Parameters in Ordner of -Argument List
param($param1,$param2)
#Do your things on the Remote-Host here
#This is not Visbible -> it is only written on the "remote Shell"
Write-Host $env:Computername
#Here you get Back Values from the remote Shell
$env:Computername
$param1
$param2
}
} -ThrottleLimit 5
Hmm his is indeed a Problem.
You could experiment with:
Start-Job
(https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/start-job?view=powershell-7.1)
Get-Job (https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/get-job?view=powershell-7.1)
Receive-Job (https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/receive-job?view=powershell-7.1)
So you have more control what the processes do.
You start Background Jobs with Start-Job. Start-Job deliveres Job Objects Back -> save them in a array or variables
With Get-Job you see all Jobs currently Running
with Receive-Job you get back the output from a Job so far. You can use receive-Job to get back all PSObjects a Background Job has written.
Cannot explain in Detail, but this woul be another try i would do for this job.

Open multiple remote sessions using 'mstsc' in powershell script

I am trying to write a powershell script that opens a remote desktop connection for each machine name saved in a text file. When I run the script, it only connects to the first machine in the list and outputs to the console: CMDKEY: Credential added successfully once (not once for each machine). mstcs seems to terminate the process after executing, and I'm not sure I'm adding credentials the right way. Can anyone point me in the right direction?
Here are some tests I've tried to figure out what's going on:
Print after mstsc. Doesn't print. Process seems to terminate after
mstcs is called. This seems to be the crux of the issue.
cmdkey /list shows all the credentials I have stored and their targets. The output does not include all the targets defined in the text file. Even if I comment out mstsc, then cmdkey /add:$MachineName /user:$User /pass:$Password only seems to execute for the first line, evidenced by the lack of more console outputs and cmdkey /list not yielding the expected targets. In addition, I have added a print statement after this cmdkey line and it prints for each line, so it doesn't terminate after running (which I already knew because mstcs executes after this line when it's not commented out).
# Read from file
$Lines = Get-Content -Path .\machines.txt | Out-String
# For each machine ...
foreach($Line in $Lines){
# Split line, save name and domain
$Tokens = $Line.Split(".")
$MachineName = $Tokens[0]
$Domain = $Tokens[1]
$User = "someDomain\someUsername"
$Password="somePassword"
# Switch username if someOtherDomain
if ($Domain -eq "someOtherDomain"){
$User = "someOtherDomain\someOtherUsername"
}
#set credentials and open connection
cmdkey /add:$MachineName /user:$User /pass:$Password
mstsc /v:$MachineName /console
}
EDIT: I have also tried replacing mstsc /v:$MachineName with Start-Process -FilePath "$env:windir\system32\mstsc.exe" -ArgumentList "/v:$MachineName" -Wait. The result is opening the session and then the script does not finish in the console but nothing additional happens.
This behavior is cause by your use of Out-String.
Get-Content outputs multiple strings, one per line in the file - but Out-String stitches them back together into a single multi-line string:
PS C:\> $machines = Get-Content machines.txt
PS C:\> $machines.GetType().Name # definitely an array
Object[]
PS C:\> $machines.Count # multiple strings in there
4
PS C:\> $machines = Get-Content machines.txt | Out-String
PS C:\> $machines.GetType().Name # now it's just a single string
String
So your foreach(){} loop only runs once, and the value of $MachineName is no longer the name of a single machine, but a multi-line string with all of them at once - which is probably why mstsc exits immediately :)
Remove |Out-String from the first line and your loop will work

Can PowerShell interact with RDP prompts?

I'm currently writing a script to automate a number of checks, I have a number of clients which I want to automatically log into one of their servers or use an app hosted via RDweb.
Right now my script works fine, however, I'm only able to get to the point that it'll start to execute the RDP pointer, I'm wondering if there's a way to hit "connect":
The method I'm currently using to run this:
[System.Diagnostics.Process]::Start("c:\file\path\file.rdp")
Is there a better way to run the .RDP file which will also allow you to "Connect"? I've also attempted to tick the "don't ask me" again, the next day it'll still prompt me with this message.
A solution I've found to start an RDP session that seems to work quite good is the following:
function Connect-RDP {
param (
[Parameter(Mandatory=$true)]
$ComputerName,
[System.Management.Automation.Credential()]
$Credential
)
# take each computername and process it individually
$ComputerName | ForEach-Object {
# if the user has submitted a credential, store it
# safely using cmdkey.exe for the given connection
if ($PSBoundParameters.ContainsKey('Credential'))
{
# extract username and password from credential
$User = $Credential.UserName
$Password = $Credential.GetNetworkCredential().Password
# save information using cmdkey.exe
cmdkey.exe /generic:$_ /user:$User /pass:$Password
}
# initiate the RDP connection
# connection will automatically use cached credentials
# if there are no cached credentials, you will have to log on
# manually, so on first use, make sure you use -Credential to submit
# logon credential
mstsc.exe /v $_ /f
}
}
Then you call it with Connect-rdp -ComputerName myserver -Credential (Get-Credential ).
Maybe you can adjust your script to use this cmdlet instead of your file.rdp.
I found the solution here:
https://www.powershellmagazine.com/2014/04/18/automatic-remote-desktop-connection/
Another way you could try is this:
[void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
# Get the ID of the process
$WindowsHandle = Get-Process | Where-Object { $_.MainWindowTitle -Match 'Remote Desktop Connection' } | Select-Object -ExpandProperty Id
# Activate the window
$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate($WindowsHandle) | Out-Null
# SendKey to connect
[System.Windows.Forms.SendKeys]::SendWait("%{c}")
%{c} stands for ALT+C
The modifier keys are:
Key | Code
-----------
SHIFT +
CTRL ^
ALT %

How to redirect or retrieve the output of a telnet process ran by a Powershell script?

I am running a Powershell script that starts a telnet process which will connect on a client machine and run a command. The client machine's operating system is a personalized version of VxWorks, and the command I'm using on the telnet calls a tool developed internally on the machine:
mediaGet("gei",1)
I'd like to retrieve the output of the code and log it.
I've tried using the parameters -NoNewWindow and -RedirectStandardOutput on the Powershell script, but it only creates me an empty file which means it fails to retrieve the output.
Here is the Powershell script:
Start-Process -FilePath 'telnet.exe' -ArgumentList '162.100.10.10'
[system.reflection.assembly]::loadwithpartialname("System.Windows.Forms")
$SendKeys = [System.Windows.Forms.SendKeys]
$sendkeys::SendWait('mediaGet{(}"gei"{)},1')
Start-Sleep -Seconds .5
$sendkeys::SendWait("{ENTER}")
Start-Sleep -Seconds .5
$sendkeys::SendWait("exit{ENTER}")
(Credits of this code go to the selected answer of this question How to use a string variable as a telnet command in a vbscript?)
This is the output of the code
mediaGet("gei",1)
> media: 12345
> up: 1000 full duplex
I would like a text file at the end with the following lines:
media: 12345
up: 1000 full duplex
How can I get there?
Komputer.
Yeppers, I missed getting back to you on the other Q&A. Good to see you are getting the response back now.
But even if that was in text file, you can just replace it after.
$TelnetData = #'
mediaGet("gei",1)
> media: 12345
> up: 1000 full duplex
'#
Clear-Host
$TelnetData -replace 'mediaGet|\("gei",1\)|> ', ''
# Results
media: 12345
up: 1000 full duplex
You can do this as the file is written as well, in normal cases.
However, on the redirect stuff, the common thing is,
MS telnet doesn't use stdin/out.
So, approaches like this …
For redirecting the output of a telnet session you can use the ...
-f logfile
...argument and then importing it into a variable after you are done with it:
$output = get-contents logfile
... are often brought up.
So, maybe this will get you where you want to be...
Start-Process -FilePath 'telnet.exe' -ArgumentList '162.100.10.10', '-f E:\Temp\log.txt'
[system.reflection.assembly]::loadwithpartialname("System.Windows.Forms")
$SendKeys = [System.Windows.Forms.SendKeys]
$sendkeys::SendWait('mediaGet{(}"gei"{)},1')
Start-Sleep -Seconds .5
$sendkeys::SendWait("{ENTER}")
Start-Sleep -Seconds .5
$sendkeys::SendWait("exit{ENTER}")
Once you do the above, then you can run the clean-up on it, using what I have above, via the Get-Content and / or Set-Content cmdlets.
Of course I cannot access the IPA you list, nor do I have that MediaGet thing, but a quick test to a telnet capable site, will do this.
Start-Process -FilePath 'telnet.exe' -ArgumentList 'www.cyberciti.biz 80', '-f E:\Temp\log.txt'
[system.reflection.assembly]::loadwithpartialname("System.Windows.Forms")
$SendKeys = [System.Windows.Forms.SendKeys]
$sendkeys::SendWait("mediaGet'(''gei''',1)'")
Start-Sleep -Seconds .5
$sendkeys::SendWait("{ENTER}")
Start-Sleep -Seconds .5
$sendkeys::SendWait("exit{ENTER}")
# PowerShell Terminal output.
GAC Version Location
--- ------- --------
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
# Telnet Window and text file content
Get-Content -Path 'E:\Temp\log.txt'
HTTP/1.1 400 Bad Request
Server: cloudflaree
Date: Sat, 18 May 2019 08:39:59 GMTi
Content-Type: text/html'Content-Type: text/html'
Connection: close
Connection: close
<html>
<head><title>400 Bad Request</title></head>e
<body bgcolor="white">i
<center><h1>400 Bad Request</h1></center>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>

How to authenticate a Firewall web page via Powershell / Selenium-Chrome Driver?

I developed several scripts in Powershell to automate the configuration of machines where I work, streamlining and avoiding the hard work of manually configuring a huge amount of stations. Basically they use disable UAC, autologon, and Task Scheduler.
Image: https://i.stack.imgur.com/pkuDl.png
The biggest problem is the use of the Fortinet Firewall that asks for authentication via browser, since much of the application uses files for installation that are on the server via SMB, it is necessary to do this authentication, because without it it is not possible for the algorithm to authenticate to the server, causing it to fail on the course.
Image: https://i.stack.imgur.com/bqZAR.png
Page URL: https://authenticator.mpms.mp.br/caplogin/?login&post=http://10.111.147.1:1000/fgtauth&magic=0202e294cb1c7073&usermac=10:e7:c6:c5:c3:61&apmac=00:00:00:00:00:00&apip=10.111.147.1&userip=10.111.147.22&ssid=PGJ-BANCADA&apname=FGT2KE3917900027&bssid=00:00:00:00:00:00&device_type=windows-pc
However, by testing this through Selenium it even authenticates, but after the computer restarts and runs the next script, it asks for authentication again.
Follow the code that I made to authenticate in Fortnet, followed after the login, to make a request in the globo.com site
############################################
######## Enable Fortinet Firewall ##########
############################################
$YourURL = "https://authenticator.mpms.mp.br/"
# Adds the path for ChromeDriver.exe to the environmental variable
$env:PATH += ";C:\Util\PSL\"
# Adding Selenium's .NET assembly (dll) to access it's classes in this PowerShell session
Add-Type -Path "C:\Util\PSL\WebDriver.dll"
$ChromeOptions = New-Object OpenQA.Selenium.Chrome.ChromeOptions
$ChromeDriver = New-Object OpenQA.Selenium.Chrome.ChromeDriver($ChromeOptions)
$ChromeDriver.Capabilities.BrowserName
# Browse to the specified website
$ChromeDriver.Navigate().GoToURL($YourURL)
# Methods to find the input textbox for google search and then to type something in it
$ChromeDriver.FindElementByName("username").SendKeys("username")
$ChromeDriver.FindElementByName("password").SendKeys("password")
$ChromeDriver.FindElementsByClassName("submit").Submit()
#### New page #####
$YourURL = "https://www.globo.com/"
$ChromeDriver.Navigate().GoToURL($YourURL)
Function Stop-ChromeDriver {Get-Process -Name chromedriver -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue}
# Close selenium browser session method
$ChromeDriver.Close()
# End ChromeDriver process method
$ChromeDriver.Quit()
# Function to make double sure the Chromedriver process is finito (double-tap!)
Stop-ChromeDriver
When we do this manually, the next steps will run normally, which by my conclusion makes the Selenium driver not really the Google Chrome browser, but rather its own one, which means that it does not recognize authentication. .
The question that remains is: Is it possible to add this option in the script so that we can authenticate to Fortinet Web and thus avoid manual steps and automate our work? I wish I could perform this task for Powershell, but I'm available with another alternative.
Thank you!
Why not use vbs in PowerShell` to send required authorizations?
$wshell = New-Object -ComObject wscript.shell; $obj = New-Object -com Wscript.Shell;
$wshell.AppActivate('Chrome');
pathping 127.0.0.1 -n -q 1 -p 300 >$null
$obj.SendKeys('paulogoncalves');
pathping 127.0.0.1 -n -q 1 -p 150 >$null
$obj.SendKeys("{TAB}")
pathping 127.0.0.1 -n -q 1 -p 150 >$null
$obj.SendKeys('senhasecreta')
pathping 127.0.0.1 -n -q 1 -p 150 >$null
$obj.SendKeys('{ENTER}');```