I obtain a list of files and then attempt to show them. I only want the name and date to be displayed. I got it to work but realized that in order to align well, I'd like the data to go first and then the name. I don't want to align by putting those in separate columns. I definitely don't want to add logic controlling the number of spaces between name and time.
To my surprise, the two printouts work differently: first one as expected, second one all empty.
$list = Get-ChildItem "."
$list `
| Sort-Object CreationTime `
| Select-Object @{Name=" "; Expression={$_.BaseName + " " + $_.CreationTime}}
$list `
| Sort-Object CreationTime `
| Select-Object @{Name=" "; Expression={$_.CreationTime + " " + $_.BaseName}}
How can I explain this discrepancy?
I obtain a list of files and then attempt to show them. I only want the name and date to be displayed. I got it to work but realized that in order to align well, I'd like the data to go first and then the name. I don't want to align by putting those in separate columns. I definitely don't want to add logic controlling the number of spaces between name and time.
To my surprise, the two printouts work differently: first one as expected, second one all empty.
$list = Get-ChildItem "."
$list `
| Sort-Object CreationTime `
| Select-Object @{Name=" "; Expression={$_.BaseName + " " + $_.CreationTime}}
$list `
| Sort-Object CreationTime `
| Select-Object @{Name=" "; Expression={$_.CreationTime + " " + $_.BaseName}}
How can I explain this discrepancy?
Share Improve this question asked Mar 13 at 12:23 Konrad VilterstenKonrad Viltersten 39.5k88 gold badges290 silver badges511 bronze badges2 Answers
Reset to default 2Column Order
You can use Format-Table
to order the columns with aligned padding:
PS> $list `
| Sort-Object CreationTime `
| Format-Table CreationTime, BaseName
CreationTime BaseName
------------ --------
05/12/2024 09:54:42 Videos
05/12/2024 09:54:42 Saved Games
05/12/2024 09:54:42 OneDrive
05/12/2024 09:54:42 Documents
05/12/2024 09:54:42 Music
05/12/2024 09:54:42 Links
05/12/2024 09:54:42 Favorites
...
And if you don't want the column headers you can add -HideTableHeaders
:
PS> $list `
| Sort-Object CreationTime `
| Format-Table CreationTime, BaseName -HideTableHeaders
05/12/2024 09:54:42 Videos
05/12/2024 09:54:42 Saved Games
05/12/2024 09:54:42 OneDrive
05/12/2024 09:54:42 Documents
05/12/2024 09:54:42 Music
05/12/2024 09:54:42 Links
05/12/2024 09:54:42 Favorites
...
If you specifically want to capture that output into a string (to write to a logfile for example) you can pipe it into Out-String
:
PS> $text = $list `
| Sort-Object CreationTime `
| Format-Table CreationTime, BaseName `
| Out-String
PS> $text
CreationTime BaseName
------------ --------
05/12/2024 09:54:42 Videos
05/12/2024 09:54:42 Saved Games
05/12/2024 09:54:42 OneDrive
05/12/2024 09:54:42 Documents
05/12/2024 09:54:42 Music
05/12/2024 09:54:42 Links
05/12/2024 09:54:42 Favorites
...
Blank Values
You're seeing blank values in your second sample because of this:
PS> "aaa" + [datetime]::Now
aaa03/13/2025 12:32:57
PS> > [datetime]::Now + "aaa"
MethodException: Cannot convert argument "1", with value: "aaa",
for "op_Addition" to type "System.TimeSpan": "Cannot convert value "aaa" to type
"System.TimeSpan". Error: "String 'aaa' was not recognized as a valid TimeSpan.""
Basically, you can add a [string]
and a [DateTime]
together because PowerShell uses the left-hand side's (i.e. [string]
's) op_addition
operator and tries to convert the [DateTime]
to a type supported by that before it performs the addition, so it converts the [DateTime]
to a string first.
However, when you try to add a [DateTime]
and a [string]
PowerShell uses [DateTime]
's op_addition
operator and tries to convert the string
to a type supported by that, but there's no conversion available so an exception gets thrown instead.
That exception means no result is returned from the Expression={$_.BaseName + " " + $_.CreationTime}
so no value is shown for that item in your output.
If you're wedded to the Select-Object
approach you can convert the date to a string yourself before the addition:
$list `
| Sort-Object CreationTime `
| Select-Object @{Name=" "; Expression={$_.CreationTime.ToString() + " " + $_.BaseName}}
-
05/12/2024 09:54:42 Videos
05/12/2024 09:54:42 Saved Games
05/12/2024 09:54:42 OneDrive
05/12/2024 09:54:42 Documents
05/12/2024 09:54:42 Music
05/12/2024 09:54:42 Links
05/12/2024 09:54:42 Favorites
You're trying to add a string to a datetime. Normally there'd be an error message, but it seems to be suppressed, even in powershell 7. "Cannot convert string to timespan."
get-childitem | foreach-object {$_.creationtime + $_.basename}
Cannot convert argument "1", with value: "foo", for "op_Addition" to type
"System.TimeSpan": "Cannot convert value "foo" to type "System.TimeSpan". Error:
"String was not recognized as a valid TimeSpan.""
At line:1 char:10
+ dir | % {$_.creationtime + $_.basename}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Converting the date to string. You can continue a line with a pipe or a plus. It still prints the dividing line between the header and the rest.
$list |
Sort-Object CreationTime |
Select-Object @{Name=" "; Expression={$_.CreationTime.tostring() + " " +
$_.BaseName}}
-
2/11/2025 11:55:26 AM script
2/11/2025 11:55:26 AM script
3/12/2025 10:05:55 AM foo
3/12/2025 10:06:00 AM foo2
I would do (yes with the "~" emacs is my editor):
dir | sort creationtime | select creationtime,name
CreationTime Name
------------ ----
2/11/2025 11:55:26 AM script.ps1
2/11/2025 11:55:26 AM script.ps1~
3/12/2025 10:05:55 AM foo
3/12/2025 10:06:00 AM foo2