PowerShell Script "&" "&&" "||" Operators - powershell

I am new to PowerShell scripting. I have been given the task to understand what a PowerShell script is doing.
I am stuck at following line:
& $basePath\CPAU.exe -u $($sqlUser.UserName) -p $(ConvertTo-UnsecureString $sqlUser.Password) -ex "cmd /c (sqlcmd $($sqlArgs -join ' ') > $outputFile && echo TRUE > SUCCESS) || echo TRUE > FAILURE" -wait -nowarn -hide
It feels like the script is trying to execute some sort of sql command. However, I am not sure of starting "&" symbol.
Also, could CPAU.exe be an external in basepath? And what do -p, -u, and -ex enforce?
Next line:
if (!(Test-Path .\SUCCESS))
{
#some more code
}
In above if statement, what does .\SUCCESS mean? Doesn't Test-Path operate on some sort of path to test whether it exists or not?

& is the PowerShell call operator, which "runs a command, script, or script block". In your case it's running the external command CPAU.exe located in $basePath with the parameters -u, -p, -ex, -wait, -nowarn, and -hide. That command runs another command (the argument of the parameter -ex):
cmd /c (sqlcmd $($sqlArgs -join ' ') > $outputFile && echo TRUE > SUCCESS) || echo TRUE > FAILURE
The above uses cmd.exe (the Windows Command Prompt) to run sqlcmd $($sqlArgs -join ' '), redirect its output to the file $outputFile, and write "TRUE" to either the file SUCCESS if the command succeeded or to the file FAILURE otherwise.
|| and && are cmd operators for command chaining. || means "run the next command if the previous command failed". && means "run the next command if the previous command succeeded".

& $basePath\CPAU.exe -u $($sqlUser.UserName) -p $(ConvertTo-UnsecureString $sqlUser.Password) -ex "cmd /c (sqlcmd $($sqlArgs -join ' ') > $outputFile && echo TRUE > SUCCESS) || echo TRUE > FAILURE" -wait -nowarn -hide
This is some Powershell code, calling the executable CPAU.exe stored in $basePath passing a username and password and making it execute some CMD code:
cmd /c (sqlcmd $($sqlArgs -join ' ') > $outputFile && echo TRUE > SUCCESS) || echo TRUE > FAILURE
The cmd executes a SQL command given some predefined $sqlArgs, joined by a space. The whole command is redirected to $outputFile which is also expected to be predefined.
If the output of the command AND the ability to Echo TRUE on the CMD console is true, a file called SUCCESS is created receiving the redirected output. Else, if something fails but the echo TRUE happens, a FAILURE file is created.
The whole thing waits for everything to be complete, gives no warning and ...hides....
Whoever wrote this, needs a vacation.

Related

Piping commands in powershell to ssh not working

I'm trying to pipe commands to a host running a different OS via ssh. I need to send the commands as one string. Sending one at a time isn't an option. I can get this to work using quotes and newlines when I test on the ps cli. For example, sending 3 commands:
>Write-Output "Command1`nCommand2s`nCommand3`n" | ssh -tt user#host > out.txt
The out.txt file gets populated with my command output.
$ Command1
<output omitted>
$ Command2
<output omitted>
$ Command3
<output omitted>
When I try the same thing in ps script it doesn't work:
$cmds="`"Command1``nCommand2``nCommand3``n`""
Write-Output "commands to be sent:" $cmds
Write-Output $cmds | ssh -tt user#host > out.txt
The output I get shows that the string in $cmds is being formatted correctly as per the manual cli command:
commands to be sent:
"Command1`nCommand2`nCommand3`n"
But on my ssh host it's being interpreted as:
Error: command 'Command1`nCommand2`nCommand3`n' not recognized
Any idea why?
By escaping the $cmds string as you have you are literally sending the " and ` and n characters to the remote system. Did you try it as just:
$cmds="Command1`nCommand2`nCommand3`n"
This way the output from Write-Output "stuff" and $cmds="stuff" ; Write-Output $cmds would be the same.

How to detect an error at the beginning of a pipeline?

