Search code examples
powershellreflectionpowershell-5.0

Using Reflection within Powershell Class


Good Evening, I am Testing out Powershell Classes in V5 and I am unable to use reflection within a Powershell class. Take the below example:

class PSHello{
    [void] Zip(){
        Add-Type -Assembly "System.IO.Compression.FileSystem"
        $includeBaseDirectory = $false
        $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
        [System.IO.Compression.ZipFile]::CreateFromDirectory('C:\test', 'c:\test.zip',$compressionLevel ,$includeBaseDirectory)
    }
}
$f = [PSHello]::new()
$f.Zip()

As we can see, i am loading the Assembly and then Using Reflection to Create a zip of a directory. However when this is run i recieve the error of

Unable to find type [System.IO.Compression.ZipFile].
+ CategoryInfo          : ParserError: (:) [],        ParentContainsErrorRecordException
+ FullyQualifiedErrorId : TypeNotFound

Now if i run the same contents of my Zip Method outside of the class it works. So why cannot Reflection be used like this inside of a class?


Solution

  • IIRC class methods are precompiled so late binding doesn't work using [type] syntax. I guess we'll need to invoke ZipFile's method manually:

    class foo {
    
        static hidden [Reflection.Assembly]$FS
        static hidden [Reflection.TypeInfo]$ZipFile
        static hidden [Reflection.MethodInfo]$CreateFromDirectory
    
        [void] Zip() {
            if (![foo]::FS) {
                $assemblyName = 'System.IO.Compression.FileSystem'
                [foo]::FS = [Reflection.Assembly]::LoadWithPartialName($assemblyName)
                [foo]::ZipFile = [foo]::FS.GetType('System.IO.Compression.ZipFile')
                [foo]::CreateFromDirectory = [foo]::ZipFile.GetMethod('CreateFromDirectory',
                    [type[]]([string], [string], [IO.Compression.CompressionLevel], [bool]))
            }
            $includeBaseDirectory = $false
            $compressionLevel = [IO.Compression.CompressionLevel]::Optimal
            [foo]::CreateFromDirectory.Invoke([foo]::ZipFile,
                @('c:\test', 'c:\test.zip', $compressionLevel, $includeBaseDirectory))
        }
    
    }
    

    $f = [foo]::new()
    $f.Zip()