Search code examples
powershellrunaspowershell-7.0

Execute a PowerShell script within RunAs in a script


I have a need to run a PowerShell script as another user (the users will actually be doing the auth) based on detected environment. The script leverages a smartcard for login. The problem I have is when the PowerShell.exe instance launches from the runas, it simply prints my command and doesn't actually run it.

Note: The filepaths have spaces that get escaped with double-`, just not shown here hence the escaped ``' in the actual command. Have also used ```".

Example:

Start-Process runas.exe "/netonly /smartcard /user:domain\$env:USERNAME ""powershell.exe -noexit -Command `'&$filePath -arg1 -arg2`' "" "

or

Start-Process runas.exe "/netonly /smartcard /user:domain\$env:USERNAME ""powershell.exe -noexit -File `'$filePath -arg1 -arg2`' "" "

File path points to the same .ps1 file. The dir is similar to: C:\Users\Username\My Documents\script.ps1

When this runs I simply get a script window that doesn't actually run, it just prints the File name. I have also tried using -File but that simply crashes (regardless of -noexit). The runas bit works fine, I get my smartcard prompt etc its just the actual PowerShell launch that I am struggling with.

These work just fine calling them directly from PowerShell Cli but when in a .ps1 it just won't work.

Any help would be greatly appreciate.


Solution

  • There's generally no reason to use Start-Process to run a console application such as runas.exe - unless you explicitly want the application to run in a new window, asynchronously (by default) - see this answer for more information.

    Eliminating Start-Process simplifies the quoting:

    runas.exe /netonly /smartcard /user:domain\$env:USERNAME "powershell.exe -noexit -File \`"$filePath\`" -arg1 -arg2"
    

    Note the - unfortunate - need to manually \-escape the embedded " chars. (`"), which is required up to at least v7.1 - see this answer.


    As for what you tried:

    On Windows, passing a '...'-enclosed string to the PowerShell CLI's -Command (-c) parameter from outside PowerShell (such as via runas.exe) causes it to be interpreted as a verbatim PowerShell string, printing its content as-is (except for whitespace normalization).

    You can verify this by running the following from cmd.exe, for instance:

    C:\>powershell -c 'Get-Date; whatever I type here is used as-is -   almost'
    
    Get-Date; whatever I type here is used as-is - almost
    

    Note how the multiple spaces before the word almost were normalized to a single one.

    The reason is that on Windows only double-quoting ("...") has syntactic function on the command line - ' characters are interpreted verbatim and therefore passed through.

    Therefore, when the -Command (-c) argument sees its argument(s) -- after command-line parsing - and then interprets the resulting space-joined, possibly double-quote-stripped arguments as PowerShell source code, a span of '...' is interpreted as a verbatim PowerShell string, as usual (see the conceptual about_Quoting_Rules help topic, which discusses the types of PowerShell string literals).

    In concrete terms:

    • 'Get-Date; whatever I type here is used as-is - almost' is parsed by the PowerShell CLI as the following arguments(!):

      • 'Get-Date;, whatever, I, type, here, is, used, as-is, -, almost' - note how any information about the amount of whitespace that originally separated these argument is lost in the process.
    • These arguments are then joined with a single space to form the string that PowerShell then interprets as PowerShell source code, which yields:

      • 'Get-Date; whatever I type here is used as-is - almost'
    • This amounts to a verbatim (single-quoted) PowerShell string literal, whose content is then output as-is.