FriendsOfMDT / PSD

PowerShell Deployment
MIT License
471 stars 72 forks source link

%SCRIPTROOT% Cannot Be Found When Running As Custom User #138

Open ewrightmdy opened 4 months ago

ewrightmdy commented 4 months ago

Hello! I'm attempting to run a custom PowerShell script to kick off a PDQ deployment following the imaging process, and I'm running into some trouble with specifying account credentials in the task sequence.

The script we are calling through the Command Line step, as per this post there are issues with calling scripts through the PowerShell step (it simply opens a blank PowerShell window and does not actually execute):

powershell.exe -ExecutionPolicy Bypass %SCRIPTROOT%\PDQDeploy.ps1

When running the task sequence the script is successfully being called, however it is returning invalid credentials for our PDQ Server. I assume what's happening is that the task sequence is attempting to run the script as the local admin user, not the domain admin user which PDQ requires. So the easy fix for this should be to specify running the script as the domain admin in the task sequence, however when I do that I get the following error:

The system cannot find the file specified. (Error: 80070002; Source: Windows)]LOG]!><time="09:39:26.308+300" date="03-01-2024" component="TSManager" context="" type="3" thread="10440" file="instruction.cxx:785">

From what I can tell, by specifying the user the task sequence step is somehow losing it's access to %SCRIPTROOT%, or at least cannot locate the script we are trying to run. Of course an easy way to get around this is to run the script without specifying the user and hardcoding the credentials into the script, but I would rather not do that. If anyone knows of another workaround for this issue it would be greatly appreciated!

technerdist commented 4 months ago

I am a co-worker of OP's and I am working on this issue with him. My take after some further testing. All of this testing was performed without running command steps as a separate user.

First, we run a successful command step: powershell.exe -command "Set-ExecutionPolicy Bypass"

Then we call our PDQ script, with another command step: powershell.exe -file %SCRIPTROOT%\PDQDeploy.ps1

Our PDQ script contains the following lines:

netsh advfirewall set allprofiles state off
ipconfig /registerdns

psexec.exe \\server.domain.com -h -accepteula ipconfig /flushdns
psexec.exe \\server.domain.com -h -accepteula pdqdeploy.exe Deploy -Package "New-ImageApplications" -Targets
 $env:COMPUTERNAME

Start-Sleep 30
while (Test-Path "C:\Windows\AdminArsenal\PDQDeployRunner\service-1.lock") {
    Start-Sleep 30
}

Manually calling the script using PSExec from the newly imaged computer, we receive an invalid credential error. I assume a credential error maybe at fault. However, when adding credentials to the PSExec command, ran on the newly imaged computer, it works. Running the same command, with the credentials, via a command step results in the script appearing to run, but there's no response from the PDQ server.

There are no errors in the SMSTS logs. Please help us understand why our PDQ script is not executing properly. I tried to set up transcription to a log, but I'm a bit of a PS noob, and it output nothing.

Thank you for any assistance you may be able to offer.

JerichoJones commented 3 months ago

Can you change it to "Run Powershell Script"? With this I have found that you don't need to specify %SCRIPTROOT%. image

JerichoJones commented 3 months ago

You will need to drop any supporting files (psexec) into %SCRIPTROOT% as well.

ewrightmdy commented 3 months ago

We can run it as a PowerShell step, but that doesn't solve our original problem which is that we need the script to run as a domain admin. Currently we have it running successfully by hardcoding the domain admin credentials in the script and running it as a "Run PowerShell Script" step, as you suggested. However that is a rather insecure way of going about it, we would much rather specify in the task sequence for it to run as a domain admin. This is a feature that is only available for the "Run Command Line" step though, and every time we specify the user for it to run as, it can no longer find the script.

JerichoJones commented 3 months ago

Yeah that would be bad.

JerichoJones commented 3 months ago

Total guess but you seem to be stuck so it might be worth a try:

  1. Open PSDCLient.xml
  2. Under step type="SMS_TaskSequence_RunCommandLineAction" name="Configure"
  3. Change <variable name="LoadProfile" property="LoadProfile">false</variable> to true
