Invoke-Expression executing external program and shell script - powershell

I'm trying to get the root folder of a connected android device with powershell, when I try the standard command for this in the cmd it just works as expected and returns the path.
CMD
adb -s <DeviceId> shell echo $EXTERNAL_STORAGE
When I try to replicate this command in powershell I get nothing not even an error.
PowerShell
Invoke-Expression -Command "adb -s <DeviceId> shell echo $EXTERNAL_STORAGE" | Out-String
I've searched for some solutions and have found a way to make it work in powershell but I was wondering if their is an other way to get the same result without calling cmd.exe in powershell
Working PowerShell but seems doggy
(cmd.exe /c adb -s $Id shell echo `$EXTERNAL_STORAGE) | Out-String

Just specify the command as-is.
$Result = & adb -s $Id shell echo `$EXTERNAL_STORAGE
Write-Host $Result

Maybe:
$Result = & adb "-s $Id shell echo `$EXTERNAL_STORAGE" | Out-String

Related

Pass Arguments to Start-Process with spaces

I would like to pass the powershell arguments to an process. The arguments may contain spaces.
Powershell Code:
$proc = Start-Process -FilePath "wsl.exe" -ArgumentList $args -NoNewWindow -PassThru
$proc | Wait-Process
Run Command
powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "`"echo Hello World`""
No Output.
Running this command with static array works fine:
$proc = Start-Process -FilePath "wsl.exe" -ArgumentList #("bash", "-c", "`"echo Hello World`"") -NoNewWindow -PassThru
$proc | Wait-Process
Output
Hello World
What I needed todo to escape the arguments from the CLI args?
See https://github.com/PowerShell/PowerShell/issues/5576 why I have to escape spaces
The obvious answer is this, with $myargs being an array of strings. "echo Hello World" needs embedded double-quotes (or single-quotes) around it, which complicates things.
$myargs = "bash", "-c", "'echo Hello World'"
$proc = Start-Process -FilePath wsl.exe -ArgumentList $myargs -NoNewWindow -PassThru
$proc | Wait-Process
Hello World
I would just do:
.\sh.ps1 bash -c 'echo hello world'
# sh.ps1 contains:
# wsl $args
Or the wsl bash for windows:
bash -c 'echo hello world'
I happened to have pwsh installed within wsl. Without the single-quotes, each word would be put on a new line.
wsl pwsh -c "echo 'hello world'"
This works for me within another powershell, with yet another set of embedded quotes:
powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "`"'echo Hello World'`""
There's no good reason to use Start-Process in your case (see this GitHub docs issue for guidance on when Start-Process is and isn't appropriate).
Instead, use direct execution, which is not only synchronous and runs in the same console window (for console applications such as wsl.exe), but also allows you to directly capture or redirect output.
In doing so, you'll also be bypassing the longstanding Start-Process bug you mention (GitHub issue #5576), because PowerShell double-quotes arguments passed to external programs as needed behind the scenes (namely if they contain spaces).
$exe, $exeArgs = $args # split argument array into exe and pass-thru args
wsl.exe -e $exe $exeArgs # execute synchronously, via wsl -e
Note that you then also don't need to embed escaped " in your PowerShell CLI call:
powershell -noprofile -executionpolicy bypass -file sh.ps1 bash -c "echo Hello World"
However, if your arguments truly needed embedded ", you'd run into another longstanding PowerShell bug that affects only direct invocation of external programs, necessitating manual escaping with \ - see this answer.
If you do need to use Start-Process - e.g. if you want the process to run in a new (console) window - you'll have to provide embedded quoting around those $args elements that need it, along the following lines:
$quotedArgs = foreach ($arg in $args) {
if ($arg -notmatch '[ "]') { $arg }
else { # must double-quote
'"{0}"' -f ($arg -replace '"', '\"' -replace '\\$', '\\')
}
}
$proc = Start-Process -FilePath "wsl.exe" -ArgumentList $quotedArgs -PassThru
$proc | Wait-Process

Prepend a command in Start-Process to provide "y" input to Plink

I saw a solution to cache a server host key by adding the command just below on the top of my script before running the other Plink tasks.
& "echo y | C:\Program Files\PuTTY\plink.exe" -ssh -batch -i $PrivateKeyPath $username "exit" 2>&1
Error message:
The term 'echoy| C:\ProgramFiles\PuTTY\plink.exe' is not recognized as the name of a cmdlet,...
So the spaces prior the pipe symbol are removed and therefore the command is not recognized.
My other attempt is to use Start-Process but I do not know how I am able to prepend echo y | to the plink.exe path.
Start-Process -FilePath 'C:\Program Files\PuTTY\plink.exe' -Argumentlist "-ssh -batch -i $PrivateKeyPath $username $command 2>&1"
Is there an option to prepend something to the -FilePath?
Do not blindly answer "y" to Plink host key verification prompt. You lose a protection against man-in-the-middle attacks.
You should use the -hostkey switch with your host key fingerprint.
Similarly for pscp: Using echo y as an automated response to a pcp hostkey prompt
& "echo y | C:\Program Files\PuTTY\plink.exe" makes echo y | part of the path to the executable.
Change this:
& "echo y | C:\Program Files\PuTTY\plink.exe" -ssh -batch -i $PrivateKeyPath $username "exit" 2>&1
into this:
echo 'y' | & 'C:\Program Files\PuTTY\plink.exe' -ssh -batch -i $PrivateKeyPath $username "exit" 2>&1

invoking certreq via powershell

I am trying to build tool which would renew expired certs and I am strugling with invoking certreq command:
this one is working:
Invoke-Command -ComputerName $Srvname -ScriptBlock {Set-Location -Path 'D:\'; $Out = cmd /c 2>&1 'certreq -q -f -new D:\cert\request_new.inf D:\cert\certreq.csr'}
but that one does not
Invoke-Command -ComputerName $Srvname -ScriptBlock {Set-Location -Path 'D:\'; $Out = cmd /c 2>&1 'certreq -f -attrib "CertificateTemplate:WebServer" -submit D:\cert\certreq.csr D:\cert\request.cer'}
I think its because I need to accept the prompt from cert authority and that prompt does not show.
The script works localy when executing:
certreq -f -attrib "CertificateTemplate:WebServer" -submit D:\cert\certreq.csr D:\cert\request.cer
Do you have any ideas?
I have tried psexec but that didnt work either. :S
From the certreq.exe documentation:
-q Use silent mode; suppress all interactive prompts.

PowerShell: passing parameters

I run the script from the file in Jenkins. Command:
psexec -i -s cmd.exe /c echo . | powershell.exe -file "c:\Program Files (x86)\Applications\Jenkins\jobs\Deploy\workspace\Deploy\script.ps1"
How can I pass a value for the "build" variable?
Please, help me
Thanks
You would simply follow the path with your arguments. Such as:
psexec -i -s cmd.exe /c echo . | powershell.exe -file "c:\Program Files (x86)\Applications\Jenkins\jobs\Deploy\workspace\Deploy\script.ps1" '-build 1.0'
You can see the command line syntax for PowerShell.exe here. It shows:
PowerShell[.exe]
[-File <FilePath> [<Args>]]
If that does not work for you, you can try and dot source the script in a -command scriptblock, such as:
psexec -i -s cmd.exe /c echo . | powershell.exe -command {. "c:\Program Files (x86)\Applications\Jenkins\jobs\Deploy\workspace\Deploy\script.ps1" -build 1}
I made mistake in the script. I forgot to insert the following code:
Param(
[int32]$build=0
)
As TheMadTechnician said, the command to run the script is:
psexec -i -s cmd.exe /c echo . | powershell.exe -file "c:\Program Files (x86)\Applications\Jenkins\jobs\Deploy\workspace\Deploy\script.ps1" -build %BUILD_NUMBER%

How can I pass a variable using psexec?

I my trying to pass a variable server name to use it with psexec, so I have a variable $hostname and i'd like to do
psexec \\$hostname
When I do this I am getting an error. What is the correct way to do this?
You need to give psexec something to run, e.g. cmd or powershell.
Are you setting the $hostname variable? if not then you have to use $env:COMPUTERNAME as Powershell is different to the standard CMD.
This works for me at an elevated prompt:
$myhost = 'localhost'
.\psexec.exe \\$myhost cmd /c dir
I have run into a similar issue passing $ variables into psexec cmds. You can use this in your case:
$hostname = Read-Host 'Enter host name' | psexec \\\\\$_ cmd
or for a list (and Powershell 7 - drop the parallel switch for 5.1 or 6)
$hostname = Get-Content "...list.txt" | Foreach-Object -Parallel { psexec \\\\$_ cmd }