1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| function Native($DllFile) { $Lib = [IO.Path]::GetFileName($DllFile) $Marshal = [System.Runtime.InteropServices.Marshal] $Module = [AppDomain]::CurrentDomain.DefineDynamicAssembly((Get-Random), 'Run').DefineDynamicModule((Get-Random)) $Struct = $Module.DefineType('DI', 1048841, [ValueType], 0) [void]$Struct.DefineField('lpStart', [IntPtr], 6) [void]$Struct.DefineField('uSize', [UIntPtr], 6) [void]$Struct.DefineField('Editable', [Boolean], 6) $DELTA_INPUT = $Struct.CreateType() $Struct = $Module.DefineType('DO', 1048841, [ValueType], 0) [void]$Struct.DefineField('lpStart', [IntPtr], 6) [void]$Struct.DefineField('uSize', [UIntPtr], 6) $DELTA_OUTPUT = $Struct.CreateType() $Class = $Module.DefineType('PSFE', 1048961, [Object], 0) [void]$Class.DefinePInvokeMethod('LoadLibraryW', 'kernel32.dll', 22, 1, [IntPtr], @([String]), 1, 3).SetImplementationFlags(128) [void]$Class.DefinePInvokeMethod('ApplyDeltaB', $Lib, 22, 1, [Int32], @([Int64], [Type]$DELTA_INPUT, [Type]$DELTA_INPUT, [Type]$DELTA_OUTPUT.MakeByRefType()), 1, 3) [void]$Class.DefinePInvokeMethod('DeltaFree', $Lib, 22, 1, [Int32], @([IntPtr]), 1, 3) $Win32 = $Class.CreateType() } function ApplyDelta($dBuffer, $dFile) { $trg = [Activator]::CreateInstance($DELTA_OUTPUT) $src = [Activator]::CreateInstance($DELTA_INPUT) $dlt = [Activator]::CreateInstance($DELTA_INPUT) $dlt.lpStart = $Marshal::AllocHGlobal($dBuffer.Length) $dlt.uSize = [Activator]::CreateInstance([UIntPtr], @([UInt32]$dBuffer.Length)) $dlt.Editable = $true $Marshal::Copy($dBuffer, 0, $dlt.lpStart, $dBuffer.Length) [void]$Win32::ApplyDeltaB(0, $src, $dlt, [ref]$trg) if ($trg.lpStart -eq [IntPtr]::Zero) { return } $out = New-Object byte[] $trg.uSize.ToUInt32() $Marshal::Copy($trg.lpStart, $out, 0, $out.Length) [IO.File]::WriteAllBytes($dFile, $out) if ($dlt.lpStart -ne [IntPtr]::Zero) { $Marshal::FreeHGlobal($dlt.lpStart) } if ($trg.lpStart -ne [IntPtr]::Zero) { [void]$Win32::DeltaFree($trg.lpStart) } } function G($DirectoryName) { $DeltaList = [ordered] @{} $doc = New-Object xml $doc.Load($DirectoryName + "\express.psf.cix.xml") $child = $doc.FirstChild.NextSibling.FirstChild while (!$child.LocalName.Equals("Files")) { $child = $child.NextSibling } $FileList = $child.ChildNodes foreach ($file in $FileList) { $fileChild = $file.FirstChild while (!$fileChild.LocalName.Equals("Delta")) { $fileChild = $fileChild.NextSibling } $deltaChild = $fileChild.FirstChild while (!$deltaChild.LocalName.Equals("Source")) { $deltaChild = $deltaChild.NextSibling } $DeltaList[$($file.id)] = @{name = $file.name; time = $file.time; stype = $deltaChild.type; offset = $deltaChild.offset; length = $deltaChild.length }; } return $DeltaList } function P($CabFile, $DllFile = 'msdelta.dll') { if ($DllFile -eq 'msdelta.dll' -and (Test-Path "$env:SystemRoot\System32\UpdateCompression.dll")) { $DllFile = "$env:SystemRoot\System32\UpdateCompression.dll" } . Native($DllFile) [void]$Win32::LoadLibraryW($DllFile) $DirectoryName = $CabFile.Substring(0, $CabFile.LastIndexOf('.')) $PSFFile = $DirectoryName + ".psf" $null = [IO.Directory]::CreateDirectory($DirectoryName) $DeltaList = G $DirectoryName $PSFFileStream = [IO.File]::OpenRead([IO.Path]::GetFullPath($PSFFile)) $cwd = [IO.Path]::GetFullPath($DirectoryName) [Environment]::CurrentDirectory = $cwd $null = [IO.Directory]::CreateDirectory("000") foreach ($DeltaFile in $DeltaList.Values) { $FullFileName = $DeltaFile.name if (Test-Path $FullFileName) { continue } $ShortFold = [IO.Path]::GetDirectoryName($FullFileName) $ShortFile = [IO.Path]::GetFileName($FullFileName) [bool]$UseRobo = (($cwd + '\' + $FullFileName).Length -gt 255) -or (($cwd + '\' + $ShortFold).Length -gt 248) if ($UseRobo -eq 0 -and $ShortFold.IndexOf("_") -ne -1) { $null = [IO.Directory]::CreateDirectory($ShortFold) } if ($UseRobo -eq 0) { $WhereFile = $FullFileName } Else { $WhereFile = "000\" + $ShortFile } try { [void]$PSFFileStream.Seek($DeltaFile.offset, 0) } catch {} $Buffer = New-Object byte[] $DeltaFile.length try { [void]$PSFFileStream.Read($Buffer, 0, $DeltaFile.length) } catch {} $OutputFileStream = [IO.File]::Create($WhereFile) try { [void]$OutputFileStream.Write($Buffer, 0, $DeltaFile.length) } catch {} [void]$OutputFileStream.Close() if ($DeltaFile.stype -eq "PA30" -or $DeltaFile.stype -eq "PA31") { ApplyDelta $Buffer $WhereFile } $null = [IO.File]::SetLastWriteTimeUtc($WhereFile, [DateTime]::FromFileTimeUtc($DeltaFile.time)) if ($UseRobo -eq 0) { continue } Start-Process robocopy.exe -NoNewWindow -Wait -ArgumentList ('"' + $cwd + '\000' + '"' + ' ' + '"' + $cwd + '\' + $ShortFold + '"' + ' ' + $ShortFile + ' /MOV /R:1 /W:1 /NS /NC /NFL /NDL /NP /NJH /NJS') } [void]$PSFFileStream.Close() $null = [IO.Directory]::Delete("000", $True) }
|