Get the Linked Element from Linked Id

Hi everyone, some time ago I checked if it was possible to get linked elements for a linked ID, but there was no solution. I’m still unsure if it’s possible now. Is there any workaround to retrieve the linked elements from a linked ID? I have a list of linked IDs (clashing elements) that I am extracting from Excel.

I came across this because i was working on a similar idea and though I share since I just started to play around with linked models scripts. this was more from an electrical standpoint trying to find linked mechanical equipment. you can use it based on parameter or element id. (shift-click) to reconfigure. hopefully this helps.

pick_config.py

# -*- coding: utf-8 -*-
# pick_config.py for FindinLink
# Saves/loads last used mode (ElementId or Parameter),
# plus category, parameter name, and linked model.
# Shift-click to reconfigure.

from pyrevit import revit, forms, script
from Autodesk.Revit.DB import RevitLinkInstance, FilteredElementCollector

logger = script.get_logger()
my_config = script.get_config("findinlink_config")


def load_configs():
    """Return last used mode, category name, parameter name, and link name (safe)."""
    try:
        last_mode = my_config.get_option("last_mode")
    except:
        last_mode = None

    try:
        last_cat = my_config.get_option("last_category")
    except:
        last_cat = None

    try:
        last_param = my_config.get_option("last_param")
    except:
        last_param = None

    try:
        last_link = my_config.get_option("last_link")
    except:
        last_link = None

    # Show summary if we have something
    summary_lines = []
    if last_mode:
        summary_lines.append("Mode: {}".format(last_mode))
    if last_mode == "Parameter":
        if last_cat:
            summary_lines.append("Category: {}".format(last_cat))
        if last_param:
            summary_lines.append("Parameter: {}".format(last_param))
    if last_link:
        summary_lines.append("Link: {}".format(last_link))

    if summary_lines:
        forms.alert("Using Preset:\n" + "\n".join(summary_lines) +
                    "\n\nShift-click to reconfigure")

    return last_mode, last_cat, last_param, last_link


def save_configs(mode, category_name, param_name, link_name):
    """Save mode, category name, parameter name, and link name"""
    my_config.last_mode = mode
    my_config.last_category = category_name
    my_config.last_param = param_name
    my_config.last_link = link_name
    script.save_config()


def configure_defaults():
    """Ask user to reconfigure defaults"""
    # Search mode
    mode_choice = forms.CommandSwitchWindow.show(
        ["ElementId", "Parameter"],
        message="Set default search mode"
    )
    if not mode_choice:
        return None, None, None, None

    picked_cat = None
    param_name = None
    picked_link = None

    if mode_choice == "Parameter":
        # categories (only model categories)
        cats = revit.doc.Settings.Categories
        model_cats = []
        for c in cats:
            try:
                if (c.CategoryType.ToString() == "Model"
                    and c.AllowsBoundParameters
                    and c.Id.IntegerValue < 0):
                    model_cats.append(c)
            except:
                pass

        picked_cat = forms.SelectFromList.show(
            sorted(model_cats, key=lambda x: x.Name),
            name_attr="Name",
            title="Select Default Category",
            multiselect=False
        )
        if not picked_cat:
            return None, None, None, None

        param_name = forms.ask_for_string(
            prompt="Enter default parameter name (e.g. Mark)",
            title="Default Parameter"
        )
        if not param_name:
            return None, None, None, None

    # linked model
    link_instances = FilteredElementCollector(revit.doc).OfClass(RevitLinkInstance).ToElements()
    if not link_instances:
        forms.alert("No linked models found in project.")
        return None, None, None, None

    link_names = [li.Name for li in link_instances]
    picked_link = forms.SelectFromList.show(
        sorted(link_names),
        title="Select Default Linked Model",
        multiselect=False
    )
    if not picked_link:
        return None, None, None, None

    save_configs(mode_choice,
                 picked_cat.Name if picked_cat else None,
                 param_name,
                 picked_link)

    return mode_choice, (picked_cat.Name if picked_cat else None), param_name, picked_link


if __name__ == "__main__":
    configure_defaults()

and then the FindinLink_script.py

