Hi all,
I stubled upon a task to automate adding 10 new phases to cca 200 files. I googled, searched through forum and find out that it is not possible to automate this by API cause it’s not published for this. But because I am too busy to open 200 files manualy I decided to go a bit deeper (with a help of Gemini) and found a solution to this issue.
In fact the sollution is pretty simple - Workflow
- Let the script open the Phase pop-up window
- just before thata start a simple script (VBScript / Py - depends on your preferences, for this case I used a VBScript ) that simulates keystrokes of user (no mouse, just keyboard hits)
- the script is running behind and executing all the “user” keystrokes
- then executes “Enter” to close the window
- It has just one little but important issue → don’t touch your mouse or keyboard when you hit “Run”
Depending on your situation you have to modify the number of “Tab” keystrokes you need to accomplish your case
My code:
# -*- coding: utf-8 -*-
import os
import subprocess
import tempfile
# Standard Dynamo Revit imports
import clr
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import RevitCommandId
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
# Get the UIApplication in Dynamo
uiapp = DocumentManager.Instance.CurrentUIApplication
# You can either hardcode the values here like your original script:
phases_to_add = ["E1", "E2", "E3","E4","E5","E6","E7","E8","E9","E10"]
rename_phase = "E0"
# OR uncomment the lines below to feed them in dynamically from Dynamo nodes:
# phases_to_add = IN[0] # Feed a list of strings into IN[0]
# rename_phase = IN[1] # Feed a string into IN[1]
def generate_and_run_killer_script(phases):
vbs_code = 'Set WshShell = WScript.CreateObject("WScript.Shell")\n'
vbs_code += 'WScript.Sleep 2500\n'
# Tab 5 times to reach the last phase
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
vbs_code += 'WshShell.SendKeys "{}"\n'.format(rename_phase)
vbs_code += 'WScript.Sleep 300\n'
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
for phase in phases:
# 1. 'F' shortcut to Insert After
vbs_code += 'WshShell.SendKeys "f"\n'
vbs_code += 'WScript.Sleep 300\n'
# 2. Tab once to enter the Name cell
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
# Wait a tiny bit longer for the cell to fully enter "Edit Mode"
vbs_code += 'WScript.Sleep 400\n'
# 3. Type the phase name
vbs_code += 'WshShell.SendKeys "{}"\n'.format(phase)
vbs_code += 'WScript.Sleep 300\n'
# 4. Tab 3 more times to escape the Name and Description parameters
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
vbs_code += 'WshShell.SendKeys "{TAB}"\n'
vbs_code += 'WScript.Sleep 300\n'
# Hit Enter to click OK and save all changes
vbs_code += 'WshShell.SendKeys "{ENTER}"\n'
# Write to temp .vbs file
temp_dir = tempfile.gettempdir()
vbs_path = os.path.join(temp_dir, "revit_phasing_killer.vbs")
with open(vbs_path, "w")as f:
f.write(vbs_code)
# Launch the VBScript as a detached process
subprocess.Popen(["wscript.exe", vbs_path])
# --- MAIN EXECUTION ---
generate_and_run_killer_script(phases_to_add)
# Post the command to open the Phasing Dialog
cmId = RevitCommandId.LookupCommandId("ID_SETTINGS_PHASES")
# Standard output variable for Dynamo
output_msg = ""
if cmId is notNoneand uiapp.CanPostCommand(cmId):
uiapp.PostCommand(cmId)
output_msg = "Success: Posted command and running VBScript."
else:
output_msg = "Failed: Cannot post command in the current state."
# Output to Dynamo
OUT = output_msg
Showcase of what it does:
Now you’re curios if you can use it for other not exposed API calls?
And I have to say, YES DEFINITELY
I did accomplish to automate “Bind link” with this exact technique
p.s. although I must admit that for the 200 files I ditched Dynamo for pyRevit to get maximum speed - sorry for that. But I hope that next time someone will search “How to add / create / copy phase” they’ll stumble at this post and will make their work a bit more effective ![]()