Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi WinShutdown per Aufgabenplanung (https://www.delphipraxis.net/187409-winshutdown-per-aufgabenplanung.html)

boeseboese 27. Nov 2015 08:17

WinShutdown per Aufgabenplanung
 
Schönen guten Morgen,

ich hoffe, dass ihr mir evtl. weiterhelfen könnt.

Derzeit nutze ich folgendes Programm um Windows herunterzufahren und dabei die Updates zu installieren:

Delphi-Quellcode:
function WindowsShutDown(Computer: PChar; Msg: PChar; Time: Word; Force: Boolean; Reboot: Boolean): Boolean;
var
  rl: Cardinal;
  hToken: Cardinal;
  tkp: TOKEN_PRIVILEGES;
  flags: DWORD;

begin
  Result:=False;
  if not OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
    RaiseLastOSError
  else
  begin
    if LookupPrivilegeValue(nil, 'SeShutdownPrivilege', tkp.Privileges[0].Luid) then
    begin
      tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      tkp.PrivilegeCount := 1;
      AdjustTokenPrivileges(hToken, False, tkp, 0, nil, rl);
      if GetLastError <> ERROR_SUCCESS then
        RaiseLastOSError
      else
      begin

        if Win32MajorVersion >= 6 then
        begin
          //Flags
          if Reboot then
            flags := SHUTDOWN_FORCE_SELF or SHUTDOWN_GRACE_OVERRIDE or SHUTDOWN_RESTART
          else
            flags := SHUTDOWN_FORCE_SELF or SHUTDOWN_GRACE_OVERRIDE or SHUTDOWN_INSTALL_UPDATES;

          //Befehl ausführen
          if InitiateShutdown(Computer, Msg, Time, flags, 0) = ERROR_SUCCESS then
            result := True
          else
            RaiseLastOSError;
        end
        else
        begin
          if InitiateSystemShutdown(Computer, Msg, Time, Force, Reboot) then
            result := True
          else
            RaiseLastOSError;
        end;{else}

      end;{else}
    end
    else
      RaiseLastOSError;
  end;{else}

end;
Das funktioniert so lange bis ich die Aufgabe als Task "unabhängig von der Benutzeranmeldung" ausführen lasse. Hierbei ist es egal, ob ich SYSTEM nehme oder einen personalisierten Benutzer.

Ich sehe den Zusammenhang mit der Privilege-Abfrage. Es stellt sich die Frage, ob es dafür der richtige Ansatz ist und ob ich diese Abfrage überhaupt benötige. Evtl. wäre auch der Einsatz von ImpersonateLoggedOnUser möglich?

Ich hoffe, dass ihr mir hier ein wenig unter die Arme greifen könnt.

Ziel ist es einen Pool von virtuellen Maschinen per Aufgabenplanung zeitgesteuert das Programm ausführen zu lassen.

Danke und Gruß
boese²

Sir Rufo 27. Nov 2015 08:40

AW: WinShutdown per Aufgabenplanung
 
Deine Routine gibt beim Ausführen entweder ein
Delphi-Quellcode:
True
zurück, oder es wird eine Exception geworfen.

Wenn es aber nur einen möglichen Wert gibt, warum gebe ich den Wert dann zurück?

Eine Exception unterbricht ausserdem die weitere Code-Ausführung.

Mit diesen beiden Erkenntnissen lässt sich dein Code erheblich verschlanken:
Delphi-Quellcode:
procedure Win32CheckSuccess(AResult : DWORD);
begin
  if AResult <> ERROR_SUCCESS then
    RaiseLastOSError;
end;

procedure WindowsShutDown( Computer: PChar; Msg: PChar; Time: Word; Force: Boolean; Reboot: Boolean );
var
  rl   : Cardinal;
  hToken: Cardinal;
  tkp  : TOKEN_PRIVILEGES;
  flags : DWORD;
begin
  Win32Check( OpenProcessToken( GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken ) );
  Win32Check( LookupPrivilegeValue( nil, 'SeShutdownPrivilege', tkp.Privileges[ 0 ].Luid ) );

  tkp.Privileges[ 0 ].Attributes := SE_PRIVILEGE_ENABLED;
  tkp.PrivilegeCount            := 1;

  Win32Check( AdjustTokenPrivileges( hToken, False, tkp, 0, nil, rl ) );

  if Win32MajorVersion >= 6
  then
    begin
      // Flags
      if Reboot
      then
        flags := SHUTDOWN_FORCE_SELF or SHUTDOWN_GRACE_OVERRIDE or SHUTDOWN_RESTART
      else
        flags := SHUTDOWN_FORCE_SELF or SHUTDOWN_GRACE_OVERRIDE or SHUTDOWN_INSTALL_UPDATES;

      // Befehl ausführen
      Win32CheckSuccess( InitiateShutdown( Computer, Msg, Time, flags, 0 ) );
    end
  else
    Win32Check( InitiateSystemShutdown( Computer, Msg, Time, Force, Reboot ) );
end;

boeseboese 27. Nov 2015 11:01

AW: WinShutdown per Aufgabenplanung
 
Hi Rufo,

danke für die Optimierung, löst aber nicht das Problem, oder?

//edit: Getestet. Verhalten bleibt leider wie gehabt.

Gruß
boese²

SvB 27. Nov 2015 13:05

AW: WinShutdown per Aufgabenplanung
 
Hat es einen Grund warum es ein eigenes Programm sein soll?
Ich hätte mir jetzt eine Batch erstellt und dort "shutdown -s -t 0" aufgerufen. Oder auch direkt, müsste man mal ausprobieren. Die Installation der Updates sollte auch klappen.

boeseboese 27. Nov 2015 16:59

AW: WinShutdown per Aufgabenplanung
 
Shutdown war natürlich mein erster Versuch. Dabei werden keine Updates installiert. Auch das vorherige installieren per Batch wäre eine Variante, aber ich möchte den Benutzer erst abgemeldet und alle Anwendungen geschlossen haben.

Der Aufruf mit Updates ist nur per API Call realisierbar. Dieser wird auch von m$ auf dem Herunterfahren-Button angewendet!

Christian Seehase 2. Dez 2015 11:37

AW: WinShutdown per Aufgabenplanung
 
Moin,

hast Du auch mal im Eventlog nachgesehen, was passiert ist?
Vielleicht habe ich es übersehen, aber: Unter welchem Betriebssystem soll das funktionieren?

Der schöne Günther 2. Dez 2015 11:50

AW: WinShutdown per Aufgabenplanung
 
Versuche es mal mit
Delphi-Quellcode:
SeRemoteShutdownPrivilege

boeseboese 2. Dez 2015 12:30

AW: WinShutdown per Aufgabenplanung
 
@Christian:
Für die Aufgabenplanung ist die Aufgabe sauber durchgeführt worden:
Zitat:

Die Aufgabenplanung hat die Aufgabe "\WinShutdown", Instanz "{242bf35e-0445-46b5-9992-a2c4c064f30e}", Aktion "C:\Scripts\WinShutdown.exe" mit Rückgabecode 0 erfolgreich abgeschlossen.
Betriebssystem ist Windows 7

@Günther:
Danke, werde ich mal weitergeben und ausprobieren.

Gruß
boese²

boeseboese 2. Dez 2015 15:24

AW: WinShutdown per Aufgabenplanung
 
Nachtrag zu Günther:
Funktioniert (leider) auch nicht.

Ich verstehe nicht, warum eine entsprechende Option in der regulären shutdown.exe fehlt. Diese lässt sich problemlos über "Unabhängig von der Benutzeranmeldung" ausführen.

Ich habe übrigens noch zusätzlich die lokale Sicherheitsrichtlinie dahingehend geprüft, dass ein Herunterfahren auch ohne Anmeldung möglich ist. Daran kann es also auch nicht liegen.

Er scheint zwingend eine aktive Session zu benötigen...


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:40 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz