Output ssh command to text file in powershell - powershell

I am trying to output the following command to a text file in powershell, but I cannot seem to get it working:
ssh -v git#git.assembla.com | Out-File C:\output.txt

As stated in the post below with using native apps, you could try using Start-Process, e.g.
Start-Process ssh "-v git#git.assembla.com" -NoNewWindow -RedirectStandardOutput stdOut.log -RedirectStandardError stdErr.log; gc *.log; rm *.log

Working on the same problem I made a detail post on my blog How to SSH from Powershell Using Putty\Plink but the short version is this bit of code. But sure you try it after installing putty.
Function Invoke-SSHCommands {
Param($Hostname,$Username,$Password, $CommandArray, $PlinkAndPath, $ConnectOnceToAcceptHostKey = $true)
$Target = $Username + '#' + $Hostname
$plinkoptions = "-ssh $Target -pw $Password"
#Build ssh Commands
$remoteCommand = ""
$CommandArray | % {$remoteCommand += [string]::Format('{0}; ', $_) }
#plist prompts to accept client host key. This section will login and accept the host key then logout.
if($ConnectOnceToAcceptHostKey)
{
$PlinkCommand = [string]::Format('echo y | & "{0}" {1} exit', $PlinkAndPath, $plinkoptions )
#Write-Host $PlinkCommand
$msg = Invoke-Expression $PlinkCommand
}
#format plist command
$PlinkCommand = [string]::Format('& "{0}" {1} "{2}"', $PlinkAndPath, $plinkoptions , $remoteCommand)
#ready to run the following command
#Write-Host $PlinkCommand
$msg = Invoke-Expression $PlinkCommand
$msg
}
$PlinkAndPath = "C:\Program Files (x86)\PuTTY\plink.exe"
$Username = "remoteshell"
$Password = "pa$$w0rd"
$Hostname = "Linuxhost"
$Commands = #()
$Commands += "ls"
$Commands += "whoami"
Invoke-SSHCommands -User $Username -Hostname $Hostname -Password $Password -PlinkAndPath $PlinkAndPath -CommandArray $Commands

Related

How to suppress "keyboard-interactive" prompts in plink.exe

