Powershell variable for cmd argument - powershell

I want to use a powershell variable for a cmd argument but I don't know how to make it.
function iptc($file)
{
$newcredit = correspondance($credit)
$cmd = '& C:\exiftool\exiftool.exe -S -t -overwrite_original -Credit=$newcredit $file.FullName'
Invoke-Expression $cmd
}
For example newcredit can be "James" but in my case when I run the command -Credit will only be "$newcredit".
Regards

Single quotes (' ') do not expand variable values in the string. You can address this by either using double quotes (" "):
$cmd = "& C:\exiftool\exiftool.exe -S -t -overwrite_original -Credit=$newcredit $file.FullName"
Or, by the method I most often use, by using string formatting:
$cmd = '& C:\exiftool\exiftool.exe -S -t -overwrite_original -Credit={0} {1}' -f $newcredit, $file.FullName
If either of the parameters has a space in it then the parameter will need to be surrounded by double quotes in the output. In that case I would definitely use string formatting:
$cmd = '& C:\exiftool\exiftool.exe -S -t -overwrite_original -Credit="{0}" "{1}"' -f $newcredit, $file.FullName

Related

How use character '$' in a Invoke-SSHCommand without error

I try to get information from a Linux server in a powershell script
I use the Windows forms and i get the informations in a RichTextBox.
There is no problem for some basic commands.
Example :
$infoversion = Invoke-SSHCommand -Index 0 -Command "uname -r"
$Result_Info.text += "Kernel Version : $($infoversion.Output) + ("`n")
But when i use a command with a pipe and the '$' character, it doesn't work.
Example :
$infouptime = Invoke-SSHCommand -Index 0 -Command "uptime -p | awk '{print $2,$3,$4,$5,$6,$7}'"
$Result_Info.text += "Server up since $($infouptime.Output)" + ("`n")
(This command work directly on the server)
I try to set \$ or 'e or '$' or "+chr(38)+" but nothing works
If someone can help me, it will be nice :)
PowerShell uses the backtick ` as the escape character in expandable strings:
$infouptime = Invoke-SSHCommand -Index 0 -Command "uptime -p | awk '{print `$2,`$3,`$4,`$5,`$6,`$7}'"
Alternatively, since you don't actually have any variables that need expanding, you could use a single-quoted string literal - the escape sequence for a literal ' is simply '':
$infouptime = Invoke-SSHCommand -Index 0 -Command 'uptime -p | awk ''{print $2,$3,$4,$5,$6,$7}'''

Powershell - passing parameters to script executed via piping [duplicate]

I am running powershell script over ssh as ssh user#host "powershell -Comand - < script.ps1. It works as expected as long as I start passing arguments.
When I put it as powershell -Command - my args it fails (as documented)
'-' was specified with the -Command parameter; no other arguments to -Command are permitted.
While the other way around powershell my args -Command - it fails with:
The term 'my' 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.
At line:1 char:3
+ my <<<< args -Command -
+ CategoryInfo : ObjectNotFound: (my:String) [], CommandNotFoundE
xception
+ FullyQualifiedErrorId : CommandNotFoundException
I intend to put in arbitrary list of parameter without any parsing.
Edit:
As I investigate further, it seems I am doing something wrong even when the command is specified explicitly:
(local bash) $ echo '\n' | ssh -i master-key Admin#10.8.55.78 '$SYSTEMROOT/System32/WindowsPowerShell/v1.0/powershell' -Command 'Write-Host \$\(\$args.Count\)' "my" "args"
0 my args
It seems that passes no arguments but they are printed on console for some reason. Avoiding the ssh does not seems to change anything:
(cygwin) $ $SYSTEMROOT/System32/WindowsPowerShell/v1.0/powershell -Command 'Write-Host $($args.Count)' "my" "args"
0 my args
You can't do that directly, but I think this can be done, if you wrap your script in scriptblock and pass arguments to it:
echo "& { $(cat script.ps1) } 'my' 'args'" | ssh user#host "powershell -Command"
Since -Command parameter can't handle multiline strings, there is a way to pass it in (though not via standard input) using Base64 encoded value of -EncodedCommand parameter, but it's ugly:
ssh user#host "powershell -encodedcommand $((echo "& {"; cat script.ps1 ; echo "} 'my' 'args'") | iconv -f ascii -t utf-16le | base64 -w0 ; echo -e "\n")
This one works as expected:
script=$(cat <<-'SCRIPT'
{
$a=$Args[0];
$b=$Args[1];
# Do not enclose $script into "" to avoid this comment spread till the EOL
Write-Host "This is 'a': $a";
Write-Host "This is 'b': $b";
} # <- call as [[[ -c "& { $script } ... " ]]] if you ommit braces '{}' here
SCRIPT
)
a="THE VALUE OF THE \"a\""
b="B B B B"
powershell -nologo -executionpolicy bypass -c "& $script '$a' '$b'"
output:
> This is 'a': THE VALUE OF THE "a"
> This is 'b': B B B B

Powershell: gpg command parameters with embedded double quotes

I'm trying to call gpg2 from a Powershell script. I need to pass parameters with embedded quotes but I get some very odd behavior when I look at the results from echoargs or the executable directly.
$Passphrase = "PassphraseWith!$#" #don't worry, real passphrase not hardcoded!
$Filename = "\\UNC\path\with\a space\mydoc.pdf.pgp"
$EncyptedFile = $Filename -replace "\\", "/"
$DecryptedFile = $EncyptedFile -replace ".pgp" , ""
$args = "--batch", "--yes", "--passphrase `"`"$PGPPassphrase`"`"", "-o `"`"$DecryptedFile`"`"", "-d `"`"$EncyptedFile`"`""
& echoargs $args
& gpg2 $args
gpg requires me to use double quotes for the passphrase because it has symbols and for the paths because of a space (confirmed this works when I run a sample single command directly from command prompt). Also, gpg wants UNC paths with forward slashes (confirmed this works too).
As you can see I am trying to wrap the passphrase and file paths with paired escaped double quotes because echoargs seems to indicate the outer quotes are being stripped off. Here is what i get from echoargs:
Arg 0 is <--batch>
Arg 1 is <--yes>
Arg 2 is <--passphrase "PassphraseWith!$#">
Arg 3 is <-o "//UNC/path/with/a space/mydoc.pdf">
Arg 4 is <-d "//UNC/path/with/a space/mydoc.pdf.pgp">
Command line:
"C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\PSCX\Apps\EchoArgs.exe" --batch --yes "--pass
phrase ""PassphraseWith!$#""" "-o ""//UNC/path/with/a space/mydoc.pdf""" "-d ""//UNC/path/with/a space/mydo
c.pdf.pgp"""
However, gpg2 gives the following result (whether run from ISE or PS directly):
gpg2.exe : gpg: invalid option "--passphrase "PassphraseWith!$#""
If I try & gpg2 "$args" to convert the array to a string then I get the following similar result:
gpg2.exe : gpg: invalid option "--batch --yes --passphrase "PassphraseWith!$#"
Any ideas on this one?
#PetSerAl's solution: You need to tokenize the flag/parameter and its value, so split out into two elements in the array:
"--passphrase", "`"$Passphrase`""
not combined as:
"--passphrase `"`"$Passphrase`"`""
Note that regular Powershell escaping quotes using backticks works fine here.
Full example below:
$Passphrase = "PassphraseWith!$#" #don't worry, real passphrase not hardcoded!
$Filename = "\\UNC\path\with\a space\mydoc.pdf.pgp"
$EncyptedFile = $Filename -replace "\\", "/"
$DecryptedFile = $EncyptedFile -replace ".pgp" , ""
$params = "--batch", "--quiet", "--yes", "--passphrase", "`"$Passphrase`"", "-o", "`"$DecryptedFile`"", "-d", "`"$EncyptedFile`""
& echoargs $params
& gpg2 $params

