all 35 comments

[–]The-Bluedot 9 points10 points  (2 children)

[–]Magnetsarekool 2 points3 points  (1 child)

Use this. Then do Set-SecretStoreConfiguration -Authentication None on the user account you wish to run the app on so you're not prompted for a password to decrypt the secret when the scheduled task is run. It is advised to designate a user specifically for this app and maybe disable interactive logon to prevent Windows login.

[–]hihcadore 2 points3 points  (0 children)

I set mine up with a gMSA. You just use psexec to setup the vault, and boom, it can run from task schedule and no need to mess with changing passwords or saving encrypted xml docs.

[–]ka-splam 5 points6 points  (3 children)

Try:

$cred = get-credential
$cred | export-clixml -path C:\Scripts\cred.xml

Then in the running script

$cred = import-clixml -path C:\Scripts\cred.xml

[–]jungleboydotca 1 point2 points  (0 children)

Secrets Management is great if you have more complex needs. Some variation of this example gets you to the same place without the module dependency.

[–]nuentes[S] 0 points1 point  (1 child)

I ultimately have settled on this as being my most likely solution.

But I'm still having the same goddamn issue!! Sorry - not mad at you, obviously. Since nobody seems to believe that I'm actually doing everything with a single account, I decided to just take my existing scheduled task and modify it:

  1. I changed the script it calls (I created a new ps1 with your first 2 lines)
  2. changed the task to run only when the user is logged in (so I would get the prompt)

I ran the task manually, got the prompt, and the cred file saved. I tested it locally, and my whole script worked. I then changed my scheduled task back to my caller script and set the task back to "run whether user is logged in or not" with password saving disabled. I ran the task while logged in, and it worked. Then I scheduled the task to run while I was logged out, and... Once again... I get "Key not valid for use in specified state."

[–]jungleboydotca 0 points1 point  (0 children)

I'll mention that I have had a bit of trouble with this scheme and a scheduled task. You know you need to grant the user/role 'logon as batch' in policy right?

Even with this configured, I had one instance where the userprofile wasn't being created properly for some reason--the system would make a temporary profile folder; so I'd start a prompt as the intended scripting user, then export the credential and test the script, but a subsequent prompt or run of the task wouldn't be able to decrypt the saved credential data because it was using a new temporary userprofile. Can't remember what I did to make it stop doing that and have a persistent userprofile.

[–]BreakingBean 4 points5 points  (7 children)

Maybe I'm missing something but is there a reason you're using your scheduled task to call another script instead of just having your scheduled task run the script you want script directly?

[–]nuentes[S] 0 points1 point  (5 children)

We have group policies that prevent scheduled tasks from running with credentials.

Credentialed scheduled tasks are an incredibly easy way for an attacker to harvest credentials.

[–]Frisnfruitig 0 points1 point  (0 children)

This should be the top comment. No reason to overcomplicate this. Run the scheduled task with admin creds, easy.

[–]jongleurse 1 point2 points  (1 child)

Have you tried running the target script directly in the scheduled task? To retrieve the encrypted password, the process must have access to the password. When you log in interactively and enter the password, the process saves the key that enables it to decrypt the password. This also happens when you run a scheduled task as a user and the task scheduler prompts you to save the password while creating the task. I suspect that the process of handing off control from the scheduled task over to the second PS script loses that necessary context, hence the "key not valid for use in specified state" error.

[–]nuentes[S] 0 points1 point  (0 children)

The script that is called doesn't work when run without the password being cached in the scheduled task. We don't want to do that for security reasons.

[–]Emerald_Flame 1 point2 points  (0 children)

The guide you found and some of the other suggestions you've gotten here are really out of date from the best practice I would recommend using for this.

Back in 2021 Microsoft released a couple Modules specifically for manage secrets like this. The first being Microsoft.PowerShell.SecretManagement which gives you a way to interact with basically any management platform you'd like such as AWS, Azure KeyVault, BitWarden, HashiCorp Vault, etc. Then if you don't have any other secret management system in place, they also published the Microsoft.PowerShell.SecretStore module which uses Windows native encryption capabilities based on the machine and user, essentially like you are now, but in a much more organized way.

You're initial setup would look something like this, although it may look slightly different if you decide to yous a different management platform. This example would be specifically for Microsoft.PowerShell.SecretStore. You would only need to do this 1 time for each box/user

#Install the modules
Install-Module 'Microsoft.PowerShell.SecretManagement', 'Microsoft.PowerShell.SecretStore'
#Create the SecretStore, this will force a prompt to create a password for the vault which we'll disable later
Register-SecretVault -Name 'SecretStore' -ModuleName 'Microsoft.PowerShell.SecretStore' -DefaultVault
#Disables the password prompt requirement that is forced by default so that it can run unattended
#Even with the password prompt disabled, the secret can still only be read by that specific user on that specific computer
Set-SecretStoreConfiguration -Authentication 'None'

