PowerShell arguments beginning with / are replaced with "True" - powershell

As the title says, any argument passed to a PowerShell script that starts with a '/' is replaced with True.
For a script
param (
[string]$wd = ""
)
echo $wd
And run with .\script.ps1 -wd "/etc/xyz", the output is True instead of the expected /etc/xyz. I was unable to find this behavior documented elsewhere, except for a similar issue in vbscript.
How can I get the string as-is?

Related

how to pass parameter to a powershell script when running from a shell script through cygwin?

i have sh script let say a.sh in which i am doing a ssh to windows server (configured with cygwin) and running a B.ps1 script which takes the parameter defined in a.sh.
Content of a.sh:
var1="abc"
var2="xyz"
#sshing to windows box
/usr/bin/scp -r -q /home/$user/Jenkins/workspace/job/jobname $user2#$x:/cygdrive/C/
/usr/bin/ssh $user2#$x 'powershell C:\\B.ps1 $var1 $var2'
this is running the script but without any parameters, when i write host variable name in B.ps1, i get blank output, which means the var1&var2 values are not getting passed to my ps1 script.
Content of B.ps1:
$var1=$args[0]
$var2=$args[1]
Write-Host "var1 is:" $var1
Write-Host "var2 is:" $var2
i have tried to use double quotation in my sh script , didn't work, it seems like there must be some way i can pass parameter but may be missing out anything on syntax.
please help.
/usr/bin/ssh $user2#$x "powershell C:/B.ps1 $var1 $var2"
You need double quoting ("...") rather than single quoting ('...') in order for the shell-variable references $var1 and $var2 to be expanded.
By using / as the path separator - which PowerShell accepts interchangeably with \ - you avoid the need to escape \ characters, which you would have had to double on transitioning from '...' to "..."; that is, the following would have worked too:
/usr/bin/ssh $user2#$x "powershell C:\\\\B.ps1 $var1 $var2"

PowerShell, Cannot read data file

I have a PowerShell script that reads a register.psd1 file with contents as below.
#{
# Building Zig compiler
zig = #{
name = "zig"
path = ./python/buildzig.py
language = "Python"
os = "all"
}
# Building Windows Terminal for Windows 10.
windowsterminal = #{
name = "WindowsTerminal"
path = ./powershell/msterminal.ps1
language = "Python"
os = "windows"
}
}
I read the file using the following command.
Import-PowerShellDataFile -Path register.psd1
After running the script I get the following error message.
Import-PowerShellDataFile : Cannot generate a PowerShell object for a ScriptBlock evaluating dynamic expressions.
What am I doing wrong and what is the possible solution?
*.psd1 files contain PowerShell hashtable literals and therefore require the same syntax as when defining such literals in code:
Therefore, if you want to create an entry with key path that contains the string literal ./python/buildzig.py (or ./powershell/msterminal.ps1), you must quote it - either form is OK here:
path = '.\powershell\msterminal.ps1'
path = ".\powershell\msterminal.ps1"
However, given that in the context of a *.psd1 file you're virtually limited to literal values, use of '...' (single quotes) makes more sense (see about_Quoting_Rules).
As for what you tried:
A hashtable entry such as path = ./python/buildzig.py attempts to create an entry with key path and the value that is the result of executing file ./python/buildzig.py, because - in the absence of quoting - the token is interpreted as a command (see about_Parsing to learn about how PowerShell parses commands and expressions).
The - unfortunately vague - error message you saw (Cannot generate a PowerShell object for a ScriptBlock evaluating dynamic expressions.), stems from the fact that for security reasons, executing commands isn't permitted in *.psd1 files, which are (mostly[1]) limited to defining literal values.
[1] You can use the following "variables", which in effect are constants: $true, $false, $null. Additionally, depending on the purpose of the *.psd1 file, a select few additional automatic variables are permitted: $PSCulture and $PSUICulture, except in files to be read by Import-PowerShellDataFile, and, additionally, $PSScriptRoot, $PSEdition, and $EnabledExperimentalFeatures in module manifests - see about_Language_Modes.
I have just added ' ' for the path parameters as following after that the error was gone. hope this is the output you wanted.
path = '.\powershell\msterminal.ps1'

Powershell (?) transforms argument in a very weird way - removes comma from string

