locked
Reboot (or shutdown) Windows 7 Prorgrammatically RRS feed

  • Question

  • I'm porting a large, complex system (written in plain C to the WIN32API) from its current Win2000 level of support to Windows 7.  One of the requirements is for the node management program to be able to reboot and shutdown a node.  This works fine with UAC disabled, but seems to silently fail when UAC is enabled.  These computers will, generally, not have a user (and often not even a monitor, keyboard or mouse) so ABSOLUTELY NOTHING is allowed to popup a window that requires human intervention.  I don't think that Windows 7 will be able to succeed under this requirement, but I'm asking here just in case there is a way to leave UAC enabled and still have this work.  Oh, and if it matters, these machines will NEVER have access to the internet, so no phoning home to check certificates with Microsoft or anything like that.
    Monday, December 5, 2011 1:47 PM

All replies

  • >One of the requirements is for the node management program to be able to reboot and shutdown a node.  This works fine with UAC disabled, but seems to silently fail when UAC is enabled. 

    You've not explained what code/API/whatever is failing for you (with
    UAC enabled).

    Dave

    Monday, December 5, 2011 1:55 PM
  • The two programs might need to reboot a node are calling ExitWindowsEx().  We had tried InitiateSystemShutdown() and InitiateSystemShutdownEx(), but those caused a problem under Windows Server 2003 because they cause a dialog to appear that requires human input, which completely eliminates the usefulness of having a program reboot a machine when a critical failure is detected.
    Tuesday, December 6, 2011 1:32 PM
  • >The two programs might need to reboot a node are calling ExitWindowsEx().  We had tried InitiateSystemShutdown() and InitiateSystemShutdownEx(), but those caused a problem under Windows Server 2003 because they cause a dialog to appear that requires human input, which completely eliminates the usefulness of having a program reboot a machine when a critical failure is detected.

    If you use the example code here (in the "How to Shut Down the System"
    link)

    http://msdn.microsoft.com/en-us/library/windows/desktop/aa376868(v=vs.85).aspx

    ... do you have the same issue?
    Does it show that AdjustTokenPrivileges isn't successful?

    Dave

    Tuesday, December 6, 2011 1:53 PM
  • Then you can use this document to get the SE_SHUTDOWN_NAME privilege for your process can do the shutdown Windows job:

    http://msdn.microsoft.com/en-us/library/aa376871(v=VS.85).aspx

    The ExitWindowsEx is a safe way to shutdown Windows, there's also a way to force shutdown the Windows using the NtShutdownSystem function, for the details you can ref this sample: http://kinglix.wordpress.com/2011/08/29/hello-world/ and this http://www.codeproject.com/KB/winsdk/Windows_Shutdown.aspx?msg=2968152

    For researching the new System's shutdown proceeds, there's also a good blog I think: http://blogs.msdn.com/b/ntdebugging/archive/2007/06/09/how-windows-shuts-down.aspx

    Best wishes,


    Mike Zhang[MSFT]
    MSDN Community Support | Feedback to us
    Tuesday, December 6, 2011 3:10 PM
  • Everything would return success codes, but sometimes the machine would just log out instead of powering down as requested.  And FWIW, our programs are running in the interactive user desktop.
    Tuesday, December 6, 2011 4:50 PM
  • Thanks for all of the references, we'll be going over them to see what we can learn.  We have temporarily resolved the issue by disabling as much of Windows 7's new security as we could and the shutdowns and reboots started working.

    Ergo, I currently believe this to be a UAC issue (since that was what we disabled just before it started working) and simply adding RequireAdministrator to the manifest isn't helping because with UAC enabled, that still causes a prompt that requires human input -- which is something we simply CANNOT have because some of these machines will be headless, in basement racks where there are rarely ever any people.

    I think Microsoft has a program for registering trusted applications for Windows 7, but I see two possible problems (as I understand the program):

    1. The cost is probably far in excess of the profit we might get on this job
    2. These machines will NEVER, EVER have internet access, but it sounds like that is required in order for the machine to discover an application's "trust" registration from Microsoft.

    If I'm correct about #2 and the trust program requires internet access from the machines running the trusted program(s), then that is a deal breaker.  People in the nuclear industry really don't like being forced to have their plant computers on the internet and, in fact, that will not happen.

    Tuesday, December 6, 2011 4:59 PM
  • You should still post your code - nobody can tell if you're doing it correctly, especially when you maintain that the APIs return success codes.

    The main reasons for this kind of situation are:

    1. The program must be elevated to perform this. Ever since Vista, UAC systems require elevation (such as an elevation manifest) to do tasks that require admin privilege *even if they are an admin user*.

    2. Failure to get the SE_SHUTDOWN_NAME privilege before doing it.


    Phil Wilson
    Wednesday, December 7, 2011 8:28 PM
  • The annoying GUI for shutdown/restart reason can be disabled in Local or Group security policy.

    Win7 is a workstation OS, it is tuned for an interactive user. This is by design. You cannot blame Win7 for doing what it is designed for. 

    MS offers other operating systems that may be much more suitable for your requirements, such as  Windows Embedded or Server Core. They have also licensing & activation models suitable for requirements like yours


    Thanks, I'll add th policy info to my notes.

    Actually, the place we had a significant problem with popup messages when a program requested reboot was on a Windows Server 2003 (and then Server 2003 R2) machine -- NOT a workstation version (those shut down quietly, when they accept the command.)

    We don't always have the luxury of choosing the target operating system for our customers.  Ours may not be the only software they intend to run on the machines, but we need to know how to configure them to run ours successfully.  If the customer then chooses to configure them some other way, that's his choice.  But FWIW, I wish we could convince them to use an embedded system for at least some of the machines.  But the "marginally attended" machines are more problemmatic -- sometimes a user will be there to use them and respond to things and other times they may run for days with no one touching them and a message could go unnoticed on the display.

    Wednesday, December 7, 2011 9:53 PM
  • OK, here's the code:

    static BOOL _spu_AdjustPrivileges( void )
    {
       HANDLE            hToken;
       TOKEN_PRIVILEGES  tkp;
       BOOL              bSuccess = FALSE;
       BOOL              bAdjust;
    
       do //once
       {
          if( IS_NT )  // if is an NT system
          {
             // Running on NT so need to change privileges
             if( !OpenProcessToken( GetCurrentProcess(),
                                    TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                                    &hToken) )
             {
                LogPrintf( gdll.hlog, "OpenProcessToken() failed in spu_AdjustPrivileges() with reason %s",
                           GetSystemLastErrorText( szMsg, sizeof(szMsg) ) );
                break;
             }
    
             // Get the LUID for shutdown privilege
             if( !LookupPrivilegeValue( NULL, SE_SHUTDOWN_NAME,
                                        &tkp.Privileges[0].Luid ) )
             {
                LogPrintf( gdll.hlog, "LookupPrivilegeValue() failed in spu_AdjustPrivileges() with reason %s",
                           GetSystemLastErrorText( szMsg, sizeof(szMsg) ) );
                break;
             }
    
             tkp.PrivilegeCount = 1;  // one privilege to set
             tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
             // Get shutdown privilege for this process.
             bAdjust = AdjustTokenPrivileges( hToken, FALSE, &tkp,
                                              0, (PTOKEN_PRIVILEGES)NULL, 0 );
             CloseHandle( hToken );
             if( !bAdjust )
             {
                LogPrintf( gdll.hlog, "AdjustTokenPrivileges() failed in spu_AdjustPrivileges() with reason %s",
                           GetSystemLastErrorText( szMsg, sizeof(szMsg) ) );
                break;
             }
          }
          else
          {  // All ready have the needed privilege
             LogPrintf( gdll.hlog, "This is not a Windows NT system...privileges cannot be adjusted" );
          }
          bSuccess = TRUE;
       }while(FALSE);
       return bSuccess;
    }
    //=============================================================================
    BOOL sp_Reboot( DWORD dwType, char *szProcName, char *szReason )
    {
       BOOL  bSuccess = FALSE;
       DWORD dwReason = SHTDN_REASON_MAJOR_OTHER    // Log shutdown as
                      | SHTDN_REASON_MINOR_OTHER    //  "Other (planned)"
                      | SHTDN_REASON_FLAG_PLANNED;  // on systems that support it
    
       do //once
       {
          if( _spu_AdjustPrivileges() )
          {  // Now to reboot...
             LogPrintf( gdll.hlog, "%s is going to %s.\n"
                        "  Reason: %s",
                        szProcName, gszRebootType[dwType], szReason );
    
             switch( dwType )
             {
             case SP_RBT_LOGOFF:
                if( !ExitWindowsEx( EWX_LOGOFF | EWX_FORCEIFHUNG, dwReason ) )
                {  // Logoff Failed...
                   LogPrintf( gdll.hlog, "ExitWindowsEx() failed in sp_Reboot() Error: %s",
                              GetSystemLastErrorText( szMsg, sizeof(szMsg) ) );
                   continue;
                }
                break;
    
             case SP_RBT_SHUTDOWN:
                if( !ExitWindowsEx( EWX_POWEROFF | EWX_FORCEIFHUNG, dwReason ) )
                {  // Logoff Failed...
                   LogPrintf( gdll.hlog, "ExitWindowsEx() failed in sp_Reboot() Error: %s",
                              GetSystemLastErrorText( szMsg, sizeof(szMsg) ) );
                   continue;
                }
                break;
    
             case SP_RBT_REBOOT:
                if( !ExitWindowsEx( EWX_REBOOT | EWX_FORCEIFHUNG, dwReason ) )
                {  // Logoff Failed...
                   LogPrintf( gdll.hlog, "ExitWindowsEx() failed in sp_Reboot() Error: %s",
                              GetSystemLastErrorText( szMsg, sizeof(szMsg) ) );
                   continue;
                }
                break;
    
             default:
             case SP_RBT_EXIT: // Note: Only exit program - don't reboot
                PostMessage( gdll.hWnd, uSpSpMsg, SP_MSG_EXIT, dwReason );
                break;
             }
             // Yes! Reboot is under way...
             bSuccess = TRUE;
          }
       }while(FALSE);
       return bSuccess;
    }
    

    Sometimes, when a SHUTDOWN or REBOOT is commanded, all of the expected messages are logged, but the machine doesn't shutdown or reboot.  And I'm pretty sure we don't see any error messages even if the program is not run as admin (or with RequireAdmin set in the manifest), but the reboot didn't happen.  We currently have UAC disabled on all of the Win7 test machines, and they shutdown and reboot quite reliably using the functions shown here.

    Thursday, December 8, 2011 2:46 PM
  • Have you checked the event log?
    Mike Zhang[MSFT]
    MSDN Community Support | Feedback to us
    Thursday, December 8, 2011 4:29 PM