gistfile1.txt
· 10 KiB · Text
Raw
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Win32;
namespace DiskUsageLog
{
class Program
{
const long ONE_GB = 1024L * 1024 * 1024;
static readonly string[] HardExcludedFolders =
{
"WinSxS",
"Microsoft.NET",
"assembly"
};
static readonly string InstallerPath = @"C:\Windows\Installer";
static Dictionary<string, ExtensionStat> ExtensionStats =
new Dictionary<string, ExtensionStat>(StringComparer.OrdinalIgnoreCase);
static List<FileInfo> LargestFiles = new List<FileInfo>();
static List<LargeFolder> LargeFolders = new List<LargeFolder>();
static void Main(string[] args)
{
string rootPath = args.Length > 0 ? args[0] : @"C:\";
if (!Directory.Exists(rootPath))
{
Console.WriteLine("Chemin invalide.");
return;
}
Console.WriteLine("DiskUsageLog - Analyse disque");
Console.WriteLine("Racine analysée : " + rootPath);
Console.WriteLine("--------------------------------------------------\n");
foreach (string dir in Directory.GetDirectories(rootPath))
{
AnalyzeDirectory(dir);
}
DisplayLargeFolders();
DisplayTopExtensions();
DisplayLargestFiles();
DisplayOrphanInstallers();
Console.WriteLine("\nAnalyse terminée.");
Console.ReadLine();
}
// ======================= ANALYSE =======================
static long AnalyzeDirectory(string path)
{
long totalSize = 0;
try
{
foreach (string file in Directory.GetFiles(path))
{
FileInfo fi = new FileInfo(file);
totalSize += fi.Length;
if (!IsSystemCritical(path))
TrackExtension(fi);
TrackLargestFiles(fi);
}
foreach (string dir in Directory.GetDirectories(path))
{
if (IsHardExcluded(dir)) continue;
totalSize += AnalyzeDirectory(dir);
}
}
catch
{
// Accès refusé / erreur disque
}
if (totalSize >= ONE_GB)
{
LargeFolders.Add(new LargeFolder
{
Path = path,
Size = totalSize,
IsRiskArea = IsRiskArea(path)
});
}
return totalSize;
}
// ======================= REGLES =======================
static bool IsHardExcluded(string path)
{
string name = Path.GetFileName(path);
return HardExcludedFolders.Any(e =>
e.Equals(name, StringComparison.OrdinalIgnoreCase));
}
static bool IsSystemCritical(string path)
{
return path.StartsWith(@"C:\Windows\System32",
StringComparison.OrdinalIgnoreCase);
}
static bool IsRiskArea(string path)
{
return path.StartsWith(@"C:\Windows\Installer", StringComparison.OrdinalIgnoreCase)
|| path.StartsWith(@"C:\Windows\Temp", StringComparison.OrdinalIgnoreCase)
|| path.StartsWith(@"C:\Windows\SoftwareDistribution", StringComparison.OrdinalIgnoreCase)
|| path.Contains(@"\AppData\Local\Temp");
}
// ======================= EXTENSIONS =======================
static void TrackExtension(FileInfo fi)
{
string ext = string.IsNullOrEmpty(fi.Extension)
? "[sans_ext]"
: fi.Extension.ToLower();
if (!ExtensionStats.ContainsKey(ext))
ExtensionStats[ext] = new ExtensionStat();
ExtensionStats[ext].Count++;
ExtensionStats[ext].Size += fi.Length;
}
static void DisplayTopExtensions()
{
Console.WriteLine("\n=== TOP 20 EXTENSIONS (hors système critique) ===\n");
Console.WriteLine("{0,-12} {1,10} {2,15}",
"Extension", "Fichiers", "Taille (GB)");
foreach (var ext in ExtensionStats
.OrderByDescending(e => e.Value.Size)
.Take(20))
{
Console.WriteLine("{0,-12} {1,10} {2,15}",
ext.Key,
ext.Value.Count,
ToGB(ext.Value.Size));
}
}
// ======================= GROS FICHIERS =======================
static void TrackLargestFiles(FileInfo fi)
{
LargestFiles.Add(fi);
LargestFiles = LargestFiles
.OrderByDescending(f => f.Length)
.Take(10)
.ToList();
}
static void DisplayLargestFiles()
{
Console.WriteLine("\n=== TOP 10 PLUS GROS FICHIERS ===\n");
foreach (FileInfo fi in LargestFiles)
{
Console.WriteLine("{0} : {1} GB",
fi.FullName,
ToGB(fi.Length));
}
}
// ======================= DOSSIERS =======================
static void DisplayLargeFolders()
{
Console.WriteLine("\n=== DOSSIERS > 1 Go ===\n");
foreach (LargeFolder f in LargeFolders
.OrderByDescending(f => f.Size))
{
string flag = f.IsRiskArea ? " !!!" : "";
Console.WriteLine("{0} : {1} GB{2}",
f.Path,
ToGB(f.Size),
flag);
}
Console.WriteLine("\n!!! = zone connue à dérive disque");
}
// ======================= MSI ORPHELINS =======================
static void DisplayOrphanInstallers()
{
Console.WriteLine("\n=== MSI / MSP ORPHELINS POTENTIELS ===\n");
if (!Directory.Exists(InstallerPath))
{
Console.WriteLine("Répertoire Windows Installer introuvable.");
return;
}
var allInstallers = GetInstallerFiles();
var referencedInstallers = GetReferencedInstallerFiles();
var orphans = allInstallers.Values
.Where(f => !referencedInstallers.Contains(f.FullName))
.OrderByDescending(f => f.Length)
.ToList();
long total = 0;
foreach (var fi in orphans)
{
Console.WriteLine("{0,-20} {1,10} GB",
fi.Name,
ToGB(fi.Length));
total += fi.Length;
}
Console.WriteLine("\nTotal récupérable potentiel : {0} GB",
ToGB(total));
Console.WriteLine(
"\nATTENTION : aucune suppression automatique.\nAnalyse uniquement.");
}
static Dictionary<string, FileInfo> GetInstallerFiles()
{
var dict = new Dictionary<string, FileInfo>(
StringComparer.OrdinalIgnoreCase);
try
{
foreach (string file in Directory.GetFiles(InstallerPath))
{
if (file.EndsWith(".msi", StringComparison.OrdinalIgnoreCase) ||
file.EndsWith(".msp", StringComparison.OrdinalIgnoreCase))
{
FileInfo fi = new FileInfo(file);
dict[fi.FullName] = fi;
}
}
}
catch
{
// Accès refusé
}
return dict;
}
static HashSet<string> GetReferencedInstallerFiles()
{
var result = new HashSet<string>(
StringComparer.OrdinalIgnoreCase);
ReadInstallerRegistry(
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData",
result);
ReadInstallerRegistry(
@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Installer\UserData",
result);
return result;
}
static void ReadInstallerRegistry(string baseKey, HashSet<string> result)
{
try
{
using (RegistryKey root =
Registry.LocalMachine.OpenSubKey(baseKey))
{
if (root == null) return;
foreach (string sid in root.GetSubKeyNames())
{
using (RegistryKey products =
root.OpenSubKey(sid + @"\Products"))
{
if (products == null) continue;
foreach (string prod in products.GetSubKeyNames())
{
using (RegistryKey installProps =
products.OpenSubKey(prod + @"\InstallProperties"))
{
if (installProps == null) continue;
string localPackage =
installProps.GetValue("LocalPackage") as string;
if (!string.IsNullOrEmpty(localPackage))
result.Add(localPackage);
}
}
}
}
}
}
catch
{
// erreur registre
}
}
// ======================= UTILS =======================
static double ToGB(long bytes)
{
return Math.Round(bytes / 1024d / 1024 / 1024, 2);
}
}
// ======================= MODELES =======================
class ExtensionStat
{
public int Count;
public long Size;
}
class LargeFolder
{
public string Path;
public long Size;
public bool IsRiskArea;
}
}
| 1 | using System; |
| 2 | using System.Collections.Generic; |
| 3 | using System.IO; |
| 4 | using System.Linq; |
| 5 | using Microsoft.Win32; |
| 6 | |
| 7 | namespace DiskUsageLog |
| 8 | { |
| 9 | class Program |
| 10 | { |
| 11 | const long ONE_GB = 1024L * 1024 * 1024; |
| 12 | |
| 13 | static readonly string[] HardExcludedFolders = |
| 14 | { |
| 15 | "WinSxS", |
| 16 | "Microsoft.NET", |
| 17 | "assembly" |
| 18 | }; |
| 19 | |
| 20 | static readonly string InstallerPath = @"C:\Windows\Installer"; |
| 21 | |
| 22 | static Dictionary<string, ExtensionStat> ExtensionStats = |
| 23 | new Dictionary<string, ExtensionStat>(StringComparer.OrdinalIgnoreCase); |
| 24 | |
| 25 | static List<FileInfo> LargestFiles = new List<FileInfo>(); |
| 26 | static List<LargeFolder> LargeFolders = new List<LargeFolder>(); |
| 27 | |
| 28 | static void Main(string[] args) |
| 29 | { |
| 30 | string rootPath = args.Length > 0 ? args[0] : @"C:\"; |
| 31 | |
| 32 | if (!Directory.Exists(rootPath)) |
| 33 | { |
| 34 | Console.WriteLine("Chemin invalide."); |
| 35 | return; |
| 36 | } |
| 37 | |
| 38 | Console.WriteLine("DiskUsageLog - Analyse disque"); |
| 39 | Console.WriteLine("Racine analysée : " + rootPath); |
| 40 | Console.WriteLine("--------------------------------------------------\n"); |
| 41 | |
| 42 | foreach (string dir in Directory.GetDirectories(rootPath)) |
| 43 | { |
| 44 | AnalyzeDirectory(dir); |
| 45 | } |
| 46 | |
| 47 | DisplayLargeFolders(); |
| 48 | DisplayTopExtensions(); |
| 49 | DisplayLargestFiles(); |
| 50 | DisplayOrphanInstallers(); |
| 51 | |
| 52 | Console.WriteLine("\nAnalyse terminée."); |
| 53 | Console.ReadLine(); |
| 54 | } |
| 55 | |
| 56 | // ======================= ANALYSE ======================= |
| 57 | |
| 58 | static long AnalyzeDirectory(string path) |
| 59 | { |
| 60 | long totalSize = 0; |
| 61 | |
| 62 | try |
| 63 | { |
| 64 | foreach (string file in Directory.GetFiles(path)) |
| 65 | { |
| 66 | FileInfo fi = new FileInfo(file); |
| 67 | totalSize += fi.Length; |
| 68 | |
| 69 | if (!IsSystemCritical(path)) |
| 70 | TrackExtension(fi); |
| 71 | |
| 72 | TrackLargestFiles(fi); |
| 73 | } |
| 74 | |
| 75 | foreach (string dir in Directory.GetDirectories(path)) |
| 76 | { |
| 77 | if (IsHardExcluded(dir)) continue; |
| 78 | totalSize += AnalyzeDirectory(dir); |
| 79 | } |
| 80 | } |
| 81 | catch |
| 82 | { |
| 83 | // Accès refusé / erreur disque |
| 84 | } |
| 85 | |
| 86 | if (totalSize >= ONE_GB) |
| 87 | { |
| 88 | LargeFolders.Add(new LargeFolder |
| 89 | { |
| 90 | Path = path, |
| 91 | Size = totalSize, |
| 92 | IsRiskArea = IsRiskArea(path) |
| 93 | }); |
| 94 | } |
| 95 | |
| 96 | return totalSize; |
| 97 | } |
| 98 | |
| 99 | // ======================= REGLES ======================= |
| 100 | |
| 101 | static bool IsHardExcluded(string path) |
| 102 | { |
| 103 | string name = Path.GetFileName(path); |
| 104 | return HardExcludedFolders.Any(e => |
| 105 | e.Equals(name, StringComparison.OrdinalIgnoreCase)); |
| 106 | } |
| 107 | |
| 108 | static bool IsSystemCritical(string path) |
| 109 | { |
| 110 | return path.StartsWith(@"C:\Windows\System32", |
| 111 | StringComparison.OrdinalIgnoreCase); |
| 112 | } |
| 113 | |
| 114 | static bool IsRiskArea(string path) |
| 115 | { |
| 116 | return path.StartsWith(@"C:\Windows\Installer", StringComparison.OrdinalIgnoreCase) |
| 117 | || path.StartsWith(@"C:\Windows\Temp", StringComparison.OrdinalIgnoreCase) |
| 118 | || path.StartsWith(@"C:\Windows\SoftwareDistribution", StringComparison.OrdinalIgnoreCase) |
| 119 | || path.Contains(@"\AppData\Local\Temp"); |
| 120 | } |
| 121 | |
| 122 | // ======================= EXTENSIONS ======================= |
| 123 | |
| 124 | static void TrackExtension(FileInfo fi) |
| 125 | { |
| 126 | string ext = string.IsNullOrEmpty(fi.Extension) |
| 127 | ? "[sans_ext]" |
| 128 | : fi.Extension.ToLower(); |
| 129 | |
| 130 | if (!ExtensionStats.ContainsKey(ext)) |
| 131 | ExtensionStats[ext] = new ExtensionStat(); |
| 132 | |
| 133 | ExtensionStats[ext].Count++; |
| 134 | ExtensionStats[ext].Size += fi.Length; |
| 135 | } |
| 136 | |
| 137 | static void DisplayTopExtensions() |
| 138 | { |
| 139 | Console.WriteLine("\n=== TOP 20 EXTENSIONS (hors système critique) ===\n"); |
| 140 | Console.WriteLine("{0,-12} {1,10} {2,15}", |
| 141 | "Extension", "Fichiers", "Taille (GB)"); |
| 142 | |
| 143 | foreach (var ext in ExtensionStats |
| 144 | .OrderByDescending(e => e.Value.Size) |
| 145 | .Take(20)) |
| 146 | { |
| 147 | Console.WriteLine("{0,-12} {1,10} {2,15}", |
| 148 | ext.Key, |
| 149 | ext.Value.Count, |
| 150 | ToGB(ext.Value.Size)); |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | // ======================= GROS FICHIERS ======================= |
| 155 | |
| 156 | static void TrackLargestFiles(FileInfo fi) |
| 157 | { |
| 158 | LargestFiles.Add(fi); |
| 159 | LargestFiles = LargestFiles |
| 160 | .OrderByDescending(f => f.Length) |
| 161 | .Take(10) |
| 162 | .ToList(); |
| 163 | } |
| 164 | |
| 165 | static void DisplayLargestFiles() |
| 166 | { |
| 167 | Console.WriteLine("\n=== TOP 10 PLUS GROS FICHIERS ===\n"); |
| 168 | |
| 169 | foreach (FileInfo fi in LargestFiles) |
| 170 | { |
| 171 | Console.WriteLine("{0} : {1} GB", |
| 172 | fi.FullName, |
| 173 | ToGB(fi.Length)); |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | // ======================= DOSSIERS ======================= |
| 178 | |
| 179 | static void DisplayLargeFolders() |
| 180 | { |
| 181 | Console.WriteLine("\n=== DOSSIERS > 1 Go ===\n"); |
| 182 | |
| 183 | foreach (LargeFolder f in LargeFolders |
| 184 | .OrderByDescending(f => f.Size)) |
| 185 | { |
| 186 | string flag = f.IsRiskArea ? " !!!" : ""; |
| 187 | Console.WriteLine("{0} : {1} GB{2}", |
| 188 | f.Path, |
| 189 | ToGB(f.Size), |
| 190 | flag); |
| 191 | } |
| 192 | |
| 193 | Console.WriteLine("\n!!! = zone connue à dérive disque"); |
| 194 | } |
| 195 | |
| 196 | // ======================= MSI ORPHELINS ======================= |
| 197 | |
| 198 | static void DisplayOrphanInstallers() |
| 199 | { |
| 200 | Console.WriteLine("\n=== MSI / MSP ORPHELINS POTENTIELS ===\n"); |
| 201 | |
| 202 | if (!Directory.Exists(InstallerPath)) |
| 203 | { |
| 204 | Console.WriteLine("Répertoire Windows Installer introuvable."); |
| 205 | return; |
| 206 | } |
| 207 | |
| 208 | var allInstallers = GetInstallerFiles(); |
| 209 | var referencedInstallers = GetReferencedInstallerFiles(); |
| 210 | |
| 211 | var orphans = allInstallers.Values |
| 212 | .Where(f => !referencedInstallers.Contains(f.FullName)) |
| 213 | .OrderByDescending(f => f.Length) |
| 214 | .ToList(); |
| 215 | |
| 216 | long total = 0; |
| 217 | |
| 218 | foreach (var fi in orphans) |
| 219 | { |
| 220 | Console.WriteLine("{0,-20} {1,10} GB", |
| 221 | fi.Name, |
| 222 | ToGB(fi.Length)); |
| 223 | |
| 224 | total += fi.Length; |
| 225 | } |
| 226 | |
| 227 | Console.WriteLine("\nTotal récupérable potentiel : {0} GB", |
| 228 | ToGB(total)); |
| 229 | |
| 230 | Console.WriteLine( |
| 231 | "\nATTENTION : aucune suppression automatique.\nAnalyse uniquement."); |
| 232 | } |
| 233 | |
| 234 | static Dictionary<string, FileInfo> GetInstallerFiles() |
| 235 | { |
| 236 | var dict = new Dictionary<string, FileInfo>( |
| 237 | StringComparer.OrdinalIgnoreCase); |
| 238 | |
| 239 | try |
| 240 | { |
| 241 | foreach (string file in Directory.GetFiles(InstallerPath)) |
| 242 | { |
| 243 | if (file.EndsWith(".msi", StringComparison.OrdinalIgnoreCase) || |
| 244 | file.EndsWith(".msp", StringComparison.OrdinalIgnoreCase)) |
| 245 | { |
| 246 | FileInfo fi = new FileInfo(file); |
| 247 | dict[fi.FullName] = fi; |
| 248 | } |
| 249 | } |
| 250 | } |
| 251 | catch |
| 252 | { |
| 253 | // Accès refusé |
| 254 | } |
| 255 | |
| 256 | return dict; |
| 257 | } |
| 258 | |
| 259 | static HashSet<string> GetReferencedInstallerFiles() |
| 260 | { |
| 261 | var result = new HashSet<string>( |
| 262 | StringComparer.OrdinalIgnoreCase); |
| 263 | |
| 264 | ReadInstallerRegistry( |
| 265 | @"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData", |
| 266 | result); |
| 267 | |
| 268 | ReadInstallerRegistry( |
| 269 | @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Installer\UserData", |
| 270 | result); |
| 271 | |
| 272 | return result; |
| 273 | } |
| 274 | |
| 275 | static void ReadInstallerRegistry(string baseKey, HashSet<string> result) |
| 276 | { |
| 277 | try |
| 278 | { |
| 279 | using (RegistryKey root = |
| 280 | Registry.LocalMachine.OpenSubKey(baseKey)) |
| 281 | { |
| 282 | if (root == null) return; |
| 283 | |
| 284 | foreach (string sid in root.GetSubKeyNames()) |
| 285 | { |
| 286 | using (RegistryKey products = |
| 287 | root.OpenSubKey(sid + @"\Products")) |
| 288 | { |
| 289 | if (products == null) continue; |
| 290 | |
| 291 | foreach (string prod in products.GetSubKeyNames()) |
| 292 | { |
| 293 | using (RegistryKey installProps = |
| 294 | products.OpenSubKey(prod + @"\InstallProperties")) |
| 295 | { |
| 296 | if (installProps == null) continue; |
| 297 | |
| 298 | string localPackage = |
| 299 | installProps.GetValue("LocalPackage") as string; |
| 300 | |
| 301 | if (!string.IsNullOrEmpty(localPackage)) |
| 302 | result.Add(localPackage); |
| 303 | } |
| 304 | } |
| 305 | } |
| 306 | } |
| 307 | } |
| 308 | } |
| 309 | catch |
| 310 | { |
| 311 | // erreur registre |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | // ======================= UTILS ======================= |
| 316 | |
| 317 | static double ToGB(long bytes) |
| 318 | { |
| 319 | return Math.Round(bytes / 1024d / 1024 / 1024, 2); |
| 320 | } |
| 321 | } |
| 322 | |
| 323 | // ======================= MODELES ======================= |
| 324 | |
| 325 | class ExtensionStat |
| 326 | { |
| 327 | public int Count; |
| 328 | public long Size; |
| 329 | } |
| 330 | |
| 331 | class LargeFolder |
| 332 | { |
| 333 | public string Path; |
| 334 | public long Size; |
| 335 | public bool IsRiskArea; |
| 336 | } |
| 337 | } |