TeamcenterKnowledge

Skills

TC Deployment Center

Skill tc-deployment-center. Teamcenter Deployment Center - the centralized web app that models environments, holds the software repository, and generates the deployment scripts that actually install or update Teamcenter on target machines. Covers the concept model (Environment / Software / Applications / Components), the repository rules that silently hide kits, quick deploy and its utilities, and how custom DC-compatible packages get built. Use for installing or updating Teamcenter modules, and for authoring Deployment Center packages.

Grounding status, read this first. Everything marked VERIFIED was checked against the live TC2606 VM. Everything else is distilled from the 2606 product documentation and has not yet been executed here. Deployment Center is not installed or running on this VM as of 2026-08-05. Do not report a DC action as done on the strength of this skill alone: run it, then verify. See tc-verify-and-cleanup.

What it actually is

A centralized web application. You model environments in it, point it at a software repository, configure components, and it generates deployment scripts. The scripts are what install or update software on each target machine. Deployment Center does not reach out and install things itself.

That split matters for automation: the DC web app is a configuration and script-generation surface, and the real work happens when the generated script runs on the target. Two phases, always.

The concept model

Four terms, used precisely throughout the product. Getting them straight avoids most confusion.

Term What it means
Environment A centrally-managed Teamcenter environment you model in DC
Software DC-compatible software kits: either downloaded from Support Center, or custom packages created by Business Modeler IDE
Applications The binaries, files and data model comprising a set of Teamcenter functionality, contained in a DC-compatible package
Components Logical representation of infrastructure (Corporate Server, Database Server, FSC, Server Manager, Web Tier, Indexer, Licensing Server, Microservice Node, ...)

★ For the package-authoring work: custom DC-compatible software packages are produced by Business Modeler IDE, not hand-assembled. That is the supported route into the Software tier, and the starting point for any "create a Deployment Center package" task.

The software repository, and the rule that hides kits

DC scans configured repository locations on a schedule. Scanned kits show up on the Software Repositories page, which also flags missing dependencies.

★★ Kits must be UNZIPPED, and they must sit in a software directory. A zipped kit, or an unzipped kit in the wrong folder, simply does not appear. It does not error. This is the first thing to check when a kit you know you downloaded is not selectable.

Three storage strategies, per the docs:

  • Single local repository on the DC web server. Simplest, use when there is no spare space near the targets.
  • Multiple locations shared with the target environment, reachable by UNC path. Plan for the full software set.
  • Copy to each target server and pass the path via -softwareLocation at deploy time. Fastest install, most disk.

Repository locations are specified when you install or upgrade DC, and managed afterwards under the maintenance settings.

Deployment flow

  1. Start and log on to Deployment Center.
  2. Set up the software repository (unzipped, in software).
  3. Create or register an environment.
  4. Select software, options, applications, then configure components.
  5. Generate deployment scripts.
  6. Run them in diagnostic mode first.
  7. Run them for real on each target machine.

Diagnostic mode is the free safety net. It validates the configuration on each target and writes errors to the log while making no changes to the machine. The documented best practice is to loop: run diagnostic, fix in DC, regenerate scripts, repeat until clean. Given how expensive a bad Teamcenter install is to unwind, treat diagnostic mode as mandatory, not optional.

Passwords entered for components are encrypted in the generated scripts, or you can supply an already-encrypted password.

Quick deploy

A lighter path that manages configuration and generates scripts through a utility rather than the full UI walk.

  • dc_quick_deploy is the utility.
  • It is driven by an XML configuration file, with an optional XML override file layered on top.
  • Quick Deploy can share components across environments.

Useful when the same environment shape gets rebuilt repeatedly, which is exactly the demo-VM pattern.

Utilities

Utility Role
send_configuration_to_dc Push a configuration into Deployment Center
deploy Run a generated deployment
dc_quick_deploy Quick deployment path

All three honor HTTPS once it is configured.

HTTPS and secrets

Two settings that are coupled, and getting them wrong produces confusing browser errors rather than clear failures.

  • useHttpsCommunication defaults to false. Setting it true enables HTTPS and disables HTTP entirely: DC then refuses all HTTP connections. An unexplained browser error after enabling it usually means the URL is still http://.
  • onlineSecretsDistribution controls where deploy scripts get secrets. true (online) means scripts fetch from the DC Vault at deploy time. false (offline) means secrets are encrypted into the generated packages.
  • If onlineSecretsDistribution is true, useHttpsCommunication MUST be true, otherwise secrets cross the wire unencrypted.

Certificates can come from the DC Vault acting as a local CA, a real CA, or a self-signed cert. Self-signed needs an associated TrustStore and password.

Registering an existing TEM environment

This VM was built with TEM, not DC, so this is the likely entry path.

  1. Scan configurations from TEM.
  2. Generate a validation report.
  3. Review and perform the actions it lists.
  4. Complete environment registration (including importing Java EE web apps).

Note the standing division of labor: actions DC cannot yet perform are done by running TEM on the target server. DC does not fully replace TEM.

Naming collision worth flagging

Deployment Center has its own environment snapshots (create, review, restore, delete) for backing up and restoring an environment's configuration.

★ These are not Hyper-V checkpoints. A DC snapshot captures environment configuration; a Hyper-V checkpoint captures the whole virtual machine. When someone says "take a snapshot before this install", establish which one they mean. On this VM the machine-level protection is the Hyper-V checkpoint: see tc-vm-operations.

Documentation map

The 2606 collection is PL20251212545240207; 2506 is PL20241125556497283. The folder IDs are opaque, so confirm by the PDF title page, which states the software version explicitly.

D:\Siemens\Help Server\collections\documentation\external\PL20251212545240207\en-US\tc_help\
    Deployment Center  Usage.pdf                      <- concepts, install, maintain, quick deploy
    Teamcenter Installation Using Deployment Center.pdf
    Teamcenter Update Using Deployment Center.pdf
    Teamcenter Environment Manager  Usage.pdf          <- TEM, still needed alongside DC
    Teamcenter Installation on Windows Using TEM.pdf

Deployment Center - Usage chapter map: 1 Introduction, 2 Installing DC, 3 Quick Start registering a TEM environment, 4 Maintaining DC (backup, password encryption, maintenance parameters, managing repositories), 5 Deploying software (UI, scripts, process bar, quick deployment), 6 Managing environments (verify, create, move/uninstall, snapshots, clone, migrate JRE), 7 Registering TEM environments, A Troubleshooting, B Uninstalling.

The Teamcenter Deployment Reference Architecture package is referenced by the docs for worked deployment examples and sample deploy scripts, but it ships separately from Support Center Downloads and is not on this machine.

State on the TC2606 VM

★★ Deployment Center IS installed here, at C:\apps\DC. Its services are Manual start type and Stopped by default, and they must be started before Deployment Center will run at all. Chrome on the guest has a bookmark for it.

Do not read "DC is not in the running-services list" as "DC is not installed". An earlier pass in this workspace concluded exactly that, because the service query filtered on a Teamcenter|FSC name pattern that DC's services do not match. Enumerate services without a name filter, or filter on state, before concluding anything is absent.

