素の.net 3.0以降でZIPファイルを扱う

.net 4.5からZipArchiveクラスが提供されます。
これによりようやくZIPファイルの扱いがまともになるわけですが、、、。
Windows7/8では、素では.net4.5は入っていません。
これをなんとかしたい。



経緯

Explorerの圧縮フォルダー機能でZIPは扱えますが、不安定じゃないですか。
それにMicrosoftも推奨ではない、とか言うし。


dotNetZipとかライブラリーを使えば良いんですけど、ライセンスとかインストールとか面倒。


ZIPと言えば、.net3.0からは、OpenDocument形式のためのクラスがある。
これはちょっと特殊なZIPファイル。(いろいろ制限がある)
でもこれができるなら、扱えるんじゃないの?と探したところ、、、あった。
http://www.codeproject.com/Articles/209731/Csharp-use-Zip-archives-without-external-libraries
登録が面倒だったので、ソースは見てないけど、十分なヒント。
非公開のクラスをリフレクションしまくりでやってみたら、、、できた!
、、、が、日付が更新できない。
今のところ、あとからバイナリー編集して日付を更新する方法しか見つけてない。

追記 2014/08/29
更新日付の変更に対応した、超割切り仕様のクラスを作成しました。
http://d.hatena.ne.jp/junjun777/20140829/dot_net_zip


以下ソース。

日付更新できない版