Word separator in powershell

I need to open a folder on a FTP server. The folder name [DAILY Files Folder] has SPACE between the words. If I try it in CMD I can use double quotes and it works. but in power shell I need the double quotes to run the actual command! does anyone know how can I add the space in my folder name without using double quotes?
$cmd = #(
"cd /DAILY Files Folder",
"put $file",
"bye"
)
[String]($cmd | & $program -pw $pass "$user#$hst" 2>&1)
Escape nested double quotes with backticks (`):
$cmd = #(
"cd `"/DAILY Files Folder`"",
"put $file",
"bye"
)
[String]($cmd | & $program -pw $pass "$user#$hst" 2>&1)
or use single quotes as the outer quotes if you don't use variables inside the string:
$cmd = #(
'cd "/DAILY Files Folder"',
"put $file",
'bye'
)
[String]($cmd | & $program -pw $pass "$user#$hst" 2>&1)
you can use the back tick character (`) to escape each space:
DAILY` Files` Folder

Piping from a variable instead of file in Powershell

Is ther any way in Powershell to pipe in from an virable instead of a file?
There are commands that I need to pipe into another command, right now that is done by first creating a file with the additional commands, and then piping that file into the original command. Code looks somehting like this now:
$val = "*some command*" + "`r`n" + "*some command*" + "`r`n" + "*some command*"
New-Item -name Commands.txt -type "file" -value $val
$command = #'
db2cmd.exe /C '*custom db2 command* < \Commands.txt > \Output.xml'
'#
Invoke-Expression -Command:$command
So instead of creating that file, can I somehow just pipe in $val insatead of Commands.txt?
Try this
$val = #("*some command*1","*some command2*","*some command3*")
$val | % { db2cmd.exe /C $_ > \Output.xml }
You should be able to pipe in from $val provided you use Write-Output or its shorthand echo, but it may also be worth trying passing the commands directly on the command line. Try this (and if it doesn't work I can delete the answer):
PS C:\> filter db2cmd() { $_ | db2cmd.exe ($args -replace '(\\*)"','$1$1\"') }
PS C:\> $val = #"
>> *custom db2 command*
>> *some command*
>> *some command*
>> *some command*
>> "#
>>
PS C:\> db2cmd /C $val > \Output.xml
What happens here is that Windows executables receive their command line from a single string. If you run them from cmd.exe you cannot pass newlines in the argument string, but Powershell doesn't have that restriction so with many programs you can actually pass multiple lines as a single argument. I don't know db2cmd.exe so it might not work here.
The strange bit of string replacement is to handle any double quotes in the arguments: Powershell doesn't quote them and the quoting rules expected by most exe files are a bit bizarre.
The only limitation here would be that $val must not exceed about 32,600 characters and cannot contain nulls. Any other restrictions (such as whether non-ascii unicode characters work) would depend on the application.
Failing that:
echo $val | db2cmd.exe /C '*custom db2 command*' > \Output.xml
may work, or you can use it in combination with the filter I defined at the top:
echo $val | db2cmd /C '*custom db2 command*' > \Output.xml