987 строки
47 KiB
VB.net
987 строки
47 KiB
VB.net
Option Explicit
|
|
Option Base 0
|
|
Private Declare PtrSafe Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" (ByVal pCaller As Long, ByVal szURL As String, ByVal szFileName As String, ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
|
|
|
|
'Constants
|
|
Const row1 = 10
|
|
Const technology_selection_row = 2
|
|
Const technology_selection_col = 7
|
|
Const language_selection_row = technology_selection_row
|
|
Const language_selection_col = technology_selection_col + 1
|
|
Const checklist_name_row = 6
|
|
Const checklist_name_col = 2
|
|
Const checklist_state_row = checklist_name_row + 1
|
|
Const checklist_state_col = checklist_name_col
|
|
Const checklist_timestamp_row = checklist_state_row + 1
|
|
Const checklist_timestamp_col = checklist_name_col + 1
|
|
Const line_break = vbCrLf
|
|
Const id_column = 1
|
|
Const category_column = id_column + 1
|
|
Const subcategory_column = category_column + 1
|
|
Const waf_column = subcategory_column + 1
|
|
Const text_column = waf_column + 1
|
|
Const description_column = text_column + 1
|
|
Const severity_column = description_column + 1
|
|
Const status_column = severity_column + 1
|
|
Const comments_column = status_column + 1
|
|
Const link_column = comments_column + 1
|
|
Const training_column = link_column + 1
|
|
Const graph_column = training_column + 1
|
|
Const guid_column = graph_column + 1
|
|
Const sec_mod_column = guid_column + 1
|
|
Const cost_mod_column = sec_mod_column + 1
|
|
Const scale_mod_column = cost_mod_column + 1
|
|
Const simple_mod_column = scale_mod_column + 1
|
|
Const ha_mod_column = simple_mod_column + 1
|
|
Const num_columns = ha_mod_column
|
|
Const values_sheet = "values"
|
|
Const values_sev_column = 1
|
|
Const values_status_column = 2
|
|
Const values_status_description_column = 8
|
|
Const values_category_column = 3
|
|
Const values_technology_selection_column = 6
|
|
Const values_language_selection_column = 7
|
|
Const values_technology_prefix_column = 10
|
|
Const values_language_prefix_column = 11
|
|
Const values_waf_column = 12
|
|
Const row_limit = 2000 'Safety net
|
|
Const user_info_guid_index = 1
|
|
Const user_info_comments_index = 2
|
|
Const user_info_status_index = 3
|
|
|
|
'Global variables
|
|
Dim user_checks() As String 'To hold the user's comments/status
|
|
Dim selected_language As String
|
|
Dim selected_technology As String
|
|
Dim import_graph_queries As Boolean
|
|
|
|
'Modifies text so that it can be stored in JSON format
|
|
' * Removes line breaks (chr10 and chr13)
|
|
' * Replaces doublequotes with single quotes
|
|
' * Eliminates blanks (replaces with  )
|
|
Function correct_format_for_JSON(ByVal input_text As String) As String
|
|
'Remove breaks
|
|
input_text = Replace(Replace(input_text, Chr(10), ""), Chr(13), "")
|
|
'Replace double quotes with single quotes
|
|
input_text = Replace(input_text, Chr(34), Chr(39))
|
|
'If it is a link, remove localization
|
|
input_text = Replace(input_text, "en-us/", "")
|
|
'Escape control characters such as "?"
|
|
'input_text = escape_character(input_text, "?")
|
|
input_text = escape_character(input_text, "\")
|
|
input_text = escape_character(input_text, "\", False) 'Second escaping to turn '\' into '\\\\'
|
|
'Avoid empty fields, the Azure translate API doesnt work well with then
|
|
If input_text = "" Then input_text = " "
|
|
correct_format_for_JSON = input_text
|
|
End Function
|
|
|
|
'Escapes a character in a string, and gives out the resulting string
|
|
Function escape_character(ByVal input_text As String, search_char As String, Optional unescape_first As Boolean = True) As String
|
|
'First we remove any possible escape signs for that character that might be already there
|
|
If unescape_first Then
|
|
input_text = Replace(input_text, "\" + search_char, search_char)
|
|
End If
|
|
'Now we escape all occurrences of the character
|
|
input_text = Replace(input_text, search_char, "\" + search_char)
|
|
'And return the output
|
|
escape_character = input_text
|
|
End Function
|
|
|
|
'Exports current checklist from excel to a json-formated text file
|
|
Sub export_json()
|
|
On Error GoTo errh
|
|
' Constants
|
|
Const export_file_name = "checklist.json"
|
|
' Variables
|
|
Dim row As Integer
|
|
Dim json As String
|
|
Dim check_id As String, check_category As String, check_subcategory As String, check_waf As String, check_text As String, check_description As String, check_severity As String, check_status As String, status_description As String, check_link As String, check_training As String, check_graph_query As String, check_guid As String
|
|
Dim check_sec_mod, check_cost_mod, check_scale_mod, check_simple_mod, check_ha_mod
|
|
Dim category_name As String, severity_name As String, status_name As String, waf_name As String
|
|
Dim export_file_path As Variant
|
|
Dim double_quote As String
|
|
Dim item_count As Integer, category_count As Integer, status_count As Integer
|
|
Dim cat_id As Integer, rel_subcat_id As Integer, rel_item_id As Integer
|
|
' Initialization
|
|
double_quote = Chr(34) ' double quote as a variable
|
|
row = row1
|
|
json = "{" + line_break
|
|
json = json + " " + double_quote + "items" + double_quote + ": ["
|
|
item_count = 0
|
|
category_count = 0
|
|
status_count = 0
|
|
cat_id = 0
|
|
rel_subcat_id = 0
|
|
rel_item_id = 0
|
|
check_category = ""
|
|
check_subcategory = ""
|
|
' Loop through all rows as long as there is content
|
|
Do While row < row_limit And Len(Cells(row, category_column)) > 0
|
|
If row > row1 Then json = json + ","
|
|
json = json + line_break
|
|
'Update ID counters
|
|
If Cells(row, category_column) <> check_category Then
|
|
'New category
|
|
cat_id = cat_id + 1
|
|
rel_subcat_id = 1
|
|
rel_item_id = 1
|
|
Else
|
|
'New subcategory
|
|
If Cells(row, subcategory_column) <> check_subcategory Then
|
|
rel_subcat_id = rel_subcat_id + 1
|
|
rel_item_id = 1
|
|
Else
|
|
'Same category and subcategory
|
|
rel_item_id = rel_item_id + 1
|
|
End If
|
|
End If
|
|
'Get values
|
|
check_id = Cells(row, id_column)
|
|
check_category = Cells(row, category_column)
|
|
check_subcategory = Cells(row, subcategory_column)
|
|
check_waf = Cells(row, waf_column)
|
|
check_text = Cells(row, text_column)
|
|
check_description = Cells(row, description_column)
|
|
check_severity = Cells(row, severity_column)
|
|
check_graph_query = Cells(row, graph_column)
|
|
check_guid = LCase(Cells(row, guid_column))
|
|
check_sec_mod = Cells(row, sec_mod_column)
|
|
check_cost_mod = Cells(row, cost_mod_column)
|
|
check_scale_mod = Cells(row, scale_mod_column)
|
|
check_simple_mod = Cells(row, simple_mod_column)
|
|
check_ha_mod = Cells(row, ha_mod_column)
|
|
'If there was no GUID, generate one
|
|
If Len(check_guid) = 0 Then check_guid = generate_guid()
|
|
'If there was no ID, generate one with the cat/subcat/item IDs
|
|
If Len(check_id) = 0 Then check_id = Trim(Str(cat_id)) & "." & Trim(Str(rel_subcat_id)) & "." & Trim(Format(rel_item_id, "00"))
|
|
'Only read More Info hyperlink if the cell contains one
|
|
If Cells(row, link_column).Hyperlinks.Count > 0 Then
|
|
'Anchors are not contained by the Address property, we need to concat the Subaddress too
|
|
If Len(Cells(row, link_column).Hyperlinks(1).SubAddress) > 0 Then
|
|
check_link = Cells(row, link_column).Hyperlinks(1).Address + "#" + Cells(row, link_column).Hyperlinks(1).SubAddress
|
|
Else
|
|
check_link = Cells(row, link_column).Hyperlinks(1).Address
|
|
End If
|
|
Else
|
|
check_link = Cells(row, link_column)
|
|
End If
|
|
'Only read Training hyperlink if the cell contains one
|
|
If Cells(row, training_column).Hyperlinks.Count > 0 Then
|
|
check_training = Cells(row, training_column).Hyperlinks(1).Address
|
|
Else
|
|
check_training = Cells(row, training_column)
|
|
End If
|
|
row = row + 1
|
|
json = json + " {" + line_break
|
|
json = json + " " + double_quote + "category" + double_quote + ": " + double_quote + correct_format_for_JSON(check_category) + double_quote + ","
|
|
json = json + line_break + " " + double_quote + "subcategory" + double_quote + ": " + double_quote + correct_format_for_JSON(check_subcategory) + double_quote
|
|
json = json + "," + line_break + " " + double_quote + "text" + double_quote + ": " + double_quote + correct_format_for_JSON(check_text) + double_quote
|
|
If Len(check_description) > 0 Then json = json + "," + line_break + " " + double_quote + "description" + double_quote + ": " + double_quote + correct_format_for_JSON(check_description) + double_quote
|
|
If Len(check_waf) > 0 Then json = json + "," + line_break + " " + double_quote + "waf" + double_quote + ": " + double_quote + correct_format_for_JSON(check_waf) + double_quote
|
|
If Len(check_guid) > 0 Then json = json + "," + line_break + " " + double_quote + "guid" + double_quote + ": " + double_quote + check_guid + double_quote
|
|
If Len(check_id) > 0 Then json = json + "," + line_break + " " + double_quote + "id" + double_quote + ": " + double_quote + check_id + double_quote
|
|
If Len(check_sec_mod) > 0 And IsNumeric(check_sec_mod) Then json = json + "," + line_break + " " + double_quote + "security" + double_quote + ": " + CStr(check_sec_mod)
|
|
If Len(check_cost_mod) > 0 And IsNumeric(check_cost_mod) Then json = json + "," + line_break + " " + double_quote + "cost" + double_quote + ": " + CStr(check_cost_mod)
|
|
If Len(check_scale_mod) > 0 And IsNumeric(check_scale_mod) Then json = json + "," + line_break + " " + double_quote + "scale" + double_quote + ": " + CStr(check_scale_mod)
|
|
If Len(check_simple_mod) > 0 And IsNumeric(check_simple_mod) Then json = json + "," + line_break + " " + double_quote + "simple" + double_quote + ": " + CStr(check_simple_mod)
|
|
If Len(check_ha_mod) > 0 And IsNumeric(check_ha_mod) Then json = json + "," + line_break + " " + double_quote + "ha" + double_quote + ": " + CStr(check_ha_mod)
|
|
If Len(check_severity) > 0 Then json = json + "," + line_break + " " + double_quote + "severity" + double_quote + ": " + double_quote + check_severity + double_quote
|
|
If Len(check_graph_query) > 0 Then json = json + "," + line_break + " " + double_quote + "graph" + double_quote + ": " + double_quote + correct_format_for_JSON(check_graph_query) + double_quote
|
|
If Len(check_training) > 0 Then json = json + "," + line_break + " " + double_quote + "training" + double_quote + ": " + double_quote + correct_format_for_JSON(check_training) + double_quote
|
|
If Len(check_link) > 0 Then json = json + "," + line_break + " " + double_quote + "link" + double_quote + ": " + double_quote + correct_format_for_JSON(check_link) + double_quote
|
|
json = json + line_break + " }"
|
|
item_count = item_count + 1
|
|
Loop
|
|
' Finish items section
|
|
json = json + line_break + " ]," + line_break
|
|
' Create categories section
|
|
json = json + " " + double_quote + "categories" + double_quote + ": ["
|
|
row = 2
|
|
Do While row < row_limit And Len(Sheets(values_sheet).Cells(row, values_category_column)) > 0
|
|
If row > 2 Then json = json + ","
|
|
json = json + line_break
|
|
category_name = Sheets(values_sheet).Cells(row, values_category_column)
|
|
json = json + " {" + line_break
|
|
json = json + " " + double_quote + "name" + double_quote + ": " + double_quote + correct_format_for_JSON(category_name) + double_quote + line_break
|
|
json = json + " }"
|
|
row = row + 1
|
|
category_count = category_count + 1
|
|
Loop
|
|
' Finish category section
|
|
json = json + line_break + " ]," + line_break
|
|
' Create WAF section
|
|
json = json + " " + double_quote + "waf" + double_quote + ": ["
|
|
row = 2
|
|
Do While row < row_limit And Len(Sheets(values_sheet).Cells(row, values_waf_column)) > 0
|
|
If row > 2 Then json = json + ","
|
|
json = json + line_break
|
|
waf_name = Sheets(values_sheet).Cells(row, values_waf_column)
|
|
json = json + " {" + line_break
|
|
json = json + " " + double_quote + "name" + double_quote + ": " + double_quote + correct_format_for_JSON(waf_name) + double_quote + line_break
|
|
json = json + " }"
|
|
row = row + 1
|
|
category_count = category_count + 1
|
|
Loop
|
|
' Finish WAF section
|
|
json = json + line_break + " ]," + line_break
|
|
' Create status section
|
|
json = json + " " + double_quote + "status" + double_quote + ": ["
|
|
row = 2
|
|
Do While row < row_limit And Len(Sheets(values_sheet).Cells(row, values_status_column)) > 0
|
|
If row > 2 Then json = json + ","
|
|
json = json + line_break
|
|
status_name = Sheets(values_sheet).Cells(row, values_status_column)
|
|
status_description = Sheets(values_sheet).Cells(row, values_status_description_column)
|
|
json = json + " {" + line_break
|
|
json = json + " " + double_quote + "name" + double_quote + ": " + double_quote + correct_format_for_JSON(status_name) + double_quote + "," + line_break
|
|
json = json + " " + double_quote + "description" + double_quote + ": " + double_quote + correct_format_for_JSON(status_description) + double_quote + line_break
|
|
json = json + " }"
|
|
row = row + 1
|
|
status_count = status_count + 1
|
|
Loop
|
|
' Finish status section
|
|
json = json + line_break + " ]," + line_break
|
|
' Create severities section
|
|
json = json + " " + double_quote + "severities" + double_quote + ": ["
|
|
row = 2
|
|
Do While row < row_limit And Len(Sheets(values_sheet).Cells(row, values_sev_column)) > 0
|
|
If row > 2 Then json = json + ","
|
|
json = json + line_break
|
|
severity_name = Sheets(values_sheet).Cells(row, values_sev_column)
|
|
json = json + " {" + line_break
|
|
json = json + " " + double_quote + "name" + double_quote + ": " + double_quote + correct_format_for_JSON(severity_name) + double_quote + line_break
|
|
json = json + " }"
|
|
row = row + 1
|
|
Loop
|
|
' Finish severities section
|
|
json = json + line_break + " ]," + line_break
|
|
' Create metadata section
|
|
json = json + " " + double_quote + "metadata" + double_quote + ": {" + line_break
|
|
json = json + " " + double_quote + "name" + double_quote + ": " + double_quote + correct_format_for_JSON(Cells(checklist_name_row, checklist_name_col)) + double_quote + "," + line_break
|
|
json = json + " " + double_quote + "state" + double_quote + ": " + double_quote + correct_format_for_JSON(Cells(checklist_state_row, checklist_state_col)) + double_quote + "," + line_break
|
|
json = json + " " + double_quote + "timestamp" + double_quote + ": " + double_quote + correct_format_for_JSON(Format(Now, "mm/dd/yyyy HH:mm:ss")) + double_quote + line_break
|
|
' Finish metadata section
|
|
json = json + " }" + line_break
|
|
' Finish JSON
|
|
json = json + "}" + line_break
|
|
' Write JSON to file
|
|
' MsgBox json
|
|
'export_file_path = ActiveWorkbook.Path + "\" + export_file_name
|
|
export_file_path = ""
|
|
export_file_path = Application.GetSaveAsFilename(FileFilter:="JSON File (*.json), *.json", Title:="Exporting JSON checklist", InitialFileName:=ActiveWorkbook.Path + "\" + export_file_name)
|
|
'checks to make sure the user hasn't canceled the dialog
|
|
If export_file_path <> False Then
|
|
'MsgBox "Exporting to " + export_file_path
|
|
Open export_file_path For Output As #1
|
|
Print #1, json
|
|
Close #1
|
|
End If
|
|
MsgBox CStr(item_count) + " checklist items and " + CStr(category_count) + " categories exported to JSON file " + export_file_path, vbInformation
|
|
Exit Sub
|
|
errh:
|
|
If Err.Number <> 0 Then
|
|
MsgBox "Error while exporting checklist to JSON " & Err.Description, vbCritical
|
|
End If
|
|
End Sub
|
|
|
|
'Import JSON from URL (first download to a local file)
|
|
Sub import_checklist_fromurl()
|
|
Const values_sheet = "values"
|
|
Const values_url_column = 4
|
|
Dim checklist_url, checklist_base_url As String
|
|
Dim json_file As Variant
|
|
Dim buf, ret As Long
|
|
Dim url_split() As String
|
|
Dim filename As String
|
|
Dim objXmlHttpReq As Object
|
|
Dim objStream As Object
|
|
Dim msg As String
|
|
'Get URL stored in the Values sheet
|
|
checklist_base_url = Sheets(values_sheet).Cells(2, values_url_column)
|
|
If Len(checklist_base_url) > 0 Then
|
|
'Look at the option buttons to set global variables that control technology (LZ, AKS, AVD, AVS, Security) and language
|
|
set_checklist_variables
|
|
'Append the technology and options variables (default to English and LZ)
|
|
If Len(selected_technology) = 0 Then selected_technology = "alz"
|
|
If Len(selected_language) = 0 Then selected_language = "en"
|
|
checklist_url = checklist_base_url + selected_technology + "_checklist." + selected_language + ".json"
|
|
'Get the filename of the URL
|
|
url_split = Split(checklist_url, "/")
|
|
filename = url_split(UBound(url_split))
|
|
' Instead of letting the user specify a download directory, picking up Downloads per default
|
|
'ChDir ActiveWorkbook.Path
|
|
'json_file = Application.GetOpenFilename(Title:="Please choose a file to open", FileFilter:="JSON Files *.json* (*.json),")
|
|
json_file = Environ("USERPROFILE") + "\Downloads\checklist.json"
|
|
msg = "Reference checklist will be downloaded from '" + checklist_url + "' to '" + CStr(json_file) + "'"
|
|
If MsgBox(msg, vbOKCancel + vbQuestion, "Downloading reference checklist") = vbOK Then
|
|
ret = URLDownloadToFile(0, checklist_url, json_file, 0, 0)
|
|
If ret = 0 Then
|
|
'Call the sub for actually doing the import
|
|
import_checklist_fromfile json_file
|
|
Else
|
|
MsgBox "Checklist could not be downloaded from '" + checklist_url + "'", vbCritical
|
|
End If
|
|
End If
|
|
Else
|
|
MsgBox "Sorry, I could not found out the reference URL in sheet '" + values_sheet + "' at cell location 2," + CStr(values_url_column), vbCritical
|
|
End If
|
|
End Sub
|
|
|
|
'Import from custom JSON file
|
|
Sub import_checklist()
|
|
On Error GoTo import_checklist_err
|
|
Dim json_file As Variant
|
|
ChDir ActiveWorkbook.Path
|
|
json_file = Application.GetOpenFilename(Title:="Please choose a file to open", FileFilter:="JSON Files *.json* (*.json),")
|
|
If json_file = False Then
|
|
MsgBox "No file selected.", vbExclamation, "Action canceled"
|
|
Exit Sub
|
|
Else
|
|
import_graph_queries = True 'Always import graph queries in advanced mode.
|
|
import_checklist_fromfile json_file
|
|
End If
|
|
import_checklist_err:
|
|
If Err.Number = 76 Then 'path not found, this happens usually if the spreadsheet is in onedrive
|
|
Resume Next
|
|
ElseIf Err.Number <> 0 Then
|
|
MsgBox "Error while importing checklist from custom file: " & CStr(Err.Number) & ": " & Err.Description, vbCritical
|
|
End If
|
|
Exit Sub
|
|
End Sub
|
|
|
|
|
|
'Import from a local JSON file
|
|
'Parse JSON code using the JsonConverter module
|
|
Sub import_checklist_fromfile(json_file As Variant)
|
|
On Error GoTo import_checklist_fromfile_err
|
|
' Constants
|
|
Const row_limit = 2000 'Safety net
|
|
'Variables
|
|
Dim json_ts As TextStream
|
|
Dim FSO As New FileSystemObject
|
|
Dim textline As String
|
|
Dim json As String
|
|
Dim json_object, json_item As Object
|
|
Dim double_quote As String
|
|
Dim line_elements() As String
|
|
Dim row, item_count As Integer, category_count As Integer, waf_count As Integer, status_count, i As Integer
|
|
Dim notverified As String
|
|
Dim get_user_info_successful As Boolean
|
|
Dim start_time As Double
|
|
'Remember time when macro starts
|
|
start_time = Timer
|
|
'Disable some stuff to speed up
|
|
Call DisableStuff
|
|
'Variable value initialization
|
|
row = row1
|
|
double_quote = Chr(34) ' double quote as a variable
|
|
json = ""
|
|
item_count = 0
|
|
category_count = 0
|
|
waf_count = 0
|
|
status_count = 0
|
|
'First of all, get the info entered by the user in a global variable
|
|
get_user_info_successful = get_user_input()
|
|
'Go through the file line by line
|
|
Dim objStream
|
|
Set objStream = CreateObject("ADODB.Stream")
|
|
objStream.Charset = "utf-8"
|
|
objStream.Open
|
|
objStream.LoadFromFile (json_file)
|
|
json = objStream.ReadText()
|
|
|
|
objStream.Close
|
|
Set objStream = Nothing
|
|
|
|
json = Replace(json, vbCrLf, "")
|
|
Set json_object = JsonConverter.ParseJson(json) 'This line might give Run-time error 10001 if there are JSON syntactic errors
|
|
'Update checklist title
|
|
If json_object.Exists("metadata") Then
|
|
If json_object("metadata").Exists("name") Then
|
|
Cells(checklist_name_row, checklist_name_col) = json_object("metadata")("name")
|
|
End If
|
|
If json_object("metadata").Exists("state") Then
|
|
Cells(checklist_state_row, checklist_state_col) = json_object("metadata")("state")
|
|
End If
|
|
If json_object("metadata").Exists("timestamp") Then
|
|
Cells(checklist_timestamp_row, checklist_timestamp_col) = json_object("metadata")("timestamp")
|
|
End If
|
|
End If
|
|
'Import status
|
|
If json_object.Exists("status") Then
|
|
row = 2
|
|
If TypeName(json_object("status")) = "Dictionary" Then
|
|
notverified = json_object("status")("0")("name") ' The "Not Verified" status is the first one
|
|
i = 0
|
|
Do
|
|
Sheets(values_sheet).Cells(row, values_status_column) = json_object("status")(CStr(i))("name")
|
|
If json_object("status")(CStr(i)).Exists("description") Then
|
|
Sheets(values_sheet).Cells(row, values_status_description_column) = json_object("status")(CStr(i))("description")
|
|
End If
|
|
row = row + 1
|
|
status_count = status_count + 1
|
|
i = i + 1
|
|
Loop While json_object("status").Exists(CStr(i))
|
|
Else
|
|
notverified = json_object("status")(1)("name") ' The "Not Verified" status is the first one
|
|
For Each json_item In json_object("status")
|
|
Sheets(values_sheet).Cells(row, values_status_column) = json_item("name")
|
|
If json_item.Exists("description") Then
|
|
Sheets(values_sheet).Cells(row, values_status_description_column) = json_item("description")
|
|
End If
|
|
row = row + 1
|
|
status_count = status_count + 1
|
|
Next json_item
|
|
End If
|
|
'Blank the rest of the status rows, although for status this shouldnt be required
|
|
Do While row < row_limit And Len(Cells(row, values_status_column)) > 0
|
|
Sheets(values_sheet).Cells(row, values_status_column) = ""
|
|
row = row + 1
|
|
Loop
|
|
End If
|
|
'Import checklist items
|
|
row = row1
|
|
'If JSON is a translated file, it is a nested dictionary with keys "0", "1", etc
|
|
If TypeName(json_object("items")) = "Dictionary" Then
|
|
i = 0
|
|
Do
|
|
update_row json_object("items")(CStr(i)), row, notverified, get_user_info_successful
|
|
row = row + 1
|
|
item_count = item_count + 1
|
|
i = i + 1
|
|
Loop While json_object("items").Exists(CStr(i))
|
|
'Otherwise, it is just an array
|
|
Else
|
|
For Each json_item In json_object("items")
|
|
update_row json_item, row, notverified, get_user_info_successful
|
|
row = row + 1
|
|
item_count = item_count + 1
|
|
Next json_item
|
|
End If
|
|
'Blank the rest of the item rows
|
|
Do While row < row_limit And (Len(Cells(row, category_column)) + Len(Cells(row, subcategory_column)) + Len(Cells(row, text_column)) + Len(Cells(row, status_column)) + Len(Cells(row, comments_column))) > 0
|
|
Cells(row, id_column) = ""
|
|
Cells(row, category_column) = ""
|
|
Cells(row, subcategory_column) = ""
|
|
Cells(row, waf_column) = ""
|
|
Cells(row, text_column) = ""
|
|
Cells(row, description_column) = ""
|
|
Cells(row, severity_column) = ""
|
|
Cells(row, link_column) = ""
|
|
Cells(row, status_column) = ""
|
|
Cells(row, comments_column) = ""
|
|
Cells(row, training_column) = ""
|
|
Cells(row, graph_column) = ""
|
|
Cells(row, guid_column) = ""
|
|
row = row + 1
|
|
Loop
|
|
'Import categories
|
|
If json_object.Exists("categories") Then
|
|
row = 2
|
|
If TypeName(json_object("categories")) = "Dictionary" Then
|
|
i = 0
|
|
Do
|
|
Sheets(values_sheet).Cells(row, values_category_column) = json_object("categories")(CStr(i))("name")
|
|
row = row + 1
|
|
category_count = category_count + 1
|
|
i = i + 1
|
|
Loop While json_object("categories").Exists(CStr(i))
|
|
Else
|
|
For Each json_item In json_object("categories")
|
|
Sheets(values_sheet).Cells(row, values_category_column) = json_item("name")
|
|
row = row + 1
|
|
category_count = category_count + 1
|
|
Next json_item
|
|
End If
|
|
'Blank the rest of the category rows
|
|
Do While row < row_limit And Len(Cells(row, values_category_column)) > 0
|
|
Sheets(values_sheet).Cells(row, values_category_column) = ""
|
|
row = row + 1
|
|
Loop
|
|
End If
|
|
'Import WAF pillars
|
|
If json_object.Exists("waf") Then
|
|
row = 2
|
|
If TypeName(json_object("waf")) = "Dictionary" Then
|
|
i = 0
|
|
Do
|
|
Sheets(values_sheet).Cells(row, values_waf_column) = json_object("waf")(CStr(i))("name")
|
|
row = row + 1
|
|
waf_count = waf_count + 1
|
|
i = i + 1
|
|
Loop While json_object("waf").Exists(CStr(i))
|
|
Else
|
|
For Each json_item In json_object("waf")
|
|
Sheets(values_sheet).Cells(row, values_waf_column) = json_item("name")
|
|
row = row + 1
|
|
waf_count = waf_count + 1
|
|
Next json_item
|
|
End If
|
|
'Blank the rest of the category rows
|
|
Do While row < row_limit And Len(Cells(row, values_waf_column)) > 0
|
|
Sheets(values_sheet).Cells(row, values_waf_column) = ""
|
|
row = row + 1
|
|
Loop
|
|
End If
|
|
'Import severities
|
|
If json_object.Exists("severities") Then
|
|
row = 2
|
|
If TypeName(json_object("severities")) = "Dictionary" Then
|
|
i = 0
|
|
Do
|
|
Sheets(values_sheet).Cells(row, values_sev_column) = json_object("severities")(CStr(i))("name")
|
|
row = row + 1
|
|
i = i + 1
|
|
Loop While json_object("severities").Exists(CStr(i))
|
|
Else
|
|
For Each json_item In json_object("severities")
|
|
Sheets(values_sheet).Cells(row, values_sev_column) = json_item("name")
|
|
row = row + 1
|
|
Next json_item
|
|
End If
|
|
'Blank the rest of the severity rows
|
|
Do While row < row_limit And Len(Cells(row, values_sev_column)) > 0
|
|
Sheets(values_sheet).Cells(row, values_sev_column) = ""
|
|
row = row + 1
|
|
Loop
|
|
End If
|
|
MsgBox CStr(item_count) + " check items and " + CStr(category_count) + " categories imported from JSON file " + json_file + " in " + CStr(Round(Timer - start_time, 2)) + " seconds", vbInformation
|
|
Call EnableStuff
|
|
Exit Sub
|
|
import_checklist_fromfile_err:
|
|
If Err.Number <> 0 Then
|
|
MsgBox "Error while importing checklist from JSON file " & json_file & ": " & Err.Description, vbCritical
|
|
Call EnableStuff
|
|
End If
|
|
End Sub
|
|
|
|
'Function with error control in case a property does not exist for an object
|
|
Function get_object_property(ByVal object_item As Object, property_name As String) As String
|
|
On Error GoTo get_object_property_err
|
|
Dim aux As String
|
|
aux = object_item(property_name)
|
|
'If it is " " or something similar (some translation engines introduce blanks between "&" and "nbsp"), set to null
|
|
If Right(aux, 4) = "nbsp" Then aux = ""
|
|
get_object_property = aux
|
|
Exit Function
|
|
get_object_property_err:
|
|
get_object_property = ""
|
|
Exit Function
|
|
End Function
|
|
|
|
' Updates a checklist row with the information in the object
|
|
Sub update_row(ByVal json_item As Object, ByVal row As Integer, notverified As String, user_input_saved As Boolean)
|
|
On Error GoTo update_row_err
|
|
' Variables and constants
|
|
Dim check_id As String, check_category As String, check_subcategory As String, check_waf As String, check_text As String, check_description As String, check_severity As String, check_status As String, check_link As String, check_training As String, check_graph_query As String, check_guid As String
|
|
Dim user_input_comments As String, user_input_status As String
|
|
Dim check_sec_mod, check_cost_mod, check_scale_mod, check_simple_mod, check_ha_mod
|
|
Dim get_guid_user_input_successful As Boolean
|
|
Dim newrow(1 To num_columns) As Variant
|
|
' Defaults to English "Not Verified"
|
|
If Len(notverified) = 0 Then notverified = "Not verified"
|
|
' Code
|
|
check_id = get_object_property(json_item, "id")
|
|
check_category = get_object_property(json_item, "category")
|
|
check_subcategory = get_object_property(json_item, "subcategory")
|
|
check_waf = get_object_property(json_item, "waf")
|
|
check_text = get_object_property(json_item, "text")
|
|
check_description = get_object_property(json_item, "description")
|
|
check_severity = get_object_property(json_item, "severity")
|
|
check_link = get_object_property(json_item, "link")
|
|
check_training = get_object_property(json_item, "training")
|
|
check_graph_query = get_object_property(json_item, "graph")
|
|
If Len(check_graph_query) = 0 Then check_graph_query = get_object_property(json_item, "graph_success") 'Backwards compatibility
|
|
check_guid = get_object_property(json_item, "guid")
|
|
check_sec_mod = get_object_property(json_item, "security")
|
|
check_cost_mod = get_object_property(json_item, "cost")
|
|
check_scale_mod = get_object_property(json_item, "scale")
|
|
check_simple_mod = get_object_property(json_item, "simple")
|
|
check_ha_mod = get_object_property(json_item, "ha")
|
|
'Create array variable with the information of the provided JSON object
|
|
newrow(id_column) = check_id
|
|
newrow(category_column) = check_category
|
|
newrow(subcategory_column) = check_subcategory
|
|
newrow(waf_column) = check_waf
|
|
newrow(text_column) = check_text
|
|
newrow(description_column) = check_description
|
|
newrow(severity_column) = check_severity
|
|
newrow(guid_column) = check_guid
|
|
'If the previous user input was saved, and we can successfully retrieve an entry for this guid, put it in the comments/status fields
|
|
If user_input_saved Then
|
|
If get_user_input_from_guid(check_guid, user_input_comments, user_input_status) Then
|
|
newrow(status_column) = CStr(user_input_status) 'Some times around this line there is a dreadful 400 error :(
|
|
newrow(comments_column) = CStr(user_input_comments)
|
|
Else
|
|
newrow(status_column) = notverified '"notverified" is a variable containing the translation of "not verified"
|
|
newrow(comments_column) = ""
|
|
End If
|
|
'Otherwise, blank them
|
|
Else
|
|
newrow(status_column) = notverified '"notverified" is a variable containing the translation of "not verified"
|
|
newrow(comments_column) = ""
|
|
End If
|
|
'Graph queries can optionally be imported or not, since it impacts readability
|
|
'Per default, they are only imported when using the English language
|
|
If import_graph_queries Then
|
|
newrow(graph_column) = check_graph_query
|
|
Else
|
|
newrow(graph_column) = ""
|
|
End If
|
|
'WAF Pillar modifiers are optional too
|
|
If IsNumeric(check_sec_mod) Then
|
|
newrow(sec_mod_column) = check_sec_mod
|
|
End If
|
|
If IsNumeric(check_cost_mod) Then
|
|
newrow(cost_mod_column) = check_cost_mod
|
|
End If
|
|
If IsNumeric(check_scale_mod) Then
|
|
newrow(scale_mod_column) = check_scale_mod
|
|
End If
|
|
If IsNumeric(check_simple_mod) Then
|
|
'Cells(row, simple_mod_column) = check_simple_mod
|
|
newrow(simple_mod_column) = check_simple_mod
|
|
End If
|
|
If IsNumeric(check_ha_mod) Then
|
|
newrow(ha_mod_column) = check_ha_mod
|
|
End If
|
|
'Update Excel full row with the array in one go
|
|
Range(Cells(row, 1), Cells(row, num_columns)).Value = newrow
|
|
'Training and MoreInfo link optional
|
|
If Len(check_link) > 0 Then
|
|
Cells(row, link_column).Hyperlinks.Add Address:=check_link, TextToDisplay:="More info", Anchor:=Cells(row, link_column), ScreenTip:=check_link
|
|
Else
|
|
Cells(row, link_column) = ""
|
|
End If
|
|
If Len(check_training) > 0 Then
|
|
Cells(row, training_column).Hyperlinks.Add Address:=check_training, TextToDisplay:="Training", Anchor:=Cells(row, training_column), ScreenTip:=check_training
|
|
Else
|
|
Cells(row, training_column) = ""
|
|
End If
|
|
Exit Sub
|
|
update_row_err:
|
|
If Err.Number <> 0 Then
|
|
MsgBox "Error while updating row: " & Err.Description, vbCritical
|
|
End If
|
|
End Sub
|
|
|
|
'Generates a random GUID
|
|
'https://danwagner.co/how-to-generate-a-guid-in-excel-with-vba/
|
|
Function generate_guid() As String
|
|
On Error GoTo genguiderr
|
|
Dim k, h As Variant
|
|
generate_guid = Space(36)
|
|
For k = 1 To Len(generate_guid)
|
|
Randomize
|
|
Select Case k
|
|
Case 9, 14, 19, 24: h = "-"
|
|
Case 15: h = "4"
|
|
Case 20: h = Hex(Rnd * 3 + 8)
|
|
Case Else: h = Hex(Rnd * 15)
|
|
End Select
|
|
Mid$(generate_guid, k, 1) = h
|
|
Next
|
|
generate_guid = LCase$(generate_guid)
|
|
genguiderr:
|
|
If Err.Number <> 0 Then
|
|
MsgBox "Error while generating GUID: " & Err.Description, vbCritical
|
|
End If
|
|
End Function
|
|
|
|
'Import Azure Resource Graph query results from a JSON file generated with checklist_graph.sh
|
|
Sub import_graph_results()
|
|
On Error GoTo import_graph_results_err
|
|
Dim json_file As Variant
|
|
Dim objStream
|
|
Dim json As String
|
|
Dim json_object, json_item As Object
|
|
Dim check_guid As String, check_success_result As String, check_failure_result As String, check_result As String, check_arm_id As String
|
|
Dim row As Integer
|
|
Dim query_result_format As String, query_result_date As String
|
|
'File pick dialog
|
|
ChDir ActiveWorkbook.Path
|
|
json_file = Application.GetOpenFilename(Title:="Please choose a file to open", FileFilter:="JSON Files *.json* (*.json),")
|
|
If json_file = False Then
|
|
MsgBox "No file selected.", vbExclamation, "Action canceled"
|
|
Exit Sub
|
|
Else
|
|
If MsgBox("This action will potentially overwrite existing contents in the Comments column. Do you want to continue?", vbQuestion + vbYesNo) = vbYes Then
|
|
'Open and read text file
|
|
Set objStream = CreateObject("ADODB.Stream")
|
|
objStream.Charset = "utf-8"
|
|
objStream.Open
|
|
objStream.LoadFromFile (json_file)
|
|
json = objStream.ReadText()
|
|
objStream.Close
|
|
Set objStream = Nothing
|
|
'Remove line breaks and parse
|
|
json = Replace(json, vbCrLf, "")
|
|
Set json_object = JsonConverter.ParseJson(json) 'This line might give Run-time error 10001 if there are JSON syntax errors
|
|
'Browse the checks one per one
|
|
If json_object.Exists("checks") Then
|
|
For Each json_item In json_object("checks")
|
|
'Get the check info
|
|
check_guid = get_object_property(json_item, "guid")
|
|
check_result = get_object_property(json_item, "compliant")
|
|
check_arm_id = get_object_property(json_item, "id")
|
|
'Now find the row with a matching GUID, and populate the comments field
|
|
row = row1
|
|
Do Until Cells(row, guid_column) = check_guid Or Cells(row, text_column) = ""
|
|
row = row + 1
|
|
Loop
|
|
'And update the comments column if it was found
|
|
If Cells(row, text_column) = "" Then
|
|
MsgBox "GUID " & check_guid & " not found in this checklist.", vbExclamation
|
|
Else
|
|
'Enter a line break if the cell wasnt empty
|
|
If Len(Cells(row, comments_column)) > 0 Then Cells(row, comments_column) = Cells(row, comments_column) & Chr(10)
|
|
'Depending on the test result, add 'compliant' or 'non-compliant'
|
|
If check_result = "true" Then
|
|
Cells(row, comments_column) = Cells(row, comments_column) & "Compliant: " + check_arm_id
|
|
ElseIf check_result = "false" Then
|
|
Cells(row, comments_column) = Cells(row, comments_column) & "Non-compliant: " + check_arm_id
|
|
Else
|
|
MsgBox "Check result " & check_result & " not understood", vbExclamation
|
|
End If
|
|
End If
|
|
Next json_item
|
|
Else
|
|
MsgBox "It looks like the JSON file " & json_file & " does not contain a 'checks' object?", vbCritical
|
|
End If
|
|
End If
|
|
|
|
End If
|
|
Exit Sub
|
|
import_graph_results_err:
|
|
If Err.Number = 10001 Then
|
|
MsgBox "Error while importing graph results: please verify that the file " & json_file & " has a valid JSON format", vbCritical
|
|
ElseIf Err.Number = 76 Then 'path not found, this happens usually if the spreadsheet is in onedrive
|
|
Resume Next
|
|
ElseIf Err.Number <> 0 Then
|
|
MsgBox "Error while importing graph results: " & CStr(Err.Number) & ": " & Err.Description, vbCritical
|
|
End If
|
|
Exit Sub
|
|
End Sub
|
|
|
|
'Clear all rows
|
|
Sub clear_rows()
|
|
Dim row As Integer
|
|
Dim emptyrow() As Variant, i As Integer
|
|
ReDim Preserve emptyrow(1 To num_columns)
|
|
row = row1
|
|
For i = 1 To num_columns
|
|
emptyrow(i) = ""
|
|
Next i
|
|
Do While row < row_limit And (Len(Cells(row, category_column)) + Len(Cells(row, subcategory_column)) + Len(Cells(row, text_column)) + Len(Cells(row, status_column)) + Len(Cells(row, comments_column))) > 0
|
|
Range(Cells(row, 1), Cells(row, num_columns)).Value = emptyrow
|
|
row = row + 1
|
|
Loop
|
|
'Delete categories
|
|
row = 2
|
|
Do While row < row_limit And Len(Sheets(values_sheet).Cells(row, values_category_column)) > 0
|
|
Sheets(values_sheet).Cells(row, values_category_column) = ""
|
|
row = row + 1
|
|
Loop
|
|
'Reset checklist title
|
|
Cells(checklist_name_row, checklist_name_col) = Sheets(values_sheet).Cells(2, 5)
|
|
'Delete status and timestamp
|
|
Cells(checklist_state_row, checklist_state_col) = ""
|
|
Cells(checklist_timestamp_row, checklist_timestamp_col) = ""
|
|
'Defaults to LZ and English
|
|
Cells(technology_selection_row, technology_selection_col) = Sheets(values_sheet).Cells(2, values_technology_selection_column)
|
|
Cells(language_selection_row, language_selection_col) = Sheets(values_sheet).Cells(2, values_language_selection_column)
|
|
End Sub
|
|
|
|
'Delete all from controls, so that the spreadsheet can be saved as macro-free
|
|
Sub delete_controls()
|
|
Dim item As Object
|
|
'Browse all shapes
|
|
For Each item In ActiveSheet.Shapes
|
|
'Only Form Controls
|
|
If item.Type = msoFormControl Then
|
|
item.Delete
|
|
End If
|
|
Next item
|
|
End Sub
|
|
|
|
'Inspect option buttons and set global variables accordingly
|
|
Sub set_checklist_variables()
|
|
On Error GoTo set_checklist_variables_err
|
|
Dim tech_found As Boolean, lang_found As Boolean
|
|
Dim row As Integer
|
|
|
|
'Initialization
|
|
tech_found = False
|
|
lang_found = False
|
|
|
|
'Find the prefix for the given technology
|
|
row = 2
|
|
Do While row < row_limit And Len(Sheets(values_sheet).Cells(row, values_technology_selection_column)) > 0
|
|
If Sheets(values_sheet).Cells(row, values_technology_selection_column) = Cells(technology_selection_row, technology_selection_col) Then
|
|
tech_found = True
|
|
selected_technology = Sheets(values_sheet).Cells(row, values_technology_prefix_column)
|
|
Exit Do
|
|
End If
|
|
row = row + 1
|
|
Loop
|
|
|
|
'Find the prefix for the given language
|
|
row = 2
|
|
Do While row < row_limit And Len(Sheets(values_sheet).Cells(row, values_language_selection_column)) > 0
|
|
If Sheets(values_sheet).Cells(row, values_language_selection_column) = Cells(language_selection_row, language_selection_col) Then
|
|
lang_found = True
|
|
selected_language = Sheets(values_sheet).Cells(row, values_language_prefix_column)
|
|
Exit Do
|
|
End If
|
|
row = row + 1
|
|
Loop
|
|
|
|
|
|
' 'Look at the technology cell
|
|
' Select Case Cells(technology_selection_row, technology_selection_col)
|
|
' Case Sheets(values_sheet).Cells(2, values_technology_selection_column)
|
|
' selected_technology = "alz"
|
|
' Case Sheets(values_sheet).Cells(3, values_technology_selection_column)
|
|
' selected_technology = "aks"
|
|
' Case Sheets(values_sheet).Cells(4, values_technology_selection_column)
|
|
' selected_technology = "avd"
|
|
' Case Sheets(values_sheet).Cells(5, values_technology_selection_column)
|
|
' selected_technology = "avs"
|
|
' Case Sheets(values_sheet).Cells(6, values_technology_selection_column)
|
|
' selected_technology = "security"
|
|
' Case Else
|
|
' MsgBox "Technology option " & Cells(technology_selection_row, technology_selection_col) & " unknown, defaulting to Landing Zone review", vbCritical
|
|
' selected_technology = "alz"
|
|
' End Select
|
|
|
|
' 'Look at the language cell
|
|
' Select Case Cells(language_selection_row, language_selection_col)
|
|
' Case Sheets(values_sheet).Cells(2, values_language_selection_column)
|
|
' selected_language = "en"
|
|
' import_graph_queries = True
|
|
' Case Sheets(values_sheet).Cells(3, values_language_selection_column)
|
|
' selected_language = "ja"
|
|
' import_graph_queries = False
|
|
' Case Sheets(values_sheet).Cells(4, values_language_selection_column)
|
|
' selected_language = "ko"
|
|
' import_graph_queries = False
|
|
' Case Sheets(values_sheet).Cells(5, values_language_selection_column)
|
|
' selected_language = "pt"
|
|
' import_graph_queries = False
|
|
' Case Sheets(values_sheet).Cells(6, values_language_selection_column)
|
|
' selected_language = "es"
|
|
' import_graph_queries = False
|
|
' Case Else
|
|
' MsgBox "Language option " & Cells(language_selection_row, language_selection_col) & " unknown, defaulting to English", vbCritical
|
|
' selected_language = "en"
|
|
' import_graph_queries = True
|
|
' End Select
|
|
|
|
'Import Azure Resource Graph queries only if the language is English (otherwise the translated queries are imported)
|
|
'If Cells(language_selection_row, language_selection_col) = "English" Then
|
|
' import_graph_queries = True
|
|
'Else
|
|
' MsgBox "Azure Resource Graph queries will not be imported, since the selected language is not English", vbInformation + vbOKOnly
|
|
'End If
|
|
|
|
'After translation has been fixed, we can now import the Graph queries safely :)
|
|
import_graph_queries = True
|
|
|
|
'Error message if tech or lang could not be found
|
|
If Not tech_found Then
|
|
MsgBox "Not able to resolve technology '" + Cells(technology_selection_row, technology_selection_col) + "' to a file prefix", vbCritical
|
|
End If
|
|
If Not lang_found Then
|
|
MsgBox "Not able to resolve language '" + Cells(language_selection_row, language_selection_col) + "' to a file prefix", vbCritical
|
|
End If
|
|
|
|
'Debug.Print "Selected technology " + selected_technology + ", selected language " + selected_language
|
|
Exit Sub
|
|
set_checklist_variables_err:
|
|
MsgBox "Error while reading checklist selection options, defaulting to Landing Zone and English: " & CStr(Err.Number) & ": " & Err.Description, vbCritical
|
|
selected_technology = "alz"
|
|
selected_language = "en"
|
|
import_graph_queries = True
|
|
End Sub
|
|
|
|
'Load in an object variable the existing values
|
|
Function get_user_input() As Boolean
|
|
On Error GoTo get_user_input_err
|
|
Dim row, checks_counter As Integer
|
|
row = row1
|
|
ReDim user_checks(3, 1) As String
|
|
Erase user_checks
|
|
checks_counter = 0
|
|
'Browse through all rows
|
|
Do While row < row_limit And Len(Cells(row, category_column)) > 0
|
|
'Only store a check if there is a non-blank comment or status is different than "Not Verified"
|
|
If Len(Cells(row, comments_column)) > 0 Or Cells(row, status_column) <> Sheets(values_sheet).Cells(2, values_status_column) Then
|
|
checks_counter = checks_counter + 1
|
|
ReDim Preserve user_checks(3, checks_counter) As String
|
|
user_checks(user_info_guid_index, checks_counter) = Cells(row, guid_column)
|
|
user_checks(user_info_comments_index, checks_counter) = Cells(row, comments_column)
|
|
user_checks(user_info_status_index, checks_counter) = Cells(row, status_column)
|
|
End If
|
|
row = row + 1
|
|
Loop
|
|
get_user_input = True
|
|
Exit Function
|
|
get_user_input_err:
|
|
If Err.Number <> 0 Then
|
|
MsgBox "Error while reading existing comments: " & Err.Description, vbCritical
|
|
End If
|
|
get_user_input = False
|
|
Exit Function
|
|
End Function
|
|
|
|
'Return the comments a status for a certain guid in an bidimensional array generated by get_user_input
|
|
Function get_user_input_from_guid(guid As String, ByRef comments As String, ByRef status As String) As Boolean
|
|
On Error GoTo get_user_input_from_guid_err
|
|
Dim i As Integer
|
|
comments = ""
|
|
status = ""
|
|
For i = 1 To UBound(user_checks(), 2)
|
|
If LCase(user_checks(user_info_guid_index, i)) = LCase(guid) Then
|
|
comments = user_checks(user_info_comments_index, i)
|
|
status = user_checks(user_info_status_index, i)
|
|
get_user_input_from_guid = True
|
|
Exit Function
|
|
End If
|
|
Next i
|
|
get_user_input_from_guid = False
|
|
Exit Function
|
|
get_user_input_from_guid_err:
|
|
If Err.Number = 9 Then 'Subscript out of range: silently exit
|
|
get_user_input_from_guid = False
|
|
Exit Function
|
|
ElseIf Err.Number <> 0 Then
|
|
Debug.Print "Error while retrieving comments/status for GUID " + guid + " - " & CStr(Err.Number) & ": " & Err.Description, vbCritical
|
|
End If
|
|
get_user_input_from_guid = False
|
|
Exit Function
|
|
End Function
|
|
|
|
'Disable some settings to speed up code
|
|
Sub DisableStuff()
|
|
Application.Calculation = xlCalculationManual
|
|
Application.ScreenUpdating = False
|
|
End Sub
|
|
|
|
'Enable settings back to normal
|
|
Sub EnableStuff()
|
|
Application.Calculation = xlCalculationAutomatic
|
|
Application.ScreenUpdating = True
|
|
End Sub
|
|
|
|
'Test sub
|
|
Sub test()
|
|
Dim comments As String, status As String
|
|
If get_user_input() Then
|
|
'Debug.Print CStr(UBound(my_checks, 2) - LBound(my_checks, 2))
|
|
If get_user_input_from_guid("a0f61565-9de5-458f-a372-49c831112dbd", comments, status) Then
|
|
Debug.Print "Comments: " + comments + ". Status: " + status
|
|
End If
|
|
End If
|
|
End Sub
|
|
|