A SOLIDWORKS user on the 3DEXPERIENCE forum recently posted a batch macro that failed to compile with “Invalid Character.” The macro tried to parameterize a Task Scheduler run with syntax like $$$FOLDER_PATH$$$ and made API calls to CustomPropertyData. Josh Brady identified it immediately: “That is AI-generated code. CustomPropertyData is a hallucinated call. It does not exist in the SolidWorks API.”
This failure pattern is now common enough to deserve a direct explanation. SOLIDWORKS Task Scheduler has no built-in parameter syntax. VBA macros cannot receive command-line arguments. There are no token substitutions in macro source code. Here is what works instead.
How Task Scheduler Actually Runs Macros
Before the fix, the problem needs to be clear.
Task Scheduler supports two different task modes that affect how macros behave:
Process Documents mode — Task Scheduler opens each file from a specified folder or file list, runs your macro on the active document, then closes the file. The macro operates on swApp.ActiveDoc. The folder is specified in the Task Scheduler UI, not in the macro. If your goal is to process every part in a folder, this is the correct mode. You do not need to pass a folder path to the macro at all — Task Scheduler handles the iteration.
Run Macro mode — Task Scheduler starts SolidWorks and runs a single macro once. The macro is responsible for opening its own files and managing file I/O. This is the mode where folder path becomes a real question: the macro must somehow know which folder to target.
Most engineers who ask “how do I pass a folder path to my macro?” are actually using Run Macro mode when Process Documents mode would solve their problem with no code changes. Before implementing any parameter-passing scheme, verify which mode fits your workflow.
Why AI Code Fails Here
The $$$FOLDER_PATH$$$ token notation does not exist in SolidWorks VBA. Depending on which AI model generated the code, it may have confused:
- SolidWorks PDM data card variable syntax — PDM card design uses
$PRP:"variablename"and%variablename%in different contexts, but none of these tokens appear in VBA source code - SolidWorks Drawing note property links —
$PRPSHEET:"Description"syntax pulls custom properties into drawing annotations, but again, not in VBA - Other automation frameworks — Windows batch file
%VARIABLE%, PowerShell$env:VAR, GitHub Actions${{ inputs.var }}, and dozens of other systems use similar delimiters; training data from these leaks into generated SolidWorks code
CustomPropertyData is similarly fictional. The actual interfaces for custom properties in the SolidWorks API are:
IModelDocExtension.CustomPropertyManager— returns anICustomPropertyManagerobject for a configurationICustomPropertyManager.Get6()— reads a property valueICustomPropertyManager.Add3()— writes a property valueICustomPropertyManager.Delete2()— removes a property
If you need to work with custom properties in bulk, the post on what the macro recorder silently drops covers why the recorder fails to capture property operations and what to write manually.
Pattern 1: Config File
The simplest reliable approach for Run Macro mode is a plain text config file. The macro reads the first line of a known file path at startup.
Option Explicit
' Path to the config file — hardcode this once and don't change it
Private Const CONFIG_FILE As String = "C:\CadTools\task_config.txt"
Sub main()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks
Dim folderPath As String
folderPath = ReadConfig(CONFIG_FILE, "FolderPath")
If Len(folderPath) = 0 Then
swApp.SendMsgToUser2 "Config key 'FolderPath' not found in: " & CONFIG_FILE, _
swMessageBoxIcon_e.swMbWarning, swMessageBoxBtn_e.swMbOk
Exit Sub
End If
ProcessFolder swApp, folderPath
End Sub
' Reads key=value pairs from a plain text config file.
' Returns empty string if file or key is missing.
Private Function ReadConfig(filePath As String, keyName As String) As String
ReadConfig = ""
If Dir(filePath) = "" Then Exit Function
Dim fileNum As Integer
fileNum = FreeFile()
Open filePath For Input As #fileNum
Dim line As String
Do While Not EOF(fileNum)
Line Input #fileNum, line
line = Trim(line)
' Skip blank lines and comments
If Len(line) = 0 Then GoTo NextLine
If Left(line, 1) = "'" Then GoTo NextLine
If Left(line, 1) = "#" Then GoTo NextLine
Dim eqPos As Integer
eqPos = InStr(line, "=")
If eqPos > 0 Then
Dim k As String, v As String
k = Trim(Left(line, eqPos - 1))
v = Trim(Mid(line, eqPos + 1))
If LCase(k) = LCase(keyName) Then
ReadConfig = v
Close #fileNum
Exit Function
End If
End If
NextLine:
Loop
Close #fileNum
End Function
Sub ProcessFolder(swApp As SldWorks.SldWorks, folderPath As String)
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FolderExists(folderPath) Then
swApp.SendMsgToUser2 "Folder not found: " & folderPath, _
swMessageBoxIcon_e.swMbWarning, swMessageBoxBtn_e.swMbOk
Exit Sub
End If
Dim folder As Object
Set folder = fso.GetFolder(folderPath)
Dim f As Object
For Each f In folder.Files
Dim ext As String
ext = LCase(Right(f.Name, 7))
If ext = ".sldprt" Or ext = ".sldasm" Or ext = ".slddrw" Then
ProcessFile swApp, f.Path
End If
Next f
End Sub
Sub ProcessFile(swApp As SldWorks.SldWorks, filePath As String)
Dim errors As Long, warnings As Long
Dim swDoc As SldWorks.ModelDoc2
Set swDoc = swApp.OpenDoc6(filePath, _
swDocumentTypes_e.swDocPART, _
swOpenDocOptions_e.swOpenDocOptions_Silent, _
"", errors, warnings)
If swDoc Is Nothing Then Exit Sub
' --- your per-file work here ---
swDoc.Save3 swSaveAsOptions_e.swSaveAsOptions_Silent, errors, warnings
swApp.CloseDoc filePath
End Sub
The config file C:\CadTools\task_config.txt contains:
# SOLIDWORKS task scheduler config
FolderPath = C:\Projects\Assemblies\2026\Batch1
OutputPath = C:\Output\DXF
To change which folder the task processes, edit the config file. The macro and the Task Scheduler task definition stay unchanged. Multiple tasks can point to the same macro with different config files by creating task_a_config.txt, task_b_config.txt, and so on, and using a wrapper macro per task that calls ReadConfig with the appropriate path.
Pattern 2: Windows Registry
If you prefer not to manage text files, the Windows registry works cleanly for string parameters.
Option Explicit
Private Const REG_ROOT As String = "HKCU\Software\CadTools\SWTasks\"
Sub main()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks
Dim wsh As Object
Set wsh = CreateObject("WScript.Shell")
Dim folderPath As String
On Error Resume Next
folderPath = wsh.RegRead(REG_ROOT & "FolderPath")
On Error GoTo 0
If Len(Trim(folderPath)) = 0 Then
swApp.SendMsgToUser2 "Registry key not found: " & REG_ROOT & "FolderPath", _
swMessageBoxIcon_e.swMbWarning, swMessageBoxBtn_e.swMbOk
Exit Sub
End If
ProcessFolder swApp, folderPath
End Sub
Set the registry value from PowerShell before the task runs:
Set-ItemProperty -Path "HKCU:\Software\CadTools\SWTasks" `
-Name "FolderPath" -Value "C:\Projects\Batch1" -Type String
Or from a scheduled PowerShell wrapper that writes the key, then invokes sldtaskscheduler.exe.
Process Documents Mode: The Folder Path You Don’t Need to Pass
If your goal is “run this macro on every part file in folder X,” stop and read the Task Scheduler task configuration dialog carefully.
The Update Custom Properties and Save As task types — and the generic Run Macro task when configured in Process Documents style — both include a folder selection field in their setup. You paste the source folder directly into the UI. Task Scheduler iterates the folder, opens each file, and calls your macro once per file with that file already active.
Inside the macro, you get the current file path from the active document:
Sub main()
Dim swApp As SldWorks.SldWorks
Set swApp = Application.SldWorks
Dim swDoc As SldWorks.ModelDoc2
Set swDoc = swApp.ActiveDoc
If swDoc Is Nothing Then Exit Sub
' The full path of the currently active document
Dim docPath As String
docPath = swDoc.GetPathName()
' Process it
Dim custMgr As SldWorks.CustomPropertyManager
Set custMgr = swDoc.Extension.CustomPropertyManager("")
Dim propVal As String, resolvedVal As String, wasResolved As Long
custMgr.Get6 "Description", False, propVal, resolvedVal, wasResolved
' Write a derived property based on the filename
Dim partNum As String
partNum = Left(Mid(docPath, InStrRev(docPath, "\") + 1), _
InStr(Mid(docPath, InStrRev(docPath, "\") + 1), ".") - 1)
custMgr.Add3 "PartNumber", swCustomInfoType_e.swCustomInfoText, _
partNum, swCustomPropertyAddOption_e.swCustomPropertyOnlyIfNew
swDoc.Save3 swSaveAsOptions_e.swSaveAsOptions_Silent, 0, 0
End Sub
No config file needed. The folder came from the Task Scheduler task definition. The macro gets the file path from ActiveDoc. This is the clean version of what John Sitek’s forum answer described as a “standalone approach” — except here it wires directly into Task Scheduler’s Process Documents mode instead of running as an independent loop.
Handling Multiple Configurations
One common scenario: a part has multiple configurations (Default, Lightweight, As Machined), and you need to run per-configuration processing. The CustomPropertyManager takes a configuration name:
' Process all configurations in the active document
Sub ProcessAllConfigs(swDoc As SldWorks.ModelDoc2)
Dim configNames As Variant
configNames = swDoc.GetConfigurationNames()
Dim i As Integer
For i = 0 To UBound(configNames)
Dim configName As String
configName = CStr(configNames(i))
Dim custMgr As SldWorks.CustomPropertyManager
Set custMgr = swDoc.Extension.CustomPropertyManager(configName)
' Read or write config-specific properties
Dim propVal As String, resolvedVal As String, wasResolved As Long
custMgr.Get6 "Description", False, propVal, resolvedVal, wasResolved
' ... process propVal
Next i
End Sub
For the general-purpose configuration of custom property management, the SolidWorks workflow automation guide covers where macros fit relative to Task Scheduler, PDM Dispatch, and C# add-ins — useful context before deciding how complex the parameter-passing scheme needs to be.
Running Task Scheduler from the Command Line
One pattern that avoids the parameter-passing problem entirely: run the task from a PowerShell script that writes the config file, then invokes the Task Scheduler executable directly. This is useful when Task Scheduler runs as part of a CI pipeline or is triggered by an external system.
# Write config file with tonight's batch folder
$batchFolder = "C:\Projects\Batch_$(Get-Date -Format 'yyyyMMdd')"
Set-Content -Path "C:\CadTools\task_config.txt" -Value "FolderPath = $batchFolder"
# Run the Task Scheduler task synchronously
$tsExe = "C:\Program Files\SOLIDWORKS Corp\SOLIDWORKS Task Scheduler\SWTaskSchedulerSrv.exe"
$taskFile = "C:\CadTools\NightlyBatchTask.swts" # saved task definition
& $tsExe /runTask $taskFile /wait
The /wait flag blocks until the task finishes. Exit code 0 means success; non-zero means something failed during processing.
What the Hallucinated Code Was Actually Trying to Do
For context: the forum user’s original code used $$$FOLDER_PATH$$$ as a template variable that they expected the Task Scheduler to substitute before passing the macro to VBA. It also called CustomPropertyData.GetFolderPath() as if a built-in class existed for this purpose.
Neither mechanism exists. The substitution idea has a parallel in some templating systems — Liquid, Mustache, even Word mail merge — but the SolidWorks macro runner is a plain VBA interpreter. It does not preprocess source code. What you write is what executes.
The CustomPropertyData class may have come from conflating ICustomPropertyManager (the real API) with a data-access object naming pattern from other frameworks. The SolidWorks API does not have helper classes like that; every operation goes through the COM interface hierarchy starting from ISldWorks.
If you are auditing AI-generated SolidWorks macro code, check for:
- Any identifier ending in
Data,Helper,Provider, orService— likely hallucinated - Token syntax with
$$$,%,{{, or[[in VBA source code — does not exist swApp.GetExtension()orswApp.GetService()— these methods do not exist onISldWorksApplication.GetCurrentDocument()— not a SolidWorks API call
The AI coding failures post covers the broader pattern of why language models produce plausible-looking but non-functional SolidWorks code.
Summary
SOLIDWORKS Task Scheduler macros cannot receive parameters through the macro itself. The two patterns that work:
| Use case | Pattern |
|---|---|
| Process Documents mode — operate on each file in a folder | No parameter passing needed — folder is in the Task Scheduler task UI |
| Run Macro mode — macro manages its own file I/O | Config file (text key=value) or Windows Registry |
Both patterns require one hardcoded path in the macro: either the config file path or the registry key root. That hardcoded path is the only dependency that needs to change when you clone a task for a different folder. Everything else — the batch logic, the per-file processing, the error handling — stays identical.
CadShift’s flat-pattern export works on top of this same pattern. If you need batch DXF export that behaves consistently across folders and doesn’t break when the source folder changes, the batch DXF export tools comparison covers what the standalone macro approach misses versus what a purpose-built add-in handles.