You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Large Tridion Docs repositories accumulate released publication outputs whose rendered blobs (PDF, HTML packages) are no longer needed. Because Remove-IshPublicationOutput cannot delete a VPUBSTATUSRELEASED output - the server rejects the deletion - a manual unrelease step is currently required before any removal. For bulk archiving operations over thousands of outputs this is a significant friction point.
Adding a -Unrelease switch to the existing Remove-IshPublicationOutput cmdlet covers this in a single pass with no new cmdlets, no new enumerations, and no extra server round-trips beyond the unrelease call itself.
Key design point: the version and logical metadata shells (title, baseline, context document) survive removal of a lng card automatically - the cascade that deletes version and logical cards is entirely client-side and is already controlled by the existing -Force switch. A caller who wants to preserve the shells for future republishing simply omits -Force and does not pipe the lng card they wish to keep. No additional protection logic is needed inside the cmdlet.
How to use
Typical archiving pattern - dry run first, then commit:
New-IshSession-WsBaseUrl "https://example.com/ISHWS/"$oldFilter=Set-IshMetadataFilterField-Name "FISHLASTMODIFIEDON"-Level Lng `-ValueType Value -FilterOperator LessThan -Value "01/01/2022 00:00:00"# Dry run - see what would be unreleased and removedGet-IshFolder-FolderPath "General\MyPublications"-FolderTypeFilter @("ISHPublication") -Recurse |ForEach-Object-Process {
Get-IshFolderContent-IshFolder $_-VersionFilter ""-MetadataFilter $oldFilter|Remove-IshPublicationOutput-Unrelease -WhatIf
}
# Commit - remove lng cards, version/logical shells survive (no -Force)Get-IshFolder-FolderPath "General\MyPublications"-FolderTypeFilter @("ISHPublication") -Recurse |ForEach-Object-Process {
Get-IshFolderContent-IshFolder $_-VersionFilter ""-MetadataFilter $oldFilter|Remove-IshPublicationOutput-Unrelease
}
# Full cleanup - remove lng cards and cascade-delete empty version/logical shellsGet-IshFolder-FolderPath "General\MyPublications"-FolderTypeFilter @("ISHPublication") -Recurse |ForEach-Object-Process {
Get-IshFolderContent-IshFolder $_-VersionFilter ""-MetadataFilter $oldFilter|Remove-IshPublicationOutput-Unrelease -Force
}
Optional: download rendered blobs before removing (memory-safe, one folder at a time):
New-IshSession-WsBaseUrl "https://example.com/ISHWS/"$oldFilter=Set-IshMetadataFilterField-Name "FISHLASTMODIFIEDON"-Level Lng `-ValueType Value -FilterOperator LessThan -Value "01/01/2022 00:00:00"Get-IshFolder-FolderPath "General\MyPublications"-FolderTypeFilter @("ISHPublication") -Recurse |ForEach-Object-Process {
Get-IshFolderContent-IshFolder $_-VersionFilter ""-MetadataFilter $oldFilter|Tee-Object-Variable folderPublications |Get-IshPublicationOutputData-FolderPath "C:\Temp\Archive"$folderPublications|Remove-IshPublicationOutput-Unrelease
}
# Note: Get-IshPublicationOutputData only downloads outputs that have rendered data.# Draft-only outputs produce no file silently.# Uncomment to push downloads to S3 (AWS.Tools.S3 required):# Get-IshPublicationOutputData -FolderPath "C:\Temp\Archive" |# ForEach-Object { Write-S3Object -BucketName "my-docs-archive" -File $_.FullName -Key $_.Name }
Known limitations
Currently-publishing outputs are skipped: outputs in VPUBSTATUSPUBLISHING status emit a WriteWarning and are neither unreleased nor removed. Re-run after publishing completes.
Unrelease requires 14SP4 with CRQ-31475 hotfix, or 15.0.0+. On older servers the SetMetadataByIshLngRef unrelease call will throw. Without -Unrelease the existing behaviour is unchanged on all versions.
Database space recovery: requires time up to 24 hours because the Crawler services makes the marked-for-deletion of the PublicationOutput an actual delete. Then a InfoShareCM_StandardInfoShareJob run actually frees up the records of the Electronic Documents (ED), since 15.3.0 this is a synchronous action and no longer requires the database job. Last is the defragmentation or shrinking that needs to be handled by the database engine.
Caller controls which cards survive - to preserve version/logical metadata shells for future republishing, omit -Force and do not pipe the lng card you wish to keep. The version and logical shells are never auto-deleted by the server; cascade deletion is always client-side via -Force.
Tasks
Implementation
Add [SwitchParameter] Unrelease property to RemoveIshPublicationOutput.cs, both IshObjectGroup and ParameterGroup parameter sets, Mandatory = false; add <para type="description"> XML doc
In ProcessRecord, pipeline path (IshObject != null): before DeleteByIshLngRef, check FISHPUBSTATUS of the current lng card
Reuse FISHPUBSTATUS from ishObject.IshFields if the caller pre-fetched it; otherwise fall back to RetrieveMetadataByIshLngRefs for that single lngRef
If VPUBSTATUSPUBLISHING: WriteWarning + continue (skip both unrelease and delete)
If VPUBSTATUSRELEASED and Unrelease.IsPresent: ShouldProcess(lngRef + " Unrelease") + SetMetadataByIshLngRef with FISHPUBSTATUS = VPUBSTATUSPUBLISHINGCANCELLED
Proceed to DeleteByIshLngRef as today
In ProcessRecord, ParameterGroup path: same status check and conditional unrelease before Delete(LogicalId, Version, OutputFormat, LanguageCombination, ...)
-RequiredCurrentMetadata: unchanged, passed to delete as today
ShouldProcess target string for unrelease step distinguishable from delete step in -WhatIf output
Update triple-slash XML doc synopsis and description; add a new <example> showing the archiving pattern with -Unrelease and folder-walk
Testing
Extend RemoveIshPublicationOutput.Tests.ps1 with -Unrelease context
Test: -Unrelease on a draft-status output removed directly without unrelease call
Test: -Unrelease with -WhatIf - nothing changed, both unrelease and delete described in output
Test: -Unrelease -Force - lng removed, version and logical shells cascade-deleted when last lng
Note: full unrelease coverage (starting from VPUBSTATUSRELEASED) requires a prior publish cycle; deferred to manual testing as noted in existing test file
Documentation
Add ReleaseNotes entry in Doc/ReleaseNotes-ISHRemote-X.Y.md with the archiving pattern, referencing the community thread
Automatic keep-one-per-version protection inside the cmdlet - caller controls this by what they pipe and whether they pass -Force
Implementation notes
FISHPUBSTATUS check: reuse from ishObject.IshFields when present to avoid an extra server call; only call RetrieveMetadataByIshLngRefs when the field is absent on the incoming object
VPUBSTATUSPUBLISHING guard must precede both the unrelease attempt and the delete attempt - a currently-publishing output cannot be unreleased or deleted by the API
No new enum, no new cmdlet, no accumulation, no EndProcessing flush - throughput matches the existing cmdlet exactly plus one SetMetadataByIshLngRef per released card
VerbsCommon.Remove cmdlet stays as-is; only a new switch parameter and status-check block are added
Business case
Large Tridion Docs repositories accumulate released publication outputs whose rendered blobs (PDF, HTML packages) are no longer needed. Because
Remove-IshPublicationOutputcannot delete aVPUBSTATUSRELEASEDoutput - the server rejects the deletion - a manual unrelease step is currently required before any removal. For bulk archiving operations over thousands of outputs this is a significant friction point.Community thread: https://community.rws.com/product-groups/tridion/tridion-docs/f/forum/61643/shrinking-a-large-test-database-can-you-create-a-new-db-with-all-the-existing-metadata-but-no-data
Adding a
-Unreleaseswitch to the existingRemove-IshPublicationOutputcmdlet covers this in a single pass with no new cmdlets, no new enumerations, and no extra server round-trips beyond the unrelease call itself.Key design point: the version and logical metadata shells (title, baseline, context document) survive removal of a lng card automatically - the cascade that deletes version and logical cards is entirely client-side and is already controlled by the existing
-Forceswitch. A caller who wants to preserve the shells for future republishing simply omits-Forceand does not pipe the lng card they wish to keep. No additional protection logic is needed inside the cmdlet.How to use
Typical archiving pattern - dry run first, then commit:
Optional: download rendered blobs before removing (memory-safe, one folder at a time):
Known limitations
VPUBSTATUSPUBLISHINGstatus emit aWriteWarningand are neither unreleased nor removed. Re-run after publishing completes.SetMetadataByIshLngRefunrelease call will throw. Without-Unreleasethe existing behaviour is unchanged on all versions.Crawlerservices makes themarked-for-deletionof the PublicationOutput an actualdelete. Then aInfoShareCM_StandardInfoShareJobrun actually frees up the records of the Electronic Documents (ED), since 15.3.0 this is a synchronous action and no longer requires the database job. Last is the defragmentation or shrinking that needs to be handled by the database engine.-Forceand do not pipe the lng card you wish to keep. The version and logical shells are never auto-deleted by the server; cascade deletion is always client-side via-Force.Tasks
Implementation
[SwitchParameter] Unreleaseproperty toRemoveIshPublicationOutput.cs, bothIshObjectGroupandParameterGroupparameter sets,Mandatory = false; add<para type="description">XML docProcessRecord, pipeline path (IshObject != null): beforeDeleteByIshLngRef, checkFISHPUBSTATUSof the current lng cardFISHPUBSTATUSfromishObject.IshFieldsif the caller pre-fetched it; otherwise fall back toRetrieveMetadataByIshLngRefsfor that single lngRefVPUBSTATUSPUBLISHING:WriteWarning+continue(skip both unrelease and delete)VPUBSTATUSRELEASEDandUnrelease.IsPresent:ShouldProcess(lngRef + " Unrelease")+SetMetadataByIshLngRefwithFISHPUBSTATUS = VPUBSTATUSPUBLISHINGCANCELLEDDeleteByIshLngRefas todayProcessRecord,ParameterGrouppath: same status check and conditional unrelease beforeDelete(LogicalId, Version, OutputFormat, LanguageCombination, ...)-Forcecascade logic (ProcessRecord:174-226): unchanged-RequiredCurrentMetadata: unchanged, passed to delete as todayShouldProcesstarget string for unrelease step distinguishable from delete step in-WhatIfoutput<example>showing the archiving pattern with-Unreleaseand folder-walkTesting
RemoveIshPublicationOutput.Tests.ps1with-Unreleasecontext-Unreleaseon a draft-status output removed directly without unrelease call-Unreleasewith-WhatIf- nothing changed, both unrelease and delete described in output-Unrelease -Force- lng removed, version and logical shells cascade-deleted when last lngVPUBSTATUSRELEASED) requires a prior publish cycle; deferred to manual testing as noted in existing test fileDocumentation
ReleaseNotesentry inDoc/ReleaseNotes-ISHRemote-X.Y.mdwith the archiving pattern, referencing the community threadClear-IshPublicationOutput) with a reference to this issue as the adopted simpler approachOut of scope
Clear-IshPublicationOutputcmdlet (superseded by this approach - see Add cmdlet Clear-IshPublicationOutput to unrelease and remove publication outputs for database archiving #262)-ForceImplementation notes
FISHPUBSTATUScheck: reuse fromishObject.IshFieldswhen present to avoid an extra server call; only callRetrieveMetadataByIshLngRefswhen the field is absent on the incoming objectVPUBSTATUSPUBLISHINGguard must precede both the unrelease attempt and the delete attempt - a currently-publishing output cannot be unreleased or deleted by the APIEndProcessingflush - throughput matches the existing cmdlet exactly plus oneSetMetadataByIshLngRefper released cardVerbsCommon.Removecmdlet stays as-is; only a new switch parameter and status-check block are added