[windows] 배치 파일을 자동으로 상승시켜 필요한 경우 UAC 관리자 권한을 요청하려면 어떻게해야합니까?

배치 파일을 높게 실행하고 싶습니다. 상승하지 않은 경우 사용자가 배치를 상승 된 상태로 다시 시작할 수있는 옵션을 제공하십시오.

시스템 변수를 설정하고 두 파일을 프로그램 파일 위치에 복사 한 다음 드라이버 설치 프로그램을 시작하기 위해 배치 파일을 작성하고 있습니다. Windows 7 / Windows Vista 사용자 ( UAC 사용 가능 및 로컬 관리자 인 경우에도)를 마우스 오른쪽 단추로 클릭하고 “관리자 권한으로 실행”을 선택하지 않고 실행하면 두 파일을 복사하고 시스템 변수를 쓰는 ‘액세스 거부’가 표시됩니다. .

사용자가 실제로 관리자 인 경우 명령을 사용하여 배치를 자동으로 다시 시작하려고합니다. 그렇지 않으면 관리자가 아닌 경우 배치 파일을 실행하려면 관리자 권한이 필요하다고 말하고 싶습니다. xcopy 를 사용 하여 파일을 복사하고 REG ADD 를 사용하여 시스템 변수를 작성합니다. 가능한 Windows XP 컴퓨터를 처리하기 위해 해당 명령을 사용하고 있습니다. 이 주제에서 비슷한 질문을 찾았지만 배치 파일을 다시 시작하는 데 도움이되는 것은 없습니다.



답변

당신은으로 스크립트 호출 자체를 가질 수 psexec에-h옵션이 상승 실행합니다.

액세스 권한 거부 오류가있는 경우에만 높은 권한으로 다시 시도 할 수 있습니까?

또는, 당신은 단순히위한 명령을 가질 수 xcopyreg.exe항상 실행할 수 psexec -h있지만,이 입력에 암호 (스크립트에 암호를 포함하는 경우 또는 안전하지 않은)마다 필요로하는 경우는 최종 사용자에 대한 성가신 것 …


답변

외부 도구를 사용할 필요없이 쉬운 방법이 있습니다 -Windows 7, 8, 8.1 및 10에서 잘 실행되며 이전 버전과도 호환됩니다 (Windows XP에는 UAC가 없으므로 높이가 필요하지 않습니다). 스크립트가 진행됩니다).

이 코드를 확인하십시오 ( Windows 7 의 스레드 배치 파일- “액세스가 거부되었습니다”에 게시 된 NIronwolf의 코드에서 영감을 얻었습니다).하지만 코드를 개선했습니다. 관리자 권한 확인) :

::::::::::::::::::::::::::::::::::::::::::::
:: Elevate.cmd - Version 4
:: Automatically check & get admin rights
:: see "https://stackoverflow.com/a/12264592/1016343" for description
::::::::::::::::::::::::::::::::::::::::::::
 @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

이 스크립트는 NET FILE관리자 권한 이 필요 하다는 사실을 활용 하고 errorlevel 1없는 경우 반환 합니다. 권한 상승을 위해 배치 파일을 다시 시작하는 스크립트를 작성하면 권한이 상승됩니다. 이로 인해 Windows가 UAC 대화 상자를 표시하고 관리자 계정과 암호를 묻습니다.

Windows 7, 8, 8.1, 10 및 Windows XP에서 테스트했습니다. 모두 잘 작동합니다. 장점은 시작 지점 후에 디버깅 목적으로 Windows 서비스를 다시 설치하고 다시 실행하려는 경우 (예 : mypackage.msi가 서비스 설치 프로그램 패키지 인 경우) 시스템 관리자 권한이 필요한 항목을 배치 할 수 있다는 것입니다. :

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

이 권한 상승 스크립트가 없으면 UAC는 관리자와 암호를 세 번 묻습니다. 이제 처음에는 한 번만 요청하고 필요한 경우에만 요청합니다.


자동 상승 대신 관리자 권한이없는 경우 스크립트에 오류 메시지 만 표시하고 종료해야하는 경우 훨씬 간단합니다. 스크립트 시작 부분에 다음을 추가하면됩니다.

