Cannot access $Profile.CurrentUserAllHosts using pwsh.exe? - powershell

I want to read the automatic variable $profile.CurrentUserAllHosts, using a Deno script.
I already know how to execute pwsh.exe from Deno.
But would like to know how to invoke pwsh.exe to get the $profile.CurrentUserAllHosts value.
For example, I expect that two commands below yields the same results rather than different results:
PS> $profile.CurrentUserAllHosts
C:\Users\Flavio\Documents\PowerShell\profile.ps1
PS> pwsh.exe -noprofile -Command "{$profile.CurrentUserAllHosts}"
C:\Users\Flavio\Documents\PowerShell\Microsoft.PowerShell_profile.ps1.CurrentUserAllHosts
Note: I'm using Powershell 7.2.5, on Windows 10 and I can guarantee that pwsh.exe is the same version for all instances.

There's two things to keep in mind here:
You're running the command in PowerShell itself, so $profile is actually expanded in your parent-session due to the double-quotes in your -Command argument.
You're passing a string with a scriptblock as the -Command argument. It's not actually executed - you're just getting the result of {$profile.CurrentUserAllHosts}.ToString() which is the content of the scriptblock.
Suggestions:
Add a call operator to invoke the scriptblock in the string, ex -Command '& { $profile.CurrentUserAllHosts }'. If invoking pwsh from PowerShell you can also use pwsh.exe -noprofile -Command { $profile.CurrentUserAllHosts }.
Or provide the command as a simple string, ex. -Command '$profile.CurrentUserAllHosts'
In both alternatives, remember single quotes OR escaping the dollar-sign with backtick.

Related

On WSL2 how do I get a powershell command's output to print to stdout

In WSL2 I want to run a powershell command and get the output of the command to print to stdout on my WSL2.
I have tried many variants but it seems I always just get the command given back and not its output:
$ pwsh.exe -Command {Get-Date}
Get-Date
$ pwsh.exe -Command '{Write-Output "hello"}'
Write-Output "hello"
You should not use curly braces here :
pwsh.exe -Command 'Get-Date'
Philippe's helpful answer provides the crucial pointer:
When calling pwsh, the PowerShell (Core) CLI, from outside PowerShell:
Do not use { ... } to enclose your command(s) - that only works from inside PowerShell.
Inside PowerShell, { ... } creates a script block literal, which is a reusable piece of PowerShell code that can be invoked on demand.
If you pass { ... } to pwsh from inside PowerShell, special processing happens behind the scenes, which notably preserves type fidelity in the output as much as possible - see this answer for details.
It should be noted that calling the PowerShell CLI from PowerShell is rarely necessary, except, for instance, on Windows, if you want to call the respective other PowerShell edition's CLI.
Instead, pass your command(s) as-is, inside a string.
If you pass a string to -Command from outside PowerShell with { ... } embedded, what happens is that PowerShell creates a script block and - in the absence of invoking it, with & or . - its string representation is output, which is the block's verbatim content (excluding { and }) - that is what you saw.
As an aside: There are many examples out there that use "& { ... }" as a -Command argument; while that technically works, it is unnecessary, and passing just "..." (or '...', from POSIX-compatible shells) is sufficient.
Thus:
# Simple case: no quoting necessary
$ pwsh.exe -Command Get-Date
# Command string that requires quoting:
$ pwsh.exe -Command 'Write-Output "hello"'

I can't run the code when I use powershell.exe -command

Cold you help me with following problem?
How to run the
"{0:n10}" -f 21.21
code in
powershell.exe -command "& {}"
argument?
There's no reason to use "& { ... }" in order to invoke code passed to PowerShell's CLI via the -Command (-c) parameter - just use "..." directly.
Older versions of the CLI documentation erroneously suggested that & { ... } is required, but this has since been corrected.
Unescaped " characters on the command line are stripped before the resulting argument(s) following -Command (-c) are interpreted as PowerShell code. " characters that need to be preserved as part of the PowerShell command to execute therefore need escaping.
From PowerShell's perspective, using \" works, in both editions.
Additionally, to prevent inadvertent whitespace normalization (folding of multiple spaces into one), the entire command to pass to -Command (-c) should be passed inside a single, "..." string overall:
Therefore (note that this assumes calling from outside PowerShell):
powershell.exe -Command " \"{0:n10}\" -f 21.21"
However, when calling from cmd.exe, specifically, \" escaping may break cmd.exe's syntax, in which case a different form of escaping of embedded " chars. is required - the following works robustly:
"^"" (sic) with powershell.exe, the Windows PowerShell CLI:
powershell.exe -Command " "^""{0:n10}"^"" -f 21.21"
"" with pwsh.exe, the PowerShell (Core) 7+ CLI:
pwsh.exe -Command " ""{0:n10}"" -f 21.21"
See this answer for details.

How to pass array parameters to a powershell script via command line or scheduled task?

