windows - Hvordan kan jeg automatisk hæve min batchfil, så det kræver anmodninger fra UAC administratorrettigheder, hvis det kræves?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg vil have, at min batchfil kun kører forhøjet. Hvis ikke forhøjet, giv brugeren mulighed for at genstarte batch som forhøjet.


Jeg skriver en batch-fil for at indstille en systemvariabel, kopiere to filer til en Programfiler -sted, og start et driverinstallationsprogram. Hvis en Windows   7/Windows   Vista-bruger (UAC aktiveret og lige hvis de er en lokal administrator) kører det uden at højreklikke og vælger 'Kør som administrator', får de 'Access Denied', kopierer de to filer og skriver systemvariablen. [56]


Jeg vil gerne bruge en kommando til automatisk at genstarte batchen som forhøjet, hvis brugeren faktisk er en administrator. Ellers vil jeg, hvis de ikke er administrator, fortælle dem, at de har brug for administratorrettigheder til at køre batchfilen. Jeg bruger xcopy til at kopiere filerne og REG ADD for at skrive systemvariablen. Jeg bruger disse kommandoer til at håndtere mulige Windows   XP-maskiner. Jeg har fundet lignende spørgsmål om dette emne, men intet der beskæftiger sig med relancering af en batchfil som forhøjet.

Bedste reference


Du kan få scriptet til at kalde sig selv med psexec s -h mulighed for at løbe højt. [57]


Jeg er ikke sikker på, hvordan du vil opdage, om den allerede kører som forhøjet eller ej ... måske prøv igen med forhøjede perms, hvis der er en Access Denied-fejl?


Eller du kan bare have kommandoer til xcopy og reg.exe altid kørt med psexec -h, men det ville være irriterende for slutbrugeren, hvis de skal indtaste deres adgangskode hver gang (eller usikker hvis du inkluderede adgangskoden i scriptet) ...

Andre referencer 1


Der er en nem måde uden brug af et eksternt værktøj. Det går fint med Windows 7, 8, 8.1 og 10 og er også bakudkompatibel (Windows XP har ikke nogen UAC , således er højden ikke nødvendig - i så fald fortsætter scriptet bare).


Tjek denne kode (jeg blev inspireret af koden af ​​NIronwolf, der blev indsendt i tråden Batchfil - 'Access nægtet' i Windows 7? ), men jeg har forbedret det - i min version er der ikke ' t enhver mappe oprettet og fjernet for at tjekke for administratorrettigheder): [58]




::::::::::::::::::::::::::::::::::::::::::::
:: Elevate.cmd - Version 4
:: Automatically check & get admin rights
::::::::::::::::::::::::::::::::::::::::::::
 @echo off
 CLS
 ECHO.
 ECHO =============================
 ECHO Running Admin shell
 ECHO =============================

:init
 setlocal DisableDelayedExpansion
 set cmdInvoke=1
 set winSysFolder=System32
 set "batchPath=\%~0"
 for \%\%k in (\%0) do set batchName=\%\%~nk
 set "vbsGetPrivileges=\%temp\%OEgetPriv\_\%batchName\%.vbs"
 setlocal EnableDelayedExpansion

:checkPrivileges
  NET FILE 1>NUL 2>NUL
  if '\%errorlevel\%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges )

:getPrivileges
  if '\%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges)
  ECHO.
  ECHO **************************************
  ECHO Invoking UAC for Privilege Escalation
  ECHO **************************************

  ECHO Set UAC = CreateObject^("Shell.Application"^) > "\%vbsGetPrivileges\%"
  ECHO args = "ELEV " >> "\%vbsGetPrivileges\%"
  ECHO For Each strArg in WScript.Arguments >> "\%vbsGetPrivileges\%"
  ECHO args = args ^& strArg ^& " "  >> "\%vbsGetPrivileges\%"
  ECHO Next >> "\%vbsGetPrivileges\%"

  if '\%cmdInvoke\%'=='1' goto InvokeCmd 

  ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "\%vbsGetPrivileges\%"
  goto ExecElevation

