<#
.SYNOPSIS
    Daily VMware Host metadata report for PowerBI trending and hardware capacity planning.

.DESCRIPTION
    Collects ESXi host metadata from vCenter including hardware, compute capacity, and
    version information. Exports a timestamped CSV and inserts into SQL each run.
    Append daily runs to build a historical dataset for PowerBI trend analysis and
    physical hardware purchasing / lifecycle decisions.

.NOTES
    Run the following DDL once to create the destination table:

        DROP TABLE IF EXISTS [dbo].[VMware_Trends_Host]

        CREATE TABLE [dbo].[VMware_Trends_Host] (
            [ReportDate]          DATETIME2      NOT NULL,
            [HostName]            NVARCHAR(255)  NOT NULL,
            [Datacenter]          NVARCHAR(100)  NULL,
            [Cluster]             NVARCHAR(100)  NULL,
            [ConnectionState]     NVARCHAR(50)   NULL,
            [PowerState]          NVARCHAR(50)   NULL,
            [InMaintenanceMode]   BIT            NOT NULL,
            [Model]               NVARCHAR(255)  NULL,
            [ProcessorType]       NVARCHAR(255)  NULL,
            [CpuSockets]          INT            NULL,
            [CoresPerSocket]      INT            NULL,
            [TotalCpuCores]       INT            NULL,
            [CpuMhz]             INT            NULL,
            [TotalCpuMhz]        INT            NULL,
            [MemoryTotalGB]       DECIMAL(10,2)  NULL,
            [MemoryUsageGB]       DECIMAL(10,2)  NULL,
            [VMCount]             INT            NULL,
            [EsxiVersion]         NVARCHAR(50)   NULL,
            [EsxiBuild]           NVARCHAR(50)   NULL,
            [UptimeDays]          DECIMAL(10,2)  NULL
        )

    MemoryUsageGB reflects real-time memory consumed by running VMs at the time of collection.
    UptimeDays will be NULL for hosts that are powered off or disconnected.
#>
[CmdletBinding()]
param(
)

#region --- Setup ---------------------------------------------------------------
[string] $OutputPath     = 'C:\temp\VM_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database       = 'ITD-Systems-Automation'
[string] $Table          = 'VMware_Trends_Host'
[System.Management.Automation.PSCredential] $SqlCredential = $SqlCred #$Secret:sql_itdpsu1

$RunDate   = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd')

if (-not (Test-Path -Path $OutputPath)) {
    New-Item -ItemType Directory -Path $OutputPath | Out-Null
}

Start-Transcript -Path (Join-Path $OutputPath "VMHostMetadataReport_$DateStamp.log") -Append

#endregion

#region --- Build VMHost -> Cluster/Datacenter Lookups (avoids per-host queries) -

Write-Verbose 'Building host-to-cluster and host-to-datacenter maps...'
$HostClusterMap    = @{}
$HostDatacenterMap = @{}

Get-Datacenter | ForEach-Object {
    $DatacenterName = $_.Name
    Get-VMHost -Location $_ | ForEach-Object {
        $HostDatacenterMap[$_.Name] = $DatacenterName
    }
}

Get-Cluster | ForEach-Object {
    $ClusterName = $_.Name
    Get-VMHost -Location $_ | ForEach-Object {
        $HostClusterMap[$_.Name] = $ClusterName
    }
}

#endregion

#region --- Collect Host Data --------------------------------------------------

Write-Verbose 'Gathering hosts...'
$AllHosts = $HostDatacenterMap.Keys | ForEach-Object { Get-VMHost -Name $_ }

Write-Verbose "Processing $($AllHosts.Count) hosts..."