I have a powershell build step in TeamCity:
param ([string] $a)
Write-Host "`$a is '$a'."
and in this step I set parameter $a as -a "%TestParam%" or as "-a %TestParam%", where TestParam has two lines abra and cadabra.
When I run the build I get the following output:
[Step 1/10] PowerShell arguments: -NoProfile, NonInteractive, -ExecutionPolicy, ByPass, -File, C:\buildAgent\temp\buildTmp\powershell1746295357460795314.ps1, -a, "abra, cadabra"
[Step 1/10] $a is 'abra cadabra'.
The only question I have: What on earth happened to the comma? Why has it disappeared?
If I do not use quotes at all (-a %TestParam%), then TeamCity passes each line as a separate parameter and I see $a is 'abra'..
Mathias R. Jessen's answer explains PowerShell's parsing of ,-separated tokens as arguments [his answer has since been deleted, but I hope it will be undeleted], but that doesn't apply in the case at hand, because any arguments passed to PowerShell's CLI via -File are not subject to PowerShell's command-line parsing - instead, such arguments are treated as literals.
That is, if the command line invoked by TeamCity truly were the following:
powershell ... -File C:\...ps1 -a "abra, cadabra"
then parameter variable $a would receive value abra, cadabra, as expected.
In other words: What is actually being passed in your case must be abra cadabra, not
abra, cadabra, so you need to revise the value of %TestParam% to ensure that it actually contains the desired comma.
As for why the log of the command invoked suggests that there is a , present in what you're passing:
I can only speculate, based on your own guess:
I suspect TeamCity of being a liar, showing lines joined with comma, but passing them without it.
Perhaps TeamCity, when logging invocation of a command line, naively breaks that command line into tokens by whitespace only, without considering quoting, and then presents them as a ,-separated list.
If this is indeed the case, then argument "abra cadabra" - without comma - would be logged as
"abra, cadabra", which would explain the confusion.

Passing strings with spaces to PowerShell

Ultimately, I want to be able to call my PS script from VBA (Excel), but the easiest way to do that seems to be with system batch commands - so I'm testing my script with a BAT file.
The script returns a text file with the contents of a webpage, sans HTML tags. It works fine called alone with default parameters; it worked fine with no spaces in the output path parameter, but I've had no luck using a path that includes a space.
PS1 script, boiled down:
param ( [string]$outputPathName="" )
$outputPathName | Out-File "D:\Documents\Google Drive\out.txt"
BAT file to test it:
powershell.exe '"D:\Documents\Google Drive\GetWebPage.ps1"' -outputPathName '"D:\Documents\Google Drive\out.txt"'
I get the error message "Unexpected token '-outputPathName' in expression or statement." (I also get a similar error for the argument, but if the parameter name were recognized I might be able to get past this.)
How can I pass a named argument in from BAT script file to PS1 script file (with spaces in the path and argument)?

How to set a PowerShell switch parameter from TeamCity build configuration

