Is there a SCP alternative for PowerShell? - powershell

I need to write a script that transfers files from a folder onto another server (Linux), but the script that's transferring files is on windows, and I was wondering if there was an alternative to scp for PowerShell (or if there was another way of doing this)

There is a handy little tool that comes with Putty called pscp.exe that will do this and can be called in powershell easily.
Example below copies from windows to a CentOS box (logging in as the usercode "bill") and you use the -pw switch in pscp to pass in a password (otherwise the command window that is spawned will prompt for the Linux password):
Start-Process 'C:\Program Files (x86)\PuTTY\pscp.exe' -ArgumentList ("-scp -pw password C:\Document.rtf bill#192.168.0.28:/home/bill/")
PuTTY Secure Copy client
Release 0.62
Usage: pscp [options] [user#]host:source target
pscp [options] source [source...] [user#]host:target
pscp [options] -ls [user#]host:filespec
Options:
-V print version information and exit
-pgpfp print PGP key fingerprints and exit
-p preserve file attributes
-q quiet, don't show statistics
-r copy directories recursively
-v show verbose messages
-load sessname Load settings from saved session
-P port connect to specified port
-l user connect with specified username
-pw passw login with specified password
-1 -2 force use of particular SSH protocol version
-4 -6 force use of IPv4 or IPv6
-C enable compression
-i key private key file for authentication
-noagent disable use of Pageant
-agent enable use of Pageant
-batch disable all interactive prompts
-unsafe allow server-side wildcards (DANGEROUS)
-sftp force use of SFTP protocol
-scp force use of SCP protocol

pscp.exe is a viable option, but I have been using a library from Rebex for a couple years now for SFTP and FTPS transfers in both C# apps and PowerShell scripts with great success. Their package also includes an SCP object but I haven't personally used it.
It does cost money vs. pscp being free. Before selecting the Rebex package, I had considered going the PuTTY route but my team decided that having a library we could easily roll into any app/script was worthwhile in the long term.

You can use WinSCP .NET assembly from PowerShell for SCP transfers.
For example see http://winscp.net/eng/docs/library_powershell#example
The example uses SFTP protocol. To use SCP, just modify it to:
$sessionOptions.Protocol = [WinSCP.Protocol]::Scp
Though if your server support SCP protocol, it's likely it also supports SFTP. SFTP is better choice, if you have the option.

Why use an alternative to SCP when you can use SCP?
Windows has OpenSSH (which includes SCP) as an optional component these days, so you could just use that. It first appeared in the Autumn 2018 version of Windows 10. It's nearly identical to the command you find in most Linux distributions, as it's derived from the same code base. Microsoft just made one or two minor tweaks to make it work on windows.
It is simple to install just go to Start->Settings->Apps->Optional Features->View Features enter in OpenSSH in the search box and check the OpenSSH client and click next. See OpenSSH in Windows for more detailed instructions on how to set it up. For a more PowerShell way of installing it run this from an elevated PowerShell prompt:
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
You can use this command to check if there is a newer version and whether you already have it installed:
Get-WindowsCapability -Online | Where Name -Like '*ssh*'
Once installed, you call scp from PowerShell just like you would any other executable command.
scp file.dat user.name#example.com:/target/path
If you really don't want to use SCP use Copy-Item
This requires PowerShell to be installed on your server. Yes you can install PowerShell on Linux. Just call Copy-Item with the -ToSession parameter passed an SSH connected session, I've never actually tried it though. It requires a recent version of PowerShell and some setting up see PowerShell remoting over SSH. Something like this:
Copy-Item C:\localPath\*.* ~\remotePath\ -ToSession (New-PSSession -HostName UserA#LinuxServer01:22 -KeyFilePath c:\\userAKey_rsa)
If both machines are Windows machines you can use the same -ToSession parameter to copy files over WinRM. But both machines have to be domain joined or there is the possibility of security issues.

There is also a ".NET friendly" way:
you can use the SharpSSH dll to execute ssh commands, and do scp/sftp tranfers.
For example:
[Reflection.Assembly]::LoadFrom((Resolve-Path .\Tamir.SharpSSH.dll))
$ssh = New-Object Tamir.SharpSsh.Sftp("server","user","password")
$ssh.Connect()
$ssh.Put("C:\localfile","distantfile")
$ssh.Close()
There is the SSH.Net library, too, it does approximatively the same things.

Related

Redirect WSL input in Powershell

I've been trying to write a powershell script that automates my windows workspace setup and configuration and am currently stuck trying to redirect input to WSL when executing it for the first time. The core of the problem is that Ubuntu's first launch prompts for a username and password, then logs in to a bash shell. I tried writing down the input lines into a text file like so:
Username
Password
Password
exit
Then, I tried redirecting the input of wsl to the file:
Start-Process ubuntu2004.exe -RedirectStandardInput stdin.txt -NoNewWindow -Wait
The above didn't work as executing WSL just starts spamming Enter new UNIX username: adduser: only one or two names allowed. I tried doing same in CMD with the < input redirection, but the result is the same.
This is not exactly the answer to your question, but in my opinion, ansible is better suited for such a task.
I myself recently became interested in assembling a workspace in wsl and ansible seemed to me the best solution.
Before starting the build, you will need to perform minimal steps (create a user and install several packages, all this can be placed in the readme), but then there will be no restrictions.
You can find several ready-made examples of wsl assembly via ansible on github.
A few ideas for setting the username/password in a new Ubuntu WSL instance:
First, a "PowerShell sendkeys" via COM or Interop might work for this. It's probably the closest in behavior to what you are actually asking.
Second, and perhaps most promising, I just tried this with a new Debian WSL installed from the Store (since I didn't want to mess with my Ubuntu install).
When running debian.exe (like ubuntu2004.exe), I let it run the install, then I Ctrl+C'd out of it when it started asking for the default username/password. At that point, the WSL instance is installed, but with only root. I assume that your script can let the command run for a certain period of time, then kill the process to replicate this.
From your script, you should then be able to run wsl -u root useradd --create-home --user-group --groups adm,dialout,cdrom,floppy,sudo,audio,dip,video,plugdev,netdev --password "encryptedPassword" username (see here for creating the encrypted password). I think that will get you a stock Ubuntu user the way that WSL sets it up.
You'll then need to either create a /etc/wsl.conf file (instructions) letting the instance know that that user is the default, or LxRunOffline lists this as one of its features.
But I'd also throw in that you might just want to keep a "backup" of an existing WSL instance that you start from. Do a wsl --export <distroname> <imagename.tgz>, then you can import it when setting up the new Windows host by copying the tgz over and doing a wsl --import <DistroName> <DirectoryWhereYouwantItToLive> <imagename.tgz>.
If you want, you can keep this image up to date with your desired WSL configuration, so that you don't have to recreate it when you rebuild the Windows hosts. That said, this is where I do follow #Mystic's suggestion of using Ansible to store my WSL "configuration as code". It allows me to not only recreate my WSL instances, but also that same configuration when I set (or reset) a Linode host or another Linux system.

Reuse in PowerShell a running PuTTY agent (pageant)

Is there a way in PS 5.1 to reuse the PuTTY agent keys?
Now, the details.
To use key agents one has an Agent that holds the keys (left box), and Client Applications that delegate administration of the keys (right box).
E.g., client application C1=putty can use its own agent A1=pageant, of course.
Client application C2=winscp knows how to use directly A1.
Certain Clients cannot use certain Agents directly, but there are Proxy agents that bridge the gap.
For instance to use A1 with C3, I need Proxy P1=ssh-pageant, see example below.
This helps centralizing in a single Agent the keys for many Clients.
Now I mean to use A1 for all my Clients (currently, only missing A1-C5 and A1-C6).
Is there a way in PS 5.1 to reuse the same PuTTY agent keys?
(I.e., a Proxy Px to use A1 with C5)
Possibly helpful:
https://superuser.com/a/1173570/245595
NOTES:
I did not try it, but it seems like winssh-pageant is a Proxy to link A2 with Client applications that understand A1 directly.
I am currently trying to use in PS the same ssh-pageant from msys2 (it is a Windows program in the end, and often times they do work), manually replacing what eval does in msys2 (so far with no luck, but I think this is fixable):
> cd <dir where ssh-pageant is>
> .\ssh-pageant -r -a "$env:USERPROFILE\tmp\.ssh-pageant-$env:USERNAME"
SSH_AUTH_SOCK='C:\Users\USER1\tmp\.ssh-pageant-USER1'; export SSH_AUTH_SOCK;
SSH_PAGEANT_PID=714; export SSH_PAGEANT_PID;
echo ssh-pageant pid 714;
> $env:SSH_AUTH_SOCK='C:\Users\USER1\tmp\.ssh-pageant-USER1'
> $env:SSH_PAGEANT_PID=714
> ssh myserver
Enter passphrase for key 'C:\Users\USER1/.ssh/id_rsa':
As an alternative workaround, is there a non-admin (I wouldn't want to interfere with it) way to load keys into a separate agent such that when I start a PS session it uses those other keys, and which allows me to keep working with my reused keys in msys2?
This would perhaps amount to using a two different agents at the same time...
weasel-pageant is such a proxy agent (based on Cygwin's ssh-pageant), for WSL (A1-C7)... still looking for a solution for PS.
ssh-agent-wsl
is a fork of weasel-pageant that includes support for using keys held by Microsoft's SSH Agent service (instead of PuTTY Pageant) (A2-C7... I guess it's remarkable that WSL needs a proxy to use Win OpenSSH agent).
Example on how to use "Proxy" agent ssh-pageant to link PuTTY pageant with Cygwin bash
The steps to achieve this are:
When I start my session in Windows, the portable PuTTY agent (pageant) is executed, loading at the same time one key.
For this, a shortcut pageant is added to C:\Users\USER1\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup, pointing at %myputty%\pageant.exe "%mykeys%\key1.ppk".
This makes the key usable by PuTTY and WinSCP, e.g.
But if I now enter a PS session, or an msys2/cygwin terminal, the keys would not be used, and I am asked for the password for the keys.
So if I now
$ ssh myserver
Enter passphrase for key 'C:\Users\USER1/.ssh/id_rsa':
In msys2/cygwin I can use ssh-pageant ("An SSH authentication agent for Cygwin/MSYS that links OpenSSH to PuTTY's Pageant"), such that it reuses whatever keys a previously loaded PuTTY agent has.
For this purpose, I simply add eval $(/usr/bin/ssh-pageant -r -a "/tmp/.ssh-pageant-$USERNAME") to my ~/.bashrc of msys2.
Now whenever I start an msys2 terminal, the link PuTTY's Pageant -> ssh-pageant is established, a couple of environment variables are created, and I can ssh without entering the password
$ env | grep -i ssh
SSH_AUTH_SOCK=/tmp/.ssh-pageant-USER1
SSH_PAGEANT_PID=960
$ ssh myserver
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-40-generic x86_64)
...
Judging from this, it seems the same can be achieved for Git bash.
Related:
http://rabexc.org/posts/pitfalls-of-ssh-agents
How to check if ssh-agent is already running in bash?
https://superuser.com/questions/1327633/how-to-maintain-ssh-agent-login-session-with-windows-10s-new-openssh-and-powers
https://superuser.com/questions/1293725/gpg-agent-under-windows-as-ssh-agent-for-git-bash
I made this work, using the same Cygwin tools (i.e., both ssh-pageant and Cygwin OpenSSH client) in a PS session.
So I would do (assuming ssh-pageant is already running from Msys2):
> cd <dir where ssh-pageant is>
> .\ssh-pageant -r -a "$env:USERPROFILE\tmp\.ssh-pageant-$env:USERNAME"
SSH_AUTH_SOCK='C:\Users\USER1\tmp\.ssh-pageant-USER1'; export SSH_AUTH_SOCK;
> $env:SSH_AUTH_SOCK='C:\Users\USER1\tmp\.ssh-pageant-USER1'
> .\ssh myserver
Logged in to myserver
I have added this to my profile.ps1 (again, it will work when ssh-pageant is already running when I start the PS session)
$env:MSYS2_DIR=<mydir>
# Assuming a proxy ssh agent is already running
$env:SSH_AUTH_SOCK="$env:MSYS2_DIR\tmp\.ssh-pageant-$env:USERNAME"
# We have to make sure we use Msys2 OpenSSH ssh client, not Windows OpenSSH ssh client
function ssh_msys2 {
& $env:MSYS2_DIR\usr\bin\ssh.exe $args
}
If an ssh-pageant is not yet active, this should work (not tested yet; the PID number may be different):
> cd <dir where ssh-pageant is>
> .\ssh-pageant -r -a "$env:USERPROFILE\tmp\.ssh-pageant-$env:USERNAME"
SSH_AUTH_SOCK='C:\Users\USER1\tmp\.ssh-pageant-USER1'; export SSH_AUTH_SOCK;
SSH_PAGEANT_PID=714; export SSH_PAGEANT_PID;
echo ssh-pageant pid 714;
> $env:SSH_AUTH_SOCK='C:\Users\USER1\tmp\.ssh-pageant-USER1'
> $env:SSH_PAGEANT_PID=714
> .\ssh myserver
Logged in to myserver
Still have to test a couple of points, and automate the operation.
In particular, executing ssh-pageant, detecting the PID # if it is returned, and setting environment variable SSH_PAGEANT_PID from PS if that is the case.
This is a little bit more cumbersome than in Msys2, since ssh-pageant spits something directly executable by bash.

Allow SSH from PowerShell without Administrator privileges

I mean to get a terminal in an Ubuntu 20.04LTS server via ssh under PS 5.1 in Win 10.
I know I can work with native support for OpenSSH, and I have already done it before.
Now I want to do it without having admin rights, to minimize "tainting" my system.
For reasons described below (1), I think I cannot work with native OpenSSH.
For reasons described below (2), I think it is possible.
For instance, I can already start a session and issue remote commands ref, see below (3).
But I couldn't start a terminal.
Is there a way to accomplish what I mean?
How?
(1) Why, for my purposes, I cannot work with native OpenSSH?
For instance, the first two commands in the PS-way of enabling OpenSSH already require admin (my PS is in Spanish):
> Get-WindowsCapability -Online | ? Name -like 'OpenSSH*'
Get-WindowsCapability : La operación solicitada requiere elevación.
> Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Add-WindowsCapability : La operación solicitada requiere elevación.
(2) Why I think it might be possible to get an ssh terminal without admin rights in PS?
Because I can already perform several similarly demanding actions as a regular user without admin rights, outside PS:
1.1. I can ssh from Msys2 portable
1.2. I can connect from putty (portable)
1.3. I can transfer via WinSCP portable
Item (3) below.
(3) How to start an ssh session and issue remote commands from PS
Install Posh-SSH for the current user only.
Then
> New-SSHSession -Host xxx.xxx.0.xxx -Credential (Get-Credential)
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
Credential
Server SSH Fingerprint
Do you want to trust the fingerprint xx:xx:...
[] Y [] N [?] Ayuda (el valor predeterminado es "N"): y
SessionId Host Connected
--------- ---- ---------
0 xxx.xxx.0.xxx True
> Get-SSHSession
SessionId Host Connected
--------- ---- ---------
0 xxx.xxx.0.xxx True
> Invoke-SSHCommand -Index 0 -Command "pwd"
Host : xxx.xxx.0.xxx
Output : {/home/user1}
ExitStatus : 0
The latest versions of Windows 10 (and 11) have the ssh.exe built-in. It does not need to be installed. If you do not have it, you either do not have up-to-date version of Windows 10, or the OpenSSH component was somehow explicitly removed/forbidden.
Anyway, you can download ssh.exe manually from Win32-OpenSSH project. You do not need Administrator permissions for that. It does not need any installation.
But on the other hand, if you are not supposed to install software, why are you trying to bypass those restrictions, if you already have PuTTY? Use PuTTY, not ssh. If you need a console tool for automation, you can use PuTTY plink.exe. It's a console equivalent of PuTTY. And for automation purposes, it's identical to OpenSSH ssh (it does not have all the interactive features of ssh – for interactive purposes, use PuTTY).
Windows 10 has SSH built in since v1809. An OpenSSH-Client is already installed, you can directly use it by calling ssh. Try Get-Command ssh. It should return C:\WINDOWS\System32\OpenSSH\ssh.exe. You can connect to anything that supports SSH without administrative privileges "out of the box":
ssh -l <username> <DNS-Name/IP>
There is also an OpenSSH-Server available, but has to be enabled as a feature first. You probably need administrative privileges to enable that.
MS documentation on enabling OpenSSH-Server

How can I make a SSH tunnel command into a service on Windows 10?

I have a very simple command in powershell to start SSH tunnels:
ssh -N -L 28777:localhost:28778 myapp-db
What's the simplest way to make this a service, so I can run:
start-service db-tunnel
etc on Windows 10? I've read an old article on doing this and it involves using C#, which seems way too complex for such a simple task.
PowerShell is not necessary. Here's one way:
Install the Windows Server 2003 Resource Kit Tools package somewhere and get the files instsrv.exe and srvany.exe.
Use srvany.exe to create the service using the ssh.exe program and its parameters using the information in Microsoft help article 137890.
For example:
instsrv "SSH Server" "C:\Program Files (x86)\Resource Kit Tools\srvany.exe"
Of course, specify whatever service name you want and the path and filename of srvany.exe.
Next, use the registry editor to go to HKLM\SYSTEM\CurrentControlSet\Services\SSH Tunnel (or whatever you named the service) in the registry and create a Parameters subkey. In the Parameters subkey create an Application value (REG_SZ type):
C:\Program Files (x86)\ssh\ssh.exe
(or whatever - the path and filename to your ssh executable).
You can also create the values AppDirectory (REG_SZ) to specify the starting directory for the executable, and AppParameters (REG_SZ) to specify the parameters to the executable; e.g.:
-N -L 28777:localhost:28778 myapp-db
You can substitute the use of the NSSM tool mentioned by BenH in his comment if you prefer that tool and are allowed to use third-party software.
To make something into a service, you would need to compile your script into an executable. This can be done via PS2EXE.
What may work just as well for you is making a function in powershell, Start-DbTunnel, and making that import into your powershell session on start. You can do this by loading functions in the foloowing path:
$PSprofilePath\Microsoft.PowerShell_profile.ps1
or for the ISE
$PSprofilePath\Microsoft.PowerShellISE_profile.ps1
Inside those files, I have
$PSprofilePath = "C:\Users\cknutson\Documents\WindowsPowershell"
$items = Get-ChildItem "$PSprofilePath\functions"
#Set-Location "$PSprofilePath\functions"
$items | ForEach-Object {
. $_.FullName
}
Set-Location C:\
Any scripts containing functions, or otherwise will be run each time you open a powershell host.

FreeSSHd in jenkins and from commandline

i have installed fresshd in one of my windows server.now i am connect to the system through putty. It is working fine.
my issue us when i am running from command line
PuTTY.lnk -ssh -2 -P 22 username#XXX -pw pswd -m command.txt
commands given in the command.txt files are not executed it just open the putty console and it is closing.
when Running from Jenkins also same issue.
I am not sure if you are connecting to Windows from a Linux machine, or to Linux from a Windows machine. Or Windows to Windows?
PuTTY.lnk is not an executable. If you try to run that, it should produce an error 'PuTTY.lnk' is not recognized as an internal or external command. I am assuming you are running the command from a Windows machine, since you are referring to windows shortcut file (.lnk)
You need to use PuTTY.exe + the rest of your command line. Please note that unless it is in your $PATH settings, you would have to provide a full path to the .exe, for example C:\LocationOfPuttyInstall\putty.exe -ssh -2 -P 22 username#XXX -pw pswd -m command.txt. For the sake of preventing any other problem, you should also specify a correct full path to the command.txt file.
If you are not sure where your Putty is installed, on the Windows machine, do the following:
Right click your PuTTY shortcut (the PuTTY.lnk file)
Look under "Target"
That would list your full path to PuTTY.exe executable.
This should resolve your problem.
p.s.
Usually Putty is used to connect from a Windows machine to a Linux machine. From your question, it almost looks like you are trying to connect from a Windows machine to another Windows machine.
You should use PsExec windows tool for such purposes:
http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx