Run steps as a different user
Some of our projects live on shared servers, and run under different users for isolation. It would be good to be able to choose which user a nuget deployment/powershell script runs under so we can protect against mistakes/malicious code in our powershell deployment scripts.

-
Anonymous commented
Really upsetting this isn't possible out of the box. Having to make some hacky process to run a scheduled task as another user to be able to launch an application in another context.
-
Michael Christensen commented
We expanded Simon Timms example a bit, handling job status output (failed/succeeded) and streaming output:
# Tentacle can run as LocalSystem
# To run, enable CredSSP and Powershell Remoting
# Enable-PSRemoting
# winrm quickconfig
# Enable-WSManCredSSP -Role server
# Enable-WSManCredSSP -Role client -DelegateComputer "<fully qualified name of machine or *>"$user = "someuser"
$password = "somepassword"
$securepassword = ConvertTo-SecureString $password -asplaintext -force
$credential = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $user,$securepassword
# Parameters are passed to the script via this hashtable.
# The hashtable will be read-only, I have not found a way to return non-output data from the job
[hashtable]$parameters = @{}
$parameters.exitcodeexe = "C:\Temp\exitcode.exe" # some exe setting the exit code
$parameters.outputexe = "C:\Temp\Debug\Output.exe" # some exe running slowly
$job = Invoke-Command localhost -AsJob -Authentication credssp -Credential $credential -ScriptBlock {
$p = $Using:parameters
Write-Output "Executing a s l o w command multiple times to test if output is streamed correctly"
1..4 | ForEach-Object { &$p.outputexe }
Write-Output "Generating exit code..."
&$p.exitcodeexe -1 verbose
Write-Output "Checking exit code"
if ($LastExitCode -ne 0)
{
throw "$($p.exitcodeexe) failed with exit code $LastExitCode"
}
}
Write-Output "Streaming job output..."
# Streaming the output is important, as non-received output is lost when an exception is thrown inside the job
while ($job.HasMoreData -and $job.State -eq "Running") {
Receive-Job -Job $job
}
Write-Output "Job finished"
# Not sure this is actually necessary, but could cover an edge case where $job stops running but .HasMoreData
$job | Wait-Job | Receive-Job -
Michael Christensen commented
After a lot of iterations trying out psexec, Start-Process, Start-Job, C# code (which consistently could not redirect standard output/error properly), we came across this article:
https://blog.simontimms.com/2015/09/02/running-process-as-a-different-user-on-windows/
which outlines a way for running a script block as a different user in Octopus Deploy using remoting to localhost.
This works great - user context is established correctly, and stdout/stderr is recorded by Octopus.
Thank you Simon Timms! -
Ian commented
Please add this feature - I'm not sure how to use Octopus to deploy database changes in an enterprise environment without it. It should prompt for the password. I can't put a user account in a tentacle service (password expiration etc.)
-
Richard Gibson commented
I, too, am pretty crushed that this is not currently possible. We've got some deployment projects that are full of hacks, hardcoded values and contain way more steps than they should all because we can't choose the user that a step runs as.
Our security is pretty locked down and certain things *have* to be run as certain users. So, unless we install literally 50 - 60 tentacles on our servers, we need this feature.
-
Andrew Haigh commented
I would find this very useful, for example when running integration tests which require a different user account to the one used by the Octopus Tentical
-
Anonymous commented
It blows me away that this doesn't exist.
My case is that I need to deploy an application to a custom location, but I do not want all build configurations to have access to the location for security reasons. -
Anders Andersson commented
As I see it, this should have been baked in from the beginning.
Much needed feature for much simpler setup, and onboarding.
-
Blair Paine commented
Would love to see this. We need to execute steps under different accounts in order to take certain actions. It's less secure to give one account rights to everything needed.
-
Taliesin Sisson commented
It is possible to do this, by using scheduled tasks. This is how Vagrant and Packer do it:
$command = @"
`$ErrorActionPreference="Stop"
whoami
Write-host 'hello'
"@function SlurpOutput($out_file, $cur_line) {
if (Test-Path $out_file) {
get-content $out_file | select -skip $cur_line | ForEach {
$cur_line += 1
Write-Host "$_"
}
}
return $cur_line
}function RunAsScheduledTask([String]$username, [String]$password, [String]$encoded_command) {
$task_name = "WinRM_Elevated_Shell_Octopus"
$out_file = "$env:SystemRoot\Temp\WinRM_Elevated_Shell_Otopus.log"if (Test-Path $out_file) {
del $out_file
}$task_xml = @'
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<Principals>
<Principal id="Author">
<UserId>{username}</UserId>
<LogonType>Password</LogonType>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>false</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT2H</ExecutionTimeLimit>
<Priority>4</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>cmd</Command>
<Arguments>{arguments}</Arguments>
</Exec>
</Actions>
</Task>
'@$arguments = "/c powershell.exe -NonInteractive -EncodedCommand $encoded_command > $out_file 2>&1"
$task_xml = $task_xml.Replace("{arguments}", $arguments)
$task_xml = $task_xml.Replace("{username}", $username)
$schedule = New-Object -ComObject "Schedule.Service"
$schedule.Connect()
$task = $schedule.NewTask($null)
$task.XmlText = $task_xml
$folder = $schedule.GetFolder("\")
$folder.RegisterTaskDefinition($task_name, $task, 6, $username, $password, 1, $null) | Out-Null$registered_task = $folder.GetTask("\$task_name")
$registered_task.Run($null) | Out-Null$timeout = 10
$sec = 0
while ( (!($registered_task.state -eq 4)) -and ($sec -lt $timeout) ) {
Start-Sleep -s 1
$sec++
}$cur_line = 0
do {
Start-Sleep -m 100
$cur_line = SlurpOutput $out_file $cur_line
} while (!($registered_task.state -eq 3))$exit_code = $registered_task.LastTaskResult
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($schedule) | Out-Nullreturn $exit_code
}$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand =[Convert]::ToBase64String($bytes)$exitCode = RunAsScheduledTask -username $ServiceBusServiceUsername -password $ServiceBusServicePassword -encoded_command $encodedCommand
exit $exitCode
-
Corneliu commented
This would work very nicely with the new Prompt for Variables from 2.3
http://octopusdeploy.com/blog/2.3
I would mark a step as Run As "user: Administrator" password: empty and then get the prompt for the password.