مؤخرًا، عندما كنت أصمم نظامًا لإدارة الواجهة الخلفية لموقع ويب، فكرت فيما إذا كان بإمكاني إعادة تشغيل خادم Windows من خلال الصفحة،
وبحثت في Google ووجدت جزءًا من التعليمات البرمجية يبدو شائعًا
جدًا يمكن استخدامه عند كتابة تطبيقات سطح المكتب مثل برامج Console أو Windows Form، لكن الاتصال عبر ASP.NET لا يمكن أن
يمرر server.com قم بإنشاء
فئة جديدة واملأ الكود التالي:
الأول هو مساحة الاسم عند استدعاء Win API، لا غنى عن InteropServices.
باستخدام النظام؛
باستخدام System.Runtime.InteropServices؛
ثم هناك سلسلة من الإعلانات الثابتة: protected const int SE_PRIVILEGE_ENABLED = 0x2;
const المحمي int TOKEN_QUERY = 0x8؛
const المحمي int TOKEN_ADJUST_PRIVILEGES = 0x20;
سلسلة ثابتة محمية SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
const المحمي int EWX_LOGOFF = 0x0;
const المحمي int EWX_SHUTDOWN = 0x1;
const المحمي int EWX_REBOOT = 0x2;
const المحمي int EWX_FORCE = 0x4;
const المحمي int EWX_POWEROFF = 0x8;
protected const int EWX_FORCEIFHUNG = 0x10;
حدد بنية Luid، وانتبه إلى السمات: [StructLayout(LayoutKind.Sequential, Pack=1)]
البنية المحمية LuidStruct {
عدد العمليات العامة؛
لويد طويل عام؛
كثافة العمليات العامة؛
}
إعلان مكتبة الارتباط الديناميكي (DLL) الخارجية غير المُدارة: [DllImport("kernel32.dll"، ExactSpelling=true)]
IntPtr GetCurrentProcess() خارجي ثابت محمي
[DllImport("advapi32.dll", SetLastError=true)]
المنطق المنطقي الخارجي الثابت المحمي OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok)
;
المنطق المنطقي الخارجي الثابت المحمي LookupPrivilegeValue(سلسلة المضيف، اسم السلسلة، المرجع الطويل pluid)؛
[DllImport("advapi32.dll"، SetLastError=true، ExactSpelling=true)]
bool خارجي ثابت محمي AdjustTokenPrivileges(IntPtr htok, bool disall, ref LuidStruct newst, int len, IntPtr prev, IntPtr relen);
[DllImport("user32.dll", SetLastError=true, ExactSpelling=true)]
المنطق المنطقي الخارجي الثابت المحمي ExitWindowsEx(int flg, int rea);
في أنظمة التشغيل على مستوى NT، تحتاج أولاً إلى إخطار Windows بأن النظام على وشك إيقاف التشغيل، والحصول على إذن بإيقاف التشغيل،
وفيما يلي تنفيذ إيقاف التشغيل وإعادة التشغيل وتسجيل الخروج: DoExitWindows(int flg) محمي بفراغ ثابت. {
LuidStructtp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
ExitWindowsEx(flg, 0);
}
إيقاف تشغيل الفراغ الثابت العام () {
DoExitWindows(EWX_SHUTDOWN);
}
إعادة تشغيل الفراغ الثابت العام () {
DoExitWindows(EWX_REBOOT | EWX_FORCE);
}
تسجيل الخروج باطل عام ثابت () {
DoExitWindows(EWX_LOGOFF);
}
عند هذه النقطة، ينتهي رمز إعادة التشغيل. يمكن أن يعمل هذا الرمز بشكل جيد في بيئة تفاعلية، أي عندما يقوم المستخدم بتسجيل الدخول إلى Windows،
ولكن ASP.NET يعمل في بيئة غير تفاعلية. تحقق من MSDN وابحث عن ملف ExitWindowsEx تعريف الوظيفة لقد وجدت هذا المقطع أدناه:
ترجع الدالة ExitWindowsEx بمجرد بدء عملية إيقاف التشغيل. ثم تتم متابعة عملية إيقاف التشغيل أو تسجيل الخروج بشكل غير متزامن دون إيقاف تشغيل الكمبيوتر فعليًا. إذا لم تكن المستخدم التفاعلي، استخدم وظيفة InitiateSystemShutdown أو InitiateSystemShutdownEx،
لذا فقد ألهمتني ووجدت أنه لا يمكن استخدام ExitWindowsEx لإعادة تشغيل الخادم بشكل غير تفاعلي، وتحتاج إلى استبداله بـ InitiateSystemShutdown
. DllImport("advapi32.dll", SetLastError=true, ExactSpelling=false)]
منطقي خارجي ثابت محمي InitiateSystemShutdown(اسم السلسلة، سلسلة رسالة، مهلة int، قوة منطقية، إعادة تشغيل منطقي)؛
شرح المعلمة:
الاسم: اسم الجهاز، يُستخدم لإعادة تشغيل الأجهزة الأخرى في الشبكة المحلية. إذا كان فارغًا، فهو الجهاز المحلي.
msg: سيتم عرض رسالة إعادة التشغيل في مربع رسالة إعادة التشغيل، وسيتم حفظها أيضًا كسجل رسائل في Windows 2003 وXP
المهلة: إذا لم تكن 0، فسيتم عرض مربع رسالة إعادة التشغيل وسيبدأ العد التنازلي بعد انتهاء المهلة بثواني.
القوة: فرض إعادة التشغيل، لا تنتظر حتى يطالبك التطبيق بحفظ العمل، يجب أن يكون صحيحًا بالنسبة للخادم
إعادة التشغيل: هل هي إعادة تشغيل؟ إذا كانت خاطئة، قم بعملية إيقاف التشغيل بالنسبة للخادم، يجب أن تكون صحيحة
أولاً، قم باستدعاء AdjustTokenPrivileges وفقًا للطريقة الموجودة في بداية المقالة للحصول على الامتياز، ثم قم بتنفيذها. صفحة ASP.NET: InitiateSystemShutdown(null,null,0, true,true);
سيتم إعادة تشغيل النظام.
الشيء الوحيد الذي يجب ذكره هنا هو أنه إذا قمت بإعادة تشغيل الجهاز، فمن المرجح أن يُرجع خطأ الخدمة غير متوفرة، وذلك لأن النظام قد بدأ في إنهاء العمليات المختلفة قبل اكتمال تنفيذ ASP.NET، بما في ذلك بالطبع عملية ASP.NET هذا أمر طبيعي، على الرغم من أن الأداء يبدو غير مريح بعض الشيء،
بالإضافة إلى أنني لم أقم بدراسة مشكلة الأذونات بالتفصيل، نظرًا لأنني اجتزت الاختبار فقط. ما إذا كان يمكن تشغيله بشكل طبيعي على خادم عام.
في البداية، اعتقدت فقط أنه يمكن حل المشكلة عن طريق محاكاة الأذونات، أي في قسم system.web في ملف web.config، اكتب <identity impersonate="true" اسم المستخدم = "المسؤول" كلمة المرور = "pass">، ولكن لم يتم تأكيد ذلك وسأحاول ذلك عندما يكون لدي الوقت. web.config ليس آمنًا جدًا، لذا قد تحتاج إلى استخدام DPAPI هنا، وهو أمر بعيد المنال بعض الشيء، لذلك دعونا نتوقف هنا أولاً.