@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 ...

이런 식으로 사용자는 마우스 오른쪽 버튼을 클릭하고 “관리자 권한으로 실행”을 선택해야 합니다. 스크립트 REM는 관리자 권한이 감지되면 명령문 다음에 진행 되고 그렇지 않으면 오류와 함께 종료됩니다. 이 필요하지 않은 경우 PAUSE제거하십시오.
중요 : NET FILE [...] EXIT /D) 같은 줄에 있어야합니다. 가독성을 높이기 위해 여기에 여러 줄로 표시됩니다!


일부 컴퓨터에서는 위의 새 버전에서 이미 해결 된 문제가 발생했습니다. 하나는 다른 큰 따옴표 처리로 인한 것이고 다른 하나는 Windows 7 컴퓨터에서 UAC가 비활성화 (최저 수준으로 설정)되어 스크립트가 계속해서 자신을 호출하기 때문입니다.

경로에서 따옴표를 제거하고 나중에 다시 추가 하여이 문제를 해결했으며 스크립트가 높은 권한으로 다시 시작될 때 추가되는 추가 매개 변수를 추가했습니다.

큰 따옴표는 다음에 의해 제거됩니다 (자세한 내용은 여기 ) :

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

그런 다음을 사용하여 경로에 액세스 할 수 있습니다 !batchPath!. 큰 따옴표가 포함되어 있지 않으므로 "!batchPath!"나중에 스크립트에서 말하는 것이 안전합니다 .

라인

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

VBScript 스크립트 가 스크립트를 이미 호출하여 권한을 높이고 있는지 확인하여 끝없는 재귀를 피합니다. 를 사용하여 매개 변수를 제거합니다 shift.


