PowerShell script with admin rights doesn't modify registry entries when executed through Start-Process
I have a PowerShell script that modifies registry entries related to autologin settings. When I execute the script directly from an elevated PowerShell session, the registry entries are modified successfully. However, when I create a temporary file and try to execute it using Start-Process within the ExecuteProcessNativeWaitOnExit function, the script runs with admin rights but fails to modify the registry entries.
Here's the relevant code:
# The function that executes the temporary file, takes the path to the file as an argument.
function ExecuteProcessNativeWaitOnExit($strScriptPath) {
$procInfo = New-Object System.Diagnostics.ProcessStartInfo
$procInfo.FileName = "powershell.exe"
$procInfo.Arguments = "-File `"$strScriptPath`""
# Hide the process window
#$procInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$proc = [System.Diagnostics.Process]::Start($procInfo)
# Wait for the process to exit
$proc.WaitForExit()
return $proc.ExitCode
}
# The content of the temporary file
Set-Location -Path 'C:\Users\ASM_Admin\Desktop\V23.x SIPLACE_Configurator_Win10_PS-Script\ConfigSiplaceWin10'
Start-Process powershell .\set_operator_autologin_station.ps1 -Verb RunAs > 'C:\Users\ASM_AD~1\AppData\Local\Temp\s4jq4pdp.4rt.outputfile' 2>&1
$LASTEXITCODE | Out-File -FilePath 'C:\Users\ASM_AD~1\AppData\Local\Temp\c5zk24o2.d05.ErrorLevelFile'
# The content of set_operator_autologin_station.ps1:
$WinlogonPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\"
try {
Set-ItemProperty -Path $WinlogonPath -Name "DefaultUserName" -Value "Operator"
Set-ItemProperty -Path $WinlogonPath -Name "AutoAdminLogon" -Value "1"
Set-ItemProperty -Path $WinlogonPath -Name "DefaultPassword" -Value "operator"
Write-Host "Autologin for Operator is generated"
} catch {
Write-Host "Autologin for Operator can't be generated"
}
read-host "Press enter to continue ..."
# If I open PowerShell with admin rights and execute set_operator_autologin_station.ps1, everything works correctly. The registry entries are changed and everything is fine.
# However, when I create the temporary file and try to execute it with ExecuteProcessNativeWaitOnExit, it shows Autologin for Operator is generated, which means it did not catch an error, but the registry entries are not changed. What could be the problem??
I have verified that the temporary file runs with admin rights, as it displays the expected output "Autologin for Operator is generated." However, the registry entries specified in set_operator_autologin_station.ps1 are not modified.
I would greatly appreciate any insights into why the registry modifications are not taking effect when executing the script through Start-Process within the ExecuteProcessNativeWaitOnExit function. Are there any additional considerations or changes needed to ensure the script successfully modifies the registry entries?
Thank you in advance for your help and suggestions!
Start-Process powershell .\set_operator_autologin_station.ps1 -Verb RunAs
Since you're running Windows PowerShell, this will predictably fail, because the elevated powershell.exe
process will look for the your *.ps1
file in C:\Windows\System32
, given that is the working directory it defaults to.
(Fortunately, PowerShell (Core) 7+ now preserves the caller's working directory).
... > 'C:\Users\ASM_AD~1\AppData\Local\Temp\s4jq4pdp.4rt.outputfile' 2>&1
Applying redirections to Start-Process
is pointless, because it produces no output.
(Adding -PassThru
would make it output a System.Diagnostics.Process
instance describing the launched process, not the launched process' own output.)
$LASTEXITCODE
Start-Process
never sets the automatic $LASTEXITCODE
variable.
To get the exit code of a process launched with Start-Process
, add -PassThru
, and then query the returned System.Diagnostics.Process
instance's .ExitCode
property - assuming you have first waited for the process to terminate, either by also passing -Wait
to the Start-Process
call or by calling .WaitForExit()
on the System.Diagnostics.Process
.
Therefore, rewrite your temporary script as follows:
$scriptPath = 'C:\Users\ASM_Admin\Desktop\V23.x SIPLACE_Configurator_Win10_PS-Script\ConfigSiplaceWin10\set_operator_autologin_station.ps1'
$pi = Start-Process -Verb RunAs -Wait -PassThru powershell "& `"$scriptPath`" *> 'C:\Users\ASM_AD~1\AppData\Local\Temp\s4jq4pdp.4rt.outputfile'"
$pi.ExitCode | Out-File -FilePath 'C:\Users\ASM_AD~1\AppData\Local\Temp\c5zk24o2.d05.ErrorLevelFile'
Note:
The full script path is passed to powershell.exe
, without an attempt to set the working directory (your target script doesn't seem to rely on any specific working directory).
`"...`"
), and invoked via &
, the call operator.-Wait
and -PassThru
are used to make Start-Process
wait for the elevated process to exit and to output a System.Diagnostics.Process
instance describing it, captured in variable $pi
Capturing (combined) output from the elevated target script is performed as part of the powershell.exe
command (*> ...
), which happens to be only way for a non-elevated process to capture an elevated process' stdout and stderr output - -RedirectStandardOut
and -RedirectStandardError
do not work with -Verb RunAs
(and fundamentally wouldn't allow capturing the combination of these streams).
$pi.ExitCode
contains the elevated process' exit code.