Permissions in a scheduled task :(

Due to the way we are automating server installations, I have to create a scheduled task from a batch job. That works fine. From within the scheduled task I am running a powershell script which gets the contents of a file which has an encrypted password (from the module SecureStringFunctions with an entrophy code), which I will use as a parameter for an application installation executed my msiexec. I run the scheduled task as SYSTEM, highest privileges.
The software installation will go fine - I have the application set the service to manual.
Then the script will change the service to automatic and give it the correct password which has come from the above file.
I use the following: $svc.change($null,$null,$null,$null,“Automatic”,$null,$null,$cred). This works correctly if I run it myself, or run it in a non-administrator PS session (but maybe I still have special rights in there?)
Anyway, executing $svc.change($null,$null,$null,$null,“Automatic”,$null,$null,$cred) as system will not work. I do know the pwd is correct because I wrote it to a file while troubleshooting.
I know there are hundreds of discussions regarding the need to have more permissions while running a script in a scheduled task, but I have not found one that has worked for me.
Can someone please advise?

When you use ConvertTo-SecureString and do not use the -Key or -SecureKey parameters (even with the additional entropy offered by the proxy function in the SecureStringFunctions.psm1 file), PowerShell uses the Data Protection API to encrypt the string, in the current user’s scope. Only the same user account that encrypted the data will be able to read it back.

If you want to encrypt data that can be read by another user account, the trick is in how to protect the encryption key. The DPAPI makes this a completely brainless, hands-off affair: windows takes care of protecting the key for you, and the key is part of a user’s profile. I’ve written a module called ProtectedData which gives you a similar ease-of-use level, but allows the encrypted data to be decrypted anywhere, so long as the person doing the decryption has the proper digital certificate (with its private key.) That module is called ProtectedData, and can be downloaded from Releases · dlwyatt/ProtectedData · GitHub . If you’re using PowerShell 5.0 (which is still in preview), there are a few new cmdlets which work along the same lines (*-CmsMessage); you give the command some data and a certificate, and it takes care of the rest.

Thanks Dave.
So what I am really after here, is to be sure the password is not hanging around in clear text, and can be used by SYSTEM in my process. I would like to have that encrypted in a file, and read by SYSTEM. So you are saying that the only way I can really do this is to use your protecteddata module. I mean, this would be the best was to store my service account password in a file? Nothing PS has that will do the same?
Otherwise, I will use your module with at cert.

There are other options. You could encrypt the data using the same account that will be decrypting it. I’m not 100% sure if that will work as SYSTEM, but you could give it a try. (Alternatively, you could have your scheduled task run as a different account.) Or you could use ConvertTo / ConvertFrom-SecureString using the -Key parameter, and come up with your own way of saving and protecting the encryption key. (You could save it to a file with strong NTFS permissions that only allow you and SYSTEM to read / write, for example.)

Thanks. I have set up the key using the SYSTEM account (using psexec -i -s Powershell.exe and running the SecureStringFunctions module) and it worked out fine. Then I ran my script inside that same PS session (as NT\Authority\SYSTEM it showed in the session) and it worked.
However, when I use a scheduled task to run the exact same script, and it does not work. I have it running as the user SYSTEM, run whether the user is logged on or not, and run with highest privileges.
I can go back to the PS session and run it manually, and it works.
Would you (or anyone else reading this :slight_smile: ) offer some suggestions as to what the difference is?

Do you have the “do not store password” box checked on that task? You may need to uncheck the box in order for the task to have access to the user profile / DPAPI keys. (I don’t know for sure if that will work; just an educated guess.)

I take it all back, it’s working now. I had commented out a line that was needed :slight_smile:
Thanks for your help Dave!

Ah, a short-lived success. Once I moved on to another computer (as SYSTEM), it no longer works. On the other server I get an error message
ConvertTo-SecureString execption calling "unprotect: with “3” argument(s). Key not valid for use in specified state.
Is it because I am on a different computer? That is what I read this morning on the web, but you know the web… :slight_smile:

I guess I will just try your other module and stop hassling you :slight_smile:

Now I am using the ProtectData function.

Because this is an automated process, I need to store the encrypted password in a file, then read the file later and decrypt it, from another server. I’ve been fooling around with this but I cannot seem to use variables when running the UnProtectData function. Is there a way to store the encrypted password in a file, read it, then use it to get my ultimately needed password?


Sorry for running monologue, but this is what I ended up doing. I hope it is secure enough. I will be deleting these files from the server after the job runs. Any id, or any computer can run this because of the -key parameter.

set up key

$key = (3,4,2,3,56,34,254,222,1,1,2,23,42,54,33,233,1,34,2,7,6,5,35,43) #(just a sample key from MS -

$password = read-host -assecurestring

$password | convertfrom-securestring -key $key | set-content somepath\file.txt

$key | set-content somepath\key.txt

To get the password when needed

$cred = (get-content somepath\file.txt ) | ConvertTo-SecureString -key (get-content somepath\key.txt)

$cred = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($cred))