최신 정보:

  • Windows 10 에서 .vbs확장명 을 등록하지 않으려면 위의 스크립트에서 줄 을 바꿨습니다. 또한 스크립트 디렉토리를 기본값으로 설정하기 위해 Stephen (별도의 답변)과 Tomáš Zato (의견)에서 제안한대로 추가 되었습니다.
    "%temp%\OEgetPrivileges.vbs"

    "%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"

    cd /d %~dp0

  • 이제 스크립트는 명령 행 매개 변수를 전달합니다. 관찰과 영감을 주신 jxmallet, TanisDLJ 및 Peter Mortensen에게 감사합니다.

  • Artjom B.의 힌트에 따르면, 나는 그것을 분석 하고 매개 변수 의 파일 이름을 유지하는 로 대체 SHIFT했습니다 SHIFT /1.%0

  • 추가 del "%temp%\OEgetPrivileges_%batchName%.vbs"받는 사람 :gotPrivileges(같은 부분은 정리하는 MLT가 제안). %batchName%다른 배치를 병렬로 실행할 경우 영향을 피하기 위해 추가되었습니다 . 파일 이름 만 추출하는 for등의 고급 문자열 함수 를 이용하려면 사용해야 합니다 %%~nk.

  • 최적화 된 스크립트 구조, 개선 ( vbsGetPrivileges파일의 경로 나 이름을 쉽게 변경할 수있는 모든 곳에서 참조되는 추가 된 변수 , .vbs배치를 늘려야 할 경우 에만 파일 삭제 )

  • 경우에 따라 고도에 다른 호출 구문이 필요했습니다. 스크립트가 작동하지 않으면 다음 매개
    set cmdInvoke=0
    set winSysFolder=System32
    변수를 set cmdInvoke=1확인하십시오 . 첫 번째 매개 변수를로 변경하고 이미 문제가 해결되었는지 확인하십시오. cmd.exe고도를 수행하는 스크립트에 추가 됩니다.
    또는 두 번째 매개 변수를로 변경하면 winSysFolder=Sysnative64 비트 시스템에서 도움이 될 수 있지만 대부분의 경우 필요하지는 않습니다. (ADBailey가이를보고했습니다). “Sysnative”는 32 비트 스크립트 호스트 (예 : Visual Studio 빌드 프로세스 또는 다른 32 비트 응용 프로그램에서 스크립트 호출)에서 64 비트 응용 프로그램을 시작하는 경우에만 필요합니다.

  • 매개 변수가 어떻게 해석되는지 더 명확하게하기 위해 다음과 같이 표시합니다 P1=value1 P2=value2 ... P9=value9. 경로와 같은 매개 변수를 큰 따옴표로 묶어야하는 경우에 특히 유용합니다 (예 🙂 "C:\Program Files".

  • VBS 스크립트를 디버깅하려는 경우 여기에//X 제안 된대로 첫 번째 매개 변수로 WScript.exe에 매개 변수를 추가 할 수 있습니다 (CScript.exe에 대해 설명되어 있지만 WScript.exe에서도 작동 함).

유용한 링크:


답변

jcoder와 Matt이 언급했듯이 PowerShell은 쉽게 만들었으며 새 스크립트를 만들지 않고도 배치 스크립트에 포함시킬 수도 있습니다.

Matt의 스크립트를 수정했습니다.

:: Check privileges
net file 1>NUL 2>NUL
if not '%errorlevel%' == '0' (
    powershell Start-Process -FilePath "%0" -ArgumentList "%cd%" -verb runas >NUL 2>&1
    exit /b
)

:: Change directory with passed argument. Processes started with
:: "runas" start with forced C:\Windows\System32 workdir
cd /d %1

:: Actual work


답변

Matt의 훌륭한 답변을 사용하고 있지만 고급 스크립트를 실행할 때 Windows 7과 Windows 8 시스템간에 차이가 있습니다.

Windows 8에서 스크립트가 승격되면 현재 디렉토리는로 설정됩니다 C:\Windows\system32. 다행히도 현재 디렉토리를 현재 스크립트의 경로로 변경하면 쉬운 해결 방법이 있습니다.

cd /d %~dp0

참고 : cd /d드라이브 문자도 변경했는지 확인하십시오.

이를 테스트하기 위해 다음을 스크립트에 복사 할 수 있습니다. 동일한 결과를 보려면 두 버전에서 정상적으로 실행하십시오. 관리자 권한으로 실행하여 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


답변

나는 이것을 이렇게한다 :

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

이 방법은 간단하며 Windows 기본 명령 만 사용합니다. 배치 파일을 재배포해야하는 경우 유용합니다.

CD /d %~dp0현재 디렉토리를 파일의 현재 디렉토리로 설정합니다 ( /d옵션으로 인해 파일이있는 드라이브에 관계없이 아직없는 경우 ).

%~nx0 확장자가있는 현재 파일 이름을 반환합니다 (확장자를 포함하지 않고 폴더에 이름이 같은 exe가 있으면 exe를 호출합니다).

이 게시물에는 답장이 너무 많아서 답을 볼 수 있을지도 모르겠습니다.

어쨌든 다른 답변에 제안 된 다른 솔루션 보다이 방법이 더 간단하다는 것을 알았습니다. 누군가에게 도움이되기를 바랍니다.


답변

Matt는 훌륭한 답변을 제공하지만 스크립트에 전달 된 모든 인수를 제거합니다. 인수를 유지하는 수정 사항은 다음과 같습니다. 또한 Windows 8의 작업 디렉토리 문제에 대한 Stephen의 수정 프로그램을 통합했습니다.

@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...


답변

PowerShell을 사용하여 높지 않은 스크립트를 다시 시작합니다. 이 줄을 스크립트 맨 위에 놓으십시오.

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

@Matt의 답변에서 ‘net name’메서드를 복사했습니다. 그의 대답은 훨씬 잘 문서화되어 있으며 오류 메시지 등이 있습니다. 이것은 Windows 7 이상에서 PowerShell이 ​​이미 설치되어 있고 사용 가능하다는 이점이 있습니다. 임시 VBScript (*. vbs) 파일이 없으므로 도구를 다운로드 할 필요가 없습니다.

이 방법은 PowerShell 실행 권한이 잠겨 있지 않는 한 구성이나 설정없이 작동합니다.