I wrote a PowerShell script which accepts a string array parameter. It is defined in the param section of the script like this:
param
(
[Parameter(Position=0)]
[string[]]$TemplateNames,
...
)
When calling the script via a PowerShell command-line, I can easily pass multiple strings to this parameter by using the following syntax:
.\Script.ps1 -TemplateNames #("Name1","Name2")
However, I need to call this script in a scheduled task and no matter what syntax I use, I can't get PowerShell to interpret the array correctly. The #(...) syntax doesn't work, passing the strings separated with a comma also doesn't work, putting the array in brackets also doesn't work and no matter how I escape the parameter or even the entire script call in single quotes, double quotes or even multiple single or double quotes, it just won't work. The same problem occurs also when calling the script manually via the Windows command line like this:
Powershell.exe -NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -File "C:\Script\Script.ps1" -TemplateNames ...
How can I pass an array to a PowerShell script in a scheduled task or when calling it via the Windows command line?
When using -command the problem of the misinterpretation can be circumvented:
powershell -command "& .\script.ps1 'Name1','Name2'"
This works because the string beetween the quotes is not (mis)interpreted.
When using double quotes you have to use three of them:
powershell -command "& .\script.ps1 """Name1""","""Name2""""
The logic of removed quotes is strange. A test with a program that simply echos the parameters shows that a variant with two quotes yields the same result as the one with three.

How can I run a PowerShell script with white spaces in the path from the command line?

So I've tried a bunch of different ways to run a PowerShell script from the command line and every single one returns an error.
Here is this path:
C:\Users\test\Documents\test\line space\PS Script\test.ps1
I've tried these:
powershell -File '"C:\Users\test\Documents\test\line space\PS Script\test.ps1"'
powershell "& ""C:\Users\test\Documents\test\line space\PS Script\test.ps1"""
Powershell "& 'C:\Users\test\Documents\test\line space\PS Script\test.ps1'"
Powershell -File 'C:\Users\test\Documents\test\line space\PS Script\test.ps1'"
I get all these errors:
& : The term 'C:\Users\test\Documents\test\line space\PS Script' 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.
Processing -File ''C:\Users\test\Documents\test\line space\PS Script'' failed: The given path's format is not support ed. Specify a valid path for the -File parameter.
How can I fix this?
The -File parameter
If you want to run powershell.exe -File from the command line, you always have to set paths with spaces in double quotes ("). Single quotes (') are only recognized by PowerShell. But as powershell.exe is invoked (and hence the file parameter processed) by the command line, you have to use ".
powershell.exe -File "C:\Users\test\Documents\Test Space\test.ps1" -ExecutionPolicy Bypass
The -Command parameter
If you use the -Command parameter, instead of -File, the -Command content is processed by PowerShell. Hence you can - and in this case have to - use ' inside ".
powershell.exe -Command "& 'C:\Users\test\Documents\Test Space\test.ps1'" -ExecutionPolicy Bypass
The double quotes are processed by the command line, and & 'C:\Users\test\Documents\Test Space\test.ps1' is a command that is actually processed by PowerShell.
Solution 1 is obviously simpler.
Note that -Command is also the default parameter that is used, if you do not specify any.
powershell.exe "& 'C:\Users\test\Documents\Test Space\test.ps1'" -ExecutionPolicy Bypass
This would work, too.
The -EncodedCommand parameter
You can encode your command as Base64. This solves many "quoting" issues and is sometimes (but not in your case though) the only possible way.
First you have to create the encoded command
$Command = "& 'C:\Users\test\Documents\Test Space\test.ps1'"
[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Command))
And then you can use the the -EncodedCommand parameter like this
powershell.exe -EncodedCommand JgAgACcAQwA6AFwAVQBzAGUAcgBzAFwAdABlAHMAdABcAEQAbwBjAHUAbQBlAG4AdABzAFwAVABlAHMAdAAgAFMAcABhAGMAZQBcAHQAZQBzAHQALgBwAHMAMQAnAA== -ExecutionPolicy Bypass
Try this:
& "C:\Users\test\Documents\test\line space\PS Script\test"
In your examples, you're mixing quotes and double quoting for no reason.
IF EXIST "C:\Users\test\Documents\test\line space\PS Script\test.ps1" (
powershell -ExecutionPolicy Unrestricted -File "C:\Users\test\Documents\test\line space\PS Script\test.ps1"
)
In case you use parameters you can do as follows.
powershell.exe -command "& {&'C:\A B C\foo.ps1' param1 param2}"
Thanks at this point to a blog post by Hesham A. Amin :-)
I needed to pass a parameter with spaces.
I am dragging and dropping a file onto a batch file, and the file is off on the server with spaces in the path and/or file name. After testing the above answers, I got this to work. Note I am changing to the working directory prior to starting the PowerShell executable.
Batch file:
pushd O:\Data\QuickList
start powershell -noexit -Command ".\QuickList.ps1 -datafile '%1'"
popd

How to Load Function in new Powershell.exe Console

I have a function (function1) which requires sta mode. I'd like tocall this function from a non sta mode poshconsole. This works when i have function1 in my Profile
$command = "function1 'MyArguments'"
powershell -sta -command $command
But how can i do this when i have the function1 not in the profile and i call
powershell -sta -noprofile -command $command
Can i execute multiple commands with a powershell.exe call? Or can i handover a customprofilepath?
You can separate multiple commands with a semicolon (;) for example, dot source your script containing your function, then call the function:
powershell -sta -noprofile -command ". c:\functions.ps1 ; function1 'MyArguments'"
There are some ways how to deal with STA:
Single Threaded Apartment in PowerShell V1
Asynchronicity in PowerShell
Thread.ApartmentState and PowerShell Execution Thread
In case you will call powershell.exe (because it is obviously easier), you can first load your script with the function and then execute function1 'My arguments'
powershell -sta -noprofile -command '<pathToYourScript>.ps1; function1 args'
I tried to use -file parameter and -command argument together, but that doesn't work.
If you are running the PowerShell Community Extensions you can use Invoke-Apartment e.g.:
PS> Invoke-Apartment -Apartment STA `
-Expr {[Threading.Thread]::CurrentThread.ApartmentState}
STA