Skip to content

Commit 74aa257

Browse files
Skip cloud files marked as "not on disk" during command discovery (PowerShell#18152)
1 parent 8374823 commit 74aa257

File tree

4 files changed

+61
-2
lines changed

4 files changed

+61
-2
lines changed

experimental-feature-linux.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
"PSLoadAssemblyFromNativeCode",
55
"PSNativeCommandErrorActionPreference",
66
"PSSubsystemPluginModel",
7+
"PSModuleAutoLoadSkipOfflineFiles",
78
"PSFeedbackProvider"
89
]

experimental-feature-windows.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
"PSLoadAssemblyFromNativeCode",
55
"PSNativeCommandErrorActionPreference",
66
"PSSubsystemPluginModel",
7+
"PSModuleAutoLoadSkipOfflineFiles",
78
"PSFeedbackProvider"
89
]

src/System.Management.Automation/engine/ExperimentalFeature/ExperimentalFeature.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class ExperimentalFeature
2222

2323
internal const string EngineSource = "PSEngine";
2424
internal const string PSNativeCommandErrorActionPreferenceFeatureName = "PSNativeCommandErrorActionPreference";
25+
internal const string PSModuleAutoLoadSkipOfflineFilesFeatureName = "PSModuleAutoLoadSkipOfflineFiles";
2526
internal const string PSCustomTableHeaderLabelDecoration = "PSCustomTableHeaderLabelDecoration";
2627
internal const string PSFeedbackProvider = "PSFeedbackProvider";
2728

@@ -118,6 +119,9 @@ static ExperimentalFeature()
118119
new ExperimentalFeature(
119120
name: PSNativeCommandErrorActionPreferenceFeatureName,
120121
description: "Native commands with non-zero exit codes issue errors according to $ErrorActionPreference when $PSNativeCommandUseErrorActionPreference is $true"),
122+
new ExperimentalFeature(
123+
name: PSModuleAutoLoadSkipOfflineFilesFeatureName,
124+
description: "Module discovery will skip over files that are marked by cloud providers as not fully on disk."),
121125
new ExperimentalFeature(
122126
name: PSCustomTableHeaderLabelDecoration,
123127
description: "Formatting differentiation for table header labels that aren't property members"),

src/System.Management.Automation/engine/Modules/ModuleUtils.cs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,46 @@ namespace System.Management.Automation.Internal
1313
{
1414
internal static class ModuleUtils
1515
{
16+
// These are documented members FILE_ATTRIBUTE, they just have not yet been
17+
// added to System.IO.FileAttributes yet.
18+
private const int FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
19+
20+
private const int FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
21+
1622
// Default option for local file system enumeration:
1723
// - Ignore files/directories when access is denied;
1824
// - Search top directory only.
1925
private static readonly System.IO.EnumerationOptions s_defaultEnumerationOptions =
20-
new System.IO.EnumerationOptions() { AttributesToSkip = FileAttributes.Hidden };
26+
new System.IO.EnumerationOptions() { AttributesToSkip = FileAttributesToSkip };
27+
28+
private static readonly FileAttributes FileAttributesToSkip;
2129

2230
// Default option for UNC path enumeration. Same as above plus a large buffer size.
2331
// For network shares, a large buffer may result in better performance as more results can be batched over the wire.
2432
// The buffer size 16K is recommended in the comment of the 'BufferSize' property:
2533
// "A "large" buffer, for example, would be 16K. Typical is 4K."
2634
private static readonly System.IO.EnumerationOptions s_uncPathEnumerationOptions =
27-
new System.IO.EnumerationOptions() { AttributesToSkip = FileAttributes.Hidden, BufferSize = 16384 };
35+
new System.IO.EnumerationOptions() { AttributesToSkip = FileAttributesToSkip, BufferSize = 16384 };
2836

2937
private static readonly string EnCulturePath = Path.DirectorySeparatorChar + "en";
3038
private static readonly string EnUsCulturePath = Path.DirectorySeparatorChar + "en-us";
3139

40+
static ModuleUtils()
41+
{
42+
if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSModuleAutoLoadSkipOfflineFilesFeatureName))
43+
{
44+
FileAttributesToSkip = FileAttributes.Hidden
45+
// Skip OneDrive files/directories that are not fully on disk.
46+
| FileAttributes.Offline
47+
| (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
48+
| (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_OPEN;
49+
50+
return;
51+
}
52+
53+
FileAttributesToSkip = FileAttributes.Hidden;
54+
}
55+
3256
/// <summary>
3357
/// Check if a directory is likely a localized resources folder.
3458
/// </summary>
@@ -276,6 +300,11 @@ internal static IEnumerable<string> GetDefaultAvailableModuleFiles(string topDir
276300
manifestPath += StringLiterals.PowerShellDataFileExtension;
277301
if (File.Exists(manifestPath))
278302
{
303+
if (HasSkippedFileAttribute(manifestPath))
304+
{
305+
continue;
306+
}
307+
279308
isModuleDirectory = true;
280309
yield return manifestPath;
281310
}
@@ -288,6 +317,11 @@ internal static IEnumerable<string> GetDefaultAvailableModuleFiles(string topDir
288317
string moduleFile = Path.Combine(directoryToCheck, proposedModuleName) + ext;
289318
if (File.Exists(moduleFile))
290319
{
320+
if (HasSkippedFileAttribute(moduleFile))
321+
{
322+
continue;
323+
}
324+
291325
isModuleDirectory = true;
292326
yield return moduleFile;
293327

@@ -337,6 +371,25 @@ internal static List<Version> GetModuleVersionSubfolders(string moduleBase)
337371
return versionFolders;
338372
}
339373

374+
private static bool HasSkippedFileAttribute(string path)
375+
{
376+
try
377+
{
378+
FileAttributes attributes = File.GetAttributes(path);
379+
if ((attributes & FileAttributesToSkip) is not 0)
380+
{
381+
return true;
382+
}
383+
}
384+
catch
385+
{
386+
// Ignore failures so that we keep the current behavior of failing
387+
// later in the search.
388+
}
389+
390+
return false;
391+
}
392+
340393
private static void ProcessPossibleVersionSubdirectories(IEnumerable<string> subdirectories, List<Version> versionFolders)
341394
{
342395
foreach (string subdir in subdirectories)

0 commit comments

Comments
 (0)