Search code examples
powershellautomationparameter-passinginvoke-commandstart-process

Run Powershell script that uses -List (parameter) with alternate credentials that


I was struggling to get this simple (?) function working today.

I have a PowerShell script that reads computer names from a txt-based file. It works fine when run from a PowerShell session by the following one-liner:

./"Server Health Check.ps1" -List One-off.txt

As you can see, it's got a long file name, so it's wrapped with quotes.

However, I'm building a PowerShell GUI form with radio boxes that will pass on a choice for a text file that will be used to a call the script. Trick is, the script needs to be run with alternate admin account, and i'm not clear how to make that work.

For another script I've got that doesn't use I know i can use something along the lines of the following, this uses the old DOS "runas", however, it doesn't work with the -list function.

invoke-command -scriptblock {runas.exe /user:domain\$Env:Username"admin" "powershell.exe -file \"\\Server\c$\LONG FOLDER\Server Health Check.PS1""}

So, in a nutshell, how do get a script to launch with alternate credentials that reads a parameter (-List) from the command line? I'm also keen to preserve my directory structure, which includes folders with spaces. The script is titled: "Server health check.ps1"

The last thing I tried was the following

$ScriptPath = "C:\SCRIPTS FOLDER\Server Health Check.ps1"
$ArgList = "-List C:\SCRIPTS FOLDER\One-off.txt"
Invoke-Command -filepath $ScriptPath -Credential DragonBallDomain\$Env:UserName"Admin"  -ArgumentList $ArgList

The result was the following message:

Invoke-Command : Parameter set cannot be resolved using the specified named parameters.

I'm almost certain this is do-able by invoke-command or start-process, it's just a matter of getting the correct formatting? I'm probably missing a / or a ' or "" somewhere in my trials with start-process or invoke-command.

Any help appreciated!

Update for April 30:

I've tried some more to make this work, i'm close, but still not quite there.

$LongScriptPath = resolve-path Script.ps1
$LongFolderPath = \\UNC\PATH TO FOLDER\WITH LONG NAME\
 start-process -filepath powershell.exe -argumentlist " -file``"$($FilePath.path)`"" -cred DOMAIN\USERID -WorkingDirectory "$LongFolderPath"

Adding the -credential is what causes an error that states that the -file parameter is invalid. I'm sure there's a way to do this.


Solution

  • Note: Completely rewritten after the requirements became clearer.

    To run a command as a different user locally, use Start-Process -Credential ...

    That is what you've attempted in your update in principle, but there are problems with how you're passing parameters; try this instead:

    $LongScriptPath = resolve-path Script.ps1
    $LongFolderPath = '\\UNC\PATH TO FOLDER\WITH LONG NAME\'
    start-process `
      powershell.exe `
      -ArgumentList '-file', $LongScriptPath, '-List', 'One-off.txt' `
      -Credential DOMAIN\USERID `
      -WorkingDirectory $LongFolderPath
    
    • The key to making this work is to pass all parameters to pass to powershell.exe as an array via Start-Process's -ArgumentList parameter, which means that the parameters must be ,-separated.

      • Note how an array is always parsed in expression mode, which means that literal string elements such as -file and -List must be quoted.
      • It is important in general to understand the difference between PowerShell's two fundamental parsing modes, argument mode and expression mode, and which is applied when - see https://technet.microsoft.com/en-us/library/hh847892.aspx
    • Add -Wait to wait for the script to finish; Start-Process is asynchronous by default (all PS cmdlets named Start-* are).

      • Caveat: For commands invoked as a different user, you can only wait from an elevated prompt.
        If it isn't, the command will still execute, but will do so asynchronously, and you'll get an Access denied error message in the current console; in effect, -Wait is ignored.
    • Only if not running as a different user: Add -NoNewWindow -Wait if you want to run the script in the current console window; Start-Process opens a new window by default for console applications such as powershell.exe and cmd.exe.

      • If you do run the command as a different user, -NoNewWindow is quietly ignored.

    As for the original symptom and why using Invoke-Command to run a command locally as a different user is ill-advised:

    • Invoke-Command -Credential ... requires that the -ComputerName parameter be specified too.

      • Run Get-Help Invoke-Command to see all parameter sets that involve the -Credential parameter. The OP's original command had only -Credential, but not -ComputerName, which caused PS to complain that no parameter set could be unambiguously identified.
    • Once you use -ComputerName, PowerShell remoting is invariably used, even if you specify . - the local computer - as the only computer to target.

      • Using remoting has two implications:
        • Remoting is not available by default, and must be configured on the target computer (the local computer, in this case).
        • Using remoting requires invocation with admin privileges.

    In short:

    • While you can perform purely local invocations with Invoke-Command, you cannot do so as another user, because that invariably involves remoting.

    • Start-Process, by contrast, solely exists to run commands locally, optionally as a different user.