Skip to content

Extend Remove-IshPublicationOutput with -Unrelease to support archiving of released publication outputs #268

Description

@ddemeyer

Business case

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.

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 -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 removed
Get-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 shells
Get-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, ...)
  • -Force cascade logic (ProcessRecord:174-226): unchanged
  • -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


Out of scope


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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions