Creating a report for all virtual environments

So this is going to be a work in progress post.. A thoughts to paper post.

Here is what I have so far.

The below code will get details from the vCenter server and populate an excel spread sheet.
The inspiration is the sydi project scripts.


</pre>
#By Whackdiddy
#Manager(s) quick report

Disconnect-VIServer * -Confirm:$false

#$config = Get-PowerCLIConfiguration
#if($config.DefaultVIServerMode -eq "Single"){
# Set-PowerCLIConfiguration -DefaultVIServerMode Multiple
#}
#
#Open your vCenter or ESX(i) connections
#
#$vclist = Read-Host 'Enter the vCenter Server Names seperated by commas: '
#foreach ($vc in $vclist){
# connect-viserver -Server $vc
#}

#$vcentername1 = Read-Host 'Enter 1st vCenter Server Name?'
#$vcentername2 = Read-Host 'Enter 2nd vCenter Server Name if none press enter?'
#$vcentername3 = Read-Host 'Enter 3rd vCenter Server Name if none press enter?'
#$vcentername4 = Read-Host 'Enter 4th vCenter Server Name if none press enter?'
#$vcentername5 = Read-Host 'Enter 5th vCenter Server Name if none press enter?'
#$vcentername6 = Read-Host 'Enter 6th vCenter Server Name if none press enter?'
#$vcentername7 = Read-Host 'Enter 7th vCenter Server Name if none press enter?'
##
echo "all connected"

#Create excel COM object
$excel = New-Object -ComObject excel.application

#Make Visible
$excel.Visible = $True
$excel.DisplayAlerts = $False

#Add a workbook
$workbook = $excel.Workbooks.Add()

#Name worksheets
$serverInfoSheet2 = $workbook.Worksheets.Item(1)
$serverInfoSheet2.Activate() | Out-Null
$serverInfoSheet2.Name = 'Dashboard'

$serverInfoSheet3 = $workbook.Worksheets.Item(3)
$serverInfoSheet3.Activate() | Out-Null
$serverInfoSheet3.Name = 'Host and Datastore'

$serverInfoSheet = $workbook.Worksheets.Item(2)
$serverInfoSheet.Activate() | Out-Null
$serverInfoSheet.Name = 'VM-Guest Info'

#Create a Title for the first worksheet
$row = 1
$Column = 1
$serverInfoSheet.Cells.Item($row,$column)= 'vMachine Report'

$range = $serverInfoSheet.Range("a1","n2")
$range.Merge() | Out-Null
$range.VerticalAlignment = -4160

#Give it a nice Style so it stands out
$range.Style = 'Title'

#Increment row for next set of data
$row++;$row++

#Save the initial row so it can be used later to create a border
$initalRow = $row

#Create a header for Disk Space Report; set each cell to Bold and add a background color
$serverInfoSheet.Cells.Item($row,$column)= 'VM_Name'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM FQDN'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM IP Address'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM MAC Address'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM Operating System'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM Operating System Family'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'vSphere Host'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM CPU Count'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM Memory'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'Custom Attrib'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM Network Cards'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM Disks'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM Harddisk'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM Harddisk used'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM Harddisk free'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM VMX Location'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'VM Datastore'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True
$Column++
$serverInfoSheet.Cells.Item($row,$column)= 'vSphere Notes'
$serverInfoSheet.Cells.Item($row,$column).Interior.ColorIndex =48
$serverInfoSheet.Cells.Item($row,$column).Font.Bold=$True

#Set up a header filter
$headerRange = $serverInfoSheet.Range("a3","n3")
$headerRange.AutoFilter() | Out-Null
$headerRange.font.bold=$True

