A recent project I worked on was to replace functionality for part of our patching process that runs commands after reboot, a task not too uncommon for installers – most notably because files were in use when the installers ran. Typically when files are in use installers such as Windows Installer and many proprietary installers will schedule a pending file rename, or PFR (also called a pending file rename operation, or PFRO). In Windows 9x/Me this is done by adding a DestinationFileName=SourceFileName pair to the [rename] section of the %WINDIR%wininit.ini file. In Windows NT a similar key/value pair is added to the HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerPendingFileRenameOperations registry key, which is a protected key requiring, by default, administrative permission to write to it. The MoveFileEx function works with the link tracker in Windows NT and will schedule a PFR if necessary.
When commands must be run, for example, to NGEN assemblies such commands must be scheduled to run after reboot or performed on the temporary source files when possible. Under certain scenarios and to keep the assemblies in the %WINDIR%Microsoft.NETFramework<Version> directory, the Global Assembly Cache (GAC), and the native image cache in parity, such commands must be handled after a reboot after the PFR is performed. Previously this was done by adding the commands (indirectly) to the RunOnce and Run registry keys.
The problem with this approach is that those registry keys require an interactive login before they are processed and – in Windows NT – the processes inherit the permissions and privileges (or lack thereof) of the interactive user. If the target of the operation is a protected store – like the GAC – administrative permissions are required. Under Windows 9x/Me this is not nearly as big a problem since everyone basically has full control on the system; but, for networked machines or Windows 9x/Me machines that have profiles enabled, an interactive login is still required when commands are scheduled in the RunOnce and Run registry keys.
To solve this problem, the RunServicesOnce and RunServices registry keys should be used under Windows 9x/Me. These are similar to the RunOnce and Run keys except that they are processed before a login is required. Under Windows NT a service that reads commands from a protected store – such as a registry key requiring administrative permissions for write access – could be used. Such a service should run with the least amount of privileges necessary. Service user accounts already exist which should meet your requirements; but, you can also install a service to run as a user who has the SE_SERVICE_LOGON_NAME account right, but then must securely prompt for their credentials which are passed as parameters to CreateService(). In the latter scenario silent installations may be difficult depending on the installation technology you use, and great care should be taken to not divulge or store any credentials which are obtained such as in an installation log file, event log, or install state data.
When its necessary to create a service to process commands independently of an interactive user, you are highly encouraged to create a threat model and to make sure that your solution is secure.