我想从PowerShell枚举当前进程中的所有AppDomains。该过程恰好是Visual Studio,它托管StudioShell。要做到这一点,我需要实例化corRuntimHost,它是mscoree.tlb的一部分,所以我可以调整this C# code ..
我试图获取CorRunTimeHost的正确名称并将其传递给New-Object -COMObject
"objectName"。基于this forum posting,我搜索了注册表,我认为正确的名称是 CLRMetaData.CorRuntimeHost 。但是,虽然New-Object -ComObject 'CLRMetaData.CorRuntimeHost' -Strict
确实返回了一个对象,但它只暴露了COM对象固有的方法。
基于this stackoverflow question,我尝试了[Activator]::CreateInstance()。但是,以下两个语句给出了与New-Object相同的问题,即我无法调用ICorRuntimeHost::EnumDomains()方法。
$corRuntimeHost = [Activator]::CreateInstance([Type]::GetTypeFromProgID('CLRMetaData.CorRuntimeHost'));
$enumerator = $null;
$corRuntimeHost.EnumDomains([ref]$enumerator);
Method invocation failed because [System.__ComObject] doesn't contain a method named 'EnumDomains'.
At line:1 char:1
+ $corRuntimeHost.EnumDomains([ref]$enumerator)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
答案 0 :(得分:2)
为了让它在PowerShell 3.0中运行,我最终不得不使用AssemblyBuilder。以下是工作代码:
问题似乎是.NET 4.0中没有mscoree.CorRuntimeHostClass的公共构造函数,但是在3.5中。
我后来在带有PowerShell 2.0的Windows 7 VM上对此进行了测试,现在这段代码可以在PowerShell 2.0和3.0中使用。
$tlbName = Split-Path -Parent ([AppDomain]::CurrentDomain.GetAssemblies() | Where { $_.Location -Match '\\mscorlib.dll$' }).Location
$tlbName = Join-Path $tlbName 'mscoree.tlb';
$csharpString = @"
//adapted from here http://blog.semanticsworks.com/2008/04/enumerating-appdomains.html
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
public class ListProcessAppDomains
{
[DllImport( `"oleaut32.dll`", CharSet = CharSet.Unicode, PreserveSig = false )]
private static extern void LoadTypeLibEx
(String strTypeLibName, RegKind regKind,
[MarshalAs( UnmanagedType.Interface )] out Object typeLib);
private enum RegKind
{
Default = 0,
Register = 1,
None = 2
}
private class ConversionEventHandler : ITypeLibImporterNotifySink
{
public void ReportEvent( ImporterEventKind eventKind, int eventCode, string eventMsg )
{
Console.Error.WriteLine("Kind: {0} Code: {1} Message");
}
public Assembly ResolveRef( object typeLib )
{
string stackTrace = System.Environment.StackTrace;
Console.WriteLine("ResolveRef ({0})", typeLib);
Console.WriteLine(stackTrace);
return null;
}
}
public static AssemblyBuilder LoadMsCoreeDll( ref Object typeLib ) {
ConversionEventHandler eventHandler = new ConversionEventHandler();
string assemblyName = "PoshComWrapper.dll";
LoadTypeLibEx( @"$($tlbName)", RegKind.None, out typeLib );
TypeLibConverter typeLibConverter = new TypeLibConverter();
return typeLibConverter.ConvertTypeLibToAssembly( typeLib, assemblyName, 0, eventHandler, null, null, null, null );
}
}
"@
# So we can run this scipt multiple times
try { [ListProcessAppDomains] } catch { Add-Type -TypeDefinition $csharpString }
function Get-AppDomain {
$typeLib = $null;
$assemblyBuilder = [ListProcessAppDomains]::LoadMsCoreeDll([ref] $typeLib)
$corRuntimeHostClass = $assemblyBuilder.CreateInstance('PoshComWrapper.CorRuntimeHostClass')
$enumHandle = [IntPtr]::Zero
$corRuntimeHostClass.EnumDomains([ref] $enumHandle);
$appDomain = $null;
do
{
$corRuntimeHostClass.NextDomain($enumHandle, [ref] $appDomain);
if ($appDomain -ne $null -and $appDomain.GetType() -eq [AppDomain]) { $appDomain; }
} while ($appDomain -ne $null)
}
Get-AppDomain