Get-View -ViewType VirtualMachine -Property Name, Runtime.Host,Config.Hardware, Guest.Disk ,Summary, Config.Hardware , Network , Guest | Where {-not $_.Config.Template} | %{
$row++
$col=1
#"VM_Name"
$serverInfoSheet.Cells.Item($row,1)=$_.Summary.Config.Name
#"VM_DNS_Name"
$serverInfoSheet.Cells.Item($row,2)=$_.Guest.HostName
if($ip = ($_.Guest | %{$_.IpAddress})){
#"VM_IP"

$serverInfoSheet.Cells.Item($row,3) = [string]::Join(',',$ip)
}
if(($mac = $_.Guest.Net | %{$_.MacAddress})){
#"VM_MAC"

$serverInfoSheet.Cells.Item($row,4) = [string]::Join(',',$mac)
}
#
$esx = Get-View $_.Runtime.Host -Property Name,Hardware.SystemInfo.Model,Parent

#"VM_OS"
$serverInfoSheet.Cells.Item($row,5)=$_.Summary.Config.GuestFullName

#"VM_OSFamily"
$serverInfoSheet.Cells.Item($row,6)=$_.Summary.Config.GuestId
#$serverInfoSheet.Cells.Item($Row,$col).NumberFormat="0.00%"

#"VM_HOST"
$serverInfoSheet.Cells.Item($row,7)=$esx.Name
#$serverInfoSheet.Cells.Item($Row,$col).NumberFormat="0.00"

#"VM_vCpu"
$serverInfoSheet.Cells.Item($row,8)=$_.Summary.Config.numCPU

#"VM_Memory"
$memory = $_.Summary.Config.MemorySizeMB
$serverInfoSheet.Cells.Item($row,9).FormulaR1C1=("=IF($memory<1024,($memory & "" MB""),($memory/1024 & "" GB""))")

#"CustomAttrib"
$serverInfoSheet.Cells.Item($row,10).FormulaR1C1=(="CustomAttrib"

#"VM_Network_Cards"
$serverInfoSheet.Cells.Item($row,11)=$_.Summary.Config.NumEthernetCards

#"VM_Disks"
$serverInfoSheet.Cells.Item($row,12)=$_.Summary.Config.NumVirtualDisks

#$hdpath = ($_.Guest.Disk | Select DiskPath)
if($Partition = ($_.Guest.Disk | %{$_.DiskPath})){

$serverInfoSheet.Cells.Item($row,13) = [string]::Join(',',$Partition)
}
#$serverInfoSheet.Cells.Item($Row,13) = $_.Guest.Disk | Select DiskPath
#if($Capacity = ($_.Guest.Disk | %{$_.Capacity})){

#$serverInfoSheet.Cells.Item($Row,14) = [math]::Round(',',$Capacity)
#The below line works will vmtools installed on all guests
#$serverInfoSheet.Cells.Item($row,14).FormulaR1C1="=$Capacity/1024/1024/1024"
$serverInfoSheet.Cells.Item($row,14).FormulaR1C1=($_.Summary.Storage.Committed/1024/1024/1024)
$serverInfoSheet.Cells.Item($row,14).NumberFormat="0"
#}
#$serverInfoSheet.Cells.Item($Row,14) = $_.Guest.Disk | Select Capacity
#if($freespace = ($_.Guest.Disk | %{$_.FreeSpace})){

#$serverInfoSheet.Cells.Item($Row,15) = [string]::Join(',',$freespace)
#$serverInfoSheet.Cells.Item($row,15).FormulaR1C1="=$freespace/1024/1024/1024"
$serverInfoSheet.Cells.Item($row,15).FormulaR1C1=($_.Summary.Storage.Uncommitted/1024/1024/1024)
$serverInfoSheet.Cells.Item($row,15).NumberFormat="0"
#}

#"VM_VMX_Location"
$serverInfoSheet.Cells.Item($row,16)=$_.Summary.Config.VmPathName
#$serverInfoSheet.Cells.Item($Row,$col).NumberFormat="0.00%"

#"VM Datastore (location of vmx)
$Mid="=MID(RC[-1],FIND(""["",RC[-1])+1,FIND(""]"",RC[-1])-FIND(""["",RC[-1])-1)"
$serverInfoSheet.Cells.Item($row,17).FormulaR1C1 = $Mid

#"VM_Notes"

$serverInfoSheet.Cells.Item($row,18)=$_.Summary.Config.Annotation

}

$usedRange = $serverInfoSheet.UsedRange
$usedRange.EntireColumn.AutoFit() | Out-Null

$row--
$dataRange = $serverInfoSheet.Range(("A{0}" -f $initalRow),("P{0}" -f $row))
7..12 | ForEach {
$dataRange.Borders.Item($_).LineStyle = 1
$dataRange.Borders.Item($_).Weight = 1
}

#$serverInfoSheet.ActiveCell.FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R[-2]C[-6]:R[18]C[-6],'Dashboard'!RC[-1])"
#$serverInfoSheet.ActiveCell.FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R4C7:R24C7,'Dashboard'!RC[-1])"
#$serverInfoSheet.Selection.AutoFill Destination:=Range("M6:M7"), Type:=xlFillDefault
#$serverInfoSheet.Range("M6:M7").Select
#$serverInfoSheet.Range("O6").Select
#$serverInfoSheet.ActiveSheet.Shapes.AddChart.Select
#$serverInfoSheet.ActiveChart.ChartType = xlColumnClustered
#$serverInfoSheet.ActiveChart.SetSourceData Source:=Range("L6:M7")

#$lastRow = row

#Connect to first worksheet to rename and make active
$serverInfoSheet3 = $workbook.Worksheets.Item(3)
$serverInfoSheet3.Activate() | Out-Null

$RowX = 2

Get-View -ViewType HostSystem -Property Name,Hardware | %{
$RowX++
#$col = 12
$serverInfoSheet3.Cells.Item(2,2)= 'vSphere Host List'
$serverInfoSheet3.Cells.Item(2,3)= 'Number of Guests'
$serverInfoSheet3.Cells.Item(2,4)= 'Vendor'
$serverInfoSheet3.Cells.Item(2,5)= 'Model'
$serverInfoSheet3.Cells.Item(2,6)= 'No. CPU(s)'
$serverInfoSheet3.Cells.Item(2,7)= 'NO. Cores'
$serverInfoSheet3.Cells.Item(2,8)= 'Memory Size GB'

$serverInfoSheet3.Cells.Item($RowX,2)=$_.Name
$serverInfoSheet3.Cells.Item($RowX,3).FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R[1]C[4]:R3389C[4],'Host and Datastore'!RC[-1])"
$serverInfoSheet3.Cells.Item($RowX,4)=$_.Hardware.SystemInfo.Vendor
$serverInfoSheet3.Cells.Item($RowX,5)=$_.Hardware.SystemInfo.Model
$serverInfoSheet3.Cells.Item($RowX,6)=$_.Hardware.CpuInfo.NumCpuPackages
$serverInfoSheet3.Cells.Item($RowX,7)=$_.Hardware.CpuInfo.NumCpuCores

if($HostMem = ($_.Hardware | %{$_.MemorySize})){

$serverInfoSheet3.Cells.Item($RowX,8).FormulaR1C1="=$HostMem/1024/1024/1024"
$serverInfoSheet3.Cells.Item($RowX,8).NumberFormat="0"
}
$lasthostchartrange = $Rowx

}

