Powershell self-elevate loop - powershell

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.

Related

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 force session level execution policy without prompt in PowerShell?

I use the following code to rerun a script with admin privilege if necessary.
# Require admin
if(!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
exit
}
However, on some systems, when I right click the script and choose run with powershell, it will prompt me for something like yes, no, all, cancel... etc. I don't know exactly when this will happen. How can I force the execution policy change without the prompt aforementioned? I checked the document and it seems there is no -force parameter for powershell. There is a -force parameter for the cmdlet set-executionpolicy though.
The reason "why" sometimes get the prompt is because the account on some "systems" is already running it as Administrator(The elevation have already happened before at login or being disabled by GPO).
However, if you are running this on a remote machine, you will not need to elevate permissions if you already have admin rights to that machine, but running it from the current session would need the elevation unless the user is already signed as admin.
Check the documentation from Microsoft on How User Account Control works
https://learn.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works
On the other hand, I think there might be a better method for your usecase.

Trying to run "reg import C:\myRegKey.reg" as an admin within a script that runs as a standard user

I am working on a PowerShell script that sets up a user's profile after their Windows Profile has been created. The script performs various functions such as pinning items to the task bar, enabling offline files for the user's personal network drive, etc. I would like to include a reg import for MS Edge that forces the Favorites Bar to be enabled in order for Edge to feel more like IE once favorites have been transferred to the user's machine. I have the reg key created, but I need to apply admin rights to import the reg key.
I would prefer to not grant every user temp admin rights when their machine is built, and I would prefer to not have to manually enter credentials every time I run the script.
I was able to successfully pass my credentials to a PSCredential object, and I was able to run other cmdlets with said credentials. I am simply struggling to pass these credentials to a reg import.
Currently, I have two scripts. The main one that performs the tasks under the user profile, and the secondary one that prompts for admin rights and then performs the reg import. The main script currently calls the second script, which prompts for admin rights and imports the reg key.
Below is the portion of the main script that calls script number 2 to perform the admin task:
$Script = "\\NetworkDrive\Enable_Edge_Favorites_Bar.ps1"
&$Script
Script 2 is below:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit }
reg import "\\NetworkDrive\Edge_Favorites_Bar.reg"
While this is functional, I am looking for a way to do this where I do not need to enter a username and password each time. Ideally in a single script, but if someone has a solution that requires multiple scripts, I am willing to work with that as well!
I have tried:
Invoke-Command -Credential $cred -ComputerName $env:COMPUTERNAME -FilePath $Script
as well, but when I do, I receive an access denied error. So it seems that we do not have remote management turned on or at the very least I do not have access to perform remote registry edits.
I feel like I am most certainly just missing something stupid, so any assistance that someone can provide would be greatly appreciated.
Thanks!

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.

Using powershell script to kill process but access deined

I need using powershell script to kill a process, however access denied. How can I get admin with powershell script? In addition, I do not want to input Admin account and password manually. The Get-Admin process needs to be done automatically. What am I suppose to do?
You would need to elivate your script, or console prompt, to use the "run as administrator" option. A good example script can be found here on how you might do this in your script.
The meat of the script provided in the link just takes the user running the script and verify if the current session is elavated. If it is not you have to open one up as that in order to kill a process. You would also deal with UAC if you are on Windows, that if the user running it does not have local admin rights you will be prompted to enter credentials.
Snippet of the code that verifies if the execution account is admin:
# Get the ID and security principal of the current user account
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
# Get the security principal for the Administrator role
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
$myWindowsPrincipal.IsInRole($adminRole)
You can find a few other options to get elevated permissions here.
Just do
start-process pwsh -Verb RunAs
or
start-process powershell -Verb RunAs
to get yourself an elevated shell. Then run the command you want