I am trying to design a VBA script that will export values from an Excel spreadsheet to a CSV file. This will be used for deployment of multiple Virtual Machines by a separate Powershell script.
Currently the Export to CSV operation is handling one single VM name per cell and the corresponding settings however, in the actual execution of the script we may have multiple VM names in a single cell (separated by a comma) but will have the same settings in the proceeding cells.
What I would like to know is whether it is possible/how to go about having those values in that cell that are separated by a comma populate a separate line but still have the settings under the appropriate headings within the CSV file.
The code:
Function BuildValuesString(colIndex As String, rows As String) As String
Dim val As Variant
For Each val In Split(rows, ",")
If Cells(val, colIndex) <> "" Then BuildValuesString = BuildValuesString & Cells(val, colIndex).Value & ","
Next val
End Function
Function BuildNullStrings(numNullStrings As Long) As String
Dim iNullStrings As Long
For iNullStrings = 1 To numNullStrings
BuildNullStrings = BuildNullStrings & "" & ","
Next iNullStrings
End Function
Sub WriteCSVFile2()
Dim My_filenumber As Integer
Dim logSTR As String
My_filenumber = FreeFile
logSTR = logSTR & "Srv. Descr." & ","
logSTR = logSTR & "E-mail" & ","
logSTR = logSTR & "Env." & ","
logSTR = logSTR & "Prot. Level" & ","
logSTR = logSTR & "DataC" & ","
logSTR = logSTR & "# VMs" & ","
logSTR = logSTR & "Name" & ","
logSTR = logSTR & "Cluster" & ","
logSTR = logSTR & "VLAN" & ","
logSTR = logSTR & "NumCPU" & ","
logSTR = logSTR & "MemoryGB" & ","
logSTR = logSTR & "C_System" & ","
logSTR = logSTR & "D_Homevg" & ","
logSTR = logSTR & "App_eHealth" & ","
logSTR = logSTR & "TotalDisk" & ","
logSTR = logSTR & "Datastore" & ","
logSTR = logSTR & "Template" & ","
logSTR = logSTR & Chr(13)
logSTR = logSTR & BuildValuesString("C", "18,19,20,21,22,26,27,28,29,30,31,32,33,34")
logSTR = logSTR & TotalIt(Range("C32:C33"))
logSTR = logSTR & Chr(13)
logSTR = logSTR & BuildNullStrings(5)
logSTR = logSTR & BuildValuesString("C", "18,19,20,21,22,37,38,39,40,41,42,43,44,46")
logSTR = logSTR & TotalIt(Range("C43:C44"))
logSTR = logSTR & Chr(13)
logSTR = logSTR & BuildNullStrings(5)
logSTR = logSTR & BuildValuesString("C", "18,19,20,21,22,48,49,50,51,52,53,54,55,58")
logSTR = logSTR & TotalIt(Range("C54:C55"))
Open "Z:\Operational Env. Requests16\Requests(Test)\" & ThisWorkbook.Name & ".csv" For Append As #My_filenumber
Print #My_filenumber, logSTR
Close #My_filenumber
End Sub
Function TotalIt(rng As Range)
Dim c, arr, t, rv As Double, v
For Each c In rng.Cells
If Len(c.Value) > 0 Then
arr = Split(c.Value, ",")
For Each v In arr
If IsNumeric(v) Then rv = rv + v
Next v
Exit For
End If
Next c
TotalIt = rv
End Function
I.E.
If cell C:27 has “VM1, VM2, VM3”, separate each value on a different line but still input values associated with the other headers.
Currently the VBA script would input the values as:
Name Cluster VLAN NumCPU MemoryGB
VM1 VM2 VM3 VMCluster VLAN1 etc.
What I would like it to do is
Name Cluster VLAN
VM1 VMCluster VLAN1
VM2 VMCluster VLAN1
VM3 VMCluster VLAN1
It messes up the alignment completely if I attempt to execute the VBA script in its current format. I was hoping to get some help on how I could go about achieving the desired results.
Thank you for any assistance you may provide
This is radically oversimplified, but based on your simplified example of Name, Cluster and VLAN in columns A-C, this would take that and split the output to a CSV.
Sub SplitToCsv()
Dim rw, lastRow As Long
Dim ws As Worksheet
Dim vms, vm, rowData As Variant
Set ws = Sheets("Sheet1")
lastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
Open "C:\test.csv" For Output As #1
For rw = 1 To lastRow
vms = Split(ws.Cells(rw, 1).Value2, ",")
For Each vm In vms
Print #1, Join(Array(vm, ws.Cells(rw, 2).Value2, ws.Cells(rw, 3).Value2), ",")
Next vm
Next rw
Close #1
End Sub
This would take this as an input:
Name Cluster VLAN
VM1,VM2,VM3 VMCluster VLAN1
VM4 VMCluster2 VLAN2
VM5,VM6 VMCluster3 VLAN3
And turn it into a file that looks like this:
Name,Cluster,VLAN
VM1,VMCluster,VLAN1
VM2,VMCluster,VLAN1
VM3,VMCluster,VLAN1
VM4,VMCluster2,VLAN2
VM5,VMCluster3,VLAN3
VM6,VMCluster3,VLAN3
— EDIT 1/3/2017 —
I think I get it now. This is a slimmed-down / refactored version of your code. I could be wrong, but I believe this is what you’re trying to do:
Sub WriteCSVFile2()
Dim My_filenumber As Integer
Dim header, line As String
Dim values, vlan, names As Variant
Dim row As Integer
My_filenumber = FreeFile
Open "c:\cdh\" & ThisWorkbook.Name & ".csv" For Append As #My_filenumber
Print #My_filenumber, Join(Array("Srv. Descr.", "E-mail", "Env.", _
"Prot. Level", "DataC", "# VMs", "Name", "Cluster", "VLAN", _
"NumCPU", "MemoryGB", "C_System", "D_Homevg", "App_eHealth", _
"TotalDisk", "Datastore", "Template"), ",")
header = Join(Application.Transpose(Range("C18:C22").Value), ",")
For row = 26 To 50 Step 12
values = Application.Transpose(Range("C" & row & ":C" & row + 8).Value)
names = values(2)
For Each vlan In Split(names, ",")
values(2) = vlan
line = Join(values, ",")
Print #My_filenumber, header & "," & line
Next vlan
Next row
' TotalIt(Range("C54:C55"))
Close #My_filenumber
End Sub
Some notes:
– I commented out TotalIt
just because I assume it works and wasn’t focused on that part
– Your code looked at rows 26, 37, 48 but the spreadsheet actually had the references at 26, 38, 50 (one additional row). My code reflects the latter
I think the smaller code base will be easier to debug and hopefully more scalable, if you ever add more config options.
Here is my output:
Srv. Descr.,E-mail,Env.,Prot. Level,DataC,# VMs,Name,Cluster,VLAN,...
Service,Email,Environment,Protection,Data Center,,VM1,VMCluster,VLAN1 etc.,,,,,
Service,Email,Environment,Protection,Data Center,,VM2,VMCluster,VLAN1 etc.,,,,,
Service,Email,Environment,Protection,Data Center,,VM3,VMCluster,VLAN1 etc.,,,,,
Tags: csv, excelexcel