I've inserted a PowerShell script to run when user clicks on the utilman (Ease of access) button to perform some default troubleshootings. But I've experienced some errors cause my scripts are not running as full elevated users.
For example, I've created a script that deletes all user profiles from Windows (win32_userprofile), but it returns COMException - Result Code 0x80070522 when I run it with a locked screen, even when I pass admin credentials with Get-Credential method, it returns that error. But when I run that script with an unlocked screen, it works great!
How can I run scripts with full admin rights while the screen is locked?
I've tried to run with external software that gives admin rights too (elevate.exe) which didn't work.
This command will let you run powershell as administrator
start-process PowerShell -verb runas
Replacing "Powershell" by another app will also grant the privileges, just add "" as in the example
start-process "notepad.exe" -verb runas
A prompt should appear asking you if you want to run it as administrator
Let me know if this works for you
I've found out a solution to my problem:
To pass user credentials, you can call "Invoke-Command" cmdlet. Like this:
Invoke-Command -ComputerName $computerName -Credential $credential -Scriptblock{Get-WmiObject Win32_UserProfile | ? LocalPath -notlike *anything* | Remove-WmiObject}
When i did that, everything worked great!
Thanks to Axanor and Anders help. Wish the best to you!
Even if you are a authoritative user and you need to do something that requires extended privileges, I have to run the terminal again by right clicking it as choosing "Run as Administrator" unlike in Linux and other operating systems where we can take help of "su" or "sudo".
My question is : Is there any way to get the same terminal window as a administrator one?
To programmatically start an elevated new PowerShell session (with administrative privileges) on Windows - invariably in a new window - from an existing session, use:
Note:
The command below invariably opens the elevated PowerShell instance in an - invariably new - regular console window (conhost.exe) - see next section for use from Windows Terminal.
Start-Process -Verb RunAs (Get-Process -Id $PID).Path
The above works in both PowerShell editions and uses the same executable that is running the current session; you can take a shortcut if you know the executable name and can assume it to be the first in $env:PATH when invoked by name only; for Windows PowerShell:
Start-Process -Verb RunAs powershell
and for PowerShell (Core) 7+:
Start-Process -Verb RunAs pwsh
See this answer for convenience functions, including for cross-platform use and the ability to pass commands to execute in the elevated session.
To open the elevated session in Windows Terminal (also invariably in a new window):
# As above, 'powershell.exe' or 'pwsh.exe' may do as the argument.
# See below for Windows Terminal profile-related options.
Start-Process -Verb RunAs wt.exe ('"{0}"' -f (Get-Process -Id $PID).Path)
Note:
If the desired PowerShell executable is the your Windows Terminal's default profile, you can omit the argument after wt.exe
# Launch the elevated session with the shell configured as
# the default profile.
Start-Process -Verb RunAs wt.exe
If you want to target a specific Windows Terminal profile, pass its name (or GUID) case-exactly to the -p (--profile) parameter; e.g.:
# Launch the elevated session with the "Windows PowerShell" profile.
Start-Process -Verb RunAs wt.exe '-p "Windows PowerShell"'
I'm not really good at PS so I decided to ask for some advice.
I have a VBA script that uses Get-DhcpServerv4Lease in a PS command to query the DHCP server (as a domain admin user) for a given Scope and arrange the data returned into Excel.
strCommand = "%SystemRoot%\system32\WindowsPowerShell\v1.0\Powershell.exe start-job -credential <domain>\" & TheAdminUser & " -ScriptBlock{Get-DhcpServerv4Lease -ComputerName '<DHCP server>' -ScopeId " & TheScope & "} | wait-job | receive-job"
Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Exec(strCommand)
strOutput = WshShellExec.StdOut.ReadAll
The script was working perfectly before, now for some unknown reason it's no longer functioning.
Tried to manually run the command in PS and realized it is now only working if I run PS as administrator (works even as local admin), else it returns the following error:
[localhost] An error occurred while starting the background process. Error reported: The directory name is invalid.
+ CategoryInfo : OpenError: (localhost:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : -2147467259,PSSessionStateBroken
Any advice what might be the problem or where could I start looking for a solution?
Update:
In the meantime I found a different workaround that fixes the original code I used.
Adding [environment]::CurrentDirectory='C:\Windows\System32\WindowsPowerShell\v1.0'; makes it run again without the error.
strCommand = "%SystemRoot%\system32\WindowsPowerShell\v1.0\Powershell.exe "[environment]::CurrentDirectory='C:\Windows\System32\WindowsPowerShell\v1.0';start-job -credential <domain>\" & TheAdminUser & " -ScriptBlock{Get-DhcpServerv4Lease -ComputerName '<DHCP server>' -ScopeId " & TheScope & "} | wait-job | receive-job"
The answers were very useful, maybe alternative workarounds for others, and got me closer to understand Powershell better.
Any advice what might be the problem
The problem is a bug in the Start-Job cmdlet that affects both Windows PowerShell (v5.1, the latest and final version) and PowerShell (Core) v6+ (albeit with different symptoms, still as of PowerShell Core 7.2.0-preview.8 - see GitHub issue #7172).
In Windows PowerShell, the background process uses a (fixed) working directory in the calling user's home-directory tree (the Documents folder), which the user whose credentials are passed to -Credential is not allowed to access, causing the error you saw - and there's no way to specify a different working directory.
Start-Job -Credential does work if your session is elevated, i.e. running with admin privileges, in which case the target user's Documents folder is switched to. Given that the standard runas.exe utility can invoke commands as a different user even from non-elevated sessions, there should be no need for this requirement, however.
Also - as you have discovered yourself - there is a workaround:
If you explicitly set the process-level working directory (which is distinct from PowerShell's) to one the target user is permitted to access, Start-Job -Credential works; for instance, you can use C:\ or $env:SYSTEMROOT\Windows32 (the latter is what runas.exe uses); a quick example (replace otheruser with the username of interest):
[Environment]::CurrentDirectory = 'C:\' # set process-level working dir.
Start-Job -Credential (Get-Credential otheruser) { whoami } |
Receive-Job -Wait -AutoRemoveJob
PowerShell (Core) now makes the background process inherit the caller's working directory (which the caller could set to a directory accessible by the target user) and also has a -WorkingDirectory parameter, but neither approach solves the problem with -Credential as of PowerShell Core 7.2.0-preview - even if you run with elevation (and the above workaround doesn't help either).
Based on the update to your question, it seems the workaround solved your problem, implying that you do not require the operation running with the domain user identity to be elevated; the following may still be of interest for use cases where elevation is required.
If you need to run the operation that uses a different user identity with elevation (with admin privileges):
Launching an elevated (run as admin) process is something Start-Job -Credential fundamentally cannot provide.
The only (PowerShell-native) way to launch an elevated process is via Start-Process -Verb RunAs.
Note: Using Start-Process means that the launched process' output cannot be captured directly by the caller, and instead requires sending the output to files via the --RedirectStandardOutput and -RedirectStandardError parameters, which the caller - assuming termination of the process is waited for - can later read.
Therefore, try the following:
strCommand = "%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -c Start-Process -Wait -Verb RunAs powershell.exe \""-c Get-DhcpServerv4Lease -ComputerName '<DHCP server>' -ScopeId " & TheScope & "\"""
Note:
Another call to powershell.exe is required, launched with elevation (-Verb RunAs), synchronously (-Wait), which then performs the Get-DhcpServerv4Lease call in the foreground.
Because Start-Process -Verb RunAs invariably launches the process in a new window, you may want to hide that window too, by adding -WindowStyle Hidden to the Start-Process call. Conversely, if you do want to see that window, you may want to hide the intermediate window that launches the elevated one, using VBA features.
Note: I've added -c (-Command) to the powershell.exe calls for conceptual clarity; while this parameter is implied in powershell.exe (Windows PowerShell), in pwsh.exe, the PowerShell (Core) equivalent, the default is now -f (-File).
Also note the need to \-escape the embedded " chars. (escaped for VBA as ""), so that the PowerShell CLI retains them as part of the command to execute after command-line argument parsing.
As with your original attempt, this will prompt for a password, and if the calling user doesn't have administrative privileges in principle, an administrator's username will have to be entered too. Note that this prompt cannot be prevented (unless you turn UAC off, which is ill-advised).
The admin username to use for elevation cannot be passed, because -Verb RunAs is mutually exclusive with -Credential. The logic of -Verb RunAs is such that if the current user is an admin user (in principle), it is invariably used for the elevated session, and you're only presented with a Yes/No confirmation dialog. Thus, if you need a different admin user, such as a domain admin, this won't work - see below. (Only if the calling user is not an admin user does the UAC prompt ask for a username and password explicitly).
If you need to run the elevated session with a given admin user account:
Unfortunately, this requires an even more deeply nested command, with additional pitfalls:
In essence, you need to first call Start-Process -Credential to create an (of necessity) non-elevated session with the target user, which then allows you to call Start-Process -Verb RunAs to create an elevated session for that user.
Caveat: This requires you to answer two prompts: first, you need to enter the password to start the non-elevated session for the admin user, and then you need to answer the Yes/No UAC prompt to confirm the intent to start an elevated session for that user.
A Set-Location C:\ command is incorporated, to ensure that the working directory is valid for the target user (in the initial non-elevated session).
Using Start-Process -Wait in order to wait for termination of a process started with a different user (-Credential) inexplicably fails due lack of permissions when invoked from a non-elevated session; the workaround is to use (Start-Process -PassThru ...).WaitForExit().
To simplify quoting, only '...' quoting (escaped as ''...'' in the nested call) is used - therefore, the commands themselves mustn't contain ' chars.
This leads to the following monstrosity.
' Assumes that the following variables are defined:
' TheAdminUser, TheComputerName, TheScope
strCommand = "%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -c Set-Location C:\; (Start-Process -WindowStyle Hidden -PassThru -Credential " & TheAdminUser & " powershell.exe ' -c Start-Process -Wait -Verb RunAs powershell.exe '' -c Get-DhcpServerv4Lease -ComputerName " & TheComputerName & " -ScopeId " & TheScope & " '' ').WaitForExit()"
Note: For troubleshooting, precede the -c argument(s) with -noexit to keep the PowerShell session(s) open.
Alternative, with prior setup:
As Joel Coehoorn points out, one way to allow a non-admin user to execute a preconfigured operation - only - with administrative privileges is to set up a scheduled task that runs with admin credentials and performs the desired operation, which non-admin users can then invoke on demand.
This would obviate the need for a password altogether, but be sure that the operation is truly safe for non-admin users to perform.
Note: Having a scheduled task run by a non-admin user / from a non-elevated process can fail under certain circumstances - though it does work in the scenario at hand, according to Joel; as he notes in reference to this Server Fault post:
I think part of the problem was trying to run as SYSTEM rather than a specific privileged user in elevated mode. It also talks about contexts like SCCM and startup, where certain registry keys are not available, and the powershell code to invoke the task may also have changed.
You should be able to use Start-Process -RunAs for the powershell.exe command and it will elevate. Note that this will trigger UAC if the vBA process isn't already elevated.
The kicker is that if you are trying to self-elevate from a different process, Start-Process is a PowerShell cmdlet so you will need to basically run PowerShell to run another elevated PowerShell session. The command will look something like this:
powershell.exe -Command "Start-Process -Wait -Verb RunAs powershell.exe '-Command ""YOUR ELEVATED CODE HERE""'"
You can test this with the following command in Command Prompt that will output "hello", wait for a key-press, then exit:
powershell.exe -Command "Start-Process -Wait -Verb RunAs powershell.exe '-Command ""echo hello; cmd /c pause""'"
Note that this is how you would invoke the command from the command line, whether PowerShell or CMD. You may need to tweak the escape sequences if calling from another language.
You should also make use of the -Command parameter when invoking powershell.exe or pwsh from somewhere else and want to exit the session once the command is complete, or the -File parameter for the same but it's a script.
You also need to make use of the -Wait parameter when you call Start-Process or else it won't block. This is antithesis to the general executable invocation pattern that non-GUI programs usually don't need the -Wait parameter to block until the process exits.
I'd like a script to be used in this situation:
gain remote access without admin privileges
remotely start Quick Assist as .\Administrator and not have a UAC dialogue.
Step 1 is usually made with Quick Assist, sometimes made with Teams screen sharing.
I'm aware that I can locate quickassist.exe in File Explorer then use Shift and the context menu to Run as a different user, however I'd like a scripted approach.
Experiment A
This works, but there's a Yes/No UAC dialogue:
$isElevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if ( -not $isElevated ) {
Start-Process powershell.exe -Credential Administrator -NoNewWindow -ArgumentList {
Start-Process quickassist.exe -Verb RunAs ;
} ;
}
Experiment B
I make multiple mistakes, don't know how to correct them. (I'm trying to learn PowerShell, gradually, but I'm easily confused whilst learning; slightly dyslexic.)
$isElevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if ( -not $isElevated ) {
Start-Process powershell.exe -Credential Administrator {
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "PromptOnSecureDesktop" -Value 0 -Force;
};
Write-Host "UAC (user account control) is weakened for a Quick Assist session …" -ForegroundColor Red;
Start-Process powershell.exe -Credential Administrator -NoNewWindow -ArgumentList {Start-Process quickassist.exe -Verb RunAs -Wait};
Write-Host "… Quick Assist session complete …" -ForegroundColor Red;
Start-Process powershell.exe -Credential Administrator {
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "PromptOnSecureDesktop" -Value 1 -Force;
};
Write-Host "… UAC is strengthened." -ForegroundColor Red;
}
the two intended changes to the registry do not occur
the third credential dialogue appears too soon – I want it to not appear until after the end of the Quick Assist session.
Also, conceptually, there's probably no need to run Quick Assist as Administrator whilst UAC is temporarily weakened.
References
https://stackoverflow.com/a/2258134/38108 (2010-02-13) I see use of -Credential with Invoke-Command but when I try to do something similar, for changes to the registry, I make a mess.
https://stackoverflow.com/a/47516161/38108 (2017-11-27) self-elevating PowerShell scripts.
https://superuser.com/a/1524960/84988 (2020-02-12) and https://serverfault.com/a/1003238/91969 (2020-02-15) are interesting – the same script in both answers – however I need something like -Credential Administrator in lieu of -ComputerName.
https://stackoverflow.com/a/60292423/38108 (2020-03-07) via https://stackoverflow.com/a/60263039/38108
PowerShell commands - PowerShell - SS64.com
https://github.com/okieselbach/Intune/blob/master/DisablePromptOnSecureDesktop.ps1 (2020-11-13) via Quick Assist the built-in Remote Control in Windows 10 – Modern IT – Cloud – Workplace
The short answer is don't. Get a real remote management tool or have someone hit the UAC yes prompt.
This is more of a windows thing than powershell, as windows explicitly denies elevating a process locally without going through UAC (and for good reason!). You used to be able to do things like this:
# Use Enter-PSSession to start a "remote" session
# This may still support elevation if you specify CredSSP and configure credential delegation):
New-PSSession MyPCName -Auth CredSSP -cred (get-credential)
# Create a scheduled task with RunAs/elevated permissions:
Register-ScheduledTask -Action $action -User .\Administrator -TaskName "Admin-Stuff" -RunLevel Highest
Which now give fat access denied messages when running locally. You also are not able to edit registry settings within HKLM: without elevation, so disabling uac temporarily is not an option.
You may be able to make use of this exploit that allows admin users to bypass uac, but I think you still have to Run-as-other-user your shell to use it.
I'm writing a small PowerShell script launched from a batch file which will change a Standard User (when logged in) to a Local Administrator. It needs to be fully automated, and I know the given machine's Admin credentials. I figured that I would begin by passing the Admin credentials, but I'm having trouble getting around the Password prompt (since it requires user action). So far I have this.
Start-Process powershell.exe -Credential "Domain\Username" -NoNewWindow -ArgumentList "Start-Process powershell.exe -Verb runAs"
$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate('Windows PowerShell Credential Request')
Sleep 1
$wshell.SendKeys('SuperSecret')
Sendkeys isn't working as far as I can tell, and neither does -Password when I try to pass it as an argument. I'm not sure if I should pursue this method or if there is other logic that will let me assume a Local Administrator without being prompted to begin with. Also, this will be run on more than one machine, however the credentials are constant since they will all be on the same network.