# -*- coding: utf-8 -*-
# pyRevit | IronPython 2.7
# Find element by ElementId OR by Parameter in Linked Model and zoom to it (case-insensitive).
# Remembers last used search mode, category, parameter, and linked model.
# Shift-click to reconfigure.

import clr, sys
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')

import System

from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import UIDocument
from pyrevit import revit, DB, forms, script, EXEC_PARAMS

# import config helper
import pick_config

doc = revit.doc
uidoc = revit.uidoc
logger = script.get_logger()


# ----------------- Helpers -----------------
def get_all_model_categories():
    """Return only valid model categories (no DWGs, no annotation)."""
    cats = revit.doc.Settings.Categories
    model_cats = []
    for c in cats:
        try:
            if (c.CategoryType == DB.CategoryType.Model
                and c.AllowsBoundParameters
                and c.Id.IntegerValue < 0):  # real BuiltInCategories only
                model_cats.append(c)
        except Exception as err:
            logger.debug("Skipped category: {}".format(err))
    return sorted(model_cats, key=lambda x: x.Name)


def pick_model_category(default_name=None):
    """Ask user to pick one model category (default preselected if available)."""
    all_cats = get_all_model_categories()
    if not all_cats:
        forms.alert("No model categories found.", exitscript=True)

    if default_name:
        for c in all_cats:
            if c.Name == default_name:
                return c

    picked = forms.SelectFromList.show(
        all_cats,
        name_attr='Name',
        title='Select Category',
        multiselect=False
    )
    return picked


def get_param_value(param):
    """Return parameter value as string for comparison."""
    if not param:
        return None
    if param.StorageType == StorageType.String:
        return param.AsString()
    elif param.StorageType == StorageType.Integer:
        return str(param.AsInteger())
    elif param.StorageType == StorageType.Double:
        return str(round(param.AsDouble(), 3))  # keep readable
    elif param.StorageType == StorageType.ElementId:
        return str(param.AsElementId().IntegerValue)
    return None


def get_parameter_by_name(elem, name):
    """Find parameter by name (case-insensitive)."""
    for p in elem.Parameters:
        if p.Definition and p.Definition.Name.lower() == name.lower():
            return p
    return None


def zoom_to_element_in_view(elem, transform, ui_view):
    """Zooms to element bounding box inside given UIView."""
    bbox = elem.get_BoundingBox(None)
    if not bbox:
        return False
    min_pt = transform.OfPoint(bbox.Min)
    max_pt = transform.OfPoint(bbox.Max)
    ui_view.ZoomAndCenterRectangle(min_pt, max_pt)
    return True


# ----------------- Step 0: Config Handling -----------------
if EXEC_PARAMS.config_mode:
    pick_config.configure_defaults()
    sys.exit()

last_mode, last_cat, last_param, last_link = pick_config.load_configs()


# ----------------- Step 1: Ask Mode -----------------
if last_mode:
    mode_choice = last_mode
else:
    mode_choice = forms.CommandSwitchWindow.show(
        ["ElementId", "Parameter"],
        message="Search by ElementId or Parameter?"
    )
if not mode_choice:
    forms.alert("No search mode selected.", exitscript=True)

is_id_search = (mode_choice.lower() == "elementid")


# ----------------- Step 2: Collect Inputs -----------------
selected_cat = None
param_name = None

if is_id_search:
    param_value = forms.ask_for_string(
        prompt="Enter the ElementId value to find (e.g. 123456):",
        title="ElementId Search"
    )
    if not param_value:
        forms.alert("No ElementId entered.", exitscript=True)

else:  # Parameter search
    selected_cat = pick_model_category(default_name=last_cat)
    if not selected_cat:
        forms.alert("No category selected.", exitscript=True)

    bic = System.Enum.ToObject(DB.BuiltInCategory, selected_cat.Id.IntegerValue)

    if last_param:
        param_name = last_param
    else:
        param_name = forms.ask_for_string(
            prompt="Enter the parameter name to search (e.g. Mark, Type Mark):",
            title="Parameter Name"
        )
    if not param_name:
        forms.alert("No parameter name entered.", exitscript=True)

    param_value = forms.ask_for_string(
        prompt="Enter the parameter value to find (e.g. VAV-101):",
        title="Parameter Value")
    if not param_value:
        forms.alert("No parameter value entered.", exitscript=True)


