Private/New-CabinetFile.ps1

function New-CabinetFile {
    <#
    .SYNOPSIS
        Creates a .cab file from a directory, preserving its folder structure.
    .DESCRIPTION
        Generates a temporary DDF (Directive Definition File) listing all files under
        SourceDirectory with their relative paths, then calls makecab.exe to produce
        the cabinet archive. The DDF is removed after the process completes.
    .PARAMETER SourceDirectory
        Root directory whose contents (recursively) will be packed into the cabinet.
    .PARAMETER Destination
        Full path for the output .cab file (e.g. C:\Temp\Logs-Parsed.cab).
    .OUTPUTS
        [string] The full path of the created .cab file.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string] $SourceDirectory,

        [Parameter(Mandatory)]
        [string] $Destination
    )

    $cabName     = Split-Path $Destination -Leaf
    $cabDir      = Split-Path $Destination -Parent
    $ddfPath     = [System.IO.Path]::GetTempFileName() + '.ddf'

    $files = Get-ChildItem -Path $SourceDirectory -Recurse -File

    if (-not $files) {
        throw "No files found in '$SourceDirectory'. Cannot create cabinet."
    }

    $ddfLines = [System.Collections.Generic.List[string]]::new()
    $ddfLines.Add('.OPTION EXPLICIT')
    $ddfLines.Add(".Set CabinetNameTemplate=$cabName")
    $ddfLines.Add(".Set DiskDirectoryTemplate=$cabDir")
    $ddfLines.Add('.Set MaxDiskSize=0')
    $ddfLines.Add('.Set CompressionType=MSZIP')
    $ddfLines.Add('.Set Cabinet=on')
    $ddfLines.Add('.Set Compress=on')

    foreach ($file in $files) {
        $relativePath = $file.FullName.Substring($SourceDirectory.TrimEnd('\').Length + 1)
        $ddfLines.Add("`"$($file.FullName)`" `"$relativePath`"")
    }

    [System.IO.File]::WriteAllLines($ddfPath, $ddfLines)

    try {
        # Run makecab with WorkingDirectory set to $cabDir so that the side files
        # it always generates (setup.inf, setup.rpt) land in a known location
        # and can be cleaned up reliably.
        $proc = Start-Process -FilePath 'makecab.exe' `
                              -ArgumentList "/F `"$ddfPath`"" `
                              -WorkingDirectory $cabDir `
                              -Wait `
                              -PassThru `
                              -WindowStyle Hidden
        if ($proc.ExitCode -ne 0) {
            throw "makecab.exe exited with code $($proc.ExitCode). Cabinet creation failed."
        }
    }
    finally {
        # Remove the temp DDF and the makecab side files (setup.inf, setup.rpt).
        Remove-Item -LiteralPath $ddfPath -Force -ErrorAction SilentlyContinue
        Remove-Item -LiteralPath (Join-Path $cabDir 'setup.inf') -Force -ErrorAction SilentlyContinue
        Remove-Item -LiteralPath (Join-Path $cabDir 'setup.rpt') -Force -ErrorAction SilentlyContinue
    }

    if (-not (Test-Path -LiteralPath $Destination)) {
        throw "makecab.exe completed but output file not found at '$Destination'."
    }

    return $Destination
}