Run a script as an admin user - ps2exe??

This topic contains 3 replies, has 2 voices, and was last updated by Profile photo of Dave Wyatt Dave Wyatt 2 years ago.

  • Author
    Posts
  • #20619
    Profile photo of stephenmbell
    stephenmbell
    Participant

    Do any of you have experience using PS2EXE ([url]https://ps2exe.codeplex.com/[/url]) script? It takes a script as input and outputs an exe file of the script. I am trying to use this process to create a script to self elevate without having the password easily obtained in the script.

    I have a script that I can pass a file path to, and it will run another powershell script as an admin user. This script that runs as the admin user copies some files to various places on the machine and across the network. I need to be able to copy files to essentially anywhere on the machine or on the other machine that is on the same subnet.

    Currently, my script, Enable-Elevated takes a parameter, FilePath. This file path is the path to the powershell script that needs to run as an admin. The script itself works fine – no problem other than the username and password being embedded in the script itself. So, ideally I would like to take my Enable-Elevated script and turn it into an exe so the password is not as easily in the clear.

    My problem is – when I exe the script, it isn't working. It doesn't seem to recognize the paramter, and I just don't understand. Like I mentioned, the script runs fine. The problem occurs when I convert it to an exe and call it with the parameter.

    Any help or ideas would be greatly appreciated.

    Thanks

    Here is my Enable-Elevated script:

    
    
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$false, 
                    ValueFromPipeline=$false,
                    ValueFromPipelineByPropertyName=$false, 
                    ValueFromRemainingArguments=$false, 
                    Position=0,
                    ParameterSetName='Parameter Set 1')]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidatePattern("([^\s]+(\.(?i)(ps1))$)")]
        [string]$FilePath,
    
        # Param2 help description
        [Parameter(Mandatory=$false, 
                    ValueFromPipeline=$false,
                    ValueFromPipelineByPropertyName=$false, 
                    ValueFromRemainingArguments=$false, 
                    ParameterSetName='Parameter Set 1')]
        [ValidateSet("Normal", "Minimized", "Hidden")]
        [string]$WindowStyle = "Hidden", 
    
        # Param3 help description
        [switch] $Help
    
    
    )
    
    $logFile = "c:\posapps\elevate\" + $(Get-Date -DisplayHint Date -Format "yyyyMMdd") + "_elevated.log"
    
    
     "$(Get-Date -DisplayHint Time -Format T)::  Elevate Process Started" | Add-Content $logFile
     
    # output usage
    if($help -or [String]::IsNullOrEmpty($FilePath)) 
    {
        Write-Host "Usage:"
        Write-Host ""
        Write-Host "    elevate.exe -FilePath '' [-WindowStyle] 'Normal' | 'Minimized' | 'Hidden'"
        Write-Host ""       
        Write-Host ""       
        Write-Host "        FilePath = Path to the signed powershell script to run"       
        Write-Host "     WindowStyle = Passes this to the powershell exe.  Options are Normal | Minimized | Hidden"       
        write-host ""
    
        "$(Get-Date -DisplayHint Time -Format T)::  Elevate Process Exiting" | Add-Content $logFile
        Exit
    }
    
    
    
    
    $command = "c:\windows\system32\windowspowershell\v1.0\powershell.exe"
    # example c:\posapps\powershell\ApplyPricing.ps1"
    #TODO - run powershell with an execution policy of allsigned
    $arguments = "-File $FilePath"
    
    "$(Get-Date -DisplayHint Time -Format T)::  File Path: $filepath" | Add-Content $logFile
    "$(Get-Date -DisplayHint Time -Format T)::  Window Style: $WindowStyle" | Add-Content $logFile
    
    $user = "DOMAIN\adminaccount"
    $pass = ConvertTo-SecureString -String "AdminPassword" -AsPlainText -Force
    $creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $pass
     
    Try{
    
        if(Test-Path -Path $FilePath)
        {
            # append the script path to the arguments
            $arguments += $FilePath
        
            # start the process
            Start-Process -FilePath $command -ArgumentList $arguments -WindowStyle $WindowStyle -Credential $creds
            
        }
    
    }
    Catch [System.Exception]
    {
    
        $message = "$_ #([environment]::NewLine) Command: $command $([environment]::NewLine) Arguments: $arguments" 
        $(Get-Date -DisplayHint Time -Format T):: ERROR: $message | Add-Content $logFile
    
    
    }
    
    # log the script ending
    
    
    "$(Get-Date -DisplayHint Time -Format T)::  Elevate Process Exiting" | Add-Content $logFile
    
    Exit
    
    
    
  • #20624
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    According to ps2exe's documentation, you need to pass the -end parameter to the executable before any arguments that you want to be passed to the embedded script.

    However, I'd just like to point out that you haven't really gained anything in terms of security. The original script still exists in easily decoded text, for anyone who cares to look. For example, using DotPeek on my compiled exe and looking at the Main function turns up this line:

    string @string = Encoding.UTF8.GetString(Convert.FromBase64String("JHBhc3N3b3JkID0gJ1N1cGVyIHNlY3JldCEn"));
    
    # Running this code at a PowerShell console:
    
    [Text.Encoding]::UTF8.GetString([convert]::FromBase64String('JHBhc3N3b3JkID0gJ1N1cGVyIHNlY3JldCEn'))
    
    # Returns my original script:
    
    $password = 'Super secret!'
    

    There is absolutely no way to have a self-elevating script (assuming the elevation happens locally) where it is not possible for the user to extract the credentials used for elevation. They can be obfuscated, but a determined person will always be able to peel back the layers and get to the original password; it's just a question of how much effort is involved.

    If that's not acceptable for you, the secure way to accomplish this is to set up a PowerShell remoting endpoint with the -RunAsCredential option set. That way, the elevated credentials are stored on a remote host and are never exposed to the local, unprivileged user. You can also define who has permissions to use the endpoint, and what commands are allowed to be run from inside of it. Jeffrey Snover has been working on a module named JEA (Just Enough Admin) to make setting up these endpoints easy; you can read about it [url="http://redmondmag.com/articles/2014/05/16/powershell-just-enough-admin.aspx"]here[/url]. He's also given talks about this module at several events over the past year (PowerShell Summit, TechEd, etc.)

    For some information about custom PSRemoting endpoints topic in general, Boe Prox did a great series on this topic back in April. Here's a link to the last article in the series; it contains links to the first 4: http://blogs.technet.com/b/heyscriptingguy/archive/2014/04/04/build-a-tool-that-uses-constrained-powershell-endpoint.aspx

  • #20625
    Profile photo of stephenmbell
    stephenmbell
    Participant

    Thank you very much for this response. I will take a look at the reading and posts about the JEA and powershell endpoints. I hope they can fit what I am trying to accomplish.

    As far as the documentation for ps2exe goes.... where do you see that? I looked on the codex, and came up empty. I did a find in ISE on the script itself and see "-end " in there at one point, is this where?

    Thanks again!
    sb

  • #20626
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    The documentation I referred to is about 2/3 down on the page at https://ps2exe.codeplex.com/ . It starts with "The generated EXE can also be calls using command line options", followed by a table with 4 parameters and their descriptions.

You must be logged in to reply to this topic.