cisco
1 TopicCreating and exporting a collection with variable properties
My script logs into multiple Cisco UCS servers and extracts the CPU information, storing it in a collection which is then written to a CSV file. My problem is that I have a loop which creates a set of properties for each CPU in the server and adds it to the collection. However some servers have 2 CPUs and some have 4. When my code exports the data to CSV, I only get 2 CPUs of data for ALL servers, even though I can see 4 CPUs defined in the collection as I step thru the code. Thus, as the code runs and collects CPU data, the collection ($IMCRackServerInventory) looks like this: Server01, CPU1_ID, CPU1_Model, CPU2_ID, CPU2_Model Server02, CPU1_ID, CPU1_Model, CPU2_ID, CPU2_Model Server03, CPU1_ID, CPU1_Model, CPU2_ID, CPU2_Model, CPU3_ID, CPU3_Model, CPU4_ID, CPU4_Model Server04, CPU1_ID, CPU1_Model, CPU2_ID, CPU2_Model But then the collection is exported to CSV and I only get the following in the CSV: Server01, CPU1_ID, CPU1_Model, CPU2_ID, CPU2_Model Server02, CPU1_ID, CPU1_Model, CPU2_ID, CPU2_Model Server03, CPU1_ID, CPU1_Model, CPU2_ID, CPU2_Model Server04, CPU1_ID, CPU1_Model, CPU2_ID, CPU2_Model So it seems to be only writing the first 2 CPU details to file as not all records have 4 entries. Is there a way around this? My Code: # # ================================FUNCTION DECLARATION START==================================================================== # # # Check the required columns for this script to run, are present in the user-selected CSV import file. Function CheckCSVColumnsExist { Param( [Object]$CSVImportFile, [Array]$ColumnsToCheck = '' ) $ColumnHeaders = (Import-Csv $CSVImportFile | Get-Member -MemberType NoteProperty).Name $MissingColumnHeaders = @() ForEach( $ColumnToCheck in $ColumnsToCheck) { $MissingColumnName = New-Object PSObject If ($ColumnHeaders -match $ColumnToCheck ) { # Nothing to do. } Else { $MissingColumnName | Add-Member -type NoteProperty -Name 'Column_Name' -Value $ColumnToCheck $MissingColumnHeaders += $MissingColumnName } } Return $MissingColumnHeaders } # This function shows the Open File dialog to the user so the user can # select the import CSV file. # Function Get-FileName($InitialDirectory) { [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.initialDirectory = $initialDirectory $OpenFileDialog.filter = "CSV (*.csv) | *.csv" $OpenFileDialog.ShowDialog() | Out-Null $OpenFileDialog.FileName } # # ================================FUNCTION DECLARATION FINISH=================================================================== # # # ================================SCRIPT START================================================================================== # # Import-Module Cisco.IMC # The input CSV file contains the details required for the script # to log into each Cisco UCS server. # # Get the CSV import file name and path: $ImportCSVFile = Get-FileName Write-Host "Script starting." -ForegroundColor Green # Check if the user cancelled the request. if ($ImportCSVFile -eq "") { # They did! Throw "No file selected. Ending script" } # Load the CSV file contents. $UCSRackServerReport = Import-CSV $ImportCSVFile -ErrorAction SilentlyContinue # Ask the user for the CIMC credential details. $IMCServerCredential = Get-Credential admin $IMCRackServerInventory = @() # Read each entry in the import CSV file, then try to logon to the # CIMC of each one and collect hardware details. ForEach ($vRow in $UCSRackServerReport) { $Item = New-Object PSObject # Get the server CIMC IP. $RackServerIMCIP = $vRow."IP Address" # Get the server User Label and Host Name. $RackServerIMCUserLabel = $vRow."User Label" $RackServerIMCHostName = $vRow."Host Name" # If the User Label is blank, use the Host Name for console output updates. If ([string]::IsNullOrWhiteSpace($RackServerIMCUserLabel) ) { $StringLabel = "[$RackServerIMCHostName/$RackServerIMCIP]" } Else { $StringLabel = "[$RackServerIMCUserLabel/$RackServerIMCIP]" } Try { # Let's connect to the CIMC. $Connected = $True Write-Host "$StringLabel Attempting a connection to server IMC." -ForegroundColor Yellow $IMCHandle = Connect-IMC -Name $RackServerIMCIP -Credential $IMCServerCredential -NotDefault -ErrorAction Stop } Catch { # Did not connect due to connection issue. Write-Host "$StringLabel Error: $($PSItem.ToString())" -ForegroundColor Red If ($PSItem.Exception.ToString().Contains("Unable to connect")) { # Set connection flag false. $Connected = $False } } # Did we connect to the CIMC? If (!$Connected) { # No we did not. Record this event. If ([string]::IsNullOrWhiteSpace($RackServerIMCUserLabel) ) { $NewUserLabel = $RackServerIMCHostName } Else { $NewUserLabel = $RackServerIMCUserLabel } # Set collection details and the properties not read in will be set to "Not Connected". $Item | Add-Member -type NoteProperty -Name 'UserLabel' -Value $NewUserLabel $Item | Add-Member -type NoteProperty -Name 'Model' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'Serial' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'ServerID' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'CIMC_IP' -Value $RackServerIMCIP $Item | Add-Member -type NoteProperty -Name 'Vendor' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'IMCName' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'DN' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'Rn' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'CPUID_1' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'CPUModel_1' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'OperState_1' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'Presence_1' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'SocketDesignation_1' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'CPUVendor_1' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'CPUIMC_1' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'Dn_1' -Value "Not Connected" $Item | Add-Member -type NoteProperty -Name 'Rn_1' -Value "Not Connected" } Else { # We connected OK. Write-Host "$StringLabel Connection to server IMC established." -ForegroundColor Cyan Write-Host "$StringLabel Gathering Rack Unit data." -ForegroundColor Cyan # Get rack server hardware details. $IMCServerUnit = Get-IMCRackUnit -Imc $IMCHandle # Check if User Label is blank and if so, use the IMC field as the server label. If ([string]::IsNullOrWhiteSpace($IMCServerUnit.UsrLbl) ) { $NewUserLabel = $IMCServerUnit.Imc } Else { $NewUserLabel = $IMCServerUnit.UsrLbl } # Record rack server hardware details. $Item | Add-Member -type NoteProperty -Name 'UserLabel' -Value $NewUserLabel $Item | Add-Member -type NoteProperty -Name 'Model' -Value $($IMCServerUnit.Model) $Item | Add-Member -type NoteProperty -Name 'Serial' -Value $($IMCServerUnit.Serial) $Item | Add-Member -type NoteProperty -Name 'ServerID' -Value $($IMCServerUnit.ServerId) $Item | Add-Member -type NoteProperty -Name 'CIMC_IP' -Value $RackServerIMCIP $Item | Add-Member -type NoteProperty -Name 'Vendor' -Value $($IMCServerUnit.Vendor) $Item | Add-Member -type NoteProperty -Name 'IMCName' -Value $($IMCServerUnit.Imc) $Item | Add-Member -type NoteProperty -Name 'DN' -Value $($IMCServerUnit.Dn) $Item | Add-Member -type NoteProperty -Name 'Rn' -Value $($IMCServerUnit.Rn) Write-Host "$StringLabel Gathering Processor data." -ForegroundColor Cyan $CPUCounter = 1 # Get the rack server processor details. $IMCServerProcessors = Get-IMCProcessorUnit -Imc $IMCHandle # For multiple processors, cycle thru each object found. ForEach ($IMCServerProcessor in $IMCServerProcessors) { # Dynamically create the property name with "_#" at the end for each processor. Record processor details. $FieldName = "CPUID_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Id) $FieldName = "CPUModel_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Model) $FieldName = "OperState_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.OperState) $FieldName = "Presence_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Presence) $FieldName = "SocketDesignation_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.SocketDesignation) $FieldName = "CPUVendor_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Vendor) $FieldName = "CPUIMC_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Imc) $FieldName = "Dn_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Dn) $FieldName = "Rn_$CPUCounter"; $Item | Add-Member -type NoteProperty -Name $FieldName -Value $($IMCServerProcessor.Rn) $CPUCounter += 1 } Write-Host "$StringLabel Gathering Firmware data." -ForegroundColor Cyan # Get the firmware package details. $IMCFirmwarePackage = Get-ImcFirmwareRunning -Imc $IMCHandle | Where {$_.Deployment -eq "system" -and $_.Type -eq "blade-controller"} # Add the firmware package details to the collection. $Item | Add-Member -type NoteProperty -Name 'BMCFirmwarePackage' -Value $($IMCFirmwarePackage.Version) } $IMCRackServerInventory += $Item Write-Host "$StringLabel Data collection completed." -ForegroundColor Blue # Close the connection to the server's CIMC. If ($IMCHandle -ne $Null ) { $CloseIMCHandle = Disconnect-IMC -Imc $IMCHandle } Write-Host "$StringLabel Closing session to server IMC." -ForegroundColor Blue Write-Host "" } # Write the collected data to CSV file. $IMCRackServerInventory | Export-CSV -Path "UCS_IMC_RackServer_Inventory.csv" -NoTypeInformation -UseCulture Write-Host "Script Finished." -ForegroundColor GreenSolved1.3KViews0likes6Comments