What permissions are needed for Register-ScheduledTask? - windows

I have a PowerShell script that runs under its own user account for security purposes. It needs to be able to schedule tasks as part of its operation, and uses the ScheduledTasks module to do so. After seeing this question, I granted the script's account Full Control over %SystemRoot%\System32\Tasks, but Register-ScheduledTask still fails with "Access is denied." I have allowed the script's account to log on as a batch job and as a service.
What permissions/configuration changes are needed to make this work right?

I've discovered that the problem was due to me specifying -RunLevel Highest. Apparently you can't do that with a restricted account. Removing that parameter allows it to work.

Related

How to download a file using BITS in a Packer provisioner?

I'm writing a provisioning script in PowerShell for a Packer-built Windows image on a CI pipeline. This process involves downloading several large files. I'm under the impression that BITS is faster than Invoke-WebRequest, so I've decided to use BITS to asynchronously download these large files.
The problem is that BITS will only process jobs for users that are interactively logged on...
BITS transfers files only when the job's owner is logged on to the computer (the user must have logged on interactively). BITS does not support the RunAs command.
...unless the job was submitted by a service account.
You can use BITS to transfer files from a service. The service must use the LocalSystem, LocalService, or NetworkService system account. These accounts are always logged on; therefore, jobs submitted by a service using these accounts always run.
But even then, there's a wrinkle:
If a service running under a system account impersonates the user before calling BITS, BITS responds as it would for any user account (for example, the user needs to be logged on to the computer for the transfer to occur).
This is an issue because the provisioning script runs as the Administrator account, which is not a service account and therefore must be logged in interactively to use BITS. This happens to be Packer's behavior, so I can't change this. I'm wrong, I can change this. See my final answer. How can I do the following in one PowerShell script?
Submit a BITS job as Administrator using a service account's credentials. I assume I need to pass something in to Start-BitsTransfer's -Credential parameter?
Store the BITS job in a local variable (jobs will be started at different places in the script)
Await the completion of the BITS job so I can start using the file I downloaded (jobs will be awaited at different places in the script)
You could use psexec to run a secondary script with SYSTEM rights by the administrator content and have the primary script identify the exit code of the psexec process to confirm it has successfully executed.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-7.1
https://learn.microsoft.com/en-us/sysinternals/downloads/psexec#:~:text=PsExec%20is%20a%20light-weight,to%20manually%20install%20client%20software.
https://weblogs.asp.net/soever/returning-an-exit-code-from-a-powershell-script
It turns out there's a solution to this, although it's specific to Packer. I didn't mention much about my use of it because I didn't think it was that important.
Contrary to my initial belief, Packer's PowerShell provisioner lets you run the provisioning script with elevated privileges as any user...
elevated_user and elevated_password (string) - If specified, the PowerShell script will be run with elevated privileges using the given Windows user.
provisioner "powershell" {
elevated_user = "Administrator"
elevated_password = build.Password
}
...including service users.
If you specify an empty elevated_password value then the PowerShell script is run as a service account. For example:
provisioner "powershell" {
elevated_user = "SYSTEM"
elevated_password = ""
}
After adjusting my Packer template's provisioner block accordingly, I can now confirm that Start-BitsTransfer and friends work as expected. No need to pass complicated arguments or play tricks with sessions.

How to run a VB6 app from a scheduled task without users being able to run it

We have a legacy VB6 application that automatically emails reports. It runs from a scheduled task on a server. Occasionally a user will run the exe - it's in a folder that we can't lock them out of, and it has to remain in that folder for reasons too complicated to go into here. Is there a way to prevent users from running the exe while still letting it run from the scheduled task? I can modify the source code for the exe, so that's an option if someone can help me figure out how.
I'm going to call your existing app AppChild and a new VB6 (or other program language) program AppParent.
Modify AppChild to test for a command line parameter at either Sub Main() or at the first form loaded in the Form_Load() event. If the command line parameter isn't there, AppChild terminates.
AppParent would be in a location not accessible to the other users. The Scheduled task runs AppParent which runs AppChild and passes the required command line parameter. This could be secured somewhat by passing a calculated hash and decoding it in AppChild if needed.
Or, if the users don't have access to the Scheduled Tasks, you could just run AppChild , passing the required parameter from the Scheduled Task. If the users do have access to the Scheduled Task this won't work because they could then see the passed parameter and create a shortcut which passes the required parameter.
You didn't state which OS the server is running but you may have problems using network resources if you try to run the Scheduled Task without a logged in user. Task Manager got a major update to handle security issues to prevent hackers from running tasks without a logged in user. Essentailly, network resources, .e.g. eMail, are not available unless a user is logged in.
https://technet.microsoft.com/en-us/library/cc722152(v=ws.11).aspx
The only way I found around that problem is to run a machine with a user with the correct permissions logged in all the time.
Are you sure you cannot lock the user out?
You could restrict access to the folder so that the user cannot access it and set up the scheduled task to use an account with access to the folder.
Although the users can't be locked out of the folder (perhaps the reports end up in there?), in Windows you can set the permissions on a per file basis. Make a new user that has the full rights (the same as your users). Schedule the VB6 app to run with that user. Remove the rights for the regular users to see the app. You do this by changing the permissions on just the VB6 app.

CreateProcessAsUser() gives "A required privilege is not held by the client" Which one?

