Environmental variable with parentheses results in "unexpected token" error - powershell

I have a PowerShell (2.0) script that runs an executable beneath my program files directory, and I'm using an environmental variable to reference the path:
Start-Process "$($env:ProgramFiles)\ProgramFolder\Executable.exe"
This worked fine on my x86 machine, but now I'm trying to run it on an x64 machine. Since the executable is 32-bit, it resides beneath "C:\Program Files (x86)", and therefore I've adjusted my script as follows since the environmental variable I need to use is ProgramFiles(x86):
Start-Process "$($env:ProgramFiles(x86))\ProgramFolder\Executable.exe"
I'm getting this error though:
Unexpected token '(' in expression or statement.
So how do I reference that environmental variable given that it contains parentheses?

You don't need the subexpression $() in this case:
"${env:ProgramFiles(x86)}\ProgramFolder\Executable.exe"
Outputs:
C:\Program Files (x86)\ProgramFolder\Executable.exe
If you still want to use a subexpression, you can specify a variable name that contains PowerShell syntax characters like so:
"$(${env:ProgramFiles(x86)})\ProgramFolder\Executable.exe"

Related

Possible encoding issue with conda in PowerShell 7

I'm trying to set up conda for PowerShell but keep running into a strange error. I'm using miniconda3 (installed for all users) and PS version 7.3.1.
The conda executable is added to $Env:PATH and I'm able to run conda init powershell, which creates a profile.ps1 file in my PowerShell directory with the following contents:
#region conda initialize
Contents within this block are managed by 'conda init' !!
If (Test-Path "C:\ProgramData\miniconda3\Scripts\conda.exe") {
(& "C:\ProgramData\miniconda3\Scripts\conda.exe" "shell.powershell" "hook") | Out-String | ?{$_} | Invoke-Expression
}
#endregion
However, when restarting the terminal, I get this error:
$Env:CONDA_EXE: The term '$Env:CONDA_EXE' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
InvalidOperation: The expression after '&' in a pipeline element produced an object that was not valid. It must result in a command name,
a script block, or a CommandInfo object.
Invoke-Expression: Cannot bind argument to parameter 'Command' because it is null.
Notice the strange character in the beginning. I've seen a few discussions that have led me to believe that this might have something to do with the encoding of the profile.ps1 file or perhaps even the encoding of the output of conda.exe (if that makes any sense). I've tried changing the encoding of the profile file to UTF-8 (without BOM) and ANSI, as suggested in other threads (here and here), but this has not solved the problem.
Another thing that might be relevant to this is that when I run conda init powershell, the profile.ps1 file is actually created in a directory that's not the same as my "actual" user directory. This is because my Windows user name contains an accented character, so instead of C:\Users\AndrásAponyi\Documents\WindowsPowerShell\profile.ps1, the file gets written to C:\Users\Andr�sAponyi\Documents\WindowsPowerShell\profile.ps1 and I have to manually copy it to the correct location.
The same conda installation works perfectly fine with PowerShell version 5.1.
It seems that the issue is with the output of conda.exe that contains an unexpected character. This is causing the PowerShell profile to fail. There are a few things that you can try to resolve this issue:
Remove the existing profile.ps1 file
Create a new user profile without accented characters in the name or
rename the existing user profile to remove the accented characters
Re-run conda init powershell
Start a new PowerShell session and check if the issue has been
resolved
If the problem persists, you can try uninstalling and reinstalling Miniconda.

How can I solve this I suppose a MS PowerShell parsing error?

When I used the command below [1] to set my configuration variable MONGODB_URI, it gives an error [2].
I am using Windows PowerShell.
[1] >> heroku config:set MONGODB_URI='mongodb+srv://myprojectname:<mypassword>#cluster0.rkitj.mongodb.net/<myusername>?retryWrites=true&w=majority'
[2] The system cannot find the file specified.
'w' is not recognized as an internal or external command,
operable program or batch file.
Note: myprojectname, mypassword and myusername are placeholders for the actual value.
It looks like the heroku CLI entry point is a batch file, as implied by the wording of the error messages, which are cmd.exe's, not PowerShell's.
PowerShell doesn't take the special parsing needs of batch files (cmd.exe) into account when it synthesizes the actual command line to use behind the scenes, which involves re-quoting, using double quotes only, and only when PowerShell thinks quoting is needed.
In this case PowerShell does not double-quote (because the value contains no spaces), which breaks the batch-file invocation.
You have the following options:
You can use embedded quoting so as to ensure that the value part of your MONGODB_URI=... key-value pair is passed in double quotes; note the '"..."' quoting:
heroku config:set MONGODB_URI='"mongodb+srv://myprojectname:<mypassword>#cluster0.rkitj.mongodb.net/<myusername>?retryWrites=true&w=majority"'
Caveat: This shouldn't work, and currently only works because PowerShell's passing of arguments to external program is fundamentally broken as of PowerShell 7.1 - see this answer. Should this ever get fixed, the above will break.
If your command line doesn't involve any PowerShell variables and expressions, you can use --%, the stop-parsing symbol, which, however, in general, has many limitations (see this answer); essentially, everything after --% is copied verbatim to the target command line, except for expanding cmd.exe-style environment-variable references (e.g., %USERNAME%):
heroku config:set --% MONGODB_URI="mongodb+srv://myprojectname:<mypassword>#cluster0.rkitj.mongodb.net/<myusername>?retryWrites=true&w=majority"
If you're willing to install a module, you can use the ie function from the PSv3+ Native module (install with Install-Module Native from the PowerShell Gallery in PSv5+), which internally compensates for all of PowerShell's argument-passing and cmd.exe's argument-parsing quirks (it is implemented in a forward-compatible manner so that should PowerShell itself ever get fixed, the function will simply defer to PowerShell); that way, you can simply focus on meeting PowerShell's syntax requirements, and let ie handle the rest:
# 'ie' prepended to an invocation that uses only PowerShell syntax
ie heroku config:set MONGODB_URI='mongodb+srv://myprojectname:<mypassword>#cluster0.rkitj.mongodb.net/<myusername>?retryWrites=true&w=majority'

