Powershell's command line handling is frustrating to say the least.
I am trying to generate a command like below and execute it from powershell
type ".\id_rsa.pub" | ".\plink.exe" -ssh [email protected] -pw usepass "umask 077; test -d .ssh || mkdir .ssh; cat >> .ssh/authorized_keys; exit; "
However I keep getting the pair of errors, depending on how I try to execute it (with Invoke-Expression or &).
ERROR: You must provide a value expression on the right-hand side of the '-' operator.
ERROR: The term 'type ".\id_rsa.pub" | ".\plink.exe" -ssh [email protected] -pw usepass "umask 077; test -d .ssh || mkdir .ssh; cat >> .ssh/authorized_keys; exit; "' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
I've googled extensively and looked at all the related stackoverflow questions and answers. I've tried changing the quotes around and commands but no luck so far.
This is the script. I am calling it quits for today. I have a batch file that's working, but it's parameter handling was terrible making it difficult for me to use it from external programs (like mremoteng). It depends on plink.exe and create a dummy file id_rsa.pub in the same folder
<#
.NAME
ssh-copy-id.ps1
.SYNOPSIS
Copy public key to remote hosts
.DESCRIPTION
See Synopsis
.SYNTAX
Invoke directly from the powershell command line
.EXAMPLES
.\Scriptname -i idtest.pub [email protected] password
.\Scriptname -i idtest.pub [email protected] password -Debug
.\ScriptName [email protected] password
.NOTES
AUTHOR: VijayS
DATE: 2014-01-23
COMMENT:
DEPENDENCIES:
plink.exe
type
.HELPURL
http://stackoverflow.com
.SEEALSO
.REFERNCE
http://www.christowles.com/2011/06/how-to-ssh-from-powershell-using.html
#>
Param(
[Parameter(Position=0,Mandatory=$true)]
[String]$user_at_hostname,
[Parameter(Position=1)]
[String]$Password,
[Parameter(HelpMessage="The public key file to copy")]
[ValidateScript({Test-Path $_})]
[Alias("i")]
[String]$identity="id_rsa.pub",
[switch]$ConnectOnceToAcceptHostKey=$false
)
####################################
Function Get-SSHCommands {
Param($Target,$Password, $CommandArray,
$PlinkAndPath,
$ConnectOnceToAcceptHostKey = $true)
$plinkoptions = "-ssh $Target"
if ($Password) { $plinkoptions += " -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)
$PlinkCommand = [string]::Format('"{0}" {1} "{2}"',
$PlinkAndPath, $plinkoptions , $remoteCommand)
#ready to run the following command
#Write-Debug $PlinkCommand
return $PlinkCommand
#$msg = Invoke-Expression $PlinkCommand
#$msg
}
##################
$ErrorActionPreference = "Stop" # "Continue" "SilentlyContinue" "Stop" "Inquire"
$DebugPreference = "Continue"
trap { #Stop on all errors
Write-Error "ERROR: $_"
}
$PlinkAndPath = '.\plink.exe'
#from http://serverfault.com/questions/224810/is-there-an-equivalent-to-ssh-copy-id-for-windows
$Commands = @()
$Commands += "umask 077" #change permissions to be restrictive
$Commands += "test -d .ssh || mkdir .ssh" #test and create .ssh director if it doesn't exist
$Commands += "cat >> .ssh/authorized_keys" #append the public key to file
#Write-Debug $Password
#Write-Debug $identity
Try {
$tmp = Get-ItemProperty -Path $identity
$tmp = Get-ItemProperty -Path $PlinkAndPath
$cmd = Get-SSHCommands -Target $user_at_hostname `
-Password $Password `
-PlinkAndPath $PlinkAndPath `
-CommandArray $Commands `
-ConnectOnceToAcceptHostKey $ConnectOnceToAcceptHostKey
# pipe the public key to the plink session to get it appended in the right place
$cmd = "type ""$identity"" | " + $cmd
Write-Debug $cmd
#Invoke-Expression $cmd
& $cmd
}
Catch {
Write-Error "$($_.Exception.Message)"
}