How can I make PowerShell run a program as a standard user? - powershell

Alright, so, I've been searching online forever, and I can't find anything on this at all.
Basically, what I want to do is run a program from an elevated PowerShell script, but I want the program to run as the standard user.
I need to do this because the program that I need to run requires access to a mapped network drive that the domain administrator accounts don't have access to. So, I basically need a line of code that will take the script out of elevated mode, or some extension to the Start-Program command that will make it run as the logged on user rather than the administrator account that the script is running from.

you could use psexec
psexec -l powershell.exe -executionpolicy unrestricted -noexit -file c:\temp\checkelevated.ps1
-l : Run process as limited user (strips the Administrators group and allows only privileges assigned to the Users group). On Windows Vista
the process runs with Low Integrity.

One way that I have used extensively in the past is to create a scheduled task on the fly specifying the currently logged user as the account that will run the task. The task would run some other script, command, etc. and it would occur in the context of the logged on user. This is possible by using Start-Process to call the schtasks.exe program that will...
Create the task (schtasks /create /tn "MyTask" /tr "powershell -file...." /ru "domain\username")
Run the task (schtasks /run /tn "MyTask")
Delete the task (schtasks /delete /tn "MyTask")
You would just need your script to get the current user, which can be done in a number of different ways. I've also put a 2 second pause in between those calls to schtasks just to ensure they all run.

There are more ways to do it (probably some even better) I guess, but this should also work.
If you need to run an executable or script under currently logged in user from an elevated environemnt, you can use RunAs with USERNAME environment variable passed as user argument:
runas /user:%USERNAME% program.exe
USERNAME environment variable should contain currently logged in user even in an elevated environment.

The generally intended and accepted way to do this is to specify the network UNC path instead of the network drive. You can even re-map the drive in the elevated process if you need it. That's how you're supposed to do it. If you have an account running a process that needs access to a network location, the proper answer is to grant that account the access it needs to do it's job.
However....
Does this or this or this describe the problem you're actually having? It's very unclear what you're trying to do. You've eliminated all context from your question.
If you're trying to run a script that needs to run elevated and needs to access the user's network drive and you can't use a UNC path for whatever reason, then the above three links are what you probably want.
If you really, truly need to impersonate a logged on user -- and I really struggle to think of a situation where I'd need to do this from a script -- then read on.
The alternatives that don't require knowledge of user credentials are:
Use a user logon script instead of a computer startup script. If necessary, grant the local user the permissions they need to run the rest of the script. I can't imagine you haven't thought of this already.
Create a scheduled task which runs as "Domain Users" or some other group that represents the users in question and the "Only run when logged on" is checked. Again, you'd need to grant the user the permissions they need to run the rest of the script, but it wouldn't tie you down to logon only.
Write a program which calls ImpersonateLoggedOnUser, which requires SeImpersonatePrivilege (Administrators have this by default, IIRC). These are native Win32 calls, not .Net, so they will not be straightforward to use in PowerShell. It's been about a decade since I've looked at this, and it used to be a huge pain because it would sometimes still prompt for credentials. I have to think that the increased security in Vista and later (UAC, et al) would have made this even worse. I also have no idea if you have access to mapped drives (i.e., if the impersonation survives network hops). I would choose this method approximately never.
For anything else, I think you will require credentials of the current user. What you'd be doing is credential hijacking, and OS security is specifically designed not to allow that.

Related

Powershell self-elevate loop

