Windows Server 2025 / Esportare l’inventario del server e dei dischi in CSV

I report CSV (comma-separated values, valori separati da virgole) consentono di confrontare i controlli dei server quando mantengono una struttura di colonne coerente. Con PowerShell si possono raccogliere sistema operativo, memoria e dischi, aggiungendo il nome del computer e l’orario di raccolta per riconoscere l’origine di ogni risultato.

Scegliere i campi e una destinazione protetta

Eseguire questo esempio localmente con Windows PowerShell 5.1 sul server da inventariare. Imparare prima la raccolta dei dati e la scrittura dei file, separatamente dall’autenticazione remota. Usare gli stessi nomi di colonna facilita la successiva unione dei report di più server.

File Contenuti
server.csv Nome del computer, orario di raccolta, sistema operativo, versione, ultimo avvio e memoria
disks.csv Nome del computer, orario di raccolta, unità, capacità, spazio libero e percentuale libera

Ogni esecuzione crea una cartella nuova sotto C:\LabReports, con data, ora e un identificatore breve, mantenendo separati i risultati precedenti. I nomi dei server e la configurazione interna possono essere informazioni operative sensibili: stabilire chi può leggere la cartella e per quanto tempo conservare i report.

Salvare ed eseguire lo script completo

Creare prima C:\LabScripts e salvare tutto il codice come C:\LabScripts\Collect-LabInventory.ps1, verificando che il nome non termini in .ps1.txt. Usare UTF-8; aggiungendo accenti o altri caratteri non ASCII, scegliere UTF-8 con indicatore dell’ordine dei byte (BOM, byte order mark), come spiegato nella documentazione sulla codifica dei caratteri. Aprire Windows PowerShell sul server con Esegui come amministratore: sono sufficienti i moduli inclusi in Windows PowerShell 5.1. Se un criterio blocca il file, rispettare i requisiti di esecuzione e firma approvati dall’organizzazione, senza disattivare le protezioni per aggirare il blocco.

$runLabel = (Get-Date -Format 'yyyyMMdd-HHmmss') + '-' + ([guid]::NewGuid().ToString('N').Substring(0,6))
$reportDirectory = Join-Path 'C:\LabReports' $runLabel
New-Item -ItemType Directory -Path $reportDirectory -Force -ErrorAction Stop | Out-Null
$os = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop
$computer = Get-CimInstance Win32_ComputerSystem -ErrorAction Stop
$collectedAt = (Get-Date).ToString('o')
[pscustomobject]@{
    ComputerName = $env:COMPUTERNAME
    CollectedAt = $collectedAt
    OS = $os.Caption
    Version = $os.Version
    LastBoot = $os.LastBootUpTime
    MemoryGiB = [math]::Round($computer.TotalPhysicalMemory / 1GB,2)
} | Export-Csv -LiteralPath (Join-Path $reportDirectory 'server.csv') -NoTypeInformation -Encoding UTF8
Get-CimInstance Win32_LogicalDisk -Filter 'DriveType=3' -ErrorAction Stop | ForEach-Object {
    [pscustomobject]@{
        ComputerName = $env:COMPUTERNAME
        CollectedAt = $collectedAt
        Drive = $_.DeviceID
        SizeGiB = [math]::Round($_.Size / 1GB,2)
        FreeGiB = [math]::Round($_.FreeSpace / 1GB,2)
        FreePercent = if ($_.Size -gt 0) { [math]::Round(100 * $_.FreeSpace / $_.Size,1) } else { $null }
    }
} | Export-Csv -LiteralPath (Join-Path $reportDirectory 'disks.csv') -NoTypeInformation -Encoding UTF8
Write-Output $reportDirectory
Set-Location 'C:\LabScripts'
.\Collect-LabInventory.ps1

CIM (Common Information Model) è un modello comune di informazioni che fornisce le classi di gestione interrogate dal codice. Gli esempi Microsoft per raccogliere informazioni sui computer illustrano questo approccio. La costante binaria 1GB equivale a 1.073.741.824 byte: MemoryGiB, SizeGiB e FreeGiB sono espressi in gibibyte, mentre FreePercent è una percentuale. Lo script non modifica servizi o impostazioni del server, ma crea la cartella di destinazione e i file CSV.

Verificare entrambi i file generati

Usare il percorso effettivamente stampato al termine della propria esecuzione. Quando Read-Host lo richiede, inserirlo o incollarlo senza virgolette. Data, ora e identificatore cambiano a ogni esecuzione: non copiare quindi una cartella di esempio da un risultato precedente:

$reportPath = Read-Host 'Report directory printed by the script'
Import-Csv -LiteralPath (Join-Path $reportPath 'server.csv') | Format-List
Import-Csv -LiteralPath (Join-Path $reportPath 'disks.csv') | Format-Table

Verificare che server.csv contenga una riga relativa al computer interrogato e che disks.csv riporti le sue unità logiche locali. ComputerName e CollectedAt devono essere coerenti nei due file; controllare anche le altre colonne. MemoryGiB deriva da TotalPhysicalMemory di Win32_ComputerSystem, il valore riportato dal sistema interrogato. In una macchina virtuale, memoria dinamica e allocazione corrente possono spiegare differenze rispetto alla configurazione prevista. Il valore non indica tutta la memoria fisica dell’host e non garantisce una misura esatta dei moduli di memoria installati.

Trattare il CSV come dati

Export-Csv scrive le proprietà degli oggetti come colonne. Inserire Format-Table prima dell’esportazione invierebbe invece oggetti di formattazione: mantenere separati oggetti, pipeline e visualizzazione in PowerShell. -NoTypeInformation omette la riga con le informazioni sul tipo, mentre -Encoding UTF8 produce UTF-8 con BOM in Windows PowerShell 5.1.

Import-Csv restituisce normalmente proprietà di testo, anche quando sembrano numeri. Convertire un valore in numero prima di confrontarlo numericamente. Le impostazioni locali del foglio di calcolo possono cambiare i separatori decimali o l’interpretazione delle date. Conservare il CSV originale e scegliere consapevolmente delimitatore, codifica e tipi di dati durante l’importazione. Il filtro seguente presuppone percentuali numeriche valide:

Import-Csv -LiteralPath (Join-Path $reportPath 'disks.csv') |
    Where-Object { [double]$_.FreePercent -lt 20 } |
    Select-Object ComputerName,Drive,FreePercent

Il 20% è una soglia di esempio per il filtro, non una regola di allarme universale. Considerare anche spazio libero assoluto, crescita e requisiti del carico di lavoro. Se FreePercent è vuoto perché Size non è valido o non è maggiore di zero, controllare separatamente quella riga prima di filtrare. Convertire una stringa vuota in double può dare 0: questo non dimostra che lo spazio libero reale sia dello 0%.

Gestire gli errori parziali e conservare i risultati utili

Se la creazione della cartella o una query non riesce, controllare autorizzazioni, spazio libero e disponibilità della classe. Il percorso stampato alla fine non dimostra da solo che tutte le esportazioni siano riuscite. Entrambi i file devono esistere, avere le colonne previste e contenere dati; un solo file non costituisce un risultato completo.

Ripetere la raccolta senza riavviare il server tra le due esecuzioni. CollectedAt deve cambiare, mentre LastBoot rimane uguale se non avviene un riavvio. Per la pulizia, identificare esattamente la cartella prodotta dall’esecuzione da eliminare. Non cancellare tutto l’albero LabReports o altri registri di controllo.