VERIFIED 2026-08-05 by enumerating every service on the guest. The four DC services, all Manual and all Stopped:

Service
DC_Service the Deployment Center web application
DC_RepoService the repository service (scans for software kits)
DC_RepoService_Publisher repository publisher
DC_Vault_Service the DC Vault, the CA and secrets store

There is a dedicated start script, and the general Teamcenter start script does not include DC:

C:\apps\PLM\Misc\Startup\Services\Start\Start_DC_Services.bat
C:\apps\PLM\Misc\Startup\Services\Stop\Stop_DC_Services.bat

Run it the same way as the Teamcenter start script: over WinRM, stdin from NUL, bounded wait, then judge by service state and listening ports rather than by the script exiting. See tc-vm-operations for the exact invocation.

Note DC_RepoService being a service in its own right: the repository scan that makes kits visible is that service's job, so "my kit does not appear" has two possible causes, the layout rule above and the repo service simply not running.

  • The environment was built with TEM, via the Vanilla_Tc2606_July2026 overlay on a Windows Server 2022 base image.
  • TC2606 installation media is staged on a second virtual disk, Deployment Center Software.vhdx at SCSI 0:2, about 16.4GB unpacked.
  • Checkpoint TC2606 baseline + DC media disk (offline, pre-Deployment-Center) 2026-08-05 is the clean pre-install restore point, taken with the VM Off.

Running it (VERIFIED 2026-08-05)

http://siemensdc:8070/deploymentcenter/#!/login
http://192.168.222.100:8070/deploymentcenter/     (from the Hyper-V host)

Plain HTTP on 8070, so useHttpsCommunication is false here. DC also listens on 8072, 8073, 8074/8075 and 8200/8208. A host-scoped firewall rule for 8070 was added on the guest (the guest blocks everything by default).

Start with Start_DC_Services.bat as described above. All four services came up and, unlike the Teamcenter start script, this one exits cleanly.

< NUL breaks the Windows timeout command. The DC script emitted ERROR: Input redirection is not supported, exiting the process immediately at each timeout, which simply skipped its built-in waits. Services still started, because net start is synchronous. But be aware that redirecting stdin neutralizes pause and defeats deliberate waits, so a script that depends on a pause between steps may race.

Driving DC over REST (VERIFIED 2026-08-06)

DC has a JSON REST API on the same port as the UI, and it behaves a lot like Teamcenter's. Three rules, all learned the hard way:

  1. HTTP Basic auth works. GET rest/isLoggedIn with an Authorization: Basic header returns {"authenticated":true,"authorities":[{"authority":"ROLE_USER"}]} and sets JSESSIONID. This means DC can be driven entirely from PowerShell with a DPAPI PSCredential, so the password never has to be typed into a browser or pasted into a transcript.
  2. POSTs 403 until the session holds an XSRF-TOKEN cookie. Do a GET first to mint one, then echo it in an X-XSRF-TOKEN header. Same bootstrap shape Teamcenter's JSON REST surface needs.
  3. ★★ DC returns HTTP 200 on faults, exactly like Teamcenter. A wrong path returns 200 with header.status = "008" and DCXXE000 : Severe error occurred : No endpoint .... Success is header.status = "000". Never treat 200 as success here. This also makes blind endpoint guessing useless: everything "works" and nothing is real.

Calls are POST rest/<area>/<operation> with a JSON body carrying a context object, not REST-noun GETs. The 24 endpoints referenced by the UI:

rest/isLoggedIn                 rest/activeUser              rest/activeProfile
rest/user/getUserId             rest/metadata/getCommands
rest/gateway/getGatewayTiles    rest/configuration/getDisplayLayoutConfiguration
rest/configuration/getDCSettingsConfiguration
rest/components/getPrimaryDetails      rest/components/getSecondaryDetails
rest/components/updateSecondaryDetails rest/components/updateBreadCrumbDetails
rest/components/createApplication      rest/components/removeApplication
rest/copy/copyEnvironment              rest/quickdeploy/exportEnvironment
rest/envRegistration/envRegistrationComplete
rest/reports/generateSoftwareReport    rest/reports/downloadSoftwareReport
rest/validationreports/generateValidationEnvironmentReport
rest/validationreports/downloadValidationReport
rest/analytics/getAnalyticsDetails     rest/analytics/saveAnalyticsEventFromUI
rest/analytics/updateProcessedEvents

Working entry point, returns the four tiles (environment, software, machine, plus Getting Started):

POST rest/gateway/getGatewayTiles     body: {"token":"gateway"}

Layout for a tile, which yields body.subLocations[].id and .tabs[].id (note the plural field names):

POST rest/configuration/getDisplayLayoutConfiguration
     body: {"context":{"locationId":"environment"}}
  -> subLocations[0].id = "all";  tabs = "deploySoftware", "overview"

★★ Reading a DC view: the call that actually works

getPrimaryDetails is the wrong operation for these pages. The UI reads Environments and Software Repositories through getSecondaryDetails. Chasing getPrimaryDetails costs hours and always ends in DCVF0008.

The verified request, recovered from dc_services.log:

POST rest/components/getSecondaryDetails
{
  "context": {
    "locationId": "environment",     // or "software", "machine"
    "subLocationId": "all",
    "tabId": "overview",             // or "deploySoftware"
    "keyPair": null,
    "mode": "view",
    "secondaryDetailsPage": false,
    "displayType": "secondary"       // ← lowercase literal, NOT a *_DISPLAY_TYPE token
  },
  "objectId": 1,                     // ← on the REQUEST, not inside context. Mandatory.
  "deselectedComponentIds": null
}

Three traps in that one payload, each of which produced a misleading error:

  1. displayType is the lowercase string "secondary". The nineteen *_DISPLAY_TYPE constants in the jars are a red herring for this call; every one of them fails. The error names the displayType field either way.
  2. objectId sits on the request, not in the context, and omitting it gives DCTE001 : ... mandatory parameters are missing, which does not say which one.
  3. ★ The context needs keyPair and secondaryDetailsPage, fields the client JS never mentions. Full-struct rule, same as Teamcenter.

Response shape: body.tabs[].viewSections[], where a section carries components[] of {dataId, dataName, subtitles[]} and each subtitle is {id, label, value} (deploymentStatus, software.version, machine.hostName). refObject names the section: installedSoftware, packaze (yes, spelled that way, matching the PACKAGE:"Packaze" typo in DCConstants.js), or environment.

★★ The oracle that ended this: C:\apps\DC\webserver\logs\dc_services.log. It logs every request at DEBUG with the fully deserialized struct. Have someone click the page once in the UI, then read the exact call back out of the log. That is faster and cheaper than any amount of payload guessing, and it needs no browser automation. Reach for it first, not last.

Historical: the getPrimaryDetails dead end

rest/components/getPrimaryDetails always returns DCVF0008 : Unable to find View Formatter for given Display Type.

