Launching Deploy-Application via PSEXEC using ServiceUI with Quoted paths fails

We are currently using an Invoke script to launch PSEXEC, using ServiceIU to display Deploy-Application UI to the user as the application is installed. This all works flawlessly with one exception, that is if $scriptParentPath has a space in it. To try and resolve the issue I have attempted to add Quotes to the existing command to deal with the spaces. But this then causes an issue with Deploy-Application. I have checked the formatting of the various quotes but running another application (with a space in the path) such as notepad++.exe with the same format works as expected. From testing the issue doesn’t appear to be the command itself but rather Deploy-Application.exe exiting as the exit code is showing as 0. It is exiting out the same second that it is launched and doesn’t create any log. Normally this isn’t an issue as MECM (SCCM) doesn’t have any spaces in its ccmcache paths, but sometimes our technicians will run the package manually on a machine from a path that has a space, I just wanted to head the issue off.

GitHub_Deploy-Application_Issue_Post_Code_COMPLETE

Toolkit Version:3.9.3
PowerShell Version: 5.1

I have posted on the GitHub Issues but thought I would also try here for visibility.

please try to change the " to ’ after -Parameters and after $DeploymentType

Hi,
Just tried that suggestion, it still fails due to the variables not translating into their values, please see log:

Hi,

Try:

Execute-Process -Path "$dirSupportFiles\psexec.exe" -Parameters "`"-accepteula -s $dirSupportFiles\ServiceUI_x64.exe`" -process:explorer.exe `"$scriptParentPath\Deploy-Application.exe`"" $DeploymentType -PassThru

Haven’t tested it but might work for you.

1 Like

As a colleague of Adi-R, I’ll give a bit of a background of why we are invoking “psexec with parameters of serviceUI and deploy-application.exe”. This does work 100% fine - just as long as you don’t have spaces in your $scriptParentPath (which to be fair isn’t typical but is something we noticed)

The reason we don’t run ServiceUI directly from SCCM is because we want a single package and Deployment Type that can run “whether or not a user is logged on” AND also displays interaction for logged-on users including RDP session users.

If we run ServiceUI directly from SCCM’s command line this does not work for Remote Desktop (RDP) sessions, and we have quite a few of these to consider. The interaction (e.g. dialogue boxes) are not displayed and will timeout, causing negative results.

Our “invoke script” will gather whether or not a user is logged on.
If “no user logged on” we execute-process “Deploy-Application.exe $DeploymentType”
If a user is logged on then we execute-process “psexec > serviceui > deploy-application.exe $DeploymentType”

Although technically only RDP or disconnect-RDP sessions need to run PsExec with ServiceUI, by doing this for all user-sessions we are “InTune-Ready” (where ServiceUI will be required for interaction).

Why are we using PsExec? Without it, we found SCCM deployments would fail. If we manually ran the same line from an administrative PsExec command prompt, it worked fine! So we added PsExec to call ServiceUI and this works 100% and we now have a SINGLE package solution.

Adi-R has only raised this question because we discovered that IF $scriptParentPath has a space in the path then it will fail and this only appears to be only a problem with “Deploy-Application” and works fine with spaces when testing against other apps such as NotePad++.

1 Like

While I completely understand your reasoning for using psexec (it’s a great utility after all), but be aware that some modern antivirus / malware prevention tools will block the use of psexec as it is often used by malicious users to wreck havoc on devices, might be worth having a read, here is some background reading:

So it may be worth considering if you could negate the use of psexec… as you are already using ServiceUI, you could specify your ServiceUI.exe command to run the install command in the System context e.g. serviceui.exe -session 0 rather than running in the user context serviceui.exe -process explorer.exe (explorer.exe will always run in session 1 as it does not run in the system context)
serviceui.exe syntax:

.\serviceui.exe

 Execute program interactively in target session. Must run from
 SYSTEM context. If no session is specified, program will run
 in session connected to keyboard/mouse (console).

 Usage: serviceui [-nowait] [ [-session:<sessionid>] | [-process:<process.exe>] ] program [arg(x)]

    -nowait   Don't wait for program completion. Exit
              code will not be captured.
    -session  Specify session number to launch in.
    -process  Search for process; program will
              launch in same session.
    program   Name of application to execute.
    arg(x)    Argument(s) for program.

 Examples:
  serviceui %windir%\notepad.exe
  serviceui -session:1 %windir%\notepad.exe
  serviceui -process:calc.exe %windir%\notepad.exe "\"my file.txt\""
  serviceui -process:calc.exe "%windir%\notepad.exe" "\"my file.txt\""



 =======================
 Exiting with [-1]
 =======================

A useful guide on using ServiceUI.exe:

As this is to have a single install that you can run on physical devices and machines with RDP sessions, you may need to detect if the machine is running RDP sessions.
Thankfully WIndows ships with two tools named QWINSTA.exe and RWINSTA.exe for querying and resetting Remote Desktop Services sessions (Who knew?!), this may help solve your challenge