$RowY = 1
Get-View -ViewType Datastore -Property Name,Summary | %{
$RowY++
#$col = 12
$serverInfoSheet3.Cells.Item(2,12)= 'Datastore Name'
$serverInfoSheet3.Cells.Item(2,13)= 'Size (GB)'
$serverInfoSheet3.Cells.Item(2,14)= 'Free Space (GB)'
$serverInfoSheet3.Cells.Item(2,15)= 'No. VM(s)'
$serverInfoSheet3.Cells.Item($RowY,12)=$_.Name
if($dstoreCapacity = ($_.Summary | %{$_.Capacity})){

#$serverInfoSheet.Cells.Item($Row,14) = [math]::Round(',',$Capacity)
$serverInfoSheet3.Cells.Item($RowY,13).FormulaR1C1="=$dstoreCapacity/1024/1024/1024"
$serverInfoSheet3.Cells.Item($RowY,13).NumberFormat="0"
}

if($dstorefree = ($_.Summary | %{$_.FreeSpace})){

#$serverInfoSheet.Cells.Item($Row,14) = [math]::Round(',',$Capacity)
$serverInfoSheet3.Cells.Item($RowY,14).FormulaR1C1="=$dstorefree/1024/1024/1024"
$serverInfoSheet3.Cells.Item($RowY,14).NumberFormat="0"
}

$serverInfoSheet3.Cells.Item($RowY,15).FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R[1]C[2]:R[3389]C[2],'Host and Datastore'!RC[-3])"

$lastdatastorechartrange=$RowY
}