The 19 valid tokens were recovered, by decompressing the server jars (class strings live in the constant pool, and jar entries are deflated, so a raw grep of the .jar finds nothing):

BASIC_TABLE  BREADCRUMB  COLLAPSIBLE  COMPONENT  COMPONENT_HEADER
COMPONENT_PROPERTY  COMPONENT_UNINSTALL  DEPLOY_INSTRUCTION  EDIT_BUTTON
GRAPH  INFORMATION  INVALID  NAVIGATION_BUTTON  PROPERTY  SOFTWARE_OPTION
SOFTWARE_OPTIONS  TABLE  TREE  WARNING          (each suffixed _DISPLAY_TYPE)

★★ All ten plausible ones fail identically, so displayType is not the discriminator. Something else in the request shape is wrong, and the error message points at the wrong field. Do not burn more time permuting this value. The displaySection.value names from the layout (OverviewTabPropertyGroups, OverviewTabApplicationGroups, ...) are the more likely missing input.

Read C:\apps\DC\webserver\logs\dc_services.log instead of guessing. It logs every request at DEBUG with the full deserialized struct, which is how the real DCContext shape was recovered:

DCContext [locationId=software, subLocationId=null, tabId=null, keyPair=null,
           mode=null, secondaryDetailsPage=false, displayType=null]

So the struct has keyPair and secondaryDetailsPage, which the client JS never reveals. Sending the complete struct still does not fix getPrimaryDetails, but this log is the single best oracle on this server: it shows exactly what arrived, and dc_server_error.log shows why it failed.

The way in is to capture the UI's own network calls: see tc-capture-awc-calls, same technique and same reason. Note the in-app browser pane cannot reach the VM's private address (navigation ... was denied or failed), so that capture has to happen from a browser that can, such as Chrome inside the guest. ★ The cheapest version of this: have someone load the DC UI once and click into Environments, then read the successful call straight out of dc_services.log and replicate it. No browser automation needed. This is exactly how the working call above was finally recovered.

SOFTWARE_OPTION(S)_DISPLAY_TYPE is the token to reach for when the options screen is eventually driven, since options are what an MBSE-style add-on is selected through.

The quick-deploy CLI is NOT installed here

The docs describe dc_quick_deploy, deploy and send_configuration_to_dc. On this VM only C:\apps\DC\repository\system\deployer\deploy.bat exists (the runner for already-generated deploy scripts). There is no dc_quick_deploy binary. If it is needed, look inside the kit's install\DeploymentCenter\deployment_center.zip or download it separately. Do not assume the documented utility set is present.

★★ Not every application is visible, and the list will lie to you

Each application has a registry entry in the kit at <kit>\dc_contributions\application_registry\<appId>_config.json:

{
  "appId": "mdw0magicdraw",
  "attributes": { "defaultSelection": false, "visible": false },
  "requireDependencies":    [ "uml0umlsysml", "behaviormodeling" ],
  "requiredByDependencies": [ "ase1systemsmodeling" ]
}

"visible": false means the application never appears in the DC Applications list, in the UI or over REST. It is installed implicitly, pulled in by whatever requiredByDependencies names. mdw0magicdraw is a real example: its display name is "Integration for Cameo", it is genuinely installed on the VM, and it is absent from all 184 rows the API returns.

So "it is not in the applications list" does not mean it is not installed. Confirm against the tier itself:

Get-ChildItem C:\apps\PLM\tc_root\install | Where-Object Name -match 'mdw0|uml0|ase1'

An installed template leaves a directory there with its *_config.json and *_dependency.xml. That check is authoritative where the DC list is not.

Two more mapping traps worth knowing:

  • Display names live apart from appIds. <appId>DCBundle_en_US.xml under dc_contributions holds the displayName, one file per locale. Grepping the English value is how "Integration for Cameo" was tied back to mdw0magicdraw. Neither the appId nor the feature XML contains the product name.
  • The product name may not be the vendor name. Cameo is MagicDraw-based, so the appId is mdw0magicdraw and the string "cameo" appears nowhere in the media manifest. Searching for the marketing name alone finds nothing.

Worked chain from this VM: System Lifecycle Management (ase1systemsmodeling, visible, installed) implicitly pulls in Integration for Cameo (mdw0magicdraw, hidden), which in turn requires uml0umlsysml and behaviormodeling. All four are present in tc_root\install.

Quick Deploy config format

C:\apps\DC\repository\quick_deploy_config\<name>\<name>_quick_deploy_configuration_<ver>.xml is the documented, UI-free automation path, and its shape is simple:

<quickDeployConfig configName="MechatronicsQuickDeploy" version="1.0">
   <deploymentTier value="2" />
   <quickDeploySoftware>
      <software id="Foundation" version="12.2" />
      <software id="ActiveWorkspace" version="4.2" />
   </quickDeploySoftware>
   <quickDeployApplications>
      <package id="smd0systemmodeling" displayName="System Modeling" />
      <package id="systemsengineering"  displayName="Systems Engineering" />
   </quickDeployApplications>
</quickDeployConfig>

This is where added options are declared, by package id. The shipped mechatronics sample is the best available reference for real package ids.

Install layout (VERIFIED)

C:\apps\DC holds webserver and repository. The repository is the canonical DC structure, and its README.txt documents each folder:

Folder Role
software The DC-compatible kits. DC scans it automatically and registers what it finds
dc_contributions DC files for installing earlier TC/AW releases. Do not alter
deploy_scripts Generated deploy scripts, per environment, in timestamped folders
snapshot Quick-deploy files backing environment snapshots
quick_deploy_config Quick Deploy configurations
system DC's own state. Do not alter
https_config, tls_configuration Certificate material

This VM already has DC state: deploy_scripts\Vanilla_Env\install, snapshot\Vanilla_Env_1, quick_deploy_config\mechatronics, and https_config\{SIEMENSDC, Vanilla_Overlay_4TClient}. So an environment named Vanilla_Env is already registered. Do not assume you are starting clean.

★★ The media disk is mounted INTO the repository, by volume GUID

C:\apps\DC\repository\software is not a real directory. It is a Junction whose target is Volume{7154c769-7361-4f11-800f-5e5769cd9b02}\, the second virtual disk. That is why the media disk has **no drive letter** and why Get-Volume in the guest shows only C:.

Do not "fix" the missing drive letter. The disk is deliberately surfaced as the DC software folder rather than as a lettered volume. (I assigned E: while investigating, then removed it once the junction explained everything. Assigning a letter is harmless but pointless, and it hides the actual design.)

Check the wiring with:

(Get-Item C:\apps\DC\repository\software -Force) | Select-Object LinkType,Target

★★ Open issue: the kit sits one level too deep

The media unpacked with a doubled directory, the same SFX artifact that bit the overlay extraction during the build:

software\tc2606_wntx64\tc2606_wntx64\{tem.bat, dc_contributions\, install\DeploymentCenter, bmide\, tc\, ...}

