PowerShell - Self elevation

highend01

Cadet 4th Year
Registriert
Okt. 2008
Beiträge
85
Hallo,

ich moechte ein PowerShell script starten, welches, wenn es ohne administrative Rechte gestartet wurde, sich selbst noch einmal (diesmal mit administrativen) Rechten neu startet.

Das hier funktioniert leider nicht... Das neue PowerShell Fenster taucht nur fuer einen kurzen Moment auf, bevor es wieder beendet wird. Die Parameter mit denen das script initial aufgerufen wurden sind aber:


PowerShell:
$cmdArgs

-NoProfile
-NoExit
-ExecutionPolicy
ByPass
-File
D:\Users\Highend\Development\PowerShell\Get font metadata.ps1

D.h. wenn die Parameter aus "$params.ArgumentList" korrekt uebergeben worden waeren, waere das neue PowerShell-Fenster offen geblieben (-NoExit). Was laeuft hier schief?

PowerShell:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) {
    $proc    = Get-Process -Id $PID
    $cmdArgs = [Environment]::GetCommandLineArgs() | Select-Object -Skip 1
    $params  = @{ FilePath = $proc.Path }
    $params.Verb = "RunAs"
    if ($cmdArgs) { $params.ArgumentList = $cmdArgs }
    Start-Process @params
    $proc.CloseMainWindow()
}
 
Probier mal (vorsicht! pwsh durch powershell ersetzten, wenn pwsh nicht installiert ist):

PowerShell:
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Start-Process pwsh -Verb RunAs -ArgumentList ( @('-NoProfile','-ExecutionPolicy','Bypass','-File', $PSCommandPath) + $args )
    break
}
 
Danke, aber das ist nicht das, was ich moechte. Manuell die Argumente an die neue Instanz zu uebergeben ist nicht Sinn und Zweck des Ganzen. Ich starte das .ps1 script per script aus einem Dateimanager heraus, vermutlich deswegen ist die interne Variable "$PSCommandPath" leer und die Fehlermeldung lautet dann:

PowerShell:
Start-Process : Cannot validate argument on parameter 'ArgumentList'. The argument is null or empty. Provide an
argument that is not null or empty, and then try the command again.
At line:2 char:60
+ ... rgumentList ( @('-NoProfile','-ExecutionPolicy','Bypass','-File', $PS ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Start-Process], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.StartProcessCommand

Mir geht es darum, alle Initialargumente (egal, welche das sind), an die neue Instanz weiterzugeben.
 
highend01 schrieb:
Mir geht es darum, alle Initialargumente (egal, welche das sind), an die neue Instanz weiterzugeben.
Genau das tut es ja. $args ist ein Array, was die Powershell automatisch anlegt, was alle Argumente enthält.

Bei mir geht das sowohl unter powershell, als auch pwsh.

PowerShell:
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Start-Process powershell -Verb RunAs -ArgumentList ( @('-NoProfile','-ExecutionPolicy','Bypass','-File', $PSCommandPath) + $args )
    break
}

echo $args
timeout /t 120

Kannst du mal erklären, wie genau du das Skript aufrufst und welche powershell Version du verwendest?
 
PSVersion = 5.1.17763.1

$args ist hier leer...

Der Aufruf erfolgt wie gesagt aus einem Dateimanager heraus (XYplorer)...
Code:
    $command = <<<>>>
"powershell.exe" -NoProfile -NoExit -ExecutionPolicy ByPass -File "<curitem>"
    >>>;
    run $command, , 0, 1;
Ein heredoc wird fuer das einfachere quoting verwendet.
 
Muss das denn ein separates Skript sein? Und ist der Rechner in einer Domäne?
Die Powershell macht viel mehr Spaß wenn sie in einer Domäne richtig eingestellt wird und zentrale Module und Skriptpfade nutzt. Dann spart man sich dieses ganze Zeug mit ExecutionPolicy etc.
 
Das ist kein separates script, sondern der erste Block in jedem script, welches zwingend administrative Rechte braucht. Ein "simples" auto-elevation falls das script nur mit eingeschraenkten Rechten gestartet wurde. Der Rechner ist nicht Teil einer Domaene.

Ich weiss jetzt zumindest, woran es liegt: Enthaelt der Name des scripts oder der Pfad in dem es liegt Leerzeichen, schlaegt der Aufruf fehl. Ich versuche es mal mit einem for ueber das array und quote Elemente, welche ein Leerzeichen enthalten...

Ok, das hier funktioniert (hier zumindest):

PowerShell:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) {
    $proc    = Get-Process -Id $PID
    $cmdArgs = [Environment]::GetCommandLineArgs() | Select-Object -Skip 1
    for ($index = 0; $index -lt $cmdArgs.length; $index++) {
        if ($cmdArgs[$index] -match " ") { $cmdArgs[$index] = "`"{0}`"" -f $cmdArgs[$index] }
    }
    $params  = @{ FilePath = $proc.Path }
    $params.Verb = "RunAs"
    if ($cmdArgs) { $params.ArgumentList = $cmdArgs }
    Start-Process @params
    $proc.CloseMainWindow()
}
 
Zuletzt bearbeitet:
highend01 schrieb:
...
Ich weiss jetzt zumindest, woran es liegt: Enthaelt der Name des scripts oder der Pfad in dem es liegt Leerzeichen, schlaegt der Aufruf fehl. Ich versuche es mal mit einem for ueber das array und quote Elemente, welche ein Leerzeichen enthalten...
...

Dann fass die Pfadvariable in "". Dann sollte das Skript damit keine Probleme haben
 
Zurück
Oben