Public/Join-File.ps1
# Copyright (c) 2023 Anthony J. Raymond, MIT License (see manifest for details) function Join-File { [CmdletBinding(SupportsShouldProcess)] [OutputType([object])] ## PARAMETERS ############################################################# param ( [Parameter( Position = 0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = "Path" )] [ValidateScript({ if (Test-Path -Path $_ -PathType Leaf -Filter *.*split) { return $true } throw "The argument specified must resolve to a valid split type file." })] [string[]] $Path, [Alias("PSPath")] [Parameter( Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "LiteralPath" )] [ValidateScript({ if (Test-Path -LiteralPath $_ -PathType Leaf -Filter *.*split) { return $true } throw "The argument specified must resolve to a valid split type file." })] [string[]] $LiteralPath, [Parameter()] [ValidateScript({ if (Test-Path -LiteralPath $_ -IsValid) { return $true } throw "The argument specified must resolve to a valid file or folder path." })] [string] $Destination = (Get-Location -PSProvider FileSystem).ProviderPath ) ## BEGIN ################################################################## begin { $DestinationInfo = [System.IO.FileInfo] (Resolve-PoshPath -LiteralPath $Destination).ProviderPath } ## PROCESS ################################################################ process { $Process = ($PSCmdlet.ParameterSetName -cmatch "^LiteralPath") | Use-Ternary { Resolve-PoshPath -LiteralPath $LiteralPath } { Resolve-PoshPath -Path $Path } foreach ($Object in $Process) { try { if ($Object.Provider.Name -ne "FileSystem") { New-ArgumentException "The argument specified must resolve to a valid path on the FileSystem provider." -Throw } $File = [System.IO.FileInfo] $Object.ProviderPath $CalculatedDestination = $DestinationInfo.Extension | Use-Ternary { $DestinationInfo } { "{0}\{1}" -f $DestinationInfo.FullName.TrimEnd("\"), $File.BaseName } if ($PSCmdlet.ShouldProcess($CalculatedDestination, "Write Content")) { if (-not ($Directory = $DestinationInfo.Extension | Use-Ternary { $DestinationInfo.Directory } { $DestinationInfo }).Exists) { $null = [System.IO.Directory]::CreateDirectory($Directory) } Write-Verbose ("WRITE {0}" -f $CalculatedDestination) Use-Object ($Writer = [System.IO.File]::OpenWrite($CalculatedDestination)) { # sort to fix ChildItem number sorting foreach ($SplitFile in (Get-ChildItem -Path ("{0}\{1}.*split" -f $File.Directory, $File.BaseName)).FullName | Sort-Object -Property @{e = { [int32] [regex]::Match($_, "\.(\d+)split$").Groups[1].Value } }) { Write-Verbose ("READ {0}" -f $SplitFile) $Bytes = [System.IO.File]::ReadAllBytes($SplitFile) $Writer.Write($Bytes, 0, $Bytes.Length) } } } Write-Output (Get-ChildItem -Path $CalculatedDestination) ## EXCEPTIONS ################################################# } catch [System.Management.Automation.MethodInvocationException] { $PSCmdlet.WriteError(( New-MethodInvocationException -Exception $_.Exception.InnerException )) } catch { $PSCmdlet.WriteError($_) } } } ## END #################################################################### end { } } |