# ----------------- Step 3: Linked Model -----------------
link_instances = FilteredElementCollector(doc).OfClass(RevitLinkInstance).ToElements()
if not link_instances:
    forms.alert("No linked models found in this project.", exitscript=True)

link_names = {li.Name: li for li in link_instances}

if last_link and last_link in link_names:
    link_choice = last_link
else:
    link_choice = forms.SelectFromList.show(
        sorted(link_names.keys()),
        title="Select Linked Model",
        multiselect=False
    )
if not link_choice:
    forms.alert("No linked model selected.", exitscript=True)

link_instance = link_names[link_choice]
link_doc = link_instance.GetLinkDocument()
if not link_doc:
    forms.alert("Linked document not available (maybe unloaded).", exitscript=True)


# ----------------- Save updated defaults -----------------
pick_config.save_configs(mode_choice,
                         selected_cat.Name if selected_cat else None,
                         param_name,
                         link_choice)


# ----------------- Step 4: Search -----------------
matches = []

if is_id_search:
    try:
        elem_id = ElementId(int(param_value))
        target_elem = link_doc.GetElement(elem_id)
        if target_elem:
            matches.append(target_elem)
    except Exception as ex:
        logger.debug("ElementId search failed: {}".format(ex))
else:
    collector = FilteredElementCollector(link_doc).OfCategory(bic).WhereElementIsNotElementType()
    for e in collector:
        p = get_parameter_by_name(e, param_name)
        val = get_param_value(p)
        if val and val.lower() == param_value.lower():
            matches.append(e)

if not matches:
    forms.alert("No element found with {} = {}".format(
        "ElementId" if is_id_search else param_name, param_value))
    sys.exit()

# If multiple matches → let user pick
if len(matches) > 1:
    target_elem = forms.SelectFromList.show(
        matches,
        name_attr='Id',
        title="Multiple matches found. Pick one:",
        multiselect=False
    )
else:
    target_elem = matches[0]


# ----------------- Step 6: View Selection + Zoom -----------------
transform = link_instance.GetTransform()
active_view = doc.ActiveView
ui_views = uidoc.GetOpenUIViews()

chosen_view = None

# Case 1: Already in a floor plan
if active_view.ViewType == ViewType.FloorPlan:
    use_current = forms.alert("You are in a floor plan view.\nDo you want to use this view?",
                              yes=True, no=True)
    if use_current:
        chosen_view = active_view

# Case 2: Ask user to pick from open floor plans
if not chosen_view:
    open_plans = []
    for uv in ui_views:
        v = doc.GetElement(uv.ViewId)
        if v.ViewType == ViewType.FloorPlan:
            open_plans.append(v)

    if open_plans:
        chosen_view = forms.SelectFromList.show(
            sorted(open_plans, key=lambda x: x.Name),  # 🔹 sort by name
            name_attr='Name',
            title="Select from open Floor Plans",
            multiselect=False
        )

# Case 3: Ask from all floor plans in project
if not chosen_view:
    all_plans = FilteredElementCollector(doc).OfClass(ViewPlan)\
                  .WhereElementIsNotElementType()\
                  .ToElements()
    chosen_view = forms.SelectFromList.show(
        sorted(all_plans, key=lambda x: x.Name),
        name_attr='Name',
        title="Select a Floor Plan View",
        multiselect=False
    )


# Final: Switch to chosen view and zoom
if chosen_view:
    uidoc.ActiveView = chosen_view
    ui_view = [uv for uv in uidoc.GetOpenUIViews() if uv.ViewId == chosen_view.Id][0]
    zoom_to_element_in_view(target_elem, transform, ui_view)

    forms.alert("✅ Found element with {} = {}\nCategory: {}\nElementId: {}\nZoomed in view: {}".format(
        "ElementId" if is_id_search else param_name,
        param_value,
        selected_cat.Name if selected_cat else "N/A",
        target_elem.Id,
        chosen_view.Name))
else:
    forms.alert("No floor plan view selected. Cannot zoom.")

@Jean-Marc

not sure if this is one worth adding to the Pick toolset but happy to share the idea.