1

Running the following command line in both PowerShell ISE and VS Code on my system:

Get-ChildItem "$($env:systemdrive)\Program Files (x86)\Windows Kits\10\bin\" -Directory | Where { $_ -match "10." }

It gives out different output. On VS Code, the output will be like:

    Directory: C:\Program Files (x86)\Windows Kits\10\bin

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----           1/27/2023 12:50 PM                10.0.14393.0
d----           1/27/2023 12:50 PM                10.0.15063.0
d----           1/27/2023 12:50 PM                10.0.16299.0
d----           1/27/2023 12:50 PM                10.0.17134.0
d----           10/7/2021  4:57 PM                10.0.18362.0
d----           10/7/2021  4:54 PM                10.0.19041.0
d----           1/11/2022  5:14 PM                10.0.20348.0
d----           1/27/2023 12:50 PM                10.0.22621.0
d----           1/27/2023 12:50 PM                arm
d----           1/27/2023 12:50 PM                arm64
d----           1/27/2023 12:50 PM                x64
d----           1/27/2023 12:50 PM                x86

Yet in the ISE, the output will be like:

    Directory: C:\Program Files (x86)\Windows Kits\10\bin


Mode                LastWriteTime         Length Name                                                                                      
----                -------------         ------ ----                                                                                      
d-----        1/27/2023  12:50 PM                10.0.14393.0                                                                              
d-----        1/27/2023  12:50 PM                10.0.15063.0                                                                              
d-----        1/27/2023  12:50 PM                10.0.16299.0                                                                              
d-----        1/27/2023  12:50 PM                10.0.17134.0                                                                              
d-----        10/7/2021   4:57 PM                10.0.18362.0                                                                              
d-----        10/7/2021   4:54 PM                10.0.19041.0                                                                              
d-----        1/11/2022   5:14 PM                10.0.20348.0                                                                              
d-----        1/27/2023  12:50 PM                10.0.22621.0 

To me, this is a bug with PowerShell within VS code, or PowerShell 7, since I have the PSVersion 7.3.3 for VS code, and PSVersion 5.1.17763.3770 for ISE.

Anybody have any thought?

mklement0
  • 382,024
  • 64
  • 607
  • 775
Weishan Yang
  • 428
  • 2
  • 5
  • 15
  • 3
    This is due to a change in behavior between Windows PowerShell 5.1 (the version used by ISE) in which "stringifying" a file system object outputs its name, whereas in PowerShell 7.x (the version underpinning VSCode) this results in the full path. Run `Get-ChildItem |% { "$_" }` in both to see this. Change your code to `Where-Object { $_.Name -match ... }` in any case – Mathias R. Jessen Mar 23 '23 at 12:47
  • 3
    Reason is, with PowerShell 7, a `DirectoryInfo` instance when converted to string would resolve to its `FullName` property and your path happens to be `C:\Program Files (x86)\Windows Kits\10\bin` and `"10."` matches this pattern so every child item is listed. As opposed, `DirectoryInfo` instances when coerced to string will display their `Name` property in PowerShell 5.1. If you want accurate results in both versions you should: `| Where { $_.Name -match "10\." }` – Santiago Squarzon Mar 23 '23 at 12:47
  • As an aside: The PowerShell ISE is [no longer actively developed](https://docs.microsoft.com/en-us/powershell/scripting/components/ise/introducing-the-windows-powershell-ise#support) and [there are reasons not to use it](https://stackoverflow.com/a/57134096/45375) (bottom section), notably not being able to run PowerShell (Core) 6+. The actively developed, cross-platform editor that offers the best PowerShell development experience is [Visual Studio Code](https://code.visualstudio.com/) with its [PowerShell extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell). – mklement0 Mar 23 '23 at 13:54

1 Answers1

0

Building on the helpful comments:

tl;dr

To be safe, always:

  • refer to the name of a directory- or file-information object output by Get-ChildItem explicitly with .Name
  • similarly, to get the full (absolute) path, use .FullName

The same applies analogously to the .Parent property of a directory-info object, which is itself a directory-info object.
By contrast, to get a file-info object's parent directory's name, use .Directory.Name, and .DirectoryName for the full path.

In your case:

Get-ChildItem "$($env:systemdrive)\Program Files (x86)\Windows Kits\10\bin" -Directory | 
  Where { $_.Name -match '^10\.' } # Note the use of .Name

Note that I've changed to 10. to ^10\.: Because the -match operator uses regular expressions, you must escape a literal . character that you want matched as such as \.
Additionally, it's better to ensure that literal 10. only match at the start of a directory name, hence the use use of ^.

That said, you can simplify and speed up your command with passing a wildcard pattern to Get-ChildItem's -Filter parameter:[1]

Get-ChildItem -Filter 10.* "$($env:systemdrive)\Program Files (x86)\Windows Kits\10\bin\" -Directory

Background information

There is no bug, just a change in behavior between .NET Framework - which Windows PowerShell (the legacy edition with versions up to v5.1) is built on - and .NET (Core) 5+ - which PowerShell (Core) 7+ is built on - with respect to how System.IO.DirectoryInfo and System.IO.FileInfo instances, as output by Get-ChildItem, stringify (are coerced to strings).

  • In Windows PowerShell, they situationally stringify by their .Name property only, depending on the specifics of the Get-ChildItem command that emitted them; at other times they stringify by their .FullName property.

    • See the bottom section of this answer for the conditions under which this name-only stringification happens.
  • In PowerShell (Core) they always stringify by their .FullName property, i.e. by their full (absolute) path.


As for what you tried:

  • $_ -match '10.' causes each input directory-info object ($_) to be stringified, due to -match being a string-only operator.

  • Therefore, in PowerShell (Core) $_ became a full path, and the full paths of all your input directories match regex 10., given that . can match _any character; e.g.:

    # -> $true, because regex '10.' matches substring '10\' in the path
    'C:\...\10\bin\arm' -match '10.'  
    

[1] Note that it is the file-system's wildcard language that -Filter supports, which differs from PowerShell's wildcards in that it has fewer features and legacy quirks - see this answer for the gory details.

mklement0
  • 382,024
  • 64
  • 607
  • 775