Just a bit of a curve ball for your thought process :wink:

2 Likes

Thanks! You were very nearly there, your command threw a PsExec AcceptEULA UI box which pointed me in the right direction for a small quote change.

These lines worked!:

Execute-Process -Path "$dirSupportFiles\psexec.exe" -Parameters '-accepteula' -IgnoreExitCodes *

Execute-Process -Path "$dirSupportFiles\psexec.exe" -Parameters "`"-accepteula -s $dirSupportFiles\ServiceUI_x64.exe`" -process:explorer.exe `"$scriptParentPath\Deploy-Application.exe`" $DeploymentType" -PassThru

I had to run psexec and accept the eula, before running that line. If I didn’t do this and keep it in the original command it would immediately exit out with [-1].

Thank you

2 Likes

I think (personally) I’d move the `" to be after -accepteula -s as I think it reads more clearly - it ‘may’ also make the need to accept the EULA twice, go away, e.g.

Execute-Process -Path "$dirSupportFiles\psexec.exe" -Parameters "-accepteula -s `"$dirSupportFiles\ServiceUI_x64.exe`" -process:explorer.exe `"$scriptParentPath\Deploy-Application.exe`" $DeploymentType" -PassThru
1 Like

Hi,

I also tried this but it doesn’t work!
Well…it does if you don’t have spaces in the $scriptParentPath (back to that issue again!).

1 Like

Hi,

We have other security mitigations for this kind of stuff. We’re tested regularly :slight_smile:

As for detecting RDP sessions, thanks to paulh we have our own methods for detecting them.

We have done extensive testing over the last few days and this method really does allow us to do everything in one script.

Thanks

1 Like

Try to use $($variable) to get rid of issues getting your vars translated to its actual value, this way you get it right using single or double quotes. :slight_smile:

3 Likes

Just to update this with the final solution. The quoted paths in the post above were all working fine…… until we tried to do a required install via SCCM(available was fine). I am still not 100% sure why this is different from available(maybe someone here knows?), but it was causing the script to fail out. We re-tested with the un-quoted line and a required install, and it worked. Then a colleague let slip there maybe spaces in Intune paths!
So back to the drawing board….

There were 2 issues to fix:

  1. PsExec -accepteula not being accepted on the command line.
  2. Allow spaces in the paths.

After looking at it with a fresh pair of eyes this is the fix I came up with:

[string]$PsExecParameters = "-accepteula -s -w `"$dirSupportFiles`" `"$dirSupportFiles\ServiceUI_x64.exe`" -process:explorer.exe ..\Deploy-Application.exe $DeploymentType"

[psobject]$ExecuteProcessResult = Execute-Process -Path "$dirSupportFiles\PsExec64.exe" -Parameters $PsExecParameters -PassThru

The lines above work for SCCM(Available/Required), and manual install (with or without spaces in the path).

I hope this helps anyone wanting to go down this path.

4 Likes

Coming back to this 1 month later from a mention in other threads (and also with a fresh pair of eyes), have you tried using @Zelto’s suggestion, so your code would now look like:

[string]$PsExecParameters = "-accepteula -s -w `"$($dirSupportFiles)`" `"$($dirSupportFiles)\ServiceUI_x64.exe`" -process:explorer.exe ..\Deploy-Application.exe $($DeploymentType)"

[psobject]$ExecuteProcessResult = Execute-Process -Path "$($dirSupportFiles)\PsExec64.exe" -Parameters $($PsExecParameters) -PassThru

Let us know :man_shrugging:

2 Likes

Hi,

I did try this to start with, but at the time it didn’t work. Now the issue has been fixed with the lines I last posted I’m just leaving as is :grinning:

Hello,
Anyone from this conversation, people you please explain, why you have discarded Execute-Process function support for array of parameters? The parameter with name “-Parameters” in source code defined as [String[]] array of strings, which should be used with supplied comma-delimited parameters, but not constructing something over-complicated like multiple times double quoted compound-escaped-parameter string, which is why I think there are issues with deployments, because you then need to address handling multiple doublequotes and interpretation by numerous powershell functions.

So, if using array-type capabilities, your command line would look like this:

