System.Collections.Hashtable vs @{key=value} as return of the same code

Hello,

I have script which scans local network and get some informations from hosts. For this I use below code:

$results = Invoke-Command -Session $sessions -ScriptBlock {
            if (($PSVersionTable.PSVersion.Major) -ge 5) {
                $Win32_ComputerSystem = Get-CimInstance -ClassName Win32_ComputerSystem -property *
                $Win32_Processor = Get-CimInstance -ClassName Win32_Processor -property *
                $Win32_SystemEnclosure = Get-CimInstance -ClassName Win32_SystemEnclosure -property *
                $Win32_DiskDrive = Get-CimInstance -ClassName Win32_DiskDrive -property *
                [pscustomobject]@{
                    ScanDate = (Get-Date -DisplayHint Date) #Get-Date -Format {dd.MM.yyyy}
                    PhysicalHostname = ([System.Net.Dns]::GetHostByName($env:computerName)).HOSTNAME
                    Manufacturer = $Win32_ComputerSystem.Manufacturer
                    Model = $Win32_ComputerSystem.Model
                    ComputerSerialNumber = $Win32_SystemEnclosure.SerialNumber
                    ProcessorName = $Win32_Processor.Name; #Get-Ciminstance -Query 'SELECT Name FROM Win32_Processor'
                    RAM = $Win32_ComputerSystem.TotalPhysicalMemory
                    DiskDrive = $Win32_DiskDrive.Size;
                    HDDPartitions = (Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3").Size;
                    OS = (Get-CimInstance Win32_OperatingSystem -Property *).Name.Split("|") | Select-Object -First 1;
                    Annotation = ($PSVersionTable.PSVersion.Major)
                }
            }
            # Code for PowerShell with version less than 5
            else {
                $Win32_ComputerSystem = Get-WmiObject -Class Win32_ComputerSystem
                $Win32_Processor = Get-WmiObject -Class Win32_Processor
                $Win32_DiskDrive = Get-WmiObject -Class Win32_DiskDrive
                [pscustomobject]@{
                    ScanDate = (Get-Date -DisplayHint Date);
                    PhysicalHostname = ([System.Net.Dns]::GetHostByName($env:computerName)).HOSTNAME
                    Manufacturer = $Win32_ComputerSystem.Manufacturer;
                    Model = $Win32_ComputerSystem.Model;
                    ComputerSerialNumber = $NULL;
                    ProcessorName = $Win32_Processor.Name;
                    RAM = $Win32_ComputerSystem.TotalPhysicalMemory;
                    DiskDrive = $Win32_DiskDrive.Size;
                    HDDPartitions = $NULL;
                    OS = ".....some os.....";
                    Annotation = ($PSVersionTable.PSVersion.Major);
                }
            }
        }
I wrote two sections, one for PowerShell greater than than 5, and second section for older versions of PowerShell (for example ver 2 in Windows 7). This is because version older than 5 cannot use "Get-CimInstance" command.
If it's scanned computer with Win 10 and PS 5 it returns hashtable:
@{ScanDate=20.10.2020 11:55:31; PhysicalHostname=5039-lukbak-k.ad.ms.gov.pl; Manufacturer=Hewlett-Packard; Model=HP Compaq Pro 6300 SFF; ComputerSerialNumber=CZC3361LCD; ProcessorName=Intel(R) Core(TM) i3-3225 CPU @ 3.30GHz; RAM=4162904064; DiskDrive=500105249280; HDDPartitions=499429404672; OS=Microsoft Windows 10 Pro; Annotation=5; PSComputerName=some_computer_name; RunspaceId=....; PSShowComputerName=True;}
And when is scanned computer with Win 7 and PS 2 it returns object System.Collections.Hashtable.

Why is that?

Best Regadrs

Daniel

Please look at screen below:

The [PSCustomObject] type accelerator was introduced in version 3. I expect version 2 is ignoring the type declaration and just creating a hashtable.

If you pipe it to Get-Member you should find that Windows 10 is returning an object of type System.Management.Automation.PSCustomObject

For version 2, I think you’re going to have to revert to New-Object and Add-Member.

For version 2 it can be a little simpler by using the hashtable and not doing Add-Member for each property. In fact this works for newer versions of PS as well so you could move this outside of your if statement and do for all like this:

 

$ht = @{
    ScanDate = (Get-Date -DisplayHint Date);
    PhysicalHostname = ([System.Net.Dns]::GetHostByName($env:computerName)).HOSTNAME
    Manufacturer = $Win32_ComputerSystem.Manufacturer;
    Model = $Win32_ComputerSystem.Model;
    ComputerSerialNumber = $NULL;
    ProcessorName = $Win32_Processor.Name;
    RAM = $Win32_ComputerSystem.TotalPhysicalMemory;
    DiskDrive = $Win32_DiskDrive.Size;
    HDDPartitions = $NULL;
    OS = ".....some os.....";
    Annotation = ($PSVersionTable.PSVersion.Major);
}
New-Object -TypeName psobject -ArgumentList $ht