Public/Split-File.ps1
# Copyright (c) 2023 Anthony J. Raymond, MIT License (see manifest for details) using namespace System.IO function Split-File { [CmdletBinding(SupportsShouldProcess)] [OutputType([object])] ## PARAMETERS ############################################################# param ( [Parameter( Mandatory, Position = 0, ValueFromPipelineByPropertyName, ValueFromPipeline, ParameterSetName = "Path" )] [ValidateScript({ if (Test-Path -Path $_ -PathType Leaf) { return $true } throw "The argument specified must resolve to a valid file path." })] [string[]] $Path, [Parameter( Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "LiteralPath" )] [Alias("PSPath")] [ValidateScript({ if (Test-Path -LiteralPath $_ -PathType Leaf) { return $true } throw "The argument specified must resolve to a valid file path." })] [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, [Parameter ( Mandatory )] [ValidateRange(0, [int32]::MaxValue)] [int32] $Size ) ## BEGIN ################################################################## begin { $DestinationInfo = [FileInfo] (Resolve-PoshPath -LiteralPath $Destination).ProviderPath } ## PROCESS ################################################################ process { $Process = ($PSCmdlet.ParameterSetName -cmatch "^LiteralPath") | ?: { 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 = [FileInfo] $Object.ProviderPath Write-Verbose ("READ {0}" -f $File) Use-Object ($Reader = [File]::OpenRead($File)) { $Buffer = [byte[]]::new($Size) $Count = 1 $CalculatedDestination = $DestinationInfo.Extension | ?: { "{0}\{1}" -f $DestinationInfo.Directory.FullName, $File.Name } { "{0}\{1}" -f $DestinationInfo.FullName.TrimEnd("\"), $File.Name } while ($Read = $Reader.Read($Buffer, 0, $Buffer.Length)) { if ($Read -ne $Buffer.Length) { [array]::Resize([ref] $Buffer, $Read) } $SplitFile = "{0}.{1}split" -f $CalculatedDestination, $Count if ($PSCmdlet.ShouldProcess($SplitFile, "Write Content")) { if (-not ($Directory = $DestinationInfo.Extension | ?: { $DestinationInfo.Directory } { $DestinationInfo }).Exists) { $null = [Directory]::CreateDirectory($Directory) } Write-Verbose ("WRITE {0}" -f $SplitFile) [File]::WriteAllBytes($SplitFile, $Buffer) } $Count++ } # sort to fix ChildItem number sorting Write-Output (Get-ChildItem -Path ("{0}.*split" -f $CalculatedDestination) | Sort-Object -Property @{e = { [int32] [regex]::Match($_.FullName, "\.(\d+)split$").Groups[1].Value } }) } ## EXCEPTIONS ################################################# } catch [System.Management.Automation.MethodInvocationException] { $PSCmdlet.WriteError(( New-MethodInvocationException -Exception $_.Exception.InnerException )) } catch { $PSCmdlet.WriteError($_) } } } ## END #################################################################### end { } } |