Powershell how to pass parameter with special characters - powershell

I'm trying to pass a variable to powershell script as parameter. Variable has some special characters and the call to ps1 script fails.
Here I just created a sample to show the problem.
PS C:\>$pass1 = '?q$*9-W$wcx)O.Ra)X-&6'
PS C:\>powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command 'echo '$pass1''
ERROR:
At line:1 char:26
+ echo ?q$*9s8ubhD8c-W$wcx)O.Ra9)DX-D&6
+ ~
Unexpected token ')' in expression or statement.
At line:1 char:32
+ echo ?q$*9s8ubhD8c-W$wcx)O.Ra9)DX-D&6
+ ~
Unexpected token ')' in expression or statement.
At line:1 char:37
+ echo ?q$*9s8ubhD8c-W$wcx)O.Ra9)DX-D&6
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation
marks ("&") to pass it as part of a string.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
enter image description here

Your script has a syntax error, it doesn't appear to be a problem with the actual value of the parameter/variable.
This is the line that has a syntax error:
powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command 'echo '$pass1''
This is where your problem is:
'echo '$pass1''
You're actually passing 3 things here...
'echo '
$pass1
''
The second single quote is exiting the string.
You need to alternate between single and double strings depending on how you need to use them:
$pass1 = '?q$*9-W$wcx)O.Ra)X-&6'
powershell -Command "echo '$pass1'"

Related

How to create a messagebox as an argument to powershell.exe?

How can I provide arguments to powershell.exe in order to spawn a message box? The key phrase here is arguments to powershell.exe, not from within a .ps1 script and also not from within the Powershell prompt itself. I currently have this but it is producing errors:
powershell.exe -Command "[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms"); [System.Windows.Forms.MessageBox]::Show("Test!!!")"
I have also tried without -Command and with Invoke-Expression, with and without double quotes surrounding.
Errors created:
At line:1 char:51
+ [System.Reflection.Assembly]::LoadWithPartialName(System.Windows.Form ...
+ ~
Missing ')' in method call.
At line:1 char:51
+ ... eflection.Assembly]::LoadWithPartialName(System.Windows.Forms); [Syst ...
+ ~~~~~~~~~~~~~~~~~~~~
Unexpected token 'System.Windows.Forms' in expression or statement.
At line:1 char:71
+ ... flection.Assembly]::LoadWithPartialName(System.Windows.Forms); [Syste ...
+ ~
Unexpected token ')' in expression or statement.
At line:1 char:114
+ ... stem.Windows.Forms); [System.Windows.Forms.MessageBox]::Show(Test!!!)
+ ~
Missing ')' in method call.
At line:1 char:114
+ ... stem.Windows.Forms); [System.Windows.Forms.MessageBox]::Show(Test!!!)
+ ~~~~~~~
Unexpected token 'Test!!!' in expression or statement.
At line:1 char:121
+ ... stem.Windows.Forms); [System.Windows.Forms.MessageBox]::Show(Test!!!)
+ ~
Unexpected token ')' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndParenthesisInMethodCall
This is a quotation problem. Using the same double quote " in both argument and its contents messes up the content. As a work-around, use single quotes within the Powershell command and double quotes around the whole -Command parameter. Like so,
powershell.exe -Command "[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Test!!!')"
That being said, Add-Type -AssemblyName is IMAO prettier way to load assemblies. Like so,
powershell.exe -Command "add-type -assemblyname System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('Test!!!')"

How to execute PowerShell Net MessageBox in cmd/batch

I have a batch file with lot of stuff. I there is one Alert Window with info for user.
On Windows Pro I'm using Msg command for it and it works fine.
On Windows Home there is no Msg, so I got the idea to use PowerShell instead:
[System.Windows.Forms.MessageBox]::Show("my text")
which works fine in PowerShell.
-However, when I try to use it in batch or execute it directly in Cmd, I only get the text:
C:\Windows\System32>powershell {[System.Windows.Forms.MessageBox]::Show("\""my text"\"")}
[System.Windows.Forms.MessageBox]::Show("my text")
Or I get errors:
C:\Windows\System32>powershell -command [System.Windows.Forms.MessageBox]::Show("my text")
At line:1 char:41
+ [System.Windows.Forms.MessageBox]::Show(my text)
+ ~
Missing ')' in method call.
At line:1 char:41
+ [System.Windows.Forms.MessageBox]::Show(my text)
+ ~~
Unexpected token 'my' in expression or statement.
At line:1 char:48
+ [System.Windows.Forms.MessageBox]::Show(my text)
+ ~
Unexpected token ')' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndParenthesisInMethodCall
or
C:\Windows\System32>powershell -command "& {[System.Windows.Forms.MessageBox]::Show('my text')}"
Unable to find type [System.Windows.Forms.MessageBox].
At line:1 char:4
+ & {[System.Windows.Forms.MessageBox]::Show('my text')}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Windows.Forms.MessageBox:TypeName) [],
RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
What should I do to get it to work?
(without rewriting the whole script to PowerShell, that is)
As TheMadTechnician stated, you may need to load it first.
This is effectively the same answer as theirs just over a couple of lines:
#Echo Off
PowerShell -Command^
"[Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')|Out-Null;"^
"[System.Windows.Forms.MessageBox]::Show(\"my text\")"
Pause
…and whilst double quotes around my text is not necessary, I've used them to show you the escapes.
You need to load the type before you can invoke it. You can do this:
powershell -command "[reflection.assembly]::LoadWithPartialName('System.Windows.Forms')|out-null;[windows.forms.messagebox]::Show('my message')"

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 - escaping string passed to child process

