Server Inventory

I’ve been tasked with creating a server inventory script. I’ve been working on this for a while, and am close to the finish line, but I’m stumbling to get across it. I need to get ClusterName, HostName, VMName, Prod/Dev, Windows Edition, Windows Version, total Physical Processors, total Physical Cores and total Virtual Cores. I have the bulk of this, but I am struggling on where to create the PSCustomObject and add-members to it. Here’s my code:

‘’’

Script-ServerInventory.ps1

$InfoObject = New-Object PSObject
$VMs = Get-VM *
foreach ($vm in $vms){
# ClusterName
$Cluster = (Get-Cluster -VM $VM).Name

    # Host Server name
    $VMHost = (Get-VMHost -VM $VM).Name

    # VMName
    $servername = $vm.name

    # Server Role (Physical, Virtual, Host)

    # Prod/Dev
        if ($servername -like "p*"){
            $servertype = 'Prod'
        }elseif($servername -like "r*"){
            $servertype = 'Prod'
        }else{
            $servertype = 'Dev'
        }

    # HA on Y/N

    # Edition (Std, Ent, Datacenter)
    $WindowsEdition = Invoke-Command -ComputerName $vm -ScriptBlock {(Get-WindowsEdition -Online).Edition}

    # Version
    $WindowsVersion = $VM.Guest.OSFullName

    # Physical Processors, Physical Cores, Virtual Cores
    $ErrorActionPreference = 'SilentlyContinue'
    $Error.Clear()
    $ProcessorConfig = Get-WmiObject -class Win32_Processor -computername $servername -namespace root\CIMV2 | Select PSComputerName, Name, NumberOfCores, NumberOfLogicalProcessors
    If ($Error.Count -gt 0)
    {
    $ProcessorConfig = New-Object psobject
    $ProcessorConfig | Add-Member -type NoteProperty -name ComputerName ('$Computer-failed to connect')
    $ProcessorConfig | Add-Member -type NoteProperty -name Name -value 'Unable to get ProcessorInfo'
    $ProcessorConfig | Add-Member -type NoteProperty -name NumberOfCores -value $null
    $ProcessorConfig | Add-Member -type NoteProperty -name NumberOfLogicalProcessors -value $null
    Write-Debug Failed to connect to $servername;
    }
    $ErrorActionPreference = 'Continue'
    $ProcessorConfig | FT * -AutoSize

    $PhysicalProcessors = $ProcessorConfig.Name
    $PhysicalCores = $ProcessorConfig.NumberOfCores
    $VirtualCores = $ProcessorConfig.NumberOfLogicalProcessors

    Add-Member -InputObject $InfoObject -MemberType NoteProperty -Name "Cluster" -Value $Cluster
    Add-Member -InputObject $InfoObject -MemberType NoteProperty -Name "ServerName" -Value $servername
    Add-Member -InputObject $InfoObject -MemberType NoteProperty -Name "Host" -Value -Force $VMHost
    Add-Member -InputObject $InfoObject -MemberType NoteProperty -Name "Environment" -Value -Force $servertype
    Add-Member -InputObject $InfoObject -MemberType NoteProperty -Name "Edition" -Value -Force $WindowsEdition
    Add-Member -InputObject $InfoObject -MemberType NoteProperty -Name "Version" -Value -Force $WindowsVersion
    Add-Member -InputObject $InfoObject -MemberType NoteProperty -Name "PhysicalProcessors" -Value -Force $PhysicalProcessors.Count
    Add-Member -InputObject $InfoObject -MemberType NoteProperty -Name "PhysicalCores" -Value -Force $PhysicalCores.Count
    Add-Member -InputObject $InfoObject -MemberType NoteProperty -Name "VirtualCores" -Value -Force $VirtualCores.Count

    $InfoObject
    } $InfoObject | Export-Csv -Path C:\temp\VMInventory.csv -Append -NoTypeInformation -Verbose

‘’’

I’m trying to get as much information from Get-VM as I can here due to the fact that we have several domains that these VMs are connected to. I keep getting "Missing an argument for -Value. Specify a parameter of type ‘System.Object’ and try again. "

Any guidance would be appreciated.

jackfalveyiv,
Welcome back to the forum. :wave:t4:

