Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

FAQ Posted: System Actions (Shutdown, Restart, etc). 2

Status
Not open for further replies.

Glenn9999

Programmer
Jun 19, 2004
2,312
US
I was coming up with these things and I didn't see anything in the FAQ section (and was hard to find some of it), so I wrote it up into a FAQ. The link is below:

faq102-6881

Please feel free to respond here with any comments.
 
thanks for another valuable FAQ!

[thumbsup]

-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
Thank you. Awesome stuff.

Can I respectfully request that any programmers use these with caution? Shutting down/Restarting the system without a direct request from the logged-in user is a bad, bad idea in my opinion. When Microsoft modified their Automatic Windows Update to automatically restart my computer in 5 minutes after it had randomly decided to do an update, and kill off anything I had running - including unsaved documents, it made me raging angry. Raging. It would drive me to despair if this sort of practice become common-place.
 
Shutting down/Restarting the system without a direct request from the logged-in user is a bad, bad idea in my opinion.

Definitely. I'd definitely suggest that some discretion be there within implied functionality. Like if you restart the system, put up a dialog asking whether the user wants it done:

Code:
if MessageDlg('Do you want to restart now?', mtWarning, [mbYes, mbNo], 0) = mrYes then
  machine_restart;
 
Glen: From a quick read this would seem to be somthing that works on the local machine?
Implementing a partial Workgroup wide shutdown would be very useful for me, any ideas on that?


Steve: N.M.N.F.
Playing the blues isn't about feeling better. It's about making other people feel worse.
 
Glen: From a quick read this would seem to be something that works on the local machine?

Correct.

Implementing a partial Workgroup wide shutdown would be very useful for me, any ideas on that?

Definitely. Actually, I just threw together a program for shutdown and restart of a remote computer on the network. Right now, I do not have the means to test it on a genuine remote computer because I do not have access to a network at the present time (though it does work against the local computer network name). Hopefully I can get access to a network in short time (or someone here can test it), and then I can add the code to the FAQ.

Incidentally I just did code to perform a locking of the local workstation, too, and can post that to the FAQ along with remote shutdown/restart code.
 
Hopefully I can get access to a network in short time (or someone here can test it), and then I can add the code to the FAQ.

Seems like I won't be able to do that, so I'll ask here about testing it, if anyone would be willing to do it.

This should shut down a remote system, but I'm not sure:

Code:
procedure TForm1.rsbuttonClick(Sender: TObject);
  { shuts down the remote system }
const
  SE_SHUTDOWN_NAME = 'SeShutdownPrivilege';
  SE_REMOTE_SHUTDOWN_NAME = 'SeRemoteShutdownPrivilege';
type
  SSFunc = function(lpMachineName, lpMessage: PChar;
           dwTimeout: DWord; bForceAppsClosed, bRebootAfterShutdown: boolean;
           dwReason: DWord): boolean; stdcall;
var
  loadhandle: THandle;
  SystemShutDownEx: SSFunc;
begin
  { load shutdown proc - shouldn't need to do much checking since we already
    checked for Windows 2000 or above, but we need to do this to protect from
    errors if this is run on any lower version }
  loadhandle := LoadLibrary('ADVAPI32.DLL');
  @SystemShutDownEx := nil;
  if LoadHandle <> 0 then
    @SystemShutDownEx := GetProcAddress(loadhandle, 'InitiateSystemShutdownExA');
  NTSetPrivilege(SE_SHUTDOWN_NAME, True);
  if not SystemShutdownEx(PChar(ComputerName.Text),
                          PChar(ShutDownReason.Text),
                          rstimeout.value, false, false, 0) then
    MessageDlg('Error in shutting down Remote System ' + ComputerName.Text,
                mtWarning, [mbOK], 0);
  NTSetPrivilege(SE_SHUTDOWN_NAME, False);
  FreeLibrary(LoadHandle);
end;

It's a button on a form that operates based on a computer name (that should be filled in via a computer browse, which I can't test either). ComputerName and ShutDownReason are TEdit, rstimeout is a TSpinEdit. I'm not sure of which privilege is required in this case, either. I know SE_SHUTDOWN_NAME is a requirement when I tested this on my local system, but the other one (or both) might be required if it is run against another computer (which I haven't/can't test).

If I know if/how to get this code working, I can figure out how to handle the rest that I would post to the FAQ.
 
If I know if/how to get this code working, I can figure out how to handle the rest that I would post to the FAQ.

I did get a place to test it, but got it to the point of a message saying "RPC Server not found." or some such thing. Getting that message seems very promising to me, but I'm not going to ask about it to the person who did me the favor about it. Anyhow, if anyone can get this working right in a way they can see it work, it'd be great - I'd sure like to see what it takes. This code seems very consistent with everything I read, too:

Code:
procedure TForm1.rsbuttonClick(Sender: TObject);
  { shuts down the remote system }
const
  SE_SHUTDOWN_NAME = 'SeShutdownPrivilege';
  SE_REMOTE_SHUTDOWN_NAME = 'SeRemoteShutdownPrivilege';
type
  SSFunc = function(lpMachineName, lpMessage: PChar;
           dwTimeout: DWord; bForceAppsClosed, bRebootAfterShutdown: boolean;
           dwReason: DWord): boolean; stdcall;
var
  loadhandle: THandle;
  SystemShutDownEx: SSFunc;
begin
  { load shutdown proc - shouldn't need to do much checking since we already
    checked for Windows 2000 or above, but we need to do this to protect from
    errors if this is run on any lower version }
  loadhandle := LoadLibrary('ADVAPI32.DLL');
  @SystemShutDownEx := nil;
  if LoadHandle <> 0 then
    @SystemShutDownEx := GetProcAddress(loadhandle, 'InitiateSystemShutdownExA');
  NTSetPrivilege('', SE_SHUTDOWN_NAME, True);
  NTSetPrivilege(ComputerName.Text, SE_REMOTE_SHUTDOWN_NAME, True);
  if SystemShutdownEx(PChar(ComputerName.Text),
                      PChar(ShutDownReason.Text),
                      rstimeout.value, false, false, 0) then
    MessageDlg('Shutting down Remote System ' + ComputerName.Text,
                mtWarning, [mbOK], 0)
  else
    MessageDlg('Error in shutting down Remote System ' + ComputerName.Text,
                mtWarning, [mbOK], 0);
  NTSetPrivilege(ComputerName.Text, SE_REMOTE_SHUTDOWN_NAME, False);
  NTSetPrivilege('', SE_SHUTDOWN_NAME, False);
  FreeLibrary(LoadHandle);
end;

The extra parm on NTSetPrivilege is accounted for by these changes (still from the page):
Code:
function NTSetPrivilege(sMachine, sPrivilege: string; bEnabled: Boolean): Boolean;
....
if LookupPrivilegeValue(PChar(sMachine), PChar(sPrivilege),
   TokenPriv.Privileges[0].Luid) then

I'll post a couple of more things to the linked FAQ (Locking the Workstation, and Event log messages) and move on.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top