﻿# encoding: utf-8
# api: powershell
# title: Get-ComputerAssetInforma
# description: A multi-threaded, windows asset gathering function.
# version: 6.1.7601
# type: function
# author: Zachary Loeber
# license: CC0
# function: Get-ComputerAssetInformation
# x-poshcode-id: 4367
# x-archived: 2013-09-28T03:07:37
# x-published: 2013-08-07T02:54:00
#
#
function Get-ComputerAssetInformation
{
<#
.SYNOPSIS
   Get inventory data for specified computer systems.
.DESCRIPTION
   Get inventory data for provided host using wmi. Data proccessing uses multithreading and supports using timeouts 
   in case of wmi problems. You can optionally include more detailed Drive, Memory, and Network information in the results.
   You can view verbose information on each runtime thread in realtime with the -Verbose option.
.PARAMETER ComputerName
   Specifies the target computer for data query.
.PARAMETER IncludeMemoryInfo
   Include information about the memory arrays and the installed memory within them. (_Memory and _MemoryArray)
.PARAMETER IncludeDiskInfo
   Include disk partition and mount point information. (_Disks)
.PARAMETER IncludeNetworkInfo
   Include general network configuration for enabled interfaces. (_Network)
.PARAMETER ThrottleLimit
   Specifies the maximum number of systems to inventory simultaneously 
.PARAMETER Timeout
   Specifies the maximum time in second command can run in background before terminating this thread.
.PARAMETER ShowProgress
   Show progress bar information
.PARAMETER PromptForCredential
   Prompt for remote system credential prior to processing request.
.PARAMETER Credential
   Accept alternate credential (ignored if the localhost is processed)
.EXAMPLE
   PS > Get-ComputerAssetInformation -ComputerName test1
 
        ComputerName        : TEST1
        Model               : ProLiant DL380 G7
        ChassisModel        : Rack Mount Unit
        OperatingSystem     : Microsoft Windows Server 2008 R2 Enterprise 
        OSServicePack       : 1
        OSVersion           : 6.1.7601
        OSSKU               : Enterprise Server Edition
        OSArchitecture      : x64
        SystemArchitecture  : x64
        PhysicalMemoryTotal : 12.0 GB
        PhysicalMemoryFree  : 621.7 MB
        VirtualMemoryTotal  : 24.0 GB
        VirtualMemoryFree   : 5.7 GB
        CPUCores            : 24
        CPUSockets          : 2
        SystemTime          : 08/04/2013 20:33:47
        LastBootTime        : 07/16/2013 07:42:01
        InstallDate         : 07/02/2011 17:52:34
        Uptime              : 19 days 12 hours 51 minutes
 
   Description
   -----------
   Query and display basic information ablout computer test1

.EXAMPLE
   PS > $cred = Get-Credential
   PS > $b = Get-ComputerAssetInformation -ComputerName Test1 -Credential $cred -IncludeMemoryInfo 
   PS > $b | Select MemorySlotsTotal,MemorySlotsUsed | fl

   MemorySlotsTotal : 18
   MemorySlotsUsed  : 6
   
   PS > $b._Memory | Select DeviceLocator,@{n='MemorySize'; e={$_.Capacity/1Gb}}

   DeviceLocator                                                                   MemorySize
   -------------                                                                   ----------
   PROC 1 DIMM 3A                                                                           2
   PROC 1 DIMM 6B                                                                           2
   PROC 1 DIMM 9C                                                                           2
   PROC 2 DIMM 3A                                                                           2
   PROC 2 DIMM 6B                                                                           2
   PROC 2 DIMM 9C                                                                           2
   
   Description
   -----------
   Query information about computer test1 using alternate credentials, including detailed memory information. Return
   physical memory slots available and in use. Then display the memory location and size.

.NOTES
   Originally posted at: http://learn-powershell.net/2013/05/08/scripting-games-2013-event-2-favorite-and-not-so-favorite/
   Extended and further hacked by: Zachary Loeber
   Site: http://www.the-little-things.net/
   Requires: Powershell 2.0
   Info: WMI prefered over CIM as there no speed advantage using cimsessions in multithreading against old systems. Starting
         around line 263 you can modify the WMI_<Property>Props arrays to include extra wmi data for each element should you
         require information I may have missed. You can also change the default display properties by modifying $defaultProperties.
         Keep in mind that including extra elements like the drive space and network information will increase the processing time per
         system. You may need to increase the timeout parameter accordingly.
   
   Version History
   1.1.0 - 8/3/2013
    - Added several parameters
    - Removed parameter sets in favor of arrays of custom object as note properties
    - Removed ICMP response requirements
    - Included more verbose runspace logging    
   1.0.2 - 8/2/2013
    - Split out system and OS architecture (changing how each it determined)
   1.0.1 - 8/1/2013
    - Updated to include several more bits of information and customization variables
   1.0.0 - ???
    - Discovered original script on the internet and totally was blown away at how awesome it is.
#>
    [CmdletBinding()]
    Param
    (
        [Parameter(ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [Alias('DNSHostName','PSComputerName')]
        [string[]]
        $ComputerName=$env:computername,
        
        [Parameter()]
        [switch]
        $IncludeMemoryInfo,
 
        [Parameter()]
        [switch]
        $IncludeDiskInfo,
 
        [Parameter()]
        [switch]
        $IncludeNetworkInfo,
       
        [Parameter()]
        [ValidateRange(1,65535)]
        [int32]
        $ThrottleLimit = 32,
 
        [Parameter()]
        [ValidateRange(1,65535)]
        [int32]
        $Timeout = 120,
 
        [Parameter()]
        [switch]
        $ShowProgress,
        
        [Parameter()]
        [switch]
        $PromptForCredential,
        
        [Parameter()]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty
    )

    Begin
    {
        # Gather possible local host names and IPs to prevent credential utilization in some cases
        Write-Verbose -Message 'Creating local hostname list'
        $IPAddresses = [net.dns]::GetHostAddresses($env:COMPUTERNAME) | Select-Object -ExpandProperty IpAddressToString
        $HostNames = $IPAddresses | ForEach-Object {
            try {
                [net.dns]::GetHostByAddress($_)
            } catch {
                # We do not care about errors here...
            }
        } | Select-Object -ExpandProperty HostName -Unique
        $LocalHost = @('', '.', 'localhost', $env:COMPUTERNAME, '::1', '127.0.0.1') + $IPAddresses + $HostNames
 
        Write-Verbose -Message 'Creating initial variables'
        $runspacetimers       = [HashTable]::Synchronized(@{})
        $runspaces            = New-Object -TypeName System.Collections.ArrayList
        $bgRunspaceCounter    = 0
        
        if ($PromptForCredential)
        {
            $Credential = Get-Credential
        }
        
        Write-Verbose -Message 'Creating Initial Session State'
        $iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
        foreach ($ExternalVariable in ('runspacetimers', 'Credential', 'LocalHost'))
        {
            Write-Verbose -Message "Adding variable $ExternalVariable to initial session state"
            $iss.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $ExternalVariable, (Get-Variable -Name $ExternalVariable -ValueOnly), ''))
        }
        
        Write-Verbose -Message 'Creating runspace pool'
        $rp = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspacePool(1, $ThrottleLimit, $iss, $Host)
        $rp.Open()
 
        # This is the actual code called for each computer
        Write-Verbose -Message 'Defining background runspaces scriptblock'
        $ScriptBlock = {
            [CmdletBinding()]
            Param
            (
                [Parameter(Position=0)]
                [string]
                $ComputerName,
 
                [Parameter(Position=1)]
                [int]
                $bgRunspaceID,
          
                [Parameter()]
                [switch]
                $IncludeMemoryInfo,
         
                [Parameter()]
                [switch]
                $IncludeDiskInfo,
         
                [Parameter()]
                [switch]
                $IncludeNetworkInfo
            )
            $runspacetimers.$bgRunspaceID = Get-Date
            
            try
            {
                Write-Verbose -Message ('Runspace {0}: Start' -f $ComputerName)
                $WMIHast = @{
                    ComputerName = $ComputerName
                    ErrorAction = 'Stop'
                }
                if (($LocalHost -notcontains $ComputerName) -and ($Credential -ne $null))
                {
                    $WMIHast.Credential = $Credential
                }

                #Due to some bug setting scriptblock directly as value can cause 'NullReferenceException' in v3 host
                $ReadableOutput = @{
                    Name = 'ToString'
                    MemberType = 'ScriptMethod'
                    PassThru = $true
                    Force = $true
                    Value = [ScriptBlock]::Create(@"
                        "{0:N1} {1}" -f @(
                            switch -Regex ([math]::Log(`$this,1024)) {
                                ^0 {
                                    (`$this / 1), ' B'
                                }
                                ^1 {
                                    (`$this / 1KB), 'KB'
                                }
                                ^2 {
                                    (`$this / 1MB), 'MB'
                                }
                                ^3 {
                                    (`$this / 1GB), 'GB'
                                }
                                ^4 {
                                    (`$this / 1TB), 'TB'
                                }
                                default {
                                    (`$this / 1PB), 'PB'
                                }
                            }
                        )
"@
                    )
                }
                
                #region GeneralInfo
                Write-Verbose -Message ('Runspace {0}: General asset information' -f $ComputerName)
                ## Lookup arrays
                $SKUs                 = @("Undefined","Ultimate Edition","Home Basic Edition","Home Basic Premium Edition","Enterprise Edition",`
                                          "Home Basic N Edition","Business Edition","Standard Server Edition","DatacenterServer Edition","Small Business Server Edition",`
                                          "Enterprise Server Edition","Starter Edition","Datacenter Server Core Edition","Standard Server Core Edition",`
                                          "Enterprise ServerCoreEdition","Enterprise Server Edition for Itanium-Based Systems","Business N Edition","Web Server Edition",`
                                          "Cluster Server Edition","Home Server Edition","Storage Express Server Edition","Storage Standard Server Edition",`
                                          "Storage Workgroup Server Edition","Storage Enterprise Server Edition","Server For Small Business Edition","Small Business Server Premium Edition")
                $ChassisModels        = @("PlaceHolder","Maybe Virtual Machine","Unknown","Desktop","Thin Desktop","Pizza Box","Mini Tower","Full Tower","Portable",`
                                          "Laptop","Notebook","Hand Held","Docking Station","All in One","Sub Notebook","Space-Saving","Lunch Box","Main System Chassis",`
                                          "Lunch Box","SubChassis","Bus Expansion Chassis","Peripheral Chassis","Storage Chassis" ,"Rack Mount Unit","Sealed-Case PC")
                # Modify this variable to change your default set of display properties
                $defaultProperties    = @('ComputerName','Model','ChassisModel','OperatingSystem','OSServicePack','OSVersion','OSSKU','OSArchitecture', `
                                          'SystemArchitecture','PhysicalMemoryTotal','PhysicalMemoryFree','VirtualMemoryTotal','VirtualMemoryFree', `
                                          'CPUCores','CPUSockets','SystemTime','LastBootTime','InstallDate','Uptime')
                # WMI Properties
                $WMI_OSProps          = @('BuildNumber','Version','SerialNumber','ServicePackMajorVersion','CSDVersion','SystemDrive',`
                                          'SystemDirectory','WindowsDirectory','Caption','TotalVisibleMemorySize','FreePhysicalMemory',`
                                          'TotalVirtualMemorySize','FreeVirtualMemory','OSArchitecture','Organization','LocalDateTime',`
                                          'RegisteredUser','OperatingSystemSKU','OSType','LastBootUpTime','InstallDate')
                $WMI_ProcProps        = @('Name','Description','MaxClockSpeed','CurrentClockSpeed','AddressWidth','NumberOfCores','NumberOfLogicalProcessors', `
                                          'DataWidth')
                $WMI_CompProps        = @('DNSHostName','Domain','Manufacturer','Model','NumberOfLogicalProcessors','NumberOfProcessors','PrimaryOwnerContact', `
                                          'PrimaryOwnerName','TotalPhysicalMemory')
                $WMI_ChassisProps     = @('ChassisTypes','Manufacturer','SerialNumber','Tag','SKU')
                # WMI data
                $wmi_compsystem = Get-WmiObject @WMIHast -Class Win32_ComputerSystem | select $WMI_CompProps
                $wmi_os = Get-WmiObject @WMIHast -Class Win32_OperatingSystem | select $WMI_OSProps
                $wmi_proc = Get-WmiObject @WMIHast -Class Win32_Processor | select $WMI_ProcProps
                $wmi_chassis = Get-WmiObject @WMIHast -Class Win32_SystemEnclosure | select $WMI_ChassisProps

                ## Calculated properties
                # CPU count
                if (@($wmi_proc)[0].NumberOfCores) #Modern OS
                {
                    $Sockets = @($wmi_proc).Count
                    $Cores = ($wmi_proc | Measure-Object -Property NumberOfLogicalProcessors -Sum).Sum
                }
                else #Legacy OS
                {
                    $Sockets = @($wmi_proc | Select-Object -Property SocketDesignation -Unique).Count
                    $Cores = @($wmi_proc).Count
                }
                
                # OperatingSystemSKU is not availble in 2003 and XP
                if ($wmi_os.OperatingSystemSKU -ne $null)
                {
                    $OS_SKU = $SKUs[$wmi_os.OperatingSystemSKU]
                }
                else
                {
                    $OS_SKU = 'Not Available'
                }
                $System_Time = ([wmi]'').ConvertToDateTime($wmi_os.LocalDateTime).tostring("MM/dd/yyyy HH:mm:ss")
                $OS_LastBoot = ([wmi]'').ConvertToDateTime($wmi_os.LastBootUptime).tostring("MM/dd/yyyy HH:mm:ss")
                $OS_InstallDate = ([wmi]'').ConvertToDateTime($wmi_os.InstallDate).tostring("MM/dd/yyyy HH:mm:ss")
                $Uptime = New-TimeSpan -Start $OS_LastBoot -End $System_Time                    

                $ResultProperty = @{
                    ### Defaults
                    'PSComputerName' = $ComputerName
                    'Model' = $wmi_compsystem.Model
                    'ChassisModel' = $ChassisModels[$wmi_chassis.ChassisTypes[0]]
                    'ComputerName' = $wmi_compsystem.DNSHostName                        
                    'OperatingSystem' = $wmi_os.Caption
                    'OSServicePack' = $wmi_os.ServicePackMajorVersion
                    'OSVersion' = $wmi_os.Version
                    'OSSKU' = $OS_SKU
                    'OSArchitecture' = "x$($wmi_proc.AddressWidth[0])"
                    'SystemArchitecture' = "x$($wmi_proc.DataWidth[0])"
                    'PhysicalMemoryTotal' = ($wmi_os.TotalVisibleMemorySize * 1024) | Add-Member @ReadableOutput
                    'PhysicalMemoryFree' = ($wmi_os.FreePhysicalMemory * 1024) | Add-Member @ReadableOutput
                    'VirtualMemoryTotal' = ($wmi_os.TotalVirtualMemorySize * 1024) | Add-Member @ReadableOutput
                    'VirtualMemoryFree' = ($wmi_os.FreeVirtualMemory * 1024) | Add-Member @ReadableOutput
                    'CPUCores' = $Cores
                    'CPUSockets' = $Sockets
                    'LastBootTime' = $OS_LastBoot
                    'InstallDate' = $OS_InstallDate
                    'SystemTime' = $System_Time
                    'Uptime' = "$($Uptime.days) days $($Uptime.hours) hours $($Uptime.minutes) minutes"
                    '_OS' = $wmi_os
                    '_System' = $wmi_compsystem
                    '_Processor' = $wmi_proc
                    '_Chassis' = $wmi_chassis
                }
                #endregion GeneralInfo
                
                #region Memory
                if ($IncludeMemoryInfo)
                {
                    Write-Verbose -Message ('Runspace {0}: Memory information' -f $ComputerName)
                    $WMI_MemProps = @('BankLabel','DeviceLocator','Capacity','PartNumber','Speed','Tag')
                    $WMI_MemArrayProps = @('Tag','MemoryDevices','MaxCapacity')
                    $wmi_memory = Get-WmiObject @WMIHast -Class Win32_PhysicalMemory | select $WMI_MemProps
                    $wmi_memoryarray = Get-WmiObject @WMIHast -Class Win32_PhysicalMemoryArray | select $WMI_MemArrayProps
                    
                    # Memory Calcs
                    $Memory_Slotstotal = 0
                    $Memory_SlotsUsed = (@($wmi_memory)).Count                
                    @($wmi_memoryarray) | % {$Memory_Slotstotal = $Memory_Slotstotal + $_.MemoryDevices}
                    
                    # Add to the existing property set
                    $ResultProperty.MemorySlotsTotal = $Memory_Slotstotal
                    $ResultProperty.MemorySlotsUsed = $Memory_SlotsUsed
                    $ResultProperty._MemoryArray = $wmi_memoryarray
                    $ResultProperty._Memory = $wmi_memory
                }
                #endregion Memory
                
                #region Network
                if ($IncludeNetworkInfo)
                {
                    Write-Verbose -Message ('Runspace {0}: Network information' -f $ComputerName)
                    $WMI_NetProps = @('Index','IpAddress','IpSubnet','MACAddress','DefaultIPGateway','Description', `
                                      'IPEnabled','InterfaceIndex','DHCPEnabled','DHCPServer', `
                                      'DNSDomain','DNSDomainSuffixSearchOrder','DomainDNSRegistrationEnabled ', `
                                      'WinsPrimaryServer', 'WinsSecondaryServer')
                    $wmi_net = Get-WmiObject @WMIHast -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled='True'" | `
                               select $WMI_NetProps
                    $ResultProperty._Network = $wmi_net
                }                    
                #endregion Network
                
                #region Disk
                if ($IncludeDiskInfo)
                {
                    Write-Verbose -Message ('Runspace {0}: Disk information' -f $ComputerName)
                    $WMI_DiskPartProps    = @('DiskIndex','Index','Name','DriveLetter','Caption','Capacity','FreeSpace','SerialNumber')
                    $WMI_DiskVolProps     = @('Name','DriveLetter','Caption','Capacity','FreeSpace','SerialNumber')
                    $WMI_DiskMountProps   = @('Name','Label','Caption','Capacity','FreeSpace','Compressed','PageFilePresent','SerialNumber')
                    
                    # WMI data
                    $wmi_diskdrives = Get-WmiObject @WMIHast -Class Win32_DiskDrive | select $WMI_DiskDriveProps
                    #$wmi_diskvolumes = Get-WmiObject @WMIHast -Class Win32_Volume -Filter "DriveLetter IS NOT NULL" | select $WMI_DiskVolProps
                    $wmi_mountpoints = Get-WmiObject @WMIHast -Class Win32_Volume -Filter "DriveType=3 AND DriveLetter IS NULL" | select $WMI_DiskMountProps
                    
                    $AllDisks = @()
                    foreach ($diskdrive in $wmi_diskdrives) 
                    {
                        $partitionquery = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID=`"$($diskdrive.DeviceID.replace('\','\\'))`"} WHERE AssocClass = Win32_DiskDriveToDiskPartition"
                        $partitions = @(Get-WmiObject @WMIHast -Query $partitionquery)
                        foreach ($partition in $partitions)
                        {
                            $logicaldiskquery = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=`"$($partition.DeviceID)`"} WHERE AssocClass = Win32_LogicalDiskToPartition"
                            $logicaldisks = @(Get-WmiObject @WMIHast -Query $logicaldiskquery)
                            foreach ($logicaldisk in $logicaldisks)
                            {
                               $diskprops = @{
                                               Disk = $diskdrive.Name
                                               Model = $diskdrive.Model
                                               Partition = $partition.Name
                                               Description = $partition.Description
                                               PrimaryPartition = $partition.PrimaryPartition
                                               VolumeName = $logicaldisk.VolumeName
                                               Drive = $logicaldisk.Name
                                               DiskSize = $logicaldisk.Size | Add-Member @ReadableOutput
                                               FreeSpace = $logicaldisk.FreeSpace | Add-Member @ReadableOutput
                                               PercentageFree = [math]::round((($logicaldisk.FreeSpace/$logicaldisk.Size)*100), 2)
                                               DiskType = 'Partition'
                                               SerialNumber = $diskdrive.SerialNumber
                                             }
                                $AllDisks += New-Object psobject -Property $diskprops
                            }
                        }
                    }
                    # Mount points are wierd so we do them seperate.
                    foreach ($mountpoint in $wmi_mountpoints)
                    {                    
                        $diskprops = @{
                               Disk = $mountpoint.Name
                               Model = ''
                               Partition = ''
                               Description = $mountpoint.Caption
                               PrimaryPartition = ''
                               VolumeName = ''
                               VolumeSerialNumber = ''
                               Drive = [Regex]::Match($mountpoint.Caption, "^.:\\").Value
                               DiskSize = $mountpoint.Capacity  | Add-Member @ReadableOutput
                               FreeSpace = $mountpoint.FreeSpace  | Add-Member @ReadableOutput
                               PercentageFree = [math]::round((($mountpoint.FreeSpace/$mountpoint.Capacity)*100), 2)
                               DiskType = 'MountPoint'
                               SerialNumber = $mountpoint.SerialNumber
                             }
                        $AllDisks += New-Object psobject -Property $diskprops
                    }
                    $ResultProperty._Disks = $AllDisks
                }
                #endregion Disk
                
                # Final output
                $ResultObject = New-Object -TypeName PSObject -Property $ResultProperty

                # Setup the default properties for output
                $ResultObject.PSObject.TypeNames.Insert(0,'My.Asset.Info')
                $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(�DefaultDisplayPropertySet�,[string[]]$defaultProperties)
                $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
                $ResultObject | Add-Member MemberSet PSStandardMembers $PSStandardMembers

                Write-Output -InputObject $ResultObject
            }
            catch
            {
                Write-Warning -Message ('{0}: {1}' -f $ComputerName, $_.Exception.Message)
            }
            Write-Verbose -Message ('Runspace {0}: End' -f $ComputerName)
        }
 
        function Get-Result
        {
            [CmdletBinding()]
            Param 
            (
                [switch]$Wait
            )
            do
            {
                $More = $false
                foreach ($runspace in $runspaces)
                {
                    $StartTime = $runspacetimers.($runspace.ID)
                    if ($runspace.Handle.isCompleted)
                    {
                        Write-Verbose -Message ('Thread done for {0}' -f $runspace.IObject)
                        $runspace.PowerShell.EndInvoke($runspace.Handle)
                        $runspace.PowerShell.Dispose()
                        $runspace.PowerShell = $null
                        $runspace.Handle = $null
                    }
                    elseif ($runspace.Handle -ne $null)
                    {
                        $More = $true
                    }
                    if ($Timeout -and $StartTime)
                    {
                        if ((New-TimeSpan -Start $StartTime).TotalSeconds -ge $Timeout -and $runspace.PowerShell)
                        {
                            Write-Warning -Message ('Timeout {0}' -f $runspace.IObject)
                            $runspace.PowerShell.Dispose()
                            $runspace.PowerShell = $null
                            $runspace.Handle = $null
                        }
                    }
                }
                if ($More -and $PSBoundParameters['Wait'])
                {
                    Start-Sleep -Milliseconds 100
                }
                foreach ($threat in $runspaces.Clone())
                {
                    if ( -not $threat.handle)
                    {
                        Write-Verbose -Message ('Removing {0} from runspaces' -f $threat.IObject)
                        $runspaces.Remove($threat)
                    }
                }
                if ($ShowProgress)
                {
                    $ProgressSplatting = @{
                        Activity = 'Getting asset info'
                        Status = '{0} of {1} total threads done' -f ($bgRunspaceCounter - $runspaces.Count), $bgRunspaceCounter
                        PercentComplete = ($bgRunspaceCounter - $runspaces.Count) / $bgRunspaceCounter * 100
                    }
                    Write-Progress @ProgressSplatting
                }
            }
            while ($More -and $PSBoundParameters['Wait'])
        }
    }
    Process
    {
        foreach ($Computer in $ComputerName)
        {
            $bgRunspaceCounter++
            #$psCMD = [System.Management.Automation.PowerShell]::Create().AddScript($ScriptBlock).AddParameter('bgRunspaceID',$bgRunspaceCounter).AddParameter('ComputerName',$Computer).AddParameter('IncludeMemoryInfo',$IncludeMemoryInfo).AddParameter('IncludeDiskInfo',$IncludeDiskInfo).AddParameter('IncludeNetworkInfo',$IncludeNetworkInfo).AddParameter('Verbose',$Verbose)
            $psCMD = [System.Management.Automation.PowerShell]::Create().AddScript($ScriptBlock)
            $null = $psCMD.AddParameter('bgRunspaceID',$bgRunspaceCounter)
            $null = $psCMD.AddParameter('ComputerName',$Computer)
            $null = $psCMD.AddParameter('IncludeMemoryInfo',$IncludeMemoryInfo)
            $null = $psCMD.AddParameter('IncludeDiskInfo',$IncludeDiskInfo)
            $null = $psCMD.AddParameter('IncludeNetworkInfo',$IncludeNetworkInfo)
            $null = $psCMD.AddParameter('Verbose',$VerbosePreference)               # Passthrough the hidden verbose option so write-verbose works within the runspaces
            $psCMD.RunspacePool = $rp
 
            Write-Verbose -Message ('Starting {0}' -f $Computer)
            [void]$runspaces.Add(@{
                Handle = $psCMD.BeginInvoke()
                PowerShell = $psCMD
                IObject = $Computer
                ID = $bgRunspaceCounter
                })
           Get-Result
        }
    }
 
    End
    {
        Get-Result -Wait
        if ($ShowProgress)
        {
            Write-Progress -Activity 'Getting asset info' -Status 'Done' -Completed
        }
        Write-Verbose -Message "Closing runspace pool"
        $rp.Close()
        $rp.Dispose()
    }
}
