Skip to content

Commit 4e2b6e9

Browse files
authored
Process reparse points for Microsoft Store applications (PowerShell#13481)
1 parent 78d0d0e commit 4e2b6e9

2 files changed

Lines changed: 57 additions & 17 deletions

File tree

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

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using System.Collections;
1111
using System.Threading;
1212
using System.Management.Automation.Internal;
13-
using System.Management.Automation.Runspaces;
1413
using System.Xml;
1514
using System.Runtime.InteropServices;
1615
using Dbg = System.Management.Automation.Diagnostics;
@@ -222,6 +221,29 @@ private string Path
222221
}
223222
}
224223

224+
/// <summary>
225+
/// Gets true if Path is Console Application.
226+
/// </summary>
227+
private bool IsConsoleApplication => !IsWindowsApplication;
228+
229+
/// <summary>
230+
/// Gets true if Path is Windows Application.
231+
/// </summary>
232+
private bool IsWindowsApplication
233+
{
234+
get
235+
{
236+
if (!_isWindowsApplication.HasValue)
237+
{
238+
_isWindowsApplication = CheckIfWindowsApplication(Path);
239+
}
240+
241+
return _isWindowsApplication.Value;
242+
}
243+
}
244+
245+
private bool? _isWindowsApplication;
246+
225247
#endregion ctor/native command properties
226248

227249
#region parameter binder
@@ -476,7 +498,7 @@ private void InitNativeProcess()
476498
bool notDone = true;
477499
if (!string.IsNullOrEmpty(executable))
478500
{
479-
if (IsConsoleApplication(executable))
501+
if (CheckIfConsoleApplication(executable))
480502
{
481503
// Allocate a console if there isn't one attached already...
482504
ConsoleVisibility.AllocateHiddenConsole();
@@ -532,7 +554,7 @@ private void InitNativeProcess()
532554
_isRunningInBackground = true;
533555
if (startInfo.UseShellExecute == false)
534556
{
535-
_isRunningInBackground = IsWindowsApplication(_nativeProcess.StartInfo.FileName);
557+
_isRunningInBackground = IsWindowsApplication;
536558
}
537559
}
538560

@@ -935,9 +957,9 @@ private static void KillChildProcesses(int parentId, ProcessWithParentId[] curre
935957
/// </summary>
936958
/// <param name="fileName"></param>
937959
/// <returns></returns>
938-
private static bool IsConsoleApplication(string fileName)
960+
private static bool CheckIfConsoleApplication(string fileName)
939961
{
940-
return !IsWindowsApplication(fileName);
962+
return !CheckIfWindowsApplication(fileName);
941963
}
942964

943965
/// <summary>
@@ -946,10 +968,22 @@ private static bool IsConsoleApplication(string fileName)
946968
/// <param name="fileName"></param>
947969
/// <returns></returns>
948970
[ArchitectureSensitive]
949-
private static bool IsWindowsApplication(string fileName)
971+
private static bool CheckIfWindowsApplication(string fileName)
950972
{
973+
#if UNIX
974+
return false;
975+
#else
951976
if (!Platform.IsWindowsDesktop) { return false; }
952977

978+
// SHGetFileInfo() does not understand reparse points and returns 0 ("non exe or error")
979+
// so we are trying to get a real path before.
980+
// It is a workaround for Microsoft Store applications.
981+
string realPath = Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods.WinInternalGetTarget(fileName);
982+
if (realPath is not null)
983+
{
984+
fileName = realPath;
985+
}
986+
953987
SHFILEINFO shinfo = new SHFILEINFO();
954988
IntPtr type = SHGetFileInfo(fileName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_EXETYPE);
955989

@@ -968,6 +1002,7 @@ private static bool IsWindowsApplication(string fileName)
9681002
// anything else - is a windows program...
9691003
return true;
9701004
}
1005+
#endif
9711006
}
9721007

9731008
#endregion checkForConsoleApplication
@@ -1266,7 +1301,7 @@ private void CalculateIORedirection(out bool redirectOutput, out bool redirectEr
12661301
redirectOutput = true;
12671302
redirectError = true;
12681303
}
1269-
else if (Platform.IsWindowsDesktop && IsConsoleApplication(this.Path))
1304+
else if (Platform.IsWindowsDesktop && IsConsoleApplication)
12701305
{
12711306
// On Windows desktops, if the command to run is a console application,
12721307
// then allocate a console if there isn't one attached already...

src/System.Management.Automation/namespaces/FileSystemProvider.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8073,16 +8073,7 @@ public static string GetTarget(PSObject instance)
80738073
if (instance.BaseObject is FileSystemInfo fileSysInfo)
80748074
{
80758075
#if !UNIX
8076-
// We set accessMode parameter to zero because documentation says:
8077-
// If this parameter is zero, the application can query certain metadata
8078-
// such as file, directory, or device attributes without accessing
8079-
// that file or device, even if GENERIC_READ access would have been denied.
8080-
using (SafeFileHandle handle = OpenReparsePoint(fileSysInfo.FullName, FileDesiredAccess.GenericZero))
8081-
{
8082-
string linkTarget = WinInternalGetTarget(handle);
8083-
8084-
return linkTarget;
8085-
}
8076+
return WinInternalGetTarget(fileSysInfo.FullName);
80868077
#else
80878078
return UnixInternalGetTarget(fileSysInfo.FullName);
80888079
#endif
@@ -8382,6 +8373,19 @@ internal static bool WinIsHardLink(ref IntPtr handle)
83828373
return succeeded && (handleInfo.NumberOfLinks > 1);
83838374
}
83848375

8376+
#if !UNIX
8377+
internal static string WinInternalGetTarget(string path)
8378+
{
8379+
// We set accessMode parameter to zero because documentation says:
8380+
// If this parameter is zero, the application can query certain metadata
8381+
// such as file, directory, or device attributes without accessing
8382+
// that file or device, even if GENERIC_READ access would have been denied.
8383+
using (SafeFileHandle handle = OpenReparsePoint(path, FileDesiredAccess.GenericZero))
8384+
{
8385+
return WinInternalGetTarget(handle);
8386+
}
8387+
}
8388+
83858389
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")]
83868390
private static string WinInternalGetTarget(SafeFileHandle handle)
83878391
{
@@ -8456,6 +8460,7 @@ private static string WinInternalGetTarget(SafeFileHandle handle)
84568460
Marshal.FreeHGlobal(outBuffer);
84578461
}
84588462
}
8463+
#endif
84598464

84608465
internal static bool CreateJunction(string path, string target)
84618466
{

0 commit comments

Comments
 (0)