I am currently logged into my system as administrator, and run power1.ps1 code to call another power2.ps1 script in elevated mode.
$command = "C:\script\Power2.ps1"
Invoke-Expression $command
power2.ps1 includes the block to run the script with admin privileges, but my problem is I that I get a UAC pop-up dialog asking for confirmation where I have to click on Yes.
Code in Power2.ps1
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
$arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}
Write-Host "Admin Privilege Code Here"
Is there any way I can completely automate the process? I will not be able to change the UAC access to disable.
Trying to simulate a user's response to a UAC (User Account Control) dialog shouldn't be done - because it defeats the entire purpose of UAC - and most likely cannot be done (if it could be done, that would be a serious bug exploitable by malware and is certainly not something to rely upon; similarly, while it is possible to disable UAC altogether (which itself requires administrative privileges), doing so is strongly discouraged for security reasons).
However, with limitations you can use a scheduled task to bypass UAC for a given command, by calling that scheduled task on demand:
Create an auxiliary scheduled task that invokes your Power2.ps1 script and is configured to run elevated.
In the Task Scheduler (taskschd.msc) UI that means: Run with highest privilege must be checked (tab General) and also Allow task to be run on demand (tab Settings).
The task must be configured to run in the same user account that it will be on-demand invoked from, and that user account must be a member of the Administrators group.
Use Start-ScheduledTask <task-path> (or schtasks.exe /Run /TN <task-path>) to invoke this task on demand, from the same account that the task is configured for, as noted.
Start-ScheduledTask (as well as schtasks.exe /Run) runs asynchronously, so for synchronous invocation more work is needed - see this article.
Note that using -AsJob to return a job whose completion can be waited for with Wait-Job unfortunately appears not to help (as of Windows PowerShell 5.1 / PowerShell 7.2.1): the job is reported as completed before the task's command has terminated.
Also, the task's command invariably runs in a new console window (if the executable invoked is a console application).
Related
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.
On a Windows 2012 R2 server there is a Powershell script that I can manually invoke to start a process on some EXE, this works just fine.
But when trying to trigger it via a scheduled task (invoking the same script) the start-process within the script just doesn't trigger or finish. Causing the task scheduler to terminate the task due to exceeding the timeout threshold.
Here's the core section of the script:
$exe = "c:\some\app.exe"
$arguments = "-user me -pwd secret"
$process = Start-Process $exe -ArgumentList $arguments -PassThru -Wait
return $process
Is there some way I can get some insights into what start-process is doing or why the same script works when invoked manually but not programmatically?
I want to emphasize that the way the script is invoked from the scheduled task is not a problem! The script triggers because the corresponding log file populates.
Any insights or help on this is greatly appreciated!
quick update on this since I found the problem. It turns out, it had nothing to do with either the powershell script or the scheduled task itself...
On the machine the script is running on, there is a network share that is mapped as the z:\ drive. I use it to save logs to. Now apparently that mapping/mounting is handled differently depending on whether the script is invoked interactively or programatically, because in the latter case it appears that the resoultion of the network path \\network\share\folder1 does not succeed, however there is nothing complaining about it, the process just silently does not start. If however, I point the logs to a physical local path or the explicit full network path itself, there is no problem running the script.
Lesson learned, never trust OS' drive mapping of network paths :D
Cheers
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.
I have this simple script on Windows 10, which works fine when just executing, but fails to start notepad when running from task scheduler. Stop-Process works perfectly, Start-Process does not run. When I run it on demand, it closes the notepad and then keeps running without opening notepad, the task does not close also.
Stop-Process -processname notepad
Start-Process "C:\Windows\system32\notepad.exe"
This is how it is configured to run.
Things I have tried, but still does not work.
First of all, I am running under administrator account.
In task schduler, run with highest privileges is checked.
I have tried -ExecutionPolicy Bypass and -ExecutionPolicy RemoteSigned
Under security policy have given my user Logon as batch job permission
Turn UAC off
The application was ran in background. To make it run on foreground, had to check the box Run only when user is logged on.
How can I run a powershell with -command parameters?
I tried adding '-Verb runAs', but I get a null valued expression.
powershell -Verb runAs -command "(Get-Date (Get-Process explorer).StartTime).ToString('yyyyMMdd')"
I open a powershell with admin right, the command
(Get-Date (Get-Process explorer).StartTime).ToString('yyyyMMdd')
return a right value. But when I start a powershell without admin right, I get a null value.
So I think the problem is the 'powershell -Verb runAs' does not run the command in admin mode.
Note: I logged in as ad administer when I tried this.
So elevating PowerShell's process can be done from within a script if you don't mind running a script instead of just executing a command. This will check if the process is already elevated, and if not it will re-launch the process with the RunAs verb so that it's running with elevated rights.
# Elevate UAC if not already running As Administrator
# 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
# Check to see if we are currently running "as Administrator"
if (!$myWindowsPrincipal.IsInRole($adminRole))
{
# We are not running "as Administrator" - so relaunch as administrator
# Create an encoded string to re-launch the script bypassing execution policy
$Code = ". '$($myInvocation.MyCommand.Definition)'"
$Encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($code))
# Indicate that the process should be elevated
Start-Process PowerShell.exe -Verb RunAs -ArgumentList "-EncodedCommand",$Encoded
# Exit from the current, unelevated, process
exit
}
# End UACElevation
The code is a little convoluted with the encrypting of the command and what not, but I found that I sometimes had issues with execution policy blocking me if I didn't do it this way. This avoids execution policy blocking PowerShell from running scripts, since it technically isn't running a script, just an encoded command. That command just happens to be for it to run a script once the PSSession is started.