Run a powershell command from run.exe - powershell

I'm trying to run this command that works perfectly fine, but from the run.exe
(new-object System.Net.WebClient).DownloadFile("host", "filename.ext");
Tried:
powershell.exe -noexit -Command "(new-object System.Net.WebClient).DownloadFile(\"host\", \"filename.ext\");"
But I get this error:
Exception calling "DownloadFile" with "2" argument(s): "An exception occurred during a WebClient request."
At line:1 char:1
+ (new-object System.Net.WebClient).DownloadFile("host ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
host and filename.ext are just placeholders.

Consider using Invoke-WebRequest instead:
powershell.exe -c "Invoke-WebRequest -Uri http://server.domain.tld/path/to/file.ext -OutFile C:\path\to\save\download\file.ext"
If you need to use the old method, which is what you attempted above, you have escaped your quotes incorrectly. The download call should look like this:
powershell.exe -noexit -Command "(new-object System.Net.WebClient).DownloadFile(`"host`", `"filename.ext`");"
Your problem with the command above is that you are trying to escape your double-quotes with a \ instead of a `. The escape character in PowerShell is `. Of course, you could always avoid the need to escape your string by using a single quote for the DownloadFile parameter instead:
powershell.exe -noexit -Command "(new-object System.Net.WebClient).DownloadFile('host', 'filename.ext');"
Note that in PowerShell, double-quoted strings can have variables and subexpressions run directly in it, and can have escaped characters. Single-quoted strings escape all special characters and thus cannot have variables or subexpressions inserted directly into them. Both single-quoted and double-quoted strings do support Format Strings, however.

This should work:
Powershell.exe -NoExit -Command "& {$wc = New-Object System.Net.WebClient; $wc.DownloadFile(`"\\host\"`, `"targetfullpathname.ext"`)}"
A script block is needed to execute multiple commands.
Don't use backticks unless there are special miserable character(s).
Another method is already described by #Bender The Greatest.

This works for me with singlequotes that cmd doesn't interpret like doublequotes.
powershell (new-object Net.WebClient).DownloadFile('https://live.sysinternals.com/procmon.exe', 'procmon.exe')
Note that the first parameter is the full address of the file, not just the host.
powershell (new-object Net.WebClient).DownloadFile
OverloadDefinitions
-------------------
void DownloadFile(string address, string fileName)
void DownloadFile(uri address, string fileName)

Related

Powershell - How to pass arguments with apostrophes in them?

I'm using a third party tool to do some AD manipulation. I run a powershell script and pass arguments to it.
Everything works except if that argument contains an apostrophe in it like Jerry O'Connor. I've tried lots of different escape combinations without any luck.
Here is my command: script.ps1 -name "'%name%'" and name contain is Jerry O'Connor.
The error is
Result:The string is missing the terminator: '.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
I've tried:
script.ps1 -name "'%name%'"
script.ps1 -name \"%name%\"
script.ps1 -name ''name''
all with same error.
If you run this at the PS CMD level you'll see the error
powershell echo -name "'Jerry O'Connor'"
Anyone know how to pass an argument to script.ps1 -name "name" where that argument contains an apostrophe?
Cheers
You need to escape any ' chars. inside the value of %name% as '' to make them work inside a single-quoted PowerShell string, which from cmd.exe you can do with %name:'=''%:
From cmd.exe / a batch file:
powershell.exe -Command ./script.ps1 -name "'%name:'=''%'"
If %name% contains verbatim Jerry O'Connor, the above expands to the following, which should work as intended:
powershell.exe -Command ./script.ps1 -name "'Jerry O''Connor'"
However, you can simplify quoting if you use the -File CLI parameter instead of -Command:
powershell.exe -File ./script.ps1 -name "%name%"
See also:
For guidance on when to use -Command vs. -File, see this answer
For a comprehensive overview of the PowerShell CLI, see this answer
Try the escape character as shown here:
$Test = "`'test`'"
$Test

How do deal with single quotes when invoking powershell.exe from cmd.exe

