How can I tell if a type created with Add-Type is loaded?

by willsteele at 2012-08-22 19:17:36

I am playing around with some C#/Add-Type code to explore P/Invoke and Win32 topics. In another thread (http://powershell.org/discuss/viewtopic.php?t=86&p=329#p329) I was using Add-Type to create a new class. Below is the snippet I am using to generate the new type:

Clear-Host;
$signature_Win32_GetForegroundWindow = @"
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
"@
$Win32API = Add-Type -MemberDefinition $signature_Win32_GetForegroundWindow <br> -Namespace Windows
-Name Win32 `
-Language CSharp


If I have already run this snippet and the type is added, I cannot re-add since the AppDomain recognizes the type as already being loaded. How would I add some checking to see if the type exists in a process before running the script? I wrote a function to check to see if a type was loaded a few weeks ago (http://learningpcs.blogspot.com/2012/06/powershell-v2-test-if-assembly-is.html) but I don’t see how it can identify types in the appdomain added via Add-Type. Also, is it possible to reload (or override) a type definition created with Add-Type? Let’s say I am testing a class, and, I need to update it after a tweak. I normally just start a new instance of PowerShell and start from scratch.
by DougFinke at 2012-08-22 19:53:58
Hey Will,

.NET has a limitation when loading DLLs etc, that’s why you need to start PowerShell from scratch. That’s the best way. You could experiment with creating another AppDomain and work out the plumbing to load and unload DLLs etc. I have not gone done that path.

So what you’d like here is to determine if the GetForegroundWindow method already exists in the PowerShell session?

Doug
by willsteele at 2012-08-22 20:03:19
Partly…this function was just an experiment off another thread where I was trying to figure out a way to enable/disable AlwaysOnTop for a process. In another project I am working on I am going to be doing a lot of these P/Invoke -Add-Type patterns. I need to check and see if the types I want to add are already in the appdomain (or the session…not sure if those are synonymous objects from a PS perspective). So, if I run the function to add the type, if it’s already in the session, just ignore the request. This would be inside a function and call down into an if block. If the type exists in the appdomain, skip the load and report it’s already there, otherwise, add the new type. Just some basic sanity checking to avoid trying to add something that already exists.
by MattG at 2012-08-23 05:40:10
There doesn’t seem to be a definitive way to determine if a type was loaded with Add-Type (that I’m aware of). However, two obvious indicators would be [Windows.Win32].Assembly.FullName and [Windows.Win32].Module.FullyQualifiedName. The name of the assembly will be a random 8 character string and the module’s FullyQualifiedName will be ‘<Unknown>’.

Also, if you wanted an easy way to test to see if a module was loaded, just put the type in a try/catch block:
[script=powershell]$Loaded = $True

try {[Windows.NotLoadedModule]} catch { $Loaded = $False }[/script]
by MattG at 2012-08-23 05:54:57
It’s also worth noting that an assembly loaded via Add-Type will not be loaded from a file on disk nor will it be registered in the GAC (obviously). As an example, here is what your [Windows.Win32] type will look like when listing the AppDomain’s loaded assemblies:

[script=powershell]PS C:&gt; [AppDomain]::CurrentDomain.GetAssemblies()

GAC Version Location
— ------- --------
True v4.0.30319 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\Microsoft.PowerShell.ConsoleHost\1.0.0.0__31bf3856ad364e35\Microsoft.PowerShell.ConsoleHost.dll
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\Microsoft.PowerShell.Commands.Diagnostics\1.0.0.0__31bf3856ad364e35\Microsoft.PowerShell.Commands.Diagnostics.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration.Install\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.Install.dll
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\Microsoft.WSMan.Management\1.0.0.0__31bf3856ad364e35\Microsoft.WSMan.Management.dll
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\Microsoft.WSMan.Runtime\1.0.0.0__31bf3856ad364e35\Microsoft.WSMan.Runtime.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_64\System.Transactions\v4.0_4.0.0.0__b77a5c561934e089\System.Transactions.dll
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\Microsoft.PowerShell.Commands.Utility\1.0.0.0__31bf3856ad364e35\Microsoft.PowerShell.Commands.Utility.dll
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\Microsoft.PowerShell.Commands.Management\1.0.0.0__31bf3856ad364e35\Microsoft.PowerShell.Commands.Management.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Management\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Management.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceProcess\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.ServiceProcess.dll
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\Microsoft.PowerShell.Security\1.0.0.0__31bf3856ad364e35\Microsoft.PowerShell.Security.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.DirectoryServices\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.DirectoryServices.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.JScript\v4.0_10.0.0.0__b03f5f7f11d50a3a\Microsoft.JScript.dll
False v4.0.30319[/script]