It is not difficult to generate a new workbook using Excel VBA. And there are tons of materials in internet that can teach you how to achieve it. Today I will present something more advanced – how to generate a new workbook that contains a VBA macro using VBA?

Enable Trust Access to VBA Project Object Model

Click on File -> Options to open Excel Optional dialogue. In the navigation pane, select Trust Center -> Trust Center Settings, Trust Center dialogue will be prompted. In the Navigation pane of Trust Center dialogue, click on Macro Settings and then check box before “Trust access to the VBA project object model” and then click OK.

Add Reference Libraries

Press Alt + F9 to get Visual Basic Editor (VBE). Click on Tools -> References to open References – VBAProject dialogue and check box for Microsoft Visual Basic for Applications Extensibility 5.3. Click OK button on the top-right corner to add this reference in your excel file.

Write VBA code into VBE

Though we have named the new worksheet in new workbook as “Test”. We still need to use “Sheet1” in this code Set VBComp = VBProj.VBComponents(“Sheet1”) in order to make the worksheet_change event work.

Sub Generate_Test()

Application.DisplayAlerts = False

Dim MainWB As Workbook
Set MainWB = Workbooks.Add

'Create New Workbook and New Worksheet
MainWB.Worksheets(1).Name = "Test"
With MainWB.Worksheets(1)
  .Range("D1:F1").Font.Name = "Arial"
  .Range("D1:F1").Font.Color = RGB(0, 0, 0)
  .Range("D1:F1").Font.Bold = True
  .Range("D1:F10").Borders.Color = RGB(0, 0, 0)
  .Range("D1:F1").Interior.Color = RGB(217, 217, 217)
  .Range("D1:F1").HorizontalAlignment = xlCenter
  .Range("D1:F1").Font.Name = "Arial"
  
  .Range("D1") = "Red"
  .Range("E1") = "Green"
  .Range("F1") = "Blue"
  
  For i = 2 To 10
    .Range("D" & i) = i * 10
    .Range("E" & i) = i + 1
    .Range("F" & i) = (i + 2) * 10
  Next
  
  .Range("A1") = "Column Name"
  .Range("A1").Font.Color = RGB(0, 0, 0)
  .Range("A1").Font.Bold = True
  .Range("A1:A2").Borders.Color = RGB(0, 0, 0)
  .Range("A1").Interior.Color = RGB(217, 217, 217)
  .Range("A1").HorizontalAlignment = xlCenter
  .Range("A1").Font.Name = "Arial"
  .Range("A1").ColumnWidth = 15

  'Add data validation for cell A1
  .Range("A2").Select
  With Selection.Validation
    .Delete
    .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
    xlBetween, Formula1:="Red, Green, Blue"
    .IgnoreBlank = True
    .InCellDropdown = True
    .InputTitle = "Column Name"
    .ErrorTitle = ""
    .InputMessage = ""
    .ErrorMessage = ""
    .ShowInput = True
    .ShowError = True
   End With
End With

