Private/ANF/Merge-SilkTCOANFData.ps1
|
function Merge-SilkTCOANFData { param ( [Parameter(Mandatory)] [array] $anflist, [Parameter()] [array] $costs ) $newarray = @() # every row carries the same columns so pool/volume/snapshot rows stack in one csv, # same shape as the rds report function New-AnfRow { $o = New-Object psobject $cols = @( 'RecordType','NetAppAccount','PoolName','VolumeName','ResourceGroupName','Region','Zone', 'ServiceLevel','QosType','ProvisionedGiB','ProvisionedTiB','ThroughputCeilingMiBps', 'AssignedThroughputMiBps','UtilizedThroughputMiBps','ProtocolTypes','NetworkFeatures', 'CoolAccess','CoolnessPeriodDays','IsLargeVolume','SnapshotPolicy','ReplicationEndpointType', 'ReplicationSchedule','Encryption','AllocatedToVolumesGiB','StrandedGiB','PoolUtilizationPct', 'SnapshotCount','Days','ListRateGiBMonthUSD', 'ProvisionedCostPeriodUSD','ProvisionedCostMonthlyUSD', 'ActualCostPeriodUSD','ActualCostMonthlyUSD','CostVariancePct', 'ApportionedCostPeriodUSD','ApportionedCostMonthlyUSD','CostNotes','Created' ) foreach ($c in $cols) { $o | Add-Member -MemberType NoteProperty -Name $c -Value $null } return $o } foreach ($item in $anflist) { # backup vaults are their own thing, one row and move on if ($item.IsBackupVault) { $backups = @($item.Backups) $row = New-AnfRow $row.RecordType = 'BackupVault' $row.NetAppAccount = $item.NetAppAccount $row.PoolName = $item.BackupVault $row.ResourceGroupName = $item.ResourceGroupName $row.Region = $item.Region $row.SnapshotCount = $backups.Count if ($backups) { $sz = ($backups | Measure-Object -Property Size -Sum).Sum if ($sz) { $row.ProvisionedGiB = [Math]::Round($sz / 1GB, 2) } } $newarray += $row continue } $poolCost = $null if ($costs) { $poolCost = $costs | Where-Object { $_.ResourceId -eq $item.ResourceId } | Select-Object -First 1 } # --- pool row: this is where the money actually lands --- $row = New-AnfRow $row.RecordType = 'Pool' $row.NetAppAccount = $item.NetAppAccount $row.PoolName = $item.PoolName $row.ResourceGroupName = $item.ResourceGroupName $row.Region = $item.Region $row.ServiceLevel = $item.ServiceLevel $row.QosType = $item.QosType $row.ProvisionedGiB = $item.ProvisionedGiB $row.ProvisionedTiB = $item.ProvisionedTiB $row.ThroughputCeilingMiBps = $item.ThroughputCeilingMiBps $row.UtilizedThroughputMiBps = $item.UtilizedThroughputMiBps $row.CoolAccess = $item.CoolAccess $row.Encryption = $item.EncryptionType $row.AllocatedToVolumesGiB = $item.AllocatedToVolumesGiB $row.StrandedGiB = $item.StrandedGiB $row.PoolUtilizationPct = $item.PoolUtilizationPct $row.SnapshotCount = @($item.Volumes | ForEach-Object { @($_.Snapshots).Count } | Measure-Object -Sum).Sum if ($poolCost) { $row.Days = $poolCost.Days $row.ListRateGiBMonthUSD = $poolCost.ListRateGiBMonthUSD $row.ProvisionedCostPeriodUSD = $poolCost.ProvisionedCostPeriodUSD $row.ProvisionedCostMonthlyUSD = $poolCost.ProvisionedCostMonthlyUSD $row.ActualCostPeriodUSD = $poolCost.ActualCostPeriodUSD $row.ActualCostMonthlyUSD = $poolCost.ActualCostMonthlyUSD $row.CostVariancePct = $poolCost.CostVariancePct $row.CostNotes = $poolCost.CostNotes } $newarray += $row # --- volume rows --- foreach ($v in @($item.Volumes)) { $vrow = New-AnfRow $vrow.RecordType = 'Volume' $vrow.NetAppAccount = $item.NetAppAccount $vrow.PoolName = $item.PoolName $vrow.VolumeName = $v.VolumeName $vrow.ResourceGroupName = $item.ResourceGroupName $vrow.Region = $v.Location $vrow.Zone = $v.Zone $vrow.ServiceLevel = $v.ServiceLevel $vrow.QosType = $item.QosType $vrow.ProvisionedGiB = $v.ProvisionedGiB $vrow.ProvisionedTiB = [Math]::Round($v.ProvisionedGiB / 1024, 4) $vrow.ThroughputCeilingMiBps = $v.ThroughputCeilingMiBps $vrow.AssignedThroughputMiBps = $v.AssignedThroughputMiBps $vrow.ProtocolTypes = $v.ProtocolTypes $vrow.NetworkFeatures = $v.NetworkFeatures $vrow.CoolAccess = $v.CoolAccess $vrow.CoolnessPeriodDays = $v.CoolnessPeriodDays $vrow.IsLargeVolume = $v.IsLargeVolume $vrow.SnapshotPolicy = $v.SnapshotPolicy $vrow.ReplicationEndpointType = $v.ReplicationEndpointType $vrow.ReplicationSchedule = $v.ReplicationSchedule $vrow.Encryption = $v.EncryptionKeySource $vrow.SnapshotCount = @($v.Snapshots).Count # anf bills the pool, so anything here is a derived share, not a billed figure. # kept in its own column so an estimate never sits next to a real number. if ($poolCost -and $item.ProvisionedGiB -gt 0) { $vrow.Days = $poolCost.Days $fraction = $v.ProvisionedGiB / $item.ProvisionedGiB # prefer the billed figure, fall back to the rate card if ($poolCost.ActualCostMonthlyUSD) { $vrow.ApportionedCostPeriodUSD = [Math]::Round($fraction * $poolCost.ActualCostPeriodUSD, 4) $vrow.ApportionedCostMonthlyUSD = [Math]::Round($fraction * $poolCost.ActualCostMonthlyUSD, 2) } elseif ($poolCost.ProvisionedCostMonthlyUSD) { $vrow.ApportionedCostPeriodUSD = [Math]::Round($fraction * $poolCost.ProvisionedCostPeriodUSD, 4) $vrow.ApportionedCostMonthlyUSD = [Math]::Round($fraction * $poolCost.ProvisionedCostMonthlyUSD, 2) $vrow.CostNotes = 'apportioned from list price' } } $newarray += $vrow # --- snapshot rows. count + date only: ARM exposes no size on an anf snapshot, # that only comes from the VolumeSnapshotSize metric which we deliberately skip foreach ($s in @($v.Snapshots)) { $srow = New-AnfRow $srow.RecordType = 'Snapshot' $srow.NetAppAccount = $item.NetAppAccount $srow.PoolName = $item.PoolName $srow.VolumeName = $v.VolumeName $srow.ResourceGroupName = $item.ResourceGroupName $srow.Region = $v.Location $srow.SnapshotPolicy = ($s.Name -split '/')[-1] $srow.Created = $s.Created $srow.CostNotes = 'snapshot capacity not available without metrics' $newarray += $srow } } } return $newarray } |