0

I have a simple script to create a scheduled task like this:

$action = New-ScheduledTaskAction -Execute "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -Argument '-file "File.ps1"'
$trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -Action $action -Trigger $trigger -TaskPath "Tasks" -TaskName "Name" -Description "Description" -User Admin -Password $password -RunLevel Highest 

how can I prompt for UAC and capture the password that user enters in the UAC prompt as $password variable to be used in the script?

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    You don't. The whole idea of UAC is to prevent 3rd party apps to seize admin rights and stealing credentials. Are you actually trying to run a script as admin? – vonPryz Dec 20 '22 at 19:14
  • I'm trying to exactly run the script I mentioned above, how else should I do that? I need user's password somehow and I don't want to ask for it in the PowerShell console. i.e. I need to pass the `$Password` variable to the script above, without asking for user to type it in PowerShell console or adding it manually to the command. –  Dec 20 '22 at 19:58
  • 2
    It looks like you have fallen into the [XY](https://xyproblem.info/) problem pit. [Edit] the question and explain the root problem you are working with. Now all we see is the solution attempt that is trying to work around UAC, and that's a fool's errand. – vonPryz Dec 20 '22 at 20:16
  • Well that's literally it, lol. I don't know how many times I have to write the same thing. again, I want to run the script above, which at some point requires a password input, and I want to give it the password that it needs, without manually adding it myself or asking user to input it in the PowerShell console. I want to run the script on multiple computers and each have different username and passwords. so what are my options? I thought about using UAC because it's a well established way of authentication but if you know any other means, please do tell. –  Dec 20 '22 at 20:48
  • 1
    Use [`Get-Credential`](https://learn.microsoft.com/powershell/module/microsoft.powershell.security/get-credential) to ask for the credentials to use with UAC. You can extract the plain-text password from the `[pscredential]` object that it returns. – mklement0 Dec 20 '22 at 20:49
  • @mklement0 sorry but which UAC ? –  Dec 20 '22 at 21:04
  • 1
    I misspoke: I should have said: the credentials you would normally use with UAC, which, by definition, are credentials capable of running _with elevation_, which is what your scheduled task requires. – mklement0 Dec 20 '22 at 21:06
  • 1
    @mklement0 I see, thanks, well I can do that, but i'd need a way to verify the password that the user enters in PowerShell console is indeed the correct password that belongs to the Windows account. is it possible to do that comparison? maybe compare the hashes? I think Windows stores password as hashes, maybe in credential manager? I wouldn't want to create tasks with wrong passwords that can never run. if it's too far from the original question, please let me know so I can delete this and make a new one. –  Dec 20 '22 at 21:08

1 Answers1

0
  • Use Get-Credential to ask for the target user's credentials, which returns a [pscredential] instance.

    • You can then call .GetNetworkCredential().Password on it in order to obtain the plain-text representation of the password stored in that [pscredential] object.
    • To be clear, for security reasons this is generally to be avoided; however, Register-ScheduledTask does require passing a plain-text password.
  • Verifying that the credentials are (a) valid in principle (i.e. that the username / password combination is correct) and (b) are capable of running with elevation requires additional work.

    • (a) can be achieved via the Test-WinCredential helper function from this MIT-licensed Gist

      • Assuming you've looked at the linked source code to ensure that it is safe, you can directly download and define it in the current session as follows (instructions on how to make it available in future sessions will print):

         irm https://gist.github.com/mklement0/83e8e6a2b39ecec7b0a14a8e631769ce/raw/Test-WinCredential.ps1 | iex
        
    • (b) can be achieved by checking whether the specified credentials refer to a user in the local Administrators group, using Get-LocalGroupMember. I think that that implies having the permission to run with elevation - do tell me if I'm wrong.

Note:

  • I've only tested the following in a local, non-domain environment.
  • Tweaks may be needed for domain environments
# Prompt for an administrator's credentials and verify that they are valid.
do {
    $cred = Get-Credential -Message 'Please specify an administrator''s credentials: '
    if (-not $cred) { Write-Warning 'Aborted by user request.'; exit 2 }
    if (-not (Test-WinCredential $cred)) {
        Write-Warning "The specified username-password combination isn't valid. Please try again."
    }
    elseif (-not (Get-LocalGroupMember -ErrorAction Ignore Administrators $cred.UserName)) {
        Write-Warning "User $($cred.UserName) is not a member of the local Administrators group. Please try again."
    } else {
        break # OK
    }
} while ($true)

# $cred.UserName now contains the username.
# Obtain the password as plain text.
# Note: This should generally be avoided.
$plainTextPassword = $cred.GetNetworkCredential().Password
mklement0
  • 382,024
  • 64
  • 607
  • 775