点源脚本

发布于 2025-01-25 05:49:36 字数 1016 浏览 2 评论 0 原文

我有一个自言自语的摘要,所以我决定,而不是在每个需要运行的脚本的顶部复制它,以将其移至一个单独的.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
        }
    }
}

因此,对于每个需要高程的脚本,我都会预先

. "$PSScriptRoot\self-elevate.ps1"
Switch-ToAdmin
# rest of script

执行以上成功成功地执行了UAC提示,但其余的脚本不会被执行。 这是不允许的吗?

I have a self elevate snippet which is quite wordy, so I decided instead of duplicating it at the top of every script that needs to be run as admin to move it into a separate .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
        }
    }
}

So for every script that needs elevation I'd prepend

. "$PSScriptRoot\self-elevate.ps1"
Switch-ToAdmin
# rest of script

Doing above successfully procs the UAC prompt, but the rest of the script won't get executed.
Is this sorta stuff disallowed?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沦落红尘 2025-02-01 05:49:36

darin 已经提供了关键的指针:

  • darin指出 自动 $ pscommandpath accoviable switch> switch toadmin function中的变量该函数称为的脚本的完整路径,但即使该脚本的定义是直接加载了 定义的脚本的完整路径通过进入主脚本的范围#点源操作员 - “ rel =“ nofollow noreferrer”>点源操作员。



    • 同样的同样适用于自动 $ psscriptroot 变量,它反映了定义脚本的完整目录路径。 path。

  • 此外,更一般地,自动 $ PSBOUNDPARAMETERS 变量在函数内部反映 该函数的绑定参数,而不是其封闭 script 'S。


  • 铁指出 cmdlet 可用于获取有关脚本的呼叫者 的信息,从索引开始代码>;返回的第一个对象 - 索引 0 ,当 get -pscallstack 输出在数组中捕获,表示 current 命令。索引 1 因此,请参考即时呼叫者,从点来源的脚本的角度来看是您的主要脚本。


因此:


顺便说一句:

即使 $ psboundParameters 包含预期的信息,“ - $($ psboundparameters.keys)” 只有在您的脚本定义的情况下,才能成功地传递绑定参数仅一个参数,如果该参数为 [switch] 参数,并且在每个调用中实际传递。

在这种情况下,通过鲁棒通过参数很难做到,并且具有固有的局限性 - 参见此答案对于 - 复杂 - 尝试使其尽可能地工作。

Darin and iRon have provided the crucial pointers:

  • Darin points out that the automatic $PSCommandPath variable variable in your Switch-ToAdmin function does not contain the full path of the script from which the function is called, but that of the script in which the function is defined, even if that script's definitions are loaded directly into the scope of your main script via ., the dot-sourcing operator.

    • The same applies analogously to the automatic $PSScriptRoot variable, which reflects the defining script's full directory path.
  • Also, more generally, the automatic $PSBoundParameters variable inside a function reflects that function's bound parameters, not its enclosing script's.

  • iRon points out that the Get-PSCallStack cmdlet can be used to get information about a script's callers, starting at index 1; the first object returned - index 0, when Get-PSCallStack output is captured in an array, represents the current command. Index 1 therefore refers to the immediate caller, which from the perspective of your dot-sourced script is your main script.

Therefore:

  • Replace $PSCommandPath with $MyInvocation.PSCommandPath, via the automatic $MyInvocation variable. $MyInvocation.PSCommandPath truly reflects the caller's full script path, irrespective of where the called function was defined.

    • Alternatively, use (Get-PSCallStack)[1].ScriptName, which despite what the property name suggests, returns the full path of the calling script too.
  • Replace $PSBoundParameters with
    (Get-PSCallStack)[1].InvocationInfo.BoundParameters

    • Note that there's also (Get-PSCallStack)[1].Arguments, but it seems to contain a single string only, containing a representation of all arguments that is only semi-structured and therefore doesn't allow robust reconstruction of the individual parameters.

As an aside:

Even if $PSBoundParameters contained the intended information, "-$($PSBoundParameters.Keys)" would only succeed in passing the bound parameters through if your script defines only one parameter, if that parameter is a [switch] parameter, and if it is actually passed in every invocation.

Passing arguments through robustly in this context is hard to do, and has inherent limitations - see this answer for a - complex - attempt to make it work as well as possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文