#Connect to first worksheet to rename and make active
$serverInfoSheet2 = $workbook.Worksheets.Item(1)
$serverInfoSheet2.Activate() | Out-Null

#$chart.SeriesCollection(1).DataLabels().Position = 2
#$serverInfoSheet3.ActiveSheet.Shapes.AddChart.Select
#$serverInfoSheet3.ActiveChart.ChartType = xlColumnClustered
#$serverInfoSheet3.ActiveChart.SetSourceData Source:=Range("L5:M30")

#Calculate Collected Statistics for OS Type Spread

#Build Heading
$serverInfoSheet3.Cells.Item(2,18)="GUEST OS"
$serverInfoSheet3.Cells.Item(2,19)="Number"
#Make Bold
$headerRange = $serverInfoSheet3.Range("A1","X2")
#$headerRange.AutoFilter() | Out-Null
$headerRange.font.bold=$True
$headerRange.EntireColumn.AutoFit() | Out-Null

$serverInfoSheet3.Cells.Item(3,18)="Microsoft Windows"
$serverInfoSheet3.Cells.Item(3,19).FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R4C5:R3889C5,""*Windows*"")"

$serverInfoSheet3.Cells.Item(4,18)="Ubuntu"
$serverInfoSheet3.Cells.Item(4,19).FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R4C5:R3889C5,""*Ubuntu*"")"

$serverInfoSheet3.Cells.Item(5,18)="RedHat"
$serverInfoSheet3.Cells.Item(5,19).FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R4C5:R3889C5,""*Red*Hat*"")"

$serverInfoSheet3.Cells.Item(6,18)="FreeBSD"
$serverInfoSheet3.Cells.Item(6,19).FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R4C5:R3889C5,""*Free*BSD*"")"

$serverInfoSheet3.Cells.Item(7,18)="Solaris"
$serverInfoSheet3.Cells.Item(7,19).FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R4C5:R3889C5,""*Solaris*"")"

$serverInfoSheet3.Cells.Item(8,18)="Other"
$serverInfoSheet3.Cells.Item(8,19).FormulaR1C1 = "=COUNTIF('VM-Guest Info'!R4C5:R3889C5,""*Other*"")"

$chartRange = $serverInfoSheet3.Range(("R2:S8"))

#Chart formula
##Add a chart to the workbook
#Open a sheet for charts
$temp = $excel.Charts.Add()
$temp.Delete()
$chart = $serverInfoSheet2.Shapes.AddChart().Chart
$serverInfoSheet3.Activate()

$chartRangeHost = $serverInfoSheet3.Range(("B2:C$lasthostchartrange"))
$charthost = $serverInfoSheet2.Shapes.AddChart().Chart
$charthost.ChartType = -4100
$charthost.SetSourceData($chartRangeHost)
$charthost.HasTitle = $True
$charthost.ChartTitle.Text = "Host Guest Distribution"
$charthost.ChartObjects("Chart2").Activate
$charthost.ApplyLayout(5) | out-Null
$charthost.ChartStyle = 48
$charthost.SeriesCollection(1).ApplyDataLabels() | out-Null
#$charthost.SeriesCollection(1).DataLabels().ShowValue = $True
#$charthost.SeriesCollection(1).DataLabels().Separator = ("{0}" -f [char]10)
#$charthost.SeriesCollection(1).DataLabels().Position = 2

#Datastore Chart
$chartRangedatastore = $serverInfoSheet3.Range(("L2:O$lastdatastorechartrange"))
$chartdatastore = $serverInfoSheet2.Shapes.AddChart().Chart
$chartdatastore.ChartType = 92
$chartdatastore.SetSourceData($chartRangedatastore)
$chartdatastore.HasTitle = $True
$chartdatastore.ChartTitle.Text = "Datastore at a glance"
$chartdatastore.ChartObjects("Chart3").Activate
$chartdatastore.ApplyLayout(5) | out-Null
$chartdatastore.ChartStyle = 42
$chartdatastore.SeriesCollection(1).ApplyDataLabels() | out-Null
$chartdatastore.SeriesCollection(2).ApplyDataLabels() | out-Null
$chartdatastore.SeriesCollection(3).ApplyDataLabels() | out-Null
#$chartdatastore.SeriesCollection(1).DataLabels().Separator = ("{0}" -f [char]10)
#$chartdatastore.SeriesCollection(1).DataLabels().Position = 2

