You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1296 lines
30 KiB
1296 lines
30 KiB
//*************************************************************
|
|
// File name: delprof.c
|
|
//
|
|
// Description: Utility to delete user profiles
|
|
//
|
|
//
|
|
// Microsoft Confidential
|
|
// Copyright (c) Microsoft Corporation 1996
|
|
// All rights reserved
|
|
//
|
|
//*************************************************************
|
|
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <stdio.h>
|
|
#include <locale.h>
|
|
#include <strsafe.h>
|
|
#include "delprof.h"
|
|
#include "userenv.h"
|
|
|
|
#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
#define VALID_COMPUTER_NAME_LENGTH MAX_COMPUTERNAME_LENGTH + 3 // including \\ with Null terminator
|
|
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
BOOL bQuiet;
|
|
BOOL bIgnoreErrors;
|
|
BOOL bPromptBeforeDelete;
|
|
BOOL bLocalComputer = FALSE;
|
|
TCHAR szComputerName[MAX_PATH];
|
|
TCHAR szSystemRoot[2*MAX_PATH];
|
|
TCHAR szSystemDrive[2*MAX_PATH];
|
|
LONG lDays;
|
|
HINSTANCE hInst;
|
|
LPDELETEITEM lpDeleteList;
|
|
LONG lCurrentDateInDays;
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// Usage()
|
|
//
|
|
// Purpose: prints the usage info
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Return: void
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
void Usage (void)
|
|
{
|
|
TCHAR szTemp[200];
|
|
|
|
LoadString (hInst, IDS_USAGE1, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf(szTemp);
|
|
|
|
LoadString (hInst, IDS_USAGE2, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf(szTemp);
|
|
|
|
LoadString (hInst, IDS_USAGE3, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf(szTemp);
|
|
|
|
LoadString (hInst, IDS_USAGE4, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf(szTemp);
|
|
|
|
LoadString (hInst, IDS_USAGE5, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf(szTemp);
|
|
|
|
LoadString (hInst, IDS_USAGE6, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf(szTemp);
|
|
|
|
LoadString (hInst, IDS_USAGE7, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf(szTemp);
|
|
|
|
LoadString (hInst, IDS_USAGE8, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf(szTemp);
|
|
|
|
LoadString (hInst, IDS_USAGE9, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf(szTemp);
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// InitializeGlobals()
|
|
//
|
|
// Purpose: Initializes the global variables
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Return: void
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
void InitializeGlobals (void)
|
|
{
|
|
OSVERSIONINFO ver;
|
|
SYSTEMTIME systime;
|
|
|
|
|
|
//
|
|
// Initialize global variables
|
|
//
|
|
|
|
bQuiet = FALSE;
|
|
bIgnoreErrors = FALSE;
|
|
bPromptBeforeDelete = FALSE;
|
|
szComputerName[0] = TEXT('\0');
|
|
lDays = 0;
|
|
lpDeleteList = NULL;
|
|
|
|
setlocale(LC_ALL,"");
|
|
|
|
hInst = GetModuleHandle(TEXT("delprof.exe"));
|
|
|
|
GetLocalTime (&systime);
|
|
|
|
lCurrentDateInDays = gdate_dmytoday(systime.wYear, systime.wMonth, systime.wDay);
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// CheckGlobals()
|
|
//
|
|
// Purpose: Checks the global variables
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Return: DWORD - ERROR_SUCCESS for success
|
|
// win32 error code for failure
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
DWORD CheckGlobals (void)
|
|
{
|
|
DWORD dwSize;
|
|
HRESULT hr;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
//
|
|
// If szComputerName is still NULL, fill in the computer name
|
|
// we're running on.
|
|
//
|
|
|
|
if (szComputerName[0] == TEXT('\0')) {
|
|
|
|
szComputerName[0] = TEXT('\\');
|
|
szComputerName[1] = TEXT('\\');
|
|
|
|
dwSize = ARRAYSIZE(szComputerName) - 2;
|
|
if (!GetComputerName(szComputerName + 2, &dwSize)) {
|
|
return GetLastError();
|
|
}
|
|
|
|
bLocalComputer = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Make sure that the computer name starts with \\
|
|
//
|
|
|
|
if (szComputerName[0] != TEXT('\\')) {
|
|
szTemp[0] = TEXT('\\');
|
|
szTemp[1] = TEXT('\\');
|
|
|
|
hr = StringCchCopy(szTemp + 2, ARRAYSIZE(szTemp) - 2, szComputerName);
|
|
if (FAILED(hr))
|
|
return HRESULT_CODE(hr);
|
|
|
|
hr = StringCchCopy(szComputerName, ARRAYSIZE(szComputerName), szTemp);
|
|
if (FAILED(hr))
|
|
return HRESULT_CODE(hr);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the user has requested to run in Quiet mode,
|
|
// then we turn off the prompt on every delete option.
|
|
//
|
|
|
|
if (bQuiet) {
|
|
bPromptBeforeDelete = FALSE;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// ParseCommandLine()
|
|
//
|
|
// Purpose: Parses the command line
|
|
//
|
|
// Parameters: lpCommandLine - Command line
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ParseCommandLine (LPTSTR lpCommandLine)
|
|
{
|
|
LPTSTR lpTemp;
|
|
DWORD cchTemp;
|
|
TCHAR szDays[32];
|
|
|
|
|
|
//
|
|
// Check for NULL command line
|
|
//
|
|
|
|
if (!lpCommandLine || !*lpCommandLine)
|
|
return TRUE;
|
|
|
|
|
|
//
|
|
// Find the executable name
|
|
//
|
|
|
|
while (*lpCommandLine && (_tcsncmp(lpCommandLine, TEXT("delprof"), 7) != 0)) {
|
|
lpCommandLine++;
|
|
}
|
|
|
|
if (!*lpCommandLine) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Find the first argument
|
|
//
|
|
|
|
while (*lpCommandLine && ((*lpCommandLine != TEXT(' ')) &&
|
|
(*lpCommandLine != TEXT('/')) &&
|
|
(*lpCommandLine != TEXT('-')))) {
|
|
lpCommandLine++;
|
|
}
|
|
|
|
|
|
//
|
|
// Skip white space
|
|
//
|
|
|
|
while (*lpCommandLine && (*lpCommandLine == TEXT(' '))) {
|
|
lpCommandLine++;
|
|
}
|
|
|
|
if (!*lpCommandLine) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// We should be at the first argument now.
|
|
//
|
|
|
|
if ((*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-'))) {
|
|
Usage();
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
while (1) {
|
|
|
|
//
|
|
// Increment the pointer and branch to the correct argument.
|
|
//
|
|
|
|
lpCommandLine++;
|
|
|
|
switch (*lpCommandLine) {
|
|
|
|
case TEXT('?'):
|
|
Usage();
|
|
ExitProcess(0);
|
|
break;
|
|
|
|
case TEXT('Q'):
|
|
case TEXT('q'):
|
|
bQuiet = TRUE;
|
|
lpCommandLine++;
|
|
break;
|
|
|
|
case TEXT('I'):
|
|
case TEXT('i'):
|
|
bIgnoreErrors = TRUE;
|
|
lpCommandLine++;
|
|
break;
|
|
|
|
case TEXT('P'):
|
|
case TEXT('p'):
|
|
bPromptBeforeDelete = TRUE;
|
|
lpCommandLine++;
|
|
break;
|
|
|
|
case TEXT('C'):
|
|
case TEXT('c'):
|
|
|
|
//
|
|
// Find the colon
|
|
//
|
|
|
|
lpCommandLine++;
|
|
|
|
if (*lpCommandLine != TEXT(':')) {
|
|
Usage();
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Find the first character
|
|
//
|
|
|
|
lpCommandLine++;
|
|
|
|
if (!*lpCommandLine) {
|
|
Usage();
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Copy the computer name
|
|
//
|
|
|
|
cchTemp = 0;
|
|
lpTemp = szComputerName;
|
|
while (*lpCommandLine && (cchTemp < ARRAYSIZE(szComputerName) - 1) &&
|
|
((*lpCommandLine != TEXT(' ')) &&
|
|
(*lpCommandLine != TEXT('/')))){
|
|
*lpTemp++ = *lpCommandLine++;
|
|
cchTemp++;
|
|
}
|
|
|
|
if (cchTemp > VALID_COMPUTER_NAME_LENGTH) {
|
|
Usage();
|
|
return FALSE;
|
|
}
|
|
|
|
*lpTemp = TEXT('\0');
|
|
|
|
break;
|
|
|
|
case TEXT('D'):
|
|
case TEXT('d'):
|
|
|
|
//
|
|
// Find the colon
|
|
//
|
|
|
|
lpCommandLine++;
|
|
|
|
if (*lpCommandLine != TEXT(':')) {
|
|
Usage();
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Find the first character
|
|
//
|
|
|
|
lpCommandLine++;
|
|
|
|
if (!*lpCommandLine) {
|
|
Usage();
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Copy the number of days (in characters)
|
|
//
|
|
|
|
lpTemp = szDays;
|
|
cchTemp = 0;
|
|
while (*lpCommandLine && (cchTemp < ARRAYSIZE(szDays) - 1) &&
|
|
((*lpCommandLine != TEXT(' ')) &&
|
|
(*lpCommandLine != TEXT('/')) &&
|
|
(*lpCommandLine != TEXT('-')))) {
|
|
*lpTemp++ = *lpCommandLine++;
|
|
cchTemp++;
|
|
}
|
|
|
|
*lpTemp = TEXT('\0');
|
|
|
|
|
|
//
|
|
// Convert the days into a number
|
|
//
|
|
|
|
lDays = _ttol(szDays);
|
|
break;
|
|
|
|
default:
|
|
Usage();
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Skip white space
|
|
//
|
|
|
|
while (*lpCommandLine && (*lpCommandLine == TEXT(' '))) {
|
|
lpCommandLine++;
|
|
}
|
|
|
|
|
|
if (!*lpCommandLine) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// We should be at the next argument now.
|
|
//
|
|
|
|
if ((*lpCommandLine != TEXT('/')) && (*lpCommandLine != TEXT('-'))) {
|
|
Usage();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// Confirm()
|
|
//
|
|
// Purpose: Confirm the user really wants to delete the profiles
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Return: TRUE if we should continue
|
|
// FALSE if not
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL Confirm ()
|
|
{
|
|
TCHAR szTemp[200];
|
|
TCHAR tChar, tTemp;
|
|
|
|
|
|
//
|
|
// If we are prompting for every profile, then don't
|
|
// give the general prompt.
|
|
//
|
|
|
|
if (bPromptBeforeDelete) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// If the user is requesting a specific day count,
|
|
// give a more appropriate confirmation message.
|
|
//
|
|
|
|
if (lDays > 0) {
|
|
LoadString (hInst, IDS_CONFIRMDAYS, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf (szTemp, szComputerName, lDays);
|
|
} else {
|
|
LoadString (hInst, IDS_CONFIRM, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf (szTemp, szComputerName);
|
|
}
|
|
|
|
tChar = _gettchar();
|
|
|
|
tTemp = tChar;
|
|
while (tTemp != TEXT('\n')) {
|
|
tTemp = _gettchar();
|
|
}
|
|
|
|
|
|
if ((tChar == TEXT('Y')) || (tChar == TEXT('y'))) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// If the user didn't press Y/y, then we bail.
|
|
//
|
|
|
|
LoadString (hInst, IDS_NO, szTemp, ARRAYSIZE(szTemp));
|
|
_tprintf (szTemp);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// PrintLastError()
|
|
//
|
|
// Purpose: Displays the last error string to the user
|
|
//
|
|
// Parameters: lError - error code
|
|
//
|
|
// Return: void
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
void PrintLastError(LONG lError)
|
|
{
|
|
TCHAR szMessage[MAX_PATH];
|
|
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
lError,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
|
|
szMessage,
|
|
ARRAYSIZE(szMessage),
|
|
NULL);
|
|
|
|
_tprintf (szMessage);
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// AddNode()
|
|
//
|
|
// Purpose: Adds a new node to the link list
|
|
//
|
|
// Parameters: szSubKey - SubKey
|
|
// szProfilePath - Profile Path (or NULL)
|
|
// bDir - Directory or file
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments: szProfilePath can be NULL. In this case, we
|
|
// are just removing the bogus registry entry.
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL AddNode (LPTSTR szSubKey, LPTSTR szProfilePath, BOOL bDir)
|
|
{
|
|
LPDELETEITEM lpItem, lpTemp;
|
|
UINT uAlloc = 0;
|
|
DWORD cchSubKeyWithNull = 0, cchProfilePathWithNull = 0;
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// Create a new node
|
|
//
|
|
|
|
cchSubKeyWithNull = lstrlen(szSubKey) + 1;
|
|
uAlloc = sizeof(DELETEITEM) + cchSubKeyWithNull * sizeof(TCHAR);
|
|
|
|
if (szProfilePath) {
|
|
cchProfilePathWithNull = lstrlen(szProfilePath) + 1;
|
|
uAlloc += cchProfilePathWithNull * sizeof(TCHAR);
|
|
}
|
|
|
|
lpItem = LocalAlloc (LPTR, uAlloc);
|
|
|
|
if (!lpItem) {
|
|
return FALSE;
|
|
}
|
|
|
|
lpItem->lpSubKey = (LPTSTR)((LPBYTE)lpItem + sizeof(DELETEITEM));
|
|
hr = StringCchCopy(lpItem->lpSubKey, cchSubKeyWithNull, szSubKey);
|
|
if (FAILED(hr)) {
|
|
LocalFree(lpItem);
|
|
return FALSE;
|
|
}
|
|
|
|
if (szProfilePath) {
|
|
lpItem->lpProfilePath = lpItem->lpSubKey + lstrlen(szSubKey) + 1;
|
|
hr = StringCchCopy(lpItem->lpProfilePath, cchProfilePathWithNull, szProfilePath);
|
|
if (FAILED(hr)) {
|
|
LocalFree(lpItem);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
lpItem->lpProfilePath = NULL;
|
|
}
|
|
|
|
lpItem->bDir = bDir;
|
|
|
|
|
|
//
|
|
// Add this node to the global lpItemList
|
|
//
|
|
|
|
if (lpDeleteList) {
|
|
lpTemp = lpDeleteList;
|
|
|
|
while (lpTemp->pNext) {
|
|
lpTemp = lpTemp->pNext;
|
|
}
|
|
|
|
lpTemp->pNext = lpItem;
|
|
} else {
|
|
lpDeleteList = lpItem;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// GetProfileDateInDays()
|
|
//
|
|
// Purpose: Gets the profile date in days.
|
|
//
|
|
// Parameters: szProfilePath - Profile path
|
|
// bDir - Directory or file
|
|
//
|
|
// Return: age in days.
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
LONG GetProfileDateInDays(LPTSTR szProfilePath, BOOL bDir)
|
|
{
|
|
TCHAR szTemp[MAX_PATH];
|
|
HANDLE hFile;
|
|
WIN32_FIND_DATA fd;
|
|
LONG days;
|
|
SYSTEMTIME systime;
|
|
FILETIME ft;
|
|
HRESULT hr;
|
|
|
|
|
|
if (bDir) {
|
|
|
|
//
|
|
// Tack on ntuser.* to find the registry hive.
|
|
//
|
|
|
|
hr = StringCchCopy(szTemp, ARRAYSIZE(szTemp), szProfilePath);
|
|
if (FAILED(hr))
|
|
return lCurrentDateInDays;
|
|
|
|
hr = StringCchCat(szTemp, ARRAYSIZE(szTemp), TEXT("\\ntuser.*"));
|
|
if (FAILED(hr))
|
|
return lCurrentDateInDays;
|
|
|
|
hFile = FindFirstFile (szTemp, &fd);
|
|
|
|
} else {
|
|
|
|
//
|
|
// szProfilePath points to a file.
|
|
//
|
|
|
|
hFile = FindFirstFile (szProfilePath, &fd);
|
|
}
|
|
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
|
|
FindClose (hFile);
|
|
|
|
FileTimeToLocalFileTime (&fd.ftLastWriteTime, &ft);
|
|
FileTimeToSystemTime (&ft, &systime);
|
|
|
|
days = gdate_dmytoday(systime.wYear, systime.wMonth, systime.wDay);
|
|
|
|
} else {
|
|
days = lCurrentDateInDays;
|
|
}
|
|
|
|
return days;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// CheckProfile()
|
|
//
|
|
// Purpose: Checks if the given profile should be deleted.
|
|
// If so, it is added to the list.
|
|
//
|
|
// Parameters: hKeyLM - Local Machine key
|
|
// hKeyUsers - HKEY_USERS key
|
|
// lpSid - Sid string (key name)
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if not
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL CheckProfile (HKEY hKeyLM, HKEY hKeyUsers, LPTSTR lpSid)
|
|
{
|
|
LONG lResult;
|
|
HKEY hkey = NULL;
|
|
TCHAR szSubKey[MAX_PATH];
|
|
DWORD dwSize, dwType;
|
|
TCHAR szTemp[MAX_PATH];
|
|
TCHAR szProfilePath[MAX_PATH];
|
|
TCHAR szError[200];
|
|
DWORD dwAttribs;
|
|
BOOL bDir;
|
|
LONG lProfileDateInDays;
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// Check if the profile is in use
|
|
//
|
|
|
|
lResult = RegOpenKeyEx (hKeyUsers, lpSid, 0, KEY_READ, &hkey);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
RegCloseKey (hkey);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Open the profile information
|
|
//
|
|
|
|
hr = StringCchPrintf(szSubKey, ARRAYSIZE(szSubKey),
|
|
TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s"),
|
|
lpSid);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
return FALSE;
|
|
}
|
|
|
|
lResult = RegOpenKeyEx (hKeyLM,
|
|
szSubKey,
|
|
0,
|
|
KEY_READ,
|
|
&hkey);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
LoadString (hInst, IDS_FAILEDOPENPROFILE, szError, ARRAYSIZE(szError));
|
|
_tprintf(szError, lpSid);
|
|
PrintLastError(lResult);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the ProfileImagePath
|
|
//
|
|
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
lResult = RegQueryValueEx (hkey,
|
|
TEXT("ProfileImagePath"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)szTemp,
|
|
&dwSize);
|
|
RegCloseKey(hkey);
|
|
hkey = NULL;
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
LoadString (hInst, IDS_FAILEDPATHQUERY, szError, ARRAYSIZE(szError));
|
|
_tprintf(szError, lpSid);
|
|
PrintLastError(lResult);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Expand the path.
|
|
//
|
|
|
|
if (_tcsnicmp(TEXT("%SystemRoot%"), szTemp, 12) == 0) {
|
|
hr = StringCchPrintf(szProfilePath, ARRAYSIZE(szProfilePath), TEXT("%s\\%s"), szSystemRoot, szTemp+13);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if (_tcsnicmp(TEXT("%SystemDrive%"), szTemp, 13) == 0) {
|
|
hr = StringCchPrintf(szProfilePath, ARRAYSIZE(szProfilePath), TEXT("%s\\%s"), szSystemDrive, szTemp+14);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if (NULL == _tcschr(szTemp, TEXT('%')) && !bLocalComputer) {
|
|
if (TEXT(':') == szTemp[1])
|
|
szTemp[1] = TEXT('$');
|
|
hr = StringCchPrintf(szProfilePath, ARRAYSIZE(szProfilePath), TEXT("%s\\%s"), szComputerName, szTemp);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
LoadString (hInst, IDS_SKIPPROFILE, szError, ARRAYSIZE(szError));
|
|
_tprintf(szError, szTemp);
|
|
return TRUE;
|
|
}
|
|
//
|
|
// Is this a directory or a file?
|
|
//
|
|
|
|
dwAttribs = GetFileAttributes (szProfilePath);
|
|
|
|
if (dwAttribs == -1) {
|
|
AddNode (szSubKey, NULL, FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
bDir = (dwAttribs & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE;
|
|
|
|
|
|
//
|
|
// Check Time/Date stamp. If the profile date is older
|
|
// than the amount specified, add it to the delete list.
|
|
//
|
|
|
|
lProfileDateInDays = GetProfileDateInDays(szProfilePath, bDir);
|
|
|
|
if (lCurrentDateInDays >= lProfileDateInDays) {
|
|
|
|
if ((lCurrentDateInDays - lProfileDateInDays) >= lDays) {
|
|
AddNode (szSubKey, szProfilePath, bDir);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// DelProfiles()
|
|
//
|
|
// Purpose: Deletes the user profiles
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL DelProfiles(void)
|
|
{
|
|
HKEY hKeyLM = NULL, hKeyUsers = NULL, hKeyProfiles = NULL;
|
|
HKEY hKeyCurrentVersion = NULL;
|
|
LONG lResult;
|
|
BOOL bResult = FALSE, bTemp;
|
|
TCHAR szError[200];
|
|
DWORD dwIndex = 0, dwNameSize;
|
|
DWORD dwBufferSize;
|
|
TCHAR szName[MAX_PATH];
|
|
TCHAR szTemp[MAX_PATH];
|
|
TCHAR tChar, tTemp;
|
|
FILETIME ft;
|
|
LPDELETEITEM lpTemp;
|
|
LPTSTR pSid, lpEnd;
|
|
DWORD lProfileKeyLen;
|
|
HRESULT hr;
|
|
|
|
|
|
lProfileKeyLen = lstrlen(TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"))+1;
|
|
|
|
//
|
|
// Open the registry
|
|
//
|
|
|
|
lResult = RegConnectRegistry(szComputerName, HKEY_LOCAL_MACHINE, &hKeyLM);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
PrintLastError(lResult);
|
|
goto Exit;
|
|
}
|
|
|
|
lResult = RegConnectRegistry(szComputerName, HKEY_USERS, &hKeyUsers);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
PrintLastError(lResult);
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Get the value of %SystemRoot% and %SystemDrive% relative to the computer
|
|
//
|
|
|
|
lResult = RegOpenKeyEx(hKeyLM,
|
|
TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion"),
|
|
0,
|
|
KEY_READ,
|
|
&hKeyCurrentVersion);
|
|
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
PrintLastError(lResult);
|
|
goto Exit;
|
|
}
|
|
|
|
dwBufferSize = sizeof(szTemp);
|
|
|
|
lResult = RegQueryValueEx(hKeyCurrentVersion,
|
|
TEXT("SystemRoot"),
|
|
NULL,
|
|
NULL,
|
|
(BYTE *) szTemp,
|
|
&dwBufferSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
PrintLastError(lResult);
|
|
goto Exit;
|
|
}
|
|
|
|
if (!bLocalComputer) {
|
|
szTemp[1] = TEXT('$');
|
|
|
|
hr = StringCchCopy(szSystemRoot, ARRAYSIZE(szSystemRoot), szComputerName);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCat(szSystemRoot, ARRAYSIZE(szSystemRoot), TEXT("\\"));
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCat(szSystemRoot, ARRAYSIZE(szSystemRoot), szTemp);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
goto Exit;
|
|
}
|
|
|
|
hr = StringCchCopy(szSystemDrive, ARRAYSIZE(szSystemDrive), szComputerName);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCat(szSystemDrive, ARRAYSIZE(szSystemDrive), TEXT("\\"));
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCatN(szSystemDrive, ARRAYSIZE(szSystemDrive), szTemp, 2);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
goto Exit;
|
|
}
|
|
}
|
|
else {
|
|
szSystemDrive[0] = TEXT('\0');
|
|
hr = StringCchCatN(szSystemDrive, ARRAYSIZE(szSystemDrive), szTemp, 2);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
goto Exit;
|
|
}
|
|
hr = StringCchCopy(szSystemRoot, ARRAYSIZE(szSystemRoot), szTemp);
|
|
if (FAILED(hr)) {
|
|
PrintLastError(HRESULT_CODE(hr));
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open the ProfileList key
|
|
//
|
|
|
|
lResult = RegOpenKeyEx (hKeyLM,
|
|
TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"),
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hKeyProfiles);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
|
|
LoadString (hInst, IDS_FAILEDPROFILELIST, szError, ARRAYSIZE(szError));
|
|
_tprintf(szError);
|
|
PrintLastError(lResult);
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Enumerate the profiles
|
|
//
|
|
|
|
dwNameSize = ARRAYSIZE(szName);
|
|
lResult = RegEnumKeyEx(hKeyProfiles,
|
|
dwIndex,
|
|
szName,
|
|
&dwNameSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ft);
|
|
|
|
|
|
while (lResult == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Hand the profile info off to CheckProfile
|
|
// to determine if the profile should be deleted or not.
|
|
//
|
|
|
|
if (!CheckProfile (hKeyLM, hKeyUsers, szName)) {
|
|
if (!bIgnoreErrors) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Reset for the next loop
|
|
//
|
|
dwIndex++;
|
|
dwNameSize = ARRAYSIZE(szName);
|
|
|
|
lResult = RegEnumKeyEx(hKeyProfiles,
|
|
dwIndex,
|
|
szName,
|
|
&dwNameSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ft);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for errors
|
|
//
|
|
|
|
if (lResult != ERROR_NO_MORE_ITEMS) {
|
|
LoadString (hInst, IDS_FAILEDENUM, szError, ARRAYSIZE(szError));
|
|
_tprintf(szError);
|
|
PrintLastError(lResult);
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Remove profiles
|
|
//
|
|
|
|
lpTemp = lpDeleteList;
|
|
|
|
while (lpTemp) {
|
|
|
|
if (lpTemp->lpProfilePath) {
|
|
|
|
//
|
|
// Prompt before deleting the profile (if approp).
|
|
//
|
|
|
|
if (bPromptBeforeDelete) {
|
|
|
|
while (1) {
|
|
LoadString (hInst, IDS_DELETEPROMPT, szError, ARRAYSIZE(szError));
|
|
_tprintf (szError, lpTemp->lpProfilePath);
|
|
|
|
|
|
tChar = _gettchar();
|
|
|
|
tTemp = tChar;
|
|
while (tTemp != TEXT('\n')) {
|
|
tTemp = _gettchar();
|
|
}
|
|
|
|
if ((tChar == TEXT('N')) || (tChar == TEXT('n'))) {
|
|
goto LoopAgain;
|
|
}
|
|
|
|
if ((tChar == TEXT('A')) || (tChar == TEXT('a'))) {
|
|
bPromptBeforeDelete = FALSE;
|
|
break;
|
|
}
|
|
|
|
if ((tChar == TEXT('Y')) || (tChar == TEXT('y'))) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete the profile
|
|
//
|
|
|
|
LoadString (hInst, IDS_DELETING, szError, ARRAYSIZE(szError));
|
|
_tprintf (szError, lpTemp->lpProfilePath);
|
|
|
|
pSid = lpTemp->lpSubKey+lProfileKeyLen;
|
|
|
|
bTemp = DeleteProfile(pSid, lpTemp->lpProfilePath, ((bLocalComputer)? NULL:szComputerName));
|
|
|
|
if (bTemp) {
|
|
LoadString (hInst, IDS_SUCCESS, szError, ARRAYSIZE(szError));
|
|
_tprintf (szError, lpTemp->lpProfilePath);
|
|
|
|
} else {
|
|
LoadString (hInst, IDS_FAILED, szError, ARRAYSIZE(szError));
|
|
_tprintf (szError, lpTemp->lpProfilePath);
|
|
PrintLastError(GetLastError());
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// If there isn't a profile path, then we are just
|
|
// cleaning up the bogus registry entry.
|
|
//
|
|
|
|
bTemp = TRUE;
|
|
|
|
//
|
|
// Clean up the registry.
|
|
//
|
|
|
|
RegDeleteKey (hKeyLM, lpTemp->lpSubKey);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Did the clean up fail?
|
|
//
|
|
|
|
if (!bTemp) {
|
|
if (!bIgnoreErrors) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
LoopAgain:
|
|
lpTemp = lpTemp->pNext;
|
|
}
|
|
|
|
|
|
//
|
|
// Success
|
|
//
|
|
|
|
bResult = TRUE;
|
|
|
|
Exit:
|
|
|
|
if (hKeyCurrentVersion)
|
|
RegCloseKey(hKeyCurrentVersion);
|
|
|
|
if (hKeyProfiles)
|
|
RegCloseKey(hKeyProfiles);
|
|
|
|
if (hKeyLM)
|
|
RegCloseKey(hKeyLM);
|
|
|
|
if (hKeyUsers)
|
|
RegCloseKey(hKeyUsers);
|
|
|
|
|
|
if (lpDeleteList) {
|
|
do {
|
|
lpTemp = lpDeleteList->pNext;
|
|
LocalFree (lpDeleteList);
|
|
lpDeleteList = lpTemp;
|
|
} while (lpDeleteList);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// main()
|
|
//
|
|
// Purpose: main entry point
|
|
//
|
|
// Parameters: argc - number of arguments
|
|
// argv - arguments
|
|
//
|
|
// Return: 0 if successful
|
|
// 1 if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 5/18/96 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
int __cdecl main( int argc, char *argv[])
|
|
{
|
|
DWORD dwErr;
|
|
|
|
//
|
|
// Initialize the globals
|
|
//
|
|
|
|
InitializeGlobals();
|
|
|
|
|
|
//
|
|
// Parse the command line
|
|
//
|
|
|
|
if (!ParseCommandLine(GetCommandLine())) {
|
|
return 1;
|
|
}
|
|
|
|
|
|
//
|
|
// Check the globals variables
|
|
//
|
|
|
|
dwErr = CheckGlobals();
|
|
if (ERROR_SUCCESS != dwErr) {
|
|
PrintLastError(dwErr);
|
|
return 1;
|
|
}
|
|
|
|
|
|
//
|
|
// Confirmation
|
|
//
|
|
|
|
if (!bQuiet) {
|
|
if (!Confirm()) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Remove the profiles
|
|
//
|
|
|
|
if (!DelProfiles()) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|