web-dev-qa-db-ja.com

必要に応じてUAC管理者権限から要求されるように、バッチファイルを自動的に昇格させる方法を教えてください。

私は自分のバッチファイルを昇格して実行したいだけです。昇格していない場合は、ユーザーが昇格したバッチを再起動するためのオプションを指定します。

システム変数を設定し、2つのファイルをProgram Filesの場所にコピーしてドライバインストーラを起動するためのバッチファイルを作成しています。 Windows 7/Windows Vistaユーザー( UAC 有効でローカル管理者であっても)を右クリックして[管理者として実行]を選択せず​​に実行すると、[アクセスが拒否されました]が表示されます。 2つのファイルをコピーしてシステム変数を書きます。

ユーザーが実際には管理者である場合は、コマンドを使用して自動的にバッチを昇格させたいと思います。それ以外の場合は、彼らが管理者ではない場合、私は彼らがバッチファイルを実行するために管理者権限が必要であることを伝えたいと思います。ファイルのコピーにxcopyを、書き込みにREG ADDを使用しています。システム変数私は可能性のあるWindows XPマシンを扱うためにこれらのコマンドを使っています。私はこのトピックに関して同様の質問を見つけました、しかし、昇格されたバッチファイルを再起動することを扱うものは何もありません。

192
PDixon724

スクリプトを自分自身で psexec-hオプションを指定して実行することで、elevatedを実行できます。

それがすでに昇格されたものとして実行されているかどうかを検出する方法がわかりません...アクセス拒否エラーが発生した場合にのみ昇格された権限で再試行してください。

あるいは、単にxcopyreg.exeのコマンドを常にpsexec -hを付けて実行することもできますが、毎回パスワードを入力する必要がある場合はエンドユーザーにとっては面倒です(またはスクリプトにパスワードを含めると安全でない場合) ...

19
ewall

外部ツールを使用せずに簡単な方法があります - それはWindows 7、8、8.1、1でうまく動き、また後方互換性があります(Windows XPはUACを持たないので昇格)必要ではない - その場合スクリプトはただ進む)。

このコードをチェックしてください(私はスレッドに投稿されたNIronwolfのコードに触発されました バッチファイル - "Access Denied"はWindows 7では? )、私はそれを改良しました - 私のバージョンでは管理者特権をチェックするために作成され削除されたディレクトリはありません。

::::::::::::::::::::::::::::::::::::::::::::
:: 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は管理者ユーザーとパスワードを3回要求します。今度は最初に1回だけ要求されます。


スクリプトがエラーメッセージを表示して、管理者権限の代わりに _自動昇格がない場合は終了するだけでよい場合は、これはさらに簡単です。スクリプト:

@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)は同じ行になければなりません。読みやすくするために、ここでは複数行で表示されています。


いくつかのマシンでは私は既に問題を抱えていますが、それは上記の新しいバージョンで解決されています。 1つは異なる二重引用符の処理によるもので、もう1つの問題はWindows 7マシンでUACが無効にされている(最低レベルに設定されている)という事実によるものです。

パス内の引用符を取り除き、後でそれらを再追加することでこれを修正しました。また、スクリプトが昇格した権限で再起動したときに追加される追加のパラメータを追加しました。

二重引用符は次のように削除されます(詳細は here )。

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

!batchPath!を使用してパスにアクセスできます。二重引用符が含まれていないので、スクリプトの後半で"!batchPath!"と言っても安全です。

この線

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

スクリプトが権利を高めるために VBScript スクリプトによってすでに呼び出されているかどうかをチェックし、それによって無限の再帰を回避します。 shiftを使用してパラメータを削除します。


