Using PowerShell and System.DirectoryServices
, I've been given an object that looks like this:
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()
All example code that I can find deals with creating new COM objects from PowerShell, not wrapping existing objects that have been returned. How can I usefully deal with this object (enumerate and use the actual properties and methods)?
Note: this object actually does have a type library ("ActiveDs"), but for some reason I am unable to use it out of the box, as a different question (Loading a Type Library via PowerShell and scripting Windows Live Writer) suggests should be the case.
Here is a one-liner showing how to get such an object:
((new-object DirectoryServices.DirectoryEntry -a '
LDAP://somedc').Properties.GetEnumerator() |?{$_.PropertyName -eq 'usnChanged' }).Value[0] | Get-Member
PowerShell reflection doesn't properly "see" these objects' properties and methods. To get to the properties and methods, I use some wrapper functions. Here is an example:
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
Note that the Set-Property and Invoke-Method use an array as their final parameter, so I use @( ) when calling those functions.
Just a little different approach then Bill Stewart’s:
The idea is that usually you do not need/want to create multiple instances of the 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
If it concerns a method, you need to add the –Method
switch, in the case of a property, the cmdlet will automatically determine whether the property need to be get or set depending on whether a value is supplied.
With this cmdlet you do not require the to create the ComObject first and retrieve e.g. to get the ComputerName
(DN) from ADSystemInfo
in a simple oneliner:
ComInvoke ADSystemInfo ComputerName
To do a the same with the 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)
A name NameTranslate
example:
ComInvoke -Method NameTranslate Init @(1, "domain.com")
ComInvoke -Method NameTranslate Set @(8, "User001")
ComInvoke -Method NameTranslate Get @(1)
Or if you do want to have multiple instances you can first create the ComObject instance and then supply it to the ComInvoke
function:
$NameTranslate = New-Object -ComObject NameTranslate
ComInvoke -Method $NameTranslate Init @(1, "domain.com")
ComInvoke -Method $NameTranslate Set @(8, "User001")
ComInvoke -Method $NameTranslate Get @(1)
For the latest Invoke-ComObject
version, see: https://powersnippets.com/invoke-comobject/