Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a class with dynamic property names in powershell

Tags:

powershell

I need to be able to have a class in powershell where I can create the names of the properties of that class dynamically. For example,

$binFiles = Get-ChildItem $files -Include *.BIN -recurse
$binFiles.Name

This would print something like:

File1.BIN

ThisFile.BIN

...

FileOther.BIN

I want these file names to be the names of the properties in my class that I will create multiple times. Is this even possible?

Class myItem {
    [String]$"File1.BIN"
    [String]$"ThisFile.BIN"
    ....
    [String]$"FileOther.BIN"
}
like image 647
HeedfulCrayon Avatar asked Mar 05 '18 18:03

HeedfulCrayon


1 Answers

You can use Invoke-Expression (the solution is PSv5+, due to using custom PS classes):

Invoke-Expression @"
Class myItem {
  $((Get-ChildItem $files -Include *.BIN -recurse).ForEach({"[string] `${$($_.Name)}`n "}))
}
"@

Note: While this particular use of Invoke-Expression is safe, because you fully control the string being evaluated, Invoke-Expression should generally be avoided.

The here-string produces the class definition as a string, which Invoke-Expression then evaluates, which defines class [myItem] for later use (e.g., $instance = [myItem]::new()).

Note:

  • The class definition statically creates properties based on the files present at the time you call Invoke-Expression.
  • Extending a class dynamically isn't directly supported[1], but you can recreate the class later based on the then-current set of files, simply by repeating the Invoke-Expression call.[2]

The here-string produced above looks something like this - note the need to enclose the property names in {...}, because they contain .:

Class myItem {
  
  [string] ${File1.Bin}
  [string] ${File2.Bin}
  # ...
 
}

[1] A class is immutable once defined, although you could add properties dynamically to its instances using PowerShell's ETS (extended type system), typically via the Add-Member cmdlet.
Adding instance properties on demand would enable TheMadTechnician's suggestion of alternatively defining the class without properties and only an (instance) method that populates / updates a given instance's properties on demand.

[2] Technically, the recreated class is a distinct .NET type, though that typically won't matter, given that referring to it via a type literal - [myItem] in this case - works the same.

like image 161
mklement0 Avatar answered Sep 27 '22 23:09

mklement0