点源自提升脚本



我有一个self - elevate代码片段,它相当冗长,所以我决定不把它复制到需要以admin身份运行的每个脚本的顶部,而是将其移动到一个单独的。ps1:

function Switch-ToAdmin {
# Self-elevate the script if required
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$Cmd = @(
"-Command Set-Location `"$(Get-Location)`"; & `"$PSCommandPath`""
"-$($PSBoundParameters.Keys)"
)
$ProcArgs = @{
FilePath     = 'PowerShell.exe'
Verb         = 'RunAs'
ArgumentList = $Cmd
}
Start-Process @ProcArgs
Exit
}
}
}

所以对于每个需要提升的脚本我都要加上

. "$PSScriptRootself-elevate.ps1"
Switch-ToAdmin
# rest of script

以上操作成功地处理了UAC提示,但脚本的其余部分不会执行。这类事情是不允许的吗?

Darin和iRon提供了关键的指针:

  • Darin指出(Switch-ToAdmin函数中的自动$PSCommandPath变量变量)包含调用函数的脚本的完整路径,而是包含定义函数的脚本的完整路径,即使该脚本的定义通过.(点源操作符)直接加载到主脚本的作用域。

    • 同样适用于自动$PSScriptRoot变量,它反映了定义脚本的完整目录路径。
  • 而且,更一般地说,函数内部的自动$PSBoundParameters变量反映了函数的绑定参数,而不是其封闭的脚本

  • iRon指出Get-PSCallStackcmdlet可用于获取有关脚本调用者的信息,从索引1开始;当在数组中捕获Get-PSCallStack输出时,返回的第一个对象- index0表示当前命令。因此,索引1引用直接调用者,从点源脚本的角度来看,它是主脚本。

  • 因此:

  • $PSCommandPath替换为$MyInvocation.PSCommandPath,通过自动的$MyInvocation变量。$MyInvocation.PSCommandPath真正反映了调用者的完整的脚本路径,而不管被调用的函数是在哪里定义的。

    • 或者,使用(Get-PSCallStack)[1].ScriptName,不管属性名如何,它也会返回调用脚本的完整路径

  • (Get-PSCallStack)[1].InvocationInfo.BoundParameters代替$PSBoundParameters

    • 请注意,也有(Get-PSCallStack)[1].Arguments,但它似乎只包含一个字符串,包含所有参数的表示,只是半结构化的,因此不允许单个参数的鲁棒重建。

作为题外话:

即使$PSBoundParameters包含预期的信息,"-$($PSBoundParameters.Keys)"也只有在脚本只定义一个参数,如果该参数是[switch]参数,并且在每次调用中都实际传递该参数时,才能成功传递绑定的参数。

在这种情况下,通过健壮地传递参数是很难做到的,并且具有固有的局限性-请参阅下面的复杂尝试,以使其尽可能好地工作。

最新更新