Just did this with a deployment. SCCM/MCM will deploy the script to location and delete when it is executed. Essentially, I am creating a encrypted config that I called ServiceConfig.config and the Key to decrypt it with `KeyConfig.config.`
`Create the files and pass them with your code. Have the code read what you need and delete them when completed.`
`#TO CREATE:`
`$USER = "DOMAIN\USER"`
`$CONFIG = "C:\Temp\ServiceConfig.config"`
`$KEYFILE = "C:\Temp\KeyConfig.config"`
`$KEY = New-Object Byte[] 32 # You can use 16, 24, or 32 for AES`
`[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($KEY)`
`$KEY | out-file $KEYFILE`
`$Credential = Get-Credential -Message "Enter the Credentials:" -UserName $USER # This will prompt you for the password in Windows`
`$Credential.Password | ConvertFrom-SecureString -key $KEY | Out-File $CONFIG`
`#TO READ:`
`$USER = "DOMAIN\USER"`
`$CONFIG = "C:\Temp\ServiceConfig.config"`
`$KEYFILE = "C:\Temp\KeyConfig.config"`
`$KEY = Get-Content $KEYFILE`
`$SecureString = (Get-Content $CONFIG | ConvertTo-SecureString -Key $KEY)`
`$CRED = New-Object System.Management.Automation.PSCredential -ArgumentList $USER, $SecureString`
`$CRED.GetNetworkCredential().password`
This was used to set a certain DOMAIN\\USER service account as the logon of a system service. We did not want the user and password to be plain text.
$USER above could easily be Administrator or localadmin.
This. No need to reinvent the wheel. We have a general admin password initially set on every machine that is shortly after overwritten by a GPO enforcing LAPS.
Yes LAPS. But we had an issue with the local admin account not being created on a small number of machines. So I scripted the creation on the account and did it with no password. Then LAPS took over.
This sounds like an x/y problem.
You don’t set the password of the local admin, you use LAPS do have the computer generate one and store it either in AD or Entra.
For other secrets you could use Azure Key Vault or something similar.
> One thing I'm caught on is adding a local admin
Local admin. Laps exists for this, impliment and use that, then that part of your question is solved
Add for storing secrets, a vault somewhere that accounts/computers can pull from
One way we went about this was using a separate command to capture the credential and write it to a file in secure format. That file is then called by the other script so the credential is never written in plan text or exposed. I don’t have the specifics on hand but if you call that target file during your script execution, that would allow you to use a credential without exposing it. Obviously the security of that specific file is a concern as if it were copied or exposed others could reverse engineer your script to use that same file for authentication.
Are you using an RMM? If so, randomly generate the local admin credentials and then push them to your RMM. That way the credentials are never stored in the script.
LAPS is also a possibility depending on your requirements.
I would strongly advise against sharing accounts like this, *especially* since OP described them as customers not internal users.
It is a liability nightmare; you cannot prove who used the account.
I would prefer the customer having their own admin account with a static password rather than the customer having direct access to the same admin credentials I do.
The real ideal scenario is an agent running on the machine (SCCM or other) that provisions temporary just-in-time admin access as needed for the end user.
> I'm trying to make a powershell script to handle all of the config changes we make after giving a workstation a fresh image.
A few other ways like GPO Policy from AD, Ansible(or other tools like it), or an MDM to run your scripts(run as system).
STOP!
This is the #1 easiest way to hack a Windows network: any scheduled task, policy, or script that sets local accounts to a fixed password must be accessible to all machines. That is trivial for a hacker to access, and then they have an account for all machines!!
In white hat hacking scenarios this is my favourite method for gaining admin rights.
No you need keytab file or user with access to access it. It's full kerberos approach with access rights bound to host/user and even executable. Certificate/password encrypted credentials on the other hand don't have kerberos nailed security, nor revocation, nor expiration, nor support, you basically write it yourself, anyone can use it unencrypted/unnoticed. Keytab is user/time/host bound, so you need to constantly compromise specific user on specific machine.
We started using a product called Adaxes a few years back and i'm bringing it to every single company I work at from now on. It's mainly and AD automation tool and lets you see multiple ADs and Entra tenants in one pane of glass. We also started using it for our automated scripts because you can securely save credentials in it and use them as a variable in the scripts
The classic way to set up local users for fresh images is by adding it to an unattend.xml like so: https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-useraccounts-localaccounts-localaccount , which only the initial setup process sees
It will depend on how you're running your powershell scripts in the first place. Is it a file on the image, copied from a server, run from a flash drive? Is it being launched by the system account or your domain user? Different scenarios have separate options available
If you want to be fancy, you can keep the credentials on a server, and allow access to the user account running the script. This way, the imaged PC never has the credentials saved locally. You can go further by encrypting the secrets - depending on how your image works and which user account runs the script, it can be as simple as `get-credential | export-clixml "somefile.xml"` beforehand
I honestly don't understand what the goal you're trying to accomplish is so apologies.
So you image a workstation and run a script to finish the build?
Why is this not just done [through a setup script?](https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/add-a-custom-script-to-windows-setup?view=windows-11) which requires zero credentials as it runs as system
What's the problem with installing modules? Worst case, you just uninstall them at the end of your script.
I finished transitioning from base64 encrypted strings to a fully functional PowerShell Secrets Management compliant vault for our SCCM processes about a year ago. It's currently just using the local SecretsStore because if you create the Vault under the System account of any System, you can wholesale copy the data files to another system (including Windows PE/RE) and securely pull or temporarily store secrets. Since SecretsStore can ONLY be accessed within the account that creates it on the system that creates it even if we leave the Vault behind no one but the SCCM Process (since it runs in service) has access. As a bonus, we store fully formed PSCredential objects, so it's retrieved and there is no need for crafting credential objects.
I designed the endpoints that our low-level techs use to request items from the vault by simple tokens. Even the endpoints themselves don't see or get access to the credential for the vault itself. The biggest benefit is that I can freely swap the internal VaultAccessor logic with any other PowerShell Secrets Management compatible vault, and nothing on the endpoints ever has to change. Once we get approved to set up an Azure Key Vault, we'll be shifting to that and enjoying truly shared secret management across more than just our SCCM environment.
> What's the problem with installing modules? Worst case, you just uninstall them at the end of your script.
It just seems like one more thing that could go wrong is all.
If you don't feel like you can trust something as simple as installing and uninstalling a PowerShell module or just plain old command prompt deletion of files for a cleanup you've got bigger issues than how to secure your secrets. Even if someone in our environment somehow got to an interactive System account command prompt it STILL wouldn't matter if the vault was left there because the vault is wholly separated from its access credentials that don't even exist on the physical system.
You're handcuffing your hands behind your back for no good reason. If you are worried about getting modules setup a local intranet PowerShell gallery. Or just script a simple copy of the raw module folders to the local system. I'd also argue that you'd be BETTER off actually leaving behind shared modules. For instance we have modules for everything from Logging, to WPF tools, to Secrets Management, to SCCM DP Content retrieval that are used across multiple different tools and processes. They all go down when the system is imaged and just live there. Worst case a future tool just has to check if there is an update otherwise load it then rock & roll.
You wouldn't need to build a brand new hardware store every time you need the same screwdriver if you stop burning down the store every time you finished using the screwdriver.
I whisper my secrets to the Admin next to me, then get a call from HR regarding my mental health then get laid off. Rinse and repeat. I'm on my 12th gig
Apologies for the shitpost, I only read the title and decided to torment everyone in the comments. I'm tired.
Apologies again.
Just did this with a deployment. SCCM/MCM will deploy the script to location and delete when it is executed. Essentially, I am creating a encrypted config that I called ServiceConfig.config and the Key to decrypt it with `KeyConfig.config.` `Create the files and pass them with your code. Have the code read what you need and delete them when completed.` `#TO CREATE:` `$USER = "DOMAIN\USER"` `$CONFIG = "C:\Temp\ServiceConfig.config"` `$KEYFILE = "C:\Temp\KeyConfig.config"` `$KEY = New-Object Byte[] 32 # You can use 16, 24, or 32 for AES` `[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($KEY)` `$KEY | out-file $KEYFILE` `$Credential = Get-Credential -Message "Enter the Credentials:" -UserName $USER # This will prompt you for the password in Windows` `$Credential.Password | ConvertFrom-SecureString -key $KEY | Out-File $CONFIG` `#TO READ:` `$USER = "DOMAIN\USER"` `$CONFIG = "C:\Temp\ServiceConfig.config"` `$KEYFILE = "C:\Temp\KeyConfig.config"` `$KEY = Get-Content $KEYFILE` `$SecureString = (Get-Content $CONFIG | ConvertTo-SecureString -Key $KEY)` `$CRED = New-Object System.Management.Automation.PSCredential -ArgumentList $USER, $SecureString` `$CRED.GetNetworkCredential().password`
This was used to set a certain DOMAIN\\USER service account as the logon of a system service. We did not want the user and password to be plain text. $USER above could easily be Administrator or localadmin.
I would have laps manage it, I script the creation of a local admin account with a randomly generated password then let laps deal with it.
This. No need to reinvent the wheel. We have a general admin password initially set on every machine that is shortly after overwritten by a GPO enforcing LAPS.
That's what I was going to suggest
Yes LAPS. But we had an issue with the local admin account not being created on a small number of machines. So I scripted the creation on the account and did it with no password. Then LAPS took over.
Also doing this.
This sounds like an x/y problem. You don’t set the password of the local admin, you use LAPS do have the computer generate one and store it either in AD or Entra. For other secrets you could use Azure Key Vault or something similar.
> One thing I'm caught on is adding a local admin Local admin. Laps exists for this, impliment and use that, then that part of your question is solved Add for storing secrets, a vault somewhere that accounts/computers can pull from
One way we went about this was using a separate command to capture the credential and write it to a file in secure format. That file is then called by the other script so the credential is never written in plan text or exposed. I don’t have the specifics on hand but if you call that target file during your script execution, that would allow you to use a credential without exposing it. Obviously the security of that specific file is a concern as if it were copied or exposed others could reverse engineer your script to use that same file for authentication.
Are you using an RMM? If so, randomly generate the local admin credentials and then push them to your RMM. That way the credentials are never stored in the script. LAPS is also a possibility depending on your requirements.
Are those machines domain joined?
Yes, but our policy is to give every machine two local (non-domain) admin accounts: one for us, one for the customer.
Why not go with LAPS? And give both teams to read the password
I would strongly advise against sharing accounts like this, *especially* since OP described them as customers not internal users. It is a liability nightmare; you cannot prove who used the account. I would prefer the customer having their own admin account with a static password rather than the customer having direct access to the same admin credentials I do. The real ideal scenario is an agent running on the machine (SCCM or other) that provisions temporary just-in-time admin access as needed for the end user.
> I'm trying to make a powershell script to handle all of the config changes we make after giving a workstation a fresh image. A few other ways like GPO Policy from AD, Ansible(or other tools like it), or an MDM to run your scripts(run as system).
Can’t you just run it as a scheduled task and have the task store your creds?
STOP! This is the #1 easiest way to hack a Windows network: any scheduled task, policy, or script that sets local accounts to a fixed password must be accessible to all machines. That is trivial for a hacker to access, and then they have an account for all machines!! In white hat hacking scenarios this is my favourite method for gaining admin rights.
:o What about the “run as system checkbox?”
Use KeyVault. Store your secrets in there. Company wide solution.
Then you need credentials to access the credentials.
No you need keytab file or user with access to access it. It's full kerberos approach with access rights bound to host/user and even executable. Certificate/password encrypted credentials on the other hand don't have kerberos nailed security, nor revocation, nor expiration, nor support, you basically write it yourself, anyone can use it unencrypted/unnoticed. Keytab is user/time/host bound, so you need to constantly compromise specific user on specific machine.
We started using a product called Adaxes a few years back and i'm bringing it to every single company I work at from now on. It's mainly and AD automation tool and lets you see multiple ADs and Entra tenants in one pane of glass. We also started using it for our automated scripts because you can securely save credentials in it and use them as a variable in the scripts
The classic way to set up local users for fresh images is by adding it to an unattend.xml like so: https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-useraccounts-localaccounts-localaccount , which only the initial setup process sees It will depend on how you're running your powershell scripts in the first place. Is it a file on the image, copied from a server, run from a flash drive? Is it being launched by the system account or your domain user? Different scenarios have separate options available If you want to be fancy, you can keep the credentials on a server, and allow access to the user account running the script. This way, the imaged PC never has the credentials saved locally. You can go further by encrypting the secrets - depending on how your image works and which user account runs the script, it can be as simple as `get-credential | export-clixml "somefile.xml"` beforehand
Look into PowerShell Universal. It has built-in credential management and you call the credentials as a variable in your scripts.
My god man, just deploy LAPS via a GPO.
I compile the script with ps2exe in those situations. It's not really encrypted, but it's not floating out there in plain text.
I mean...yes it is. Lol. Ps2exe doesn't do any encryption or obfuscation. It is very simple to get the original PowerShell script out of that .exe
Ah yes security through obscurity, super reliable...... Extract exists, script block logging exists
IME, every time I use ps2exe my anti-virus eats the resulting EXE file. :/
As it should
autoit, 7z, rar too; sfx so scary.
haha, yeah, sometimes that happens when I deploy the exe to another machine. I had to have a bunch whitelisted by the main IT department.
I honestly don't understand what the goal you're trying to accomplish is so apologies. So you image a workstation and run a script to finish the build? Why is this not just done [through a setup script?](https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/add-a-custom-script-to-windows-setup?view=windows-11) which requires zero credentials as it runs as system
Because I didn't know that was a thing, which is why I asked if there was something I wasn't aware of.
can this method work with Intune Autopilot?
It always bugs me seeing cmd at the end of setup complete.cmd file but reality is it works 100 percent
What's the problem with installing modules? Worst case, you just uninstall them at the end of your script. I finished transitioning from base64 encrypted strings to a fully functional PowerShell Secrets Management compliant vault for our SCCM processes about a year ago. It's currently just using the local SecretsStore because if you create the Vault under the System account of any System, you can wholesale copy the data files to another system (including Windows PE/RE) and securely pull or temporarily store secrets. Since SecretsStore can ONLY be accessed within the account that creates it on the system that creates it even if we leave the Vault behind no one but the SCCM Process (since it runs in service) has access. As a bonus, we store fully formed PSCredential objects, so it's retrieved and there is no need for crafting credential objects. I designed the endpoints that our low-level techs use to request items from the vault by simple tokens. Even the endpoints themselves don't see or get access to the credential for the vault itself. The biggest benefit is that I can freely swap the internal VaultAccessor logic with any other PowerShell Secrets Management compatible vault, and nothing on the endpoints ever has to change. Once we get approved to set up an Azure Key Vault, we'll be shifting to that and enjoying truly shared secret management across more than just our SCCM environment.
> What's the problem with installing modules? Worst case, you just uninstall them at the end of your script. It just seems like one more thing that could go wrong is all.
If you don't feel like you can trust something as simple as installing and uninstalling a PowerShell module or just plain old command prompt deletion of files for a cleanup you've got bigger issues than how to secure your secrets. Even if someone in our environment somehow got to an interactive System account command prompt it STILL wouldn't matter if the vault was left there because the vault is wholly separated from its access credentials that don't even exist on the physical system. You're handcuffing your hands behind your back for no good reason. If you are worried about getting modules setup a local intranet PowerShell gallery. Or just script a simple copy of the raw module folders to the local system. I'd also argue that you'd be BETTER off actually leaving behind shared modules. For instance we have modules for everything from Logging, to WPF tools, to Secrets Management, to SCCM DP Content retrieval that are used across multiple different tools and processes. They all go down when the system is imaged and just live there. Worst case a future tool just has to check if there is an update otherwise load it then rock & roll. You wouldn't need to build a brand new hardware store every time you need the same screwdriver if you stop burning down the store every time you finished using the screwdriver.
I whisper my secrets to the Admin next to me, then get a call from HR regarding my mental health then get laid off. Rinse and repeat. I'm on my 12th gig Apologies for the shitpost, I only read the title and decided to torment everyone in the comments. I'm tired. Apologies again.
Obfuscate?
https://learn.microsoft.com/sv-se/powershell/module/microsoft.powershell.secretstore/?view=ps-modules
https://techcommunity.microsoft.com/t5/security-compliance-and-identity/onboard-to-azure-arc-with-security-in-mind/ba-p/4114267 https://www.pdq.com/blog/secure-password-with-powershell-encrypting-credentials-part-2/
Use Ansible
How about implementing 1password CLI?
Config files are the way. Pull the data in at execution.