日付が更新できなくても良いなら、これで良いかと。

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace ZipPackageSample
{
    class ZipArchive : IDisposable
    {
        private static Type _type = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipArchive");
        private static MethodInfo _openOnFile = _type.GetMethod("OpenOnFile", BindingFlags.Static | BindingFlags.NonPublic);
        private static MethodInfo _openOnStream = _type.GetMethod("OpenOnStream", BindingFlags.Static | BindingFlags.NonPublic);

        public static ZipArchive OpenOnFile(string path, FileMode mode, FileAccess access, FileShare share, bool streaming)
        {
            return new ZipArchive { _zipArchive = _openOnFile.Invoke(null, new object[] { path, mode, access, share, streaming }) };
        }
        public static ZipArchive OpenOnStream(Stream stream, FileMode mode, FileAccess access, bool streaming)
        {
            return new ZipArchive { _zipArchive = _openOnStream.Invoke(null, new object[] { stream, mode, access, streaming }) };
        }

        private static Type _typeCme = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.CompressionMethodEnum");
        private static object _stored = _typeCme.GetField("Stored", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _deflated = _typeCme.GetField("Deflated", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static Type _typeDoe = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.DeflateOptionEnum");
        private static object _normal = _typeDoe.GetField("Normal", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _maximum = _typeDoe.GetField("Maximum", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _fast = _typeDoe.GetField("Fast", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _superFast = _typeDoe.GetField("SuperFast", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _none = _typeDoe.GetField("None", BindingFlags.Static | BindingFlags.Public).GetValue(null);

        public static CompressionMethodEnum FromInternalCme(object cme)
        {
            CompressionMethodEnum ret = CompressionMethodEnum.Stored;
            if (_deflated.Equals(cme)) ret = CompressionMethodEnum.Deflated;
            return ret;
        }
        public static object ToInternalCme(CompressionMethodEnum cme)
        {
            object ret = _stored;
            if (cme == CompressionMethodEnum.Deflated) ret = _deflated;
            return ret;
        }
        public static DeflateOptionEnum FromInternalDoe(object doe)
        {
            DeflateOptionEnum ret = DeflateOptionEnum.None;
            if (_normal.Equals(doe))
            {
                ret = DeflateOptionEnum.Normal;
            }
            else if (_maximum.Equals(doe))
            {
                ret = DeflateOptionEnum.Maximum;
            }
            else if (_fast.Equals(doe))
            {
                ret = DeflateOptionEnum.Fast;
            }
            else if (_superFast.Equals(doe))
            {
                ret = DeflateOptionEnum.SuperFast;
            }
            return ret;
        }
        public static object ToInternalDoe(DeflateOptionEnum doe)
        {
            object ret = _none;
            if (doe == DeflateOptionEnum.Normal)
            {
                ret = _normal;
            }
            else if (doe == DeflateOptionEnum.Maximum)
            {
                ret = _maximum;
            }
            else if (doe == DeflateOptionEnum.Fast)
            {
                ret = _fast;
            }
            else if (doe == DeflateOptionEnum.SuperFast)
            {
                ret = _superFast;
            }
            return ret;
        }

        private object _zipArchive = null;
        private static MethodInfo _addFile = _type.GetMethod("AddFile", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _getFile = _type.GetMethod("GetFile", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _fileExists = _type.GetMethod("FileExists", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _deleteFile = _type.GetMethod("DeleteFile", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _getFiles = _type.GetMethod("GetFiles", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _flush = _type.GetMethod("Flush", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _close = _type.GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _dispose = _type.GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public);
        private static PropertyInfo _openAccess = _type.GetProperty("OpenAccess", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _zipFileInfoDictionary = _type.GetProperty("ZipFileInfoDictionary", BindingFlags.Instance | BindingFlags.NonPublic);

        public ZipFileInfo AddFile(string path, CompressionMethodEnum cme, DeflateOptionEnum doe)
        {
            return new ZipFileInfo(_addFile.Invoke(_zipArchive, new object[] { path, ToInternalCme(cme), ToInternalDoe(doe) }));
        }
        public ZipFileInfo GetFile(string path)
        {
            return new ZipFileInfo(_getFile.Invoke(_zipArchive, new object[] { path }));
        }
        public bool FileExists(string path)
        {
            return (bool)_fileExists.Invoke(_zipArchive, new object[] { path });
        }
        public void DeleteFile(string path)
        {
            _deleteFile.Invoke(_zipArchive, new object[] { path });
        }
        private static Type _typeZfic = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipFileInfoCollection");
        private static MethodInfo _getEnumerator = _typeZfic.GetMethod("System.Collections.IEnumerable.GetEnumerator", BindingFlags.Instance | BindingFlags.NonPublic);
        public IEnumerable<ZipFileInfo> GetFiles()
        {
            var zfic = _getEnumerator.Invoke(_getFiles.Invoke(_zipArchive, null), null) as System.Collections.IEnumerator;
            while (zfic.MoveNext())
            {
                yield return new ZipFileInfo(zfic.Current);
            }
        }
        public void Flush()
        {
            _flush.Invoke(_zipArchive, null);
        }
        public void Close()
        {
            _close.Invoke(_zipArchive, null);
        }
        public void Dispose()
        {
            _dispose.Invoke(_zipArchive, null);
        }
        public FileAccess OpenAccess
        {
            get { return (FileAccess)_openAccess.GetValue(_zipArchive, null); }
        }
        public System.Collections.IDictionary ZipFileInfoDictionary
        {
            get { return _zipFileInfoDictionary.GetValue(_zipArchive, null) as System.Collections.IDictionary; }
        }


        public class ZipFileInfo
        {
            private static Type _type = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipFileInfo");
            private static MethodInfo _getStream = _type.GetMethod("GetStream", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _name = _type.GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _zipArchive = _type.GetProperty("ZipArchive", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _compressionMethod = _type.GetProperty("CompressionMethod", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _lastModFileDateTime = _type.GetProperty("LastModFileDateTime", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _deflateOption = _type.GetProperty("DeflateOption", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _folderFlag = _type.GetProperty("FolderFlag", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _volumeLabelFlag = _type.GetProperty("VolumeLabelFlag", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _localFileBlock = _type.GetProperty("LocalFileBlock", BindingFlags.Instance | BindingFlags.NonPublic);
            private static Type _typeL = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipIOLocalFileBlock");
            private static PropertyInfo _lastMod = _typeL.GetProperty("LastModFileDateTime", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _compSize = _typeL.GetProperty("CompressedSize", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _uncompSize = _typeL.GetProperty("UncompressedSize", BindingFlags.Instance | BindingFlags.NonPublic);

            private object _zipFileInfo = null;
            private object _lfb = null;

            public ZipFileInfo(object zipFileInfo)
            {
                _zipFileInfo = zipFileInfo;
            }

            public Stream GetStream(FileMode mode, FileAccess access)
            {
                return _getStream.Invoke(_zipFileInfo, new object[] { mode, access }) as Stream;
            }

            public string Name
            {
                get { return _name.GetValue(_zipFileInfo, null) as string; }
            }
            public ZipArchive ZipArchive
            {
                get { return new ZipArchive { _zipArchive = _zipArchive.GetValue(_zipFileInfo, null) }; }
            }
            public CompressionMethodEnum CompressionMethod
            {
                get { return ZipArchive.FromInternalCme(_compressionMethod.GetValue(_zipFileInfo, null)); }
            }
            public DateTime LastModFileDateTime
            {
                get { return (DateTime)_lastModFileDateTime.GetValue(_zipFileInfo, null); }
            }
            public DeflateOptionEnum DeflateOption
            {
                get { return ZipArchive.FromInternalDoe(_deflateOption.GetValue(_zipFileInfo, null)); }
            }
            public bool FolderFlag
            {
                get { return (bool)_folderFlag.GetValue(_zipFileInfo, null); }
            }
            public bool VolumeLabelFlag
            {
                get { return (bool)_volumeLabelFlag.GetValue(_zipFileInfo, null); }
            }
            public long CompressedSize
            {
                get
                {
                    if (_lfb == null) _lfb = _localFileBlock.GetValue(_zipFileInfo, null);
                    return (long)_compSize.GetValue(_lfb, null);
                }
            }
            public long UncompressedSize
            {
                get
                {
                    if (_lfb == null) _lfb = _localFileBlock.GetValue(_zipFileInfo, null);
                    return (long)_uncompSize.GetValue(_lfb, null);
                }
            }
        }


        public enum CompressionMethodEnum
        {
            Stored,
            Deflated
        }
        public enum DeflateOptionEnum
        {
            Normal,
            Maximum,
            Fast,
            SuperFast,
            None
        }
    }
}

Powershell

一部文法がPowershellで使えなかったので(Powershellバージョンのせいかな)、少し改変した。

$source = @"
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

public class ZipArchive : IDisposable
{
    private static Assembly _ass = Assembly.GetAssembly(typeof(System.IO.Packaging.Package));
    private static Type _type = _ass.GetType("MS.Internal.IO.Zip.ZipArchive");
    private static MethodInfo _openOnFile = _type.GetMethod("OpenOnFile", BindingFlags.Static | BindingFlags.NonPublic);
    private static MethodInfo _openOnStream = _type.GetMethod("OpenOnStream", BindingFlags.Static | BindingFlags.NonPublic);

    public static ZipArchive OpenOnFile(string path, FileMode mode, FileAccess access, FileShare share, bool streaming)
    {
        return new ZipArchive(_openOnFile.Invoke(null, new object[] { path, mode, access, share, streaming }));
    }
    public static ZipArchive OpenOnStream(Stream stream, FileMode mode, FileAccess access, bool streaming)
    {
        return new ZipArchive(_openOnStream.Invoke(null, new object[] { stream, mode, access, streaming }));
    }

    private static Type _typeCme = _ass.GetType("MS.Internal.IO.Zip.CompressionMethodEnum");
    private static object _stored = _typeCme.GetField("Stored", BindingFlags.Static | BindingFlags.Public).GetValue(null);
    private static object _deflated = _typeCme.GetField("Deflated", BindingFlags.Static | BindingFlags.Public).GetValue(null);
    private static Type _typeDoe = _ass.GetType("MS.Internal.IO.Zip.DeflateOptionEnum");
    private static object _normal = _typeDoe.GetField("Normal", BindingFlags.Static | BindingFlags.Public).GetValue(null);
    private static object _maximum = _typeDoe.GetField("Maximum", BindingFlags.Static | BindingFlags.Public).GetValue(null);
    private static object _fast = _typeDoe.GetField("Fast", BindingFlags.Static | BindingFlags.Public).GetValue(null);
    private static object _superFast = _typeDoe.GetField("SuperFast", BindingFlags.Static | BindingFlags.Public).GetValue(null);
    private static object _none = _typeDoe.GetField("None", BindingFlags.Static | BindingFlags.Public).GetValue(null);

    public ZipArchive(object zipArchive)
    {
        _zipArchive = zipArchive;
    }

    public static CompressionMethodEnum FromInternalCme(object cme)
    {
        CompressionMethodEnum ret = CompressionMethodEnum.Stored;
        if (_deflated.Equals(cme)) ret = CompressionMethodEnum.Deflated;
        return ret;
    }
    public static object ToInternalCme(CompressionMethodEnum cme)
    {
        object ret = _stored;
        if (cme == CompressionMethodEnum.Deflated) ret = _deflated;
        return ret;
    }
    public static DeflateOptionEnum FromInternalDoe(object doe)
    {
        DeflateOptionEnum ret = DeflateOptionEnum.None;
        if (_normal.Equals(doe))
        {
            ret = DeflateOptionEnum.Normal;
        }
        else if (_maximum.Equals(doe))
        {
            ret = DeflateOptionEnum.Maximum;
        }
        else if (_fast.Equals(doe))
        {
            ret = DeflateOptionEnum.Fast;
        }
        else if (_superFast.Equals(doe))
        {
            ret = DeflateOptionEnum.SuperFast;
        }
        return ret;
    }
    public static object ToInternalDoe(DeflateOptionEnum doe)
    {
        object ret = _none;
        if (doe == DeflateOptionEnum.Normal)
        {
            ret = _normal;
        }
        else if (doe == DeflateOptionEnum.Maximum)
        {
            ret = _maximum;
        }
        else if (doe == DeflateOptionEnum.Fast)
        {
            ret = _fast;
        }
        else if (doe == DeflateOptionEnum.SuperFast)
        {
            ret = _superFast;
        }
        return ret;
    }

    private object _zipArchive = null;
    private static MethodInfo _addFile = _type.GetMethod("AddFile", BindingFlags.Instance | BindingFlags.NonPublic);
    private static MethodInfo _getFile = _type.GetMethod("GetFile", BindingFlags.Instance | BindingFlags.NonPublic);
    private static MethodInfo _fileExists = _type.GetMethod("FileExists", BindingFlags.Instance | BindingFlags.NonPublic);
    private static MethodInfo _deleteFile = _type.GetMethod("DeleteFile", BindingFlags.Instance | BindingFlags.NonPublic);
    private static MethodInfo _getFiles = _type.GetMethod("GetFiles", BindingFlags.Instance | BindingFlags.NonPublic);
    private static MethodInfo _flush = _type.GetMethod("Flush", BindingFlags.Instance | BindingFlags.NonPublic);
    private static MethodInfo _close = _type.GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
    private static MethodInfo _dispose = _type.GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public);
    private static PropertyInfo _openAccess = _type.GetProperty("OpenAccess", BindingFlags.Instance | BindingFlags.NonPublic);
    private static PropertyInfo _zipFileInfoDictionary = _type.GetProperty("ZipFileInfoDictionary", BindingFlags.Instance | BindingFlags.NonPublic);

    public ZipFileInfo AddFile(string path, CompressionMethodEnum cme, DeflateOptionEnum doe)
    {
        return new ZipFileInfo(_addFile.Invoke(_zipArchive, new object[] { path, ToInternalCme(cme), ToInternalDoe(doe) }));
    }
    public ZipFileInfo GetFile(string path)
    {
        return new ZipFileInfo(_getFile.Invoke(_zipArchive, new object[] { path }));
    }
    public bool FileExists(string path)
    {
        return (bool)_fileExists.Invoke(_zipArchive, new object[] { path });
    }
    public void DeleteFile(string path)
    {
        _deleteFile.Invoke(_zipArchive, new object[] { path });
    }
    private static Type _typeZfic = _ass.GetType("MS.Internal.IO.Zip.ZipFileInfoCollection");
    private static MethodInfo _getEnumerator = _typeZfic.GetMethod("System.Collections.IEnumerable.GetEnumerator", BindingFlags.Instance | BindingFlags.NonPublic);
    public IEnumerable<ZipFileInfo> GetFiles()
    {
        System.Collections.IEnumerator zfic = _getEnumerator.Invoke(_getFiles.Invoke(_zipArchive, null), null) as System.Collections.IEnumerator;
        while (zfic.MoveNext())
        {
            yield return new ZipFileInfo(zfic.Current);
        }
    }
    public void Flush()
    {
        _flush.Invoke(_zipArchive, null);
    }
    public void Close()
    {
        _close.Invoke(_zipArchive, null);
    }
    public void Dispose()
    {
        _dispose.Invoke(_zipArchive, null);
    }
    public FileAccess OpenAccess
    {
        get { return (FileAccess)_openAccess.GetValue(_zipArchive, null); }
    }
    public System.Collections.IDictionary ZipFileInfoDictionary
    {
        get { return _zipFileInfoDictionary.GetValue(_zipArchive, null) as System.Collections.IDictionary; }
    }


    public class ZipFileInfo
    {
        private static Assembly _ass = Assembly.GetAssembly(typeof(System.IO.Packaging.Package));
        private static Type _type = _ass.GetType("MS.Internal.IO.Zip.ZipFileInfo");
        private static MethodInfo _getStream = _type.GetMethod("GetStream", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _name = _type.GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _zipArchive = _type.GetProperty("ZipArchive", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _compressionMethod = _type.GetProperty("CompressionMethod", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _lastModFileDateTime = _type.GetProperty("LastModFileDateTime", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _deflateOption = _type.GetProperty("DeflateOption", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _folderFlag = _type.GetProperty("FolderFlag", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _volumeLabelFlag = _type.GetProperty("VolumeLabelFlag", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _localFileBlock = _type.GetProperty("LocalFileBlock", BindingFlags.Instance | BindingFlags.NonPublic);
        private static Type _typeL = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipIOLocalFileBlock");
        private static PropertyInfo _offset = _typeL.GetProperty("Offset", BindingFlags.Instance | BindingFlags.Public);
        private static PropertyInfo _size = _typeL.GetProperty("Size", BindingFlags.Instance | BindingFlags.Public);
        private static PropertyInfo _compSize = _typeL.GetProperty("CompressedSize", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _uncompSize = _typeL.GetProperty("UncompressedSize", BindingFlags.Instance | BindingFlags.NonPublic);

        private object _zipFileInfo = null;
        private object _lfb = null;

        public ZipFileInfo(object zipFileInfo)
        {
            _zipFileInfo = zipFileInfo;
        }

        public Stream GetStream(FileMode mode, FileAccess access)
        {
            return _getStream.Invoke(_zipFileInfo, new object[] { mode, access }) as Stream;
        }

        public string Name
        {
            get { return _name.GetValue(_zipFileInfo, null) as string; }
        }
        public ZipArchive ZipArchive
        {
            get { return new ZipArchive(_zipArchive.GetValue(_zipFileInfo, null)); }
        }
        public CompressionMethodEnum CompressionMethod
        {
            get { return ZipArchive.FromInternalCme(_compressionMethod.GetValue(_zipFileInfo, null)); }
        }
        public DateTime LastModFileDateTime
        {
            get { return (DateTime)_lastModFileDateTime.GetValue(_zipFileInfo, null); }
        }
        public DeflateOptionEnum DeflateOption
        {
            get { return ZipArchive.FromInternalDoe(_deflateOption.GetValue(_zipFileInfo, null)); }
        }
        public bool FolderFlag
        {
            get { return (bool)_folderFlag.GetValue(_zipFileInfo, null); }
        }
        public bool VolumeLabelFlag
        {
            get { return (bool)_volumeLabelFlag.GetValue(_zipFileInfo, null); }
        }
        public long Offset
        {
            get
            {
                if (_lfb == null) _lfb = _localFileBlock.GetValue(_zipFileInfo, null);
                return (long)_offset.GetValue(_lfb, null);
            }
        }
        public long Size
        {
            get
            {
                if (_lfb == null) _lfb = _localFileBlock.GetValue(_zipFileInfo, null);
                return (long)_size.GetValue(_lfb, null);
            }
        }
        public long CompressedSize
        {
            get
            {
                if (_lfb == null) _lfb = _localFileBlock.GetValue(_zipFileInfo, null);
                return (long)_compSize.GetValue(_lfb, null);
            }
        }
        public long UncompressedSize
        {
            get
            {
                if (_lfb == null) _lfb = _localFileBlock.GetValue(_zipFileInfo, null);
                return (long)_uncompSize.GetValue(_lfb, null);
            }
        }
    }


    public enum CompressionMethodEnum
    {
        Stored,
        Deflated
    }
    public enum DeflateOptionEnum
    {
        Normal,
        Maximum,
        Fast,
        SuperFast,
        None
    }
}
"@
Add-Type -Language CSharp -TypeDefinition $source -ReferencedAssemblies ('WindowsBase')
#([AppDomain]::CurrentDomain).GetAssemblies() | Out-Gridview

$zipPath = 'C:\test.zip'
$outPath = $zipPath + '.copy.zip'

$zip = [ZipArchive]::OpenOnFile($zipPath, 'Open', 'Read', 'Read', $false)
$zipCopy = [ZipArchive]::OpenOnFile($outPath, 'CreateNew', 'Write', 'Read', $true)
foreach($f in $zip.GetFiles()) {
        $s = $zipCopy.AddFile($f.Name, $f.CompressionMethod, $f.DeflateOption)
        $ist = $f.GetStream('Open', 'Read')
        $ost = $s.GetStream('Open', 'Write')
        $buf = New-Object byte[] $f.UncompressedSize
        while(($n = $ist.Read($buf, 0, $buf.Length)) -gt 0) {
                $ost.Write($buf, 0, $n)
        }
        $ost.Dispose()
        $ist.Dispose()
}
$zipCopy.Dispose()
$zip.Dispose()

参考:ここまで内部に立ち入ってみた

一見更新できるんだけど、展開するとダメ。
バイナリーを確認すると、CentralDirectoryHeaderは更新されていて圧縮フォルダー上は期待した日付だけど、LocalFileHeaderの日付が更新した日付に更新されちゃってダメ。

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

namespace ZipPackageSample
{
    class ZipArchive : IDisposable
    {
        private static Type _type = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipArchive");
        private static MethodInfo _openOnFile = _type.GetMethod("OpenOnFile", BindingFlags.Static | BindingFlags.NonPublic);
        private static MethodInfo _openOnStream = _type.GetMethod("OpenOnStream", BindingFlags.Static | BindingFlags.NonPublic);

        public static ZipArchive OpenOnFile(string path, FileMode mode, FileAccess access, FileShare share, bool streaming)
        {
            return new ZipArchive { _zipArchive = _openOnFile.Invoke(null, new object[] { path, mode, access, share, streaming }) };
        }
        public static ZipArchive OpenOnStream(Stream stream, FileMode mode, FileAccess access, bool streaming)
        {
            return new ZipArchive { _zipArchive = _openOnStream.Invoke(null, new object[] { stream, mode, access, streaming }) };
        }

        private static Type _typeCme = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.CompressionMethodEnum");
        private static object _stored = _typeCme.GetField("Stored", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _deflated = _typeCme.GetField("Deflated", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static Type _typeDoe = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.DeflateOptionEnum");
        private static object _normal = _typeDoe.GetField("Normal", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _maximum = _typeDoe.GetField("Maximum", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _fast = _typeDoe.GetField("Fast", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _superFast = _typeDoe.GetField("SuperFast", BindingFlags.Static | BindingFlags.Public).GetValue(null);
        private static object _none = _typeDoe.GetField("None", BindingFlags.Static | BindingFlags.Public).GetValue(null);

        public static CompressionMethodEnum FromInternalCme(object cme)
        {
            CompressionMethodEnum ret = CompressionMethodEnum.Stored;
            if (_deflated.Equals(cme)) ret = CompressionMethodEnum.Deflated;
            return ret;
        }
        public static object ToInternalCme(CompressionMethodEnum cme)
        {
            object ret = _stored;
            if (cme == CompressionMethodEnum.Deflated) ret = _deflated;
            return ret;
        }
        public static DeflateOptionEnum FromInternalDoe(object doe)
        {
            DeflateOptionEnum ret = DeflateOptionEnum.None;
            if (_normal.Equals(doe))
            {
                ret = DeflateOptionEnum.Normal;
            }
            else if (_maximum.Equals(doe))
            {
                ret = DeflateOptionEnum.Maximum;
            }
            else if (_fast.Equals(doe))
            {
                ret = DeflateOptionEnum.Fast;
            }
            else if (_superFast.Equals(doe))
            {
                ret = DeflateOptionEnum.SuperFast;
            }
            return ret;
        }
        public static object ToInternalDoe(DeflateOptionEnum doe)
        {
            object ret = _none;
            if (doe == DeflateOptionEnum.Normal)
            {
                ret = _normal;
            }
            else if (doe == DeflateOptionEnum.Maximum)
            {
                ret = _maximum;
            }
            else if (doe == DeflateOptionEnum.Fast)
            {
                ret = _fast;
            }
            else if (doe == DeflateOptionEnum.SuperFast)
            {
                ret = _superFast;
            }
            return ret;
        }

        private object _zipArchive = null;
        private static MethodInfo _addFile = _type.GetMethod("AddFile", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _getFile = _type.GetMethod("GetFile", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _fileExists = _type.GetMethod("FileExists", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _deleteFile = _type.GetMethod("DeleteFile", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _getFiles = _type.GetMethod("GetFiles", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _flush = _type.GetMethod("Flush", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _close = _type.GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
        private static MethodInfo _dispose = _type.GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public);
        private static PropertyInfo _openAccess = _type.GetProperty("OpenAccess", BindingFlags.Instance | BindingFlags.NonPublic);
        private static PropertyInfo _zipFileInfoDictionary = _type.GetProperty("ZipFileInfoDictionary", BindingFlags.Instance | BindingFlags.NonPublic);

        public ZipFileInfo AddFile(string path, CompressionMethodEnum cme, DeflateOptionEnum doe)
        {
            return new ZipFileInfo(_addFile.Invoke(_zipArchive, new object[] { path, ToInternalCme(cme), ToInternalDoe(doe) }));
        }
        public ZipFileInfo GetFile(string path)
        {
            return new ZipFileInfo(_getFile.Invoke(_zipArchive, new object[] { path }));
        }
        public bool FileExists(string path)
        {
            return (bool)_fileExists.Invoke(_zipArchive, new object[] { path });
        }
        public void DeleteFile(string path)
        {
            _deleteFile.Invoke(_zipArchive, new object[] { path });
        }
        private static Type _typeZfic = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipFileInfoCollection");
        private static MethodInfo _getEnumerator = _typeZfic.GetMethod("System.Collections.IEnumerable.GetEnumerator", BindingFlags.Instance | BindingFlags.NonPublic);
        public IEnumerable<ZipFileInfo> GetFiles()
        {
            var zfic = _getEnumerator.Invoke(_getFiles.Invoke(_zipArchive, null), null) as System.Collections.IEnumerator;
            while (zfic.MoveNext())
            {
                yield return new ZipFileInfo(zfic.Current);
            }
        }
        public void Flush()
        {
            _flush.Invoke(_zipArchive, null);
        }
        public void Close()
        {
            _close.Invoke(_zipArchive, null);
        }
        public void Dispose()
        {
            _dispose.Invoke(_zipArchive, null);
        }
        public FileAccess OpenAccess
        {
            get { return (FileAccess)_openAccess.GetValue(_zipArchive, null); }
        }
        public System.Collections.IDictionary ZipFileInfoDictionary
        {
            get { return _zipFileInfoDictionary.GetValue(_zipArchive, null) as System.Collections.IDictionary; }
        }


        public class ZipFileInfo
        {
            private static Type _type = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipFileInfo");
            private static MethodInfo _getStream = _type.GetMethod("GetStream", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _name = _type.GetProperty("Name", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _zipArchive = _type.GetProperty("ZipArchive", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _compressionMethod = _type.GetProperty("CompressionMethod", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _lastModFileDateTime = _type.GetProperty("LastModFileDateTime", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _deflateOption = _type.GetProperty("DeflateOption", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _folderFlag = _type.GetProperty("FolderFlag", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _volumeLabelFlag = _type.GetProperty("VolumeLabelFlag", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _localFileBlock = _type.GetProperty("LocalFileBlock", BindingFlags.Instance | BindingFlags.NonPublic);
            private static Type _typeLB = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipIOLocalFileBlock");
            private static FieldInfo _localFileHeader = _typeLB.GetField("_localFileHeader", BindingFlags.Instance | BindingFlags.NonPublic);
            private static Type _typeL = typeof(System.IO.Packaging.Package).Assembly.GetType("MS.Internal.IO.Zip.ZipIOLocalFileHeader");
            private static PropertyInfo _lastMod = _typeL.GetProperty("LastModFileDateTime", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _compSize = _typeL.GetProperty("CompressedSize", BindingFlags.Instance | BindingFlags.NonPublic);
            private static PropertyInfo _uncompSize = _typeL.GetProperty("UncompressedSize", BindingFlags.Instance | BindingFlags.NonPublic);

            private object _zipFileInfo = null;
            private object _lfh = null;

            public ZipFileInfo(object zipFileInfo)
            {
                _zipFileInfo = zipFileInfo;
            }

            public Stream GetStream(FileMode mode, FileAccess access)
            {
                return _getStream.Invoke(_zipFileInfo, new object[] { mode, access }) as Stream;
            }

            public string Name
            {
                get { return _name.GetValue(_zipFileInfo, null) as string; }
            }
            public ZipArchive ZipArchive
            {
                get { return new ZipArchive { _zipArchive = _zipArchive.GetValue(_zipFileInfo, null) }; }
            }
            public CompressionMethodEnum CompressionMethod
            {
                get { return ZipArchive.FromInternalCme(_compressionMethod.GetValue(_zipFileInfo, null)); }
            }
            public DateTime LastModFileDateTime
            {
                get { return (DateTime)_lastModFileDateTime.GetValue(_zipFileInfo, null); }
                set
                {
                    if (_lfh == null)
                    {
                        var lfb = _localFileBlock.GetValue(_zipFileInfo, null);
                        _lfh = _localFileHeader.GetValue(lfb);
                    }
                    uint date = (((uint)value.Year - 1980 << 9) | ((uint)value.Month << 5) | (uint)value.Day);
                    uint time = (((uint)value.Hour << 11) | ((uint)value.Minute << 5) | ((uint)value.Second / 2));
                    _lastMod.SetValue(_lfh, date << 16 | time, null);
                }
            }
            public DeflateOptionEnum DeflateOption
            {
                get { return ZipArchive.FromInternalDoe(_deflateOption.GetValue(_zipFileInfo, null)); }
            }
            public bool FolderFlag
            {
                get { return (bool)_folderFlag.GetValue(_zipFileInfo, null); }
            }
            public bool VolumeLabelFlag
            {
                get { return (bool)_volumeLabelFlag.GetValue(_zipFileInfo, null); }
            }
            public long CompressedSize
            {
                get
                {
                    if (_lfh == null)
                    {
                        var lfb = _localFileBlock.GetValue(_zipFileInfo, null);
                        _lfh = _localFileHeader.GetValue(lfb);
                    }
                    return (long)_compSize.GetValue(_lfh, null);
                }
            }
            public long UncompressedSize
            {
                get
                {
                    if (_lfh == null)
                    {
                        var lfb = _localFileBlock.GetValue(_zipFileInfo, null);
                        _lfh = _localFileHeader.GetValue(lfb);
                    }
                    return (long)_uncompSize.GetValue(_lfh, null);
                }
            }
        }


        public enum CompressionMethodEnum
        {
            Stored,
            Deflated
        }
        public enum DeflateOptionEnum
        {
            Normal,
            Maximum,
            Fast,
            SuperFast,
            None
        }
    }
}