Multiple Powershell command needs to be run from command line - powershell

i need to run single line powershell script like this one:
$a = Get-Content test.tmp; $b = [timespan]::fromseconds($a); "{0:HH:mm:ss,fff}" -f ([datetime]$b.Ticks)
in command line. When running it directly from powerhsell cli it work fine. but when trying run:
powershell "$a = Get-Content test.tmp; $b = [timespan]::fromseconds($a); "{0:HH:mm:ss,fff}" -f ([datetime]$b.Ticks)"
from command line cli i get error. I cannot run it from script in form of .ps1 file as i am not allowed to change restriction policy regarding to run powershell script.
Anybodoy would be able to point me what i have to change to run it properly from command line?
Many thanks

With proper quoting / parentheses you need no intermediate variables and only one command:
'{0:HH:mm:ss,fff}' -f ([datetime]([timespan]::fromseconds((Get-Content test.tmp))).Ticks)
In a batch:
powershell -C "'{0:HH:mm:ss,fff}' -f ([datetime]([timespan]::fromseconds((Get-Content test.tmp))).Ticks)"
Or to get the duration into a batch variable:
:: Q:\Test\2017\09\23\SO_46379453.cmd
#Echo off
For /f "tokens=1*" %%A in (
'powershell -C "\"{0:HH:mm:ss,fff}\" -f ([datetime]([timespan]::fromseconds((Get-Content test.tmp))).Ticks)" '
) Do Set "Duration=%%A,%%B"
set Duration

Related

Avoid Line break at end of cmd output?

when I use this command pwsh -c echo hello in cmd I get the following output:
C:\>pwsh -c echo hello
hello
C:\>
I do not get that line break at the end
when I run it on powershell:
PS C:\> pwsh -c echo hello
hello
PS C:\>
So I think the problem is in cmd. I know this is not such a problem and have an easy fix but I have some programs uses cmd to access powershell and removing that line break is not that fun.
So is there any fix to prevent cmd to add that line ?
Mofi has provided the crucial pointers in comments:
When executing a command interactively, cmd.exe unconditionally appends a a newline (line break) to the command's output, presumably for readability and perhaps also to ensure that the next prompt always starts on a new line.
This applies irrespective of what that command is. In other words: It doesn't matter that your command happens to be a PowerShell command.
However, that trailing newline does not become part of the command's output, therefore programmatic processing of a command's output is not affected, such as when you redirect > to a file or process the output lines one by one with for /f.
In other words: for programmatic processing you need not remove the trailing newline, because it isn't part of the actual command output.
Conversely, if you really need to in effect suppress the trailing newline for display, you'll have to modify the command's output - if that is even an option - so that the output itself doesn't end in a newline, as shown in this SuperUser answer for cmd.exe's own echo command; for PowerShell, you could do pwsh -c Write-Host -NoNewLine hello.
Edge case:
When capturing output from a batch file that is running without #echo off (or with echo on) - in which case the trailing newlines do become part of the output - you can filter out empty lines by piping to findstr /r /v /c:"^$" (as also shown in the linked answer); e.g.
foo.cmd | findstr /r /v /c:"^$"
However, note that all empty lines are filtered out this way - potentially including actual empty lines in the output from commands executed by the batch file.
If preventing that is required, a more sophisticated approach is required, which, however (a) relies on the standard prompt string (e.g., C:\>) being used and (b) can still yield false positives:
foo.cmd | powershell -nop -c "#($Input) -join \"`n\" -replace '\n(?=[a-z]:\\.*?>)'"
Finally note that if you execute the above commands without capturing or redirecting their output, their overall output in the cmd.exe console will again have a trailing newline.

Running executable with command line parameters in PowerShell