:InvokeCmd
  ECHO args = "/c """ + "!batchPath!" + """ " + args >> "\%vbsGetPrivileges\%"
  ECHO UAC.ShellExecute "\%SystemRoot\%\%winSysFolder\%cmd.exe", args, "", "runas", 1 >> "\%vbsGetPrivileges\%"

:ExecElevation
 "\%SystemRoot\%\%winSysFolder\%WScript.exe" "\%vbsGetPrivileges\%" \%*
 exit /B

:gotPrivileges
 setlocal & cd /d \%~dp0
 if '\%1'=='ELEV' (del "\%vbsGetPrivileges\%" 1>nul 2>nul  &  shift /1)

 ::::::::::::::::::::::::::::
 ::START
 ::::::::::::::::::::::::::::
 REM Run shell as admin (example) - put here code as you like
 ECHO \%batchName\% Arguments: P1=\%1 P2=\%2 P3=\%3 P4=\%4 P5=\%5 P6=\%6 P7=\%7 P8=\%8 P9=\%9
 cmd /k


Skriptet udnytter den kendsgerning, at NET FILE kræver administratorrettigheder og returnerer errorlevel 1, hvis du ikke har det. Højningen opnås ved at oprette et script, der genstarter batchfilen for at opnå privilegier. Dette får Windows til at præsentere UAC-dialogen og beder dig om administratorkonto og adgangskode.


Jeg har testet det med Windows   7, 8, 8.1, 10 og med Windows   XP - det virker fint for alle.
Fordelen er, at efter startpunktet kan du placere alt, der kræver systemadministratorrettigheder, for eksempel hvis du har til hensigt at geninstallere og genstarte en Windows-tjeneste til fejlfinding (antages at mypackage.msi er en serviceinstallationspakke) :


msiexec /passive /x mypackage.msi
msiexec /passive /i mypackage.msi
net start myservice


UAC vil ikke spørge dig tre gange for din administratorbruger og adgangskode - nu du bliver bedt om en gang i starten, og kun hvis det kræves.





Hvis dit script bare skal vise en fejlmeddelelse og afslutte, hvis der ikke er nogen administratorrettigheder i stedet for automatisk hævning, er det endnu enklere: Du kan opnå dette ved at tilføje følgende i begyndelsen af dit script:


@ECHO OFF & CLS & ECHO.
NET FILE 1>NUL 2>NUL & IF ERRORLEVEL 1 (ECHO You must right-click and select &
  ECHO "RUN AS ADMINISTRATOR"  to run this batch. Exiting... & ECHO. &
  PAUSE & EXIT /D)
REM ... proceed here with admin rights ...


På denne måde skal brugeren højreklikke og vælge 'Kør som administrator'. Scriptet fortsætter efter REM erklæringen, hvis det registrerer administratorrettigheder, ellers afslut med en fejl. Hvis du ikke kræver PAUSE, skal du bare fjerne den.
Vigtigt: NET FILE [...] EXIT /D) skal være på samme linje. Det vises her i flere linjer for bedre læsbarhed!





På nogle maskiner har jeg haft problemer, der allerede er løst i den nye version ovenfor. En skyldes forskellige dobbeltkvoter, og det andet problem skyldtes, at UAC var deaktiveret (sat til laveste niveau) på en Windows   7 maskine, derfor kalder scriptet igen og igen.


Jeg har rettet dette nu ved at fjerne citaterne i stien og geninstallere dem senere, og jeg har tilføjet en ekstra parameter, der tilføjes, når scriptet genstarter med forhøjede rettigheder.


De dobbelte citater fjernes af følgende (detaljer er her):


setlocal DisableDelayedExpansion
set "batchPath=\%~0"
setlocal EnableDelayedExpansion


Du kan derefter få adgang til stien ved hjælp af !batchPath!. Det indeholder ikke nogen dobbelt citater, så det er sikkert at sige "!batchPath!" senere i scriptet.


Linjen


if '\%1'=='ELEV' (shift & goto gotPrivileges)


Kontrollerer, om scriptet allerede er blevet kaldt af VBScript-scriptet for at hæve rettigheder, og dermed undgå endeløse rekursioner. Det fjerner parameteren ved hjælp af shift. [60]





Opdatering:



  • For at undgå at registrere .vbs udvidelsen i Windows 10 , har jeg erstattet linjen

    "\%temp\%OEgetPrivileges.vbs"

    ved

    "\%SystemRoot\%System32WScript.exe" "\%temp\%OEgetPrivileges.vbs"

    i scriptet ovenfor; tilføjede også cd /d \%~dp0 som foreslået af Stephen (separat svar) og af Tomáš Zato (kommentar) for at indstille manuskatalog som standard.

  • Nu skriptet hedder kommandolinjeparametre, der sendes til det. Takket være jxmallet, TanisDLJ og Peter Mortensen til observationer og inspirationer.

  • I henhold til Artjom B.'s antydning analyserede jeg det og erstattede SHIFT med SHIFT /1, som bevarer filnavnet til parameteren \%0

  • Tilføjet del "\%temp\%OEgetPrivileges\_\%batchName\%.vbs" til sektionen :gotPrivileges for at rydde op (som foreslået mlt). Tilføjet \%batchName\% for at undgå konsekvenser, hvis du kører forskellige batcher parallelt. Bemærk at du skal bruge for for at kunne udnytte de avancerede strengfunktioner, som f.eks. \%\%~nk, som kun uddrager filnavnet.

  • Optimeret scriptstruktur, forbedringer (tilføjet variabel vbsGetPrivileges, som nu henvises overalt, så det nemt kan ændre stien eller navnet på filen, kun slet .vbs fil, hvis partiet skal hæves)

  • I nogle tilfælde blev der krævet en anden kaldende syntax til elevation. Hvis scriptet ikke virker, skal du kontrollere følgende parametre:

     set cmdInvoke=0

     set winSysFolder=System32

    Du kan enten ændre 1. parameter til set cmdInvoke=1 og kontrollere, om det allerede løser problemet. Det vil tilføje cmd.exe til scriptet, der udfører højden.

    Eller prøv at ændre 2. parameter til winSysFolder=Sysnative, dette kan hjælpe (men er i de fleste tilfælde ikke nødvendigt) på 64 bit systemer. (ADBailey har rapporteret dette). 'Sysnative' er kun nødvendig for at starte 64-bit applikationer fra en 32-bit script host (for eksempel en Visual Studio build proces eller script invokation fra en anden 32-bit applikation).

  • For at gøre det mere klart, hvordan parametrene fortolkes, viser jeg det nu som P1=value1 P2=value2 ... P9=value9. Dette er især nyttigt, hvis du skal vedhæfte parametre som stier i dobbelt citater, f.eks. "C:Program Files".


Andre referencer 2


Som jcoder og Matt nævnte, gjorde PowerShell det nemt, og det kunne endda være integreret i batch script uden at skabe et nyt script.


Jeg modificerede Matt's script:


:checkPrivileges 
NET FILE 1>NUL 2>NUL
if '\%errorlevel\%' == '0' ( goto gotPrivileges 
) else ( powershell "saps -filepath \%0 -verb runas" >nul 2>&1)
exit /b 


Der er ikke noget behov for :getPrivileges mærket.

Andre referencer 3


Jeg bruger Matts fremragende svar, men jeg ser en forskel mellem mine Windows   7 og Windows &Nbsp; 8-systemer, når du kører forhøjede scripts.


Når scriptet er hævet på Windows   8, er den aktuelle mappe indstillet til C:Windowssystem32. Heldigvis er der en nem løsning ved at ændre den aktuelle mappe til stien til det aktuelle script:


cd /d \%~dp0


Bemærk: Brug cd /d for at sikre, at drevbogstav også ændres.


For at teste dette kan du kopiere følgende til et script. Kør normalt på begge versioner for at se det samme resultat. Kør som Admin og se forskellen i Windows   8:


@echo off
echo Current path is \%cd\%
echo Changing directory to the path of the current script
cd \%~dp0
echo Current path is \%cd\%
pause

Andre referencer 4


Jeg gør det på denne måde:


NET SESSION
IF \%ERRORLEVEL\% NEQ 0 GOTO ELEVATE
GOTO ADMINTASKS

:ELEVATE
CD /d \%~dp0
MSHTA "javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('\%~nx0', '', '', 'runas', 1);close();"
EXIT

:ADMINTASKS
(Do whatever you need to do here)
EXIT


På denne måde er det enkelt og kun brug Windows standardkommandoer.
Det er fantastisk, hvis du skal omfordele din batchfil.


CD /d \%~dp0 Indstiller den aktuelle mappe til filens aktuelle mappe (hvis det ikke allerede er, uanset hvilket drev filen er i, takket være indstillingen /d.


\%~nx0 Returnerer det aktuelle filnavn med udvidelsen (Hvis du ikke inkluderer udvidelsen, og der er en exe med samme navn i mappen, vil det kalde exe).


Der er så mange svar på dette indlæg, jeg ved ikke engang, om mit svar vil ses.


Anyway, jeg finder denne måde enklere end de andre løsninger foreslået på de andre svar, jeg håber det hjælper nogen.

Andre referencer 5


Matt har et godt svar, men det fjerner alle argumenter, der sendes til scriptet. Her er min ændring, der holder argumenter. Jeg har også indarbejdet Stephen 's fix for work directory problem i Windows 8.


@ECHO OFF
setlocal EnableDelayedExpansion

NET FILE 1>NUL 2>NUL
if '\%errorlevel\%' == '0' ( goto START ) else ( goto getPrivileges ) 

:getPrivileges
if '\%1'=='ELEV' ( goto START )

set "batchPath=\%~f0"
set "batchArgs=ELEV"

::Add quotes to the batch path, if needed
set "script=\%0"
set script=\%script:"=\%
IF '\%0'=='!script!' ( GOTO PathQuotesDone )
    set "batchPath=""\%batchPath\%"""
