2

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)"
}

1 Answer 1

2

--% stops PowerShell from parsing the rest. That in combination with not putting plink.exe in quotes might do the trick.

type ".\id_rsa.pub" | .\plink.exe --% -ssh [email protected] -pw usepass "umask 077; test -d .ssh || mkdir .ssh; cat >> .ssh/authorized_keys; exit; "

update

--% only works in PowerShell 3 and higher. For lower versions you might try to escape all conflicting characters with ` (back tick). See here.

Sign up to request clarification or add additional context in comments.

2 Comments

Doesn't --% work only with v3? I am trying to keep the script compatible with v2.
Yes, v3 only. For lower version you need to use `

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.