In my script I need to work with the exit status of the non-last command of a pipeline:
do_real_work 2>&1 | tee real_work.log
To my surprise, $? contains the exit code of the tee. Indeed, the following command:
false 2>&1 | tee /dev/null ; echo $?
outputs 0. Surprise, because the csh's (almost) equivalent
false |& tee /dev/null ; echo $status
prints 1.
How do I get the exit code of the non-last command of the most recent pipeline?
Bash has set -o pipefail which uses the first non-zero exit code (if any) as the exit code of a pipeline.
POSIX shell doesn't have such a feature AFAIK. You could work around that with a different approach:
tail -F -n0 real_work.log &
do_real_work > real_work.log 2>&1
kill $!
That is, start following the as yet non-existing file before running the command, and kill the process after running the command.

Escape folder with spacing in command to be executed by cmd in Powershell

How to escape spacing in the following power shell script? I tried `, ^ and even double quotation enclosing folder name with spacing but still hit directory not exist. The execution stopped at with "C:\Users\Super:" directory not exist
cmd /c C:\Users\Super Human\.nuget\packages\google.protobuf.tools\3.5.1\tools\windows_x64\protoc.exe -I C:\Users\Super Human\Desktop\School Service\School.Service.Student\Grpc\Protobuf\proto\exception\ -I ...
$dq=$([char]34)
$CommandLine=-join (
$dq,
'C:\Users\Super Human\.nuget\packages\google.protobuf.tools\3.5.1\tools\windows_x64\protoc.exe',
$dq,
' -I ',
$dq,
'C:\Users\Super Human\Desktop\School Service\School.Service.Student\Grpc\Protobuf\proto\exception\',
$dq,
' -I '
)
cmd.exe /c $CommandLine

How to capture error message from prompt - shell or perl

I am trying to capture the output of a command. It works fine if the command executes. However when there is an error, i am unable to capture what gets displayed in commandline
Eg.
$ out=`/opt/torque/bin/qsub submitscript`
qsub: Unauthorized Request MSG=group ACL is not satisfied: user abc#xyz.org, queue home
$ echo $out
$
I want $out to have the message
Thanks!
Errors are on stderr, so you need to redirect them into stdout so the backticks will capture it:
out=`/opt/torque/bin/qsub submitscript 2>&1`
if [ $? -gt 0 ] ; then
# By convention, this is sent to stderr, but if you need it on
# stdout, just remove the >&2 redirection
echo "Error: $out" >&2
else
echo "Success: $out"
fi
You should test the exit status of the command to figure out what the output represents (one way shown). It is similar for perl, slightly different syntax of course.
Have you tried doing it like this
$ out=`/opt/torque/bin/qsub submitscript 2>&1 > /dev/null`
$ echo $out

PSEXEC INPUT REDIRECTION

I am using Psexec to run a remote batch file. I pass input to psexec and redirect it to the remote batch file which seeks a filename as its input. However while redirecting, the file name becomes a garbage as ###&#* which means actual file name is not passed to batch file which the user gives. can anyone tell what might be the reason for this.
pause
cd c:
set /P INPUT=Type input: %=%
echo Your input was: %INPUT%
copy %INPUT% \\remotemachineip\C$ && c:\psexec \\machineip cmd /k "c:\batchfile.bat arg1 < %INPUT% & del %INPUT%" -e -c -f -i
pause
pause
cd c:
set /P INPUT=Type input: %=%
echo Your input was: %INPUT%
copy %INPUT% \\remotemachineip\C$ && c:\psexec \\machineip cmd /k c:\batchfile.bat %INPUT% & del %INPUT% -c -f -i
pause
the remote batch file which seeks input from the above batch file commands on the local machine. so %1(below command) is replaced by the %INPUT%(the second argument in the cmd.exe in the above code content) which the user enters and the sqlcmd command will be executed. so the input which the user passes in the above batch file will be successfully redirected to the below batch file(content) and the command(sqlcmd below) in it will be successfully executed.
SQLCMD -Sservername -d(databasename) -iC:LINKEDSERVER.sql -v filename="%1"
for e.g if I give %INPUT% as c:\inputfile.xls it will be redirected to SQLCMD command in place of %1, so it executes it as--
SQLCMD -Sservername -d(databasename) -iC:LINKEDSERVER.sql -v filename="c:\inputfile.xls"