I'm one of the IT admins in our company. Lately, cyber-security want to get stricter on how easily users can read and/or write data on USB sticks and external mass storage. In addition all new users getting new Windows notebooks will only have "non admin" permissions. All requests to install software etc must come through the IT desk.
An Active Directory OU has been created and some test notebooks have been assigned to it. My boss would like to me to write and test some Powershell scripts that would allow my colleagues and I (in a screen-sharing session with the user) to temporarily delete the registry keys that control USB storage access (until the next group policy update comes along). The hard part has already been taken care of. The intention is that script will be stored as a Nal-Object on ZenWorks, so the user would not be able to see the source code (kinda similar to an exe file that is just double-clicked on).
The code that is causing hassle...
# self-elevate to admin user - code at the very top of the PS file..
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Start-Process PowerShell -Verb RunAs "-NoProfile -ExecutionPolicy Bypass -Command `"cd '$pwd'; & '$PSCommandPath';`"";
exit;}
# all the main code follows..
Here, if I run the script (in an non-admin account) I am prompted by UAC to enter the name and password of a local (or domain) admin account, a new window/session in PS opens and I can run whatever main commands need running.
The problem however is that is that when prompted for credentials and then type the correct password for a local non-admin account (as some users are inevitably going to do!) a new empty PS window/session just keeps opening indefinitely in a periodic fashion.
I've also tried adding an 'else clause' to the if-statement (to show an alert to the user and/or force quit Powershell, but it never seems to be get executed).
When I test this on a computer is that non part of any domain etc, I just get a "user is not authorised" kind of alert in UAC and no error gets the chance to propagate.
Is there any kind of workaround for this? It would be great too if the UAC prompt just defaulted to the name "ROOT\install". Nobody knows that password to this account except for IT admins.
I've also run Get-ExecutionPolicy -List... MachinePolicy and LocalMachine are "RemoteSigned", everything else is "Undefined".
I don't think execution policy plays a role in this strange loop, but I am open to being wrong. The script I am testing has not been through any signing procedures etc and is just sitting locally on the Desktop of one of the test computers.
Thanks.
Your symptom is mysterious; it implies the following:
The UAC prompt triggered by Start-Process -Verb RunAs mistakenly accepts a NON-admin user's credentials.
On re-entry into the script, the test for whether the session is elevated (!([Security.Principal.WindowsPrincipal] ...) then fails, and Start-Process -Verb RunAs is run again, at which point no UAC prompt is shown, because Start-Process does think the session is elevated and instantly spawns a new window.
The result is an infinite loop of new windows getting opened.
I have no idea what would cause this discrepancy - do tell us if you ever find out.
As workaround, you can try the following approach:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
$passThruArgs = "-NoProfile -ExecutionPolicy Bypass -NoExit -Command `"cd \`"$pwd\`"; & \`"$PSCommandPath\`""
if ([Environment]::CommandLine -match [regex]::Escape($passThruArgs)) {
throw "You entered non-admin credentials. Please try again with admin credentials."
}
Start-Process -Verb RunAs PowerShell $passThruArgs
exit
}
# all the main code follows..
'Now running elevated...'
That is, the on re-entry the process command line is examined for containing the same arguments that were passed on elevated re-invocation. If so, the implication is that even though the UAC prompt accepted the credentials, the new session still isn't elevated, and an error is thrown.
Note that I've added -NoExit to the re-invocation, so that the new window stays open, which allows the results to be examined.

Powershell $env:username different outputs

I have a Powershell script that relies on the $env:username variable to distinguish file paths. However on several occasions (my script has to be run as admin) it picks up the Powershell Run As user rather than the logged on user.
Has anyone experienced this before or know a workaround. The bizarre thing is it seems to vary from machine to machine.
My script needs admin as it needs to delete files with sys permissions etc.
Thanks
$env:USERNAME reflects the user identity of the current process.
Therefore, whether this value matches that of the user that logged on to the current OS session (window station) in an elevated (Run as adminstrator) process depends on what identity was used to launch it.
If a different account had to be used - in case the the logged-on user doesn't have permission to elevate him- or herself - $env:USERNAME will therefore differ from the logged-on user's username.
You can use the following command to get the logged-on user's username, irrespective of what account was used to start the calling PowerShell session:
(Get-CimInstance Win32_ComputerSystem).UserName

Allow Win 10 user to reset network adaptor via PS script without UAC

Firstly: I have found a number of questions answered that do everything but allow me to bypass UAC. I am IT for a small business, but it is not my primary responsibility.
I have two machines in my domain that on startup often fail to correctly connect to the domain network. Restarting the network adapter fixes the issue until the machine restarts. Unfortunately, one of the machines is used by a non-admin, and a technically illiterate one at that.
I hoped to use a powershell script to do this. Using this website, I created script and batch files to solve the issue. Since the computer only has one network adaptor, I went simple:
internet.ps1
Get-NetAdapter | Restart-NetAdapter
internet.cmd
#ECHO OFF
SET ThisScriptsDirectory=%~dp0
SET PowerShellScriptPath=%ThisScriptsDirectory%internet.ps1
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%PowerShellScriptPath%""' -Verb RunAs}";
Unfortunately, I don't fully understand the last command in the batch file. As such I struggle to research the command to pass some form of user credential. This environment is not very secure. But I don't want to give this user domain admin permissions generally, or provide them with some admin credentials which would end up on a sticky note. Either option is just inviting trouble from my older, technically illiterate colleagues. And going over to punch in credentials every day is time consuming.
I am looking for a script that cycles the network adaptor and provides the necessary credentials to make that change so a non-admin user can fix their domain and internet access without having admin credentials on a post-it note.
You could schedule a task using the Task Scheduler in Windows. When scheduling a task, you can specify credentials for the task to use when it runs. You can add a trigger for this task to have it run when the computer starts, or you can simply allow the user to manually start it.
If you decide to go this route, there is a check box you can check that runs the program with the highest possible privileges. The entire point of that last line is to start a new PowerShell window that runs as administrator so it actually has permission to restart the adapter. This means that you can get rid of almost your entire script, and just keep the part that actually restarts the adapter.
For example, when you go to create a new task in Task Scheduler, under the Actions tab, you can create a new action and enter the following:
Program/script:
PowerShell
Add arguments:
-Command "Get-NetAdapter | Restart-NetAdapter"
Note: I'm not sure if this is still the case, but in my past experience, sometimes it will try to run before Windows is fully loaded. If it doesn't seem to be doing anything on startup, you may need to add a delay to it. You can do this by running the Start-Sleep command. You can add it to the arguments field by doing the following:
-Command "Start-Sleep 5; Get-NetAdapter | Restart-NetAdapter"
Replace the number 5 with how many seconds you would like it to wait.

How to avoid UAC prompt while running powershell script

I am running powershell script through jenkins. It has one cmdlets which require elevated permission. so i am writing those cmdlet as below
start-process powershell.exe -verb runas -argumentlist "net localgroups administrators domain\user /add"
But this prompts a UAC where i have to manual click yes. then its moves further.
I want to elevate the cmdlet without giving UAC prompt and continue to go ahead....
The account used to run the script has admin permission on that machine.
Besides disabling UAC - which obviously should be the last resort - you may achieve your goal with creating a 'scheduled' task which is set up to run elevated and trigger that task from Jenkins.
The difficulty here will be probably about how to pass information to and retrieve information from the task - maybe you can achieve that via some files of well-known paths.
See here for how to set up such a task and here for how to trigger it.
As I do not have any Jenkins installation right now I could not test it though - sry.
The problem is the switich:
-verb runas
That instructs Windows that you need your code to run as an Administrator.
Remove that, and Windows will stop prompting the user for administrator privileges.
Your next question might be:
But i want a standard user to be able to do things that require administrative privileges.
Sorry, that is not allowed on secure operating systems.
if I'm a standard user
I simply can't just decide to be an administrator
I actually have to be granted those rights.
The 8 year old, or the corporate desktop user, can't just become an administrator because they wrote:
start-process explorer.exe -verb runas
They will need me, or someone from IT, to walk the 6 buildings over to type in my admin credentials - because i actually do have Administrator privileges.
Imagine Life Before UAC
Every developer complaining about UAC, who hates UAC, wants to go back to before UAC. Lets imagine that.
It's 2002, you're running Windows XP SP3
There's no UAC, so you're always a standard user
And you want to run some code as an Administrator.
You can't do that; you're a standard user.
The only solution is to:
Fast User Switch
and get an Administrator to login to the machine
have them run your script
they then logout
and you fast-user-switch back to your own account
UAC is much better; since they can just type their credentials into the UAC dialog:
But I Just Don't Want A UAC Prompt
You might be saying:
I don't care about any of that. I just don't want the UAC prompts. I want it to work like it did in Windows XP
If you don't want the UAC prompts, and you want it to behave like it did in Windows XP: then you absolutely can do that. You are perfectly free to turn off UAC.
Standard users will always be standard users, with no way to elevate
Administrators will always be administrative users, with no need to elevate
And that is your preference, and you can do that.
Many other users don't want to do their day-to-day work as an Administrator. But since you're only running your script on your computer: it's fine.

Run specific commands in PowerShell under different credentials?

I am trying to run a specific command line function in my PowerShell script. The catch is the command needs elevated permissions to be able to execute.
Here is a condensed example:
# PowerShell code...
query session /server:"SERVERNAME" #NEEDS ELEVATED PERMISSIONS
# More PowerShell code
The query command needs to be run under elevated permissions.
I have tried the following:
Invoke-Command -ScriptBlock {
query session /server:"SERVERNAME"
} -Credential get-credential
But this doesn't work because the -ComputerName parameter needs to be present when using a -Credential parameter. I want to be able to run this without using a remote server.
I know I can get around it by having the users start up PowerShell under their elevated account credentials, but I'd rather just prompt for credentials while the script runs and just run that single command under their administrator account credentials. Everything else the script does is fine under normal credentials.
There are some add-ins for PowerShell, but I actually found the simplest way was to:
Sysinternals in regular command line
With the PSexec process, you can pass IP address, usermame, and password
Fiddle with it to a point you're happy
Create a batch file to then run from PowerShell if that is the desired deploy to environment
When creating the method, have it consume parameters if you want the call out to be dynamic and consume different usernames/passwords/IP addresses to log into
If the exec will always run on "computerA" using "loginA" and "pwA" then there is obviously no need to parameterize
*Sysinternals cannot be used to outright hack a terminal. The user of a remote exec must first have the same Sysinternals tools installed to the system that is to accept remote executables, that tool must be opened once and given GUI-based approval to allow run on said system must be physically addressed.
Note: Any remote PSexec's using credentials will execute with the same level of permissions that the provided username/password is granted on that system.
Here is the link: (PsExec v2.2). Although I recommend going a level or two up and downloading the entire toolbox.