$Results = foreach ($VMHost in $AllHosts) {

    $Ext = $VMHost.ExtensionData  # single API object -- reuse for all fields

    #--- CPU info from hardware summary
    $CpuSockets     = $Ext.Hardware.CpuInfo.NumCpuPackages
    $TotalCpuCores  = $Ext.Hardware.CpuInfo.NumCpuCores
    $CoresPerSocket = if ($CpuSockets -gt 0) { [int]($TotalCpuCores / $CpuSockets) } else { $null }
    $CpuMhz         = $Ext.Hardware.CpuInfo.Hz / 1000000  # Hz -> MHz
    $TotalCpuMhz    = $Ext.Summary.Hardware.CpuMhz * $TotalCpuCores

    #--- Memory
    $MemoryTotalGB = [Math]::Round($VMHost.MemoryTotalGB, 2)
    $MemoryUsageGB = [Math]::Round($VMHost.MemoryUsageGB, 2)

    #--- VM count on this host right now
    $VMCount = ($Ext.Vm | Measure-Object).Count

    #--- Uptime (null when host is powered off / disconnected)
    $UptimeDays = $null
    $BootTime   = $Ext.Runtime.BootTime
    if ($null -ne $BootTime) {
        $UptimeDays = [Math]::Round(($RunDate - $BootTime).TotalDays, 2)
    }

    [PSCustomObject]@{
        ReportDate        = $Timestamp
        HostName          = $VMHost.Name
        Datacenter        = $HostDatacenterMap[$VMHost.Name]
        Cluster           = $HostClusterMap[$VMHost.Name]
        ConnectionState   = $VMHost.ConnectionState
        PowerState        = $VMHost.PowerState
        InMaintenanceMode = $VMHost.ExtensionData.Runtime.InMaintenanceMode
        Model             = $Ext.Hardware.SystemInfo.Model
        ProcessorType     = $VMHost.ProcessorType
        CpuSockets        = $CpuSockets
        CoresPerSocket    = $CoresPerSocket
        TotalCpuCores     = $TotalCpuCores
        CpuMhz            = [int]$CpuMhz
        TotalCpuMhz       = $TotalCpuMhz
        MemoryTotalGB     = $MemoryTotalGB
        MemoryUsageGB     = $MemoryUsageGB
        VMCount           = $VMCount
        EsxiVersion       = $VMHost.Version
        EsxiBuild         = $VMHost.Build
        UptimeDays        = $UptimeDays
    }
}

#endregion

#region --- Export CSV ---------------------------------------------------------

$OutputFile = Join-Path $OutputPath "VMHostMetadata_$DateStamp.csv"
$Results | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Verbose "Exported $($Results.Count) host records to: $OutputFile"

#endregion

#region --- SQL Insert ---------------------------------------------------------

$DataTable = [System.Data.DataTable]::new()

$ColDefs = [ordered]@{
    ReportDate        = [datetime]
    HostName          = [string]
    Datacenter        = [string]
    Cluster           = [string]
    ConnectionState   = [string]
    PowerState        = [string]
    InMaintenanceMode = [bool]
    Model             = [string]
    ProcessorType     = [string]
    CpuSockets        = [int]
    CoresPerSocket    = [int]
    TotalCpuCores     = [int]
    CpuMhz            = [int]
    TotalCpuMhz       = [int]
    MemoryTotalGB     = [decimal]
    MemoryUsageGB     = [decimal]
    VMCount           = [int]
    EsxiVersion       = [string]
    EsxiBuild         = [string]
    UptimeDays        = [decimal]
}

foreach ($Col in $ColDefs.GetEnumerator()) {
    $Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
    $Column.AllowDBNull = $true
    [void]$DataTable.Columns.Add($Column)
}

foreach ($Row in $Results) {
    $DataRow = $DataTable.NewRow()
    foreach ($Col in $ColDefs.Keys) {
        $Val = $Row.$Col
        $DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
    }
    [void]$DataTable.Rows.Add($DataRow)
}

$SqlParams = @{
    ServerInstance = $ServerInstance
    DatabaseName   = $Database
    SchemaName     = 'dbo'
    TableName      = $Table
    Credential     = $SqlCredential
    InputData      = $DataTable
}
Write-SqlTableData @SqlParams

Write-Verbose "Inserted $($DataTable.Rows.Count) host records into [$Database].[dbo].[$Table]"

#endregion

#region --- Cleanup -------------------------------------------------------------
Stop-Transcript

#endregion
