From 3dbe3f994e0a3c581354c7d4e3ea5e1298cb8659 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Fri, 22 Aug 2025 12:09:28 -0400 Subject: [PATCH 1/3] for each subdirectory, set attribute to normal so it can be deleted without access denied error and add error handling --- src/code/Utils.cs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index ae540f9e4..1a43fe8eb 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1658,6 +1658,16 @@ public static void DeleteDirectoryWithRestore(string dirPath) } } + private static void SetAttributesHelper(DirectoryInfo directory) + { + foreach (var subDirectory in directory.GetDirectories()) + { + subDirectory.Attributes = FileAttributes.Normal; + SetAttributesHelper(subDirectory); + } + + directory.Attributes = FileAttributes.Normal; + } /// /// Deletes a directory and its contents /// This is a workaround for .NET Directory.Delete(), which can fail with WindowsPowerShell @@ -1672,13 +1682,17 @@ public static void DeleteDirectory(string dirPath) } // Remove read only file attributes first - foreach (var dirFilePath in Directory.GetFiles(dirPath,"*",SearchOption.AllDirectories)) + foreach (var dirFilePath in Directory.GetFiles(dirPath, "*", SearchOption.AllDirectories)) { if (File.GetAttributes(dirFilePath).HasFlag(FileAttributes.ReadOnly)) { File.SetAttributes(dirFilePath, File.GetAttributes(dirFilePath) & ~FileAttributes.ReadOnly); } } + + DirectoryInfo rootDir = new DirectoryInfo(dirPath); + SetAttributesHelper(rootDir); + // Delete directory recursive, try multiple times before throwing ( #1662 ) int maxAttempts = 5; int msDelay = 5; @@ -1686,7 +1700,7 @@ public static void DeleteDirectory(string dirPath) { try { - Directory.Delete(dirPath,true); + Directory.Delete(dirPath, true); return; } catch (Exception ex) @@ -1695,6 +1709,10 @@ public static void DeleteDirectory(string dirPath) { Thread.Sleep(msDelay); } + else if (ex is System.IO.IOException) + { + throw new Exception(string.Format("Access denied to path while deleting path {0}", dirPath), ex); + } else { throw; From ccb00d37bae6a51696ca89a2adeba889ab36d3ed Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 20 Oct 2025 11:47:58 -0400 Subject: [PATCH 2/3] add error message for WindowsPowerShell --- src/code/Utils.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 1a43fe8eb..501bd5ac3 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1711,6 +1711,13 @@ public static void DeleteDirectory(string dirPath) } else if (ex is System.IO.IOException) { + string psVersion = System.Management.Automation.Runspaces.Runspace.DefaultRunspace.Version.ToString(); + if (ex.Message.Contains("The directory is not empty") && psVersion.StartsWith("5")) + { + // there is a known bug with WindowsPowerShell and OneDrive based module paths, where at uninstall time .NET Directory.Delete() will give 'The directory is not empty.' error + throw new Exception(string.Format("Cannot uninstall module with OneDrive based path on WindowsPowerShell due to .NET issue. Try installing and uninstalling using PowerShellCore if using OneDrive."), ex); + } + throw new Exception(string.Format("Access denied to path while deleting path {0}", dirPath), ex); } else From aa85c9e67ae20991127801b901bb1b2f77afe858 Mon Sep 17 00:00:00 2001 From: Anam Navied Date: Mon, 20 Oct 2025 11:49:42 -0400 Subject: [PATCH 3/3] update comment --- src/code/Utils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code/Utils.cs b/src/code/Utils.cs index 501bd5ac3..7fe491376 100644 --- a/src/code/Utils.cs +++ b/src/code/Utils.cs @@ -1714,7 +1714,7 @@ public static void DeleteDirectory(string dirPath) string psVersion = System.Management.Automation.Runspaces.Runspace.DefaultRunspace.Version.ToString(); if (ex.Message.Contains("The directory is not empty") && psVersion.StartsWith("5")) { - // there is a known bug with WindowsPowerShell and OneDrive based module paths, where at uninstall time .NET Directory.Delete() will give 'The directory is not empty.' error + // there is a known bug with WindowsPowerShell and OneDrive based module paths, where .NET Directory.Delete() will throw a 'The directory is not empty.' error. throw new Exception(string.Format("Cannot uninstall module with OneDrive based path on WindowsPowerShell due to .NET issue. Try installing and uninstalling using PowerShellCore if using OneDrive."), ex); }