Running PowerShell as another user, and launching a script
Asked Answered
T

9

90

I won't get into all the details of why I need this, but users must be able to launch PowerShell as a service account and when PowerShell loads it needs to run a script. I already can launch PowerShell with the stored credentials (stored as a secure string), but for the life of me I cannot get the script (located in $args) to run. I have tried a variety of things, and below is where I am currently. Any help would be greatly appreciated.

$user = "domain\service.account" 
$pwd1 = "big long huge string of characters"
$pwd = ($pwd1 | ConvertTo-SecureString)
$Credential = New-Object System.Management.Automation.PSCredential $user, $pwd
$args = "\\domain.local\location\location\location\Script\script.ps1"
Start-Process powershell.exe -Credential $Credential -ArgumentList ("-file $args")
Tropical answered 11/3, 2015 at 14:47 Comment(1)
When I try to run as different user, nothing happens. Is there some kind of policy in my server against that?Revareval
I
112

You can open a new powershell window under a specified user credential like this:

start powershell -credential ""

enter image description here

Intine answered 29/6, 2016 at 14:15 Comment(3)
Somehow, when I use this method, I can't type anything into newly opened powershell window. Using trick from https://mcmap.net/q/235090/-running-powershell-as-another-user-and-launching-a-script works, though. Sigh.Starfish
Oh weird, if you close the parent powershell window, the new child one can receive keyboard inputGora
Because, It is the feature from windows by default.Intine
D
62

I found this worked for me.

$username = 'user'
$password = 'password'

$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword
Start-Process Notepad.exe -Credential $credential

Updated: changed to using single quotes to avoid special character issues noted by Paddy.

Dieselelectric answered 16/12, 2015 at 8:50 Comment(6)
I had to put my password in single quotes since it contained 'special' characters. You can check the password has been stored correctly by writing $password at the prompt, it will print what is stored in the variableFlask
Thanks @Paddy, I've updated the code to reflect your comment.Dieselelectric
probably best to default to using single quotes in practice. helps avoid unintended issues cropping up--saving double quotes for when you intend to use them for a specific purpose.Sock
I feel like this should be the go-to solution for all the 'Run As' issues people face due to execution restrictions. Personally, I have tried a lot of solutions on SO and found this to be the only working one.Dissimilation
Security remark This stores the password in plain text in the script, which is usually a bad idea.Resonate
@Resonate Very good point. Make sure you don't store your passwords in your scripts! Pull them in from environment variables or other data stores.Dieselelectric
F
61

Here's also nice way to achieve this via UI.

0) Right click on PowerShell icon when on task bar

1) Shift + right click on Windows PowerShell

2) "Run as different user"

Pic

Falzetta answered 28/6, 2017 at 8:49 Comment(0)
U
9

Try adding the RunAs option to your Start-Process

Start-Process powershell.exe -Credential $Credential -Verb RunAs -ArgumentList ("-file $args")
Urena answered 11/3, 2015 at 15:54 Comment(2)
Thanks, I eventually saw the reason for the credentials prompt. The massive string used is too large, so I need to look at other options for storing and/or converting this password.Tropical
Adding -Verb RunAs yields me a Parameter set cannot be resolved using the specified named parameters. My other parameters are -Wait, -Credential $creds, -WorkingDirectory C:\ -ArgumentList "..." This is with powershell 5.Tobar
U
4

This command works for me:

Start-Process powershell.exe -Credential $Credential -ArgumentList "-file $FILE"

If the $FILE is on network, make sure the run-as user can access the file.


Script

I just created a script to make it easier for automation:

 <#

.SYNOPSIS

Run command as another user.

.DESCRIPTION

Run batch or PowerShell command as another user.

.PARAMETER Command

The batch command you'd like to execute as another user.

.PARAMETER ScriptBlock

The PowerShell command you'd like to execute as another user.

.PARAMETER Username

Run the command as what user.

.PARAMETER Password

Password of the user.

.PARAMETER Credential

PowerShell credential of the user, it can be generated by `Get-Credential`.

.PARAMETER Wait

Wait command to complete or not.
Command output would not be displayed if it is not specified.

#>

Param (
    [Parameter(Mandatory = $true, ParameterSetName = "bat-user-password")]
    [Parameter(Mandatory = $true, ParameterSetName = "bat-credential")]
    [ValidateNotNullOrEmpty()]
    [String]
    $Command,

    [Parameter(Mandatory = $true, ParameterSetName = "ps-user-password")]
    [Parameter(Mandatory = $true, ParameterSetName = "ps-credential")]
    [ScriptBlock]
    $ScriptBlock,

    [Parameter(Mandatory = $true, ParameterSetName = "bat-user-password")]
    [Parameter(Mandatory = $true, ParameterSetName = "ps-user-password")]
    [ValidateNotNullOrEmpty()]
    [String]
    $Username,

    [Parameter(Mandatory = $true, ParameterSetName = "bat-user-password")]
    [Parameter(Mandatory = $true, ParameterSetName = "ps-user-password")]
    [ValidateNotNullOrEmpty()]
    [String]
    $Password,

    [Parameter(Mandatory = $true, ParameterSetName = "bat-credential")]
    [Parameter(Mandatory = $true, ParameterSetName = "ps-credential")]
    [PSCredential]
    $Credential,

    [Switch]
    $Wait
)

