Files
Backup/_NDGOV_WindowsTeam/ITD.Infra-Servers-PowerShellUniversal.Production/Infra-VMware.Administration/Sync-ITDOneViewServerInventoryToSql.ps1
T
Zack Meier 1d304511b8 update
2026-04-15 15:45:50 -05:00

271 lines
9.9 KiB
PowerShell

<#
.SYNOPSIS
Daily HPE OneView enclosure and server inventory for PowerBI trending and lifecycle planning.
.DESCRIPTION
Iterates across all configured HPE OneView appliances, collecting enclosure and server
hardware metadata including compute capacity, power state, and server profile assignment.
Exports timestamped CSVs and inserts into SQL each run.
Append daily runs to build a historical dataset for PowerBI trend analysis and
physical hardware purchasing / lifecycle decisions.
Appliances processed:
itdoneviewp1.nd.gov - Rack servers only (no enclosures)
itdbissyncompp1.nd.gov - Synergy enclosures + servers
itdmdnsyncompp1.nd.gov - Synergy enclosures + servers
.NOTES
Run the following DDL once to create the destination tables:
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Enclosure]
CREATE TABLE [dbo].[VMware_Trends_Enclosure] (
[ReportDate] DATETIME2 NOT NULL,
[ApplianceConnection] NVARCHAR(100) NULL,
[EnclosureName] NVARCHAR(255) NOT NULL,
[EnclosureModel] NVARCHAR(255) NULL,
[EnclosureSerialNumber] NVARCHAR(100) NULL,
[Status] NVARCHAR(50) NULL,
[DeviceBayCount] INT NULL
)
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Server]
CREATE TABLE [dbo].[VMware_Trends_Server] (
[ReportDate] DATETIME2 NOT NULL,
[ApplianceConnection] NVARCHAR(100) NULL,
[EnclosureName] NVARCHAR(255) NULL,
[BayNumber] INT NULL,
[ServerHardwareName] NVARCHAR(255) NOT NULL,
[ServerName] NVARCHAR(255) NULL,
[ServerModel] NVARCHAR(255) NULL,
[ServerSerialNumber] NVARCHAR(100) NULL,
[Status] NVARCHAR(50) NULL,
[PowerState] NVARCHAR(50) NULL,
[ServerProfileName] NVARCHAR(255) NULL,
[ProcessorType] NVARCHAR(255) NULL,
[ProcessorCount] INT NULL,
[MemoryGB] DECIMAL(10,2) NULL,
[FormFactor] NVARCHAR(100) NULL
)
EnclosureName and BayNumber are NULL for rack-mounted servers not seated in an enclosure.
ServerName is the iLO/DNS hostname populated once a server profile is assigned.
#>
[CmdletBinding()]
param(
)
#region --- Setup ---------------------------------------------------------------
[string[]] $OVHostnames = @(
'itdoneviewp1.nd.gov',
'itdbissyncompp1.nd.gov',
'itdmdnsyncompp1.nd.gov'
)
[string] $OutputPath = 'C:\temp\OV_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database = 'ITD-Systems-Automation'
[string] $EnclosureTable = 'VMware_Trends_Enclosure'
[string] $ServerTable = 'VMware_Trends_Server'
[System.Management.Automation.PSCredential] $OVCredential = $Secret:ndgov_svcitdvmhpe
[System.Management.Automation.PSCredential] $SqlCredential = $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 "OVServerInventory_$DateStamp.log") -Append
#endregion
#region --- Collect Data From All Appliances -----------------------------------
$AllEnclosureResults = [System.Collections.Generic.List[PSCustomObject]]::new()
$AllServerResults = [System.Collections.Generic.List[PSCustomObject]]::new()
foreach ($OVHostname in $OVHostnames) {
Write-Verbose "Connecting to HPE OneView: $OVHostname"
Connect-OVMgmt -Hostname $OVHostname -Credential $OVCredential -AuthLoginDomain nd.gov -LoginAcknowledge
#--- Enclosures ------------------------------------------------------------
Write-Verbose "[$OVHostname] Gathering enclosures..."
$Enclosures = Get-OVEnclosure
# Build URI map for server lookups (only populated if there are enclosures)
$EnclosureUriMap = @{}
foreach ($Enclosure in $Enclosures) {
$EnclosureUriMap[$Enclosure.uri] = $Enclosure.name
$AllEnclosureResults.Add([PSCustomObject]@{
ReportDate = $Timestamp
ApplianceConnection = $OVHostname
EnclosureName = $Enclosure.name
EnclosureModel = $Enclosure.model
EnclosureSerialNumber = $Enclosure.serialNumber
Status = $Enclosure.status
DeviceBayCount = ($Enclosure.deviceBays | Measure-Object).Count
})
}
#--- Servers ---------------------------------------------------------------
Write-Verbose "[$OVHostname] Gathering servers..."
$Servers = Get-OVServer | Where-Object { $_.serverName -like 'itdvm*' }
# Build profile URI map for this appliance
$ProfileUriMap = @{}
Get-OVServerProfile | ForEach-Object {
$ProfileUriMap[$_.uri] = $_.name
}
Write-Verbose "[$OVHostname] Processing $($Servers.Count) servers..."
foreach ($Server in $Servers) {
$EnclosureName = if ($Server.locationUri) {
$EnclosureUriMap[$Server.locationUri]
} else {
$null
}
$ProfileName = if ($Server.serverProfileUri) {
$ProfileUriMap[$Server.serverProfileUri]
} else {
$null
}
$MemoryGB = if ($null -ne $Server.memoryMb -and $Server.memoryMb -gt 0) {
[Math]::Round($Server.memoryMb / 1024, 2)
} else {
$null
}
$AllServerResults.Add([PSCustomObject]@{
ReportDate = $Timestamp
ApplianceConnection = $OVHostname
EnclosureName = $EnclosureName
BayNumber = if ($null -ne $Server.position) { [int]$Server.position } else { $null }
ServerHardwareName = $Server.name
ServerName = $Server.serverName
ServerModel = $Server.model
ServerSerialNumber = $Server.serialNumber
Status = $Server.status
PowerState = $Server.powerState
ServerProfileName = $ProfileName
ProcessorType = $Server.processorType
ProcessorCount = if ($null -ne $Server.processorCount) { [int]$Server.processorCount } else { $null }
MemoryGB = $MemoryGB
FormFactor = $Server.formFactor
})
}
Disconnect-OVMgmt
Write-Verbose "[$OVHostname] Disconnected."
}
#endregion
#region --- Export CSVs --------------------------------------------------------
$EnclosureCsv = Join-Path $OutputPath "OVEnclosures_$DateStamp.csv"
$ServerCsv = Join-Path $OutputPath "OVServers_$DateStamp.csv"
$AllEnclosureResults | Export-Csv -Path $EnclosureCsv -NoTypeInformation
$AllServerResults | Export-Csv -Path $ServerCsv -NoTypeInformation
Write-Verbose "Exported $($AllEnclosureResults.Count) enclosure records to: $EnclosureCsv"
Write-Verbose "Exported $($AllServerResults.Count) server records to: $ServerCsv"
#endregion
#region --- SQL Insert: Enclosures ---------------------------------------------
$EnclosureTable_DT = [System.Data.DataTable]::new()
$EnclosureColDefs = [ordered]@{
ReportDate = [datetime]
ApplianceConnection = [string]
EnclosureName = [string]
EnclosureModel = [string]
EnclosureSerialNumber = [string]
Status = [string]
DeviceBayCount = [int]
}
foreach ($Col in $EnclosureColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$EnclosureTable_DT.Columns.Add($Column)
}
foreach ($Row in $AllEnclosureResults) {
$DataRow = $EnclosureTable_DT.NewRow()
foreach ($Col in $EnclosureColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$EnclosureTable_DT.Rows.Add($DataRow)
}
Write-SqlTableData -ServerInstance $ServerInstance -DatabaseName $Database -SchemaName 'dbo' `
-TableName $EnclosureTable -Credential $SqlCredential -InputData $EnclosureTable_DT
Write-Verbose "Inserted $($EnclosureTable_DT.Rows.Count) enclosure records into [$Database].[dbo].[$EnclosureTable]"
#endregion
#region --- SQL Insert: Servers ------------------------------------------------
$ServerTable_DT = [System.Data.DataTable]::new()
$ServerColDefs = [ordered]@{
ReportDate = [datetime]
ApplianceConnection = [string]
EnclosureName = [string]
BayNumber = [int]
ServerHardwareName = [string]
ServerName = [string]
ServerModel = [string]
ServerSerialNumber = [string]
Status = [string]
PowerState = [string]
ServerProfileName = [string]
ProcessorType = [string]
ProcessorCount = [int]
MemoryGB = [decimal]
FormFactor = [string]
}
foreach ($Col in $ServerColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$ServerTable_DT.Columns.Add($Column)
}
foreach ($Row in $AllServerResults) {
$DataRow = $ServerTable_DT.NewRow()
foreach ($Col in $ServerColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$ServerTable_DT.Rows.Add($DataRow)
}
Write-SqlTableData -ServerInstance $ServerInstance -DatabaseName $Database -SchemaName 'dbo' `
-TableName $ServerTable -Credential $SqlCredential -InputData $ServerTable_DT
Write-Verbose "Inserted $($ServerTable_DT.Rows.Count) server records into [$Database].[dbo].[$ServerTable]"
#endregion
#region --- Cleanup ------------------------------------------------------------
Stop-Transcript
#endregion