Powershell environment variable

In a Powershell script (.ps1)
Launched from the command line of a console (cmd.exe)
How can set and environment variable in the console,
so that when the Powershell script ends processing,
and exits to the console where was invoked...
the environment variable exists,
and can be read by a batch file,
or viewed with the SET command ?
do not want to set a 'Machine' or a 'User' variable...
only a console process variable...
the same variable you get if you use SET in the console
To run a PowerShell script from cmd.exe invariably requires a (powershell.exe / pwsh.exe) child process, and child processes fundamentally cannot set environment variables for their parent process[1].
Your best bet is to have your *.ps1 file output the name and value of the desired environment variable and then have the calling cmd.exe process create it, based on that output.
Security note: Blindly defining environment variables based on the name-value pairs output by another command (a *.ps1 script, in your case) should only be done if you trust that command not to output malicious definitions.
Here's a simple example (run directly from an interactive cmd.exe session):
for /f "delims== tokens=1,*" %v in ('powershell.exe -c "'FOO=bar'"') do #set "%v=%w"
The above defines environment variable %FOO% with value bar, based on the PowerShell command outputting the literal name-value pair FOO=bar.
Verify with echo %FOO%.
To extend this approach to defining multiple environment variables, make the command output each definition on its own line (which in PowerShell you can achieve by outputting an array of strings):
for /f "delims== tokens=1,*" %v in ('powershell.exe -c "'FOO=bar', 'BAZ=bam'"') do #set "%v=%w"
The above additionally defines %BAZ% with value bam.
To make this more convenient, I suggest creating a wrapper batch file (*.cmd) that performs the above:
Note that you'll have to use %%v and %%w instead of %v and %w there.
Instead of -c (for -Command) with the demo command, use -File with the path to your *.ps1 file to invoke it.
Also consider use of -NoProfile as well, to bypass loading of your PowerShell environment's $PROFILE file, which not only slows things down, but may pollute your command's output.
[1] As LotPings points out, child processes inherit copies of the parent process' environment variables. Modifications of these copies are never seen by the parent. A child process is fundamentally unable to modify its parent's environment, which is a restriction at the OS level - for good reasons: Modifying a running process' environment by an arbitrary (child) process would be a serious security concern.

Build path and call python with arguments

I have a PowerShell script that works fine:
../third_party/python3/win_x86_64/python.exe fusion.py $args
Now obviously this only works if the current working directory is correct. So I added a variable $abs_parent_path.
Simply adding that in front sadly does not work:
$abs_parent_path/../third_party/python3/win_x86_64/python.exe fusion.py $args
Seems some magic of PowerShell is then breaking down.
Now the question to me is how to build the absolute path to Python and Invocate.

Invoking a command with variable evaluation in Octopus Deploy Powershell script

I have a simple Powershell script that I execute during an Octopus Deploy installation. This line works fine:
& $exe install --autostart
I runs an application identified by $exe variable with command line arguments "install --autostart".
Now I need to expand command line arguments with a value evaluated from a variable:
& $exe install --autostart -servicename=$serviceName
"$serviceName" is the variable that gets its value during the script execution. Whatever I do it's passed to the line above by variable name, not the value, e.g. it's passed as "$serviceName". I tried single and double quotes, nothing helps. As long it's a command invocation (triggered by the "&" symbol in the beginnging of the line), the rest of the line is interpreted verbatim, no variable substitions.
I used last couple of hours trying to figure this out and this is driving me mad. Any tips are appreciated.
I just did some testing on my side and it looks like if you'd like the variable passed in to the command to be evaluated as a variable it needs whitespace on both sides. So you would want to define your variable as $serviceName = "-servicename=*name*" or if that is not possible then create a new variable just before running the command
$tmpServicename = "-servicename=$($serviceName)"
& $exe install --autostart $tmpServiceName