|
|
/*++
File Description:
This file contains all the functions required to add a registry entry to force execution of the system clone worker upon reboot.
--*/
#include <stdio.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntpoapi.h>
#include <ntdddisk.h>
#include <windows.h>
#include <shlwapi.h>
#include <stdlib.h>
#include <lmcons.h>
#include <lmerr.h>
#include <lmjoin.h>
#include <lmaccess.h>
#include <lmserver.h>
#include <regstr.h>
#include "sysprep.h"
#include "msg.h"
#include "resource.h"
#include <tchar.h>
#include <opklib.h>
#include <ntverp.h>
#include <spsyslib.h>
#include <sysprep_.c>
#include <winbom.h>
#include <initguid.h>
#include <ntddpar.h>
// External functions
//
extern void uiDialogTopRight(HWND hwndDlg); extern HWND ghwndOemResetDlg;
//
// Does the user want a new SID?
//
BOOL NoSidGen = FALSE; BOOL SetupClPresent = TRUE;
//
// Does the user want confirmation?
//
BOOL QuietMode = FALSE;
//
// Do PnP re-enumeration?
//
BOOL PnP = FALSE;
//
// Do we shutdown when we're done?
//
BOOL NoReboot = FALSE;
//
// Instead of shutting down, do we reboot?
//
BOOL Reboot = FALSE;
//
// Clean out the critical devices database?
//
BOOL Clean = FALSE;
//
// Force the shutdown instead of trying to poweroff?
//
BOOL ForceShutdown = FALSE;
//
// Generating an Image for Factory Preinstallation.
//
BOOL Factory = FALSE;
//
// Reseal a machine after running FACTORY.EXE
//
BOOL Reseal = FALSE; // Per/Pro SKUs defaults to OOBE, Server SKUs always use MiniSetup.
// Pro SKU can override OOBE with -mini to use MiniSetup also
// via sysprep.inf
BOOL bMiniSetup = FALSE;
//
// Just do an audit boot if this switch is passed in. ( '-audit' )
//
BOOL Audit = FALSE; //
// Rollback
//
BOOL bActivated = FALSE;
//
// Build list of pnpids in [sysprepmassstorage] section in sysprep.inf
//
BOOL BuildMSD = FALSE;
//
// If we're running on a domain controler this should be set.
//
BOOL bDC = FALSE;
//
// Internal Define(s):
//
#define SYSPREP_LOG _T("SYSPREP.LOG") // Sysprep log file
#define SYSPREP_MUTEX _T("SYSPREP-APP-5c9fbbd0-ee0e-11d2-9a21-0000f81edacc") // GUID used to determine if sysprep is currently running
#define SYSPREP_LOCK_SLEEP 100 // Number of miliseconds to sleep in LockApplication function
#define SYSPREP_LOCK_SLEEP_COUNT 10 // Number of times to sleep during LockApplication function
// Path to the sysprep directory.
//
TCHAR g_szSysprepDir[MAX_PATH] = NULLSTR;
// Path to the SYSPREP.EXE.
//
TCHAR g_szSysprepPath[MAX_PATH] = NULLSTR;
// Path to the Sysprep log file.
//
TCHAR g_szLogFile[MAX_PATH] = NULLSTR;
// Path to the Winbom file.
//
TCHAR g_szWinBOMPath[MAX_PATH] = NULLSTR;
// Public functions
//
BOOL FProcessSwitches();
// Local functions
static BOOL RenameWinbom(); static INT CleanupPhantomDevices(); static VOID CleanUpDevices(); static VOID CleanupParallelDevices();
#if !defined(_WIN64)
static BOOL SaveDiskSignature(); #endif // !defined(_WIN64)
//
// UI stuff...
//
HINSTANCE ghInstance; UINT AppTitleStringId = IDS_APPTITLE; HANDLE ghWaitEvent = NULL, ghWaitThread = NULL; BOOL gbScreenSaver = FALSE;
void StartWaitThread(); void EndWaitThread(); void DisableScreenSaver(BOOL *pScreenSaver); void EnableScreenSaver(BOOL *pScreenSaver);
int MessageBoxFromMessageV( IN DWORD MessageId, IN DWORD CaptionStringId, IN UINT Style, IN va_list *Args ) { TCHAR Caption[512]; TCHAR Buffer[5000]; if(!LoadString(ghInstance,CaptionStringId,Caption,sizeof(Caption)/sizeof(TCHAR))) { Caption[0] = 0; }
if( !FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, ghInstance, MessageId, 0, Buffer, sizeof(Buffer) / sizeof(TCHAR), Args ) ) { return GetLastError(); } else { return(MessageBox(NULL,Buffer,Caption,Style)); } }
int MessageBoxFromMessage( IN DWORD MessageId, IN DWORD CaptionStringId, IN UINT Style, ... ) { va_list arglist; int i = IDOK; // Default return value of "OK".
// If we're in the middle of a Wait thread kill it
//
EndWaitThread();
if ( !QuietMode ) { va_start(arglist,Style);
i = MessageBoxFromMessageV(MessageId,CaptionStringId,Style,&arglist);
va_end(arglist); }
return(i); }
/*++
=============================================================================== Routine Description:
This routine will attempt to disjoin a user from a domain, if he is already in a domain
Arguments:
none
Return Value:
TRUE - Everything is okay.
FALSE - Something bad happened.
=============================================================================== --*/ BOOL UnjoinNetworkDomain ( void ) { if (IsDomainMember()) { // He's a member of some domain. Let's try and remove him
// from the domain.
if (NO_ERROR != NetUnjoinDomain( NULL, NULL, NULL, 0 )) { return FALSE; } } return TRUE; }
/*++
=============================================================================== Routine Description:
This routine will setup the setup for operation on the "factory floor" The purpose here is to run a process which will facilitate the installation of updated drivers for new devices, and to boot quickly into full GUI mode for application pre-install/config, as well as to customize the system.
Arguments:
none
Return Value:
TRUE if no errors, FALSE otherise
=============================================================================== --*/ BOOL SetupForFactoryFloor ( void ) { TCHAR szFactory[MAX_PATH] = NULLSTR, szSysprep[MAX_PATH] = NULLSTR, szSystem[MAX_PATH] = NULLSTR; LPTSTR lpFilePart = NULLSTR;
// Make sure we have the right privileges
//
pSetupEnablePrivilege(SE_RESTORE_NAME,TRUE); pSetupEnablePrivilege(SE_BACKUP_NAME,TRUE);
// We need the path to sysprep.exe and factory.exe.
//
if ( !( GetModuleFileName(NULL, szSysprep, AS(szSysprep)) && szSysprep[0] && GetFullPathName(szSysprep, AS(szFactory), szFactory, &lpFilePart) && szFactory[0] && lpFilePart ) ) { return FALSE; }
// Replace the sysprep.exe filename with factory.exe.
//
StringCchCopy ( lpFilePart, AS ( szFactory ) - ( lpFilePart - szFactory ), TEXT( "factory.exe" ) ); // Make sure that sysprep.exe and factory.exe are on the system drive.
//
if ( ( ExpandEnvironmentStrings(TEXT("%SystemDrive%"), szSystem, AS(szSystem)) ) && ( szSystem[0] ) && ( szSystem[0] != szSysprep[0] ) ) { // Well that sucks, we should try and copy the files over to the %SystemDrive%\sysprep folder.
//
AddPath(szSystem, TEXT("sysprep")); lpFilePart = szSystem + lstrlen(szSystem); CreateDirectory(szSystem, NULL);
// First copy factory locally.
//
AddPath(szSystem, TEXT("factory.exe")); CopyFile(szFactory, szSystem, FALSE); StringCchCopy ( szFactory, AS ( szFactory ), szSystem );
// Now try to copy sysprep.exe.
//
*lpFilePart = TEXT('\0'); AddPath(szSystem, TEXT("sysprep.exe")); CopyFile(szSysprep, szSystem, FALSE); //lstrcpy(szSysprep, szSystem);
}
if (!SetFactoryStartup(szFactory)) return FALSE;
// Clear out any previous Factory.exe state settings
RegDeleteKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Factory\\State");
// Remove any setting before Factory
//
NukeMruList();
// Rearm
//
if (!IsIA64() && !bActivated && (ERROR_SUCCESS != ReArm())) { // Display warning that grace period limit has reached and cannot
// re-active grace period, and we continue thru.
//
MessageBoxFromMessage( MSG_REARM_ERROR, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL ); }
return TRUE; }
INT_PTR CALLBACK WaitDlgProc ( IN HWND hwndDlg, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam ) { switch (msg) { case WM_INITDIALOG: { // Centers the wait dialog in parent or screen
//
HWND hwndParent = GetParent(hwndDlg); CenterDialogEx(hwndParent, hwndDlg);
// If no parent then make sure this is visible
//
if (hwndParent == NULL) SetForegroundWindow(hwndDlg);
// Play the animation
//
Animate_Open(GetDlgItem(hwndDlg,IDC_ANIMATE),MAKEINTRESOURCE(IDA_CLOCK_AVI)); Animate_Play(GetDlgItem(hwndDlg,IDC_ANIMATE),0,-1,-1); } break; } return (BOOL) FALSE; }
DWORD WaitThread(LPVOID lpVoid) { HWND hwnd;
if ( hwnd = CreateDialog(ghInstance, MAKEINTRESOURCE(IDD_WAIT), ghwndOemResetDlg, WaitDlgProc) ) { MSG msg; HANDLE hEvent = (HANDLE) lpVoid;
ShowWindow(hwnd, SW_SHOWNORMAL); while ( MsgWaitForMultipleObjects(1, &hEvent, FALSE, INFINITE, QS_ALLINPUT) == (WAIT_OBJECT_0 + 1) ) { while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) { TranslateMessage(&msg); DispatchMessage(&msg); } }
DestroyWindow(hwnd); } else GetLastError();
return 0; }
void StartWaitThread() { // Create a dialog to show progress is being made.
//
DWORD dwThread;
// Disable the toplevel Oemreset dialog
//
if (ghwndOemResetDlg) EnableWindow(ghwndOemResetDlg, FALSE);
if ( ghWaitEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("SYSPREP_EVENT_WAIT"))) ghWaitThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) WaitThread, (LPVOID) ghWaitEvent, 0, &dwThread); }
void EndWaitThread() { // Kill the Status Dialog.
//
if ( ghWaitEvent ) SetEvent(ghWaitEvent);
// Try and let the thread terminate nicely.
//
if ( ghWaitThread ) WaitForSingleObject(ghWaitThread, 2000);
// Clear the handles
//
ghWaitEvent = NULL; ghWaitThread = NULL;
// Enable the toplevel OemReset dialog
//
if (ghwndOemResetDlg) EnableWindow(ghwndOemResetDlg, TRUE); }
/*++
=============================================================================== Routine Description:
This is the error callback handler for SetDefaultOEMApps()
=============================================================================== --*/
void ReportSetDefaultOEMAppsError(LPCTSTR pszAppName, LPCTSTR pszIniVar) { MessageBoxFromMessage( MSG_SETDEFAULTS_NOTFOUND, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL, pszAppName, pszIniVar); }
/*++
=============================================================================== Routine Description:
This routine will perform the tasks necessary to reseal the machine, readying it to be shipped to the end user.
Arguments:
BOOL fIgnoreFactory - ignores if factory floor was run
Return Value:
TRUE if no errors, FALSE otherwise
=============================================================================== --*/ BOOL ResealMachine ( void ) { // Make sure privileges have been set
//
pSetupEnablePrivilege(SE_RESTORE_NAME,TRUE); pSetupEnablePrivilege(SE_BACKUP_NAME,TRUE); // Prepare the machine to be hardware independent.
//
if (!FPrepareMachine()) { MessageBoxFromMessage( MSG_REGISTRY_ERROR, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL ); return FALSE; }
//
// Cleanup registry no matter what since factorymode=yes can set this
// and winbom.ini can set this and sysprep -factory can set this, or else
// PnP will hang on FactoryPreInstallInProgress being set.
//
CleanupRegistry();
// Clean up the factory mess.
//
RegDelete(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", L"AutoAdminLogon"); SHDeleteKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Factory");
// Rearm
//
if (!IsIA64() && !bActivated && (ERROR_SUCCESS != ReArm())) { // Display warning that grace period limit has reached and cannot
// re-active grace period, and we continue thru.
//
MessageBoxFromMessage( MSG_REARM_ERROR, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL ); }
#if defined(_WIN64)
//
// For EFI machines set the boot timeout to 5 seconds so that developers get a chance to see
// the boot menu and have the option to boot to the EFI shell, CD, or other menu options,
// for development purposes.
//
ChangeBootTimeout(5);
#else
ChangeBootTimeout(0); // reset the timeout to 0 secs
#endif // !defined(_WIN64)
//
// First part of reseal.
//
AdjustFiles();
//
// Second part of reseal.
//
// This is common reseal code used by both Riprep and Sysprep.
// These happen whether or not factory floor was run before.
//
if (!FCommonReseal()) { MessageBoxFromMessage( MSG_COMMON_ERROR, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL ); return FALSE; } // ISSUE-2000/06/06-DONALDM
// We need to handle the network configuration problem for factory more cleanly
// We need to define what the network state is when factory first comes up, and
// what the network state is for final customer delivery. Simply disjoining from
// a domain during reseal is probably not enough...
//
// if( !UnjoinNetworkDomain())
// {
// // We failed to disjoin. Our only option is to
// // inform the user and bail.
// MessageBoxFromMessage( MSG_DOMAIN_INCOMPATIBILITY,
// AppTitleStringId,
// MB_OK | MB_ICONSTOP | MB_TASKMODAL );
// return FALSE;
// }
//
// Set default middleware applications.
//
if (!SetDefaultOEMApps(g_szWinBOMPath)) { // SetDefaultApplications will do its own MessageBoxFromMessage
// with more detailed information
return FALSE; }
// Call functions in published SYSPREP_.C file that we skiped when the
// FACTORY option was selected
// ISSUE-2000/06/05-DONALDM - We need to really decide about how to handle network settings for
// the factory case. I think we don't need this call, becase we should have
// already dealt with networking settings when FACTORY.EXE ran.
//
// RemoveNetworkSettings(NULL);
return TRUE; }
// Macro for processing command line options.
// Setting bVar to 1 (not to 'TRUE') because we need it for mutually exclusive option checks below.
//
#define CHECK_PARAM(lpCmdLine, lpOption, bVar) if ( LSTRCMPI(lpCmdLine, lpOption) == 0 ) bVar = 1
//
// Parse command line parameters
//
static BOOL ParseCmdLine() { DWORD dwArgs; LPTSTR *lpArgs; BOOL bError = FALSE; BOOL bHelp = FALSE;
if ( (dwArgs = GetCommandLineArgs(&lpArgs) ) && lpArgs ) { LPTSTR lpArg; DWORD dwArg;
// We want to skip over the first argument (it is the path
// to the command being executed.
//
if ( dwArgs > 1 ) { dwArg = 1; lpArg = *(lpArgs + dwArg); } else lpArg = NULL;
// Loop through all the arguments.
//
while ( lpArg && !bError ) { // Now we check to see if the first char is a dash or forward slash.
//
if ( *lpArg == _T('-') || *lpArg == _T('/')) { LPTSTR lpOption = CharNext(lpArg);
// This is where you add command line options that start with a dash (-).
//
CHECK_PARAM( lpOption, _T("quiet"), QuietMode); CHECK_PARAM( lpOption, _T("nosidgen"), NoSidGen); CHECK_PARAM( lpOption, _T("pnp"), PnP); CHECK_PARAM( lpOption, _T("noreboot"), NoReboot); CHECK_PARAM( lpOption, _T("reboot"), Reboot); CHECK_PARAM( lpOption, _T("clean"), Clean); CHECK_PARAM( lpOption, _T("forceshutdown"), ForceShutdown); CHECK_PARAM( lpOption, _T("factory"), Factory); CHECK_PARAM( lpOption, _T("reseal"), Reseal); CHECK_PARAM( lpOption, _T("mini"), bMiniSetup); CHECK_PARAM( lpOption, _T("audit"), Audit); CHECK_PARAM( lpOption, _T("activated"), bActivated); CHECK_PARAM( lpOption, _T("bmsd"), BuildMSD); CHECK_PARAM( lpOption, _T("dc"), bDC); CHECK_PARAM( lpOption, _T("?"), bHelp); } else if ( *lpArg ) { bError = TRUE; }
// Setup the pointer to the next argument in the command line.
//
if ( ++dwArg < dwArgs ) lpArg = *(lpArgs + dwArg); else lpArg = NULL; }
// Make sure to free the two buffers allocated by the GetCommandLineArgs() function.
//
FREE(*lpArgs); FREE(lpArgs); } if (bError || bHelp) { // Set the quiet switch in this case so we display the error.
// Note that we return FALSE and exit the application following this.
//
QuietMode = FALSE; MessageBoxFromMessage( MSG_USAGE, AppTitleStringId, MB_OK | MB_TASKMODAL ); return FALSE; }
//
// Now look at the switches passed in and make sure that they are consistent.
// If they are not, display an error message and quit, unless we're in quiet
// mode where we do not display any error messages.
//
//
// Check that the shutdown options are not conflicting with each other.
if ( (NoReboot + Reboot + ForceShutdown) > 1 ) { bError = TRUE; } // These top-level options are exclusive: -bmsd, -clean, -audit, -factory, -reseal.
//
else if ( (BuildMSD + Clean + Audit + Factory + Reseal) > 1 ) { bError = TRUE; } // For Clean or BuildMSD none of the options except -quiet are valid.
//
else if ( Clean || BuildMSD ) { if ( NoSidGen || PnP || NoReboot || Reboot || ForceShutdown || bMiniSetup || bActivated ) { bError = TRUE; } } else if ( Audit ) { if ( NoSidGen || PnP || bMiniSetup || bActivated ) { bError = TRUE; } } else if ( Factory ) { if ( PnP || bMiniSetup ) { bError = TRUE; } } else if ( Reseal ) { // If -pnp is specified -mini must have been specified unless we're running on server or ia64 (because
// later we force bMiniSetup to be true on server and ia64.
//
if ( PnP && !bMiniSetup && !(IsServerSKU() || IsIA64()) ) { bError = TRUE; } }
// If there was some inconsistency in the switches specified put up
// an error message.
if ( bError ) { // Reset the quiet switch in this case so we display the error.
// Note that we return FALSE and exit the application following this.
//
QuietMode = FALSE; MessageBoxFromMessage( MSG_USAGE_COMBINATIONS, AppTitleStringId, MB_OK | MB_TASKMODAL | MB_ICONERROR); return FALSE; } // Force MiniSetup on IA64 and Servers.
//
if (IsIA64() || IsServerSKU()) { bMiniSetup = TRUE; } else if ( IsPersonalSKU() ) { if ( bMiniSetup ) { // Can't specify mini-setup for personal sku
//
MessageBoxFromMessage( MSG_NO_MINISETUP, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL ); bMiniSetup = FALSE; }
if ( PnP ) { // Can't specify -pnp because we're not running mini-setup on personal sku.
//
MessageBoxFromMessage( MSG_NO_PNP, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL ); PnP = FALSE; } } //
// If we're cleaning up the critical device database,
// then we'll be wanting to set some additional flags.
//
if (Clean || BuildMSD) { QuietMode = TRUE; NoReboot = TRUE; } return !bError; }
BOOL IsFactoryPresent( VOID )
/*++
=============================================================================== Routine Description:
This routine tests to see if FACTORY.EXE is present on the machine. FACTORY.EXE will be required to run on reboot, so if it's not here, we need to know.
Arguments:
None.
Return Value:
TRUE - FACTORY.EXE is present.
FALSE - FACTORY.EXE is not present.
=============================================================================== --*/
{ WCHAR FileName[MAX_PATH];
// Attempt to locate FACTORY.EXE
//
if (GetModuleFileName(NULL, FileName, MAX_PATH)) { if (PathRemoveFileSpec(FileName)) { OPKAddPathN(FileName, TEXT("FACTORY.EXE"), AS ( FileName )); if (FileExists(FileName)) return TRUE; } } return FALSE; }
void PowerOff(BOOL fForceShutdown) { SYSTEM_POWER_CAPABILITIES spc; ULONG uiFlags = EWX_POWEROFF;
ZeroMemory(&spc, sizeof(spc));
// Make sure we have privilege to shutdown
//
pSetupEnablePrivilege(SE_SHUTDOWN_NAME,TRUE);
//
// Use flag else query system for power capabilities
//
if (fForceShutdown) uiFlags = EWX_SHUTDOWN; else if (NT_SUCCESS(NtPowerInformation(SystemPowerCapabilities, NULL, 0, &spc, sizeof(spc)))) { //
// spc.SystemS1 == sleep 1
// spc.SystemS2 == sleep 2
// spc.SystemS3 == sleep 3
// spc.SystemS4 == hibernate support
// spc.SystemS5 == poweroff support
//
if (spc.SystemS5) { // ACPI capable
uiFlags = EWX_POWEROFF; } else { // Non-ACPI
uiFlags = EWX_SHUTDOWN; } }
ExitWindowsEx(uiFlags|EWX_FORCE, SYSPREP_SHUTDOWN_FLAGS); }
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) /*++
=============================================================================== Routine Description:
This routine is the main entry point for the program.
We do a bit of error checking, then, if all goes well, we update the registry to enable execution of our second half.
=============================================================================== --*/
{ DWORD dwVal; HKEY hKey; LPTSTR lpFilePart = NULL; INITCOMMONCONTROLSEX icex; LPTSTR lpAppName = NULL;
ghInstance = hInstance;
SetErrorMode(SEM_FAILCRITICALERRORS);
memset(&icex, 0, sizeof(icex)); icex.dwSize = sizeof(icex); icex.dwICC = ICC_PROGRESS_CLASS|ICC_ANIMATE_CLASS; InitCommonControlsEx(&icex); // We need the path to sysprep.exe and where it is located.
//
GetModuleFileName(NULL, g_szSysprepPath, AS(g_szSysprepPath)); if ( GetFullPathName(g_szSysprepPath, AS(g_szSysprepDir), g_szSysprepDir, &lpFilePart) && g_szSysprepDir[0] && lpFilePart ) { // Chop off the file name.
//
*lpFilePart = NULLCHR; }
// If either of those file, we must quit (can't imagine that every happening).
//
if ( ( g_szSysprepPath[0] == NULLCHR ) || ( g_szSysprepDir[0] == NULLCHR ) ) { // TODO: Log this failure.
//
// LogFile(WINBOM_LOGFILE, _T("\n"));
return 0; }
// Need the full path to the log file.
//
StringCchCopy ( g_szLogFile, AS ( g_szLogFile ), g_szSysprepDir); AddPath(g_szLogFile, SYSPREP_LOG);
// Attempt to aquire a lock on the application
//
if ( !LockApplication(TRUE) ) { // Let the user know that we are busy
//
MessageBoxFromMessage( MSG_ALREADY_RUNNING, AppTitleStringId, MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL ); return 0;
}
//
// Check to see if we are allowed to run on this build of the OS
//
if ( !OpklibCheckVersion( VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE ) ) { MessageBoxFromMessage( MSG_NOT_ALLOWED, AppTitleStringId, MB_OK | MB_ICONERROR | MB_SYSTEMMODAL ); return 0; } // Ensure that the user has privilege/access to run this app.
if(!pSetupIsUserAdmin() || !pSetupDoesUserHavePrivilege(SE_SHUTDOWN_NAME) || !pSetupDoesUserHavePrivilege(SE_BACKUP_NAME) || !pSetupDoesUserHavePrivilege(SE_RESTORE_NAME) || !pSetupDoesUserHavePrivilege(SE_SYSTEM_ENVIRONMENT_NAME)) {
MessageBoxFromMessage( MSG_NOT_AN_ADMINISTRATOR, AppTitleStringId, MB_OK | MB_ICONSTOP | MB_TASKMODAL );
LockApplication(FALSE); return 0; }
// Check the command line
if( !ParseCmdLine() ) { LockApplication(FALSE); return 0; }
// Determines whether we can run SidGen. If not quit the application
//
// Make sure setupcl.exe is present in the system32 directory, if we need
// to use it.
if( !(SetupClPresent = IsSetupClPresent()) && !NoSidGen ) { MessageBoxFromMessage( MSG_NO_SUPPORT, AppTitleStringId, MB_OK | MB_ICONSTOP | MB_TASKMODAL );
LockApplication(FALSE); return 1; }
// Put up a dialog to identify ourselves and make sure the user
// really wants to do this.
if ( IDCANCEL == MessageBoxFromMessage( MSG_IDENTIFY_SYSPREP, AppTitleStringId, MB_OKCANCEL| MB_ICONEXCLAMATION | MB_SYSTEMMODAL ) ) { LockApplication(FALSE); return 0; }
// Allocate memory for window
//
if ( (lpAppName = AllocateString(NULL, IDS_APPNAME)) && *lpAppName ) { ghwndOemResetDlg = FindWindow(NULL, lpAppName);
// Free up the allocated memory
//
FREE(lpAppName); }
DisableScreenSaver(&gbScreenSaver);
//
// Call RenameWinbom() once to initialize it. First time it is called it will check the factory
// state registry key for the current winbom.ini that we are using. The second time it gets called it
// will actually perform the rename if necessary. Make sure that the first time this gets called
// for intialization it is before LocateWinBom() because LocateWinBom() populates the registry with
// the winbom it finds.
//
RenameWinbom(); // Need full path to winbom too. It is not an error if the file is
// not found. (It is optional.)
//
LocateWinBom(g_szWinBOMPath, AS(g_szWinBOMPath), g_szSysprepDir, INI_VAL_WBOM_TYPE_FACTORY, LOCATE_NORMAL); // Process switches
//
if ( !FProcessSwitches() && !ghwndOemResetDlg) { ShowOemresetDialog(hInstance); }
EnableScreenSaver(&gbScreenSaver);
// Unlock application and free up memory
//
LockApplication(FALSE);
return 0; }
// Factory Preinstall now also prepares the machine
//
BOOL FDoFactoryPreinstall() { HKEY hKey; DWORD dwVal;
if (!IsFactoryPresent()) { MessageBoxFromMessage( MSG_NO_FACTORYEXE, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL );
return FALSE; }
// Setup factory.exe for factory floor
//
if (!SetupForFactoryFloor()) { MessageBoxFromMessage( MSG_SETUPFACTORYFLOOR_ERROR, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL );
return FALSE; }
// Prepare machine to be hardware independent for factory floor
//
if (!FPrepareMachine()) { MessageBoxFromMessage( MSG_REGISTRY_ERROR, AppTitleStringId, MB_OK | MB_ICONERROR | MB_TASKMODAL ); return FALSE; }
// Set the boot timeout for boot on factory floor
if (!ChangeBootTimeout( 1 )) return FALSE;
return TRUE; }
// Prepares the machine to be hardware independent
//
BOOL FPrepareMachine() { TCHAR szSysprepInf[MAX_PATH] = TEXT("");
//
// Make sure we've got the required privileges to update the registry.
//
pSetupEnablePrivilege(SE_RESTORE_NAME,TRUE); pSetupEnablePrivilege(SE_BACKUP_NAME,TRUE);
// Build path to sysprep.inf from where sysprep.exe is located
//
if (GetModuleFileName(NULL, szSysprepInf, MAX_PATH)) { PathRemoveFileSpec(szSysprepInf); OPKAddPathN(szSysprepInf, TEXT("sysprep.inf"), AS ( szSysprepInf ) ); }
// Disable System Restore
//
DisableSR();
// Make sure we're not a member of a domain. If we are, then try and
// force the unjoin.
//
if( !bDC && !UnjoinNetworkDomain()) { // We failed to disjoin. Our only option is to
// inform the user and bail.
MessageBoxFromMessage( MSG_DOMAIN_INCOMPATIBILITY, AppTitleStringId, MB_OK | MB_ICONSTOP | MB_TASKMODAL ); return FALSE; }
#if !defined(_WIN64)
// Set the boot disk signature in the registry. The mount manager uses this
// to avoid a PNP pop-up after imaging.
//
if ( !SaveDiskSignature() ) { return FALSE; } #endif // !defined(_WIN64)
// Determine if we should set the BigLba support in registry
//
if ( !SetBigLbaSupport(szSysprepInf) ) { return FALSE; }
// Determine if we should remove the tapi settings
//
if ( !RemoveTapiSettings(szSysprepInf) ) { return FALSE; }
// Set OEMDuplicatorString
if (!SetOEMDuplicatorString(szSysprepInf)) return FALSE;
// If we want to regenerate the SID's on the next boot do it.
//
if ( NoSidGen ) { // Remember that we didn't generate SIDs
//
RegSetDword(HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_SIDGEN, 0); } else { if ( PrepForSidGen() ) { // Write out registry value so that we know that we've regenerated SIDs.
//
RegSetDword(HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_SIDGEN, 1);
// Set this registry key, only UpdateSecurityKeys can remove this key
//
RegSetDword(HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_SIDGENHISTORY, 1); } else { return FALSE; } }
// If Mass Storage Devices were installed, clean up the ones not being used.
// Note: We only want to CleanUpDevices() if we are resealing. This is the equivalent of
// automatically running "sysprep -clean" on reseal if we know that we need to do it.
//
if ( RegCheck(HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_MASS_STORAGE)) { if ( Reseal ) { // Clean the critical device database, since we might have put some
// HDC and network drivers in there during factory floor from PopulateDeviceDatabase()
CleanUpDevices();
// Remove this key because we just ran CleanUpDevices().
//
RegDelete(HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_MASS_STORAGE); } } else { BOOL fPopulated = FALSE;
// Set up Hardware independence for mass storage controllers.
//
BuildMassStorageSection(FALSE); if (!PopulateDeviceDatabase(&fPopulated)) return FALSE; // Write out signature value to know that we have built the mass-storage section.
//
if ( fPopulated && !RegSetDword(HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_MASS_STORAGE, 1) ) return FALSE; }
// Cleaning up the Parallel Port
//
CleanupParallelDevices();
// Remember the mount manager settings
//
if ( !RememberAndClearMountMgrSettings() ) return FALSE; // Remove network settings/card last so any errors during Device Database won't loose
// networking.
//
if (!RemoveNetworkSettings(szSysprepInf)) return FALSE;
return TRUE; }
// Reseal and Factory should behave the same according to the shutdown path.
//
void DoShutdownTypes() { pSetupEnablePrivilege(SE_SHUTDOWN_NAME,TRUE);
if (Reboot) ExitWindowsEx(EWX_REBOOT|EWX_FORCE, SYSPREP_SHUTDOWN_FLAGS); else if (NoReboot) PostQuitMessage(0); else PowerOff(ForceShutdown); // Default
}
// Process action switches return TRUE if processed
//
BOOL FProcessSwitches() { // There are currently 4 basic operating modes for SYSPREP:
// 1) Factory floor mode. This mode is new for Whistler and will not completly
// clone the system, but will prep the system for OEM factory floor installation
// 2) Clean mode. In this mode, sysprep will clean up the critical device database
// 3) Reseal mode. This is the complement to factory mode which will "complete" the
// cloning process after factory floor mode has been used.
// 4) "Audit" mode. The system just executes an audit boot. Used to restart the system
// at the end of factory.exe processing.
// These are just flags for reseal
//
if (Reseal) { StartWaitThread(); // Ensure that we're running on the right OS.
//
if( !CheckOSVersion() ) { MessageBoxFromMessage( MSG_OS_INCOMPATIBILITY, AppTitleStringId, MB_OK | MB_ICONSTOP | MB_TASKMODAL ); return TRUE; }
// Reseal the machine
//
if (!ResealMachine()) { MessageBoxFromMessage( MSG_RESEAL_ERROR, AppTitleStringId, MB_OK | MB_ICONSTOP | MB_TASKMODAL );
return TRUE;
}
// Rename the current winbom so we don't use it again.
//
RenameWinbom();
// Shutdown or reboot?
DoShutdownTypes();
EndWaitThread(); return TRUE; } else if (Factory) { StartWaitThread();
// Set Factory to start on next boot and prepare for imaging
//
if (!FDoFactoryPreinstall()) return TRUE;
// Rename the current winbom so we don't use it again.
//
RenameWinbom();
// Shutdown or reboot?
DoShutdownTypes();
EndWaitThread();
return TRUE; } else if (Clean) { CleanUpDevices();
// Remove this key because we just ran CleanUpDevices().
//
RegDelete(HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_MASS_STORAGE); return TRUE; } else if (Audit) { // Prepare for pseudo factory but get back to audit.
//
if ( RegCheck(HKLM, REGSTR_PATH_SYSTEM_SETUP, REGSTR_VALUE_AUDIT) ) { TCHAR szFactoryPath[MAX_PATH] = NULLSTR; // Going into Audit mode requires Factory.exe and winbom.ini
// to exist.
//
if (FGetFactoryPath(szFactoryPath)) { SetFactoryStartup(szFactoryPath); DoShutdownTypes(); } else { LogFile(g_szLogFile, MSG_NO_FACTORYEXE);
MessageBoxFromMessage( MSG_NO_FACTORYEXE, IDS_APPTITLE, MB_OK | MB_ICONERROR | MB_TASKMODAL ); } } else { LogFile(g_szLogFile, IDS_ERR_FACTORYMODE); } return TRUE; } else if (BuildMSD) { StartWaitThread(); BuildMassStorageSection(TRUE /* Force build */); EndWaitThread(); return TRUE; } // Return False to show the UI
//
Reseal = Factory = Clean = Audit = 0; return FALSE; }
BOOL LockApplication(BOOL bState) { static HANDLE hMutex; BOOL bReturn = FALSE, bBail = FALSE; DWORD dwSleepCount = 0;
// We want to lock the application
//
if ( bState ) { // Check to see if we can create the mutex and that the mutex did not
// already exist
//
while ( !bReturn && (dwSleepCount < SYSPREP_LOCK_SLEEP_COUNT) && !bBail) { SetLastError(ERROR_SUCCESS);
if ( hMutex = CreateMutex(NULL, FALSE, SYSPREP_MUTEX) ) { if ( GetLastError() == ERROR_ALREADY_EXISTS ) { CloseHandle(hMutex); hMutex = NULL;
dwSleepCount++; Sleep(SYSPREP_LOCK_SLEEP); } else { // Application successfully created lock
//
bReturn = TRUE; } } else { bBail = TRUE; } } } else if ( hMutex ) { CloseHandle(hMutex); hMutex = NULL; bReturn = TRUE; }
// Return whether or not the lock/unlock was successful
//
return bReturn; }
//
// Shutdown or Reboot the machine
//
VOID ShutdownOrReboot(UINT uFlags, DWORD dwReserved) { // Enable privileges for shutdown
//
EnablePrivilege(SE_SHUTDOWN_NAME, TRUE);
// Shutdown or Reboot the machine
//
ExitWindowsEx(uFlags|EWX_FORCE, dwReserved); }
// Remember the Screen Saver state and to disable it during Sysprep
//
void DisableScreenSaver(BOOL *pScreenSaver) { SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, (PVOID)pScreenSaver, 0); if (*pScreenSaver == TRUE) { SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, SPIF_SENDWININICHANGE); } }
// Remember the Screen Saver state and to re-enable it after Sysprep
//
void EnableScreenSaver(BOOL *pScreenSaver) { if (*pScreenSaver == TRUE) { SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, TRUE, 0, SPIF_SENDWININICHANGE); } }
// Rename the old winbom when going into factory or reseal so that we don't use it again by mistake.
static BOOL RenameWinbom() { BOOL bRet = TRUE; static LPTSTR lpszWinbom = NULL; static BOOL bInitialized = FALSE;
if ( !bInitialized ) { // Only bother to try if we are in audit mode and there
// is a winbom in use.
//
if ( RegCheck(HKLM, _T("SYSTEM\\Setup"), _T("AuditInProgress")) ) { lpszWinbom = RegGetExpand(HKLM, _T("SOFTWARE\\Microsoft\\Factory\\State"), _T("Winbom")); } bInitialized = TRUE; } else if ( lpszWinbom ) { // Make sure the winbom in the registry exists.
//
if ( *lpszWinbom && FileExists(lpszWinbom) ) { LPTSTR lpszExtension; TCHAR szBackup[MAX_PATH]; DWORD dwExtra;
// At this point, if we don't rename the file then it
// means there was an error.
//
bRet = FALSE;
// Copy the full path to the winbom into our own buffer.
//
lstrcpyn(szBackup, lpszWinbom, AS(szBackup));
// Get a pointer to the extension of the file name.
//
if ( lpszExtension = StrRChr(szBackup, NULL, _T('.')) ) { // Set the extension pointer to after the '.' character.
//
lpszExtension = CharNext(lpszExtension);
// See how many characters are in the current extension.
//
if ( (dwExtra = lstrlen(lpszExtension)) < 3 ) { // There is less then a 3 character extension, so
// we need some extra space for our 3 digit one.
//
dwExtra = 3 - dwExtra; } else { // If there are already at least 3 characters in
// the exension, then no more space is required.
//
dwExtra = 0; } } else { // No extension, so we need 4 characters extra for
// the '.' and the 3 digit extension.
//
dwExtra = 4; }
// Make sure there is enough room for our extension to be
// added to our buffer.
//
if ( ( lstrlen(lpszWinbom) < AS(szBackup) ) && ( lstrlen(szBackup) + dwExtra < AS(szBackup) ) ) { DWORD dwNum = 0;
// If there is no extension, add the dot.
//
if ( NULL == lpszExtension ) { // Add our '.' to the end of the string, and set the
// extension pointer past it.
//
lpszExtension = szBackup + lstrlen(szBackup); *lpszExtension = _T('.'); lpszExtension = CharNext(lpszExtension); }
// Try to find out new file name. Keep increasing our
// number from 000 until we find a name that doesn't exist.
//
do { StringCchPrintf ( lpszExtension, AS ( szBackup ) - ( szBackup - lpszExtension), _T("%3.3d"), dwNum); } while ( ( FileExists(szBackup) ) && ( ++dwNum < 1000 ) );
// If we found a name that doesn't exist, rename
// the winbom.
//
if ( dwNum < 1000 ) { // If the move works, then return success.
//
bRet = MoveFile(lpszWinbom, szBackup); } } }
// Free the buffer allocated.
//
FREE(lpszWinbom); }
// Return TRUE if we didn't need to rename the winbom,
// or we were able to do so successfully.
//
return bRet; }
#if !defined(_WIN64)
static BOOL SaveDiskSignature() { BOOL bRet = FALSE; WCHAR szBuf[MAX_PATH] = NULLSTR; HANDLE hDisk; DWORD dwBytesReturned = 0; TCHAR cDriveLetter;
szBuf[0] = NULLCHR; if ( GetWindowsDirectory(szBuf, AS(szBuf)) && szBuf[0] ) { // We only need the drive letter from this.
cDriveLetter = szBuf[0]; StringCchPrintf ( szBuf, AS ( szBuf ), _T("\\\\.\\%c:"), cDriveLetter); } else { return FALSE; }
// Attempt to open the file
//
hDisk = CreateFile( szBuf, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
// Check to see if we were able to open the disk
//
if ( INVALID_HANDLE_VALUE == hDisk ) { bRet = FALSE; DbgPrint("SaveDiskSignature(): Unable to open file on %ws. Error (%lx)\n", szBuf, GetLastError()); } else { PDRIVE_LAYOUT_INFORMATION_EX pLayoutInfoEx = NULL; ULONG lengthLayoutEx = 0; DbgPrint("SaveDiskSignature(): Successfully opened file on %ws\n", szBuf);
lengthLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX) * 128); pLayoutInfoEx = (PDRIVE_LAYOUT_INFORMATION_EX) MALLOC( lengthLayoutEx ); if ( pLayoutInfoEx ) { // Attempt to get the drive layout
//
bRet = DeviceIoControl( hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, pLayoutInfoEx, lengthLayoutEx, &dwBytesReturned, NULL );
// Check the status of the drive layout
//
if ( bRet ) { // Only do this on MBR disks
//
if ( PARTITION_STYLE_MBR == pLayoutInfoEx->PartitionStyle ) { // Only set this value on MBR disks.
//
if ( !RegSetDword(HKEY_LOCAL_MACHINE, REGSTR_PATH_SYSTEM_SETUP, REGSTR_VAL_DISKSIG, pLayoutInfoEx->Mbr.Signature) ) { DbgPrint("SaveDiskSignature(): Cannot write disk signature to registry\n."); bRet = FALSE; } } else { // bRet = TRUE at this point.
DbgPrint("SaveDiskSignature(): Not supported on GPT disks.\n"); } } else { DbgPrint("SaveDiskSignature(): Unable to open IOCTL on %ws. Error (%lx)\n", szBuf, GetLastError()); } // Clean up. Macro checks for NULL;
//
FREE( pLayoutInfoEx ); } else { bRet = FALSE; } CloseHandle( hDisk ); } return bRet; }
#endif // !defined(_WIN64)
//
// Helper function for CleanupPhantomDevices. Decides whether it is ok to remove
// certain PNP devices.
//
BOOL CanDeviceBeRemoved( HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PTSTR DeviceInstanceId ) { BOOL bCanBeRemoved = TRUE;
if (_tcsicmp(DeviceInstanceId, TEXT("HTREE\\ROOT\\0")) == 0) { //
// The device has the DeviceInstanceId of HTREE\ROOT\0 then it is the
// root of the device tree and can NOT be removed!
//
bCanBeRemoved = FALSE; } else if (_tcsnicmp(DeviceInstanceId, TEXT("SW\\"), lstrlen(TEXT("SW\\"))) == 0) { //
// If the DeviceInstanceId starts with SW\\ then it is a swenum (software
// enumerated) device and should not be removed.
//
bCanBeRemoved = FALSE; } else if (IsEqualGUID(&(DeviceInfoData->ClassGuid), &GUID_DEVCLASS_LEGACYDRIVER)) { //
// If the device is of class GUID_DEVCLASS_LEGACYDRIVER then do not
// uninstall it.
//
bCanBeRemoved = FALSE; }
return bCanBeRemoved; }
//
// Cleans up phantom PNP devices. This is useful for cleaning up devices that existed
// on the machine that was imaged but do not exist on the target machine.
//
static INT CleanupPhantomDevices( VOID ) { HDEVINFO DeviceInfoSet; HDEVINFO InterfaceDeviceInfoSet; SP_DEVINFO_DATA DeviceInfoData; SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; INT DevicesRemoved = 0; INT MemberIndex, InterfaceMemberIndex; DWORD Status, Problem; CONFIGRET cr; TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
//
// Get a list of all the devices on this machine, including present (live)
// and not present (phantom) devices.
//
DeviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES );
if (DeviceInfoSet != INVALID_HANDLE_VALUE) {
DeviceInfoData.cbSize = sizeof(DeviceInfoData); MemberIndex = 0;
//
// Enumerate through the list of devices.
//
while (SetupDiEnumDeviceInfo(DeviceInfoSet, MemberIndex++, &DeviceInfoData )) {
//
// Check if this device is a Phantom
//
cr = CM_Get_DevNode_Status(&Status, &Problem, DeviceInfoData.DevInst, 0 );
if ((cr == CR_NO_SUCH_DEVINST) || (cr == CR_NO_SUCH_VALUE)) {
//
// This is a phantom. Now get the DeviceInstanceId so we
// can display/log this as output.
//
if (SetupDiGetDeviceInstanceId(DeviceInfoSet, &DeviceInfoData, DeviceInstanceId, sizeof(DeviceInstanceId)/sizeof(TCHAR), NULL)) {
if (CanDeviceBeRemoved(DeviceInfoSet, &DeviceInfoData, DeviceInstanceId)) {
#ifdef DEBUG_LOGLOG
LOG_Write(L"CLEANUP: %s will be removed.\n", DeviceInstanceId); #endif
//
// Call DIF_REMOVE to remove the device's hardware
// and software registry keys.
//
if (SetupDiCallClassInstaller(DIF_REMOVE, DeviceInfoSet, &DeviceInfoData )) { DevicesRemoved++; } else { #ifdef DEBUG_LOGLOG
LOG_Write(L"CLEANUP: Error 0x%X removing phantom\n", GetLastError()); #endif
} } } } }
SetupDiDestroyDeviceInfoList(DeviceInfoSet); } return DevicesRemoved; }
#define REGSTR_PATH_PARVDM REGSTR_PATH_SERVICES _T("\\ParVdm")
#define REGSTR_VAL_START _T("Start")
//
// This code special cases the legacy parallel devices on a machine that is being resealed. We must disable the
// PARVDM service and enumerate through all system parallel devices, setting them to reinstall on the next boot.
//
static VOID CleanupParallelDevices( VOID ) { HDEVINFO DeviceInfoSet = NULL; SP_DEVICE_INTERFACE_DATA DevInterfaceData; SP_DEVINFO_DATA DevInfoData; GUID Guid = GUID_PARALLEL_DEVICE; // GUID for all Parallel devices on the system
DWORD dwConfigFlags = 0, dwIndex = 0;
//
// Disable the PARVDM service
//
RegSetDword(HKLM, REGSTR_PATH_PARVDM, REGSTR_VAL_START, 4);
//
// Mark all Parallel devices for reinstall
//
// Get the class of devices
//
DeviceInfoSet = SetupDiGetClassDevs(&Guid, NULL, NULL, DIGCF_INTERFACEDEVICE);
// Did we successfully get device list
//
if (DeviceInfoSet != INVALID_HANDLE_VALUE) { // Zero out the structure and set the size
//
ZeroMemory( &DevInterfaceData, sizeof(DevInterfaceData) ); DevInterfaceData.cbSize = sizeof(DevInterfaceData); // Enumerate through each device
//
while (DevInfoData.cbSize = sizeof(DevInfoData), SetupDiEnumDeviceInfo(DeviceInfoSet, dwIndex, &DevInfoData)) { // Increment our indexer
//
dwIndex++;
// Attempt to get the device's current config flags property
//
if ( SetupDiGetDeviceRegistryProperty(DeviceInfoSet, &DevInfoData, SPDRP_CONFIGFLAGS, NULL, (PVOID) &dwConfigFlags, sizeof(dwConfigFlags), NULL ) ) { // OR in the reinstall flag for the property
//
dwConfigFlags |= CONFIGFLAG_REINSTALL;
// Attempt to set the flag in the registry
//
if( !SetupDiSetDeviceRegistryProperty( DeviceInfoSet, &DevInfoData, SPDRP_CONFIGFLAGS, (PVOID)&dwConfigFlags, sizeof( dwConfigFlags ) ) ) { #ifdef DEBUG_LOGLOG
LOG_Write(L"CLEANUP: Failed to mark parallel port for reinstall.\n"); #endif
} else { #ifdef DEBUG_LOGLOG
LOG_Write(L"CLEANUP: Successfully marked parallel port for reinstall.\n"); #endif
} } }
// Clean up the set list
//
SetupDiDestroyDeviceInfoList(DeviceInfoSet); } return; }
// Cleans unused services and phantom PNP devices.
//
static VOID CleanUpDevices() { // Cleanup the services that we installed in the [SysprepMassStorage] section.
//
CleanDeviceDatabase(); // Cleanup phantom devices.
//
CleanupPhantomDevices(); }
BOOL CheckOSVersion( VOID )
/*++
=============================================================================== Routine Description:
This routine returns TRUE if the OS that we're running on meets the specified criteria.
Arguments:
NONE
Return Value:
TRUE - OS meets all criteria.
FALSE - Failed to meet some criteria.
=============================================================================== --*/
{ OSVERSIONINFOEX OsVersionEx = {0}; BOOL bRet = FALSE; //
// Get the OS version. We need to make sure we're on NT5. We need to make sure we are not a DC,
// except if the user specified that he wants to sysprep a DC on the command line and we're running on SBS.
//
OsVersionEx.dwOSVersionInfoSize = sizeof(OsVersionEx); if ( ( GetVersionEx( (LPOSVERSIONINFO) &OsVersionEx) ) && ( OsVersionEx.dwMajorVersion >= 5 ) ) { if ( bDC && ( OsVersionEx.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED ) ) { bRet = TRUE; } else { PSERVER_INFO_101 pSI = NULL;
//
// Make sure we're not a Domain Controller (either primary or backup)
//
if ( ( NERR_Success == NetServerGetInfo( NULL, 101, (LPBYTE *) &pSI ) ) && ( pSI ) && !( pSI->sv101_type & SV_TYPE_DOMAIN_CTRL ) && !( pSI->sv101_type & SV_TYPE_DOMAIN_BAKCTRL ) ) { // He's not a DC. Succeed.
//
bRet = TRUE; } // Free up the buffer allocated by NetServerGetInfo.
//
if ( pSI ) { NetApiBufferFree( pSI ); } } }
return bRet; }
BOOL RememberAndClearMountMgrSettings( VOID ) /*++
=============================================================================== Routine Description:
Saves the current MountMgr noautomount setting to the sysprep keys and clears it from the MountMgr service key.
Arguments:
NONE
Return Value:
TRUE - Operations succeeded.
FALSE - Operations failed.
=============================================================================== --*/ { BOOL bRet = TRUE; DWORD dwNoAutoMount = 0; if ( RegExists( HKLM, REGSTR_PATH_SERVICES_MOUNTMGR, REGSTR_VAL_NOAUTOMOUNT ) ) { dwNoAutoMount = RegGetDword( HKLM, REGSTR_PATH_SERVICES_MOUNTMGR, REGSTR_VAL_NOAUTOMOUNT );
if ( !( RegDelete ( HKLM, REGSTR_PATH_SERVICES_MOUNTMGR, REGSTR_VAL_NOAUTOMOUNT ) && RegSetDword( HKLM, REGSTR_PATH_SYSPREP, REGSTR_VAL_NOAUTOMOUNT, dwNoAutoMount ) ) ) { bRet = FALSE; } }
return bRet; }
|