Search code examples
powershellcollectionsinitializationcustom-objectpowershell-5.1

How to initialise a custom object list in Powershell 5.1?


What I want to achieve:
Create a list of files, show their name and version and sort alphabetically.

My attempt:

class File_Information
{
    [ValidateNotNullOrEmpty()][string]$Name
    [ValidateNotNullOrEmpty()][string]$FileVersion
}

$FileList = New-Object System.Collections.Generic.List[File_Information]

foreach ($file in Get-Item("*.dll")){
  $C = [File_Information]@{
    Name = $file.Name
    FileVersion = $file.VersionInfo.FileVersion
  }
  $FileList = $FileList.Add($C)
}

foreach ($file in Get-Item("*.exe")){
  $C = [File_Information]@{
    Name = $file.Name
    FileVersion = $file.VersionInfo.FileVersion
  }
  $FileList = $FileList.Add($C)
}

Write-Output $FileList | Sort-Object -Property "Name" | Format-Table

My Powershell version:

Prompt> Get-Host | Select-Object Version
Version       
-------       
5.1.19041.1320

My problems and/or questions (first is the major question, second and third are optional):

  • I don't know how to initialise a list of custom objects (I've been looking on the site, but this question only gives the possibility to initialise with an existing value, while I want to initialise to an empty list).
    The error I receive is:

      You cannot call a method on a null-valued expression.
      At line:... char:...
      +   $FileList = $FileList.Add($C)
      +   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
          + FullyQualifiedErrorId : InvokeMethodOnNull
    
  • Currently I ask for the same thing twice: I have tried Get-Item(*.dll,*.exe), Get-Item(*.dll;*.exe) and Get-Item(*.dll|*.exe) but none of them worked.
    Is it even possible to search for different patterns?

  • Until now I am struggling just to get Write-Output $FileList working. Are the other two commands (Sort-Object -Property "Name", Format-Table) correct?


Solution

  • Why use a class and a List object for that at all? You can just use Select-Object on the files of interest you gather using Get-ChildItem and output the needed properties there:

    # capture the resulting objects in a variable $result
    $result = Get-ChildItem -Path 'X:\path\to\the\files' -File -Include '*.dll','*.exe' -Recurse |
              Select-Object Name, @{Name = 'FileVersion'; Expression = {$_.VersionInfo.FileVersion}}
    
    # output on screen
    $result | Sort-Object Name | Format-Table -AutoSize
    

    To use two different name patterns on Get-ChildItem, you need to also add switch -Recurse, or append \* to the path.
    If you do not want recursion, you will need to add a Where-Object clause like:

    $result = Get-ChildItem -Path 'X:\path with spaces' | Where-Object {$_.Extension -match '\.(dll|exe)'} |
              Select-Object Name, @{Name = 'FileVersion'; Expression = {$_.VersionInfo.FileVersion}}