Today working with my brother we needed to automate some administration of some Linux VMs for Students. The goal was simple enough, in a PowerShell script create the Linux VMs, Power it on and then SSH into it to configure Linux and create student account on their VM.
Its an odd project that is sort of last minute but we think we can script a solution for the college faculty. One of the assumed easy features of this plan was to SSH into the Linux VM from PowerShell. But surprisingly their didn't a appear to be any easy solutions. The two options available appeared to be:
SharpSSH - I tried to use it but could only get the following error:
Exception getting "formatValueList": "Microsoft.PowerShell.Commands.Internal.Format.FreeFormatEntry.formatValueList"
And /N Software NetCmdlets which is a paid solution i don't have access to and didn't find very good usage on. Lastly I found that it appears best to use plink.exe. Plink comes with putty and is the command line only version of putty. The result being you can pipe your command and through plink however you first have to accept to trust the host key. That a problem because despite all my attempts I couldn't find a command parameter to allow it to accept the host key. Here is the prompt.
C:\Program Files (x86)\PuTTY>plink -ssh username@host -pw password The server's host key is not cached in the registry. You ave no guarantee that the server is the computer you think it is. The server's rsa2 key fingerprint is: ssh-rsa 2048 8e:39:5f:6e:6d:80:77:50:6e:39:b0:c1:13:98:ab:c1 If you trust this host, enter "y" to add the key to PuTTY's cache and carry on connecting. If you want to carry on connecting just once, without adding the key to the cache, enter "n". If you do not trust this host, press Return to abandon the connection. Store key in cache? (y/n)
However I worked out a solution, it isn't pretty but it works well.
Using " Echo y " and piping that to the plink it will accept the host key, but keep entering y over and over. The solution is to then pass the command exit to plink which will logout the ssh session the second it gets logged in. With that the host key is cache and trusted. How simply plink again with out the "echo y"
ehco y | plink -ssh username@host -pw password exit
plink -ssh username@host -pw password ls
Below is the PowerShell script that will allow you to pass multiple SSH commands at once. Comment if you have questions or ways to improve this.
test
Function Invoke-SSHCommands { Param($Hostname,$Username,$Password, $CommandArray, $PlinkAndPath, $ConnectOnceToAcceptHostKey = $true) $Target = $Username + '@' + $Hostname $plinkoptions = "-ssh $Target -pw $Password" #Build ssh Commands $CommandArray += "exit" $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 $Command
"Was one one else surprised that Powershell didn't have a better way to do this as I was?"
ReplyDelete- What surprises me is that a 'linux guy' cant figure out a better way ;)
#####
# 1) On any of your linux nodes (could also be your windows box in a moment, but lets make it simple) , generate yourself an SSH key. Here is an example of how.
cantin@sodium:~> ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/cantin/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/cantin/.ssh/id_rsa.
Your public key has been saved in /home/cantin/.ssh/id_rsa.pub.
- The one thing they don't show is creation of the authorized_keys file which is simple at this point. You need this file to tell each linux box which key(s) you trust as authorization rather than the users password, during ssh.
- I would run these two commands (should work without modification if your output files from key creation are named similarly).
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/*
- The first command above (cat) will append (or create new) your public key (hence the .pub extension) into the file authorized_keys . If this file already has one or more keys, this command will not hurt that file, simply add to it. Duplicate entries do not hurt either.
- The second command (chmod) will set proper permissions on all files in ~/.ssh/* .
SSH requires the files in ~/.ssh/* to be set to 600 (user only, read/write with no group or other permissions). If it is not set this way, SSH will fail to read any keys/data from this directory and simply prompt you for users password instead.
When complete, your ~/.ssh/ directory will look like so:
[deployer@att-prod-deploy-401 DPS-11928]$ ls ~/.ssh -lrth
total 96K
-rw------- 1 deployer users 248 Aug 27 2010 id_rsa.pub
-rw------- 1 deployer users 887 Aug 27 2010 id_rsa
-rw------- 1 deployer users 248 Aug 27 2010 authorized_keys
#####
# 2)
- Using putty to connect from a windows box is alright, but if you truly need command line for things like piping data from one server to the next via ssh, or passwordless scp, Just install OpenSSH for windows!!
http://sshwindows.sourceforge.net/download/
#####
# 3
- Once ssh/scp (same package) is installed:
- Add the installed path\bin to your system path. (C:\Program Files\OpenSSH\bin)
- ssh will act in powershell, just as it does on your linux boxes (With a few exceptions with remote commands, due to powershell having different escape characters as compared to BASH ,but you'll figure it out)
- You can even add your ~/.ssh/ files...
From: Any of the linux VM's (id-rsa , id-rsa.pub , authorized_keys)
To: widnows box at %USERPROFILE%\.ssh\
- This will give you passwordless ssh/scp to that node or set of nodes.
#####
# 4
- Launch a new powershell (so that the new path addition is added to this shell session) and type ssh
~FIN
Summary:
1) Make an ssh key:
http://rcsg-gsir.imsb-dsgi.nrc-cnrc.gc.ca/documents/internet/node31.html
- Dont forget authorized_keys and file permissions.
- Copy tar/gz the directory ~/.ssh/ up , and untar it on the other VM's, same path.
2) Install OpenSSH for windows:
http://sshwindows.sourceforge.net/download/
- There are others, but this is the one I use. Even Cygwin's ssh should work.
3) Configure Windows box, at %USERPROFILE%\.ssh\ to contain the same files your linux ~/.ssh/ directories have.
4) Start new PowerShell, then Profit. You have achieved passwordless scp/ssh, usable in PowerShell.
?5) At this point, make an alias or some jazz that you can pipe any ssh commands output to for conversion to powershell usable data, as this solution eliminates all the user/password bullsh*t from the script , which is most of the script to begin with.
- Zhoul : The Old-n-Busted (and quite pertentious, but well meaning) Tech
If you enjoy linux, I can send you a package of "Unix commands, converted to Windows" that I've collected over the years. I have confirmed that 70% of them function in PowerShell, and the remaining 30% I simply don't use frequently.
ReplyDeleteBelow is the all-awesome list (ssh and scp absent because they are in the openssh\bin directory):
agrep.exe
ansi2knr.exe
basename.exe
bc.exe
bison.exe
bunzip2.exe
bzip2.exe
bzip2recover.exe
cat.exe
chgrp.exe
chmod.exe
chown.exe
cksum.exe
cmp.exe
comm.exe
compress.exe
cp.exe
csplit.exe
cut.exe
date.exe
dc.exe
dd.exe
df.exe
diff.exe
diff3.exe
dircolors.exe
dirname.exe
du.exe
echo.exe
egrep.exe
env.exe
expr.exe
factor.exe
fgrep.exe
flex.exe
fmt.exe
fold.exe
fsplit.exe
gawk.exe
gclip.exe
gplay.exe
grep.exe
grephelp.bat
gsar.exe
gunzip.exe
gzip.exe
head.exe
id.exe
indent.exe
install.exe
join.exe
jwhois.exe
less.exe
lesskey.exe
libeay32.dll
libfl.a
libfl.lib
libiconv2.dll
libintl3.dll
libssl32.dll
ln.exe
logname.exe
ls.exe
m4.exe
make.exe
makedepend.exe
makemsg.exe
man.exe
md5sum.exe
mkdir.exe
mkfifo.exe
mknod.exe
mv.exe
mvdir.exe
nc.exe
nl.exe
od.exe
paste.exe
patch.exe
pathchk.exe
pclip.exe
pr.exe
printenv.exe
printf.exe
pwd.exe
recode.exe
rm.exe
rman.exe
rmdir.exe
sdiff.exe
sed.exe
seq.exe
sh.exe
shar.exe
sleep.exe
split.exe
stego.exe
su.exe
sum.exe
sync.exe
tac.exe
tail.exe
tar.exe
tee.exe
test.exe
test.txt
touch.exe
tr.exe
type.exe
uname.exe
unexpand.exe
uniq.exe
unix_find.exe
unixdate.exe
unixexpand.exe
unixfind.exe
unixsort.exe
unrar.exe
unshar.exe
unzip.exe
uudecode.exe
uuencode.exe
wc.exe
wget.exe
wget.GID
wget.hlp
which.exe
whoami.exe
xargs.exe
xmllint.exe
yes.exe
zcat.exe
zip.exe
Can you send me the command please
DeleteHi,
DeleteThis list is really interesting and am curious and excited to use these commands from powershell. May I request you to kindly share these commands with me, please?
Do you have it as a package or individual files? Or do you have a link to your webpage from where we can download these?
Regards,
Sreeram
(Note: This was supposed to preceed my previous post, but did not post correctly. Attempting again.)
ReplyDelete"Was one one else surprised that Powershell didn't have a better way to do this as I was?"
- What surprises me is that a 'linux guy' cant figure out a better way ;)
#####
# 1) On any of your linux nodes (could also be your windows box in a moment, but lets make it simple) , generate yourself an SSH key. Here is an example of how.
cantin@sodium:~> ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/cantin/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/cantin/.ssh/id_rsa.
Your public key has been saved in /home/cantin/.ssh/id_rsa.pub.
- The one thing they don't show is creation of the authorized_keys file which is simple at this point. You need this file to tell each linux box which key(s) you trust as authorization rather than the users password, during ssh.
- I would run these two commands (should work without modification if your output files from key creation are named similarly).
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/*
- The first command above (cat) will append (or create new) your public key (hence the .pub extension) into the file authorized_keys . If this file already has one or more keys, this command will not hurt that file, simply add to it. Duplicate entries do not hurt either.
- The second command (chmod) will set proper permissions on all files in ~/.ssh/* .
SSH requires the files in ~/.ssh/* to be set to 600 (user only, read/write with no group or other permissions). If it is not set this way, SSH will fail to read any keys/data from this directory and simply prompt you for users password instead.
When complete, your ~/.ssh/ directory will look like so:
[deployer@att-prod-deploy-401 DPS-11928]$ ls ~/.ssh -lrth
total 96K
-rw------- 1 deployer users 248 Aug 27 2010 id_rsa.pub
-rw------- 1 deployer users 887 Aug 27 2010 id_rsa
-rw------- 1 deployer users 248 Aug 27 2010 authorized_keys
#####
# 2)
- Using putty to connect from a windows box is alright, but if you truly need command line for things like piping data from one server to the next via ssh, or passwordless scp, Just install OpenSSH for windows!!
http://sshwindows.sourceforge.net/download/
#####
# 3
- Once ssh/scp (same package) is installed:
- Add the installed path\bin to your system path. (C:\Program Files\OpenSSH\bin)
- ssh will act in powershell, just as it does on your linux boxes (With a few exceptions with remote commands, due to powershell having different escape characters as compared to BASH ,but you'll figure it out)
- You can even add your ~/.ssh/ files...
From: Any of the linux VM's (id-rsa , id-rsa.pub , authorized_keys)
To: widnows box at %USERPROFILE%\.ssh\
- This will give you passwordless ssh/scp to that node or set of nodes.
#####
# 4
- Launch a new powershell (so that the new path addition is added to this shell session) and type ssh
~FIN
(Part 2 of the above comment)
ReplyDeleteSummary:
1) Make an ssh key:
http://rcsg-gsir.imsb-dsgi.nrc-cnrc.gc.ca/documents/internet/node31.html
- Dont forget authorized_keys and file permissions.
- Copy tar/gz the directory ~/.ssh/ up , and untar it on the other VM's, same path.
2) Install OpenSSH for windows:
http://sshwindows.sourceforge.net/download/
- There are others, but this is the one I use. Even Cygwin's ssh should work.
3) Configure Windows box, at %USERPROFILE%\.ssh\ to contain the same files your linux ~/.ssh/ directories have.
4) Start new PowerShell, then Profit. You have achieved passwordless scp/ssh, usable in PowerShell.
?5) At this point, make an alias or some jazz that you can pipe any ssh commands output to for conversion to powershell usable data, as this solution eliminates all the user/password bullsh*t from the script , which is most of the script to begin with.
- Zhoul - The Old-n-Busted (and quite pertentious) Tech
You can alway install msysgit
ReplyDeleteI should note that this Powershell code needed be run from many VMs. For myself I didn't want to have additional software dependencies.
ReplyDeleteChris,
DeleteYou do have a dependency either on Putty/Plink or OpenSSH, don't you?
Unless you do run Putty/Plink from a file share ;-)
To Zhoul:
authorized_keys logon works pretty much same way for both Putty/Plink and OpenSSH.
I guess, you can pipe in and out too.
What is the OpenSSH advantage than?
Chris,
DeleteYou can bypass:
echo y | plink -ssh username@host -pw password exit
if the key exists already.
Better have it thought, because host key might have been changed for whatever reason ;-(
http://www.xinotes.org/notes/note/156/
I do have an dependency on Putty/plink. I however it should work on a remote share just fine.
DeleteAs for the Host Key the section "#plist prompts to accept client host key." will accept the host key no matter what is in case I haven't connected to that machine before if its Key has changed.
YOU ROCK!!!
ReplyDeleteecho y | plink -ssh username@host -pw password exit
That command is not elegant but its easy & IT WORKS on my datadomains.
Thank you for ending my GOD DAMNED headache!!!
thanks!
ReplyDeleteHi, Thanks for the guide. would like to know how can i execute a .sh file using the script?
ReplyDeleteHello Mr. Towles,
ReplyDeleteI just started a number of automation projects, and this script was instrumental in getting them off the ground. Thanks for sharing it, it's been very useful and much appreciated.
Brilliant! Thanks for the advice!
ReplyDeleteThis is a very nice post for all those who are working with power cli. I was wandering where to add the power shell script given at the end, to work with multiple commands at a time. Please anyone let me know where should i keep it.
ReplyDeleteThanks All
I've said Jimminy Jillekers so often- the words have lost all meaning!!!
ReplyDeleteI wrote an SSH-Sessions module for executing commands via SSH from PowerShell, based on the SSH.NET library found on CodePlex. It sports New-SshSession, Invoke-SshCommand and even an Enter-SshSession. Pretty cool stuff. Check it out at: http://www.powershelladmin.com/wiki/SSH_from_PowerShell_using_the_SSH.NET_library
ReplyDeleteHello everyone and thanks for the great script! it gets the job done! Only one question, why isn't the output written in powershell command line until the end of all operations?
ReplyDeleteI would really like to see whats happening in real time as if i was connected with putty.
Thanks!1
Have a look at HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\SshHostKeys, you can pre-populate that with the appropriate value for your Linux server. IOW, connect on one machine, make a note of the values, then you can plonk that straight into HKCU as the first step in your Powershell script, instead of the echo y | plink command. Ultimately it's no different, except that it saves you from a (probably extremely unlikely) MITM attack.
ReplyDeleteThis isn't working for me. When I run it in Powershell ISE it just seems to hang, the connection via Plink doesn't exit. Simplifing things I ran this command (with the corrent login id/password)
ReplyDeleteInvoke-Expression -Command "plink -ssh id@IHRDEV -pw password -V"
and it returns: "Using keyboard-interactive authentication." It never continues...
Yet if I run the same plink -ssh id@IHRDEV -pw password -V at a DOS prompt, it runs fine and exits.
Any ideas?
thanks,
Bruce
Awesome! Line 49 should be "CommandArray $Commands"
ReplyDeleteReally great script, thank you Chris
ReplyDeleteThanks, it helped me a lot!
ReplyDeleteThis is the closest I've found to a CSSH type bit for powershell. However this still fails. Thanks to special characters in my passwords. I can connect via plink if I have the password in double quotes (") but I haven't been able to update the plinkoptions to pass the password with quotes in tact. Ideas?
ReplyDelete