Passing new line from command line to PowerShell - powershell

How to pass a new line character from the command line to PowerShell?
// MyScript.ps1:
[CmdletBinding()]
Param(
[Parameter()] $Param
)
Write-Host $Param
// Command line (not PowerShell - cmd.exe!)
powershell.exe -File MyScript.ps1 -Param "First`nSecond"
Does not work. Also using the command line's new line character \n does not work. So how to pass a new line tothe command line?

A workaround would be to use any other character, e.g. \n in the command line, and replace it within PowerShell:
$x = $param.Replace("\n", "`n")
This works, however, it is of course a hack and not my preferred solution.

There is a special character as in First Line◙Second Line.

When calling from CMD with a variable, I had to pass the parameter as a literal (using ' instead of ").
Sample pstest.ps1:
Write-Host "Without Replace:"
Write-Host $args[0]
Write-Host #Blank Space for Readability
Write-Host "With Replace:"
Write-Host $args[0].Replace("\n", "`n")
Call from CMD and results:
> set "tmpvar=blar1 de \nblar2"
> powershell.exe .\pstest.ps1 '%tmpvar%'
Without Replace:
blar1 de \nblar2
With Replace:
blar1 de
blar2

You need a carriage return and line feed:
`r`n
So this should work:
powershell.exe -File MyScript.ps1 -Param "First`r`nSecond"

Related

How to add a text in a file with an argument in Powershell

I am trying to add the text passed as an argument in powershell to config file. Below is the sample of the code. What I am expecting that below command will read the config file & search for parameter1 & when it find the parameter it will add the value (passed as an argument) after "="
(gc config.params) -replace "Parameter1 =", "$&` $1" | sc inifile.params
So the output supposed to be like:
Parameter1 = hostname
when the following command will be executed:
powershell.exe Untitled1.ps1 hostname
Please suggest.
$1 is not how arguments are passed to PowerShell scripts; they get an array $args or you specify parameter names. And the array does not have the script path as the first element.
So, for your code:
(gc config.params) -replace "Parameter1 =", "$&` $($args[0])" | sc inifile.params
or
param($text)
(gc config.params) -replace "Parameter1 =", "$&` $text" | sc inifile.params

Adding variable to text string and adding new line in powershell

I have the following code
$scriptpath = "C:\Test"
$scriptname = "mount.bat"
$myimage = Read-Host 'Enter the file name of your image'
if (Test-Path $scriptpath\$scriptname) {
Remove-Item $scriptpath\$scriptname
}
Add-Content $scriptpath\$scriptname ':Loop 'n "C:\Program
Files\file.exe" -f \\host\"Shared Folders"\$myimage -m V: `n if not
%errorlevel% equal 0 goto :Loop'
I can't get powershell to output the variable correctly in the output batch file it just says "$myimage" and not the file name. I have tried using the break ` ' symbols but no luck. I also cannot get powershell to export onto a separate line. If anyone could help that would be great.
Since you're using (a) variable references ($myimage) and (b) escape sequences such as `n (to represent a newline) in your string, you must use double quotes to get the expected result.
(Single-quoted strings treat their contents literally - no interpolation takes place.[1])
Furthermore, since your string has embedded double quotes, they must be escaped as `"
Here's a fixed version; note that I've used actual line breaks for readability (rather than `n escape sequences in a single-line string):
$myImage = 'test.png'
":Loop
`"C:\ProgramFiles\file.exe`" -f \\host\`"Shared Folders`"\$myimage -m V:
if not %errorlevel% equal 0 goto :Loop"
[1] The only interpretation that takes place is to recognize escape sequence '' as an embedded '.

How to correctly escape spaces and backslashes in command line arguments?

I had some issues passing an array of strings to a command in PowerShell, so I'm debugging my script. I'm using the EchoArgs.exe program found in the PowerShell Community Extension Project (PSCX).
If I execute this script:
Import-Module Pscx
cls
$thisOne = 'this_one\';
$secondOne = 'second one\';
$lastOne = 'last_one'
$args = $thisOne `
, "the $secondOne" `
, "the_$lastOne"
EchoArgs $args
I get this result:
Arg 0 is <this_one\>
Arg 1 is <the second one" the_last_one>
Command line:
"C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" this_one\ "the second one\" the_last_one
It seems that if a string contains spaces, the last backslash escapes the double quote. In fact all seems working if I escape only that backslash:
Import-Module Pscx
cls
$thisOne = 'this_one\';
$secondOne = 'second one\\';
$lastOne = 'last_one'
$args = $thisOne `
, "the $secondOne" `
, "the_$lastOne"
EchoArgs $args
with this result:
Arg 0 is <this_one\>
Arg 1 is <the second one\>
Arg 2 is <the_last_one>
Command line:
"C:\Program Files (x86)\PowerShell Community Extensions\Pscx3\Pscx\Apps\EchoArgs.exe" this_one\ "the second one\\" the_last_one
Is there a "smart" way in PowerShell (i.e. a cmdlet) to escape any string in order to avoid such issues?
Try using Start-Process instead. It has an $Arguments parameter that would suit this better.
See here: PowerShell - Start-Process and Cmdline Switches

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

Executing Powershell script from command line with quoted parameters

I am automating the build of a legacy MS Access application, and in one of the steps, I am trying to make an Access executable (.ADE). I have come up with the following code, which is stored in a file (PSLibrary.ps1):
Add-Type -AssemblyName Microsoft.Office.Interop.Access
function Access-Compile {
param (
[Parameter(Mandatory=$TRUE,Position=1)][string]$source,
[Parameter(Mandatory=$TRUE,Position=2)][string]$destination
)
Write-Output "Starting MS Access"
$access = New-Object -ComObject Access.Application
$access.Visible = $FALSE
$access.AutomationSecurity = 1
if (!(Test-Path $source)) { Throw "Source '$source' not found" }
if ((Test-Path $destination)) {
Write-Output "File '$destination' already exists - deleting..."
Remove-Item $destination
}
Write-Output "Compiling '$source' to '$destination'"
$result = $access.SysCmd(603, $source, $destination)
$result
Write-Output "Exiting MS Access"
$access.quit()
}
If I go into the PowerShell ISE and run the command below, then everything works fine, and the expected output is created:
PS C:>& "C:\Temp\PSLibrary.ps1"
PS C:>Access-Compile "C:\Working\Project.adp" "C:\Working\Project.ade"
However, I can't seem to generate the right hocus-pocus to get this running from the command line, as I would in an automated build. For instance,
powershell.exe -command "& \"C:\\Temp\\PSLibrary.ps1\" Access-Compile \"C:\\Temp\\Project.adp\" \"C:\\Temp\\Project.ade\""
What am I doing wrong?
For complex parameters, you can use Powershell's -EncodedCommand parameter. It will accept a Base64 encoded string. No escaping is needed for quotes, slashes and such.
Consider a test function that will print its parameters. Like so,
function Test-Function {
param (
[Parameter(Mandatory=$TRUE,Position=1)][string]$source,
[Parameter(Mandatory=$TRUE,Position=2)][string]$destination
)
write-host "src: $source"
write-host "dst: $destination"
}
Create command to load the script and some parameters. Like so,
# Load the script and call function with some parameters
. C:\Temp\Calling-Test.ps1; Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""
After the command syntax is OK, encode it into Base64 form. Like so,
[System.Convert]::ToBase64String([System.Text.Encoding]::UNICODE.GetBytes('. C:\Temp\Calling-Test.ps1; Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""'))
You'll get a Base64 string. Like so,
LgAgAEMAOgBcAFQAZQBtAHAAXABDAGEAbABsAGkAbgBnAC0AVABlAHMAdAAuAHAAcwAxADsAIAAgAFQAZQBzAHQALQBGAHUAbgBjAHQAaQBvAG4AIAAiAHMAbwBtAGUAXABzAHAAZQBjAGkAYQBsADoAYwBoAGEAcgBhAGMAdABlAHIAcwA/ACIAIAAiAGAAIgBjADoAXABtAHkAIABwAGEAdABoAFwAdwBpAHQAaABcAHMAcABhAGMAZQBzACAAdwBpAHQAaABpAG4ALgBlAHgAdABgACIAIgA=
Finally, start Powershell and pass the encoded string as a parameter. Like so,
# The parameter string here is abreviated for readability purposes.
# Don't do this in production
C:\>powershell -encodedcommand LgAgA...
Output
src: some\special:characters?
dst: "c:\my path\with\spaces within.ext"
Should you later want to reverse the Base64 encoding, pass it into decoding method. Like so,
$str = " LgAgA..."
[Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($str))
# Output
. C:\Temp\Calling-Test.ps1; Test-Function "some\special:characters?" "`"c:\my path\with\spaces within.ext`""
PowerShell like Bash can take single or double quotes
PS C:\Users\Steven> echo "hello"
hello
PS C:\Users\Steven> echo 'hello'
hello
this can alleviate some of the headache, also I think you can use the literal backslashes without escaping.
To run PowerShell, choose
Start Menu Programs Accessories
Windows Powershell Windows Powershell