英文:
Registry modifications not taking effect when executing PowerShell script with admin rights
问题
PowerShell 脚本以管理员权限运行时,通过 Start-Process 执行时不会修改注册表项。
我有一个修改与自动登录设置相关的注册表项的 PowerShell 脚本。当我直接从以管理员权限运行的 PowerShell 会话中执行该脚本时,注册表项会成功修改。然而,当我创建一个临时文件并尝试使用 ExecuteProcessNativeWaitOnExit 函数内的 Start-Process 执行它时,脚本会以管理员权限运行,但无法修改注册表项。
这是相关的代码:
# 执行临时文件的函数,以文件路径作为参数。
function ExecuteProcessNativeWaitOnExit($strScriptPath) {
$procInfo = New-Object System.Diagnostics.ProcessStartInfo
$procInfo.FileName = "powershell.exe"
$procInfo.Arguments = "-File `"$strScriptPath`""
# 隐藏进程窗口
#$procInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$proc = [System.Diagnostics.Process]::Start($procInfo)
# 等待进程退出
$proc.WaitForExit()
return $proc.ExitCode
}
# 临时文件的内容
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'
# 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 "为 Operator 生成自动登录"
} catch {
Write-Host "无法为 Operator 生成自动登录"
}
read-host "按 Enter 键继续 ..."
# 如果我以管理员权限打开 PowerShell 并执行 set_operator_autologin_station.ps1,一切都能正常运行。注册表项会被更改,一切正常。
# 但是,当我创建临时文件并尝试使用 ExecuteProcessNativeWaitOnExit 执行它时,它会显示“为 Operator 生成自动登录”,这意味着它没有捕获错误,但注册表项没有更改。可能是什么问题??
我已经验证了临时文件以管理员权限运行,因为它显示了预期输出“为 Operator 生成自动登录”。然而,在 set_operator_autologin_station.ps1 中指定的注册表项没有被修改。
我将非常感激对于通过 ExecuteProcessNativeWaitOnExit 函数内的 Start-Process 执行脚本时为什么注册表修改没有生效的任何见解。是否有任何其他需要考虑或需要更改以确保脚本成功修改注册表项的额外注意事项?谢谢您提前提供的帮助和建议!
英文:
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!
答案1
得分: 0
<!-- language-all: sh -->
> `Start-Process powershell .\set_operator_autologin_station.ps1 -Verb RunAs`
由于您正在运行 _Windows PowerShell_,这将可预测地失败,因为提升的 `powershell.exe` 进程将在 `C:\Windows\System32` 中查找您的 `*.ps1` 文件,因为这是它默认的工作目录。
(幸运的是,[_PowerShell (Core) 7+_](https://github.com/PowerShell/PowerShell/blob/master/README.md) 现在保留了调用者的工作目录)。
> `... > 'C:\Users\ASM_AD~1\AppData\Local\Temp\s4jq4pdp.4rt.outputfile' 2>&1`
对 `Start-Process` 应用重定向是无意义的,因为它不产生 _任何输出_。
(添加 `-PassThru` 将使其输出一个描述已启动进程的 [`System.Diagnostics.Process`](https://learn.microsoft.com/en-US/dotnet/api/System.Diagnostics.Process) 实例,而不是已启动进程自己的输出)。
> `$LASTEXITCODE`
[`Start-Process`](https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Management/Start-Process) _从不_ 设置 [自动 `$LASTEXITCODE` 变量](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Automatic_Variables#lastexitcode)。
要获取使用 `Start-Process` 启动的进程的退出代码,请添加 `-PassThru`,然后查询返回的 `System.Diagnostics.Process` 实例的 `.ExitCode` 属性 - 假设您首先等待进程终止,要么通过在 `Start-Process` 调用中也传递 `-Wait`,要么通过在 `System.Diagnostics.Process` 上调用 `.WaitForExit()`。
---
因此,重新编写您的临时脚本如下:
```powershell
$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'
注意:
-
完整的脚本路径被传递给
powershell.exe
,没有尝试设置工作目录(您的目标脚本似乎不依赖于任何特定的工作目录)。- 由于完整路径包含 空格,必须将其包含在嵌入的引号中(
`"...`"
),并通过&
,即 调用运算符 进行调用。
- 由于完整路径包含 空格,必须将其包含在嵌入的引号中(
-
使用
-Wait
和-PassThru
使Start-Process
等待提升的进程退出并输出描述它的System.Diagnostics.Process
实例,捕获在变量$pi
中 -
从提升的目标脚本捕获(合并的)输出是作为
powershell.exe
命令的一部分执行的(*> ...
),这恰好是非提升进程捕获提升进程的 stdout 和 stderr 输出的唯一方式 --RedirectStandardOut
和-RedirectStandardError
与-Verb RunAs
不起作用(基本上不允许捕获这两个流的 组合)。
<details>
<summary>英文:</summary>
<!-- language-all: sh -->
> `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+_](https://github.com/PowerShell/PowerShell/blob/master/README.md) 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`](https://learn.microsoft.com/en-US/dotnet/api/System.Diagnostics.Process) instance describing the launched process, _not_ the launched process' own output.)
> `$LASTEXITCODE`
[`Start-Process`](https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Management/Start-Process) _never_ sets the [automatic `$LASTEXITCODE` variable](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Automatic_Variables#lastexitcode).
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).
* Because the full path contains _spaces_, it must be enclosed in embedded quoting (`` `"...`" ``), and invoked via `&`, the [call operator](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Operators#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.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论