Commands/Copy-OpenPackage.ps1
|
function Copy-OpenPackage { <# .SYNOPSIS Copies Open Packages .DESCRIPTION Copies Contents from one packages to another. .EXAMPLE Copy-OpenPackage -DestinationPath ./Examples/Copy.docx -InputObject ./Examples/Sample.docx -Force .LINK Get-OpenPackage .LINK Select-OpenPackage #> [Alias('Copy-OP','cpop','cpOpenPackage')] param( # The destination. # If this is not a `[IO.Packaging.Package]`, it will be considered a file path. [Parameter(ValueFromPipelineByPropertyName)] [Alias('DestinationPath')] [PSObject] $Destination, <# Includes the specified parts. Enter a wildcard pattern, such as `*.txt` Wildcards are permitted. #> [ValidateNotNullOrEmpty()] [SupportsWildcards()] [string[]] $Include, <# Excludes the specified parts. Enter a wildcard pattern, such as `*.txt` Wildcards are permitted. #> [ValidateNotNullOrEmpty()] [SupportsWildcards()] [string[]] $Exclude, <# Includes the specified content types. Enter a wildcard pattern, such as `text/*` #> [ValidateNotNullOrEmpty()] [SupportsWildcards()] [string[]] $IncludeContentType, <# Excludes the specified content types. Enter a wildcard pattern, such as `text/*` #> [ValidateNotNullOrEmpty()] [SupportsWildcards()] [string[]] $ExcludeContentType, # If set, will merge contents into an existing file. [switch] $Merge, # The input object [Parameter(ValueFromPipeline)] [PSObject] $InputObject, # If set, will update existing packages. [switch] $Force ) begin { $selectOpenPackage = $ExecutionContext.SessionState.InvokeCommand.GetCommand('Select-OpenPackage','Function') } process { # If the input was not a package if ($inputObject -isnot [IO.Packaging.Package]) { $loadedPackage = # see if it is a file we can load if ($InputObject -is [IO.FileInfo]) { Get-OpenPackage $InputObject.FullName } elseif ($inputFile = Get-Item -ErrorAction Ignore -Path "$InputObject") { Get-OpenPackage $inputFile.FullName } # If it was not, return. if ($loadedPackage -isnot [IO.Packaging.Package]) { return } $InputObject = $loadedPackage } $destinationPackage = if ($Destination -is [IO.Packaging.Package]) { $Destination } elseif ($Destination) { # Get the absolute path of the destination, without creating the file, $unresolvedDestination = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Destination) # then see if the file exists. $fileExists = Test-Path $unresolvedDestination # If it does and we are not using the -Force if ($fileExists -and -not $force) { # write an error Write-Error "$unresolvedDestionation already exists, use -Force to overwrite" -Category ResourceExists return } # If it did not exist, create it with New-Item -Force elseif (-not $Merge) { # this will create intermediate paths. $packageFile = New-Item -ItemType File -Path $unresolvedDestination -Force if (-not $packageFile) { return } } elseif ($Merge) { $packageFile = Get-Item -ItemType File -Path $unresolvedDestination } # Try to open or create our package for read and write. [IO.Packaging.Package]::Open($packageFile.FullName, 'OpenOrCreate', 'ReadWrite') } else { $memoryStream = [IO.MemoryStream]::new() [IO.Packaging.Package]::Open($memoryStream, 'OpenOrCreate', 'ReadWrite') | Add-Member NoteProperty MemoryStream $memoryStream -Force -PassThru } # If we could not, we are done. if (-not $destinationPackage) { return } # Start off with the package properties foreach ($property in $InputObject.PackageProperties.psobject.properties) { if ($property.IsSettable) { $destinationPackage.PackageProperties.$($property.Name) = $InputObject.PackageProperties.$($property.Name) } } # Get the input parts and relationships $inputPackageParts = $InputObject.GetParts() $selectSplat = [Ordered]@{InputObject=$InputObject} foreach ($key in $PSBoundParameters.Keys) { if ($selectOpenPackage.Parameters[$key]) { $selectSplat[$key] = $PSBoundParameters[$key] } } $inputPackageParts = Select-OpenPackage @selectSplat $inputPackageRelationships = @($InputObject.GetRelationships()) # For each part in the input foreach ($inputPart in $inputPackageParts) { # Create or open a part in the destination $destinationPart = if (-not $destinationPackage.PartExists($inputPart.Uri)) { $destinationPackage.CreatePart($inputPart.Uri, $inputPart.ContentType, $inputPart.CompressionOption) } else { $destinationPackage.GetPart($inputPart.Uri) } # and copy the streams. $inputStream = $inputPart.GetStream('Open', 'Read') $destinationStream = $destinationPart.GetStream() $inputStream.CopyTo($destinationStream) $inputStream.Close() $destinationStream.Close() $partRelationships = @( try { $inputPart.GetRelationships() } catch { # Relationships cannot have relationships # Also, we can't copy any relationship that throws an exception. # So simply ignore the error. } ) if ($partRelationships) { $inputPackageRelationships += $partRelationships } } # Then, create any relationships that do not exist. foreach ($inputRelationship in $inputPackageRelationships) { if ($inputRelationship.SourceUri -eq '/') { if (-not $destinationPackage.RelationshipExists($inputRelationship.id)) { $null = $destinationPackage.CreateRelationship( $inputRelationship.targetUri, $inputRelationship.targetMode, $inputRelationship.relationshipType, $inputRelationship.id ) } } elseif ($inputRelationship.SourceUri -match '^/.') { $destinationPackagePart = $destinationPackage.GetPart($inputRelationship.SourceUri) if (-not $destinationPackagePart.RelationshipExists($inputRelationship.id)) { $destinationPackagePart.CreateRelationship( $inputRelationship.targetUri, $inputRelationship.targetMode, $inputRelationship.relationshipType, $inputRelationship.id ) } } } if ($destination -and $Destination -isnot [IO.Packaging.Package]) { # We can now close our package, writing the file. $destinationPackage.Close() # We want to open it right back up again as we output the updated file. Get-OpenPackage -FilePath $unresolvedDestination } else { $destinationPackage } } } |