The repository README says to "unzip it and copy the unzipped folder into the software directory", i.e. DC expects software\<kitFolder>\ to be the kit root. Here software\tc2606_wntx64\ contains only another tc2606_wntx64, so the kit root is one level below where DC scans.

Evidence says DC copes: the scanner recurses. Its scan cache lists both levels:

C:\apps\DC\webserver\repotool\lastScannedMedia.json
  ...\software\tc2606_wntx64                 (the doubled outer folder)
  ...\software\tc2606_wntx64\tc2606_wntx64   (the real kit root)

That file is a path to last-scanned-epoch-millis map, not a status report, so it proves the scanner walked the real kit root; it does not by itself prove the software registered as selectable. Confirm on the Software Repositories page before moving anything. Do not relocate the folder on the strength of the doubled path alone.

The scan log also reports two harmless failures, because the junction targets the volume root, so DC sees the volume's hidden folders:

software\System Volume Information -> Error: Unsupported File
software\$RECYCLE.BIN              -> Error: Unsupported File

Expect those every scan. They are noise, not a broken repository.

★★ Stop_all_tc_services_sessions.bat also stops the DC services. Despite the name suggesting Teamcenter only, a Teamcenter restart cycle leaves DC down. Re-run Start_DC_Services.bat afterwards, and check Get-Service DC_* rather than assuming DC survived.

The kit itself is DC-compatible: it ships dc_contributions\ (with deployablecomponents and quickdeploy), install\DeploymentCenter, and bmide\, alongside tem.bat for the TEM path.

  • Whether the repository will live on the media disk or be copied into the guest.
  • Which port DC serves on here, and whether it needs its own host-scoped firewall rule (the guest blocks everything by default: see tc-vm-operations).
  • Whether useHttpsCommunication should be enabled for a single-machine demo VM, given it disables HTTP outright.

★★★ The real shape of a translator package.xml, read off the TC2606 media itself

Verified 2026-08-06 by directly enumerating C:\Users\chris\Downloads\tc2606_wntx64.zip (15.97 GB, 29,990 entries) and extracting dc_contributions\packages\ asyncservice_translator_package.xml — Siemens' own real, shipped package for a stock Dispatcher translator. This is a stronger source than the DC Usage guide, which does not cover BMIDE package internals at all (confirmed by reading the actual help topic behind xid1161106 — it's the "Getting started" concepts page; the guide's only mention of custom packages is one bullet naming BMIDE as the authoring tool, no schema).

This zip's media is NOT doubled the way the VM's already-extracted copy is. tc2606_wntx64.zip's root is tc2606_wntx64/ with dc_contributions\, bmide\, install\DeploymentCenter\, tem.bat directly one level below — the doubled software\tc2606_wntx64\tc2606_wntx64\... structure documented above for the VM is an artifact of how that copy was self-extracted, not a property of the shipped zip itself. Don't assume every future media drop needs the doubled-directory workaround.

The translator package shape, directly reusable for any new Dispatcher translator:

<package packageId="asyncServiceSel_translator" guid="...">
    <textBundle value="${packageId}Bundle.xml"/>
    <contentType value="translatorContent"/>
    <group value="translators"/>
    <dependencies><dependency type="requires" id="dispatcher"/></dependencies>
    <artifact artifactType="fnd0_translatorArtifact" guid="...">
        <deploymentActions>
          <install>
            <target name="fileProcessing">
              <unzip src="${Teamcenter_Foundation_path}/additional_applications/asynctranslator.zip"
                     dest="${fnd0_dispatcherRootDirectory}/Module/Translators/asyncservice" overwrite="true"/>
            </target>
            <target name="preDatabaseUpdate">
              <chmod dir=".../Translators/asyncservice" perm="754" includes="**/*"/>
            </target>
            <target name="databaseUpdate">
              <xmlReplace fileName="${dispatcherRootDirectoryModified}/Module/conf/translator.xml">
                <replace xPath="/Translators/AsyncService[@service='asyncservice']/@isactive" withText="true"/>
              </xmlReplace>
            </target>
            <target name="postDatabaseUpdate"/>
          </install>
          <update> <!-- same 4 targets --> </update>
          <maintenance><target name="maintenanceUpdate"/></maintenance>
        </deploymentActions>
    </artifact>
</package>

Key confirmed facts this gives you, none of which are documented in the Usage guide:

  • contentType="translatorContent" / group="translators" is how a translator package identifies itself to DC.
  • Dependency on the dispatcher package is declared, not assumed.
  • translator.xml's root element is literally <Translators>, and each translator is a CHILD ELEMENT NAMED AFTER THE TRANSLATOR (<AsyncService service="asyncservice" isactive="..."/>, not a generic <Translator name="...">) — confirmed by the xmlReplace xPath itself, which is real, server-validated Ant task syntax, not documentation prose that could be stale.
  • xmlReplace is the Ant task for idempotent XML config patches during databaseUpdate — the DC-native alternative to hand-rolling a script-based XML patch, when the change is simple (a single attribute flip). For a change too complex for one xPath/withText pair (multiple new child elements, an <Options> block, conditional removal of a stale entry), delegating to a tcexec PowerShell script from postDatabaseUpdate instead (see the DSS pattern below) is the more tractable route — don't fight xmlReplace for a multi-node edit.
  • dispatcher_module_package.xml (the parent) is deprecated="true" visible="false" on this release — a hint at API churn worth checking before modeling a NEW package on it specifically; asyncservice's own package is not deprecated and is the safer template to copy.
  • Translator packages are not separately-selectable top-level DC "Applications" — no standalone application_registry\<name>_config.json exists for asyncservice/nxtopvdirect/etc. They attach as fnd0_translatorArtifact-typed artifacts under the parent fnd0_dispatcherModule component, confirmed via that component's own fnd0_dispatcher_module_DCC.xml: <supportedType value="fnd0_translatorArtifact" conditionId="enableTranslatorArtifactCondition"/>. So a new translator's own package needs no application_registry entry at all.

bmide\ on this media is thin at the top level — just compressed_files\{bmide.zip, bmide_aw.zip, bmide_edaserver.zip}. The actual BMIDE tool and any shipped extension-project samples live inside those nested zips, not unpacked in the media tree itself.

★★ Combining the two known-good package.xml patterns

Two genuinely different, both-confirmed patterns now exist in this workspace, and a new package should pick the one that fits each piece of what it deploys rather than forcing everything through one:

