1

I'm trying to create a report file which lists all files in my Git repository with these columns:

  • Name
  • Size
  • Last Modified
  • Git Commit

The first 3 are no problem:

gci -File -Recurse | Select-Object -Property @{
 label = 'Size(KB)'
 expr = { [string]::Format("{0:0.00}", $_.Length/1KB) }
}, LastWriteTime, FullName

However, retrieving the git commit requires running Git, a native command.

I've tried, among others:

gci -File -Recurse | Select-Object -Property @{
 label = 'Git commit'
  expr = { Invoke-Expression "git log -1 --format:format=`"%s`" -- $($_.FullName)" }
},
@{
 label = 'Size(KB)'
 expr = { [string]::Format("{0:0.00}", $_.Length/1KB) }
}, LastWriteTime, FullName

But it just gets stuck.

Does anyone know how to do this??

P.S. All the flags and options to Git doesn't matter for the manner of sake, I just copied what I already did.

YoavKlein
  • 2,005
  • 9
  • 38
  • Generally speaking: [`Invoke-Expression` should generally be avoided](https://stackoverflow.com/a/51252636/45375); definitely [don't use it to invoke an external program or PowerShell script](https://stackoverflow.com/a/57966347/45375). – mklement0 Apr 27 '21 at 12:56
  • 1
    Option `--format:format="%s"` doesn't look right; it should be `--format=format:"%s"`. (PowerShell will strip the `"`, but that shouldn't make a difference.) Therefore, does it work if you replace the `Invoke-Expression` command with the following? `git log -1 --format=format:"%s" -- $_.FullName` – mklement0 Apr 27 '21 at 13:11
  • It's now implied by the answer that you've accepted, but let me spell it out: the `git` options made all the difference, because the syntactically invalid `git` command then produces only _stderr_ output, which in the context of calculated properties is _quietly discarded_, so you'll end up with an empty `Git commit` output column. See my answer for details. – mklement0 Apr 27 '21 at 13:51

2 Answers2

4

As @mklement0 suggested in the comments, the issue was just that your formatting for the --format command was off just enough to cause a problem.

You had:

 --format:format="%s"  # won't work
 --format=format:"%s"  # works

So to fix it, we just swap in the right format, giving us this command with the output below.

gci -File | Select-Object -Property @{
 label = 'Git commit'
  expr = { Invoke-Expression "git log -1 --format=format:`"%s`" $($_.Name)" }
},
@{
 label = 'Size(KB)'
 expr = { [string]::Format("{0:0.00}", $_.Length/1KB) }
}, LastWriteTime, FullName

Git commit             Size(KB) LastWriteTime         FullName                        
----------             -------- -------------         --------                        
applied gitingore      6.07     5/11/2020 11:22:06 AM C:\git\ClientFaux\.gitignore    
cleanin up layout      1.40     10/9/2020 3:20:33 PM  C:\git\ClientFaux\ClientFaux.sln
Create LICENSE (#25)   34.98    7/13/2020 9:55:00 AM  C:\git\ClientFaux\LICENSE       
Update README.md (#27) 3.37     7/13/2020 9:55:00 AM  C:\git\ClientFaux\README.md     
                       31.13    7/13/2020 9:55:27 AM  C:\git\ClientFaux\UpgradeLog.htm
mklement0
  • 382,024
  • 64
  • 607
  • 775
FoxDeploy
  • 12,569
  • 2
  • 33
  • 48
2

FoxDeploy's helpful answer contains the crucial pointer, but let me offer a (corrected) PowerShell-idiomatic reformulation of your code.

Get-ChildItem -File -Recurse | Select-Object -Property @{
    label = 'Git commit'
    expr = { git log -1 --format=format:%s -- $_.FullName }
  },
  @{
    label = 'Size(KB)'
    expr = { '{0:0.00}' -f ($_.Length/1KB) }
  }, LastWriteTime, FullName

Note:


Calling native executables in calculated properties:

Generally, note that there's nothing fundamentally special about calling native executables from the expression script block ({ ... }) of a calculated property.

Specifically, the following considerations apply:

  • In PowerShell, stdout output from native executables is invariably converted to text ([string] instances). If the output comprises multiple lines, the property values becomes a (regular [object[]]) array containing strings.

    • If the native executable produces no stdout output, the value of the property is "nothing", i.e. the so-called "Automation Null" value ([System.Management.Automation.Internal.AutomationNull]::Value) that in most context behaves like $null.
  • Any stderr output from the native executable is quietly discarded. (Analogously, errors from PowerShell commands or expressions in expression script blocks are quietly ignored.)

Therefore, in order to troubleshoot an expression script block, execute it stand-alone, via a ForEach-Object command (whose built-in alias is %), so as to surface any errors; e.g.:

# Uses broken `git` syntax; note the resulting error message.
PS> (Get-ChildItem -File)[0] | % { git log -1 --format:format=%s -- $_.FullName } 
fatal: unrecognized argument: --format:format=%s

As for what you tried:

Because your git command was syntactically incorrect, git only produced stderr output, which PowerShell then ignored, as explained above.

Thus, your Git commit properties ended up containing "nothing", which simply renders blank in output formatting.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    Great answer! This part especially `Therefore, in order to troubleshoot an expression script block, execute it stand-alone, via a ForEach-Object command (whose built-in alias is %), so as to surface any errors; e.g.: ` – FoxDeploy Apr 27 '21 at 16:59