#Configure the chart for OS Type Spread
##Use a 3D Pie Chart
$chart.ChartType = 92
$chart.Elevation = 7
$charthost.Elevation = 7
$chartdatastore.Elevation = 7

#Give it some color
#$serverInfoSheet2.Shapes.Item("Chart 2").Fill.ForeColor.TintAndShade = .34
#$serverInfoSheet2.Shapes.Item("Chart 2").Fill.ForeColor.ObjectThemeColor = 5
#$serverInfoSheet2.Shapes.Item("Chart 2").Fill.BackColor.TintAndShade = .765
#$serverInfoSheet2.Shapes.Item("Chart 2").Fill.ForeColor.ObjectThemeColor = 5
#$serverInfoSheet2.Shapes.Item("Chart 2").Fill.TwoColorGradient(1,1)

#Set the location and size of the chart(s)
$serverInfoSheet2.Shapes.Item("Chart 1").Placement = 3
$serverInfoSheet2.Shapes.Item("Chart 1").Top = 30
$serverInfoSheet2.Shapes.Item("Chart 1").Left = 100
$serverInfoSheet2.Shapes.Item("Chart 1").Width = 600
$serverInfoSheet2.Shapes.Item("Chart 1").Height = 200

$serverInfoSheet2.Shapes.Item("Chart 2").Placement = 3
$serverInfoSheet2.Shapes.Item("Chart 2").Top = 240
$serverInfoSheet2.Shapes.Item("Chart 2").Left = 100
$chart2width = ($lasthostchartrange*110)
$serverInfoSheet2.Shapes.Item("Chart 2").Width = $chart2width
$serverInfoSheet2.Shapes.Item("Chart 2").Height = 300

$serverInfoSheet2.Shapes.Item("Chart 3").Placement = 3
$serverInfoSheet2.Shapes.Item("Chart 3").Top = 550
$serverInfoSheet2.Shapes.Item("Chart 3").Left = 100
$chart3width = ($lastdatastorechartrange*140)
$serverInfoSheet2.Shapes.Item("Chart 3").Width = $chart3width
$serverInfoSheet2.Shapes.Item("Chart 3").Height = 450

$chart.SetSourceData($chartRange)
$chart.HasTitle = $True

$chart.ApplyLayout(5) | out-Null
$chart.ChartTitle.Text = "OS Type Spread"
$chart.ChartStyle = 42
#$chart.PlotVisibleOnly = $False
$chart.SeriesCollection(1).ApplyDataLabels() | out-Null
#$chart.SeriesCollection(1).DataLabels().ShowValue = $True
#$chart.SeriesCollection(1).DataLabels().Separator = ("{0}" -f [char]10)

#$chart.SeriesCollection(1).DataLabels().Position = 2
#Critical
#$chart.SeriesCollection(1).Points(1).Format.Fill.ForeColor.RGB = 255
#Warning
#$chart.SeriesCollection(1).Points(2).Format.Fill.ForeColor.RGB = 65535
#Good
#$chart.SeriesCollection(1).Points(3).Format.Fill.ForeColor.RGB = 5287936

#Hide the data
#$chartRange.EntireRow.Hidden = $True

#
Disconnect-VIServer * -Confirm:$false

#Connect to first worksheet to make active
$serverInfoSheet2 = $workbook.Worksheets.Item(1)
$serverInfoSheet2.Activate() | Out-Null

$serverInfoSheet2.Cells.Item(4,17).FormulaR1C1= "=""$vcentername1 "" & ""$vcentername2 "" & ""$vcentername3 "" & ""$vcentername4 "" & ""$vcentername5 "" & ""$vcentername6 "" & ""$vcentername7"""
$sheet1titlerange = $serverInfoSheet2.Range("q4","u4")
$sheet1titlerange.Merge() | Out-Null
$sheet1titlerange.Style = 'Heading 1'

#Release COM Object
[System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$excel) | Out-Null


So whilst this code works fine, it is a bit slower than I would like, and I would like to port to a html document rather than to excel.
But this will suffice for the moment.

Advertisements