WinCC VBScript: Loop HMI Tags with a Counter and Export to Excel
When an HMI project grows to dozens of similarly named tags (for example, twelve recipe data blocks, fifty counter values, or a hundred axis parameters), hard-coding one VBScript line per tag becomes unmanageable. The fix is the same technique used in every other language: build the tag name as a string, concatenate an integer counter, and execute the read/write inside a For...Next loop. This article documents the working pattern for SIMATIC WinCC Professional / TIA Portal and WinCC Runtime Advanced, shows the corrected loop syntax, the Excel automation model, and a fallback path that exports an Online Table Control to CSV without enumerating tags at all.
1. Problem Definition
The starting point is a tag list that follows a strict numeric pattern. In a TIA Portal project with a S7-1500 PLC connection named S7(1), the HMI tag prefix typically resolves to the program block or the data block reference in the runtime namespace:
HMIRuntime.Tags("Programa$S7(1)/DATOS1.B_E_CAD")
HMIRuntime.Tags("Programa$S7(1)/DATOS2.B_E_CAD")
HMIRuntime.Tags("Programa$S7(1)/DATOS3.B_E_CAD")
...
HMIRuntime.Tags("Programa$S7(1)/DATOS12.B_E_CAD")
Repeating that statement 50 times is fragile: any rename of the connection or block forces a global search-and-replace, and the script is difficult to review. The objective is to:
- Loop from
1toN(whereNis configurable, e.g. 12 or 50). - Build the runtime tag name as
"Programa$S7(1)/DATOS" & i & ".B_E_CAD". - Read the tag value through the
HMIRuntime.Tagsobject. - Write the value into a specific cell of an Excel worksheet.
- Close Excel and release the COM object.
2. Prerequisites
| Item | Requirement |
|---|---|
| Engineering framework | TIA Portal V16 or higher (tested through V18 / V19 with WinCC Professional V18/V19) |
| Runtime | WinCC Runtime Advanced (PC-based) or WinCC Professional (RT) on Windows 10/11 / Windows Server 2019/2022 |
| Scripting language | VBScript 5.8 (Windows Script Host), no external libraries |
| Target application | Microsoft Excel 2016 / 2019 / 2021 / 365 (32-bit or 64-bit, matching Office install of the runtime PC) |
| PLC connection | An active S7-1200/1500 HMI connection in the project (e.g. S7(1)). See SIMATIC WinCC Professional V18 - Communication
|
| Tag namespace | Numeric suffix must be contiguous (e.g. 1..12). Non-contiguous names require an array of indices. |
3. WinCC Tag Naming Convention
WinCC Runtime Advanced and WinCC Professional expose two distinct namespaces for the Tags object:
| Runtime | Object model | Reference syntax |
|---|---|---|
| WinCC Professional (TIA Portal V18+) | HmiRuntime |
HmiRuntime.Tags("TagName") |
| WinCC Runtime Advanced (TIA Portal V16-V17) | HMIRuntime |
HMIRuntime.Tags("TagName") |
| WinCC V7 / WinCC V8 (Classic) |
HMIRuntime with different hierarchy |
HMIRuntime.Tags("S7(1)/TagName") |
For a TIA Portal project where the S7-1500 program block is named Programa and the connection is S7(1), a tag inside an instance DB shows up as:
Programa$S7(1)/DATOS1.B_E_CAD
The separator characters are fixed:
-
$separates the program block from the connection. -
()bracket the connection ID number. -
/separates the connection from the tag path. -
.(dot) addresses a UDT/struct member, identical to the S7 dot notation in the PLC.
HmiRuntime (capital H, capital R). The legacy spelling HMIRuntime still works in older runtimes but is documented for V16/V17 projects. Mixing the two in the same script triggers Object required: 'HmiRuntime' at runtime. Refer to the TIA Portal V18 WinCC Professional manual for the canonical object name.4. Why the Original Loop Did Not Run
The original draft contained a syntax error in the For header and was missing the Set keyword on the tag assignment. The two issues are independent:
For i = 1 To i= 12 ' INVALID: VBScript uses 'To', not 'i= 12'
HMIRuntime.Tags("Programa$S7(1)/DATOS" & i & ".B_E_CAD") ' missing Set
objTag.Read
o
VBScript requires the bound of a For loop to be a constant, variable, or numeric expression — never an assignment. The corrected header is:
For i = 1 To 12
Set objTag = HMIRuntime.Tags("Programa$S7(1)/DATOS" & i & ".B_E_CAD")
objTag.Read
objWorkSheet.Cells(1 + i, 2).Value = objTag.Value
Next
Three things changed:
-
For i = 1 To 12instead ofFor i = 1 To i = 12— the loop end value is the literal12, not a re-assignment. -
Set objTag = HMIRuntime.Tags(...)— theTags(...)property returns aTagobject; assigning it to a variable requires theSetstatement in VBScript. -
objTag.Readrefreshes the value from the PLC; without it, the cached value from the last cycle is returned.
5. Building the Tag String with a Counter
String concatenation in VBScript uses the ampersand (&). The numeric counter is implicitly converted to a string when concatenated with a string literal. The expression "Programa$S7(1)/DATOS" & i & ".B_E_CAD" builds:
| i | Resolved runtime tag path |
|---|---|
| 1 | Programa$S7(1)/DATOS1.B_E_CAD |
| 2 | Programa$S7(1)/DATOS2.B_E_CAD |
| 3 | Programa$S7(1)/DATOS3.B_E_CAD |
| ... | ... |
| 12 | Programa$S7(1)/DATOS12.B_E_CAD |
For non-contiguous indices (for example, odd/even sets or a recipe that uses 10, 20, 30...), replace the integer with a constant array and iterate over it:
Dim idx
idx = Array(1, 4, 7, 12, 19, 27)
For Each i In idx
Set objTag = HMIRuntime.Tags("Programa$S7(1)/DATOS" & i & ".B_E_CAD")
objTag.Read
objWorkSheet.Cells(1 + i, 2).Value = objTag.Value
Next
6. Excel Automation Object Model
VBScript launches Excel as an out-of-process COM server through CreateObject("Excel.Application"). The object hierarchy used in this article is:
| Object | Type / class | Role |
|---|---|---|
objExcelApp |
Excel.Application |
Top-level Excel process; controls visibility, workbooks, and quit |
objWorkBook |
Excel.Workbook |
A single .xls[x] file |
objWorkSheet |
Excel.Worksheet |
One sheet inside a workbook |
objWorkSheet.Cells(r, c) |
Excel.Range |
A single cell addressed by row/column integers (1-based) |
Common pitfalls when scripting Excel from WinCC:
-
File path with spaces. Always double the backslash or use
Replace(path, "\\", "\\\\"); the path inWorkbooks.Openis a single string. -
Already-open workbook. If a user has the same file open,
Workbooks.Openwill attach to that instance. UseReadOnlyor a unique temporary path to avoid conflicts. -
Process leak.
Quitfollowed bySet objExcelApp = Nothingis mandatory; otherwise the Excel process remains in Task Manager underEXCEL.EXE.
7. Complete Working Script (12-Recipe Export)
Drop this code into a button's Click event in WinCC Professional / Runtime Advanced. Change the constants in the top block to match your connection, tag prefix, and Excel file path.
' --- Configuration --------------------------------------------------
Const TAG_PREFIX = "Programa$S7(1)/DATOS"
Const TAG_SUFFIX = ".B_E_CAD"
Const FIRST_INDEX = 1
Const LAST_INDEX = 12
Const EXCEL_PATH = "C:\Recipes\export.xls"
Const SHEET_NAME = "Recipes"
Const START_ROW = 2 ' row 1 reserved for header
' -------------------------------------------------------------------
Dim i
Dim objTag
Dim objExcelApp
Dim objWorkBook
Dim objWorkSheet
Dim strHeader
Dim bHeaderWritten
Set objExcelApp = CreateObject("Excel.Application")
objExcelApp.Visible = True
objExcelApp.DisplayAlerts = False
' Open an existing workbook or create a new one
Set objWorkBook = objExcelApp.Workbooks.Open(EXCEL_PATH, , False) ' ReadWrite
Set objWorkSheet = objWorkBook.Sheets(SHEET_NAME)
If objWorkSheet Is Nothing Then
Set objWorkSheet = objWorkBook.Sheets.Add
objWorkSheet.Name = SHEET_NAME
End If
' Write a header once
If objWorkSheet.Cells(1, 2).Value = "" Then
objWorkSheet.Cells(1, 1).Value = "Recipe #"
objWorkSheet.Cells(1, 2).Value = "Barcode / CAD value"
bHeaderWritten = True
End If
For i = FIRST_INDEX To LAST_INDEX
Set objTag = HmiRuntime.Tags(TAG_PREFIX & i & TAG_SUFFIX)
If objTag Is Nothing Then
' Skip missing tags - avoids 0-value pollution
HmiRuntime.Trace "Missing tag: " & TAG_PREFIX & i & TAG_SUFFIX & vbCrLf
Else
objTag.Read
objWorkSheet.Cells(START_ROW + i - 1, 1).Value = i
objWorkSheet.Cells(START_ROW + i - 1, 2).Value = objTag.Value
End If
Next
objWorkBook.Save
objWorkBook.Close False
objExcelApp.Quit
Set objWorkSheet = Nothing
Set objWorkBook = Nothing
Set objExcelApp = Nothing
Set objTag = Nothing
The script will:
- Open (or create)
C:\Recipes\export.xls. - Activate the sheet
Recipesor create it if it does not exist. - Write the header line the first time the script runs.
- Loop from
1to12, reading each tag and writing two columns: index and value. - Save and close the workbook, then release the COM references.
8. Scaling the Loop to 50+ Tags
Replacing LAST_INDEX = 12 with 50 is the only change required to export fifty tags. Two refinements are recommended when the loop count grows:
-
Drive
LAST_INDEXfrom a tag. A signed integer HMI tag (for example,Config.LastIndex) makes the script reusable without recompilation.Const FIRST_INDEX = 1 Dim nLast Set objTag = HmiRuntime.Tags("Config.LastIndex") objTag.Read nLast = CInt(objTag.Value) For i = FIRST_INDEX To nLast ... Next -
Batch the read with a tag array. If all 50 tags share the same S7 connection and area, declare a tag array in TIA Portal (right-click on the HMI tag > Properties > Array). The runtime exposes the whole array with a single
Read:
A single read of a structured array is typically 10-50x faster than 50 individual round-trips because the S7 communication driver batches the request.Set objTag = HmiRuntime.Tags("Programa$S7(1)/DATOS_Array") objTag.Read For i = 0 To objTag.Count - 1 objWorkSheet.Cells(START_ROW + i, 2).Value = objTag.Value(i) Next
objTag.Read inside a tight loop blocks the HMI main thread. With 50 tags on a 100 ms tag cycle this adds 5 s of UI latency. Use Change-made triggered reads (event-driven) or the array method above to keep the HMI responsive. See SIMATIC WinCC Performance Tuning for guidance on tag acquisition rate and screen refresh.9. Exporting the Online Table Control to CSV without Enumerating Tags
When the data already lives inside an Online Table Control (the WinCC control that records a tag history and renders it as a table), there is a one-liner that exports the visible buffer as a CSV without iterating tag names. The runtime object is ScreenItems("ControlName"), exposed through the WinCC Controls documentation:
Dim objTable
Set objTable = HmiRuntime.Screens("Recipe_Overview").ScreenItems("TableControl1")
objTable.SaveData "C:\Recipes\table_export.csv", 1 ' 1 = CSV
The SaveData method is part of the Online Table Control interface and supports the following flags:
| Constant | Value | Effect |
|---|---|---|
vbCSV |
1 | Comma-separated values, one header row + one row per record |
vbText |
2 | Tab-separated, useful for paste into Excel via clipboard |
vbUnicode |
64 | UTF-16 LE output; required for non-ASCII characters in recipes |
To export several online table controls at once (e.g. one per process cell), use a For Each loop over a collection or an array of control names:
Dim sName, sScreen
Dim aControls
sScreen = "Recipe_Overview"
aControls = Array("TableControl1", "TableControl2", "TableControl3")
For Each sName In aControls
HmiRuntime.Screens(sScreen).ScreenItems(sName).SaveData _
"C:\Recipes\" & sName & ".csv", 1 + 64 ' CSV + Unicode
Next
This approach exports the runtime history of each table control — which is what end users want when they press the "Export" button on a process screen. It does not require enumerating the source tags at all.
10. Reading, Quality Code, and Caching
The Tag object exposes a QualityCode property and a Quality string that report the validity of the last read. Always check it before writing a value to Excel, otherwise a stale or bad value (PLC disconnected, area pointer overflow) silently contaminates the report:
objTag.Read
Select Case objTag.QualityCode
Case 0 ' Good
objWorkSheet.Cells(START_ROW + i - 1, 2).Value = objTag.Value
Case &H0010 ' Uncertain
objWorkSheet.Cells(START_ROW + i - 1, 2).Value = objTag.Value
objWorkSheet.Cells(START_ROW + i - 1, 3).Value = "UNCERTAIN"
Case Else ' Bad / Not connected
objWorkSheet.Cells(START_ROW + i - 1, 2).Value = ""
objWorkSheet.Cells(START_ROW + i - 1, 3).Value = "BAD (0x" & Hex(objTag.QualityCode) & ")"
End Select
Quality code values are defined by the OPC UA specification. The most common codes observed in a WinCC runtime are:
| Code (hex) | Status | Meaning in a WinCC/S7 environment |
|---|---|---|
| 0x00000000 | Good | Value valid, fresh, no constraint violation |
| 0x40000000 | Uncertain | Value is plausible but the source is suspect |
| 0x803D0000 | Bad - Out of Service | Tag disabled in TIA Portal configuration |
| 0x803F0000 | Bad - Communication Error | Connection to the S7 PLC is down |
| 0x80400000 | Bad - Waiting for Initial Data | Runtime started; no first read yet |
Reference the OPC UA Part 4 - Service Set / StatusCodes for the complete list.
11. Error Handling in VBScript
VBScript does not have structured try/catch blocks. The standard pattern is On Error Resume Next followed by explicit error inspection with Err.Number / Err.Description:
On Error Resume Next
Set objExcelApp = CreateObject("Excel.Application")
If Err.Number <> 0 Then
HmiRuntime.Trace "Excel not available: 0x" & Hex(Err.Number) _
& " - " & Err.Description & vbCrLf
Err.Clear
Exit Sub
End If
On Error Resume Next
Set objWorkBook = objExcelApp.Workbooks.Open(EXCEL_PATH)
If Err.Number <> 0 Then
HmiRuntime.Trace "Cannot open " & EXCEL_PATH _
& " - " & Err.Description & vbCrLf
objExcelApp.Quit
Exit Sub
End If
On Error Goto 0
On Error Goto 0 before entering the main loop. Leaving Resume Next in effect masks PLC tag errors that should be visible during commissioning.12. Verification Checklist
Run the script in the runtime and confirm the following before sign-off:
- Open the target Excel file and confirm the header row is written only once (not overwritten on every click).
- Confirm rows 2..13 contain the values of
DATOS1.B_E_CADthroughDATOS12.B_E_CADin column B. Change one of the PLC values and re-click the button; the script should overwrite the cell with the new value. - Stop the S7-1500 connection in TIA Portal's "Online > Accessible nodes" and re-run. The Quality column should read
BAD (0x803F0000), and Excel should be empty for that row. - Open Task Manager. After script completion, no
EXCEL.EXEinstance should remain (orphan process check). - Force a typographic error in the tag name (e.g.
DATOS1B_E_CADmissing the dot). The script should produce a trace entry, not a hard crash.
13. Frequently Asked Questions
What is the correct VBScript syntax for a numeric For...Next loop in WinCC?
Use For i = 1 To 12 with the constant 12 as the upper bound; do not write For i = 1 To i = 12. The To keyword requires a constant or expression on its right side, never an assignment. Reference the Microsoft VBScript Language Reference for the full grammar.
Can I read an entire S7 data block with one call instead of looping 50 times?
Yes. Declare a PLC tag of type array of with the right number of elements in the DB and read it once through HmiRuntime.Tags("Programa$S7(1)/DATOS_Array"). The runtime returns a Value array that you can index directly: objTag.Value(i). This is the recommended pattern for 30+ tags because it cuts S7 round-trips from 30 to 1.
Why does the script fail with "Object required: 'HmiRuntime'"?
Either the object name is misspelled (use HmiRuntime in TIA Portal V18+, HMIRuntime in older runtimes), or the script is running in a context where the runtime is not initialised (e.g. a global function called from the scheduler before the first screen loads). Move the script to a button Click event in a loaded screen, or use the HMIRuntime.Trace method to confirm the runtime is alive.
How do I export several Online Table Controls to separate CSV files?
Use the SaveData method on the control object: HmiRuntime.Screens("MyScreen").ScreenItems("TableControl1").SaveData "C:\export\a.csv", 1. Loop over an array of control names to export them all in one script. The flag 1 requests CSV; add 64 to request Unicode encoding for non-ASCII recipes.
What is the difference between HMIRuntime and HmiRuntime?
HMIRuntime is the legacy object name used in WinCC Runtime Advanced / WinCC Flexible / TIA Portal V15-V17. TIA Portal V18 standardised on HmiRuntime (capital H, capital R). Both still compile in the current WinCC Professional V18/V19 editor for backward compatibility, but new projects should use the V18 spelling. The complete API surface is documented in the TIA Portal V18 WinCC Professional manual.