I am using plink to ssh to many servers and execute commands. But, unable to execute commands on console when password has special characters.
Usage: plink.exe -ssh -pw "password" user#myhost "command to execute"
apof~!##$%^&*()_+{}|:"sdfsdfs!df - Success when escaped " with \.
apof~!##<>$%^&*()_+{}|:"sdfsdfs!df - Success when escaped " with \.
apof~!##$%^&*()_+{}|:"<>sdfsdfs!df - Failed. Escaped " with \. Failure message: > was unexpected at this time.
apof~!##$%^&*()_+{}|:"><sdfsdfs!df - Failed. Escaped " with \. Failure message: < was unexpected at this time.
apof~!##$%^&*()_+{}|:"<sdfsdfs!df - Failed. Escaped " with \. Failure message: The system cannot find the path specified.
apof~!##$%^&*()_+{}|:">sdfsdfs!df - Failed. Escaped " with \. Failure message: The system cannot find the path specified.
Looks like when < or > appear after ", the escape does not work. Many I know how to handle this?
Realized that the issue is not with plink to escape the special characters, but with how cmd handles special characters. For this, I created a simple Java class to take the command line argument and print it:
public class MyTest {
public static void main(String args[]) {
System.out.println(args[0]);
}
}
I passed inputs with special characters to this application and here is the output:
C:\>java MyTest "apof~!##$%^&*()_+{}|:"<>?-=`[]\;',./sss"
> was unexpected at this time.
C:\>java MyTest "apof~!##$%^&*()_+{}|:\"<>?-=`[]\;',./sss"
> was unexpected at this time.
C:\>java MyTest "apof~!##$%^&*()_+{}|:\"^<^>?-=`[]\;',./sss"
apof~!##$%^&*()_+{}|:"<>?-=`[]\;',./sss
C:\>java MyTest "apof~!##$%^&*()_+{}|:\"^<^>?-=`[]\;',./s\"sasfafds"
apof~!##$%^&*()_+{}|:"<>?-=`[]\;',./s"sasfafds
C:\>java MyTest "apof~!##$%^&*()_+{}|:\"^<^>?-=`[]\;',./s\"sasf<>afds"
apof~!##$%^&*()_+{}|:"<>?-=`[]\;',./s"sasf<>afds
C:\>java MyTest "apof~!##$%^&*()_+{}|:\"^<^>?-=`[]\;',./s\"sasf<>af\"ds"
apof~!##$%^&*()_+{}|:"<>?-=`[]\;',./s"sasf<>af"ds
C:\>java MyTest "apof~!##$%^&*()_+{}|:\"^<^>?-=`[]\;',./s\"sasf<>af\"dasd<>fs"
> was unexpected at this time.
C:\>java MyTest "apof~!##$%^&*()_+{}|:\"^<^>?-=`[]\;',./s\"sasf<>af\"dasd^<^>fs"
apof~!##$%^&*()_+{}|:"<>?-=`[]\;',./s"sasf<>af"dasd<>fs
C:\>java MyTest "apof~!#<>#$%^&*()_+{}|:\"^<^>?-=`[]\;',./s\"sasf<>af\"dasd^<^>fs"
apof~!#<>#$%^&*()_+{}|:"<>?-=`[]\;',./s"sasf<>af"dasd<>fs
From this analysis, it is found that only special character to be escaped is " and any < or > symbol occurring after alternate " has also to be escaped with ^. This document pointed me to the escape part.
Below is the python function which I have written for generating the escaped parameter:
def escapepassword(initpassword):
passsplit = list(initpassword)
quotesflag=False
index = -1
for token in passsplit:
index += 1
if quotesflag and (token in ("<", ">")):
passsplit[index] = "^" + token
else:
if token == '"':
passsplit[index] = "\\\""
quotesflag = not quotesflag
return "".join(passsplit)
Still I had issues with calling the executable with escaped arguments. I was using the following way of executing the command:
subprocess.Popen('plink.exe -ssh -batch -pw' + escapepassword(password) + ' ' + username + '#' + ipaddress + ' "' + command + '"', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Or to say in Java, it would be:
Runtime.getRuntime().exec("plink.exe -ssh -batch -pw" + escapepassword(password) + " " + username + "#" + ipaddress + " \"" + command + "\"");
This has given much trouble. The way python or Java execute the process is different. The special characters gets escaped and gets passed to the process. Hence, it creates much more issues. To handle this, I changed the above code to:
commandtoexecute = ['plink.exe', '-ssh', '-batch', '-pw', password, username + '#' + ipaddress, command]
subprocess.Popen(commandtoexecute, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
In Java, could be written as:
Runtime.getRuntime().exec(new String [] {"plink.exe", "-ssh", "-batch", "-pw", password, username + "#" + ipaddress, command);
Here, command had space in between, for e.g. ls -al, but this is the way to pass arguments to start a process. When I tried passing command between ", it had given error saying command not found because " was also getting passed for execution on the remote system.
Note:
I had used the command WMIC path win32_process get name,Commandline | find "plink.exe" to see the commandline arguments. The output is html escaped, however, it has helped to find the arguments passed.
Related
I am trying to execute set of commands from jenkinsfile.
The problem is, when I try to assign the value of stdout to a variable it is not working.
I tried different combinations of double quotes and single quotes, but so far no luck.
Here I executed the script with latest version of jenkinsfile as well as old version. Putting shell commands inside """ """ is not allowing to create new variable and giving error like client_name command does not exist.
String nodeLabel = env.PrimaryNode ? env.PrimaryNode : "slave1"
echo "Running on node [${nodeLabel}]"
node("${nodeLabel}"){
sh "p4 print -q -o config.yml //c/test/gradle/hk/config.yml"
def config = readYaml file: 'devops-config.yml'
def out = sh (script:"client_name=${config.BasicVars.p4_client}; " +
'echo "client name: $client_name"' +
" cmd_output = p4 clients -e $client_name" +
' echo "out variable: $cmd_output"',returnStdout: true)
}
I want to assign the stdout from the command p4 clients -e $client_name to variable cmd_output.
But when I execute the code the error that is thrown is:
NoSuchPropertyException: client_name is not defined at line cmd_output = p4 clients -e $client_name
What am I missing here?
Your problem here is that all the $ are interpreted by jenkins when the string is in double quotes. So the first 2 times there's no problem since the first variable comes from jenkins and the second time it's a single quote string.
The the third variable is in a double quote string, therefore jenkins tries to replace the variable with its value but it can't find it since it's generated only when the shell script is executed.
The solution is to escape the $ in $client_name (or define client_name in an environment block).
I rewrote the block:
String nodeLabel = env.PrimaryNode ? env.PrimaryNode : "slave1"
echo "Running on node [${nodeLabel}]"
node("${nodeLabel}"){
sh "p4 print -q -o config.yml //c/test/gradle/hk/config.yml"
def config = readYaml file: 'devops-config.yml'
def out = sh (script: """
client_name=${config.BasicVars.p4_client}
echo "client name: \$client_name"
cmd_output = p4 clients -e \$client_name
echo "out variable: \$cmd_output"
""", returnStdout: true)
}
I am trying to execute a shell command n groovy
def shellString = "s/\[\|]\|\s\|'\|(\|)//g"
def temp2 = "echo response| sed -e ${shellString}".execute()
It throws compilation error:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 33: unexpected char: '\' # line 33, column 24.
def shellString = "s/\[\|]\|\s\|'\|(\|)//g"
^
1 error
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
at org.codehaus.groovy.control.ErrorCollector.addFatalError(ErrorCollector.java:150)
at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:120)
at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:132)
at org.codehaus.groovy.control.SourceUnit.addError(SourceUnit.java:350)
at org.codehaus.groovy.antlr.AntlrParserPlugin.transformCSTIntoAST(AntlrParserPlugin.java:139)
at org.codehaus.groovy.antlr.AntlrParserPlugin.parseCST(AntlrParserPlugin.java:110)
at org.codehaus.groovy.control.SourceUnit.parse(SourceUnit.java:234)
at org.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:168)
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:943)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:605)
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:581)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:558)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688)
at groovy.lang.GroovyShell.parse(GroovyShell.java:700)
at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.doParse(CpsGroovyShell.java:131)
at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:125)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:560)
at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:521)
at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:330)
at hudson.model.ResourceController.execute(ResourceController.java:97)
at hudson.model.Executor.run(Executor.java:429)
shellString isn't a slashed string, so not sure why a \ would create a problem. Any help is appreciated.
You need to escape slash to avoid compilation errors:
def shellString = "s/\\[\\|]\\|\\s\\|'\\|(\\|)//g"
def temp2 = "echo response| sed -e ${shellString}".execute()
println temp2.text
Output:
response| sed -e s/\[\|]\|\s\|'\|(\|)//g
This will fail on many levels. The biggest problem you will face is the fact, that execute is really just executing a process (not a shell command). So first of all you can not use | at all. Next quoting arguments will not work, because execute will just split at whitespace. So if you want to use "shellisms" use the equivalent of sh -c "..." instead and use execute on a string array. E.g.
["sh", "-c", "..."].execute()
Then you can put your ... shell code in there with all the redirections, quotings, env-vars etc. with the proper Groovy quoting applied as mentioned in the other answer.
And to circumvent all of that: why even bother with sed here? Just use replaceAll on the resulting string on the groovy side of things.
I try to use:
string result;
string path = "C:/winccoa.projects/filters/bin/tools/rxrepl.exe";
string cmd = "'opcki' | " + path + " -s 'op' -r 'tata'";
system(cmd, result);
DebugN(result);
But in LogViewer i see nothing, instead ["tatacki"]
Why? What i doing wrong?
In PowerShell that works fine:
PS C:\> 'opcki' | C:/winccoa.projects/filters/bin/tools/rxrepl.exe -s "op" -r "tata"
tatacki
I'm assuming that WinCC's system() function targets cmd.exe, not powershell.exe (which is typical, because historically cmd.exe has been the default shell, and APIs are unlikely to change, so as to maintain backward compatibility).
Therefore, formulate your command for cmd.exe:
string cmd = "echo opcki | " + path + " -s op -r tata";
Not the use of echo to produce output and the omission of single-quoting ('...'), which cmd.exe doesn't recognize.
If embedded quoting were needed, you'd have to use `" inside "..." PowerShell strings (or use '...' PowerShell strings (whose content is taken literally) and embed " chars. as-is).
In my Powershell script, I use "rmtshare.exe" to get information about share level permission. The "rmtshare.exe" can run perfectly under CMD environment with following command:
rmtshare.exe \\fs-sw-206\"C&C FQT"
However, when I bring it to powershell environment. I can't figure out how to escape the space and the ampersand. Here is what I have tried so far which it is not working:
$rmtShare = "C:\rmtshare.exe"
$ServerName = "fs-sw-206"
$ShareName = "C&C FQT"
Invoke-Expression ($rmtShare + " " + "\\" + $ServerName + "\" + $ShareName)
The script above will give error message from the CMD, it said "if a sharename or path contains spaces, it should be enclosed in quotes".
If I changed the last line to this:
Invoke-Expression ($rmtShare + " " + "\\" + $ServerName + "\" + "'"+'"'+"'" + $ShareName +"'"+'"'+"'")
The error message was from Powershell itself, it said "The ampersand (&) character is not allowed". NOTE: if there is no ampersand, it works. So, now I am stuck because I need to escape both characters at the same time.
Please offer your solution.
You may need to download the rmtshare.exe to test out yourself. Download site: (https://www.symantec.com/connect/downloads/remove-folder-share-remote-computer)
so, here is the code in Powershell that overcame the problem - escape space and ampersand in same time in powershell script that execute CMD
$s = " "
$q = '"'
$Verbatim = '--%'
$rmtShare = "C:\rmtshare.exe"
$ServerName = "fs-sw-206"
$ShareName = "C&C FQT"
Invoke-Expression ($rmtShare +$s+$Verbatim+$s+"\\"+$ServerName+"\"+$q+$ShareName+$q)
There should be other solutions as well. Please post if you know it.
my build script has the following task
task editProjectArtificat (type:Exec) {
executable "sed"
args "-e '/myInsertionMatchingPattern/r " + projectDir.toString() + "/scripts/install/myTextFileToInsert' < " + projectDir.toString() + "/build/scripts/MyOriginalInputFile > " + projectDir.toString() + "/build/scripts/MyChangedOutputFile"
}
gradle build fails when the above task executes with this error message
sed: 1: " '/myInsertionPattern/r ...": invalid command code
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':MyProject:editProjectArtificat'.
Process 'command 'sed'' finished with non-zero exit value 1
However, when I change the gradle.build script to make the task look like this
task editProjectArtificat (type:Exec) {
executable "sed"
args "-e /myInsertionMatchingPattern/r " + projectDir.toString() + "/scripts/install/myTextFileToInsert < " + projectDir.toString() + "/build/scripts/MyOriginalInputFile > " + projectDir.toString() + "/build/scripts/MyChangedOutputFile"
}
Now that both of the "'" removed in the "arg" line, we no longer get gradle build errors; however, sed does not produce "MyChangedOutputFile" file as expected when gradle build is done.
Typing sed command with both "'" on a shell produces the expected output? sed fails when the "'" are removed on the shell. my understanding sed needs "'" around the matching pattern and commands.
I don't know gradle, but it seems like args needs a list with each argument separated. However, you are using redirection (< and >) and that has to be done by the shell, so you shouldn't be executing sed but bash. You want to have something like bash -c "sed -e '/.../r ...' <... >..." so something like this might work:
task editProjectArtificat (type:Exec) {
executable "bash"
args "-c", "sed -e '/myInsertionMatchingPattern/r " + projectDir.toString() + "/scripts/install/myTextFileToInsert' < " + projectDir.toString() + "/build/scripts/MyOriginalInputFile > " + projectDir.toString() + "/build/scripts/MyChangedOutputFile"
}