'Add VBA code
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim CodeMod As VBIDE.CodeModule
Dim LineNum As Long
Const DQUOTE = """" ' one " character

Set VBProj = MainWB.VBProject
Set VBComp = VBProj.VBComponents("Sheet1")

Set CodeMod = VBComp.CodeModule

With CodeMod
    LineNum = .CountOfLines + 1
    .InsertLines LineNum, "Private Sub Worksheet_Change(ByVal Target As Range)"
    LineNum = LineNum + 1
    .InsertLines LineNum, "  Dim KeyCells As Range"
    LineNum = LineNum + 1
    .InsertLines LineNum, "  If Target.Address =" & DQUOTE & "$A$2" & DQUOTE & "Then"
    LineNum = LineNum + 1
    .InsertLines LineNum, "     Set KeyCells = Range(" & DQUOTE & "A2" & DQUOTE & " )"
    LineNum = LineNum + 1
    .InsertLines LineNum, "     Call Column_Click"
    LineNum = LineNum + 1
    .InsertLines LineNum, "  Else"
    LineNum = LineNum + 1
    .InsertLines LineNum, "     Exit Sub"
    LineNum = LineNum + 1
    .InsertLines LineNum, "  End If"
    LineNum = LineNum + 1
    .InsertLines LineNum, "End Sub"
    LineNum = LineNum + 1
    .InsertLines LineNum, "Sub Column_Click"
    LineNum = LineNum + 1
    .InsertLines LineNum, "     Value = Trim(ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$A$2" & DQUOTE & ").Value)"
    LineNum = LineNum + 1
    .InsertLines LineNum, "     If strComp(Value, " & DQUOTE & "Red" & DQUOTE & ")" & "= 0 Then"
    LineNum = LineNum + 1
    .InsertLines LineNum, "        For i = 2 to 10"
    LineNum = LineNum + 1
    .InsertLines LineNum, "            If ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$D$" & DQUOTE & " & i).Value mod 3 = 0 then "
    LineNum = LineNum + 1
    .InsertLines LineNum, "               ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$D$" & DQUOTE & " & i).Font.Color = RGB(255, 0, 0) "
    LineNum = LineNum + 1
    .InsertLines LineNum, "               ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$D$" & DQUOTE & " & i).Font.Bold = True "
    LineNum = LineNum + 1
    .InsertLines LineNum, "            End If "
    LineNum = LineNum + 1
    .InsertLines LineNum, "        Next "
    LineNum = LineNum + 1
    .InsertLines LineNum, "     ElseIf strComp(Value, " & DQUOTE & "Green" & DQUOTE & ")" & "= 0 Then"
    LineNum = LineNum + 1
    .InsertLines LineNum, "        For j = 2 to 10"
    LineNum = LineNum + 1
    .InsertLines LineNum, "            If ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$E$" & DQUOTE & " & j).Value mod 3 = 0 then "
    LineNum = LineNum + 1
    .InsertLines LineNum, "               ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$E$" & DQUOTE & " & j).Font.Color = RGB(0, 255, 0) "
    LineNum = LineNum + 1
    .InsertLines LineNum, "               ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$E$" & DQUOTE & " & j).Font.Bold = True "
    LineNum = LineNum + 1
    .InsertLines LineNum, "            End If "
    LineNum = LineNum + 1
    .InsertLines LineNum, "        Next "
    LineNum = LineNum + 1
    .InsertLines LineNum, "     Else"
    LineNum = LineNum + 1
    .InsertLines LineNum, "        For k = 2 to 10"
    LineNum = LineNum + 1
    .InsertLines LineNum, "            If ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$F$" & DQUOTE & " & k).Value mod 3 = 0 then "
    LineNum = LineNum + 1
    .InsertLines LineNum, "               ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$F$" & DQUOTE & " & k).Font.Color = RGB(0, 0, 255) "
    LineNum = LineNum + 1
    .InsertLines LineNum, "               ThisWorkbook.Worksheets(1).Range(" & DQUOTE & "$F$" & DQUOTE & " & k).Font.Bold = True "
    LineNum = LineNum + 1
    .InsertLines LineNum, "            End If "
    LineNum = LineNum + 1
    .InsertLines LineNum, "        Next "
    LineNum = LineNum + 1
    .InsertLines LineNum, "     End If "
    LineNum = LineNum + 1
    .InsertLines LineNum, "End Sub "
End With


MainWB.Worksheets(1).Activate
MainWB.SaveAs Filename:="D:\Test\Sample.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled
MainWB.Save
MainWB.Close SaveChanges:=True

End Sub

Generate New Work

By clicking on “Generated Sample” button showed above, a new excel file called “Sample” will be created. The extension of this newly created excel file is “XLSM”.

Here are the code written into this excel file by above VBA code.

Private Sub Worksheet_Change(ByVal Target As Range)
  Dim KeyCells As Range
  If Target.Address = "$A$2" Then
     Set KeyCells = Range("A2")
     Call Column_Click
  Else
     Exit Sub
  End If
End Sub
Sub Column_Click()
     Value = Trim(ThisWorkbook.Worksheets(1).Range("$A$2").Value)
     If StrComp(Value, "Red") = 0 Then
        For i = 2 To 10
            If ThisWorkbook.Worksheets(1).Range("$D$" & i).Value Mod 3 = 0 Then
               ThisWorkbook.Worksheets(1).Range("$D$" & i).Font.Color = RGB(255, 0, 0)
               ThisWorkbook.Worksheets(1).Range("$D$" & i).Font.Bold = True
            End If
        Next
     ElseIf StrComp(Value, "Green") = 0 Then
        For j = 2 To 10
            If ThisWorkbook.Worksheets(1).Range("$E$" & j).Value Mod 3 = 0 Then
               ThisWorkbook.Worksheets(1).Range("$E$" & j).Font.Color = RGB(0, 255, 0)
               ThisWorkbook.Worksheets(1).Range("$E$" & j).Font.Bold = True
            End If
        Next
     Else
        For k = 2 To 10
            If ThisWorkbook.Worksheets(1).Range("$F$" & k).Value Mod 3 = 0 Then
               ThisWorkbook.Worksheets(1).Range("$F$" & k).Font.Color = RGB(0, 0, 255)
               ThisWorkbook.Worksheets(1).Range("$F$" & k).Font.Bold = True
            End If
        Next
     End If
End Sub