Why don’t you make your life easier and use the work others already did and shared it with the world? You don’t have to re-invent the wheel again and again. There are more than enough examples for something like this out there. :wink:

For example here:

4sysops.com/archives/how-to-build-a-powershell-inventory-script-for-windows-servers/

Here’s a function I wrote years ago for a customer. You may use a few lines as inspiration. It works locally and remote.

function Get-WMIPCInfo {
    [CmdletBinding()]
    param(
        $ComputerName = $ENV:ComputerName
    )
    if (Test-Connection $ComputerName -Quiet -Count 1) {
        Write-Debug -Message "$ComputerName reachable"
        $so = New-CimSessionOption -Protocol DCOM 
        $WMIData = New-CimSession -CN $ComputerName -SessionOption $so
        $BIOS = Get-CimInstance -Class CIM_BIOSElement -CimSession $WMIData | Select-Object -Property *
        $OS = Get-CimInstance -Class CIM_OperatingSystem -CimSession $WMIData | Select-Object -Property *
        $ServiceBranch = (([wmiclass]"\\$($ComputerName)\root\default:stdRegProv").GetStringValue(2147483650, 'SOFTWARE\Microsoft\Windows NT\CurrentVersion', 'ReleaseID')).svalue
        $DISK = Get-CimInstance -Class CIM_LogicalDisk -CimSession $WMIData | Where-Object { $_.DeviceID -eq "C:" } | Select-Object -Property *
        $Computer = Get-CimInstance -Class CIM_ComputerSystem -CimSession $WMIData | Select-Object -Property *
        $IPConfig = Get-CimInstance -Class Win32_NetworkAdapterConfiguration -CimSession $WMIData | Where-Object { $_.DefaultIPGateway -match "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}" }  | Select-Object -Property *
        $UserQuery = ( C:\Windows\System32\quser.exe /server:$ComputerName 2> null)
        if ($UserQuery) {
            $UserQuery[1].Trim() -match "^(\S+)\s+.*((\d{2}\.){2}\d{4}\s+\d{2}:\d{2})" | Out-Null
            $LoggedOnUser = $Matches[1]
            $LogonTime = Get-Date -Date $Matches[2]
        }
        Remove-CimSession $WMIData
        Write-Debug -Message "`$BIOS: $BIOS"
        Write-Debug -Message "`$OS:  $OS"
        Write-Debug -Message "`$DISK:  $DISK"
        Write-Debug -Message "`$Computer:  $Computer"
        Write-Debug -Message "`$IPConfig:  $IPConfig"
        Write-Debug -Message "`$LoggedOnUser:  $LoggedOnUser"
        $CIMOutput = [PSCustomObject]@{
            ComputerName   = $BIOS.PSComputerName;
            Model          = $Computer.Model;
            BIOSName       = $BIOS.Name;
            SMBIOSVersion  = $BIOS.SMBIOSBIOSVersion;
            BIOSVersion    = $BIOS.BIOSVersion;
            ReleaseDate    = $BIOS.ReleaseDate;
            SerialNumber   = $BIOS.SerialNumber;
            OSCaption      = $OS.Caption;
            OSVersion      = $OS.Version;
            ServiceBranch  = $ServiceBranch;
            InstallDate    = $OS.InstallDate;
            LastBootUpTime = $OS.LastBootUpTime;
            PhysicalRAM    = [math]::round((($Computer.TotalPhysicalMemory) / 1GB), 2);
            DiskSize       = [math]::round(($DISK.Size / 1GB), 2);
            DiskFreeSpace  = [math]::round(($DISK.FreeSpace / 1GB), 2);
            IPV4Address    = $IPConfig.IPAddress[0];
            DefaultGateway = $IPConfig.DefaultIPGateway[0];
            DNSDomain      = $IPConfig.DNSDomain;
            DHCPEnabled    = $IPConfig.DHCPEnabled;
            LoggedOnUser   = $LoggedOnUser
            LogonTime      = $LogonTime
        }
        $CIMOutput
    }
    else {
        Write-Warning "`tDer Rechner '$($ComputerName)' ist nicht erreichbar`n" -ForegroundColor Yellow
    }
}