# Single Line - Pass array of parameters to -Parameters, which expects input as [String[]] array of strings
[psobject]$ExecuteProcessResult = Execute-Process -Path "$dirSupportFiles\PsExec64.exe" -Parameters @('-accepteula','-s',"-w ""$dirSupportFiles""","""$dirSupportFiles\ServiceUI_x64.exe"" -process:explorer.exe ""$dirSupportFiles\Deploy-Application.exe"" -DeploymentType $DeploymentType") -PassThru
# Two Line - pass parameters as variable (maybe better readable)
[String[]]$Parameters = @(
    '-accepteula'
    '-s'
    "-w ""$dirSupportFiles"""
    """$dirSupportFiles\ServiceUI_x64.exe"" -process:explorer.exe ""$dirSupportFiles\Deploy-Application.exe"" -DeploymentType $DeploymentType"
)

[psobject]$ExecuteProcessResult = Execute-Process -Path "$dirSupportFiles\PsExec64.exe" -Parameters $Parameters -PassThru

I haven’t test it with actual PSADT and PsExec, but syntax like this "-w ""$dirSupportFiles""" makes explicit double quotes for $dirSupportFiles.
Let me know if this works for you.

By the way, How its going with deploying apps with PsExec64.exe? :slight_smile:

Microsoft Windows Defender Security Update: Attack Surface Reduction Rule “Block Process Creations Originating from PSExec and WMI Commands”
The Attack Surface Reduction (ASR) rule introduced in Microsoft Defender blocks process creations originating from PsExec and WMI commands to mitigate potential abuse by attackers. This rule is part of Microsoft’s effort to reduce the attack surface and prevent lateral movement within networks, as PsExec and WMI are commonly exploited by malware.

I just updated from Windows Update and caught new Microsoft Windows Defender ASR rule, which prevents PsExec from running even for admin user.
Adrian_Scott has warned in this thread about potential problems having running PsExec integrated into deployment script. He was so damn right!

1 Like

Unless I have misunderstood what you are saying, you can simplify this quite simply…
I’d strongly suggest you escape the extra quotes around $dirSupportFiles, so it should look something like this:

"-w `"$dirSupportFiles"`"

and the escaped example in full:

# Single Line - Pass array of parameters to -Parameters, which expects input as [String[]] array of strings
[psobject]$ExecuteProcessResult = Execute-Process -Path "$dirSupportFiles\PsExec64.exe" -Parameters @('-accepteula','-s',"-w `"$dirSupportFiles`","`"$dirSupportFiles\ServiceUI_x64.exe`" -process:explorer.exe `"$dirSupportFiles\Deploy-Application.exe`" -DeploymentType $DeploymentType") -PassThru

and two line:

# Two Line - pass parameters as variable (maybe better readable)
[String[]]$Parameters = @(
    '-accepteula'
    '-s'
    "-w `"$dirSupportFiles`""
    "`"$dirSupportFiles\ServiceUI_x64.exe`" -process:explorer.exe `"$dirSupportFiles\Deploy-Application.exe`" -DeploymentType $DeploymentType"
)

[psobject]$ExecuteProcessResult = Execute-Process -Path "$dirSupportFiles\PsExec64.exe" -Parameters $Parameters -PassThru
1 Like

This may not be sufficient to escape.

For example, consider this code:
Write-Host "`[31mThis is red text`[0m"
Output:
[31mThis is red text[0m But this is normal text.
Obviously, this means escape character " ` " doesn’t work in powershell. Or in some circumstances it doesn’t work (as AI told me this fails in advanced and complex scenarios like Invoke-Script and passing parameters with backticks to external programs, which may re-parse string and interpret ` differently and this can produce unexpected results. Which makes ` usage unreliable for deployment script, as those exactly mess with invoking scripts and passing arguments to other executables.

Now if you explicitly create escape character using [char]27 as in example below:
Write-Host "$([char]27)[31mThis is red text$([char](27))[0m But this is normal text."
Output is:
This is red text But this is normal text.
Which also gets Red-colored as in this case explicit escape character creation using [char]27 does invoke correct interpretation of ANSI color codes.

Same can be done for double quotes to make them explicit when string gets interpreted in powershell using ASCII [char]34 definition:
Write-Host "$([char]34)C:\This is\a path\with spaces\$([char]34)"
Output is:
"C:\This is\a path\with spaces\"

I’ve been using Chr(34) in VBScript for years to safely enclose paths which may contain spaces to pass them as parameters.
You might try how this approach works for you.
I wouldn’t bet on " ` " as always foolproof solution, despite its being suggested almost everywhere.

I was saying - that rather than having one very long over-complicated parameter, if you can utilize capabilities of array type of parameter “-Parameters” of Execute-Process function to brake down multiple parameters into separate strings and have less nested double quotes to escape, then probably should try that to have more simple approach. “-Parameters” in “Execute-Process” expects input as [String[]], which means there is no need to embed “-accepteula” inside long parameter string, unless passing parameters as array doesn’t work for some other reason.

1 Like

FYI It does, you just need to know how to play it :wink:
Simply surround your escaped line within a code block (3 escape characters on their own line before ``` and 3 on their own line after) - or simply use Ctrl+e or the Preformatted text button </>
That’s how I achieved this:

"-w `"$dirSupportFiles"`"
2 Likes

Kudos, thanks, I edited my reply to have displayed backticks (grave accent) characters ` properly.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.