Am I invoking PsExec wrong or is it not working properly?

Merwinsson 0 Reputation points
2024-04-16T17:43:13.7766667+00:00

I am attempting to use PsExec from an admin powershell to spawn a GUI Win32 program from my current session into another session (#1).

Like this:

./psexec64 -i 1 path-to-my-exe-to-run

Since it didn't work with my program, and returned a negative return code, I tried simpler things like CMD and NOTEPAD. Neither of these worked either, but failed in different ways. CMD actually ran, but the window was completely devoid of output or window controls - just a black void with an empty title bar. ALT F4 closed it. For NOTEPAD it spawned a few processes that then disappeared leaving 1 process in SUSPENDED state and no UI to be seen. Had no idea what to do with the suspended process remnant - attempting to kill it did nothing.

So that brings me to my point: am I doing something wrong or am I misinterpreting PsExec functionality, or is this buggy behavior?

I need to be able to run my Win32 GUI program with admin rights but without getting a UAC prompt, and in another desktop session.

Yes, I am aware of the security implications. My use case requires it, so let's not get bogged down and focus on specifically what I'm asking - is PsExec broken or have I misused or misinterpreted it?

If this sounds like I'm trying to create malware, yes, I am...no...just kidding, so to head off any potential comments as to my intentions and whether or not they are malicious, here is the boring explanation of EXACTLY why I am trying to do this, as I see now I'm going to have to go into these details so people don't get uncomfortable.

I have a really dumb program called Amcrest Surveillance Pro which is coded VERY BADLY. It does SOMETHING that requires elevation, so normal non-admin users MUST enter an admin password to start it. Well, as you might imagine, I (the sysadmin) don't want regular users to know any admin level passwords, but I definitely DO want the users to be able to run this run this program. What to do, what to do...

I can't abuse Task Scheduler anymore; the best I can do is get a non-gui EXE running with admin privs in session 0 - which, to elaborate for those who are unaware, is the special session where non-gui procs like services run.

I've used said Scheduled Task to get me running an admin powershell session running in session 0. So the next logical step to get my GUI prog running in session 1 (with admin rights) is to use PsExec as I outlined - it's just not working correctly at all.

BTW, asking CoPilot to help me resulted in it recommending PsExec.

I am running Windows 11 Pro at the latest consumer patch level.

Windows 11
Windows 11
A Microsoft operating system designed for productivity, creativity, and ease of use.
9,974 questions
Sysinternals
Sysinternals
Advanced system utilities to manage, troubleshoot, and diagnose Windows and Linux systems and applications.
1,171 questions
{count} votes

1 answer

Sort by: Most helpful
  1. MotoX80 34,516 Reputation points
    2024-04-19T16:49:41.5533333+00:00

    Here is RunAsAdmin.ps1.

    It's working for me on Win11+PS5.1. Give it a go and let me know if something doesn't work.

    <#
    
    .SYNOPSIS
    
    This script allows a user that is not a member of the administrators group to run 
    a process as a different account that DOES have admin rights. The userid and password 
    are saved in the registry in base64 format. This won't stop a tech saavy user 
    who can write Powershell code from getting the password, but for the majority 
    of users, this is good enough. 
    
    If additional security is needed, one option would be to use the PS2EXE tool to encapsulate 
    the script into an executable file. https://github.com/MScholtes/PS2EXE
    
    Author: MotoX80 on Microsoft Q&A Forums 
    
    .DESCRIPTION
    
    Run a process as a UAC elevated admin account.  
    
    This script accepts these parameters.
    -Define    A switch to indicate that a task is to be defined and saved into the registry. 
    -Run       A switch to indicate that a task is to be launched.   
    -Task      The name of the "thing" we want define/run.  
    -User      The userid of the administrator account
    -Password  The userid's password.
    -Exe       The path to the program to be executed.
    -Parms     Optional, any parameters to passed to the program. 
    
    .EXAMPLE
    
    ./RunAsAdmin.ps1 -Define -Task xxxx -Exe cmd.exe -Parms "/k timeout /t 5" -User admin -Password admin
    ./RunAsAdmin.ps1 -Run -Task xxxx 
    
    .EXAMPLE
    
    ./RunAsAdmin.ps1 -Define -Task AR -Exe "C:\Program Files\Mythicsoft\Agent Ransack\AgentRansack.exe" -User admin -Password admin
    ./RunAsAdmin.ps1 -Run -Task AR 
    
    #>
    
    param (
      [switch]$Run,
      [switch]$Define,
      [string]$User = "",
      [string]$Password = "",
      [string]$Exe = "",
      [string]$Parms = "",
      [string]$Task = ""
    )
    
    $RegPath = 'HKCU:\SOFTWARE\Madware\Tasks'                   # modify if you don't like my name
    
    If ($Task -eq "") {
        "You need to specify a task name."
        return
    }
    if ($Run) {
        "Attempting to to run $Task"
        if (!(Test-Path –Path "$RegPath\$Task")) {
            "Task not defined."
            return
        }
        $x64 = (Get-ItemProperty –Path "$RegPath\$Task").1 
        $User = [Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($x64))
        $x64 = (Get-ItemProperty –Path "$RegPath\$Task").2 
        $Password = [Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($x64))
        $x64 = (Get-ItemProperty –Path "$RegPath\$Task").3 
        $Exe = "'" + [Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($x64)) + "'"
        $x64 = (Get-ItemProperty –Path "$RegPath\$Task").4 
        $Parms = "'" + [Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($x64)) + "'"
        $secpswd = ConvertTo-SecureString $Password -AsPlainText -Force
        $Cred = New-Object System.Management.Automation.PSCredential ($User, $secpswd)
        # We first have to start a PS process with the users' credentials.
    	# That instance of PS can then launch the elevated application process.  
    	# The downside to this approach is that if the app .exe doesn't run, this current script won't capture the error.  
    	try {             
            if ($Parms -eq "''") {
                $p2 = "Start-Process $Exe -verb runas"
                Start-Process Powershell.exe -ArgumentList "-command $p2"   -credential $Cred
           } else {
                $p2 = "Start-Process $Exe -argumentlist $Parms -verb runas"
                Start-Process Powershell.exe -ArgumentList "-command $p2"   -credential $Cred
           }
        } catch  {
            "Error starting Powershell."
            $_.exception
        }
    } elseif ($Define) {
        if ($User -eq "") {
            "Please specify a user."
            return
        }
        if ($Password -eq "") {
            "Please specify a password."
            return
        }
        if ($Exe -eq "") {
            "Please specify an executable."
            return
        }
    
        if (!(Test-Path –Path "$RegPath\$Task")) {
            "Adding new task $Task."
            $null = New-Item –Path "$RegPath\$Task" –Force
        } else {
            "Updating task $Task."
        }
    	# Check to see if the exe exists. If the user entered "cmd.exe" which would be resolved via the 
        # system path, just assume it's ok.
        # If they've included a drive letter, check that.	
    	if ($exe.contains(":") -eq $true) {
    		if (!(Test-Path –Path $exe)) {
    			"File not found. $exe"
    			return
    		}
    	}	
    	
        $x64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($User))
        $null = New-ItemProperty –Path "$RegPath\$Task" –Name '1' –Value $x64 –PropertyType 'String' -Force
        $x64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($Password))
        $null = New-ItemProperty –Path "$RegPath\$Task" –Name '2' –Value $x64 –PropertyType 'String' -Force
        $x64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($Exe))
        $null = New-ItemProperty –Path "$RegPath\$Task" –Name '3' –Value $x64 –PropertyType 'String' -Force
        $x64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($Parms))
        $null = New-ItemProperty –Path "$RegPath\$Task" –Name '4' –Value $x64 –PropertyType 'String' -Force
    } else {
        "You need to specify either -Define or -Run."
    }
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.