เมื่อเร็วๆ นี้ ตอนที่ฉันออกแบบระบบการจัดการแบ็กเอนด์ของเว็บไซต์ ฉันคิดว่าฉันสามารถรีสตาร์ทเซิร์ฟเวอร์ Windows ผ่านหน้าเว็บได้หรือไม่
ฉันค้นหาใน Google และพบโค้ดชิ้นหนึ่งที่ดูเหมือนจะเป็นเรื่องธรรมดามาก
ปรากฎว่าโค้ดนี้เป็นเช่นนั้น ใช้เมื่อเขียนแอปพลิเคชันบนเดสก์ท็อปเช่นโปรแกรม Console หรือ Windows Form สามารถทำงานได้ตามปกติ แต่การโทรผ่าน ASP.NET ไม่สามารถผ่าน
. แต่ฉันยังคงโพสต์โค้ดนี้เนื่องจากจำเป็นต้องรีสตาร์ทโค้ดบางบรรทัด เซิร์ฟเวอร์ สร้าง
คลาสใหม่และกรอกโค้ดต่อไปนี้ :
อันแรกคือเนมสเปซ เมื่อเรียก Win API จะขาดไม่ได้:
ใช้ระบบ;
โดยใช้ System.Runtime.InteropServices;
จากนั้นจะมีการประกาศอย่างต่อเนื่องหลายชุด: protected const int SE_PRIVILEGE_ENABLED = 0x2;
ป้องกัน const int TOKEN_QUERY = 0x8;
ป้องกัน const int TOKEN_ADJUST_PRIVILEGES = 0x20;
สตริง const ที่มีการป้องกัน 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;
ป้องกัน const int EWX_FORCEIFHUNG = 0x10;
กำหนดโครงสร้าง Luid โดยคำนึงถึงแอตทริบิวต์: [StructLayout(LayoutKind.Sequential, Pack=1)]
โครงสร้างที่ได้รับการป้องกัน LuidStruct {
จำนวน int สาธารณะ;
สาธารณะยาว Luid;
มหาชน int Attr;
-
การประกาศ DLL ที่ไม่มีการจัดการภายนอก: [DllImport("kernel32.dll", ExactSpelling=true)]
ป้องกันคงที่ภายนอก IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", SetLastError=true)]
ป้องกันบูลภายนอกแบบคงที่ OpenProcessToken (IntPtr h, int acc, อ้างอิง IntPtr phtok);
[DllImport ("advapi32.dll", SetLastError = true)]
LookupPrivilegeValue ภายนอกแบบคงที่ที่ได้รับการป้องกัน (โฮสต์สตริง ชื่อสตริง อ้างอิง pluid แบบยาว);
[DllImport("advapi32.dll", SetLastError=true, ExactSpelling=true)]
ป้องกันบูลภายนอกแบบคงที่ AdjustTokenPrivileges (IntPtr htok, บูล disall, อ้างอิง LuidStruct newst, int len, IntPtr ก่อนหน้า, IntPtr relen);
[DllImport ("user32.dll", SetLastError=true, ExactSpelling=true)]
ป้องกันบูลภายนอกคงที่ ExitWindowsEx (int flg, int rea);
บนระบบปฏิบัติการระดับ NT คุณต้องแจ้ง Windows ก่อนว่าระบบกำลังจะปิดระบบ และขอรับสิทธิ์ในการปิดระบบ
ต่อไปนี้คือการดำเนินการปิดระบบ รีสตาร์ท และออกจากระบบ: protected static void DoExitWindows(int flg) {
LuidStructtp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, อ้างอิง htok);
tp.นับ = 1;
tp.ลุยด์ = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue (null, SE_SHUTDOWN_NAME, อ้างอิง tp.Luid);
AdjustTokenPrivileges(htok, false, อ้างอิง tp, 0, IntPtr.Zero, IntPtr.Zero);
ออกจาก WindowsEx (flg, 0);
}
การปิดระบบโมฆะคงที่สาธารณะ () {
ออกจาก Windows(EWX_SHUTDOWN);
}
โมฆะสาธารณะคงที่ รีบูต () {
ออกจาก Windows(EWX_REBOOT | EWX_FORCE);
}
การออกจากระบบสาธารณะเป็นโมฆะคงที่ () {
ออกจาก Windows(EWX_LOGOFF);
-
ณ จุดนี้ รหัสการรีสตาร์ทจะสิ้นสุดลง รหัสนี้สามารถทำงานได้ดีในสภาพแวดล้อมแบบโต้ตอบ นั่นคือ เมื่อผู้ใช้เข้าสู่ระบบ Windows
แต่ ASP.NET กำลังทำงานในสภาพแวดล้อมที่ไม่โต้ตอบ ตรวจสอบ MSDN และค้นหา ExitWindowsEx คำจำกัดความของฟังก์ชัน ฉันพบข้อความนี้ด้านล่าง:
ฟังก์ชัน ExitWindowsEx จะส่งกลับทันทีที่ได้เริ่มกระบวนการปิดระบบ การปิดระบบหรือออกจากระบบจะดำเนินการแบบอะซิงโครนัส ฟังก์ชันนี้ได้รับการออกแบบมาเพื่อหยุดกระบวนการทั้งหมดในเซสชันการเข้าสู่ระบบของผู้เรียก ดังนั้น หากคุณไม่ใช่ผู้ใช้แบบโต้ตอบ ฟังก์ชันนี้สามารถดำเนินการได้สำเร็จ โดยไม่ต้องปิดเครื่องคอมพิวเตอร์จริงๆ หากคุณไม่ใช่ผู้ใช้แบบโต้ตอบ ให้ใช้ฟังก์ชัน InitiateSystemShutdown
หรือ
InitiateSystemShutdownEx DllImport("advapi32.dll", SetLastError=true, ExactSpelling=false)]
ป้องกันบูลภายนอกแบบคงที่ InitiateSystemShutdown (ชื่อสตริง, สตริงข้อความ, การหมดเวลา int, แรงบูล, รีบูตบูล);
คำอธิบายพารามิเตอร์:
name: ชื่อเครื่อง ใช้เพื่อรีสตาร์ทเครื่องอื่นใน LAN หากเป็นค่าว่าง แสดงว่าเป็นเครื่องภายในเครื่อง
msg: ข้อความรีสตาร์ท จะแสดงบนกล่องข้อความรีสตาร์ท และจะถูกบันทึกเป็นบันทึกข้อความใน Windows 2003 และ XP
หมดเวลา: หากไม่ใช่ 0 กล่องข้อความรีสตาร์ทจะปรากฏขึ้น และการนับถอยหลังจะรีสตาร์ทหลังจากหมดเวลาไม่กี่วินาที
บังคับ: บังคับให้รีสตาร์ท ไม่ต้องรอให้แอปพลิเคชันแจ้งว่าจะบันทึกงานหรือไม่ สำหรับเซิร์ฟเวอร์ควรเป็นจริง
รีบูต: เป็นการรีบูตหรือไม่ หากเป็นเท็จ ให้ดำเนินการปิดระบบ สำหรับเซิร์ฟเวอร์ ควร
เรียก AdjustTokenPrivileges ก่อนตามวิธีการตอนต้นของบทความเพื่อรับสิทธิพิเศษ จากนั้นจึงดำเนินการในนั้น หน้า ASP.NET: InitiateSystemShutdown(null,null,0, true,true);
ระบบจะรีสตาร์ท
สิ่งหนึ่งที่ต้องพูดถึงคือ หากคุณรีสตาร์ทเครื่อง มักจะส่งคืนข้อผิดพลาด Service Unavailable เนื่องจากระบบได้เริ่มสิ้นสุดกระบวนการต่างๆ ก่อนที่การทำงานของ ASP.NET จะเสร็จสิ้น รวมถึง แน่นอนว่ากระบวนการของ ASP.NET นี่เป็นเรื่องปกติ แม้ว่าประสิทธิภาพจะดูอึดอัดเล็กน้อย
นอกจากนี้ เนื่องจากฉันเพิ่งผ่านการทดสอบในเครื่องของตัวเอง ฉันจึงไม่ได้ศึกษาปัญหาการอนุญาตอย่างละเอียด จึงไม่แน่ใจ ไม่ว่ามันจะสามารถทำงานได้ตามปกติบนเซิร์ฟเวอร์ทั่วไปหรือไม่
ตอนแรกฉันแค่คิดว่าสามารถแก้ไขได้ด้วยการจำลองการอนุญาต นั่นคือในส่วน system.web ของไฟล์ web.config ให้เขียน <identity impersonate="true" userName="Administrator"password="pass">แต่ยังไม่ได้รับการยืนยัน ฉันจะลองใช้เมื่อมีเวลา web.config ไม่ปลอดภัยมากนัก ดังนั้นคุณอาจต้องใช้ DPAPI ที่นี่ ซึ่งค่อนข้างซับซ้อน ดังนั้นมาหยุดที่นี่ก่อน