using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; namespace RobvanderWoude { class DelTrash { static string progver = "1.03"; static int Main( string[] args ) { #region Initialize Variables int rc = 0; long totalsize = 0; int deleteditems = 0; int accessdenieddirs = 0; bool accessdenied = false; bool confirm = false; bool listonly = false; bool progress = false; bool quiet = false; bool verbose = false; RecycleFlags flags = RecycleFlags.RecycleNoSound; string drive = null; // default: All drives string windrive = Path.GetPathRoot( Environment.SystemDirectory ); #endregion Initialize Variables #region Parse Command Line if ( args.Length > 3 ) { return ShowHelp( ); } foreach ( string arg in args ) { switch ( arg.ToUpper( ) ) { case "/?": return ShowHelp( ); case "/C": if ( confirm ) { return ShowHelp( "Duplicate command line switch /C" ); } confirm = true; break; case "/L": if ( listonly ) { return ShowHelp( "Duplicate command line switch /L" ); } listonly = true; break; case "/P": if ( progress ) { return ShowHelp( "Duplicate command line switch /P" ); } progress = true; break; case "/Q": if ( quiet ) { return ShowHelp( "Duplicate command line switch /Q" ); } if ( verbose ) { return ShowHelp( "Switches /V and /Q are mutually exclusive" ); } verbose = true; break; case "/V": if ( verbose ) { return ShowHelp( "Duplicate command line switch /V" ); } if ( quiet ) { return ShowHelp( "Switches /V and /Q are mutually exclusive" ); } verbose = true; break; case "/W": if ( drive != null ) { if ( drive == windrive ) { return ShowHelp( "Either specify a drive letter or use the /W switch, not both" ); } else { return ShowHelp( "Duplicate drive specification {0} and {1}", drive, arg.ToUpper( ) ); } } drive = windrive; break; default: bool validdrive = false; DriveInfo[] alldrives = DriveInfo.GetDrives( ); foreach ( DriveInfo drvinf in alldrives ) { if ( drvinf.Name == arg.ToUpper( ) + "\\" ) { validdrive = true; drive = arg.ToUpper( ); } } if ( !validdrive ) { return ShowHelp( "Invalid command line argument \"{0}\"", arg ); } break; } } verbose = verbose || listonly; if ( !confirm ) { flags |= RecycleFlags.RecycleNoConfirmation; } if ( !progress ) { flags |= RecycleFlags.RecycleNoProgressUI; } #endregion Parse Command Line #region Verbose Output if ( verbose ) { foreach ( DriveInfo diskdrive in DriveInfo.GetDrives( ) ) { if ( diskdrive.DriveType == DriveType.Fixed ) // local harddisks only { string recyclebin = Path.Combine( diskdrive.Name, "$RECYCLE.BIN" ); if ( Directory.Exists( recyclebin ) ) { long size = 0; int items = 0; string[] files = new string[0]; string[] folders = Directory.GetDirectories( recyclebin ); foreach ( string folder in folders ) { try { // assuming any access denied will occur on the first directory level files = Directory.GetFiles( folder, "*.*", SearchOption.AllDirectories ); foreach ( string file in files ) { size += new FileInfo( file ).Length; items++; } } catch ( UnauthorizedAccessException ) { accessdenied = true; accessdenieddirs++; } } if ( items == 1 ) { Console.WriteLine( "Marking 1 file ({1}) from drive {2} for deletion", items, FormatBytes( size ), diskdrive.Name.Remove( 2 ) ); totalsize += size; deleteditems += items; } else if ( items > 1 ) { Console.WriteLine( "Marking {0} files ({1}) from drive {2} for deletion", items, FormatBytes( size ), diskdrive.Name.Remove( 2 ) ); totalsize += size; deleteditems += items; } } } } } #endregion Verbose Output #region Actual Deletion if ( listonly ) { Console.WriteLine( "\n{0} items with a total size of {1} would have been deleted.", deleteditems, FormatBytes( totalsize ) ); } else { uint result = SHEmptyRecycleBin( IntPtr.Zero, drive, flags ); if ( result == 0 ) { if ( !quiet ) { Console.WriteLine( "\n{0} items with a total size of {1} have been permanently deleted.", deleteditems, FormatBytes( totalsize ) ); if ( accessdenied ) { if ( accessdenieddirs == 1 ) { Console.WriteLine( "Not all items could be removed permanently because access was denied to 1 directory." ); } else { Console.WriteLine( "Not all items could be removed permanently because access was denied to {0} directories.", accessdenieddirs ); } } } rc = 0; } else { if ( !quiet ) { Console.WriteLine( "\nNot all items could be removed permanently." ); } rc = 1; } } #endregion Actual Deletion return rc; } static string FormatBytes( long bytes ) { int KB = 1024; int MB = 1024 * KB; int GB = 1024 * MB; if ( bytes < KB ) { return bytes.ToString( ) + " B"; } else if ( bytes < MB ) { return ( bytes / KB ).ToString( ) + " KB"; } else if ( bytes < GB ) { return ( bytes / MB ).ToString( ) + " MB"; } else { return ( bytes / GB ).ToString( ) + " GB"; } } static int ShowHelp( params string[] errmsg ) { #region Error Message if ( errmsg.Length > 0 ) { List errargs = new List( errmsg ); errargs.RemoveAt( 0 ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR:\t" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) ); Console.ResetColor( ); } #endregion Error Message #region Help Text /* DelTrash.exe, Version 1.03 Empty the Recycle Bin Usage: DelTrash.exe [ drive: | /W ] [ /C ] [ /P ] [ /L | /Q | /V ] Where: drive: empty recycle bin on this drive only (default: all drives) /W empty recycle bin on Windows' drive only (default: all drives) /C prompt for Confirmation /L List only, do not delete /P show Progress bar /Q Quiet mode, no screen output /V Verbose mode, show number of files and total size per disk drive Notes: Switches /L and /Q and /V are mutually exclusive. Return code is 0 if the Recycle Bin was emptied successfully, or 1 if there was nothing to delete or in case of (command line) errors. Credits: Based on code by Vinoth Kumar www.codeproject.com/Articles/20172/Empty-the-Recycle-Bin-using-C Number of items and size calculation based on Written by Rob van der Woude https://www.robvanderwoude.com */ #endregion Help Text #region Display Help Text Console.Error.WriteLine( ); Console.Error.WriteLine( "DelTrash.exe, Version {0}", progver ); Console.Error.WriteLine( "Empty the Recycle Bin" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "DelTrash.exe [ drive: | /W ] [ /C ] [ /P ] [ /L | /Q | /V ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "drive:" ); Console.ResetColor( ); Console.Error.WriteLine( " empty recycle bin on this drive only (default: all drives)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /W" ); Console.ResetColor( ); Console.Error.Write( " empty recycle bin on " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "W" ); Console.ResetColor( ); Console.Error.WriteLine( "indows' drive only (default: all drives)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /C" ); Console.ResetColor( ); Console.Error.Write( " prompt for " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "C" ); Console.ResetColor( ); Console.Error.WriteLine( "onfirmation" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /L L" ); Console.ResetColor( ); Console.Error.WriteLine( "ist only, do not delete" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /P" ); Console.ResetColor( ); Console.Error.Write( " show " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "P" ); Console.ResetColor( ); Console.Error.WriteLine( "rogress bar" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /Q Q" ); Console.ResetColor( ); Console.Error.WriteLine( "uiet mode, no screen output" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /V V" ); Console.ResetColor( ); Console.Error.WriteLine( "erbose mode, show number of files and total size per disk drive" ); Console.Error.WriteLine( ); Console.Error.Write( "Notes: Switches " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/L" ); Console.ResetColor( ); Console.Error.Write( " and " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/Q" ); Console.ResetColor( ); Console.Error.Write( " and " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/V" ); Console.ResetColor( ); Console.Error.WriteLine( " are mutually exclusive." ); Console.Error.WriteLine( " Return code is 0 if the Recycle Bin was emptied successfully, or 1" ); Console.Error.WriteLine( " if there was nothing to delete or in case of (command line) errors." ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Credits: Based on code by Vinoth Kumar" ); Console.ForegroundColor = ConsoleColor.DarkGray; Console.Error.WriteLine( " www.codeproject.com/Articles/20172/Empty-the-Recycle-Bin-using-C" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "https://www.robvanderwoude.com" ); #endregion Display Help Text return 1; } public enum RecycleFlags : uint { RecycleNoConfirmation = 0x00000001, RecycleNoProgressUI = 0x00000002, RecycleNoSound = 0x00000004 } [DllImport( "Shell32.dll", CharSet = CharSet.Unicode )] static extern uint SHEmptyRecycleBin( IntPtr hwnd, string pszRootPath, RecycleFlags dwFlags ); } }