Récemment, lorsque je concevais un système de gestion backend de site Web, je me suis demandé si je pouvais redémarrer le serveur Windows via la page que
j'ai recherchée sur Google et j'ai trouvé un morceau de code qui semblait très courant
. utilisé lors de l'écriture d'applications de bureau telles que des programmes Console ou Windows Form. Il peut fonctionner normalement, mais l'appel via ASP.NET ne peut pas passer
. Mais j'ai quand même posté ce code, car à l'exception de quelques lignes, les autres codes sont nécessaires pour redémarrer le. serveur. Créez
une nouvelle classe et remplissez le code suivant :
Le premier est l'espace de noms. Lors de l'appel de l'API Win, InteropServices est indispensable :
utiliser le système ;
en utilisant System.Runtime.InteropServices ;
Il y a ensuite une série de déclarations de constantes : protected const int SE_PRIVILEGE_ENABLED = 0x2;
protégé const int TOKEN_QUERY = 0x8;
protégé const int TOKEN_ADJUST_PRIVILEGES = 0x20;
chaîne const protégée SE_SHUTDOWN_NAME = "SeShutdownPrivilege" ;
protégé const int EWX_LOGOFF = 0x0;
protégé const int EWX_SHUTDOWN = 0x1;
protégé const int EWX_REBOOT = 0x2;
protégé const int EWX_FORCE = 0x4;
protégé const int EWX_POWEROFF = 0x8;
protégé const int EWX_FORCEIFHUNG = 0x10;
Définissez la structure Luid, faites attention aux attributs : [StructLayout(LayoutKind.Sequential, Pack=1)]
structure protégée LuidStruct {
public int Nombre ;
public long Luid;
public int Attr ;
}
Déclaration de DLL externe non gérée : [DllImport("kernel32.dll", ExactSpelling=true)]
externe statique protégé IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", SetLastError=true)]
protected static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok [
DllImport("advapi32.dll", SetLastError=true)]
protected static extern bool LookupPrivilegeValue(string host, string name, ref long pluid
("advapi32.dll", SetLastError=true, ExactSpelling=true))
;
protected static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref LuidStruct newst, int len, IntPtr prev, IntPtr relen);
[DllImport("user32.dll", SetLastError=true, ExactSpelling=true)]
protected static extern bool ExitWindowsEx(int flg, int rea);
Sur les systèmes d'exploitation de niveau NT, vous devez d'abord informer Windows que le système est sur le point de s'arrêter et obtenir l'autorisation de s'arrêter.
Voici la mise en œuvre de l'arrêt, du redémarrage et de la déconnexion : protected static void DoExitWindows(int flg) {
LuidStructp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, réf htok);
tp.Count = 1 ;
tp.Luid = 0 ;
tp.Attr = SE_PRIVILEGE_ENABLED ;
LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, réf tp.Luid);
AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
QuitterWindowsEx(flg, 0);
}
public static void Shutdown() {
DoExitWindows(EWX_SHUTDOWN);
}
public static void Reboot() {
DoExitWindows(EWX_REBOOT | EWX_FORCE);
}
public static void Déconnexion() {
DoExitWindows(EWX_LOGOFF);
}
À ce stade, le code de redémarrage se termine. Ce code peut fonctionner correctement dans un environnement interactif, c'est-à-dire lorsque l'utilisateur s'est connecté à Windows,
mais qu'ASP.NET s'exécute dans un environnement non interactif. Vérifiez MSDN et recherchez ExitWindowsEx. définition de la fonction. J'ai trouvé ce passage ci-dessous :
La fonction ExitWindowsEx est renvoyée dès qu'elle a lancé le processus d'arrêt. L'arrêt ou la déconnexion se déroule ensuite de manière asynchrone. La fonction est conçue pour arrêter tous les processus de la session de connexion de l'appelant. Par conséquent, si vous n'êtes pas l'utilisateur interactif, la fonction peut réussir. sans réellement arrêter l'ordinateur. Si vous n'êtes pas un utilisateur interactif, utilisez la fonction InitiateSystemShutdown ou InitiateSystemShutdownEx.
J'ai donc été inspiré et j'ai découvert qu'ExitWindowsEx ne pouvait pas être utilisé pour redémarrer le serveur de manière non interactive
. DllImport("advapi32. dll", SetLastError=true, ExactSpelling=false)]
protected static extern bool InitiateSystemShutdown (nom de chaîne, msg de chaîne, délai d'attente int, force bool, redémarrage bool) ;
Explication des paramètres :
name : nom de la machine, utilisé pour redémarrer les autres machines du LAN. S'il est nul, il s'agit de la machine locale.
msg : le message de redémarrage sera affiché dans la boîte de message de redémarrage et sera également enregistré en tant que journal des messages dans Windows 2003 et XP.
timeout : S'il n'est pas 0, une boîte de message de redémarrage s'affichera et le compte à rebours redémarrera après un délai d'attente de quelques secondes.
force : forcer le redémarrage, n'attendez pas que l'application vous demande si vous souhaitez sauvegarder le travail, pour le serveur, cela devrait être vrai
reboot : est-ce un redémarrage ? Si c'est faux, effectuez le processus d'arrêt pour le serveur, cela devrait être vrai.
Appelez d'abord AdjustTokenPrivileges selon la méthode au début de l'article pour obtenir le privilège, puis exécutez-le. la page ASP.NET : InitiateSystemShutdown(null,null,0, true,true) ;
Le système redémarrera.
Une chose à mentionner ici est que si vous redémarrez la machine, il renverra très probablement une erreur de service indisponible. Cela est dû au fait que le système a commencé à terminer divers processus avant la fin de l'exécution d'ASP.NET, notamment. bien sûr, le processus ASP.NET. C'est normal, même si les performances semblent un peu inconfortables,
de plus, comme je n'ai réussi le test que sur ma propre machine, je n'ai pas étudié le problème des autorisations en détail, donc je ne peux pas en être sûr. s'il peut fonctionner normalement sur un serveur général.
Au début, je pensais seulement que cela pouvait être résolu par une simulation d'autorisation, c'est-à-dire dans la section system.web du fichier web.config, écrivez <identity impersonate="true" userName="Administrator" password="pass">, mais cela n'a pas été confirmé, je l'essaierai quand j'aurai le temps. web.config n'est pas très sécurisé, vous devrez donc peut-être utiliser DPAPI ici, ce qui est un peu tiré par les cheveux, alors arrêtons-nous d'abord ici.