2

I'm writing a PowerShell script that uses parameters / arguments and needs to be run as administrator but I'm trying to make it as user-friendly as possible so I'm trying to write it so that if it wasn't run as administrator then it can auto-elevate itself and preserve the original parameters (only switches and strings).

I was not able to find a solution online, hence this post.

mythofechelon
  • 3,692
  • 11
  • 37
  • 48
  • Possible duplicate of [Running a command as Administrator using PowerShell?](https://stackoverflow.com/questions/7690994/running-a-command-as-administrator-using-powershell) – iRon Aug 22 '19 at 15:35
  • @iRon That method doesn't preserve parameters. – mythofechelon Aug 23 '19 at 09:19
  • Agree, although it is touched in several comments, none of the answers actually covers this (retracted my `close`). I think it is appropriate to make a referral to this [Running a command as Administrator using PowerShell?](https://stackoverflow.com/questions/7690994/running-a-command-as-administrator-using-powershell) duplicate in your question (`+1` from me if you do). Below is my answer. – iRon Aug 25 '19 at 10:28

2 Answers2

3

I managed to accomplish this by "stringifying" $PsBoundParameters then using that with Start-Process PowerShell -Verb Runas -ArgumentList.

Note: $PsBoundParameters uses the parameters of the current scope ("root" vs inside a function, for example) so if you need to reference the command-line parameters (as I do) then you'll need to either use this variable outside of a function or first pass the variable to the function (as I've done here).

I've created a demonstration of this:

Param(
    [switch]$ExampleSwitch,
    [string]$ExampleString
)

Function Restart ($AllParameters, $Admin) {
    $AllParameters_String = "";
    ForEach ($Parameter in $AllParameters.GetEnumerator()){
        $Parameter_Key = $Parameter.Key;
        $Parameter_Value = $Parameter.Value;
        $Parameter_Value_Type = $Parameter_Value.GetType().Name;

        If ($Parameter_Value_Type -Eq "SwitchParameter"){
            $AllParameters_String += " -$Parameter_Key";
        } Else {
            $AllParameters_String += " -$Parameter_Key $Parameter_Value";
        }
    }

    $Arguments = "-File `"" + $PSCommandPath + "`" -NoExit" + $AllParameters_String;

    If ($Admin -Eq $True){
        Start-Process PowerShell -Verb Runas -ArgumentList $Arguments;
    } Else {        
        Start-Process PowerShell -ArgumentList $Arguments;
    }
}

$RanAsAdministrator = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator);

Write-Host "ExampleSwitch value:" $ExampleSwitch;
Write-Host "ExampleString value:" $ExampleString;
Write-Host "";

If ($RanAsAdministrator -Eq $True){
    Write-Host "Running as administrator: Yes.";
} Else {
    Write-Host "Running as administrator: No.";
}

$Elevate = Read-Host "Restart as current user or admin? (u/a)";
Write-Host "";

If ($Elevate -Like "u"){
    Restart $PsBoundParameters;
} ElseIf ($Elevate -Like "a") {
    Restart $PsBoundParameters -Admin $True;
}

Start-Sleep -Seconds 9999;
mythofechelon
  • 3,692
  • 11
  • 37
  • 48
  • This fails if a parameter contains a string with spaces, like: `-ExampleString "Test 123"`, I guess you need to quote your `$Parameter_Value` values. – iRon Aug 25 '19 at 17:54
2
Param(
    [Switch]$MySwitch,
    [String]$MyString,
    [Switch]$NoExit
)

If (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
    $PSHost = If ($PSVersionTable.PSVersion.Major -le 5) {'PowerShell'} Else {'PwSh'}
    Start-Process -Verb RunAs $PSHost (@(' -NoExit')[!$NoExit] + " -File `"$PSCommandPath`" " + ($MyInvocation.Line -split '\.ps1[\s\''\"]\s*', 2)[-1])
    Break
}

Write-Host "MySwitch:" $MySwitch;
Write-Host "MyString:" $MyString;

Explanation:

  • ($MyInvocation.Line -split '\.ps1[\s\''\"]\s*', 2)[-1]) will resolve the current parameters

  • $MyHost determines the current PowerShell Host (PowerShell for Windows or PowerShell Core) and use the same host for the elevated window.

  • The -NoExit switch will prevent the elevated window to automatically close

Example:

.\RunAsAdministrator.ps1 -MyString "Test 123" -MySwitch -NoExit
iRon
  • 20,463
  • 10
  • 53
  • 79