Code Library
SolidWorks APIVBASolidWorks 2016+ · built-in VBA editorMIT licenseAdvanced

Round-trip SolidWorks custom properties through a CSV (no PDM)

The shop without a PDM vault still needs to bulk-edit part numbers, materials, and revisions — and clicking through Properties on 200 parts is how an afternoon disappears. This is two macros sharing one schema constant: ExportPropertiesToCsv dumps every part's custom properties in a folder to one CSV; edit it in Excel; ImportPropertiesFromCsv writes the changes back. No vault, no Excel automation, no per-part clicking.

Before you run it

  • A folder of .SLDPRT files sharing the same custom-property schema
  • SolidWorks type-library references ticked in the VBA editor
  • Edit the FOLDER and PROP_NAMES constants to match your title block before running

The code

GitHub
Option Explicit

' Two macros, one schema. Export every part's custom properties in a folder
' to CSV, edit in Excel, then write the changes back. Parts only (.SLDPRT) -
' duplicate the loop with swDocASSEMBLY if you also need assemblies.

Const FOLDER As String = "C:\Parts\"                    ' must end with a backslash
Const CSV_PATH As String = "C:\Parts\properties.csv"
Const PROP_NAMES As String = "Description,PartNumber,Material,Revision"  ' edit to your schema

Sub ExportPropertiesToCsv()
    Dim swApp As SldWorks.SldWorks
    Set swApp = Application.SldWorks

    Dim props() As String
    props = Split(PROP_NAMES, ",")

    Dim f As Integer
    f = FreeFile
    Open CSV_PATH For Output As #f
    Print #f, "File," & PROP_NAMES

    Dim fileName As String
    fileName = Dir$(FOLDER & "*.sldprt")
    Dim opened As Long, failed As Long

    Do While fileName <> ""
        Dim errs As Long, warns As Long
        Dim swModel As SldWorks.ModelDoc2
        Set swModel = swApp.OpenDoc6(FOLDER & fileName, swDocPART, _
            swOpenDocOptions_Silent Or swOpenDocOptions_ReadOnly, "", errs, warns)

        If Not swModel Is Nothing Then
            Dim swCustProp As SldWorks.CustomPropertyManager
            Set swCustProp = swModel.Extension.CustomPropertyManager("")

            Dim row As String
            row = fileName
            Dim i As Long
            For i = 0 To UBound(props)
                Dim val As String, resolved As String
                swCustProp.Get4 Trim$(props(i)), False, val, resolved
                row = row & "," & Replace(resolved, ",", ";")  ' a comma here would break the CSV
            Next i
            Print #f, row
            opened = opened + 1
            swApp.CloseDoc swModel.GetTitle
        Else
            failed = failed + 1
            Debug.Print "COULD NOT OPEN: " & fileName
        End If

        fileName = Dir$()
    Loop
    Close #f

    swApp.SendMsgToUser opened & " file(s) exported to:" & vbNewLine & CSV_PATH & _
        vbNewLine & failed & " could not be opened."
End Sub

Sub ImportPropertiesFromCsv()
    Dim swApp As SldWorks.SldWorks
    Set swApp = Application.SldWorks

    Dim props() As String
    props = Split(PROP_NAMES, ",")

    Dim f As Integer
    f = FreeFile
    Open CSV_PATH For Input As #f

    Dim header As String
    Line Input #f, header   ' discard the header row

    Dim updated As Long, failed As Long
    Do While Not EOF(f)
        Dim rowText As String
        Line Input #f, rowText
        Dim cells() As String
        cells = Split(rowText, ",")
        If UBound(cells) < UBound(props) Then GoTo NextRow

        Dim errs As Long, warns As Long
        Dim swModel As SldWorks.ModelDoc2
        Set swModel = swApp.OpenDoc6(FOLDER & cells(0), swDocPART, _
            swOpenDocOptions_Silent, "", errs, warns)

        If Not swModel Is Nothing Then
            Dim swCustProp As SldWorks.CustomPropertyManager
            Set swCustProp = swModel.Extension.CustomPropertyManager("")

            Dim i As Long
            For i = 0 To UBound(props)
                swCustProp.Add3 Trim$(props(i)), swCustomInfoText, cells(i + 1), _
                    swCustomPropertyReplaceValue
            Next i
            swModel.Save3 swSaveAsOptions_Silent, errs, warns
            updated = updated + 1
            swApp.CloseDoc swModel.GetTitle
        Else
            failed = failed + 1
            Debug.Print "COULD NOT OPEN: " & cells(0)
        End If
NextRow:
    Loop
    Close #f

    swApp.SendMsgToUser updated & " file(s) updated, " & failed & " failed." & _
        vbNewLine & "Failures (if any) are in the Immediate window (Ctrl+G)."
End Sub

What you get

properties.csv

File,Description,PartNumber,Material,Revision
Bracket_100.SLDPRT,Mounting bracket,BRK-100,6061-T6,C
Standoff_012.SLDPRT,Spacer standoff,STD-012,303 SS,A
CoverPlate.SLDPRT,Access cover,CVR-045,5052-H32,B

3 file(s) exported to:
C:\Parts\properties.csv
0 could not be opened.

How it works

  • Both subs share one schema constantPROP_NAMES — so export and import always agree on which CSV column maps to which property. Change your schema once, in one place.
  • CustomPropertyManager.Get4 returns both the raw and the resolved value — resolved is what actually displays (it follows equations and linked properties), which is what belongs in a report.
  • Export replaces commas in values with semicolons before writing — the classic way a hand-rolled CSV writer corrupts itself is a comma inside a text field.
  • Import uses Add3 with swCustomPropertyReplaceValue, so re-running it is safe: properties get overwritten, not duplicated.

Gotchas & honest limits

  • Parts only, on purpose — assemblies need swDocASSEMBLY in OpenDoc6; duplicate the loop with the type swapped if you also batch assemblies.
  • This reads and writes file-level custom properties, not configuration-specific ones. Pass a configuration name into CustomPropertyManager instead of "" for config-specific values.
  • The import CSV must match the export CSV's column order exactly (File, then one column per name in PROP_NAMES) — it's positional, not header-matched like the openpyxl report script.
  • Round-tripping through Excel: format the property columns as text before saving the CSV, or Excel will happily mangle a part number that looks like a number (leading zeros, dashes read as minus signs).

Goes deeper

Want this adapted to your shop — or built into a real tool?

Samples are the free 80%. The last 20% is the part I do for a living.

Get in touch
Home
Blog
Tools
Code
Email
LinkedIn
Résumé