I spent some time figuring out the correct syntax for a Powershell script. However in the end it was trial and error approach and I would like to know why the syntax below doesn't work.
The script starts new Powershel in elevated mode and sets environment variable. Here's the excerpt:
$x = "NewValue"
$arguments = "-NoExit", "-command", "&{ [Environment]::SetEnvironmentVariable(`"MyVar1`", `"$x`", [EnvironmentVariableTarget]::Machine) }"
Start-Process powershell -Verb runAs -ArgumentList $arguments
If I just print out the variable $arguments, it's an array as I would expect:
-NoExit
-command
&{ [Environment]::SetEnvironmentVariable("MyVar1", "NewValue", [EnvironmentVariableTarget]::Machine) }
However, in the child Powershell the double quotes are eaten somehow and missing. Why? Is it expected behavior? It outputs:
At line:1 char:42
+ &{ [Environment]::SetEnvironmentVariable(MyVar1, NewValue, [EnvironmentVariableT ...
+ ~
Missing ')' in method call.
At line:1 char:42
+ &{ [Environment]::SetEnvironmentVariable(MyVar1, NewValue, [EnvironmentVariableT ...
+ ~~~~~~
Unexpected token 'MyVar1' in expression or statement.
At line:1 char:48
+ &{ [Environment]::SetEnvironmentVariable(MyVar1, NewValue, [EnvironmentVariableT ...
+ ~
Missing argument in parameter list.
At line:1 char:2
+ &{ [Environment]::SetEnvironmentVariable(MyVar1, NewValue, [EnvironmentVariableT ...
+ ~
Missing closing '}' in statement block.
At line:1 char:96
+ ... arget]::Machine) }
+ ~
Unexpected token ')' in expression or statement.
At line:1 char:98
+ ... get]::Machine) }
+ ~
Unexpected token '}' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndParenthesisInMethodCall
My environment:
> $PSVersionTable
Name Value
---- -----
PSVersion 4.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.42000
BuildVersion 6.3.9600.17400
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion 2.2
===============================================================
For reference, here's working version using single quotes instead of double quotes (I also removed -NoExit parameter, which was there only for debugging):
$x = "NewValue"
$arguments = "-command", "&{ [Environment]::SetEnvironmentVariable('MyVar1', `'$x`', [EnvironmentVariableTarget]::Machine) }"
Start-Process powershell -Verb runAs -ArgumentList $arguments
It is how PowerShell.exe parse its command line. It mostly follows .NET rules of command line parsing:
Space is an argument separator. PowerShell.exe will join individual arguments by single space regardless of how many spaces you use to separate arguments.
CMD> PowerShell -Command echo 'multiple spaces'
multiple spaces
If you want to include space in argument value, then you should enclose space in double quotes. Double quotes itself are not a part of resulting argument value and can be anywhere inside argument:
CMD> PowerShell -Command echo 'mult"iple spa"ces'
multiple spaces
If you want literal double quote to be part of argument value, then you have to escape it with backslash:
CMD> PowerShell -Command echo 'literal\"double\"quotes'
literal"double"quotes
If you want literal backslash to precede double quote, then you have to escape that backslash with another backslash. Other than that, backslash interpreted literally and does not need to be escaped:
CMD> PowerShell -Command echo 'back\\slash\\" something\\else\\"'
back\\slash\ something\\else\

Passing empty strings using double quotes via PowerShell.exe -command

Seems like a bug... Only thing I can think of is double quotes are being lost through external invocation but it works when the string has a character, so I don't think so. Zero length string fails.
My version:
>$host
Name : ConsoleHost
Version : 3.0
Empty string fails:
> powershell.exe -command '&{write-host ""}'
The string is missing the terminator: ".
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
Works if the string has a character:
> powershell.exe -command '&{write-host "a"}'
a
Works by itself:
> &{write-host ""}
<blank line>
Works with reversed quotes:
>powershell.exe -command "&{write-host ''}"
<blank line>
And as #Ansgar pointed out escaping works (\ isn't documented in powershell.exe /?)
> powershell.exe -command '&{write-host \"\"}'
<blank line>
It appears to be using the at-string parser. The command ends up being:
#"'&{write-host ""}'"
which reduces to
'&{write-host "}'
The alternatives are:
# Like you said, escape the string
powershell.exe -command '&{write-host \"\"}'
# Use a script block instead of a string
powershell.exe -command {write-host ""}
You might also look into using a Base64 encoded command, but I've never gotten that to work.