Recientemente, cuando estaba diseñando un sistema de administración de backend de un sitio web, pensé si podía reiniciar el servidor de Windows a través de la página.
Busqué en Google y encontré un código que parecía ser muy común
. se usa al escribir aplicaciones de escritorio como programas de consola o Windows Form. Puede ejecutarse normalmente, pero la llamada a través de ASP.NET no puede pasar
. Aún así, publiqué este código porque, a excepción de algunas líneas, los otros códigos son necesarios para reiniciar. server.Cree
una nueva clase y complete el siguiente código:
El primero es el espacio de nombres. Al llamar a Win API, InteropServices es indispensable:
usando Sistema;
usando System.Runtime.InteropServices;
Luego hay una serie de declaraciones constantes: protected const int SE_PRIVILEGE_ENABLED = 0x2;
constante protegida int TOKEN_QUERY = 0x8;
constante protegida int TOKEN_ADJUST_PRIVILEGES = 0x20;
cadena constante protegida SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
constante protegida int EWX_LOGOFF = 0x0;
constante protegida int EWX_SHUTDOWN = 0x1;
constante protegida int EWX_REBOOT = 0x2;
constante protegida int EWX_FORCE = 0x4;
constante protegida int EWX_POWEROFF = 0x8;
constante protegida int EWX_FORCEIFHUNG = 0x10;
Defina la estructura Luid, preste atención a los atributos: [StructLayout(LayoutKind.Sequential, Pack=1)]
estructura protegida LuidStruct {
recuento público int;
público largo Luid;
atributo int público;
}
Declaración de DLL externa no administrada: [DllImport("kernel32.dll", ExactSpelling=true)]
externo estático protegido IntPtr GetCurrentProcess()
[DllImport("advapi32.dll", SetLastError=true)]
bool externo estático protegido OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok [
DllImport("advapi32.dll", SetLastError=true)]
bool externo estático protegido LookupPrivilegeValue (host de cadena, nombre de cadena, pluid largo de referencia
[DllImport("advapi32.dll", SetLastError=true, ExactSpelling=true)]
bool externo estático protegido AjustaTokenPrivileges(IntPtr htok, bool disall, ref LuidStruct newst, int len, IntPtr prev, IntPtr relen
[DllImport("user32.dll", SetLastError=true, ExactSpelling=true)]
bool externo estático protegido ExitWindowsEx(int flg, int rea);
En los sistemas operativos de nivel NT, primero debe notificar a Windows que el sistema está a punto de apagarse y obtener permiso para apagarse.
La siguiente es la implementación de apagar, reiniciar y cerrar sesión: protected static void DoExitWindows(int flg) {
LuidStructtp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Contar = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue(nulo, SE_SHUTDOWN_NAME, referencia tp.Luid);
AjustarPrivilegesToken(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
SalirWindowsEx(flg, 0);
}
Apagado vacío estático público() {
HacerSalir de Windows(EWX_SHUTDOWN);
}
reinicio vacío estático público() {
Salir de Windows(EWX_REBOOT | EWX_FORCE);
}
cierre de sesión público estático vacío() {
HacerSalir de Windows(EWX_LOGOFF);
}
En este punto, el código de reinicio finaliza. Este código puede funcionar bien en un entorno interactivo, es decir, cuando el usuario ha iniciado sesión en Windows,
pero ASP.NET se está ejecutando en un entorno no interactivo. Verifique MSDN y busque ExitWindowsEx. definición de función. Encontré este pasaje a continuación:
La función ExitWindowsEx regresa tan pronto como ha iniciado el proceso de cierre. El cierre o cierre de sesión se realiza de forma asincrónica. La función está diseñada para detener todos los procesos en la sesión de inicio de sesión de la persona que llama. Por lo tanto, si usted no es el usuario interactivo, la función puede tener éxito. sin apagar realmente la computadora. Si no es el usuario interactivo, use la función InitiateSystemShutdown o InitiateSystemShutdownEx.
Entonces me inspiré y descubrí que ExitWindowsEx no se puede usar para reiniciar el servidor de forma no interactiva. Debe reemplazarlo con InitiateSystemShutdown:
[. DllImport("advapi32. dll", SetLastError=true, ExactSpelling=false)]
bool externo estático protegido InitiateSystemShutdown (nombre de cadena, mensaje de cadena, tiempo de espera int, fuerza bool, reinicio bool);
Explicación del parámetro:
nombre: nombre de la máquina, utilizado para reiniciar otras máquinas en la LAN. Si es nulo, es la máquina local.
msg: mensaje de reinicio, se mostrará en el cuadro de mensaje de reinicio y también se guardará como un registro de mensajes en Windows 2003 y XP.
tiempo de espera: si no es 0, se mostrará un cuadro de mensaje de reinicio y la cuenta regresiva se reiniciará después de los segundos del tiempo de espera.
forzar: forzar el reinicio, no espere a que la aplicación le pregunte si desea guardar el trabajo; para el servidor, debería ser verdadero
reiniciar: ¿Es un reinicio? Si es falso, realice el proceso de apagado para el servidor, debería ser verdadero.
Primero llame a AdjustTokenPrivileges de acuerdo con el método al principio del artículo para obtener el privilegio y luego ejecútelo
.la página ASP.NET: InitiateSystemShutdown(null,null,0, true,true);
El sistema se reiniciará.
Una cosa que hay que mencionar aquí es que si reinicia la máquina, lo más probable es que devuelva un error de Servicio no disponible. Esto se debe a que el sistema ha comenzado a finalizar varios procesos antes de que se complete la ejecución de ASP.NET. Por supuesto, el proceso ASP.NET es normal. Aunque el rendimiento parece un poco incómodo,
además, como solo pasé la prueba en mi propia máquina, no he estudiado el problema de los permisos en detalle, por lo que no puedo estar seguro. Si se puede ejecutar normalmente en un servidor general,
al principio solo pensé que podría resolverse mediante la simulación de permisos, es decir, en la sección system.web del archivo web.config, escriba <identity impersonate="true". userName="Administrator" password="pass">, pero no se ha confirmado. Lo intentaré cuando tenga tiempo. web.config no es muy seguro, por lo que es posible que necesites usar DPAPI aquí, lo cual es un poco exagerado, así que detengámonos aquí primero.