Using System.Diagnostic.Process.Start() from IIS Express running in my interactive session, I can execute a program running as a different user with correction functionality. Unfortunately, it seems that this doesn't work from non-interactive sessions.
Process.Start internally calls CreateProcessWithLogonW(CPLW) when
credentials are specified. CreateProcessWithLogonW cannot be called
from a Windows Service Environment (such as an IIS WCF service). It
can only be called from an Interactive Process (an application
launched by a user who logged on via CTRL-ALT-DELETE).
-- from this SO answer
I need to publish this site to IIS 8 from the app pool account. So I CreateProcessAsUser as suggested by the above-quoted answer. I've set the service account and agent account with Local Security Policies and restarted as suggested in that answer - service account can replace token, modify quotas and agent account can logon as batch (and as service for that test). But I can't get it to work in IIS Express (or a console test app) nor IIS 8. I've tried running as LOGON32_LOGON_BATCH, LOGON32_LOGON_NETWORK_CLEARTEXT, and LOGON32_LOGON_SERVICE, and even LOGON32_LOGON_INTERACTIVE. I've even given my own account "logon as service" and "act as part of the operating system" privilege with no change - all tested after a reboot.
I'm getting "A required privilege is not held by the client" from IIS Express for all configurations. On the server, I get the same running the console app. But publishing the app, it seems to start the process just fine, but then I seem to be getting permissions errors subsequently.
I'd like to know WHICH privilege my accounts are missing when running locally so I can debug them properly (and eventually figure out whatever permissions error I'm getting). Is there any way to determine that? Either way, if you know what the issue is, I'd like that too!
Thanks!
Per the documentation:
CreateProcessAsUser function
Typically, the process that calls the CreateProcessAsUser function must have the SE_INCREASE_QUOTA_NAME privilege and may require the SE_ASSIGNPRIMARYTOKEN_NAME privilege if the token is not assignable. If this function fails with ERROR_PRIVILEGE_NOT_HELD (1314), use the CreateProcessWithLogonW function instead. CreateProcessWithLogonW requires no special privileges, but the specified user account must be allowed to log on interactively. Generally, it is best to use CreateProcessWithLogonW to create a process with alternate credentials.
...
If hToken is a restricted version of the caller's primary token, the SE_ASSIGNPRIMARYTOKEN_NAME privilege is not required. If the necessary privileges are not already enabled, CreateProcessAsUser enables them for the duration of the call.
The calling thread can use OpenThreadToken() and AdjustTokenPrivileges() to enable individual privileges as needed before calling CreateProcessAsUser(). But since it does that internally anyway, that implies the user associated with the calling thread does not have those privileges available to begin with.

How can I have better priviledges management in Azure roles?

AFAIK when I set up my Azure roles I have only one way to specify how much priviledges the process running role code will have - by using <Runtime executionContext> XML tag.
However this looks coarse grained. If I specify "elevated" my code runs under "Local system" which is unlimited priviledges and if I specify "limited" my code runs under some low priviledges user that doesn't have priviledges my code needs.
Is there some convenient way to run Azure role code under some custom user that has limited priviledges that I myself would control?
Right now, your code will already run as a limited user. In fact, there are no users on the VM - it is using a SID injection technique to get a security context at all. From your question, it seems like you need more than a normal user, but less than an admin?
If you really want to have different permissions, you need to create some users (use Startup tasks and net add or DirectoryServices) and set permissions. All of this is scriptable.
The more challenging part comes now to run your code as that user. For this, you need to do what is called impersonation. Your more privileged code (an admin process typically) can obtain a token for a local user and use that to impersonate a user. The code then runs as the user and is restricted. Impersonation is a well covered topic in .NET and other languages.
If you want a clever example of running code as another user, check this post by David Aiken:
http://www.davidaiken.com/2011/01/19/running-azure-startup-tasks-as-a-real-user/

GetProcessesByName() and Windows Server 2003 scheduled task

Does anybody know what user privileges are needed for the following code needs to successfully execute as a scheduled task on Windows Server 2003:
System.Diagnostics.Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName)
When NOT running as scheduled task i.e. under a logged in user, as long as the user is a member of "Performance Monitor Users", this code will not throw an exception.
When running as a scheduled task under the same user account, it fails.
The only way I can get it to work is to run it as a member of the Local Administrator group.
Any ideas?
My humblest apologies. The user I was using was NOT a member of "Performance Monitor Users" group.
This is necessary for .NET Framework 1.1 implementation of System.Diagnostics.
I have added the user to this group, and all is well.
What user rights assignments have you given the account that is running as a scheduled task? You'll need to give the account in question 'Log on as a batch job' in your local security settings.
Update: Does your app write to any files and if so does the scheduled task user have enough rights?
I just knocked up a test app that writes the process names from the Process[] array returned by Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName) to a file and it works just fine as a scheduled task...even running under the identity of a user that is only a member of the Users group (not even a member of 'Performance Monitor Users'.
The folder it writes to is assigned modify rights to SYSTEM, Administrators and the scheduled task user.
Any chance of pasting your code or at least a small enough snippet that demonstrates the exe failing as a scheduled task so we can help diagnose the problem?
Cheers
Kev
One issue that I have seen with reading the process name is that access to the performance counters can get disabled.
Crack open your registry and see if this key is there:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PerfProc\Performance]
"Disable Performance Counters"=dword:00000001
You can either set it to zero or deleted it.
Taken from MSDN:
Permissions LinkDemand - for full
trust for the immediate caller. This
member cannot be used by partially
trusted code.

Resources