271 lines
9.9 KiB
PowerShell
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
|