Running a command as Administrator using PowerShell?

后端 未结 26 3371
粉色の甜心
粉色の甜心 2020-11-22 09:41

You know how if you\'re the administrative user of a system and you can just right click say, a batch script and run it as Administrator without entering the administrator p

26条回答
  •  闹比i
    闹比i (楼主)
    2020-11-22 10:03

    The problem with the @pgk and @Andrew Odri's answers is when you have script parameters, specially when they are mandatory. You can solve this problem using the following approach:

    1. The user right-clicks the .ps1 file and selects 'Run with PowerShell': ask him for the parameters through input boxes (this is a much better option than use the HelpMessage parameter attribute);
    2. The user executes the script through the console: allow him to pass the desired parameters and let the console force him to inform the mandatory ones.

    Here is how would be the code if the script had the ComputerName and Port mandatory parameters:

    [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
    

提交回复
热议问题