Running PowerShell as another user, and launching a script
PowershellRunasPowershell Problem Overview
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")
Powershell Solutions
Solution 1 - Powershell
You can open a new powershell window under a specified user credential like this:
start powershell -credential ""
Solution 2 - Powershell
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.
Solution 3 - Powershell
Here's also nice way to achieve this via UI.
-
Right click on PowerShell icon when on task bar
-
Shift + right click on Windows PowerShell
-
"Run as different user"
Solution 4 - Powershell
Try adding the RunAs
option to your Start-Process
Start-Process powershell.exe -Credential $Credential -Verb RunAs -ArgumentList ("-file $args")
Solution 5 - Powershell
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.
Solution 6 - Powershell
You can get a credential popup that will get the username and password as strings like this:
#Get credentials
$credential = Get-Credential
$username = $credential.Username
$password = $credential.GetNetworkCredential().Password
Then you can use in your script the variables $username and $password
Solution 7 - Powershell
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:\>