您知道如果您是系统的管理员用户,您可以右键单击一个批处理脚本,然后以管理员身份运行它,而无需输入管理员密码?

我想知道如何用PowerShell脚本做到这一点。我不想输入我的密码;我只是想模仿右键单击Run As Administrator方法。

到目前为止,我读到的所有内容都要求您提供管理员密码。


当前回答

@pgk和@Andrew Odri的回答的问题是当您有脚本参数时,特别是当它们是强制性的时。可以通过以下方法解决此问题:

用户右键单击.ps1文件并选择“使用PowerShell运行”:通过输入框向他询问参数(这是比使用HelpMessage参数属性更好的选择); 用户通过控制台执行脚本:允许他传递所需的参数,并让控制台强制他通知必须的参数。

下面是如何将是代码,如果脚本有计算机名和端口强制参数:

[CmdletBinding(DefaultParametersetName='RunWithPowerShellContextMenu')]
param (
    [parameter(ParameterSetName='CallFromCommandLine')]
    [switch] $CallFromCommandLine,

    [parameter(Mandatory=$false, ParameterSetName='RunWithPowerShellContextMenu')]
    [parameter(Mandatory=$true, ParameterSetName='CallFromCommandLine')]
    [string] $ComputerName,

    [parameter(Mandatory=$false, ParameterSetName='RunWithPowerShellContextMenu')]
    [parameter(Mandatory=$true, ParameterSetName='CallFromCommandLine')]
    [UInt16] $Port
)

function Assert-AdministrativePrivileges([bool] $CalledFromRunWithPowerShellMenu)
{
    $isAdministrator = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

    if ($isAdministrator)
    {
        if (!$CalledFromRunWithPowerShellMenu -and !$CallFromCommandLine)
        {
            # Must call itself asking for obligatory parameters
            & "$PSCommandPath" @script:PSBoundParameters -CallFromCommandLine
            Exit
        }
    }
    else
    {
        if (!$CalledFromRunWithPowerShellMenu -and !$CallFromCommandLine)
        {
            $serializedParams = [Management.Automation.PSSerializer]::Serialize($script:PSBoundParameters)

            $scriptStr = @"
                `$serializedParams = '$($serializedParams -replace "'", "''")'

                `$params = [Management.Automation.PSSerializer]::Deserialize(`$serializedParams)

                & "$PSCommandPath" @params -CallFromCommandLine
"@

            $scriptBytes = [System.Text.Encoding]::Unicode.GetBytes($scriptStr)
            $encodedCommand = [Convert]::ToBase64String($scriptBytes)

            # If this script is called from another one, the execution flow must wait for this script to finish.
            Start-Process -FilePath 'powershell' -ArgumentList "-ExecutionPolicy Bypass -NoProfile -EncodedCommand $encodedCommand" -Verb 'RunAs' -Wait
        }
        else
        {
            # When you use the "Run with PowerShell" feature, the Windows PowerShell console window appears only briefly.
            # The NoExit option makes the window stay visible, so the user can see the script result.
            Start-Process -FilePath 'powershell' -ArgumentList "-ExecutionPolicy Bypass -NoProfile -NoExit -File ""$PSCommandPath""" -Verb 'RunAs'
        }

        Exit
    }
}

function Get-UserParameters()
{
    [string] $script:ComputerName = [Microsoft.VisualBasic.Interaction]::InputBox('Enter a computer name:', 'Testing Network Connection')

    if ($script:ComputerName -eq '')
    {
        throw 'The computer name is required.'
    }

    [string] $inputPort = [Microsoft.VisualBasic.Interaction]::InputBox('Enter a TCP port:', 'Testing Network Connection')

    if ($inputPort -ne '')
    {
        if (-not [UInt16]::TryParse($inputPort, [ref]$script:Port))
        {
            throw "The value '$inputPort' is invalid for a port number."
        }
    }
    else
    {
        throw 'The TCP port is required.'
    }
}

# $MyInvocation.Line is empty in the second script execution, when a new powershell session
# is started for this script via Start-Process with the -File option.
$calledFromRunWithPowerShellMenu = $MyInvocation.Line -eq '' -or $MyInvocation.Line.StartsWith('if((Get-ExecutionPolicy')

Assert-AdministrativePrivileges $calledFromRunWithPowerShellMenu

# Necessary for InputBox
[System.Reflection.Assembly]::Load('Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') | Out-Null

if ($calledFromRunWithPowerShellMenu)
{
    Get-UserParameters
}

# ... script code
Test-NetConnection -ComputerName $ComputerName -Port $Port

其他回答

要将命令的输出附加到包含当前日期的文本文件名,可以这样做:

$winupdfile = 'Windows-Update-' + $(get-date -f MM-dd-yyyy) + '.txt'
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -Command `"Get-WUInstall -AcceptAll | Out-File $env:USERPROFILE\$winupdfile -Append`"" -Verb RunAs; exit } else { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -Command `"Get-WUInstall -AcceptAll | Out-File $env:USERPROFILE\$winupdfile -Append`""; exit }

使用

#需要-RunAsAdministrator

还没有声明。它似乎是从PowerShell 4.0开始出现的。

http://technet.microsoft.com/en-us/library/hh847765.aspx

当这个switch参数被添加到require语句时, 它指定您所在的Windows PowerShell会话 运行脚本时必须使用提升的用户权限 (以管理员身份运行)。

对我来说,这似乎是一个很好的方法,但我还不确定现场经验。PowerShell 3.0运行时可能会忽略这一点,甚至更糟,会给出一个错误。

当脚本以非管理员身份运行时,会给出以下错误:

脚本“StackOverflow.”Ps1 '不能运行,因为它包含 以管理员身份运行的“#requires”语句。当前的 Windows PowerShell会话没有以管理员身份运行。开始 Windows PowerShell使用“以管理员身份运行”选项,然后 尝试再次运行脚本。 + CategoryInfo: PermissionDenied:(StackOverflow.ps1:String) [], ParentContainsErrorRecordException + fullyqualifiederrid: ScriptRequiresElevation

这种行为是经过设计的。因为微软真的不想让.ps1文件成为最新的电子邮件病毒,所以有多层安全措施。有些人认为这与任务自动化的概念相悖,这是公平的。Vista+安全模型是“去自动化”的,这样用户就可以接受。

但是,我怀疑如果你启动powershell本身作为提升,它应该能够运行批处理文件,而不需要再次要求密码,直到你关闭powershell。

加上我的意见。我的简单版本基于net session,到目前为止一直在Windows 7 / Windows 10中工作。为什么要过于复杂呢?

if (!(net session)) {$path =  "& '" + $myinvocation.mycommand.definition + "'" ; Start-Process powershell -Verb runAs -ArgumentList $path ; exit}

只需添加到脚本顶部,它将以管理员身份运行。

我最近需要在ansible上建立一个环境。我说马上——决定权不在我,但我不记得是从哪里得到的。是这样的:

powershell.exe -NoProfile -ExecutionPolicy Unrestricted -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Unrestricted -Command Get-Service -Name ssh-agent | Set-Service -StartupType Automatic' -Verb RunAs}";

本示例启用ssh-agent自动启动。 所需的命令在-Command后指定。唯一的问题是启动发生在一个新的PS实例上,但到目前为止,这是我所知道的以管理员身份执行命令而不需要额外步骤的唯一方法。