windows - كيف يمكنني رفع ملف دفعي تلقائيًا ، بحيث يطلب من حقوق مسؤول UAC إذا لزم الأمر؟




batch-file windows-10 (6)

أريد أن ملف الدفعي الخاص بي لتشغيل فقط مرتفعة. إذا لم يكن مرتفعًا ، فقدم خيارًا للمستخدم لإعادة تشغيل الدُفعة كقيمة مرتفعة.

أقوم بكتابة ملف دفعي لضبط متغير النظام ، وقم بنسخ ملفين إلى موقع ملفات البرامج ، وابدأ تثبيت برنامج التشغيل. إذا قام مستخدم Windows 7 / Windows Vista (بتمكين UAC وحتى إذا كان مسؤولاً محليًا) بتشغيله دون النقر بزر الماوس الأيمن وتحديد "تشغيل كمسؤول" ، فسيحصلون على "الوصول مرفوض" نسخ الملفين وكتابة متغير النظام .

أرغب في استخدام أمر لإعادة تشغيل الدُفعة تلقائيًا إذا كان المستخدم في الواقع مسؤولاً. وإلا ، إذا لم يكن مسؤولاً ، فأخبرهم أنهم يحتاجون إلى امتيازات المسؤول لتشغيل الملف الدفعي. أنا باستخدام xcopy لنسخ الملفات و REG ADD لكتابة متغير النظام. أستخدم هذه الأوامر للتعامل مع أجهزة Windows XP الممكنة. لقد وجدت أسئلة مماثلة حول هذا الموضوع ، ولكن لا شيء يتعامل مع إعادة تشغيل ملف دفعي كملف مرتفع.


أستخدم 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. يتم توثيق جوابه بشكل أفضل بكثير ولديه رسائل خطأ وما شابه ذلك. هذا واحد لديه ميزة أن PowerShell مثبت بالفعل ومتاح على ويندوز 7 وما فوق. لا توجد ملفات VBScript مؤقتة (* .vbs) ، ولا يلزم تنزيل أدوات.

يجب أن تعمل هذه الطريقة بدون أي تكوين أو إعداد ، طالما أن أذونات تنفيذ PowerShell لا يتم قفلها.


أستخدم إجابة "مات" الممتازة ، لكنني أرى اختلافًا بين نظامي 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

بالنسبة لبعض البرامج ، __COMPAT_LAYER متغير البيئة __COMPAT_LAYER السري __COMPAT_LAYER على RunAsInvoker

set "__COMPAT_LAYER=RunAsInvoker"
start regedit.exe

على الرغم من هذا ، لن يكون هناك طلب UAC الذي سيؤدي إلى استمرار المستخدم بدون أذونات المشرف.


كما ذكر jcoder و Matt ، جعلت PowerShell الأمر سهلاً ، ويمكن حتى تضمينه في البرنامج النصي الدفعي بدون إنشاء نص جديد.

قمت بتعديل البرنامج النصي لـ Matt:

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


لقد قمت بلصق هذا في بداية النص:

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

هناك طريقة سهلة دون الحاجة إلى استخدام أداة خارجية - فهي تعمل بشكل جيد مع أنظمة التشغيل Windows 7 و 8 و 8.1 و 10 وهي متوافقة مع الإصدارات السابقة أيضًا (لا يحتوي نظام التشغيل Windows XP على أي UAC ، وبالتالي لا يلزم الارتفاع - في ذلك حالة المضي قدما في البرنامج النصي فقط).

تحقق من هذا الرمز (كنت مستوحاة من رمز NIronwolf المنشور في ملف دفعي الموضوع - "تم رفض الوصول" في Windows 7؟ ) ، لكنني قمت بتحسينه - في روايتي ليس هناك أي دليل تم إنشاؤه وإزالته إلى تحقق من امتيازات المسؤول):

::::::::::::::::::::::::::::::::::::::::::::
:: 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

يستفيد البرنامج النصي من حقيقة أن 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) على نفس السطر. يتم عرضه هنا في عدة أسطر للحصول على قراءة أفضل!

على بعض الأجهزة ، واجهت مشاكل ، والتي تم حلها في الإصدار الجديد أعلاه بالفعل. أحدهما كان بسبب تعامل الاقتباس المزدوج المختلف ، والسبب الآخر كان بسبب حقيقة أن UAC تم تعطيله (تم ضبطه إلى أدنى مستوى) على جهاز Windows 7 ، وبالتالي فإن البرنامج النصي يستدعي نفسه مرارا وتكرارا.

