diff --git a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/FileSystem_format_ps1xml.cs b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/FileSystem_format_ps1xml.cs index e35cb4ecc1..183262b2a5 100644 --- a/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/FileSystem_format_ps1xml.cs +++ b/src/System.Management.Automation/FormatAndOutput/DefaultFormatters/FileSystem_format_ps1xml.cs @@ -42,28 +42,33 @@ namespace System.Management.Automation.Runspaces private static IEnumerable ViewsOf_FileSystemTypes(CustomControl[] sharedControls) { - const string LengthScriptBlock = -@"if ($_ -is [System.IO.DirectoryInfo]) { return '' } -if ($_.Attributes -band [System.IO.FileAttributes]::Offline) -{ - return '({0})' -f $_.Length -} -return $_.Length"; - yield return new FormatViewDefinition("children", TableControl.Create() .GroupByProperty("PSParentPath", customControl: sharedControls[0]) .AddHeader(Alignment.Left, label: "Mode", width: 7) .AddHeader(Alignment.Right, label: "LastWriteTime", width: 25) .AddHeader(Alignment.Right, label: "Length", width: 14) - .AddHeader() + .AddHeader(Alignment.Left, label: "Name") + .StartRowDefinition(wrap: true) + .AddPropertyColumn("ModeWithoutHardLink") + .AddPropertyColumn("LastWriteTimeString") + .AddPropertyColumn("LengthString") + .AddPropertyColumn("NameString") + .EndRowDefinition() + .EndTable()); + + yield return new FormatViewDefinition("childrenWithHardlink", + TableControl.Create() + .GroupByProperty("PSParentPath", customControl: sharedControls[0]) + .AddHeader(Alignment.Left, label: "Mode", width: 7) + .AddHeader(Alignment.Right, label: "LastWriteTime", width: 25) + .AddHeader(Alignment.Right, label: "Length", width: 14) + .AddHeader(Alignment.Left, label: "Name") .StartRowDefinition(wrap: true) .AddPropertyColumn("Mode") - .AddScriptBlockColumn(@" - [String]::Format(""{0,10} {1,8}"", $_.LastWriteTime.ToString(""d""), $_.LastWriteTime.ToString(""t"")) - ") - .AddScriptBlockColumn(LengthScriptBlock) - .AddPropertyColumn("Name") + .AddPropertyColumn("LastWriteTimeString") + .AddPropertyColumn("LengthString") + .AddPropertyColumn("NameString") .EndRowDefinition() .EndTable()); @@ -72,7 +77,7 @@ return $_.Length"; .GroupByProperty("PSParentPath", customControl: sharedControls[0]) .StartEntry(entrySelectedByType: new[] { "System.IO.FileInfo" }) .AddItemProperty(@"Name") - .AddItemScriptBlock(LengthScriptBlock, label: "Length") + .AddItemProperty("LengthString", label: "Length") .AddItemProperty(@"CreationTime") .AddItemProperty(@"LastWriteTime") .AddItemProperty(@"LastAccessTime") diff --git a/src/System.Management.Automation/engine/Types_Ps1Xml.cs b/src/System.Management.Automation/engine/Types_Ps1Xml.cs index 8b71076ad8..5b28c7bc5e 100644 --- a/src/System.Management.Automation/engine/Types_Ps1Xml.cs +++ b/src/System.Management.Automation/engine/Types_Ps1Xml.cs @@ -183,18 +183,28 @@ namespace System.Management.Automation.Runspaces var td19 = new TypeData(@"System.IO.DirectoryInfo", true); td19.Members.Add("Mode", new CodePropertyData("Mode", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "Mode"), null)); + td19.Members.Add("ModeWithoutHardLink", + new CodePropertyData("ModeWithoutHardLink", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "ModeWithoutHardLink"), null)); td19.Members.Add("BaseName", new ScriptPropertyData(@"BaseName", GetScriptBlock(@"$this.Name"), null)); td19.Members.Add("Target", new CodePropertyData("Target", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetTarget"), null)); td19.Members.Add("LinkType", new CodePropertyData("LinkType", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetLinkType"), null)); + td19.Members.Add("NameString", + new CodePropertyData("NameString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "NameString"), null) { IsHidden = true }); + td19.Members.Add("LengthString", + new CodePropertyData("LengthString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "LengthString"), null) { IsHidden = true }); + td19.Members.Add("LastWriteTimeString", + new CodePropertyData("LastWriteTimeString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "LastWriteTimeString"), null) { IsHidden = true }); td19.DefaultDisplayProperty = @"Name"; yield return td19; var td20 = new TypeData(@"System.IO.FileInfo", true); td20.Members.Add("Mode", new CodePropertyData("Mode", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "Mode"), null)); + td20.Members.Add("ModeWithoutHardLink", + new CodePropertyData("ModeWithoutHardLink", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "ModeWithoutHardLink"), null)); td20.Members.Add("VersionInfo", new ScriptPropertyData(@"VersionInfo", GetScriptBlock(@"[System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName)"), null)); td20.Members.Add("BaseName", @@ -203,6 +213,12 @@ namespace System.Management.Automation.Runspaces new CodePropertyData("Target", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetTarget"), null)); td20.Members.Add("LinkType", new CodePropertyData("LinkType", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods), "GetLinkType"), null)); + td20.Members.Add("NameString", + new CodePropertyData("NameString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "NameString"), null) { IsHidden = true }); + td20.Members.Add("LengthString", + new CodePropertyData("LengthString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "LengthString"), null) { IsHidden = true }); + td20.Members.Add("LastWriteTimeString", + new CodePropertyData("LastWriteTimeString", GetMethodInfo(typeof(Microsoft.PowerShell.Commands.FileSystemProvider), "LastWriteTimeString"), null) { IsHidden = true }); td20.DefaultDisplayPropertySet = new PropertySetData(new[] { "LastWriteTime", "Length", "Name" }) { Name = "DefaultDisplayPropertySet" }; yield return td20; diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index e4f495ce55..82f01d0552 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -1867,33 +1867,99 @@ namespace Microsoft.PowerShell.Commands /// Provides a mode property for FileSystemInfo. /// /// Instance of PSObject wrapping a FileSystemInfo. + /// A string representation of the FileAttributes, with one letter per attribute. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")] - public static string Mode(PSObject instance) + public static string Mode(PSObject instance) => Mode(instance, excludeHardLink: false); + + /// + /// Provides a ModeWithoutHardLink property for FileSystemInfo, without HardLinks for performance reasons. + /// + /// Instance of PSObject wrapping a FileSystemInfo. + /// A string representation of the FileAttributes, with one letter per attribute. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")] + public static string ModeWithoutHardLink(PSObject instance) => Mode(instance, excludeHardLink: true); + + private static string Mode(PSObject instance, bool excludeHardLink) { - if (instance == null) + string ToModeString(FileSystemInfo fileSystemInfo) { - return string.Empty; + FileAttributes fileAttributes = fileSystemInfo.Attributes; + + bool isReparsePoint = InternalSymbolicLinkLinkCodeMethods.IsReparsePoint(fileSystemInfo); + bool isLink = isReparsePoint || (excludeHardLink ? false : InternalSymbolicLinkLinkCodeMethods.IsHardLink(fileSystemInfo)); + if (!isLink) + { + // special casing for the common cases - no allocations + switch (fileAttributes) + { + case FileAttributes.Archive: + return "-a---"; + case FileAttributes.Directory: + return "d----"; + case FileAttributes.Normal: + return "-----"; + case FileAttributes.Directory | FileAttributes.ReadOnly: + return "d-r--"; + case FileAttributes.Archive | FileAttributes.ReadOnly: + return "-ar--"; + } + } + + bool isDirectory = fileAttributes.HasFlag(FileAttributes.Directory); + ReadOnlySpan mode = stackalloc char[] + { + isLink ? 'l' : isDirectory ? 'd' : '-', + fileAttributes.HasFlag(FileAttributes.Archive) ? 'a' : '-', + fileAttributes.HasFlag(FileAttributes.ReadOnly) ? 'r' : '-', + fileAttributes.HasFlag(FileAttributes.Hidden) ? 'h' : '-', + fileAttributes.HasFlag(FileAttributes.System) ? 's' : '-', + }; + return new string(mode); } - FileSystemInfo fileInfo = (FileSystemInfo)instance.BaseObject; - if (fileInfo == null) - { - return string.Empty; - } + return instance?.BaseObject is FileSystemInfo fileInfo + ? ToModeString(fileInfo) + : string.Empty; + } - char[] mode = new char[6]; - mode[0] = (fileInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory ? 'd' : '-'; - mode[1] = (fileInfo.Attributes & FileAttributes.Archive) == FileAttributes.Archive ? 'a' : '-'; - mode[2] = (fileInfo.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly ? 'r' : '-'; - mode[3] = (fileInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden ? 'h' : '-'; - mode[4] = (fileInfo.Attributes & FileAttributes.System) == FileAttributes.System ? 's' : '-'; - // Mark the last bit as a "l" if it's a reparsepoint (symbolic link or junction) - // Porting note: these need to be handled specially - bool isReparsePoint = InternalSymbolicLinkLinkCodeMethods.IsReparsePoint(fileInfo); - bool isHardLink = InternalSymbolicLinkLinkCodeMethods.IsHardLink(fileInfo); - mode[5] = isReparsePoint || isHardLink ? 'l' : '-'; + /// + /// Provides a NameString property for FileSystemInfo. + /// + /// Instance of PSObject wrapping a FileSystemInfo. + /// Name if a file or directory, Name -> Target if symlink. + public static string NameString(PSObject instance) + { + return instance?.BaseObject is FileSystemInfo fileInfo + ? InternalSymbolicLinkLinkCodeMethods.IsReparsePoint(fileInfo) + ? $"{fileInfo.Name} -> {InternalSymbolicLinkLinkCodeMethods.GetTarget(instance)}" + : fileInfo.Name + : string.Empty; + } - return new string(mode); + /// + /// Provides a LengthString property for FileSystemInfo. + /// + /// Instance of PSObject wrapping a FileSystemInfo. + /// Length as a string. + public static string LengthString(PSObject instance) + { + return instance?.BaseObject is FileInfo fileInfo + ? fileInfo.Attributes.HasFlag(FileAttributes.Offline) + ? $"({fileInfo.Length})" + : fileInfo.Length.ToString() + : string.Empty; + } + + /// + /// Provides a LastWriteTimeString property for FileSystemInfo. + /// + /// Instance of PSObject wrapping a FileSystemInfo. + /// LastWriteTime formatted as short date + short time. + public static string LastWriteTimeString(PSObject instance) + { + return instance?.BaseObject is FileSystemInfo fileInfo + ? string.Format(CultureInfo.CurrentCulture, "{0,10:d} {0,8:t}", fileInfo.LastWriteTime) + : string.Empty; } #region RenameItem @@ -2481,8 +2547,8 @@ namespace Microsoft.PowerShell.Commands flags |= NativeMethods.SymbolicLinkFlags.AllowUnprivilegedCreate; } - int created = NativeMethods.CreateSymbolicLink(path, strTargetPath, flags); - return (created == 1) ? true : false; + var created = NativeMethods.CreateSymbolicLink(path, strTargetPath, flags); + return created; } private static bool WinCreateHardLink(string path, string strTargetPath) @@ -7013,7 +7079,8 @@ namespace Microsoft.PowerShell.Commands /// Flag values from SymbolicLinkFlags enum. /// 1 on successful creation. [DllImport(PinvokeDllNames.CreateSymbolicLinkDllName, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern int CreateSymbolicLink(string name, string destination, SymbolicLinkFlags symbolicLinkFlags); + [return: MarshalAs(UnmanagedType.I1)] + internal static extern bool CreateSymbolicLink(string name, string destination, SymbolicLinkFlags symbolicLinkFlags); /// /// Flags used when creating a symbolic link. @@ -7034,7 +7101,7 @@ namespace Microsoft.PowerShell.Commands /// /// Allow creation of symbolic link without elevation. Requires Developer mode. /// - AllowUnprivilegedCreate = 2 + AllowUnprivilegedCreate = 2, } /// @@ -7709,7 +7776,7 @@ namespace Microsoft.PowerShell.Commands /// /// The object of FileInfo or DirectoryInfo type. /// The target of the reparse point. - public static IEnumerable GetTarget(PSObject instance) + public static string GetTarget(PSObject instance) { if (instance.BaseObject is FileSystemInfo fileSysInfo) { @@ -7718,13 +7785,11 @@ namespace Microsoft.PowerShell.Commands { string linkTarget = WinInternalGetTarget(handle); - if (linkTarget != null) - { - return (new string[] { linkTarget }); - } + return linkTarget; } +#else + return UnixInternalGetTarget(fileSysInfo.FullName); #endif - return InternalGetTarget(fileSysInfo.FullName); } return null; @@ -7743,84 +7808,23 @@ namespace Microsoft.PowerShell.Commands { return InternalGetLinkType(fileSysInfo); } - else - return null; + + return null; } - private static List InternalGetTarget(string filePath) - { - var links = new List(); #if UNIX + private static string UnixInternalGetTarget(string filePath) + { string link = Platform.NonWindowsInternalGetTarget(filePath); - if (!string.IsNullOrEmpty(link)) - { - links.Add(link); - } - else + + if (string.IsNullOrEmpty(link)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } -#elif !CORECLR // FindFirstFileName, FindNextFileName and FindClose are not available on Core Clr - UInt32 linkStringLength = 0; - var linkName = new StringBuilder(); - - // First get the length for the linkName buffer. - IntPtr fileHandle = InternalSymbolicLinkLinkCodeMethods.FindFirstFileName(filePath, 0, ref linkStringLength, linkName); - int lastError = Marshal.GetLastWin32Error(); - - // Return handle is INVALID_HANDLE_VALUE and LastError was ERROR_MORE_DATA - if ((fileHandle == (IntPtr)(-1)) && (lastError == 234)) - { - linkName = new StringBuilder((int)linkStringLength); - fileHandle = InternalSymbolicLinkLinkCodeMethods.FindFirstFileName(filePath, 0, ref linkStringLength, linkName); - lastError = Marshal.GetLastWin32Error(); - } - - if (fileHandle == (IntPtr)(-1)) - { - throw new Win32Exception(lastError); - } - - bool continueFind = false; - - try - { - do - { - StringBuilder fullName = new StringBuilder(); - fullName.Append(Path.GetPathRoot(filePath)); // hard link source and target must be on the same drive. So we can use the source for find the path root. - fullName.Append(linkName.ToString()); - FileInfo fInfo = new FileInfo(fullName.ToString()); - - // Don't add the target link to the list. - if (string.Compare(fInfo.FullName, filePath, StringComparison.OrdinalIgnoreCase) != 0) - links.Add(fInfo.FullName); - - continueFind = InternalSymbolicLinkLinkCodeMethods.FindNextFileName(fileHandle, ref linkStringLength, linkName); - - lastError = Marshal.GetLastWin32Error(); - - if (!continueFind && lastError == 234) // ERROR_MORE_DATA - { - linkName = new StringBuilder((int)linkStringLength); - continueFind = InternalSymbolicLinkLinkCodeMethods.FindNextFileName(fileHandle, ref linkStringLength, linkName); - } - - if (!continueFind && lastError != 38) // ERROR_HANDLE_EOF. No more links. - { - throw new Win32Exception(lastError); - } - } - while (continueFind); - } - finally - { - InternalSymbolicLinkLinkCodeMethods.FindClose(fileHandle); - } -#endif - return links; + return link; } +#endif private static string InternalGetLinkType(FileSystemInfo fileInfo) { @@ -7909,16 +7913,9 @@ namespace Microsoft.PowerShell.Commands internal static bool IsReparsePoint(FileSystemInfo fileInfo) { - if (Platform.IsWindows) - { - // Note that this class also has a enum called FileAttributes, so use fully qualified name - return (fileInfo.Attributes & System.IO.FileAttributes.ReparsePoint) - == System.IO.FileAttributes.ReparsePoint; - } - else - { - return Platform.NonWindowsIsSymLink(fileInfo); - } + return Platform.IsWindows + ? fileInfo.Attributes.HasFlag(System.IO.FileAttributes.ReparsePoint) + : Platform.NonWindowsIsSymLink(fileInfo); } internal static bool WinIsHardLink(FileSystemInfo fileInfo) diff --git a/test/Test.Common.props b/test/Test.Common.props index e87a213c4e..9c102ff956 100644 --- a/test/Test.Common.props +++ b/test/Test.Common.props @@ -10,5 +10,10 @@ true true + true + + + + $(DefineConstants);UNIX diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 index f785c3da50..08607469e2 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 @@ -190,3 +190,51 @@ Describe "Get-ChildItem" -Tags "CI" { } } } + +Describe 'FileSystem Provider Formatting' -Tag "CI","RequireAdminOnWindows" { + + BeforeAll { + $modeTestDir = New-Item -Path "$TestDrive/testmodedirectory" -ItemType Directory -Force + $targetFile1 = New-Item -Path "$TestDrive/targetFile1" -ItemType File -Force + $targetFile2 = New-Item -Path "$TestDrive/targetFile2" -ItemType File -Force + $targetDir1 = New-Item -Path "$TestDrive/targetDir1" -ItemType Directory -Force + $targetDir2 = New-Item -Path "$TestDrive/targetDir2" -ItemType Directory -Force + + $testcases = @( + @{ expectedMode = "d----"; expectedModeWithoutHardlink = "d----"; itemType = "Directory"; itemName = "Directory"; fileAttributes = [System.IO.FileAttributes] "Directory"; target = $null } + @{ expectedMode = "l----"; expectedModeWithoutHardlink = "l----"; itemType = "SymbolicLink"; itemName = "SymbolicLink-Directory"; fileAttributes = [System.IO.FileAttributes]::Directory -bor [System.IO.FileAttributes]::ReparsePoint; target = $targetDir2.FullName } + ) + + if ($IsWindows) + { + $testcases += @{ expectedMode = "l----"; expectedModeWithoutHardlink = "l----"; itemType = "Junction"; itemName = "Junction-Directory"; fileAttributes = [System.IO.FileAttributes]::Directory -bor [System.IO.FileAttributes]::ReparsePoint; target = $targetDir1.FullName } + $testcases += @{ expectedMode = "-a---"; expectedModeWithoutHardlink = "-a---"; itemType = "File"; itemName = "ArchiveFile"; fileAttributes = [System.IO.FileAttributes] "Archive"; target = $null } + $testcases += @{ expectedMode = "la---"; expectedModeWithoutHardlink = "la---"; itemType = "SymbolicLink"; itemName = "SymbolicLink-File"; fileAttributes = [System.IO.FileAttributes]::Archive -bor [System.IO.FileAttributes]::ReparsePoint; target = $targetFile1.FullName } + $testcases += @{ expectedMode = "la---"; expectedModeWithoutHardlink = "-a---"; itemType = "HardLink"; itemName = "HardLink"; fileAttributes = [System.IO.FileAttributes] "Archive"; target = $targetFile2.FullName } + } + } + + It 'Validate Mode property - ' -TestCases $testcases { + + param($expectedMode, $expectedModeWithoutHardlink, $itemType, $itemName, $fileAttributes, $target) + + $item = if ($target) + { + New-Item -Path $modeTestDir -Name $itemName -ItemType $itemType -Target $target + } + else + { + New-Item -Path $modeTestDir -Name $itemName -ItemType $itemType + } + + $item | Should -BeOfType "System.IO.FileSystemInfo" + + $actualMode = [Microsoft.PowerShell.Commands.FileSystemProvider]::Mode($item) + $actualMode | Should -BeExactly $expectedMode + + $actualModeWithoutHardlink = [Microsoft.PowerShell.Commands.FileSystemProvider]::ModeWithoutHardlink($item) + $actualModeWithoutHardlink | Should -BeExactly $expectedModeWithoutHardlink + + $item.Attributes | Should -Be $fileAttributes + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-FormatData.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-FormatData.Tests.ps1 index 45562a6c7c..5c50e448f1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-FormatData.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Get-FormatData.Tests.ps1 @@ -15,7 +15,7 @@ Describe "Get-FormatData" -Tags "CI" { $format.TypeNames | Should -HaveCount 2 $format.TypeNames[0] | Should -BeExactly "System.IO.DirectoryInfo" $format.TypeNames[1] | Should -BeExactly "System.IO.FileInfo" - $format.FormatViewDefinition | Should -HaveCount 3 + $format.FormatViewDefinition | Should -HaveCount 4 } It "Should return nothing for format data requiring '-PowerShellVersion 5.1' and not provided" { diff --git a/test/powershell/engine/Api/TypeInference.Tests.ps1 b/test/powershell/engine/Api/TypeInference.Tests.ps1 index fb689c028b..5cf7dae9fd 100644 --- a/test/powershell/engine/Api/TypeInference.Tests.ps1 +++ b/test/powershell/engine/Api/TypeInference.Tests.ps1 @@ -418,7 +418,7 @@ Describe "Type inference Tests" -tags "CI" { It "Infers typeof Select-Object when Parameter is ExcludeProperty" { $res = [AstTypeInference]::InferTypeOf( { [io.fileinfo]::new("file") | Select-Object -ExcludeProperty *Time*, E* }.Ast) $res.Count | Should -Be 1 - $res[0].Name | Should -Be "System.Management.Automation.PSObject#Attributes:BaseName:Directory:DirectoryName:FullName:IsReadOnly:Length:LinkType:Mode:Name:Target:VersionInfo" + $res[0].Name | Should -BeExactly "System.Management.Automation.PSObject#Attributes:BaseName:Directory:DirectoryName:FullName:IsReadOnly:Length:LengthString:LinkType:Mode:ModeWithoutHardLink:Name:NameString:Target:VersionInfo" $names = $res[0].Members.Name $names -contains "BaseName" | Should -BeTrue $names -contains "Name" | Should -BeTrue diff --git a/test/xUnit/csharp/test_FileSystemProvider.cs b/test/xUnit/csharp/test_FileSystemProvider.cs index e46171b678..f6dc81ddda 100644 --- a/test/xUnit/csharp/test_FileSystemProvider.cs +++ b/test/xUnit/csharp/test_FileSystemProvider.cs @@ -14,6 +14,8 @@ using System.Management.Automation.Internal.Host; using System.Management.Automation.Provider; using System.Management.Automation.Runspaces; using System.Reflection; +using System.Reflection.Metadata; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.PowerShell; using Microsoft.PowerShell.Commands; using Xunit; @@ -107,9 +109,9 @@ namespace PSTests.Parallel executableObject = new FileInfo(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); } - Assert.Equal("d-----", FileSystemProvider.Mode(PSObject.AsPSObject(directoryObject)).Replace("r", "-")); - Assert.Equal("------", FileSystemProvider.Mode(PSObject.AsPSObject(fileObject)).Replace("r", "-").Replace("a", "-")); - Assert.Equal("------", FileSystemProvider.Mode(PSObject.AsPSObject(executableObject)).Replace("r", "-").Replace("a", "-")); + Assert.Equal("d----", FileSystemProvider.Mode(PSObject.AsPSObject(directoryObject)).Replace("r", "-")); + Assert.Equal("-----", FileSystemProvider.Mode(PSObject.AsPSObject(fileObject)).Replace("r", "-").Replace("a", "-")); + Assert.Equal("-----", FileSystemProvider.Mode(PSObject.AsPSObject(executableObject)).Replace("r", "-").Replace("a", "-")); } [Fact] @@ -125,13 +127,8 @@ namespace PSTests.Parallel fileSystemProvider.GetProperty(testPath, new Collection(){ "IsReadOnly" }); FileInfo fileSystemObject1 = new FileInfo(testPath); PSObject psobject1 = PSObject.AsPSObject(fileSystemObject1); - foreach (PSPropertyInfo property in psobject1.Properties) - { - if (property.Name == "IsReadOnly") - { - Assert.False((bool)property.Value); - } - } + PSPropertyInfo property = psobject1.Properties["IsReadOnly"]; + Assert.False((bool)property.Value); } [Fact] @@ -144,13 +141,9 @@ namespace PSTests.Parallel fileSystemProvider.GetProperty(testPath, new Collection(){ "Name" }); FileInfo fileSystemObject1 = new FileInfo(testPath); PSObject psobject1 = PSObject.AsPSObject(fileSystemObject1); - foreach (PSPropertyInfo property in psobject1.Properties) - { - if (property.Name == "FullName") - { - Assert.Equal(testPath, property.Value); - } - } + PSPropertyInfo property = psobject1.Properties["FullName"]; + + Assert.Equal(testPath, property.Value); } [Fact]