technerdist commented 3 months ago

We appreciate your assistance @JerichoJones but these suggestions have not been helpful for this issue.

PowerShellCrack commented 3 months ago

My first ask: Why does the account need to be a Domain Admin? I would HIGHLY recommend using delegated rights. The credential info can be retrieved within winpe just by loading the task sequence module and retrieving the variable.dat file (the same can be said with MECM OSD)

IMO, I would obfuscate the password with an AES key in the PowerShell; makes it a little harder to decrypt.

$ADUser = 'contoso\admin'
#STEP 1 - create random passphase (256 AES). Save the output as a variable (copy/paste)
#NOTE: this key is unique; the same key must be used to decrypt
$AESKey = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey)
Write-host ('$AESKey = @(' + ($AESKey -join ",").ToString() + ')')

#STEP 2 - Encrypt password with AES key. Save the output as a variable (copy/paste)
$AESEncryptedPassword = ConvertTo-SecureString -String '!QAZ1qaz!QAZ1qaz' -AsPlainText -Force | ConvertFrom-SecureString -Key $AESKey
Write-host ('$ADEncryptedPassword = "' + $AESEncryptedPassword + '"')

#STEP 3 - Store as useable credentials; converts encrypted key into secure key for use (used in the script)
$SecurePass = $AESEncryptedPassword | ConvertTo-SecureString -Key $AESKey
$credential = New-Object System.Management.Automation.PsCredential($ADUser, $SecurePass)

#STEP 4 - Test password output (clear text) from creds
$credential.GetNetworkCredential().password

this will output what you need in the script.

You could take this one step further and put the AES key as a variable in the TS or in the cutomsettings.ini which makes it even harder to retrieve.

OR another option is since the PSD Wizard still uses the MDT Deployment workbench, the UI does not have the runas option for PowerShell scripts. Have you thought of running a command line but calling powershell:

powershell -ExecutionPolicy Bypass -File script.ps1

Hopefully this helps

matsmcp commented 2 months ago

My first ask: Why does the account need to be a Domain Admin? I would HIGHLY recommend using delegated rights. The credential info can be retrieved within winpe just by loading the task sequence module and retrieving the variable.dat file (the same can be said with MECM OSD)

IMO, I would obfuscate the password with an AES key in the PowerShell; makes it a little harder to decrypt.

$ADUser = 'contoso\admin'
#STEP 1 - create random passphase (256 AES). Save the output as a variable (copy/paste)
#NOTE: this key is unique; the same key must be used to decrypt
$AESKey = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($AESKey)
Write-host ('$AESKey = @(' + ($AESKey -join ",").ToString() + ')')

#STEP 2 - Encrypt password with AES key. Save the output as a variable (copy/paste)
$AESEncryptedPassword = ConvertTo-SecureString -String '!QAZ1qaz!QAZ1qaz' -AsPlainText -Force | ConvertFrom-SecureString -Key $AESKey
Write-host ('$ADEncryptedPassword = "' + $AESEncryptedPassword + '"')

#STEP 3 - Store as useable credentials; converts encrypted key into secure key for use (used in the script)
$SecurePass = $AESEncryptedPassword | ConvertTo-SecureString -Key $AESKey
$credential = New-Object System.Management.Automation.PsCredential($ADUser, $SecurePass)

#STEP 4 - Test password output (clear text) from creds
$credential.GetNetworkCredential().password

this will output what you need in the script.

You could take this one step further and put the AES key as a variable in the TS or in the cutomsettings.ini which makes it even harder to retrieve.

OR another option is since the PSD Wizard still uses the MDT Deployment workbench, the UI does not have the runas option for PowerShell scripts. Have you thought of running a command line but calling powershell:

powershell -ExecutionPolicy Bypass -File script.ps1

Hopefully this helps

I fully agree -Domain admin in a deployment is a really bad idea. If I read the script correctly the only things it does is to run PSexec commands as domain admin. One way of making it better would be to use restPS to create a Webservice and call the webservice from the deployment. It's still NOT a good way to do it since domain admin accounts shouldn't be required for anything automated. The correct permissions should be delegated instead