1

I have a Powershell script with parameters that I'd like to be able to self-elevate.

[CmdletBinding()]
param (
    [Parameter(ParameterSetName="cp")]
    [Switch]
    $copy = $false,
    [Parameter(ParameterSetName="mv")]
    [Switch]
    $move = $false
)
# Elevate 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 = (
      '-File',
      "`"$($MyInvocation.MyCommand.Path)`"",
      $MyInvocation.BoundParameters
    )
    $ProcArgs = @{
      FilePath = 'PowerShell.exe'
      Verb = 'RunAs'
      ArgumentList = $Cmd
    }
    Start-Process @ProcArgs
    Exit
  }
}
Set-Location -LiteralPath $PSScriptRoot
Write-Host "$copy"
Pause

If I comment out the param block and run script.ps1 -copy, an elevated Powershell window opens and prints out Press enter to continue, i.e. it works.

If I comment out the if statement, the current window outputs True, i.e. it also works.

If I run the whole thing though, the elevated windows opens for a split second, then closes ignoring Pause with no output anywhere. I want the elevated window to open and print out True.

4
  • The @() is the sub-expression operator, which you don't necessarily need since your arguments in $cmd are already comma separated, but I thought I'd share; because you're using just the regular grouping operator () is why I mention it. Anyways, you can try adding a Start-Transcript and seeing the results. It should capture the error message and output it to a file. Commented Dec 21, 2021 at 12:29
  • You're passing the string System.Management.Automation.PSBoundParametersDictionary as argument instead of passing the actual switch parameter. Commented Dec 21, 2021 at 14:17
  • @AbrahamZinala I use () so I could align the elements vertically. No output in transcript, unfortunately. It just shows script.ps1 -copy Commented Dec 22, 2021 at 1:31
  • @SantiagoSquarzon Thanks for the heads up! I've updated the post. That doesn't solve the problem, unfortunately. Commented Dec 22, 2021 at 1:32

1 Answer 1

1

I tested this on Linux and worked for me but couldn't test on Windows, I don't see other way around having to manipulate the $PSBoundParameters into strings to pass the arguments on -ArgumentList.

Below code is meant to be exclusively for testing, hence why I've removed the if conditions.

[CmdletBinding()]
param (
    [Parameter(ParameterSetName="cp")]
    [Switch]$copy,
    [Parameter(ParameterSetName="mv")]
    [Switch]$move
)

$argument = @(
    "-File $PSCommandPath"    
    "-$($PSBoundParameters.Keys)"
)

$ProcArgs = @{
    FilePath = 'powershell.exe'
    Verb = 'RunAs'
    ArgumentList = $argument
}

Start-Process @ProcArgs

"Started new Process with the argument: -$($PSBoundParameters.Keys)"
[System.Console]::ReadKey()
Exit
Sign up to request clarification or add additional context in comments.

4 Comments

This throws Start-Process : This command cannot be run due to the error: The system cannot find the file specified at line Start-Process @ProcArgs i.imgur.com/bOr9SWD.png
@stackexchange_account1111 right, I forgot to change pwsh with powershell.exe my bad
That worked! It kept creating new elevated window indefinitely, but after I put the if statements back it created an elevated window successfully and passed the parameter. Many thanks.
@stackexchange_account1111 that's right, the script is recursively calling itself, should've mentioned that sorry lol! happy to help :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.