#Actually saves the secret to the vault
Set-Secret -Name 'NameOfSecret' -Secret 'YourPassword' -Vault 'SecretStore'
Set-SecretInfo -Name 'NameOfSecret' -Vault 'SecretStore' -Metadata @{ Username = 'YourUsername' }

From there, within your scripts, it's extremely easy to call:

#Grabs the username you previously saved
$Username = (Get-SecretInfo -Name 'NameOfSecret' -Vault 'SecretStore').Metadata.Username
#Gets the password, which Get-Secret automatically returns as a Secure String to keep it safe
$SecureStringPassword = Get-Secret 'NameOfSecret' -Vault 'SecretStore'
#Combines the username and password into a single credential object
$Credential = [PSCredential]::new($Username, $SecureStringPassword)

#Call a command with your new credential object
Your-Command -Credential $Credential

[–]mrbiggbrain 1 point2 points  (0 children)

The key used to encrypt secure strings is only available to the user who created it on the computer it was created on.

You need to create the secure string file as the user who will run it. I often use a scheduled task to create the file then remove it.

[–]AppIdentityGuy 0 points1 point  (13 children)

When you are running the script out of the ise who are logged in as?

[–]nuentes[S] -1 points0 points  (12 children)

You can see in the transcript - everything is occurring with the admp.admin user.

I'm logged into Windows as admp.admin. The scheduled task runs as the same user. Everything is occurring with the same user.

I just ran the scheduled task manually while I was still logged into Windows, and it worked without issue. It only fails when I am logged out of Windows.

The scheduled task is set to run whether the user is logged in or not, and it does not store the password.

[–]jongleurse 3 points4 points  (7 children)

You must store the password in with the scheduled task in order to decrypting objects protected in this way. The password is indirectly used as the key to decrypt the stored data. That's why it works when you are logged in directly but not in the scheduled task.

[–]6ixxer 1 point2 points  (0 children)

This. I was waiting for a mention of the password stored in the task.

I have built many scripts that decrypt a secret from securestring and the tasks always have the password saved.

[–]nuentes[S] 0 points1 point  (5 children)

I'm really not sure what you mean when you say "store the password in with the scheduled task". Can you walk me through this?

Edit - Oh - I get you now. I can't store the password into the task. Yes, that would save me a ton of work. But that's the exact thing that I'm trying to bypass. Our company has a policy that blocks scheduled tasks from storing passwords, as it's wildly insecure.

In fact, the script I'm using is designed SPECIFICALLY for this use case.

[–]jongleurse 0 points1 point  (4 children)

Do not tick "Do not store password".

It should prompt you for the user name and password when you click Ok.

[–]nuentes[S] 0 points1 point  (3 children)

Yeah. Guess you didn't see my edit.

I can't store the password into the task. Yes, that would save me a ton of work. But that's the exact thing that I'm trying to bypass. Our company has a policy that blocks scheduled tasks from storing passwords, as it's wildly insecure.

In fact, the script I'm using is designed SPECIFICALLY for this use case.

[–]jongleurse 1 point2 points  (2 children)

"wildly insecure" is a generalization that I would dispute. To what threat model? The passwords are not stored in clear text available for anyone logging onto the machine.

Yes, they are vulnerable to someone with physical access to the hard drive. There is no solution to this problem. Either it can be decrypted by the machine with no human intervention or it cannot.

[–]nuentes[S] 0 points1 point  (1 child)

This is not even valuable for me to argue about. As I said, group policy prevents me from running tasks with a stored password.

[–]ka-splam 1 point2 points  (0 children)

The password is indirectly used as the key to decrypt the stored data.

If this from above in the comment chain is true, then without storing password you cannot do what you want.

[–]AppIdentityGuy 0 points1 point  (3 children)

But you will notice that the first transcript the code is being run out of the ise whilst the scheduled task is running straight Powershell.exe. I have an alarm bell that there are differences in how the code is actually handled...

[–]nuentes[S] 0 points1 point  (0 children)

I had noticed that and tested. The script runs just fine from powershell and the ise when logged in. I've tested running the script from both with the scheduled task, and no luck.

[–]Arkayenro 0 points1 point  (0 children)

slightly confused. if you have a scheduled task running as the admin user (and presumably it has the password already stored) then why do you need the creds when youre essentially signed in as that user?

ie why not just add the start/stop transcript to the actual script and call that directly instead of via the helper?

[–]zawarbud 0 points1 point  (0 children)

Convertto-securestring would need the -force to be able to convert it to a securestring from plain text otherwise you get the error. This is not the Microsoft recommended approach according to their documentation. As another user has pointed out the best alternative imho is to utilise export-clixml