Please see sample below which fails to work due to how cmd.exe interprets single quotes looks like.
powershell.exe -Command "& {param($a) ConvertFrom-JSON $a }" -a '{"name":"greg"}'
C:\>powershell.exe -Command "& {param($a) ConvertFrom-JSON $a }" -a '{"name":"greg"}'
ConvertFrom-JSON : Invalid JSON primitive: greg.
At line:1 char:14
+ & {param($a) ConvertFrom-JSON $a } -a '{name:greg}'
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [ConvertFrom-Json], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.ConvertFromJsonCommand
The Windows PowerShell CLI (powershell.exe) requires " chars. that are to be preserved as such to be escaped as \".[1]
Note: PowerShell (Core) 7+'s CLI (pwsh.exe) now also accepts "", which when calling from cmd.exe is actually preferable for robustness.[2]
There is no point in trying to split the CLI arguments into a PowerShell script block and its arguments, because the PowerShell CLI simply stitches together multiple arguments - after stripping syntactic enclosing double quotes - into a single, space-separated string and then evaluates the result as PowerShell code.
Therefore, try the following:
C:\>powershell.exe -Command "ConvertFrom-JSON '{\"name\":\"greg\"}'"
name
----
greg
[1] By contrast, PowerShell-internally it is `, the backtick, that serves as the escape character.
[2] E.g. pwsh.exe -c " Write-Output ""a & b"" " outputs a & b, as expected, whereas
pwsh.exe -c " Write-Output \"a & b\" " fails, because cmd.exe - due to not recognizing \" as an escaped " - considers the & unquoted and therefore interprets it as its statement separator.

New-Object not recognized

I want to run a script that will continue executing even when I close the terminal window.
I use the following command on PowerShell 2.0 to download files from the Internet:
$fyle = New-Object System.Net.WebClient;
$fyle.DownloadFile($url, $dest);
The following script downloads and runs a .ps1 script, and I can close the window, but not immediately since I have to wait for the file to download..
$fyle = New-Object System.Net.WebClient;
$fyle.DownloadFile($url, $dest_filename);
Start-Process cmd -ArgumentList " /c start /min powershell -Exec Bypass $dest_filename" -NoNewWindow
To try to fix that, all I did was put $fyle inside the Start-Process block:
$url = "https://google.com";
$dir = "$env:userprofile/adir";
$dest_filename = "$dir/script.ps1";
Start-Process cmd -ArgumentList " /c start powershell -Exec Bypass mkdir $dir; $fyle=New-Object System.Net.WebClient; $fyl.DownloadFile($url,$dest_filename); $dest_filename"
However, I get this error:
The term '=New-Object' 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:40
+ mkdir C:\Users\IEUser/adir; =New-Object <<<< System.Net.WebClient; .DownloadFile(https://google.com,C:\Users\IEUser/adir/script.ps1); C:\Users\IEUser/adir/script.ps1
+ CategoryInfo : ObjectNotFound: (=New-Object:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
The typo in your code aside, if you take a closer look at the statement throwing the error it becomes pretty much apparent what is happening:
+ mkdir C:\Users\IEUser/adir; =New-Object <<<< System.Net.WebClient; .DownloadFile(https://google.com,C:\Users\IEUser/adir/script.ps1); C:\Users\IEUser/adir/script.ps1
^^ ^^
The variable you intend to use is missing at the positions I indicated above. Without the variable the statements become incomplete commands, thus throwing the error you observed.
The reason for this is that you're passing the arguments for CMD in a double-quoted string. PowerShell's parser expands all variables in that string before passing it to Start-Process. Undefined variables are expanded to empty strings, leaving you with an incomplete commandline to execute. The variable expansion also leads to another issue with your code, because the variables that serve as the arguments for DownloadFile() are also expanded before the string is passed to Start-Process. However, DownloadFile() expects strings not bare words as its arguments.
You can fix this by escaping the $ in variables you define inside your argument string and adding quotes around the arguments for DownloadFile():
Start-Process cmd -ArgumentList " /c start powershell -Exec Bypass mkdir $dir; `$fyle=New-Object System.Net.WebClient; `$fyle.DownloadFile('$url','$dest_filename'); $dest_filename"
# ^ ^ ^ ^ ^ ^
Better yet, define your argument list as an array before passing it to Start-Process:
$params = '/c', 'start', 'powershell', '-Exec Bypass',
"mkdir $dir;",
'$fyle=New-Object System.Net.WebClient;',
"`$fyle.DownloadFile('$url','$dest_filename');",
"$dest_filename"
Start-Process cmd -ArgumentList $params

How to pass path with spaces to script