更新:

  • Windows 1.vbs拡張子を登録する手間を省くために、この行を置き換えました。
    "%temp%\OEgetPrivileges.vbs"
    によって
    "%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
    上記のスクリプトでは。スクリプトディレクトリをデフォルトに設定するために、Stephen(個別の回答)およびTomášZato(コメント)が提案しているようにcd /d %~dp0も追加しました。

  • 今スクリプトはそれに渡されるコマンドラインパラメータを尊重します。観察と霊感を寄せてくれたjxmallet、TanisDLJとPeter Mortensenに感謝します。

  • Artjom B.のヒントによると、私はそれを分析し、SHIFTSHIFT /1に置き換えました。これは%0パラメーターのファイル名を保存します。

  • クリーンアップするためにdel "%temp%\OEgetPrivileges_%batchName%.vbs"セクションに:gotPrivilegesを追加しました( mlt 推奨)。異なるバッチを並行して実行した場合の影響を避けるために%batchName%を追加しました。ファイル名だけを抽出する%%~nkなどの高度な文字列関数を利用するには、forを使用する必要があります。

  • 最適化されたスクリプト構造、改善点(ファイルのパスや名前を簡単に変更できるように、あらゆる場所で参照される変数vbsGetPrivilegesが追加されました。バッチを昇格させる必要がある場合は.vbsファイルのみを削除します)

  • 場合によっては、昇格に別の呼び出し構文が必要でした。スクリプトが機能しない場合は、次のパラメータを確認してください。
    set cmdInvoke=0
    set winSysFolder=System32
    最初のパラメータをset cmdInvoke=1に変更し、それがすでに問題を解決するかどうか確認してください。昇格を実行するスクリプトにcmd.exeを追加します。
    または、2番目のパラメータをwinSysFolder=Sysnativeに変更しようとすると、64ビットシステムでは役に立ちます(しかしほとんどの場合は必須ではありません)。 (ADBaileyがこれを報告しています)。 "Sysnative"は、32ビットスクリプトホストから64ビットアプリケーションを起動するためにのみ必要です(たとえば、Visual Studioのビルドプロセス、または別の32ビットアプリケーションからのスクリプト呼び出し)。

  • パラメータがどのように解釈されるかをより明確にするために、P1=value1 P2=value2 ... P9=value9のように表示しています。これは、パスのようなパラメータを二重引用符で囲む必要がある場合に特に便利です。 "C:\Program Files"

便利なリンク:

302
Matt

JcoderとMattが述べたように、PowerShellはそれを容易にしました、そしてそれは新しいスクリプトを作成することなしにバッチスクリプトに埋め込むことさえできました。

私はマットのスクリプトを修正しました:

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

:getPrivilegesラベルは必要ありません。

32
Ir Relevant

私は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
27

私はこうやっています:

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ファイルを呼び出します)。

この記事には非常に多くの返信があります私の返信が表示されるかどうかさえわかりません。

とにかく、私はこの方法が他の答えで提案された他の解決策より単純であると思う、私はそれが誰かに役立つことを願っています。

24
Matheus Rocha

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...
22
jxmallett

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's answerから 'net name'メソッドをコピーしました。彼の答えははるかに文書化されており、エラーメッセージなどがあります。これには、PowerShellが既にインストールされており、Windows 7以降で利用できるという利点があります。一時的なVBScript(* .vbs)ファイルはなく、ツールをダウンロードする必要はありません。

この方法は、PowerShellの実行権限がロックされていない限り、設定や設定をしなくても機能します。

17
Ryan Bemrose

一部のプログラムでは、スーパーシークレットの__COMPAT_LAYER環境変数をRunAsInvokerに設定します 動作するでしょう 。これをチェックしてください:

set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe

このようにしても、ユーザーに管理者権限なしで続行するように促すUACはありません。

13
npocmaka

これをスクリプトの冒頭に貼り付けました。

:: BatchGotAdmin
:-------------------------------------
REM  --> Check for permissions
>nul 2>&1 "%SYSTEMROOT%\system32\icacls.exe" "%SYSTEMROOT%\system32\config\system"

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"
:--------------------------------------
5
TanisDLJ

この質問には直接適用できませんが、ユーザーの情報が必要なため、googleはタスクスケジューラから昇格した.batファイルを実行したいときにここに来ました。

最も簡単なアプローチは、.batファイルへのショートカットを作成することでした。ショートカットの場合は、Run as administratorを詳細プロパティから直接設定できるためです。

タスクスケジューラからショートカットを実行すると、昇格した.batファイルが実行されます。

0
Hugo Delsing