13

This is something incredibly simple, but I just can't get anything to work. I want to run a block code in a powershell script under a specific user. The keyword is locally and I'm using powershell 2.0.

Invoke-Command seems to require a remote host? I run the following and the error message that I see seems to suggest as much:

$strScriptUser = "DOMAIN\USER"
$strPass = "PASSWERD"
$PSS = ConvertTo-SecureString $strPass -AsPlainText -Force
$cred = new-object system.management.automation.PSCredential $strScriptUser,$PSS
Invoke-Command -ComputerName "." -scriptblock {
write-output "HI!"
} -Credential $cred

Start-Job with -ScriptBlock isn't supported with powershell 2.0? I run the following and the error message that I see seems to suggest as much:

$strScriptUser = "DOMAIN\USER"
$strPass = "PASSWERD"
$PSS = ConvertTo-SecureString $strPass -AsPlainText -Force
$cred = new-object system.management.automation.PSCredential $strScriptUser,$PSS
Start-Job -ScriptBlock {
write-output "HI!"
} -Credential $cred

Am I doing something wrong, or is there an alternative way?

Added: Here is what I'm trying to do in the first place. I'm making a scheduled task that runs when a user logs into/unlocks a terminal that writes logon information to a file. The scheduled task runs as the local user in order to get at the username, profile, etc. information. The logon information is then written to a log file using a different user account, which is the only account that can modify the file. To deter access to the logon credentials in the script I convert the script to an EXE using PS2EXE.

wrieedx
  • 254
  • 1
  • 3
  • 14
  • 1
    See here: http://matthewyarlett.blogspot.be/2014/04/powershell-runas.html The trick is to go through a PSSession – David Brabant Sep 01 '14 at 08:38
  • It may be hard to help if the only person that sees error messages is you... ;) – BartekB Sep 01 '14 at 18:30
  • The error messages aren't in English, so I will do my best to translate. For Invoke-Command: 「Failed to connect to remote server [localhost]. The client could not connect to the specified destination. Please confirm that the destination service is running and is in a state that can receive requests.」 – wrieedx Sep 01 '14 at 23:43
  • 1
    The `Start-Job` solution worked for me in PowerShell 3.0. (Of course, you have to call `Wait-Job | Receive-Job` to actually get the results.) – JamesQMurphy Mar 31 '16 at 17:37

3 Answers3

9

Here is another way.

# Get the other user's credentials
$credential = Get-Credential

# Execute a scriptblock as another user
$commands = @'
    $env:username
    # ... more commands ...
'@
Start-Process -FilePath Powershell -LoadUserProfile -Credential $credential -ArgumentList '-Command', $commands

# Execute a file as another user 
$script = '.\path\name.ps1'
Start-Process -FilePath Powershell -LoadUserProfile -Credential $credential -ArgumentList '-File', $script

With the -LoadUserProfile switch, this has the added benefit of creating the user's profile if it does not already exist.

Nathan Hartley
  • 4,005
  • 2
  • 43
  • 46
3

Another approach is impersonation, it is good option if you are not willing to enable remoting.

Check this and this out.

You should just put your code between

Push-ImpersonationContext $credential

and

Pop-ImpersonationContext

olegk
  • 765
  • 4
  • 13
  • 6
    Your link is dead – Steztric Jul 05 '17 at 13:48
  • 1
    Wayback machine archived version of article: https://web.archive.org/web/20170410101407/poshcode.org/1867 – stalskal Jan 08 '19 at 05:49
  • 1
    Thanks for this pointer, two additions - better to take the latest from this repository https://github.com/claudiospizzi/SecurityFever and if you run the script as Administrator and want to impersonate another user but have your script continue running as Administrator - use Push-ImpersonationContext $Credential -LogonType Batch – Avi Pinto Aug 25 '20 at 10:00
  • One thing to be aware of with this approach: if your code results in a new process being started (e.g. with `Start-Process`), then that process will run under the original context, not the impersonated one. – Dan Nolan Feb 08 '21 at 04:40
1

It would help to see the error messages you're not showing us, but I think the answer to your question is to use PowerShell Remoting as you tried with Invoke-Command. The computer name . is fine as is localhost but you do have to have remoting enabled on your machine to do it.

To enable remoting, run Enable-PSRemoting within powershell, or run winrm quickconfig in a regular command prompt.

If you already have remoting enabled, then you might be trying to do the remoting with a non-administrative user. If that's the case, take a look at the output of Get-PSSessionConfiguration. You'll get a list of endpoints and the permissions that are applied.

The endpoint you're connecting to by default is called Microsoft.Powershell and you could change the permissions with Set-PSSessionConfiguration (be sure to use the -ShowSecurityDescriptorUI parameter unless you want to mess with SDDL).

But instead of doing that, there should already be a group given access called BUILTIN\Remote Management Users which you can add your limited user to.

If none of this helps, give more details and error messages.

Edit

After seeing the explanation of what you're ultimately trying to accomplish, I have another suggestion for you.

  1. Your existing scheduled task writes the information to a known location.
  2. A different scheduled task running under the privileged user account picks up that information and puts it into the file that the limited user cannot access.
  3. Bonus: start the second task from the first task.

This could be a quick compromise to do what you want without remoting and without exposing the credentials of the privileged user.

Issues with the current approach:

The major problem I have with your original idea is that you're going to need to embed the credentials into the script, so the limited user will have access to the credentials of the account that can modify the file anyway.

Ideally:

You would have a web service that you could invoke with your limited-user powershell script in which you can only give it the login information and not get anything back. So you'd hit a URL and do a POST or whatever with the data that you want to log, but that user can't ever retrieve any info. It might be a bit beyond what you're willing to do for this.

briantist
  • 45,546
  • 6
  • 82
  • 127
  • PSRemoting is not enabled, and the user in question is not an admin. It seems that this is more complicated than I imagined, so I think that I had better try to explain what I am trying to accomplish in the first place. (Details added to original question). So what you are saying is that what I need to do is enable PSRemoting (eventually for all clients) and add the user that runs the command block to BUILTIN\Remote Management Users? I don't see this BUILTIN group in my domain. – wrieedx Sep 02 '14 at 00:25
  • Ah, yes. About the user seeing the credentials, I was going to use PS2EXE to turn the script into an EXE file. I probably should have mentioned that too. A really clever person could probably extract the logon information from the EXE, but I don't think that anybody where I work is capable of doing that. Anyhow, both of your suggestions sound very promising and have their own respective merits. I'll try testing them out... – wrieedx Sep 02 '14 at 01:02
  • It took me a while, but I was able to get the above answer working. I created 3 tasks, one triggered via user logon, one triggered via screensaver unlock, and a 'helper' task that writes the actual logon information to a file. Hiding the black command box that appears when a powershell script is executed was a challenge, as well as figuring out how to sign the powershell scripts and deploy the certificates via the domain. Also, there were permissions issues when trying to allow a normal user run a non-scheduled windows task. It wasn't fun, and it took way too much time, but I got it to work! – wrieedx Oct 06 '14 at 06:56
  • For the record, I was able to get Start-Job with -ScriptBlock working and then use PS2EXE to convert the powershell script to an exe. But the problem was that I couldn't get the black command box to not pop up each time the exe was run. – wrieedx Oct 06 '14 at 06:59