param( [string]$ServerUrl = "http://localhost:8080" ) $ComputerName = $env:COMPUTERNAME $User = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name $IPAddress = (Get-NetIPAddress -AddressFamily IPv4 -InterfaceAlias "Ethernet*", "Wi-Fi*" | Select-Object -First 1).IPAddress $MacAddress = (Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1).MacAddress $LastSeen = Get-Date -Format "yyyy-MM-dd HH:mm:ss" # Get installed software from registry (32 and 64 bit) $SoftwareList = New-Object System.Collections.Generic.List[PSCustomObject] $RegistryPaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" ) foreach ($Path in $RegistryPaths) { Get-ItemProperty $Path -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -ne $null } | ForEach-Object { $SoftwareList.Add([PSCustomObject]@{ Name = [string]$_.DisplayName Version = [string]$_.DisplayVersion }) } } # Unique list and sort (Now works correctly with PSCustomObject) $Software = $SoftwareList | Sort-Object Name -Unique $Inventory = @{ ComputerName = $ComputerName User = $User IPAddress = $IPAddress MacAddress = $MacAddress LastSeen = $LastSeen Software = $Software } # Convert to JSON $Json = $Inventory | ConvertTo-Json -Depth 10 # FIX FOR POWERSHELL 5.1: Ensure Software is always an array # If Software has only 1 item, ConvertTo-Json creates an object {} instead of an array [{}] if ($Software.Count -eq 1) { # Find the Software block and wrap it in brackets if it's not already an array # This regex is more robust: it looks for the Software key followed by an object start { $Json = $Json -replace '("Software":\s*)\{', '$1[{' # And then closes the bracket after that object $Json = $Json -replace '(\s+)(\d+|".*?"|null|true|false)\s+\},(\s+"[A-Z])', '$1$2$1}],$3' # If Software was the last element in the JSON $Json = $Json -replace '(\s+)(\d+|".*?"|null|true|false)\s+\}\s+\}', '$1$2$1}] }' } try { $Response = Invoke-RestMethod -Uri "$ServerUrl/inventory" -Method Post -Body $Json -ContentType "application/json" Write-Host "Inventory sent successfully to $ServerUrl" } catch { Write-Error "Failed to send inventory: $_" if ($_.Exception.Response) { $Reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream()) $ErrorBody = $Reader.ReadToEnd() Write-Host "Error Body: $ErrorBody" -ForegroundColor Red } }