This has to be possible. I am able to open a command prompt in windows and do the following:
<some exe> <some exe command line parameters>
There must be an equivalent way to do this in PowerShell or even a standard windows batch file. For example, from the windows command prompt I can start a docker container with:
docker run –-net=kafka -d –-name=zookeeper -e ZOOKEEPER_CLIENT_PORT=2181 confluentinc/cp-zookeeper:4.1.0
however if I try something like this with PowerShell
& "docker" run –-net=kafka -d –-name=zookeeper -e ZOOKEEPER_CLIENT_PORT=2181 confluentinc/cp-zookeeper:4.1.0
it fails with an generic error:
invalid reference format.
Perhaps PowerShell is not suited for this type of advanced use case. Any suggestions would be appreciated!
Is there a better scripting language for advanced usages like this?
I think Start-Process cmdlet will be useful. ArgumentList can be single or double quoted.
Start-Process docker -ArgumentList "run –-net=kafka -d –-name=zookeeper -e ZOOKEEPER_CLIENT_PORT=2181 confluentinc/cp-zookeeper:4.1.0"
By and large, external programs in PowerShell are called the same way as from cmd.exe - there are differences, due to PowerShell having additional metacharacters such as $ and #, but they do not come into play in your specific case.
(Your & "docker" ... variant would work in principle too, but the use of & is only necessary if you must use a quoted or variable-based command name or path).
The problem is that your original command line contains two instances of – (EN DASH, U+2013) instead of the expected ASCII-range - dash (hyphen), which docker doesn't recognize.
A quick way to discover the problem:
# Print the code points of characters outside the ASCII range.
PS> [int[]] [char[]] '& "docker" run –-net=kafka -d –-name=zookeeper -e ZOOKEEPER_CLIENT_PORT=2181 confluentinc/cp-zookeeper:4.1.0' -gt 127
8211
8211
Decimal 8211 is hex. 0x2013, the code point of en-dash, whereas the code point of the regular - is 45 (0x2d).
All that is needed is to replace these – instances with - (and, since docker needn't be quoted, there is no need for &):
docker run --net=kafka -d --name=zookeeper -e ZOOKEEPER_CLIENT_PORT=2181 confluentinc/cp-zookeeper:4.1.0
Your own answer shows a variable-based implementation of the command that is effectively the same as the command above - if all the arguments are known in advance, there is never a need to use variables.
If you do want to use variables, it is much simpler to use a single array variable for all the arguments and pass that:
$dockerExe = 'docker'
$dockerArgs = 'run',
'--net=kafka',
'-d',
'--name=zookeeper',
'-e',
'ZOOKEEPER_CLIENT_PORT=2181',
'confluentinc/cp-zookeeper:4.1.0'
& $dockerExe $dockerArgs
Note:
The executable name/path must always be specified separately, and if it is quoted or involves variable references (as in this case), &, the call operator must be used for invocation, for syntactic reasons.
Passing the arguments as an array this way works with external programs; for PowerShell commands, you'd create a hashtable variable that you pass with sigil # instead of $, a feature known as splatting.
There is a lot of complexities in powershell escaping. I wrote this module to assist with running of external commands:
https://github.com/choovick/ps-invoke-externalcommand
Demo:
https://terminalizer.com/view/49acb54a979
Install-Module -Name ExternalCommand -Scope CurrentUser
Invoke-ExternalCommand -Command "docker" -Arguments #("run","-d","--name=zookeeper","--net=kafka","-e","ZOOKEEPER_CLIENT_PORT=2181", "confluentinc/cp-zookeeper:4.1.0")
Here's how to do it.
$app = 'docker'
$a1 = 'run'
$a2 = '--net=kafka'
$a3 = '-d'
$a4 = '--name=zookeeper'
$a5 = '-e'
$a6 = 'ZOOKEEPER_CLIENT_PORT=2181'
$a7 = 'confluentinc/cp-zookeeper:4.1.0'
& $app $a1 $a2 $a3 $a4 $a5 $a6 $a7

Compressing to tar.xz using 7-zip through a pipe on windows

My command line is this (powershell):
$7z ="`"c:\Program Files\7-Zip\7z.exe`""
&$7z a -r -ttar -bd -so . | &$7z a -r -txz -bd $archive -si
The produced archive file indeed contains a tar file, but that tar file is corrupt.
Note, that breaking the pipe into two commands works correctly:
&$7z a -r -ttar -bd ${archive}.tmp .
&$7z a -r -txz -bd $archive ${archive}.tmp
The produced archive is perfectly valid.
So, what is wrong with my pipeline?
(I am using Powershell)
Nothing is wrong with your pipeline it is the way that the pipeline works that's causing the error.
PowerShell pipe works in an asynchronous way. Meaning that output of the first command is available to the second command immediately one object at the time even if the first one has not finished executing, See here.
Both Unix and PowerShell pipes operate in the same way. The reason why you might be seeing a difference from Unix to PowerShell is the way in which they go about it is different.
Unix passes Strings between the commands. Where as a Powershell pipe will pass full-fledged .net object between commands. This difference in the data type being past between command will be why it works on unix and not in PowerShell. If 7z.exe can not huddle these .net objects correctly the files will be come corrupt, See here.
Try adding | %{ "$_" } in between the pipes like
&$7z a -r -ttar -bd -so . | %{ "$_" } | &$7z a -r -txz -bd $archive -si
The point is that the second call to 7z expects unmodified data on STDIN, but PowerShell is converting the output from the first call to 7z to (multiple) (string) objects. % is an alias for foreach-object, so what the additional command does is to loop over each object and convert it to a plain string before passing it on to the second call to 7z.
Edit: Reading through PowerShell’s Object Pipeline Corrupts Piped Binary Data it looks to me now as if my suggestion would not work, and there's also no way to fix it. Well, other than wrapping the whole pipeline into a cmd /c "..." call to make cmd and not PowerShell handle the pipeline.
Edit2: I also was trying this solution from the PowerShell Cookbook, but it was very slow.
In the end, I created a .cmd script with the 7z pipes that I'm calling from my PowerShell script.

Calling Patch.exe from Powershell with p0 argument

I'm currently trying to patch some files via PowerShell using Patch.exe
I am able to call the exe using the '&' command, but it doesn't seem to be reading my p0 input. I'm not an expert on PowerShell and any help would be appreciated!
here is what I am calling in PS:
$output = & "$scriptPath\patch.exe" -p0 -i $scriptPath\diff.txt
My error reads:
can't find file to patch at input line 5
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
Which I can emulate by leaving out the p0 parameter on my patch file from commandline.
Here are some alternatives I've already tried:
#$output = & "$scriptPath\patch.exe" -p0 -i "$scriptPath\diff.txt"
#CMD /c “$scriptPath\patchFile.bat” (where patchFile.bat has %~dp0patch.exe -p0 < %~dp0diff.txt, seems like powershell reads < as 0<, so there is an error there I think)
#GET-CONTENT $scriptPath\diff.txt | &"$scriptPath\patch.exe" "-p0"
#GET-CONTENT $scriptPath\diff.txt | CMD /c “$scriptPath\patch.exe -p0”
Thanks!
Try:
$output = & "$scriptPath\patch.exe" -p0 -i "$scriptPath\diff.txt"
Patch.exe started in the wrong context and I solved this by using Push-Location / Pop-Location
Here is what my code looks like now
Push-Location $scriptPath
$output = & "$scriptPath\patch.exe" -p0 -i "$scriptPath\diff.txt"
Pop-Location
Keith also mentioned in one of his comments that you can use:
[Environment]::CurrentDirectory = $pwd
I have not tested this, but I assume it does the same thing (Keith is a powershell MVP, I am just a student).

Execute command with arguments and a pipe

I'm trying to execute the command below in a PowerShell script
C:\PATH TO GPG\gpg.exe --output OUTPUTFILE.csv --batch --passphrase-fd 0 --decrypt C:\PATH TO INPUT\INPUTFILE.txt < C:\PATH TO PASS\Passphrase.txt
When I assign various sections of the command to variables and then combine them in a command varible and try and execute it as follows:
$decryptCommand = "${gpg} --output ${dateStamp}.csv --batch --passphrase-fd 0 --decrypt ${fileName} < ${passphraseFile}"
&$decryptCommand
I receive the following error:
The term 'XXXX' 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 have tried to surround various parts of the command in single and double quotes but nothing I've tried seems to work.
Is there something extra I should be doing to execute this command from a PowerShell script?
There are several problems with you script. First, you don't need to surround variable with {}, secon - you have to pass parameters seperately, like this:
&$gpg --output $dateStamp.csv --batch --passphrase-fd 0 --decrypt $fileName < $passphraseFile
The only thing I'm not sure about is < symbol. It might be the case that you will need to escape it with '