:PathQuotesDone

::Add quotes to the arguments, if needed.
:ArgLoop
IF '\%1'=='' ( GOTO EndArgLoop ) else ( GOTO AddArg )
    :AddArg
    set "arg=\%1"
    set arg=\%arg:"=\%
    IF '\%1'=='!arg!' ( GOTO NoQuotes )
        set "batchArgs=\%batchArgs\% "\%1""
        GOTO QuotesDone
        :NoQuotes
        set "batchArgs=\%batchArgs\% \%1"
    :QuotesDone
    shift
    GOTO ArgLoop
:EndArgLoop

::Create and run the vb script to elevate the batch file
ECHO Set UAC = CreateObject^("Shell.Application"^) > "\%temp\%OEgetPrivileges.vbs"
ECHO UAC.ShellExecute "cmd", "/c ""!batchPath! !batchArgs!""", "", "runas", 1 >> "\%temp\%OEgetPrivileges.vbs"
"\%temp\%OEgetPrivileges.vbs" 
exit /B

:START
::Remove the elevation tag and set the correct working directory
IF '\%1'=='ELEV' ( shift /1 )
cd /d \%~dp0

::Do your adminy thing here...

Andre referencer 6


Jeg bruger PowerShell til at genstarte scriptet forhøjet, hvis det ikke er tilfældet. Sæt disse linjer øverst på dit script.


