Última actividad 1777326157

fred revisó este gist 1777326157. Ir a la revisión

1 file changed, 412 insertions, 6 deletions

gistfile1.txt

@@ -1,7 +1,9 @@
1 1 using System;
2 2 using System.Collections.Generic;
3 + using System.Diagnostics;
3 4 using System.IO;
4 5 using System.Linq;
6 + using System.Text;
5 7 using Microsoft.Win32;
6 8
7 9 namespace DiskUsageLog
@@ -9,6 +11,7 @@ namespace DiskUsageLog
9 11 class Program
10 12 {
11 13 const long ONE_GB = 1024L * 1024 * 1024;
14 + const long ONE_MB = 1024L * 1024;
12 15
13 16 static readonly string[] HardExcludedFolders =
14 17 {
@@ -19,14 +22,36 @@ namespace DiskUsageLog
19 22
20 23 static readonly string InstallerPath = @"C:\Windows\Installer";
21 24
25 + static readonly string[] KnownCacheFolderNames =
26 + {
27 + "Temp", "tmp", "Logs", "LogFiles",
28 + "INetCache", "Temporary Internet Files",
29 + "WER", "CrashDumps"
30 + };
31 +
22 32 static Dictionary<string, ExtensionStat> ExtensionStats =
23 33 new Dictionary<string, ExtensionStat>(StringComparer.OrdinalIgnoreCase);
24 34
25 35 static List<FileInfo> LargestFiles = new List<FileInfo>();
26 36 static List<LargeFolder> LargeFolders = new List<LargeFolder>();
37 + static List<FileInfo> StaleFiles = new List<FileInfo>();
38 + static List<LargeFolder> RootBreakdown = new List<LargeFolder>();
39 + static List<CacheFolder> DetectedCacheFolders = new List<CacheFolder>();
40 + static List<LargeFolder> SystemDiagResults = new List<LargeFolder>();
41 +
42 + static long TotalFilesScanned;
43 + static long TotalFoldersScanned;
44 + static long TotalErrorCount;
45 + static long TotalSizeScanned;
46 +
47 + static Stopwatch Timer = new Stopwatch();
48 + static int spinnerIndex;
49 + static readonly char[] SpinnerChars = { '|', '/', '-', '\\' };
27 50
28 51 static void Main(string[] args)
29 52 {
53 + Console.OutputEncoding = System.Text.Encoding.UTF8;
54 +
30 55 string rootPath = args.Length > 0 ? args[0] : @"C:\";
31 56
32 57 if (!Directory.Exists(rootPath))
@@ -37,20 +62,41 @@ namespace DiskUsageLog
37 62
38 63 Console.WriteLine("DiskUsageLog - Analyse disque");
39 64 Console.WriteLine("Racine analysée : " + rootPath);
65 + DisplayXstoreInfo();
40 66 Console.WriteLine("--------------------------------------------------\n");
41 67
42 - foreach (string dir in Directory.GetDirectories(rootPath))
68 + Timer.Start();
69 +
70 + string[] rootDirs;
71 + try { rootDirs = Directory.GetDirectories(rootPath); }
72 + catch { rootDirs = new string[0]; }
73 +
74 + foreach (string dir in rootDirs)
43 75 {
44 - AnalyzeDirectory(dir);
76 + long size = AnalyzeDirectory(dir);
77 + RootBreakdown.Add(new LargeFolder
78 + {
79 + Path = dir,
80 + Size = size
81 + });
45 82 }
46 83
84 + ClearProgress();
85 + Timer.Stop();
86 +
87 + DisplaySummary();
88 + DisplayRootBreakdown();
47 89 DisplayLargeFolders();
48 90 DisplayTopExtensions();
49 91 DisplayLargestFiles();
92 + DisplayStaleFiles();
93 + DisplayCacheFolders();
94 + DisplaySystemDiagnostic();
50 95 DisplayOrphanInstallers();
51 96
97 + ExportReport(rootPath);
98 +
52 99 Console.WriteLine("\nAnalyse terminée.");
53 - Console.ReadLine();
54 100 }
55 101
56 102 // ======================= ANALYSE =======================
@@ -58,6 +104,11 @@ namespace DiskUsageLog
58 104 static long AnalyzeDirectory(string path)
59 105 {
60 106 long totalSize = 0;
107 + TotalFoldersScanned++;
108 +
109 + string folderName = Path.GetFileName(path);
110 + bool isKnownCache = KnownCacheFolderNames.Any(c =>
111 + c.Equals(folderName, StringComparison.OrdinalIgnoreCase));
61 112
62 113 try
63 114 {
@@ -65,13 +116,24 @@ namespace DiskUsageLog
65 116 {
66 117 FileInfo fi = new FileInfo(file);
67 118 totalSize += fi.Length;
119 + TotalFilesScanned++;
120 + TotalSizeScanned += fi.Length;
68 121
69 - if (!IsSystemCritical(path))
122 + bool excluded = IsExcludedFile(fi, path);
123 +
124 + if (!IsSystemCritical(path) && !excluded)
70 125 TrackExtension(fi);
71 126
72 - TrackLargestFiles(fi);
127 + if (!excluded)
128 + {
129 + TrackLargestFiles(fi);
130 + TrackStaleFiles(fi);
131 + }
73 132 }
74 133
134 + if (TotalFoldersScanned % 100 == 0)
135 + UpdateProgress(path);
136 +
75 137 foreach (string dir in Directory.GetDirectories(path))
76 138 {
77 139 if (IsHardExcluded(dir)) continue;
@@ -80,7 +142,17 @@ namespace DiskUsageLog
80 142 }
81 143 catch
82 144 {
83 - // Accès refusé / erreur disque
145 + TotalErrorCount++;
146 + }
147 +
148 + if (isKnownCache && totalSize >= 50 * ONE_MB)
149 + {
150 + DetectedCacheFolders.Add(new CacheFolder
151 + {
152 + Path = path,
153 + Size = totalSize,
154 + FolderName = folderName
155 + });
84 156 }
85 157
86 158 if (totalSize >= ONE_GB)
@@ -119,6 +191,17 @@ namespace DiskUsageLog
119 191 || path.Contains(@"\AppData\Local\Temp");
120 192 }
121 193
194 + // ======================= EXCLUSIONS =======================
195 +
196 + static bool IsExcludedFile(FileInfo fi, string dirPath)
197 + {
198 + if (fi.Extension.Equals(".dbf", StringComparison.OrdinalIgnoreCase)
199 + && dirPath.StartsWith(@"C:\xstoredb", StringComparison.OrdinalIgnoreCase))
200 + return true;
201 +
202 + return false;
203 + }
204 +
122 205 // ======================= EXTENSIONS =======================
123 206
124 207 static void TrackExtension(FileInfo fi)
@@ -312,12 +395,328 @@ namespace DiskUsageLog
312 395 }
313 396 }
314 397
398 + // ======================= PROGRESSION =======================
399 +
400 + static void UpdateProgress(string currentDir)
401 + {
402 + spinnerIndex = (spinnerIndex + 1) % SpinnerChars.Length;
403 + string dir = currentDir.Length > 50
404 + ? "..." + currentDir.Substring(currentDir.Length - 47)
405 + : currentDir;
406 +
407 + string line = string.Format("\r {0} {1:N0} fichiers | {2:N0} dossiers | {3} GB | {4}",
408 + SpinnerChars[spinnerIndex],
409 + TotalFilesScanned,
410 + TotalFoldersScanned,
411 + ToGB(TotalSizeScanned),
412 + dir);
413 +
414 + int width = 120;
415 + try { width = Console.WindowWidth; } catch { }
416 + if (line.Length < width)
417 + line = line.PadRight(width - 1);
418 + else if (line.Length >= width)
419 + line = line.Substring(0, width - 1);
420 +
421 + Console.Write(line);
422 + }
423 +
424 + static void ClearProgress()
425 + {
426 + int width = 120;
427 + try { width = Console.WindowWidth; } catch { }
428 + Console.Write("\r" + new string(' ', width - 1) + "\r");
429 + }
430 +
431 + // ======================= RESUME =======================
432 +
433 + static void DisplaySummary()
434 + {
435 + Console.WriteLine("\n=== RESUME DU SCAN ===\n");
436 + Console.WriteLine("Machine : {0}", Environment.MachineName);
437 + Console.WriteLine("Duree : {0}", Timer.Elapsed.ToString(@"hh\:mm\:ss"));
438 + Console.WriteLine("Fichiers analyses : {0:N0}", TotalFilesScanned);
439 + Console.WriteLine("Dossiers analyses : {0:N0}", TotalFoldersScanned);
440 + Console.WriteLine("Taille totale scannee : {0} GB", ToGB(TotalSizeScanned));
441 + Console.WriteLine("Erreurs (acces refuse) : {0:N0}", TotalErrorCount);
442 + }
443 +
444 + // ======================= ARBORESCENCE RACINE =======================
445 +
446 + static void DisplayRootBreakdown()
447 + {
448 + Console.WriteLine("\n=== REPARTITION RACINE (top 30) ===\n");
449 +
450 + foreach (var item in RootBreakdown.OrderByDescending(r => r.Size).Take(30))
451 + {
452 + string name = Path.GetFileName(item.Path);
453 + if (string.IsNullOrEmpty(name)) name = item.Path;
454 +
455 + double pct = TotalSizeScanned > 0
456 + ? (item.Size * 100.0 / TotalSizeScanned)
457 + : 0;
458 +
459 + int barLen = Math.Min((int)(pct / 2), 25);
460 + string bar = new string('#', barLen).PadRight(25);
461 +
462 + Console.WriteLine("{0,-40} {1,8} GB [{2}] {3,5:F1}%",
463 + name.Length > 40 ? name.Substring(0, 37) + "..." : name,
464 + ToGB(item.Size),
465 + bar,
466 + pct);
467 + }
468 + }
469 +
470 + // ======================= FICHIERS ANCIENS =======================
471 +
472 + static void TrackStaleFiles(FileInfo fi)
473 + {
474 + try
475 + {
476 + if (fi.Length < 100 * ONE_MB) return;
477 + if (fi.LastWriteTime > DateTime.Now.AddYears(-2)) return;
478 +
479 + StaleFiles.Add(fi);
480 + StaleFiles = StaleFiles
481 + .OrderByDescending(f => f.Length)
482 + .Take(20)
483 + .ToList();
484 + }
485 + catch { }
486 + }
487 +
488 + static void DisplayStaleFiles()
489 + {
490 + if (StaleFiles.Count == 0) return;
491 +
492 + Console.WriteLine("\n=== GROS FICHIERS ANCIENS (>100 Mo, non modifies depuis 2+ ans) ===\n");
493 +
494 + foreach (var fi in StaleFiles)
495 + {
496 + string path = fi.FullName.Length > 75
497 + ? "..." + fi.FullName.Substring(fi.FullName.Length - 72)
498 + : fi.FullName;
499 +
500 + Console.WriteLine("{0,-75} {1,8} GB {2:yyyy-MM-dd}",
501 + path, ToGB(fi.Length), fi.LastWriteTime);
502 + }
503 + }
504 +
505 + // ======================= DOSSIERS TEMPORAIRES =======================
506 +
507 + static void DisplayCacheFolders()
508 + {
509 + if (DetectedCacheFolders.Count == 0) return;
510 +
511 + Console.WriteLine("\n=== DOSSIERS TEMPORAIRES / LOGS DETECTES (>50 Mo) ===\n");
512 +
513 + long total = 0;
514 + foreach (var cf in DetectedCacheFolders.OrderByDescending(c => c.Size).Take(30))
515 + {
516 + string path = cf.Path.Length > 70
517 + ? "..." + cf.Path.Substring(cf.Path.Length - 67)
518 + : cf.Path;
519 +
520 + Console.WriteLine("{0,-70} {1,8} GB",
521 + path, ToGB(cf.Size));
522 + total += cf.Size;
523 + }
524 +
525 + Console.WriteLine("\nTotal temporaires/logs : {0} GB", ToGB(total));
526 + }
527 +
528 + // ======================= DIAGNOSTIC SYSTEME =======================
529 +
530 + static void DisplaySystemDiagnostic()
531 + {
532 + Console.WriteLine("\n=== DIAGNOSTIC ZONES SYSTEME ===\n");
533 +
534 + var zones = new List<string>
535 + {
536 + @"C:\Windows\SoftwareDistribution\Download",
537 + @"C:\Windows\Temp",
538 + @"C:\Windows\Logs",
539 + @"C:\Windows\Panther",
540 + @"C:\ProgramData\Microsoft\Windows\WER",
541 + @"C:\$Recycle.Bin"
542 + };
543 +
544 + // Temp + cache par profil utilisateur
545 + try
546 + {
547 + foreach (string userDir in Directory.GetDirectories(@"C:\Users"))
548 + {
549 + string userName = Path.GetFileName(userDir);
550 + if (userName.Equals("Public", StringComparison.OrdinalIgnoreCase)
551 + || userName.Equals("Default", StringComparison.OrdinalIgnoreCase)
552 + || userName.Equals("Default User", StringComparison.OrdinalIgnoreCase))
553 + continue;
554 +
555 + zones.Add(Path.Combine(userDir, @"AppData\Local\Temp"));
556 + zones.Add(Path.Combine(userDir, @"AppData\Local\Microsoft\Windows\INetCache"));
557 +
558 + // Firefox cache
559 + string firefoxProfiles = Path.Combine(userDir, @"AppData\Local\Mozilla\Firefox\Profiles");
560 + if (Directory.Exists(firefoxProfiles))
561 + {
562 + foreach (string profile in Directory.GetDirectories(firefoxProfiles))
563 + zones.Add(Path.Combine(profile, "cache2"));
564 + }
565 + }
566 + }
567 + catch { }
568 +
569 + // memory.dmp
570 + string memDump = @"C:\Windows\memory.dmp";
571 + if (File.Exists(memDump))
572 + {
573 + long dumpSize = new FileInfo(memDump).Length;
574 + SystemDiagResults.Add(new LargeFolder { Path = memDump, Size = dumpSize });
575 + Console.WriteLine("{0,-65} {1,8} GB", memDump, ToGB(dumpSize));
576 + }
577 +
578 + long grandTotal = 0;
579 + foreach (string zone in zones)
580 + {
581 + if (!Directory.Exists(zone)) continue;
582 + long size = GetDirectorySize(zone);
583 + if (size < ONE_MB) continue;
584 +
585 + SystemDiagResults.Add(new LargeFolder { Path = zone, Size = size });
586 + Console.WriteLine("{0,-65} {1,8} GB",
587 + zone.Length > 65 ? "..." + zone.Substring(zone.Length - 62) : zone,
588 + ToGB(size));
589 + grandTotal += size;
590 + }
591 +
592 + Console.WriteLine("\nTotal zones systeme recuperable : {0} GB", ToGB(grandTotal));
593 + }
594 +
595 + static long GetDirectorySize(string path)
596 + {
597 + long size = 0;
598 + try
599 + {
600 + foreach (string file in Directory.GetFiles(path))
601 + {
602 + try { size += new FileInfo(file).Length; } catch { }
603 + }
604 + foreach (string dir in Directory.GetDirectories(path))
605 + {
606 + size += GetDirectorySize(dir);
607 + }
608 + }
609 + catch { }
610 + return size;
611 + }
612 +
613 + // ======================= EXPORT =======================
614 +
615 + static void ExportReport(string rootPath)
616 + {
617 + string fileName = Environment.MachineName + ".diskusage.log";
618 + string exeDir = AppDomain.CurrentDomain.BaseDirectory;
619 + string exportPath = Path.Combine(exeDir, fileName);
620 +
621 + try
622 + {
623 + var sb = new StringBuilder();
624 + sb.AppendLine("DiskUsageLog - Rapport d'analyse disque");
625 + sb.AppendLine("Machine : " + Environment.MachineName);
626 + sb.AppendLine("Racine : " + rootPath);
627 + sb.AppendLine("Date : " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
628 + sb.AppendLine("Duree : " + Timer.Elapsed.ToString(@"hh\:mm\:ss"));
629 + sb.AppendLine(new string('=', 80));
630 +
631 + sb.AppendFormat("\nFichiers analyses : {0:N0}\n", TotalFilesScanned);
632 + sb.AppendFormat("Dossiers analyses : {0:N0}\n", TotalFoldersScanned);
633 + sb.AppendFormat("Taille totale : {0} GB\n", ToGB(TotalSizeScanned));
634 + sb.AppendFormat("Erreurs : {0:N0}\n", TotalErrorCount);
635 +
636 + sb.AppendLine("\n--- REPARTITION RACINE ---");
637 + foreach (var item in RootBreakdown.OrderByDescending(r => r.Size).Take(30))
638 + {
639 + string name = Path.GetFileName(item.Path);
640 + if (string.IsNullOrEmpty(name)) name = item.Path;
641 + sb.AppendFormat("{0,-60} {1} GB\n", name, ToGB(item.Size));
642 + }
643 +
644 + sb.AppendLine("\n--- DOSSIERS > 1 Go ---");
645 + foreach (var f in LargeFolders.OrderByDescending(f => f.Size))
646 + {
647 + string flag = f.IsRiskArea ? " !!!" : "";
648 + sb.AppendFormat("{0} : {1} GB{2}\n", f.Path, ToGB(f.Size), flag);
649 + }
650 +
651 + sb.AppendLine("\n--- TOP 20 EXTENSIONS ---");
652 + foreach (var ext in ExtensionStats.OrderByDescending(e => e.Value.Size).Take(20))
653 + {
654 + sb.AppendFormat("{0,-12} {1,10} fichiers {2} GB\n",
655 + ext.Key, ext.Value.Count, ToGB(ext.Value.Size));
656 + }
657 +
658 + sb.AppendLine("\n--- TOP 10 PLUS GROS FICHIERS ---");
659 + foreach (var fi in LargestFiles)
660 + sb.AppendFormat("{0} : {1} GB\n", fi.FullName, ToGB(fi.Length));
661 +
662 + if (StaleFiles.Count > 0)
663 + {
664 + sb.AppendLine("\n--- GROS FICHIERS ANCIENS ---");
665 + foreach (var fi in StaleFiles)
666 + sb.AppendFormat("{0} : {1} GB (modifie {2:yyyy-MM-dd})\n",
667 + fi.FullName, ToGB(fi.Length), fi.LastWriteTime);
668 + }
669 +
670 + if (DetectedCacheFolders.Count > 0)
671 + {
672 + sb.AppendLine("\n--- DOSSIERS TEMPORAIRES / LOGS ---");
673 + foreach (var cf in DetectedCacheFolders.OrderByDescending(c => c.Size).Take(30))
674 + sb.AppendFormat("{0} : {1} GB\n", cf.Path, ToGB(cf.Size));
675 + }
676 +
677 + if (SystemDiagResults.Count > 0)
678 + {
679 + sb.AppendLine("\n--- DIAGNOSTIC ZONES SYSTEME ---");
680 + foreach (var sd in SystemDiagResults.OrderByDescending(s => s.Size))
681 + sb.AppendFormat("{0} : {1} GB\n", sd.Path, ToGB(sd.Size));
682 + }
683 +
684 + File.WriteAllText(exportPath, sb.ToString());
685 + Console.WriteLine("\nRapport exporte : " + exportPath);
686 + }
687 + catch (Exception ex)
688 + {
689 + Console.WriteLine("\nErreur export : " + ex.Message);
690 + }
691 + }
692 +
315 693 // ======================= UTILS =======================
316 694
317 695 static double ToGB(long bytes)
318 696 {
319 697 return Math.Round(bytes / 1024d / 1024 / 1024, 2);
320 698 }
699 +
700 + static void DisplayXstoreInfo()
701 + {
702 + try
703 + {
704 + using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\GFI"))
705 + {
706 + if (key == null) return;
707 +
708 + Console.WriteLine(" --- XSTORE ---");
709 +
710 + foreach (var name in key.GetValueNames())
711 + {
712 + var val = key.GetValue(name);
713 + if (val != null && val.ToString().Length > 0)
714 + Console.WriteLine($" {name,-25}: {val}");
715 + }
716 + }
717 + }
718 + catch { }
719 + }
321 720 }
322 721
323 722 // ======================= MODELES =======================
@@ -334,4 +733,11 @@ namespace DiskUsageLog
334 733 public long Size;
335 734 public bool IsRiskArea;
336 735 }
736 +
737 + class CacheFolder
738 + {
739 + public string Path;
740 + public long Size;
741 + public string FolderName;
742 + }
337 743 }

fred revisó este gist 1777323499. Ir a la revisión

1 file changed, 337 insertions

gistfile1.txt(archivo creado)

@@ -0,0 +1,337 @@
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 + }
Siguiente Anterior