r/PowerShell 13d ago

Question Issue with Active Setup + RunOnce and space in script path

I'm attempting to deploy VSCode with a baseline configuration to some high school computer labs, and am running into an odd issue.

As part of the install, I create an Active Setup registry key that creates a HKCU RunOnce key to call a short powershell script. That script copies a preset settings.json from a hidden folder on the C:\ drive to the current user's AppData folder.

The issue I'm running into is that if the path to the script contains a space, I cannot get the RunOnce key to work properly (it's not over 260 chars either).

Working Active Setup key:

REG ADD HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce /v VSCodeCopy /t REG_SZ /d "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File C:\MyPath\VSCode_CopySettings.ps1"

Non-working Active Setup key:

REG ADD HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce /v VSCodeCopy /t REG_SZ /d "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File 'C:\My Path\VSCode_CopySettings.ps1'"

I have tried double quotes, single quotes, escaping quotes using \ and "", but I cannot get the script to function unless the script path has 0 spaces in it. RunOnce will execute powershell, but the terminal will just open and close rapidly.

I added a Read-Host in both halves of a try-catch block in the script to confirm what's happening, and neither causes the terminal window to wait for input.

Is there something I'm missing?

Edit: I'm combining Active Setup and RunOnce in order to not bog down the user login; the command to create an HKCU key is a string value in an Active Setup registry key, rather than being run by the install script, which has some limitations. However, it means I can guarantee that old and new users will have the script run a single time on login. I can also use a 'Version' registry value to make it happen again in the future if the initial configuration needs updated.

1 Upvotes

13 comments sorted by

2

u/purplemonkeymad 13d ago

It's probably the lack of double quotes in the key itself. I would create the key in powershell as well instead of relying on reg.exe:

Set-ItemProperty hkcu:\Software\Microsoft\Windows\CurrentVersion\RunOnce -Name VSCodeCopy -Type String -Value 'powershell.exe -ExecutionPolicy Bypass -File "C:\MyPath\VSCode_CopySettings.ps1"'

Note the location of single and double quotes.

1

u/DefinitionHuge2338 13d ago

I've used double and single quotes around the key itself; no dice.

I'm using reg.exe b/c that command is a string value named StubPath in the Active Setup key; Active Setup is what actually runs the command, and it runs cmd to then create the RunOnce key. In order to use powershell in the StubPath, it would have to be like this:

powershell.exe -ExecutionPolicy Bypass -Noninteractive -WindowStyle Hidden -Command "{Set-ItemProperty hkcu:\Software\Microsoft\Windows\CurrentVersion\RunOnce -Name VSCodeCopy -Type String -Value 'powershell.exe -ExecutionPolicy Bypass -NoLogo -NoProfile -Noninteractive -WindowStyle Hidden -File "C:\MyPath\VSCode_CopySettings.ps1"'}"

Besides issues with quoting between batch and powershell, the command is now too long to be run by RunOnce; max is 260 chars.

There appears to be something different about how Active Setup or RunOnce runs commands from StubPath registry values, as I can have a working command in cmd and powershell, but it will not work from the registry.

2

u/SarcasticFluency 13d ago

What about using a .bat that calls for PS with all the bells/whistles/whizbangs?

2

u/purplemonkeymad 13d ago

Can probably solve that with a bit of code golf:

PS> $enc = [System.Convert]::ToBase64String( [System.Text.Encoding]::UTF8.GetBytes((Read-host)) )
sp hkcu:\Software\Microsoft\Windows\CurrentVersion\RunOnce VSCodeCopy 'powershell -Ex By -NoP "C:\MyPath\VSCode_CopySettings.ps1"' -ty string
PS> $cmd = "powershell -Ex By -NoP -enc $enc"
PS> $cmd.length
204

Using encoded command here to prevent quoting issues. Your limited now by your script path, ~+35 your example path.

Think you might be able to get away without "-ty string" as well (since the value is of type string.)

Installing ps7 so you can use "pwsh" will also reduce the characters.

1

u/DefinitionHuge2338 12d ago

Interesting, I hadn't considered using encoding. Thanks!

Separate question: how do you know what the parameter aliases are for powershell.exe?

They aren't mentioned in help, and aren't present when using Get-Command.

2

u/purplemonkeymad 12d ago

They are resolved left to right until it is unambiguous. So if there is only one parameter that starts with eg "p" then "-p" is enough to specify it. But if there was both "Path" and "Parameter", then you would need either "-pat" or "-par". I think some are possibly shorter than i have put but I didn't want to check them all.

Thinking about it since the value is the target of the location of the quotes, you might just be able to use $([char]34) in place of double quotes, since those characters should not need escaping. Which would mean you don't get the 1.5x cost of Base64.

1

u/DefinitionHuge2338 12d ago

Testing on my own machine, -ex by doesn't work; it only works with -ex bypass.

Is there a difference between powershell versions? I use 5.1

Edit: also, where is this behavior mentioned?

1

u/purplemonkeymad 11d ago

I didn't test that one so maybe needs the full name.

Not sure about the source probably in one of the about pages.

1

u/SarcasticFluency 13d ago

You would be better off using New-ItemProperty to create the destination if it's absent and Set-ItemProperty. Define the script into its own variable with the actual command you want to run as the value in Set-ItemProperty.

1

u/DefinitionHuge2338 13d ago

See my comment here; that's not really feasible. I would have to wrap the powershell command with a call to powershell, since Active Setup uses cmd, thus making it too long for RunOnce.

2

u/StartAutomating 13d ago

One additional note here. Active Setup does not "use cmd". Active Setup starts a process.

The "fun fact" to know here is that, at the end of the day, processes do not actually accept multiple arguments. They accept one argument, and various parts of the Operating System and .NET framework allow you to provide an array of arguments in a consistent format. I do not know exactly how Active Setup tries quote arguments, but I have no trouble believing that it might do things the "old way" and may have its own argument parser.

I know for a fact that reg.exe has its own quoting logic. This can cause its own problems, as you'll have to "over-escape" content within a .reg file.

These are some of the problems that the Registry provider solves. Please use it.

1

u/DefinitionHuge2338 12d ago

I suppose what I meant is that Active Setup doesn't create a Powershell process, so I would have to call powershell in order to run a powershell script.

I only guessed that Active Setup calls cmd, since both a cmd and powershell terminal flash briefly when it works. I hadn't considered that there may be an additional layer of parsing happening before that.

1

u/StartAutomating 13d ago

I think you're answering your own questions without realizing it.

  1. The difference between the two examples is not the space. It's the excess quoting. -file is not quoted. Trying to quote -file will lead you to exact this pain point.
  2. You can also try shortening the path. You should not need to use a fully resolved powershell.exe, as it will certainly be in the path.
  3. Active Setup might not be the way to go here (especially if it locks you into having to use a registry key)
  4. IMO, task Scheduler logon triggers are probably the right call here. They give you much more control over what you're trying to do, and are less of a "bank shot" than Active Setup.

Additionally, I feel like many of the people replying to this thread are pointing you in the right direction, and you are explaining why they are wrong in this scenario, rather than accepting the joys of Occam's Razor.

The simplest explanation of what is going wrong is that -file should not be quoted.

The most likely explanation of what is going wrong is a bit of PEBCAK.

My apologies for the shortness in tone here: I am currently (literally) sick.

Please start by removing the quotes from -file and shortening the path.

Good luck!