I am attempting to delete user profile folders in the Users
folder after I remove the user from the domain. The problem is some times the folder may be in use by the system.
The problem is using MOVEFILE_DELAY_UNTIL_REBOOT
with MoveFileEx
will only delete folders that are empty.
If dwFlags specifies MOVEFILE_DELAY_UNTIL_REBOOT and lpNewFileName is NULL, MoveFileEx registers the lpExistingFileName file to be deleted when the system restarts. If lpExistingFileName refers to a directory, the system removes the directory at restart only if the directory is empty.
What is the correct way to delete a non-empty folder that has a file inside it that is in use?
Here is a simple test program based on Michel's answer, it works as expected.
internal static class Program
{
private static void Main(string[] args)
{
foreach (var file in Directory.EnumerateFiles(args[0], "*", SearchOption.AllDirectories))
{
Console.WriteLine(file);
}
foreach (var directory in Directory.EnumerateDirectories(args[0], "*", SearchOption.AllDirectories))
{
Console.WriteLine(directory);
DeleteFileOnReboot(directory);
}
DeleteFileOnReboot(args[0]);
}
private static void DeleteFileOnReboot(string file)
{
bool result = MoveFileEx(file, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT);
try
{
if (!result)
throw new Win32Exception();
}
catch (Win32Exception ex)
{
Console.WriteLine(ex);
}
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags);
}
[Flags]
enum MoveFileFlags
{
MOVEFILE_REPLACE_EXISTING = 0x00000001,
MOVEFILE_COPY_ALLOWED = 0x00000002,
MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004,
MOVEFILE_WRITE_THROUGH = 0x00000008,
MOVEFILE_CREATE_HARDLINK = 0x00000010,
MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020
}
I do this over two loops with Directory.EnumerateFiles
and Directory.EnumerateDirectories
because Directory.EnumerateFileSystemEntries
will list the folders before the files in the folders so the delete would fail.
In most of the implementations I've seen, every file in the directory is "deleted" with
MoveFileEx
withMOVEFILE_DELAY_UNTIL_REBOOT
, and then the directory is "deleted" the same way. The order of operations is preserved upon reboot -- the files are deleted first, then the directory.