【问题标题】:Use PowerShell to wrap an existing COM object使用 PowerShell 包装现有的 COM 对象
【发布时间】:2013-12-13 10:09:31
【问题描述】:

使用 PowerShell 和 System.DirectoryServices,我得到了一个如下所示的对象:

   TypeName: System.__ComObject

Name                      MemberType Definition
----                      ---------- ----------
CreateObjRef              Method     System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Equals                    Method     bool Equals(System.Object obj)
GetHashCode               Method     int GetHashCode()
GetLifetimeService        Method     System.Object GetLifetimeService()
GetType                   Method     type GetType()
InitializeLifetimeService Method     System.Object InitializeLifetimeService()
ToString                  Method     string ToString()

我能找到的所有示例代码都涉及从 PowerShell 创建新的 COM 对象,而不是包装已返回的现有对象。我怎样才能有效地处理这个对象(枚举和使用实际的属性和方法)?

注意:这个对象实际上确实有一个类型库(“ActiveDs”),但由于某种原因,我无法直接使用它,作为一个不同的问题(Loading a Type Library via PowerShell and scripting Windows Live Writer)建议应该是这样。

这是一个单行代码,展示了如何获取这样的对象:

((new-object DirectoryServices.DirectoryEntry -a '
LDAP://somedc').Properties.GetEnumerator() |?{$_.PropertyName -eq 'usnChanged' }).Value[0] | Get-Member

【问题讨论】:

  • 有专门设计用于活动目录的 cmdlet。 technet.microsoft.com/en-us/library/ee617195.aspx 如果您使用这些,可能会让您的生活更轻松。
  • 能否请您提供一个代码示例,返回您遇到问题的特定对象
  • 很遗憾我无法安装任何新模块;否则我肯定会使用它。
  • 我已经添加了一个代码示例。
  • 谢谢你,现在我明白了这个问题。比尔的回答应该对你有用,我也想提供这个:stackoverflow.com/a/13475504/284111 至于为什么你不应该依赖 ActiveDs 的解释。此问题并非特定于 powershell。这只是 tlb/interop 的不足。解决方法如所述。

标签: powershell com


【解决方案1】:

PowerShell 反射不能正确“看到”这些对象的属性和方法。为了获得属性和方法,我使用了一些包装函数。这是一个例子:

function Get-Property {
  param(
    [__ComObject] $object,
    [String] $propertyName
  )
  $object.GetType().InvokeMember($propertyName,"GetProperty",$NULL,$object,$NULL)
}

function Set-Property {
  param(
    [__ComObject] $object,
    [String] $propertyName,
    $propertyValue
  )
  [Void] $object.GetType().InvokeMember($propertyName,"SetProperty",$NULL,$object,$propertyValue)
}

function Invoke-Method {
  param(
    [__ComObject] $object,
    [String] $methodName,
    $methodParameters
  )
  $output = $object.GetType().InvokeMember($methodName,"InvokeMethod",$NULL,$object,$methodParameters)
  if ( $output ) { $output }
}

$ADS_ESCAPEDMODE_ON = 2      # see ADS_ESCAPE_MODE_ENUM
$ADS_SETTYPE_DN = 4          # see ADS_SETTYPE_ENUM
$ADS_FORMAT_X500_PARENT = 8  # see ADS_FORMAT_ENUM

$Pathname = New-Object -ComObject "Pathname"
# store initial EscapedMode
$escapedMode = Get-Property $PathName "EscapedMode"
# Enable all escaping
Set-Property $PathName "EscapedMode" @($ADS_ESCAPEDMODE_ON)
Invoke-Method $Pathname "Set" @("CN=Ken Dyer,OU=H/R,DC=fabrikam,DC=com",$ADS_SETTYPE_DN)
Invoke-Method $Pathname "Retrieve" @($ADS_FORMAT_X500_PARENT)
# outputs 'OU=H\/R,DC=fabrikam,DC=com'
$escapedMode = Set-Property $PathName "EscapedMode" @($escapedMode)
# set EscapedMode property back to initial value

请注意,Set-Property 和 Invoke-Method 使用数组作为它们的最终参数,因此我在调用这些函数时使用 @( )

【讨论】:

  • 我已经在使用 InvokeMember,但它很难看。实际上有一个 TLB,但出于某种原因,PS 似乎忽略了它。有没有办法列出可用的“真实”属性和方法、获取真实类型名称或加载正确的 TLB?
【解决方案2】:

与比尔·斯图尔特的方法略有不同:

这个想法是通常您不需要/不想创建 ComObject 的多个实例:

Function Invoke-ComObject([Parameter(Mandatory = $true)]$ComObject, [Switch]$Method, [Parameter(Mandatory = $true)][String]$Property, $Value) {
    If ($ComObject -IsNot "__ComObject") {
        If (!$ComInvoke) {$Global:ComInvoke = @{}}
        If (!$ComInvoke.$ComObject) {$ComInvoke.$ComObject = New-Object -ComObject $ComObject}
        $ComObject = $ComInvoke.$ComObject
    }
    If ($Method) {$Invoke = "InvokeMethod"} ElseIf ($MyInvocation.BoundParameters.ContainsKey("Value")) {$Invoke = "SetProperty"} Else {$Invoke = "GetProperty"}
    [__ComObject].InvokeMember($Property, $Invoke, $Null, $ComObject, $Value)
}; Set-Alias ComInvoke Invoke-ComObject

如果涉及方法,则需要添加–Method开关,如果是属性,cmdlet会根据是否提供值自动判断是否需要获取或设置该属性。 使用此 cmdlet,您不需要先创建 ComObject 并检索例如在一个简单的 oneliner 中从 ADSystemInfo 获取 ComputerName (DN):

ComInvoke ADSystemInfo ComputerName

PathName做同样的事情:

$EscapedMode = ComInvoke PathName EscapedMode
ComInvoke PathName EscapedMode @($ADS_ESCAPEDMODE_ON)
ComInvoke Pathname -Method Set @("CN=Ken Dyer,OU=H/R,DC=fabrikam,DC=com", $ADS_SETTYPE_DN)
ComInvoke Pathname -Method Retrieve @($ADS_FORMAT_X500_PARENT)
ComInvoke PathName EscapedMode @($EscapedMode)

姓名NameTranslate 示例:

ComInvoke -Method NameTranslate Init @(1, "domain.com")
ComInvoke -Method NameTranslate Set @(8, "User001")
ComInvoke -Method NameTranslate Get @(1)

或者,如果您确实想要拥有多个实例,您可以先创建 ComObject 实例,然后将其提供给 ComInvoke 函数:

$NameTranslate = New-Object -ComObject NameTranslate
ComInvoke -Method $NameTranslate Init @(1, "domain.com")
ComInvoke -Method $NameTranslate Set @(8, "User001")
ComInvoke -Method $NameTranslate Get @(1)

最新的Invoke-ComObject版本,见:https://powersnippets.com/invoke-comobject/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 2019-10-19
    • 1970-01-01
    • 2017-06-16
    • 1970-01-01
    相关资源
    最近更新 更多