From 7923241ec5fdecc018899e0a594a4d5f34fe790a Mon Sep 17 00:00:00 2001 From: Ilya Date: Wed, 19 Aug 2020 16:51:26 +0500 Subject: [PATCH 1/2] Process reparse points to Microsoft Store applications --- .../engine/NativeCommandProcessor.cs | 49 ++++++++++++++++--- .../namespaces/FileSystemProvider.cs | 27 ++++++---- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 3a12dab6295..05b316f0de0 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -10,7 +10,6 @@ using System.Collections; using System.Threading; using System.Management.Automation.Internal; -using System.Management.Automation.Runspaces; using System.Xml; using System.Runtime.InteropServices; using Dbg = System.Management.Automation.Diagnostics; @@ -222,6 +221,29 @@ private string Path } } + /// + /// Gets true if Path is Console Application. + /// + private bool IsConsoleApplication => !IsWindowsApplication; + + /// + /// Gets true if Path is Windows Application. + /// + private bool IsWindowsApplication + { + get + { + if (!_isWindowsApplication.HasValue) + { + _isWindowsApplication = CheckIfWindowsApplication(Path); + } + + return _isWindowsApplication.Value; + } + } + + private bool? _isWindowsApplication; + #endregion ctor/native command properties #region parameter binder @@ -476,7 +498,7 @@ private void InitNativeProcess() bool notDone = true; if (!string.IsNullOrEmpty(executable)) { - if (IsConsoleApplication(executable)) + if (CheckIfConsoleApplication(executable)) { // Allocate a console if there isn't one attached already... ConsoleVisibility.AllocateHiddenConsole(); @@ -532,7 +554,7 @@ private void InitNativeProcess() _isRunningInBackground = true; if (startInfo.UseShellExecute == false) { - _isRunningInBackground = IsWindowsApplication(_nativeProcess.StartInfo.FileName); + _isRunningInBackground = IsWindowsApplication; } } @@ -935,9 +957,9 @@ private static void KillChildProcesses(int parentId, ProcessWithParentId[] curre /// /// /// - private static bool IsConsoleApplication(string fileName) + private static bool CheckIfConsoleApplication(string fileName) { - return !IsWindowsApplication(fileName); + return !CheckIfWindowsApplication(fileName); } /// @@ -946,10 +968,22 @@ private static bool IsConsoleApplication(string fileName) /// /// [ArchitectureSensitive] - private static bool IsWindowsApplication(string fileName) + private static bool CheckIfWindowsApplication(string fileName) { +#if UNIX + return false; +#else if (!Platform.IsWindowsDesktop) { return false; } + // SHGetFileInfo() does not understand reparse points and returns 0 ("non exe or error") + // so we are trying to get a real path before. + // It is a workaround for Microsoft Store applications. + string realPath = Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods.WinInternalGetTarget(fileName); + if (realPath is not null) + { + fileName = realPath; + } + SHFILEINFO shinfo = new SHFILEINFO(); IntPtr type = SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_EXETYPE); @@ -968,6 +1002,7 @@ private static bool IsWindowsApplication(string fileName) // anything else - is a windows program... return true; } +#endif } #endregion checkForConsoleApplication @@ -1266,7 +1301,7 @@ private void CalculateIORedirection(out bool redirectOutput, out bool redirectEr redirectOutput = true; redirectError = true; } - else if (Platform.IsWindowsDesktop && IsConsoleApplication(this.Path)) + else if (Platform.IsWindowsDesktop && IsConsoleApplication) { // On Windows desktops, if the command to run is a console application, // then allocate a console if there isn't one attached already... diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index c1a539fb3ac..1adc58d8fbf 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -8073,16 +8073,7 @@ public static string GetTarget(PSObject instance) if (instance.BaseObject is FileSystemInfo fileSysInfo) { #if !UNIX - // We set accessMode parameter to zero because documentation says: - // If this parameter is zero, the application can query certain metadata - // such as file, directory, or device attributes without accessing - // that file or device, even if GENERIC_READ access would have been denied. - using (SafeFileHandle handle = OpenReparsePoint(fileSysInfo.FullName, FileDesiredAccess.GenericZero)) - { - string linkTarget = WinInternalGetTarget(handle); - - return linkTarget; - } + return WinInternalGetTarget(fileSysInfo.FullName); #else return UnixInternalGetTarget(fileSysInfo.FullName); #endif @@ -8382,6 +8373,21 @@ internal static bool WinIsHardLink(ref IntPtr handle) return succeeded && (handleInfo.NumberOfLinks > 1); } +#if !UNIX + internal static string WinInternalGetTarget(string path) + { + // We set accessMode parameter to zero because documentation says: + // If this parameter is zero, the application can query certain metadata + // such as file, directory, or device attributes without accessing + // that file or device, even if GENERIC_READ access would have been denied. + using (SafeFileHandle handle = OpenReparsePoint(path, FileDesiredAccess.GenericZero)) + { + string linkTarget = WinInternalGetTarget(handle); + + return linkTarget; + } + } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")] private static string WinInternalGetTarget(SafeFileHandle handle) { @@ -8456,6 +8462,7 @@ private static string WinInternalGetTarget(SafeFileHandle handle) Marshal.FreeHGlobal(outBuffer); } } +#endif internal static bool CreateJunction(string path, string target) { From d6ee64847415d60dae32e82e6fdd7e34550d77ba Mon Sep 17 00:00:00 2001 From: Ilya Date: Thu, 27 Aug 2020 08:08:33 +0500 Subject: [PATCH 2/2] Update src/System.Management.Automation/namespaces/FileSystemProvider.cs Co-authored-by: Robert Holt --- .../namespaces/FileSystemProvider.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 1adc58d8fbf..e4567a96b31 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -8382,9 +8382,7 @@ internal static string WinInternalGetTarget(string path) // that file or device, even if GENERIC_READ access would have been denied. using (SafeFileHandle handle = OpenReparsePoint(path, FileDesiredAccess.GenericZero)) { - string linkTarget = WinInternalGetTarget(handle); - - return linkTarget; + return WinInternalGetTarget(handle); } }