لقد أصلحت هذا الآن عن طريق تجريد علامات الاقتباس في المسار وإعادة إضافتها لاحقًا ، ولقد أضفت معلمة إضافية تتم إضافتها عند إعادة تشغيل البرنامج النصي مع حقوق مرتفعة.

تتم إزالة علامات الاقتباس المزدوجة من قبل (التفاصيل here ):

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

يمكنك بعد ذلك الوصول إلى المسار باستخدام !batchPath! . لا يحتوي على أي علامات اقتباس مزدوجة ، لذا من الآمن أن تقول "!batchPath!" لاحقا في البرنامج النصي.

الخط

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

التحقق مما إذا كان البرنامج النصي قد تم استدعاء بالفعل من قبل البرنامج النصي VBScript لرفع الحقوق ، وبالتالي تجنب العودية التي لا نهاية لها. أنه يزيل المعلمة باستخدام shift .

تحديث:

  • لتجنب الاضطرار إلى تسجيل ملحق .vbs في نظام التشغيل Windows 10 ، قمت باستبدال الخط
    "%temp%\OEgetPrivileges.vbs"
    بواسطة
    "%SystemRoot%\System32\WScript.exe" "%temp%\OEgetPrivileges.vbs"
    في البرنامج النصي أعلاه ؛ أضاف أيضًا cd /d %~dp0 كما اقترح Stephen (إجابة منفصلة) و Tomáš Zato (comment) لتعيين دليل البرنامج النصي كإعداد افتراضي.

  • الآن البرنامج النصي يكرم معلمات سطر الأوامر التي يتم تمريرها إليه. بفضل jxmallet ، TanisDLJ وبيتر مورتنسن للملاحظات والإلهام.

  • استناداً إلى تلميح Artjom B. قمت بتحليلها واستبدلت SHIFT بواسطة SHIFT /1 ، والذي يحافظ على اسم الملف للمعلمة %0

  • تمت إضافة del "%temp%\OEgetPrivileges_%batchName%.vbs" إلى :gotPrivileges قسم :gotPrivileges لتنظيف (كما اقترح mlt ). تمت إضافة %batchName% لتجنب التأثير إذا قمت بتشغيل دفعات مختلفة في نفس الوقت. لاحظ أنك تحتاج إلى استخدام لتكون قادرة على الاستفادة من وظائف السلسلة المتقدمة ، مثل %%~nk ، والتي تقوم فقط باستخراج اسم الملف.

  • بنية vbsGetPrivileges للنص البرمجي ، تحسينات (إضافة vbsGetPrivileges متغيرة vbsGetPrivileges إليها الآن في كل مكان مما يسمح بتغيير مسار الملف أو اسمه بسهولة ، فقط قم بحذف ملف .vbs إذا كانت هناك حاجة إلى رفع الدُفعة)

  • في بعض الحالات ، يلزم بناء جملة استدعاء مختلفة للارتفاع. إذا لم يعمل البرنامج النصي ، تحقق من المعلمات التالية:
    set cmdInvoke=0
    set winSysFolder=System32
    إما تغيير المعلمة الأولى set cmdInvoke=1 وتحقق مما إذا كان هذا بالفعل يعمل على إصلاح المشكلة. سيضيف cmd.exe إلى البرنامج النصي أداء الارتفاع.
    أو حاول تغيير المعلمة الثانية إلى winSysFolder=Sysnative ، قد يساعد هذا (ولكن في معظم الحالات غير مطلوب) على أنظمة 64 بت. (أبلغ ADBailey هذا). مطلوب "Sysnative" فقط لتشغيل تطبيقات 64 بت من مضيف برنامج نصي 32 بت (على سبيل المثال عملية إنشاء Visual Studio أو استدعاء البرنامج النصي من تطبيق 32 بت آخر).

  • لتوضيح كيفية تفسير المعلمات ، أقوم P1=value1 P2=value2 ... P9=value9 الآن مثل P1=value1 P2=value2 ... P9=value9 . هذا مفيد بشكل خاص إذا كنت بحاجة إلى إحاطة معلمات مثل المسارات في علامات اقتباس مزدوجة ، مثل "C:\Program Files" .





elevated-privileges