$IsCurrentAdminUser = $([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')

# Find a dir that every user have full access to
$TempDir = "$env:SystemDrive\Users\Public\run_as"
if (-not (Test-Path -Path $TempDir)) {
    $null = New-Item -Path $TempDir -ItemType Directory
    attrib +h $TempDir
}

# Generate a uniq id for problem tracking
$ExecId = Get-Random -Maximum 99999999 -Minimum 10000000

# Temp files
$UserScriptPrefix = "$TempDir\$ExecId-UserScript"
$UserStdOut = "$TempDir\$ExecId-UserStdOut.log"
$UserErrOut = "$TempDir\$ExecId-UserErrOut.log"
$WaitFile = "$TempDir\$ExecId-Running"

$ExecScript = "$TempDir\$ExecId-Exec.ps1"
$CmdToExec = "Start-Process"

if ($PsCmdlet.ParameterSetName.StartsWith('bat')) {
    $UserScript = $UserScriptPrefix + '.bat'
    $Command |Out-File -FilePath $UserScript -Encoding ascii

    $CmdToExec += " cmd.exe -ArgumentList '/c $UserScript'"
} elseif ($PsCmdlet.ParameterSetName.StartsWith('ps')) {
    $UserScript = $UserScriptPrefix + '.ps1'
    $ScriptBlock |Out-File -FilePath $UserScript -Encoding ascii

    $CmdToExec += " PowerShell.exe -ArgumentList '-file $UserScript'"
}

if ($PsCmdlet.ParameterSetName.EndsWith('user-password')) {
    $SecPassword = ConvertTo-SecureString -String $Password -AsPlainText -Force
    $Credential = New-Object -TypeName System.Management.Automation.PSCredential ($Username, $SecPassword)
}

$CmdToExec += " -WorkingDirectory $env:SystemDrive\"

if ($Wait) {
    # Redirect output only if -Wait flag is set
    $CmdToExec += " -RedirectStandardError $UserErrOut"
    $CmdToExec += " -RedirectStandardOutput $UserStdOut"

    if ($IsCurrentAdminUser) {
        # -Wait parameter of Start-Process only works with admin users
        # Using it with non-admin users will get an "Access is denied" error
        $CmdToExec += " -Wait"
    }
}

$script = @'
Param($Cred)
"" | Out-File -FilePath {0}

try {{
    {1} -Credential $Cred
}} catch {{
    Write-Host $_
}} finally {{
    Remove-Item -Path {0} -Force -Confirm:$false
}}
'@ -f $WaitFile, $CmdToExec

$Script |Out-File -FilePath $ExecScript -Encoding ascii

try {
    & $ExecScript -Cred $Credential
} catch {
    Write-Host $_
} finally {
    if ($Wait) {
        if (-not $IsCurrentAdminUser) {
            # Impelment the wait by file monitoring for non-admin users
            do {
                Start-Sleep -Seconds 1
            } while (Test-Path -Path $WaitFile)
    
            # Wait output are write to files completely
            Start-Sleep -Seconds 1
        }

        # Read command output from files
        if (Test-Path -Path $UserStdOut) {
            Get-Content -Path $UserStdOut
        }

        if (Test-Path -Path $UserErrOut) {
            Get-Content -Path $UserErrOut
        }
    }

    Remove-Item -Path "$TempDir\$ExecId-*" -Force -Confirm:$false -ErrorAction SilentlyContinue
}

Copy the content and save to a *.ps1 file, like run_as.ps1.

Document

Show build-in doucment:

PS C:\> Get-Help C:\run_as.ps1 -detailed

NAME
    C:\run_as.ps1

SYNOPSIS
    Run command as another user.


SYNTAX
    C:\run_as.ps1 -Command <String> -Credential <PSCredential> [-Wait] [<CommonParameters>]

    C:\run_as.ps1 -Command <String> -Username <String> -Password <String> [-Wait] [<CommonParameters>]

    C:\run_as.ps1 -ScriptBlock <ScriptBlock> -Credential <PSCredential> [-Wait] [<CommonParameters>]

    C:\run_as.ps1 -ScriptBlock <ScriptBlock> -Username <String> -Password <String> [-Wait] [<CommonParameters>]


DESCRIPTION
    Run batch or PowerShell command as another user.


PARAMETERS
......

Examples

01

Current user is administrator, run batch command as user01 with password

Note: Please DO NOT use plain password in production environment. You can use it for testing. In a production environment, you can use -Credential option instead.

PS C:\> whoami
test-win-1\administrator
PS C:\> .\run_as.ps1 -Command 'whoami' -Username 'user01' -Password 'password1'
PS C:\> 
PS C:\> # Add -Wait to get command output
PS C:\> .\run_as.ps1 -Command 'whoami' -Username 'user01' -Password 'password1' -Wait

C:\>whoami
test-win-1\user01
PS C:\> 
PS C:\> # Add '@' to batch command to avoid the header lines
PS C:\> .\run_as.ps1 -Command '@whoami' -Username 'user01' -Password 'password1' -Wait
test-win-1\user01
PS C:\>

02

Current user is administrator, run PowerShell command as user02 with password

Note: Please DO NOT use plain password in production environment. You can use it for testing. In a production environment, you can use -Credential option instead.

PS C:\> $env:USERPROFILE
C:\Users\Administrator
PS C:\> .\run_as.ps1 -ScriptBlock {$env:USERPROFILE} -Username 'user02' -Password 'password2' -Wait
C:\Users\user02
PS C:\>

03

Current user is administrator, run PowerShell command as user02 with its credential

PS C:\> $env:USERPROFILE
C:\Users\Administrator
PS C:\> $cred = Get-Credential user02    # input user02's password in the pop-up window
PS C:\> .\run_as.ps1 -ScriptBlock {$env:USERPROFILE} -Credential $cred -Wait
C:\Users\user02
PS C:\>

04

Current user is user01, run PowerShell command as administrator

PS C:\> $(Get-ChildItem C:\Users\Administrator\).FullName                                                                                 
Get-ChildItem : Access to the path 'C:\Users\Administrator' is denied.                                                                    
At line:1 char:3                                                                                                                          
+ $(Get-ChildItem C:\Users\Administrator\).FullName                                                                                       
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                                                                                                 
    + CategoryInfo          : PermissionDenied: (C:\Users\Administrator\:String) [Get-ChildItem], UnauthorizedAccessException             
    + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand                                
                                                                                                                                        
PS C:\> whoami                                                                                                                            
test-win-1\user01                                                                                                                         
PS C:\> # Standard user cannot access administrator user's home directory
PS C:\> 
PS C:\> .\run_as.ps1 -ScriptBlock {$(Get-ChildItem C:\Users\Administrator\).FullName} -Username Administrator -Password 'adminpasswd' -Wait  
C:\Users\Administrator\.vscode                                                                                                            
C:\Users\Administrator\3D Objects                                                                                                         
C:\Users\Administrator\Contacts                                                                                                           
C:\Users\Administrator\Desktop                                                                                                            
C:\Users\Administrator\Documents                                                                                                          
C:\Users\Administrator\Downloads                                                                                                          
C:\Users\Administrator\Favorites                                                                                                          
C:\Users\Administrator\Links                                                                                                              
C:\Users\Administrator\Music                                                                                                              
C:\Users\Administrator\Pictures                                                                                                           
C:\Users\Administrator\Saved Games                                                                                                        
C:\Users\Administrator\Searches                                                                                                           
C:\Users\Administrator\Videos                                                                                                             
PS C:\>                                                                                                                                   
Undertrump answered 4/3, 2022 at 7:11 Comment(2)
This script is great, but you should add a note that if you do NOT supply the -password it will prompt you for it, which is WAY more secure than having it in your command history.Holst
Thanks for the suggestion! I have added notes for that. You're right, but the bad thing is that you need to input password every time. If you use the -Credential, the PSCrednetial object only need to be created one time and can be used for many times.Undertrump
T
3

In windows server 2012 or 2016 you can search for Windows PowerShell and then "Pin to Start". After this you will see "Run as different user" option on a right click on the start page tiles.

Thursday answered 14/4, 2017 at 14:50 Comment(0)
T
3

You can get a credential popup that will get the username and password as strings like this:

enter image description here

#Get credentials
$credential = Get-Credential
$username = $credential.Username
$password = $credential.GetNetworkCredential().Password

Then you can use in your script the variables $username and $password

Tammany answered 30/8, 2021 at 7:15 Comment(0)
S
1

This worked for me. This is helpful in remote servers where you just a have remote command line tool available to use.

runas /user:Administrator "powershell Start-Transcript -Path C:\Users\m\testlog.txt;import-module 'C:\Users\m\script.ps1';Stop-Transcript"

This will also ensure that you can get the output of the command in testlog.txt

Sudbury answered 12/8, 2022 at 5:40 Comment(0)
E
1

Two things:

As far as I can tell, your script is correct because your credential is in the form of <domain>\<user>

But, I have two questions:

  1. Does your service user have sufficient permissions to access the script you want to run in the location from which you want to run it?
  2. Does your service user have sufficient permissions to exist in the directory from which you are running PowerShell?

If your answer to #1 is no, well, you know how to fix that.

If your answer to #2 is no, then specify -WorkingDirectory <path> where <path> is the location of the script (because you've already fixed/verified any permission issues), or a location to which the service user has access.

Exonerate answered 27/2 at 18:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.