I am trying to use PowerShell to call an EXE that is at a location/path containing spaces. When I call the script from the command line, the EXE's full path is not being passed to the script. Any ideas as to why this is happening?
PowerShell Script Contents (Untitled1.ps1)
Here is the entire script that gets called from the command line:
param(
[string] $ParamExePath
)
function Run-CallThisExe {
param(
[string] $ThisExePath
)
Write-Host "ThisExePath: " "$ThisExePath"
start-process -FilePath $ThisExePath
}
write-host "ParamExePath: " $ParamExePath
Run-CallThisExe -ThisExePath "$ParamExePath"
Command Line String
Here is the command line string being run from the PowerShell script's parent folder:
powershell -command .\Untitled1.ps1 -NonInteractive -ParamExePath "C:\path with spaces\myapp.exe"
Output
Here is what is output after running the script
ParamExePath: C:\path
ThisExePath: C:\path
start-process : This command cannot be run due to the error: The system cannot
find the file specified.
At C:\sample\Untitled1.ps1:11 char:5
+ start-process -FilePath $ThisExePath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Start-Process], InvalidOperationException
+ FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand
Just change this:
powershell -command .\Untitled1.ps1 -NonInteractive -ParamExePath "C:\path with spaces\myapp.exe"
To This:
powershell -file .\Untitled1.ps1 -NonInteractive -ParamExePath "C:\path with spaces\myapp.exe"
The -Command Parameter used to execute commands for example {Get-Date}
The -File Parameter used to Run .ps1 Script File
-Command
Executes the specified commands (and any parameters) as though they were
typed at the Windows PowerShell command prompt, and then exits, unless
NoExit is specified. The value of Command can be "-", a string. or a
script block.
-File
Runs the specified script in the local scope ("dot-sourced"), so that the
functions and variables that the script creates are available in the
current session. Enter the script file path and any parameters.
File must be the last parameter in the command, because all characters
typed after the File parameter name are interpreted
as the script file path followed by the script parameters.
Type Powershell /? to get full details on each Parameter
A couple of other ways to call it:
powershell -command .\Untitled1.ps1 -NonInteractive "-ParamExePath 'C:\path with spaces\myapp.exe'"
powershell -command ".\Untitled1.ps1 -ParamExePath 'C:\path with spaces\myapp.exe'" -NonInteractive
Note that if you pass a folder path to Powershell that has a trailing backslash it cannot handle it. e.g. -ParamFolder "C:\project folder\app\bin debug\". The parameter string ends up with a double quote at the end. So when you try to append the name of a file to it you end up with something like C:\project folder\app\bin debug"Filename.txt. In this case you have to send in a second backslash at the end.

Invoke-Expression: Positional parameter cannot be found that accepts argument /s

I have a .ps1 script which contains a line
Invoke-Expression -Command "C:\Builds\$BuildName /s /v`"/l*v c:\build_install.txt /qn`""<br/>
This is performing Silent installation of a product.
Now, if I try to run this command from Linux box through ssh it gives the following error:
Invoke-Expression : A positional parameter cannot be found that accepts argument '/s'.
At line:1 char:1
+ Invoke-Expression C:\NWTBuilds\Setup-NimbleNWT-x64.2.0.4.117.exe /s /v`/l*v c:\n ...
+ CategoryInfo : InvalidArgument: (:) [Invoke-Expression], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.InvokeExpressionCommand
Do you have any suggestions on this? Do I need to provide any credentials?
So I have also tried the following options:
Send the command through ssh or telnet powershell.exe -Command ...
Call the powershell Script from ssh or telnet powershell.exe -File C:\Sample.ps1
However If I ran the same Sample.ps1 from windows Powershell, silent installation is done?
Your /s is being interpreted as being part of your Invoke-Expression call. Can you try Invoke-Command, i.e.:
Invoke-Command { C:\Builds\$BuildName /s /v "/l*v c:\build_install.txt /qn" }
The error message indicates that PowerShell is trying to parse /s as the name of a parameter of Invoke-Expression rather than as part of the argument supplied to -Command, which it would not do if the /s were part of the string. This implies that the string is being terminated just before that. Check the value of $BuildName, it probably contains something that terminates the string. I'm not quite sure what that might be, because a pair of double quotes within the variable value shouldn't have that effect. At least it wouldn't at a PowerShell prompt. Maybe the ssh client is interpreting what you're typing in some way that terminates the string before /s?
In any case, I'd be willing to bet money that the answer lies in the value of $BuildName, because logically the error indicates that the string argument to -Command terminates at that point.