I have a PowerShell script with a switch (boolean) parameter that I want to call from a TeamCity build step.
I want the value of the switch (true/false) to be set according to a TeamCity build parameter, a configuration parameter.
So, something like this:
And in the PowerShell runner build step:
But the above does not work.
I get this error
[14:27:01][Step 1/1] Cannot process argument transformation on parameter 'preRelease'. Cannot
[14:27:01][Step 1/1] convert value "System.String" to type
[14:27:01][Step 1/1] "System.Management.Automation.SwitchParameter". Boolean parameters accept only
[14:27:01][Step 1/1] Boolean values and numbers, such as $True, $False, 1 or 0.
As you can see, it seems that PowerShell insist on interpreting the parameter as a string.
I have tried many variants of writing the script argument. None of these work:
-preRelease:%IncludePreRelease%
-preRelease:([boolean]%IncludePreRelease%)
-preRelease:([System.Convert]::ToBoolean(%IncludePreRelease%))
No, this still won't work. It seems that TC will always treat the value as a string no matter what. Maybe the answer was from a version of TC that allowed this, but the latest release does not.
Without colon:
[16:18:37]Step 1/6: Migrate Up (Powershell)
[16:18:37][Step 1/6] PowerShell Executable: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
[16:18:37][Step 1/6] PowerShell arguments: [-NonInteractive, -ExecutionPolicy, ByPass, -File, C:\BuildAgent\work\f2797fec10821a01\data\Migration\MigrateUp.ps1, "data\change scripts", DB, xxxxxxx, sa, *******, -NoExec, $false]
[16:18:37][Step 1/6] C:\BuildAgent\work\f2797fec10821a01\data\Migration\MigrateUp.ps1 : A positional parameter cannot be found that accepts argument '$false'.
With colon:
[16:18:37]Step 2/6: Migrate Up (Powershell)
[16:18:37][Step 2/6] PowerShell Executable: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
[16:18:37][Step 2/6] PowerShell arguments: [-NonInteractive, -ExecutionPolicy, ByPass, -File, C:\BuildAgent\work\f2797fec10821a01\data\Migration\MigrateUp.ps1, "data\change scripts", DB, xxxxxx, sa, *******, -NoExec:$false]
[16:18:37][Step 2/6] C:\BuildAgent\work\f2797fec10821a01\data\Migration\MigrateUp.ps1 : Cannot process argument transformation on parameter 'NoExec'. Cannot convert value "System.String" to type "System.Management.Automation.SwitchParameter". Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 or 0.
Removing the [switch] also does not work as any value you give it will not be treated as a Boolean - but rather a string assigned to a Boolean - and, thus, all Boolean operations will be $true.
In other words, anything you send will look like:
0 => '0'
1 => '1'
$false => '$false'
$true => '$true'
(none of which are == $false but all of which are equivalent to $true)
I have no idea how to get TC to accept Booleans!
Best I could do was assume the argument was a string and use System.Convert.ToBoolean() internally in my script...
This is an old question, but if you are still looking for an answer, I managed to get it working.
The main trick is that you shouldn't actually use the colon between the parameter name and the value as you would with PowerShell (I know, confusing...).
It looks like TeamCity is invoking the script in a different way and passes the parameters as string.
So with your example, the following should work:
-preRelease $%IncludePreRelease%
Note that I have added a dollar sign in front of the TeamCity variable to change "true" into "$true"
Let me know if it works for you
Thanks!
According to the Microsoft .Net documentation for Convert.ToBoolean the value passed to the method must be:
For a successful conversion to occur, the value parameter must equal
either Boolean.TrueString, a constant whose value is True,
Boolean.FalseString, a constant whose value is False, or it must be
null. In comparing value with Boolean.TrueString and
Boolean.FalseString, the method ignores case as well as leading and
trailing white space.
If you change your TeamCity IncludePreRelease variable value to either "True" or "False" (without the quotes) then it should convert correctly.
Make passing the switch at all dependent on the configuration parameter:
When you create the Configuration Parameter, choose Type "Checkbox".
In "Checked value", put "-preRelease".
Leave "Unchecked value" blank.
Simply append "%IncludePreRelease%" to your script arguments. When the parameter is checked, it'll pass "-preRelease" (=true), and when it's not, it will be omitted (=false).
This worked for me using TeamCity 10.0.4.
I know this is a late answer but I just had a colleague at work stumble upon the same problem and found this question.
If we forget about TC for a minute, if you wanted to execute the same command from a cmd (not powershell console) the exact command would be:
powershell.exe -File script.ps1 -preRelease
This command sets the switch to True. What is important here is that the command is first parsed by the shell (cmd).
Because the shell is cmd, powershell code in the command line will not be executed.
For example:
powershell -File script.ps1 -preRelase:"([System.Convert]::ToBoolean(%IncludePreRelease%))"
after first pass of the cmd parsing it ends up being:
powershell -File script.ps1 -preRelase:"([System.Convert]::ToBoolean(True))"
so the preRelease flag is being set to the whole string which gives you exactly
Cannot process argument transformation on parameter 'preRelease'.
Cannot convert value "System.String" to type
"System.Management.Automation.SwitchParameter"
Based on the documentation, when using -File you either pass the switch parameters or you don't. There doesn't seem to be a way to pass the True or False value.
To make it work change from -File to -Command like so:
powershell -Command .\script.ps1 -preRelease:$%IncludePreRelease%
Now, back to TeamCity. Teamcity doesn't seem to support -Comand like above. They support it by dumping your whole script into the command line as a script block which can lead to very interesting errors.
The solution is to change the Script to Source and inside the script content add
.\script.ps1 -preRelease:$%env.IncludePreRelease%