asyncservice_translator_package.xml (Siemens, shipped) dss4decisionsupport_package.xml (this workspace, decision_support)
Best for Simple file staging + a single-attribute config flip Complex logic: preference imports, multi-step, arbitrary scripts
Mechanism unzip / chmod / xmlReplace Ant tasks, inline getTcAdminPasswordFile + tcexec calling preferences_manager directly, then a second tcexec calling an arbitrary PowerShell script
Where the real logic lives In the package.xml itself In postinstall/*.ps1 scripts the package.xml just invokes

For anything beyond a trivial translator (multiple config files, a generated per-tier JSON, machine environment variables, workflow template handlers) the DSS pattern — thin package.xml, real logic in an idempotent PowerShell orchestrator — is far more maintainable and testable in isolation than trying to express it all in Ant XML. A full worked example combining both (translator content following asyncservice's shape, postDatabaseUpdate delegating to a PowerShell orchestrator following DSS's shape) is in Capital_TC_Integration/deploy/bmide/ — built 2026-08-06 for the CapitalForward Dispatcher translator + its workflow trigger + subscription daemons, not yet deployed against a real instance. Read its own README before cloning it.

decision_support has two install trees; only one is current. deploy/bmide/ is canonical (BMIDE "Generate Software Package" output plus hand-authored files assembled by tools/finish-software-package.ps1, the "3-file config" pattern — package.xml itself, rtserver.zip/aws2stage.zip, and the final install zip are NOT fully BMIDE-generated, only the template/media/ partial application_registry are). deploy/deployment-center/ is explicitly marked deprecated (DEPRECATED.md: "Deployment packaging has moved to deploy/bmide/ (single path)") — don't clone it.

Workflow templates as BMIDE ops-data, in case a future package wants to try this route instead of SOA-scripting the handlers post-creation: decision_support ships deploy/bmide/workflows/Dss4DecisionApproval.xml, a simplified declarative <WorkflowTemplate>/<Task>/<Handler>/<Participant>/<Action> format (NOT raw EPM XML), deployed via BMIDE's native workflows/ ops-data folder (enableOpsDataDeploy="true" in dependency.xml). Unverified as an alternative route to the same result the paragraph below now covers over SOA directly.

★★★ RETRACTED 2026-08-08: createOrUpdateTemplate-only-makes-a-task-template is wrong, and so is "a template's stage is a GUI-only state transition." Both were measured against a real tier at the time and both were genuinely true of the payload shapes tried, but neither is true of the operation itself. Captured live by reading what Active Workspace's own Workflow Designer actually posts, then reproducing the same calls over SOA, verified end to end on TC2606 including create → publish → delete on a disposable throwaway template before touching a real one:

  • createOrUpdateTemplate creates a genuine PROCESS template (template_classification = 0) when additionalData carries {"stage":["1"]} on the create call. Every earlier attempt omitted this key and got a Task template every time: the operation was never incapable of it, the payload was incomplete.
  • Publishing ("Set Stage to Available") is a SECOND createOrUpdateTemplate call, templateToUpdate = the template's uid, additionalData carrying {"template_stage":["2"]}. Note the key name difference from the read-back property: setProperties on stage really is a documented silent no-op (that half of the original finding holds), but stage is not the write key either: template_stage is, and it only exists on this second createOrUpdateTemplate call, not as a generic settable property at all.

So the CapitalForward package's own "genuinely unscriptable, manual GUI step" conclusion (referenced throughout this skill and in that package's own docs) is retracted too, see Capital_TC_Integration/deploy/bmide/workflows/ CSAIntCapitalForwardTranslate-MANUAL-STEP.md for the package-level writeup, and tc-workflow-authoring for the full derivation including the exact payload shapes. The BMIDE ops-data route above remains untested and is now moot for this specific problem: the direct SOA route is proven, so there's no remaining reason to reach for the untested alternative.

★★★ First live test on TC2606, four confirmed bugs, all in the postinstall scripts not the package.xml design

Verified 2026-08-06: a colleague session with WinRM access to the siemensdc VM ran the CapitalForward package's postinstall orchestrator directly (bypassing DC's own deploy mechanism, which is still unproven on write — see below) against real paths on TC2606. Nothing was written to the tier — every step that would have modified TC failed or skipped cleanly before doing so, which is exactly the behavior a first real run against a new tier should have. Four bugs found, all fixed same-day:

  1. A path-computation bug lost one directory segment, computing an artifacts-lookup path two levels above a script instead of one — the classic off-by-one from double-applying Split-Path -Parent when only one hop was needed. Caught immediately by the actual error message naming the wrong path.
  2. ★★ preferences_manager.exe (and by extension any TC utility) needs its environment SOURCED IN THE SAME PROCESS, and the site's own env-setup script name is NOT constant across tiers. Confirmed by direct empirical test on this VM: preferences_manager -h with no environment → exit -1073741515 (0xC0000135, STATUS_DLL_NOT_FOUND) and zero output; the identical binary after call tc_root\tc_menu\tc_Vanilla_Env.bat → exit 0, full usage text. This VM's environment-setup script lives at tc_root\tc_menu\tc_<EnvName>_Env.bat (e.g. tc_Vanilla_Env.bat), not %TC_DATA%\tc_profilevars.bat as seen on the cloud/saber2506 tier this integration was originally built against. A script that hardcodes one convention will silently fail on a site using the other. Fix: auto-detect both candidates, accept an explicit override, and run the actual utility through cmd.exe /c "call <envscript> && <utility> <args>" as ONE process — PowerShell invoking a .bat and then an .exe as two separate calls does NOT carry the sourced environment across, because a batch file's call-sourced variables only persist within that same cmd.exe process.
  3. ★★★ The most important bug: an orchestrator step that skips its own work (exit 2, a documented "non-fatal, missing prerequisite" signal used throughout this package) does NOT throw a terminating exception in PowerShell — it just sets $LASTEXITCODE and returns normally. A naive try { & $Body } catch { ... } wrapper around each step therefore records a fully-skipped step as OK. Confirmed live: a workflow-handler-wiring step reported OK in the summary table while having wired zero handlers, because its password-file lookup silently failed first. This is the exact "silence reads as success" failure class this whole package's own error messages warn about elsewhere in text — reproduced by the orchestrator wrapping those same scripts. Fix: any multi-step orchestrator wrapping sub-scripts that use exit codes (not exceptions) to signal "skipped" must explicitly check $LASTEXITCODE after each call, not rely on try/catch alone.
  4. A hardcoded assumption about which credential file already exists on a tier was wrong, and the colleague session correctly refused to substitute a look-alike file rather than guess: this VM's tc_root\security\ had TCDB_infodba.pwf (a database-account** password file) but no TC-user .pwf for infodba at all, contradicting the assumption (true on every other tier touched by this integration) that one already ships from install. **Do not assume a .pwf exists just because the tier is "the same kind of install" as another one you've seen — verify the directory listing first, and if genuinely absent, find the real creation utility rather than trying a same-size, differently-prefixed file as a substitute.

The general lesson for any DC postinstall script, beyond this one package: a script correct in isolation can still be silently wrong in an orchestrator that (a) doesn't source the environment the same way the target tier does, and (b) treats "didn't throw" as the only failure signal. Both are easy to get wrong and both produce a false "deployed successfully" report — test the orchestrator's own error-propagation, not just each step's happy path, on a genuinely fresh tier before trusting a summary table.

★★★ Fifth bug, found the same night: getWorkflowTemplates (2013-05) needs a fully-specified payload, or it looks exactly like the deprecated-route symptom

provision-workflow-handlers.ps1's Find-TcWorkflowTemplateUid helper called getWorkflowTemplates with an empty body and read .templates/.output off the response. Both were wrong, and both failures produced the same misleading symptom: "no candidate templates," which reads exactly like the deprecated 2008-06-route trap already known to this workspace (see tc-workflow-authoring), sending the first debugging pass toward the wrong hypothesis. Live testing against TC2606 (170 real EPMTaskTemplate objects on that tier) established the real cause and fix, documented in full in tc-workflow-authoring's "...but the 2013-05 route ALSO returns an empty-looking result" section: the request needs four required attributes (clientId, includeUnderConstruction, getFiltered, group) under a member named input (not inputs), and the response's real payload lives at templatesOutput[0].workflowTemplates, not .templates or .output. Fixed in tc-soa-lib.ps1's Find-TcWorkflowTemplateUid and verified against the corrected shape.

The debugging discipline worth repeating: when a "returns nothing" symptom matches a known trap exactly, verify the payload and response-parsing before accepting the known trap as the cause. Two different bugs producing an identical-looking empty result is not a coincidence to be surprised by; it's the default outcome when TC returns 200 OK for both "wrong operation" and "well-formed but underspecified request" alike.

★★★ Sixth bug: tc_profilevars.bat is a SUPPLEMENT, not a standalone environment script, and that's the root cause of the earlier preferences_manager exit-1

Confirmed live on TC2606, 2026-08-07, and this is the resolution of the "preferences_manager exit 1 (post-env-fix)" item that was open at the end of the fourth-bug pass above. It looked like a NEW, different failure from the earlier 0xC0000135 DLL-not-found bug (same symptom class, a TC CLI utility failing, but a different exit code), and turned out to be the same root cause wearing a different mask.

%TC_DATA%\tc_profilevars.bat assumes TC_ROOT/TC_DATA are ALREADY set by whatever calls it; it does not establish them itself. Called on its own (bare, in a fresh process), it leaves both unset: confirmed by inspecting the resulting environment, where TC_BIN ends up literally \bin, i.e. %TC_ROOT%\bin expanded with TC_ROOT empty. preferences_manager then fails with exit 1, "Login with -pf option failed! Error code = 26052 (POM_internal_error)", a message shaped exactly like a bad credential or bad .pwf file, which is a red herring. Proof it's the environment, not the credential: Siemens' own smart_discovery_helper reproduces the identical 26052 under the same broken env; a plaintext -p= password fails the same way; a read-only -mode=export fails the same way. A whole family of "this specific option/credential must be wrong" hypotheses can be ruled out at once by checking whether TC_ROOT/TC_DATA actually resolved, before touching any of them individually.

tc_root\tc_menu\tc_<EnvName>_Env.bat (the script already identified as this VM's convention in bug 2 above) IS self-sufficient: it sets TC_ROOT/TC_DATA itself before internally calling tc_profilevars.bat, which is exactly why it worked when tried directly, and exactly why any auto-detection logic that tries tc_profilevars.bat FIRST (reasonable-looking, since it's the convention on other tiers this integration was built against) silently picks the broken half-environment and never reaches the working fallback. Fix: try the self-sufficient tc_menu\tc_*_Env.bat FIRST, and set TC_ROOT/TC_DATA explicitly in the invoking cmd.exe command line as a second layer of defense, so that even a tc_profilevars.bat-only fallback (a tier with no tc_menu folder at all) works instead of reproducing the same bug by a different path.

Two secondary findings from the same investigation, worth carrying into any similar script:

  • The utility's report file is NOT under TC_DATA\logs. It lands in %TEMP% (e.g. C:\Temp\preferences_manager_<stamp>.log), and the utility prints the exact path to stdout on success: point error messages there, or parse stdout for the real path, rather than a guessed conventional location.
  • ★★ Preference reads are session-cached. A getPreferences call on a session that was opened before an import completed can report a just-imported preference as absent, and this genuinely reversed itself after a fresh login: it is not a propagation-delay issue, it is the specific session's cache. A verification step must open a brand-new session (not reuse one opened earlier in the same script or process) after the import, or it can report a false failure on a successful import.

★★★ Three more findings from a third live test, run 3

Verified 2026-08-07, same colleague session, same package. Two real bugs and one false alarm that's worth documenting as a process lesson on its own.

The false alarm: a "still failing" report was actually a stale file

Run 3 reported the exact parse error from the very first attempt at fixing bug 6's error message (an invalid \"-escaped string, since backslash is not an escape character inside a PowerShell double-quoted string: use a backtick, or double the quote). That first attempt had already been caught and fixed in the same edit pass, before ever being reported as ready. The file on the authoring side parsed clean and had zero remaining \" occurrences, with a save timestamp clearly after the fix. The run had executed a copy of the file staged before the fix landed, not the current one. Lesson for any workflow that separates the machine authoring a script from the machine running it: when a report describes an error that's already been fixed and verified, check file provenance (timestamp, a hash, anything) before assuming the fix regressed. A stale copy is at least as likely as a real regression, and costs nothing to rule out first.

Bug: SOA call timeouts on a cold session pool, misread as a payload problem

A 60-second Invoke-RestMethod timeout was too tight for two compounding factors: a cold Teamcenter session pool can take 15-25 seconds just to assign a tcserver process (confirmed independently: a colleague's own tc_connect against the same tier timed out twice in a row on a cold pool, then succeeded on the third try with the tier fully healthy, 21 services / 24 tcserver processes up), and a heavier call on top of that (getWorkflowTemplates with getFiltered:false against a 170-template site) returned a 74KB payload that takes real time to generate server-side. The combination pushed a cold first call past 60s with nothing to show for it but a bare HTTP client timeout: no TC-side error, no partial response, nothing to diagnose the actual payload against. Fix: raise the timeout (120s) and add a small retry-with-backoff specifically for timeout exceptions (not for real HTTP errors or SOA faults; those mean the request completed and failed for a substantive reason, and retrying them just wastes time or masks a real bug). Applied to both the login call (where the cold-pool assignment actually happens) and every subsequent operation call. The general lesson: a bare timeout on the first call against a freshly-started or freshly-restarted Teamcenter tier is not by itself evidence the payload or route is wrong. Rule out a cold pool first, especially on a call whose response is large.

Bug: a scheduled-task daemon script can silently double a process that predates it

setup-subscription-daemons.ps1's own header claimed "starting an already-running daemon is a no-op": this was wrong, and a live run proved it. After the script ran, TWO subscriptionmgrd and TWO actionmgrd processes were running against the same database, one pair pre-existing (started by hand during earlier manual work on the tier, Administrator-owned) and one pair freshly started by the new scheduled task (SYSTEM-owned). Start-ScheduledTask always launches a fresh process for its own task instance; MultipleInstances = IgnoreNew only prevents the SAME scheduled task from double-firing. It does nothing to detect an unrelated process of the same executable already running outside that task. For any daemon/service-like executable with no built-in single-instance lock, a deployment script that unconditionally calls Start-ScheduledTask/Start-Process/equivalent WILL create a duplicate if one is already running by some other means (manual start, an earlier tool, a different install path), and this is exactly the class of thing that never shows up on a genuinely clean VM: it only bites a real, previously-touched environment, which is precisely the kind DC packages actually deploy to. Fix: check for an already-running instance (by process name, any owner) before starting a new one. Registering the scheduled task for future-boot survival can still happen unconditionally (harmless, idempotent); only the immediate start should be conditional. If duplicates are found ALREADY existing (not caused by this run), warn loudly and require manual cleanup rather than guessing which instance to kill: a script that picks a pid to terminate on someone else's tier is a destructive action past what an idempotent deploy step should decide on its own.

★★★ Run 4: -pf= needs the ENCRYPTED file for every TC CLI utility, not just the daemons; the earlier docs had this backwards

Verified 2026-08-07, same package, same colleague session. This closes the preferences_manager story for good: run 3's "exit 1 / 26052" was the missing environment (bug 6 above); run 4's NEW "exit 1 / 515143 (POM_invalid_account_values)" was a second, independent bug once the environment was fixed, and the direct A/B is unambiguous:

-pf=TCDB_infodba.pwf (encrypted)          -> exit 0, "7 preferences imported successfully"
-pf=TC_DATA\password_file (plaintext)     -> exit 1, 515143 (POM_invalid_account_values)

Same env script, same account, only the file format differs. -pf= on preferences_manager means the standard encrypted .pwf format, the same one subscriptionmgrd/actionmgrd use, not a plaintext password file: this package's earlier design (and its own README) had it backwards, assuming preferences_manager needed the plaintext file used for scripted SOA login elsewhere in the package and that the encrypted .pwf was what caused 515143. The opposite was true. Fixed by giving register-capitalforward-preferences.ps1 its own encrypted-.pwf discovery (same TCDB_<user>.pwf / config1_<user>.pwf convention already used for the daemons), reserving the plaintext-password chain for what it's actually needed for: the script's own optional post-import SOA verification login, which sends a literal password string in a JSON body and genuinely cannot use an encrypted file. The general rule, worth checking on any new TC CLI utility wrapper: -pf= (or any file-based credential flag on a compiled TC utility) almost certainly wants the encrypted format; a plaintext password only ever belongs on a scripted SOA/REST login, never on a CLI utility's credential flag, even when both authenticate as the same account.

★★ A second lesson from the same investigation: don't diagnose an exit code, diagnose the actual output text. preferences_manager returned the identical exit code (1) for two unrelated root causes across run 3 and run 4 (missing environment vs. wrong -pf= file format). An error-handling block that branches purely on $LASTEXITCODE will confidently misdiagnose whichever cause it wasn't written for first: exactly what happened here, run 4 hit the new 515143 case and got served the old 26052 diagnosis, which sent debugging effort toward the environment when the environment was already fine. Fix: capture the utility's actual stdout/stderr text ($output = & cmd.exe /c $cmdLine 2>&1, not a bare & that lets it stream past uncaptured) and branch error messages on substrings of that text, falling back to a generic "check the captured output above" message for anything not specifically recognized. This generalizes to any wrapped CLI utility whose distinct failure modes share an exit code.

★★★ Run 5: a genuinely successful import was misreported as FAILED, by PowerShell itself, not by TC

Verified 2026-08-07, same package. The -pf= fix above worked (report logs confirmed "A total of 1 preferences has been imported successfully!", exit code 0), but the orchestrator still printed Register preferences FAILED: with an empty message. Root cause is a documented Windows PowerShell 5.1 defect, not a Teamcenter problem or a logic bug in the diagnosis code added in the previous fix:

Redirecting a native executable's stderr AT THE POWERSHELL CALL SITE (& cmd.exe /c $cmdLine 2>&1) wraps every stderr line the exe writes in a NativeCommandError, and sets $? to $false, even when the exe exits 0. preferences_manager writes a single blank line to stderr on a completely successful run. That blank line was enough to trigger the defect: PowerShell manufactured an ErrorRecord whose text was the blank line, which is exactly why the failure message came through empty, and why the substring-branching diagnosis added for bugs 6/7 above couldn't classify it: there was no real 26052 or 515143 text to match, because there was no real error at all.

Fix: keep the redirect INSIDE the string handed to cmd.exe, not as a PowerShell-level redirect on the & call itself. $cmdLine already ends with the command to run; append 2>&1 to that same string (cmd.exe merges stdout/stderr in its own process before PowerShell ever sees the output) and invoke it as & cmd.exe /c $cmdLine with no PowerShell-side redirect at all. This preserves the single-string-argument invocation shape already proven to work correctly across four prior live runs; do not additionally wrap the whole $cmdLine in a second layer of quotes to "do the redirect outside" (a tempting-looking alternative) since cmd.exe /c argument parsing has its own quote-stripping behavior that a second wrapping layer can collide with when the inner string already contains embedded quotes, which this one does.

The general rule for any PowerShell script wrapping a native executable: 2>&1 (or any stderr redirect) belongs on the native side of a cmd.exe /c "..." string, never bolted onto the PowerShell & call itself, unless you have specifically confirmed the target executable never writes anything to stderr on success. A wrapper that looks correct and has passed every prior test can still misreport the moment the wrapped executable emits so much as one stderr byte on an otherwise-successful run: this is a silent, intermittent-looking failure mode (it depends on the exe's own stderr behavior on that specific invocation) that will not show up until exactly the right exe/argument combination triggers it. Worth auditing every script in a package that shells out to a native utility for the same pattern, not just the one that happened to trip it first: the audit in this package's other five scripts found no other occurrence (none of the other native-executable invocations combine a PowerShell-level 2>&1 with the & call operator), but that is a fact worth re-checking after any future edit, not something to assume stays true.

★★★ Design gap found after the fact: subscriptionmgrd/actionmgrd already exist as OOTB Windows services, and this package's scheduled task is a SECOND, competing mechanism

Discovered live 2026-08-07, after the duplicate-daemon bug above was already fixed and tested. This isn't a new bug so much as a finding that the earlier fix, correct as far as it went, was papering over a structural design choice worth reconsidering: TC2606 ships subscripmgrd and actionmgrd as genuine Windows services (StartType Manual), separate from and racing for the same ImanEvent queue as any package (like this one) that instead runs the executables directly under a boot-triggered scheduled task. On a genuinely clean tier, those OOTB services exist, Manual and Stopped, exactly like this VM started.

This reframes the duplicate-consumer problem (bug 6, "silently double a process that predates it") as structural, not incidental. The already-running-instance guard added there correctly stops the SAME script from adding a third consumer, but it cannot stop the OOTB service mechanism from racing the scheduled-task mechanism: nothing in Teamcenter's own tooling (a future run of a service-startup script, or an admin manually starting the Manual-type service) knows this package's scheduled task exists, so the double-consumer situation can silently reappear after a clean deploy, at any later point, with no warning from anything this package wrote.

Two real design options, deliberately not decided inside this package: (a) keep the scheduled task (explicit SYSTEM ownership, unlimited execution time, which is presumably why it was chosen originally) and document the OOTB service conflict clearly enough that nobody re-enables it by accident, or (b) switch the package to configure and start the OOTB Windows services instead (closer to out-of-the-box behavior, inherits whatever service config the tier already has, removes the whole duplicate class by construction rather than guarding against it). The general lesson for any DC package that stands up a background process: check whether Teamcenter already ships that process as a Windows service before reaching for a scheduled task, Start-Process, or any other custom persistence mechanism. A custom mechanism can be made correct in isolation (idempotent, guarded against self-duplication) and still collide with an OOTB mechanism neither package author nor operator thought to check for, because the collision only becomes visible when both are actually running side by side against the same real backend, which a unit-test-style check of the script alone will never surface.

A live side effect worth knowing about, not just the lesson: cleaning up what looked like a stray duplicate daemon pair on a real tier turned out, on reflection, to have stopped the underlying OOTB Windows services themselves (the processes killed were the services' own child processes, not unrelated strays as first assumed), so the services now show Stopped on that tier as a result. The functional end state (exactly one consumer of the queue, reboot-survivable) was still correct, but which mechanism owns the daemons on that specific tier changed as a side effect of the cleanup, which is worth knowing before drawing conclusions from that tier's current service state later.

★★★ Run 6: the third instance of the same forwarding-gap bug, plus a stale hardcoded port

Verified 2026-08-07, same package. The stderr-redirect fix above worked (Register preferences now genuinely reports OK), but its optional verification sub-step silently failed to run: WARNING: Could not verify over SOA (Unable to connect to the remote server).

Two compounding causes, and the first is a pattern worth naming on its own:

  1. A hand-built per-step $args hashtable in the orchestrator forgot to forward -TcHost to the preferences step. This is the THIRD time this exact bug shape hit this package: -TcData missing from workflow handlers (an earlier run), -InfodbaEncryptedPwf missing from preferences (bug 7 above), now -TcHost missing from preferences. Each time, the orchestrator held the right value in a variable and simply forgot to include it in one step's hand-written argument list. Fix, generalizable beyond this package: when an orchestrator forwards a growing set of shared values to several sub-scripts with different parameter surfaces, build the values once in a single hashtable and select each step's subset through a shared helper (a "which of these common values does this step declare" map), rather than hand-writing a fresh $args = @{...} per step. A repeated manual pattern that has already produced the identical bug three times is strong evidence the pattern itself, not the individual instances, is the thing to fix. This package's orchestrator now builds one $common hashtable plus a New-StepArgs -Map @{ CommonKey = 'TargetParamName' } helper; adding or wiring a new value in the future is a one-line change to one step's map, not a hunt through every step's argument block.

  2. The verification step's default web-tier port was hardcoded to 7001, a habit inherited from a different tier this integration was originally built against, and nothing listens on 7001 on TC2606 (the real port is 3000). A wrong default port produces "Unable to connect to the remote server," which reads exactly like a real connectivity problem and gives no hint that the actual cause is a bad guess baked into the script. Fix: remove the hardcoded fallback entirely. No port is universally correct across the tiers this package has touched (cloud/saber2506 vs. TC2606 genuinely differ), so guessing one is guaranteed to be wrong on some tier. Fail toward "skip this optional step with a clear, specific reason" (or, for a step where the connection is the whole point rather than optional, fail loudly with exit 2 before attempting anything) rather than toward silently trying a plausible-looking value. The general rule: a configuration default that was right on the tier a script was originally developed against is not a safe default for a script meant to run anywhere else: if there's no single correct value, don't pick one and hope; require it explicitly or refuse cleanly.

Neither cause was a functional failure of the import itself (which had already succeeded and correctly reported so). This was exactly the "we think it's verified and it isn't" shape this whole testing effort had been guarding against elsewhere, now caught in the one place that had been missed.

Also worth knowing: what looked like a regression was a stale file, not a code fault

A "still failing, identical error" report against an already-fixed script turned out to be the runner executing a copy staged before the fix landed, not a real regression. See the "Three more findings from a third live test, run 3" section above for the full writeup: this is a recurring risk in any workflow where the machine authoring a script and the machine running it are different, and it's cheap to rule out (check a timestamp or hash) before assuming a fix didn't actually work.

★ DC's write path (create Environment / register Software / actually deploy) is still UNPROVEN over REST

Everything in the "Driving DC over REST" section above was exercised as a read. createApplication / removeApplication and the actual deploy-script generation and execution have never been called — those endpoint names came from harvesting string literals out of the DC client JS, not from a successful call. Whether DC's deploy path can be driven headlessly over REST at all is an open question, not a proven capability this skill can claim. The proven oracle technique for cracking it when the time comes is unchanged from the read path: have someone perform the action once in the real DC UI, then read the exact request out of C:\apps\DC\webserver\logs\dc_services.log (DEBUG, logs every request with the fully deserialized struct) and replicate it — that is how the read path was cracked after hours of failed payload guessing, and it is almost certainly the fastest way into the write path too.

★★ Headless BMIDE package generation, however, IS confirmed to exist: C:\apps\PLM\tc_root\bin\bmide_generate_package.bat (shells to com.teamcenter.bmide.foundation.core.internal.install.PackageProjectMain), needs the TC environment sourced first (see the env-script trap above). Verbatim usage:

-projectLocation=<Location of the project which is to be packaged>
[-packageLocation=<Location where the package is to be created>]     default: <project_loc>\output
-dependencyTemplateFolder=<Location of the dependency templates>
[-codeGenerationFolder=<Location of the project's compiled generated code>]
-softwareVersion=<Software Version>          patterns: 1 | 1.1 | 1.1.1 | 1.1.1.2
[-buildVersion=<Internal Build Version>]
[-allPlatform]  [-addTimeStamp]  [-skipFoundationVersion]  [-log=<Log file>]  [-h]

-allPlatform is described as generating a package deployable to a TC business logic server on ANY platform, "useful when your software package only has a BMIDE template and no platform specific files such as compiled libraries" — the right flag for a package like CapitalForward's (data-model + hooks + PowerShell + a payload zip, no compiled libs), though note the same help text says rt_server.zip will NOT be built under -allPlatform if the template project is configured to build one. Unresolved: the help text also says "The project must be loaded in BMIDE client without errors for validation before packaging" — whether that is a hard runtime-enforced requirement, a one-time-only precondition, or purely advisory has not been tested. Cheapest way to find out is to just run the utility against a real project and read what it actually does, rather than reason about the sentence further.

Related skills

tc-vm-operations (the VM this runs on, and its checkpoint discipline), tc-verify-and-cleanup (do not claim an install landed without checking), tc-soa-session, tc-workflow-authoring (process/task template creation and publishing over SOA, including the retraction of the earlier "GUI-only" conclusion), tc-dispatcher-requests (translator.xml / Service.properties mechanics this skill's package examples configure).


Generated from skills/tc-deployment-center/SKILL.md in the tc-automation-skills library, which is the canonical copy and also serves as the agent skill set for Teamcenter work.