I have a PowerShell script that calls plink.exe regularly. Normally, the two output lines about keyboard-interactive prompts are simply annoying.
However, when run using Start-Job, they get output as error text as soon as I call Receive-Job.
Is there any way to suppress these? I'd rather not suppress all errors.
My test code:
$test_scriptblock = [scriptblock]::Create(#"
param(
`$argumentlist
)
`$pw = `$argumentlist.pw
& 'C:\Program Files\Putty\Plink.exe' -ssh `"admin#*.*.*.*" -pw `$pw -batch whoami
"#)
$testParm = #{
pw = Read-Host "password"
}
$testjob = Start-Job -scriptblock $test_scriptblock -Argumentlist $testParm
$i = 0
do {
$i++
sleep 2
$results = Receive-Job $testjob
ForEach ($result in $results) {
Write-Host $result
}
if ($testjob.State -eq "Completed") {
$jobcompleted = $true
}
If ($i -gt 10) {
Stop-job $testjob
$jobcompleted = $true
}
} until ($jobcompleted)
Just add the stderr redirect to your plink or pscp commandline, to an extra dummy file, like
pscp ... 2> stderr.txt
With a caveat that it may swallow other valid error msgs, at your own risk :)
There's no way to suppress keyboard-interactive prompts in Plink.
I suggest you use a native .NET SSH implementation, like SSH.NET instead of driving an external console application.
Ir was a bit cumbersome, but finally I managed to suppress the "keyboard-interactive" messages this way:
[String] $Plink = 'C:\Program Files\PuTTY\plink.exe'
[Array] $PlinkPar = #("-ssh", "-l", $usr, "-pw", $pwd, $hst) # Set plink parameters
[Boolean] $PlinkOK = $True
Write-Host "Accept possibly unknown host key"
"y" | & $Plink $PlinkPar "exit" 2>&1 | Tee-Object -Variable PlinkOut | Out-Null
$PlinkOut | Foreach-Object {
$PlinkStr = $_.ToString()
If ($_ -is [System.Management.Automation.ErrorRecord]) {
If (! $PlinkStr.Contains("eyboard-interactive")) {
Write-Host "Error: $PlinkStr"
$PlinkOK = $False
}
} else {
Write-Host "$PlinkStr"
}
}
If (! $PlinkOK) { exit }
$PlinkPar += "-batch
And the output is like this:
>powershell .\InstCR.ps1 -usr myuser -pwd mypassword -hst doesnotexist
Accept possibly unknown host key
Error: Unable to open connection:
Error: Host does not exist
This plink call is just to accept a possibly unknown host key (without "-batch" and piping the "y" to answer the prompt). Then "-batch" is added to the Plink parameters to be used on all subsequent plink calls.

How to trigger a bat file on remote server only after the pssession is formed on the server

Write-Host "Welcome to Application Process Start/Stop Dashboard" -ForegroundColor Green
Write-Host "`n" "1) Stop" "`n" "2) Start"
[int]$resp = Read-Host "Choose option 1 or 2 for stopping or starting application process respectively"
if($resp -eq 1)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$result = [System.Windows.Forms.MessageBox]::Show('Are you sure you want to STOP ?', "Info" , 4 )
if ($result -eq 'Yes')
{
$user = "NAmarshmellow"
$server = "Desktop_10U"
$storesess = New-PSSession -ComputerName $server -Credential $user
Enter-PSSession -Session $storesess
$path = "\\Users\mellow\Documents\Proj"
$pwd = Read-Host -AsSecureString
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwd)
$value = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
NET USE $path /user:$user $value
Start-Process cmd -ArgumentList "/C C:\Users\Desktop_10U\Documents\Some\Stop.bat" -Wait
Clear-Variable storesess
Exit-PSSession
}
}
I want to trigger a bat file which has some commands that will stop a specific application process. To stop this application process there are specific commands which requires triggering the cmd file on a network drive. So I have written a code which will form PSSession and after the PSSession is formed only then the NET USE command should run. If I first form the PSSession and then trigger the command manually fire the NET USE command then it works fine. But when I trigger the code as a whole it doesn't run fine it throws below error.
NET : System error 1219 has occurred.
At line:18 char:1
+ NET USE $path /user:$user $value
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (System error 1219 has occurred.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared
resource and try again.
The issue is that Enter-PSSession only works via an interactive prompt. aka. You typing in commands into a prompt. A script/running everything together is not interactive (i.e. you can't start entering in commands into the middle of the running script).
The work around is to use Invoke-Command and place everything you want to perform in a script block. This way can be executed as non-interactive commands. e.g.:
....
$user = "NAmarshmellow"
$server = "Desktop_10U"
$path = "\\Users\mellow\Documents\Proj"
$pwd = Read-Host -AsSecureString
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwd)
$value = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
$script = {
$user = $Using:user
$path = $Using:path
$value = $Using:value
NET USE $path /user:$user $value
Start-Process cmd -ArgumentList "/C C:\Users\Desktop_10U\Documents\Some\Stop.bat" -Wait
}
Invoke-Command -ComputerName $server -Credential $user -ScriptBlock $script
....

Issues with colon (:) in when next to variable in PowerShell

I am trying to get the following to work so I can automate some SCP uploads I need to do. I believe the problem is how ${user}#${device} is being interpreted.
$user = "user1"
$device = "server1"
Start-Process 'C:\Program Files\PuTTY\pscp.exe' `
-ArgumentList ("c:\temp\myfile.txt ${user}#${device}:/shared/tmp/") -NoNewWindow
I've tried $user#$device (powershell barks about syntax), $user#${device}and ${user}#${device} (these tell me you can't copy from local to local which indicates in is not parsing the :/shared/tmp/ correctly.)
You can also escape the : with `:
"c:\temp\myfile.txt ${user}#${device}`:/shared/tmp/"
As always, unless you have a specific reason for using Start-Process: don't bother. Use the call operator (&) instead.
This worked perfectly fine when I just tested it:
$user = 'user1'
$device = 'server1'
$params = 'c:\temp\myfile.txt', "${user}#${device}:/shared/tmp/"
& 'C:\Program Files\PuTTY\pscp.exe' #params
Try this:
$user = "user1"
$device = "server1"
Start-Process 'C:\Program Files\PuTTY\pscp.exe' `
-ArgumentList ("c:\temp\myfile.txt {$($user)}#{$($device)}:/shared/tmp/") -NoNewWindow
try this:
$user = "user1"
$device = "server1"
$Program='C:\Program Files\PuTTY\pscp.exe'
$Arguments="c:\temp\myfile.txt {0}#{1}:/shared/tmp/ -NoNewWindow" -f $user, $device
Start-Process $Program $Arguments

Powershell Msdeploy command error

I am trying to invoke Msdeploy in powershell , which is part of a teamcity build task.
My script is like this below
$folderName = "packageTmp"
$packagePath = (gci -path %teamcity.build.checkoutDir%\extract -filter $foldername -Recurse | Select-Object -Expand FullName) |Out-String
$azureSite ="%azureSite%"
$azurePublishUrl = "%azurePublishUrl%"
$azureUsername ="%azureUsername%"
$azurePassword = "%azurePassword%"
$localPath =$packagePath
$server ="https://$azurePublishUrl/msdeploy.axd?site=$azureSite,UserName=$azureUsername,Password=$azurePassword,AuthType=Basic"
$remotePath="%azureSite%"
$env:Path += ";C:\Program Files\IIS\Microsoft Web Deploy V3"
function PushToTarget() {
param([string]$server, [string]$remotePath, [string]$localPath)
cmd.exe /C $("msdeploy.exe -verb:sync -source:contentPath=`"{0}`" -dest:computerName=`"{1}`",contentPath=`"{2}`" -whatif" -f $localPath, $server, $remotePath )
}
echo "Server: " $server
echo "remote path: " $remotePath
echo "local path: " $localPath
PushToTarget "$server" "$remotePath" "$localPath"
while i run this i get following error , error stack follows
Error: A '-dest' argument must be specified with the 'sync' verb.
As error says i have included sync keyword already.
what i am doing wrong and how can i rectify it ?
i tried to use following solutions
solution1
stackoverflow post
I don't see a problem in your script but PS can be particular.
Here is how the new ASP.NET 5 PS-based deployment executes MSDeploy.exe maybe this will work better for you:
$webrootOutputFolder = (get-item (Join-Path $packOutput $webroot)).FullName
$publishArgs = #()
$publishArgs += ('-source:IisApp=''{0}''' -f "$webrootOutputFolder")
$publishArgs += ('-dest:IisApp=''{0}'',ComputerName=''{1}'',UserName=''{2}'',Password=''{3}'',IncludeAcls=''False'',AuthType=''Basic''{4}' -f
$publishProperties['DeployIisAppPath'],
(Get-MSDeployFullUrlFor -msdeployServiceUrl $publishProperties['MSDeployServiceURL']),
$publishProperties['UserName'],
$publishPwd,
$sharedArgs.DestFragment)
$publishArgs += '-verb:sync'
$publishArgs += '-enableLink:contentLibExtension'
$publishArgs += $sharedArgs.ExtraArgs
$command = '"{0}" {1}' -f (Get-MSDeploy),($publishArgs -join ' ')
if (! [String]::IsNullOrEmpty($publishPwd)) {
$command.Replace($publishPwd,'{PASSWORD-REMOVED-FROM-LOG}') | Print-CommandString
}
Execute-Command -exePath (Get-MSDeploy) -arguments ($publishArgs -join ' ')

How can I automate none-PATH plink (Putty Link) on windows? and get its output?

I have been trying both standard PS1 using what I read about using:
ECHO y | plink .....
But the issue I have is that plink is being saved on a network drive. I can call it using:
$plink = "P:\path\plink.exe"
echo y | &$plink -ssh -l user-pw password $addrss exit
&$plink -ssh -l user -pw password -m "P:\path\SCOTDiagScript.txt" $addrss
The issue I have is that if I run plink manually via cmd, I get output, that I need to read and possibly display to the user. Piping the last line to Out-File gives me nothing and if I try to call cmd to then redirect to a txt file, I get an error because the path for plink has a space in it; and I am using quotes.
I have also given using .NET a try, but doing a .StandardOutput.ReadToEnd() causes it to hang; deadlock maybe? Even though I am placing it well before the exit and I have it sleep a bit before any type of exit takes place:
$ps = New-Object -TypeName System.Diagnostics.Process
$ps.StartInfo.UseShellExecute = $false
$ps.StartInfo.RedirectStandardInput = $true
$ps.StartInfo.RedirectStandardOutput = $true;
$ps.StartInfo.FileName = "P:\path\plink.exe"
$ps.StartInfo.Arguments = "-ssh -l user -pw password $addrss"
[void]$ps.Start()
Start-Sleep -m 500
$ps.StandardInput.Write("cd c:/scot/bin`r")
Start-Sleep -m 500
$ps.StandardInput.Write("GetDiagFiles.exe`r")
Start-Sleep -m 500
$ps.StandardInput.Write("cd c:/temp`r")
Start-Sleep -m 500
$ps.StandardInput.Write("ls *.zip`r")
Start-Sleep -m 500
$ps.StandardInput.Write("cd c:/scot/monitor`r")
$Out = $ps.StandardOutput.ReadToEnd();
Start-Sleep -s 10
$ps.StandardInput.Write("exit`r")
$PlinkStreamWriter.Close();
if (!$ps.HasExited) { $ps.Kill() }
$Out
I'm sure I'm doing something wrong, but I have scoured over everything at MSDN and nothing.
Doing what you ask should be as easy as:
plink -ssh -l user -pw password -m script.txt > output.log
Where the script.txt contains your commands:
cd c:/scot/bin
GetDiagFiles.exe
cd c:/temp
ls *.zip
cd c:/scot/monitor
exit
If this does not work (as you claim you have tried something similar), give us more details about the problem.
You have not created a System.Diagnostics.ProcessStartInfo object to feed into the System.Diagnostics.Process object.
You needed to put `n at the end of the commands not `r, or you can remove them altogether when using the .WriteLine method
I tested the code below using some cmd.exe and made the alterations you need, it should work with plink.exe
$ProcessStartInfo = New-Object System.Diagnostics.ProcessStartInfo
$ProcessStartInfo.UseShellExecute = $false
$ProcessStartInfo.RedirectStandardError = $true
$ProcessStartInfo.RedirectStandardInput = $true
$ProcessStartInfo.RedirectStandardOutput = $true
$ProcessStartInfo.FileName = "P:\path\plink.exe"
$ProcessStartInfo.Arguments = "-ssh -l user -pw password $addrss"
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $ProcessStartInfo
$Process.Start() | Out-Null
$Process.StandardInput.WriteLine("cd c:/scot/bin")
$Process.StandardInput.WriteLine("GetDiagFiles.exe")
$Process.StandardInput.WriteLine("cd c:/temp")
$Process.StandardInput.WriteLine("ls *.zip")
$Process.StandardInput.WriteLine("cd c:/scot/monitor")
$Process.StandardInput.WriteLine("exit")
$Process.WaitForExit()
$stdoutput = $Process.StandardOutput.ReadToEnd()
$erroutput = $Process.StandardError.ReadToEnd()
Write-Host "Standard Output: $stdoutput"
Write-Host "Error Output : $erroutput"
Write-Host "exit code: " + $Process.ExitCode