net file 1>nul 2>nul && goto :run || powershell -ex unrestricted -Command "Start-Process -Verb RunAs -FilePath '\%comspec\%' -ArgumentList '/c \%~fnx0 \%*'"
goto :eof
:run
:: TODO: Put code here that needs elevation


Jeg kopierede 'netnavnet' -metoden fra @ Matt's svar. Hans svar er meget bedre dokumenteret og har fejlmeddelelser og lignende. Dette har den fordel, at PowerShell allerede er installeret og tilgængelig på Windows 7 og op. Ingen midlertidig VBScript (* .vbs) filer, og du behøver ikke downloade værktøjer.


Denne metode skal fungere uden nogen konfiguration eller opsætning, så længe dine PowerShell-eksekveringsrettigheder ikke er låst.

Andre referencer 7


For nogle programmer vil den superhemmelige \_\_COMPAT\_LAYER miljøvariabel til RunAsInvoker fungere. Check dette: [62]


set "\_\_COMPAT\_LAYER=RunAsInvoker"
start regedit.exe


Selv om dette ikke er tilfældet, vil UAC få besked om, at brugeren vil fortsætte uden administratorrettigheder.

Andre referencer 8


Jeg indsatte dette i begyndelsen af ​​scriptet:


:: BatchGotAdmin
:-------------------------------------
REM  --> Check for permissions
>nul 2>&1 "\%SYSTEMROOT\%system32icacls.exe" "\%SYSTEMROOT\%system32configsystem"

REM --> If error flag set, we do not have admin.
if '\%errorlevel\%' NEQ '0' (
    echo Requesting administrative privileges...
    goto UACPrompt
) else ( goto gotAdmin )

:UACPrompt
    echo Set UAC = CreateObject^("Shell.Application"^) > "\%temp\%getadmin.vbs"
    echo args = "" >> "\%temp\%getadmin.vbs"
    echo For Each strArg in WScript.Arguments >> "\%temp\%getadmin.vbs"
    echo args = args ^& strArg ^& " "  >> "\%temp\%getadmin.vbs"
    echo Next >> "\%temp\%getadmin.vbs"
    echo UAC.ShellExecute "\%~s0", args, "", "runas", 1 >> "\%temp\%getadmin.vbs"

    "\%temp\%getadmin.vbs" \%*
    exit /B

:gotAdmin
    if exist "\%temp\%getadmin.vbs" ( del "\%temp\%getadmin.vbs" )
    pushd "\%CD\%"
    CD /D "\%~dp0"
:--------------------------------------

Andre referencer 9


Følgende løsning er ren og fungerer perfekt.



  1. Download Løft zip-fil fra https://www.winability.com/download/Elevate.zip[63]

  2. Inde i zip skal du finde to filer: Elevate.exe og Elevate64.exe. (Sidstnævnte er en native 64-bit compilation, hvis du har brug for det, selvom den almindelige 32-bit version Elevate.exe skal fungere fint med både 32- og 64-bit versioner af Windows)

  3. Kopier filen Elevate.exe til en mappe, hvor Windows altid kan finde den (f.eks. C:/Windows). Eller du bedre kan du kopiere i samme mappe, hvor du planlægger at holde din flagermusfil.

  4. For at bruge det i en batchfil, skal du blot udføre den kommando, du vil udføre som administrator med elevatorkommandoen, som denne:




 elevate net start service ...