none
PowerShell GUIs - Active Directory, Directory Object Picker?

Answers

  • it's not exactly what i was looking for but it's working as needed:

    http://thepip3r.blogspot.com/2011/06/powershell-guis-active-directory.html

    • Marked as answer by thepip3r Thursday, June 02, 2011 6:46 PM
    Thursday, June 02, 2011 6:45 PM
  • I haven't had much free time to work on this, but I'm glad you found a workaround. Here's the beginnings of a script named Show-DsObjectPicker.ps1 that displays a down-level DsObjectPicker window for either the current host or the host passed to the -computername parameter. It demonstrates several key bits of PowerShell functionality and lots of silly workarounds for PowerShell behavior that's either unforgiving or something I don't quite grok. ;-) This should really go into an snap-in (maybe PSCX) as a full-featured cmdlet written in C#.

    # Show-DsObjectPicker.ps1
    
    param(
      [string]
      $ComputerName
    )
    
    add-type -typedefinition @"
      using System;
      using System.Runtime.InteropServices;
      using System.Runtime.InteropServices.ComTypes;
    
      public enum DsScope : uint
      {
        DSOP_SCOPE_TYPE_TARGET_COMPUTER = 0x00000001,
        DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN = 0x00000002,
        DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN = 0x00000004,
        DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN = 0x00000008,
        DSOP_SCOPE_TYPE_GLOBAL_CATALOG = 0x00000010,
        DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN = 0x00000020,
        DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN = 0x00000040,
        DSOP_SCOPE_TYPE_WORKGROUP = 0x00000080,
        DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE = 0x00000100,
        DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE = 0x00000200
      };
    
      public enum DsScopeInitInfo : uint
      {
        DSOP_SCOPE_FLAG_STARTING_SCOPE = 0x00000001,
        DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT = 0x00000002,
        DSOP_SCOPE_FLAG_WANT_PROVIDER_LDAP = 0x00000004,
        DSOP_SCOPE_FLAG_WANT_PROVIDER_GC = 0x00000008,
        DSOP_SCOPE_FLAG_WANT_SID_PATH = 0x00000010,
        DSOP_SCOPE_FLAG_WANT_DOWNLEVEL_BUILTIN_PATH = 0x00000020,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS = 0x00000040,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS = 0x00000080,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_COMPUTERS = 0x00000100,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_CONTACTS = 0x00000200,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_SERVICE_ACCOUNTS = 0x00000400
      };
    
      public enum DsFilter : uint
      {
        DSOP_FILTER_INCLUDE_ADVANCED_VIEW = 0x00000001,
        DSOP_FILTER_USERS = 0x00000002,
        DSOP_FILTER_BUILTIN_GROUPS = 0x00000004,
        DSOP_FILTER_WELL_KNOWN_PRINCIPALS = 0x00000008,
        DSOP_FILTER_UNIVERSAL_GROUPS_DL = 0x00000010,
        DSOP_FILTER_UNIVERSAL_GROUPS_SE = 0x00000020,
        DSOP_FILTER_GLOBAL_GROUPS_DL = 0x00000040,
        DSOP_FILTER_GLOBAL_GROUPS_SE = 0x00000080,
        DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL = 0x00000100,
        DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE = 0x00000200,
        DSOP_FILTER_CONTACTS = 0x00000400,
        DSOP_FILTER_COMPUTERS = 0x00000800,
        DSOP_FILTER_SERVICE_ACCOUNTS = 0x00001000
      };
    
      public enum DsDownlevelFilter : uint
      {
        DSOP_DOWNLEVEL_FILTER_USERS = 0x80000001,
        DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS = 0x80000002,
        DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS = 0x80000004,
        DSOP_DOWNLEVEL_FILTER_COMPUTERS = 0x80000008,
        DSOP_DOWNLEVEL_FILTER_WORLD = 0x80000010,
        DSOP_DOWNLEVEL_FILTER_AUTHENTICATED_USER = 0x80000020,
        DSOP_DOWNLEVEL_FILTER_ANONYMOUS = 0x80000040,
        DSOP_DOWNLEVEL_FILTER_BATCH = 0x80000080,
        DSOP_DOWNLEVEL_FILTER_CREATOR_OWNER = 0x80000100,
        DSOP_DOWNLEVEL_FILTER_CREATOR_GROUP = 0x80000200,
        DSOP_DOWNLEVEL_FILTER_DIALUP = 0x80000400,
        DSOP_DOWNLEVEL_FILTER_INTERACTIVE = 0x80000800,
        DSOP_DOWNLEVEL_FILTER_NETWORK = 0x80001000,
        DSOP_DOWNLEVEL_FILTER_SERVICE = 0x80002000,
        DSOP_DOWNLEVEL_FILTER_SYSTEM = 0x80004000,
        DSOP_DOWNLEVEL_FILTER_EXCLUDE_BUILTIN_GROUPS = 0x80008000,
        DSOP_DOWNLEVEL_FILTER_TERMINAL_SERVER = 0x80010000,
        DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS = 0x80020000,
        DSOP_DOWNLEVEL_FILTER_LOCAL_SERVICE = 0x80040000,
        DSOP_DOWNLEVEL_FILTER_NETWORK_SERVICE = 0x80080000,
        DSOP_DOWNLEVEL_FILTER_REMOTE_LOGON = 0x80100000,
        DSOP_DOWNLEVEL_FILTER_INTERNET_USER = 0x80200000,
        DSOP_DOWNLEVEL_FILTER_OWNER_RIGHTS = 0x80400000,
        DSOP_DOWNLEVEL_FILTER_SERVICES = 0x80800000,
        DSOP_DOWNLEVEL_FILTER_LOCAL_LOGON = 0x81000000,
        DSOP_DOWNLEVEL_FILTER_THIS_ORG_CERT = 0x82000000,
        DSOP_DOWNLEVEL_FILTER_IIS_APP_POOL = 0x84000000
      };
    
      public enum DsInitInfo : uint
      {
        DSOP_FLAG_MULTISELECT = 0x00000001,
        DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK = 0x00000002
      };
    
      [StructLayout(LayoutKind.Sequential)]
      public struct DSOP_UPLEVEL_FILTER_FLAGS
      {
        //public DsFilter flBothModes;
        //public DsFilter flMixedModeOnly;
        //public DsFilter flNativeModeOnly;
        public uint flBothModes;
        public uint flMixedModeOnly;
        public uint flNativeModeOnly;
      }
    
      [StructLayout(LayoutKind.Sequential)]
      public struct DSOP_FILTER_FLAGS
      {
        public DSOP_UPLEVEL_FILTER_FLAGS Uplevel;
        //public DsDownlevelFilter flDownlevel;
        public uint flDownlevel;
      }
    
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
      public struct DSOP_SCOPE_INIT_INFO
      {
        public uint cbSize;
        //public DsScope flType;
        public uint flType;
        //public DsScopeInitInfo flScope;
        public uint flScope;
        public DSOP_FILTER_FLAGS FilterFlags;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzDcName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzADsPath;
        public uint hr;
      }
    
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
      public struct DSOP_INIT_INFO
      {
        public uint cbSize;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzTargetComputer;
        public uint cDsScopeInfos;
        public IntPtr aDsScopeInfos;
        //public DsInitInfo flOptions;
        public uint flOptions;
        public uint cAttributesToFetch;
        public IntPtr apwzAttributeNames;
      };
    
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
      public struct DS_SELECTION
      {
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzADsPath;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzClass;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzUPN;
        public IntPtr pvarFetchedAttributes;
        public uint flScopeType;
      };
    
      [StructLayout(LayoutKind.Sequential)]
      public struct DS_SELECTION_LIST
      {
        public uint cItems;
        public uint cFetchedAttributes;
        //public IntPtr aDsSelection;
      };
    
      [Guid("0c87e64e-3b7a-11d2-b9e0-00c04fd8dbf7"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      public interface IDsObjectPicker
      {
        void Initialize(
          [In] ref DSOP_INIT_INFO pInitInfo);
    
        void InvokeDialog(
          [In] IntPtr hwndParent,
          [Out, MarshalAs(UnmanagedType.Interface)] out object ppdoSelections);
      }
    
      [Guid("e2d3ec9b-d041-445a-8f16-4748de8fb1cf"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      public interface IDsObjectPickerCredentials
      {
        void SetCredentials(
          [In, MarshalAs(UnmanagedType.LPWStr)] string szUserName,
          [In, MarshalAs(UnmanagedType.LPWStr)] string szPassword);
      }
    
      [ComImport, Guid("17d6ccd8-3b7b-11d2-b9e0-00c04fd8dbf7")]
      public class __DsObjectPicker
      {
      }
    
      public class DsObjectPicker
      {
        private __DsObjectPicker p;
    
        public static string CFSTR_DSOP_DS_SELECTION_LIST = "CFSTR_DSOP_DS_SELECTION_LIST";
    
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr GlobalLock([In] IntPtr handle);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern uint GlobalUnlock([In] IntPtr handle);
    
        [DllImport("ole32.dll")]
        public static extern void ReleaseStgMedium([In] ref STGMEDIUM pmedium);
        
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern uint RegisterClipboardFormat(string lpszFormat);
    
        public DsObjectPicker()
        {
          p = new __DsObjectPicker();
        }
    
        public void Initialize(ref DSOP_INIT_INFO pInitInfo)
        {
          IDsObjectPicker i = p as IDsObjectPicker;
          i.Initialize(ref pInitInfo);
        }
    
        public DataObject InvokeDialog(IntPtr hwndParent)
        {
          object pdoSelections;
          IDsObjectPicker i = p as IDsObjectPicker;
          i.InvokeDialog(hwndParent, out pdoSelections);
          return new DataObject(pdoSelections as IDataObject);
        }
    
        public void SetCredentials(string szUserName, string szPassword)
        {
          IDsObjectPickerCredentials i = p as IDsObjectPickerCredentials;
          i.SetCredentials(szUserName, szPassword);
        }
      }
      
      public class DataObject
      {
        private IDataObject p;
        
        public DataObject(IDataObject i)
        {
          p = i;
        }
        
        public void GetData(ref FORMATETC format, out STGMEDIUM medium)
        {
          p.GetData(ref format, out medium);
        }
      }
    "@
    
    $aDsScopeInfos = @()
    
    $DsScopeInfos = new-object DSOP_SCOPE_INIT_INFO
    $DsScopeInfos.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf([DSOP_SCOPE_INIT_INFO])
    $DsScopeInfos.flType = [DsScope]::DSOP_SCOPE_TYPE_TARGET_COMPUTER
    $DsScopeInfosFilterFlags = new-object DSOP_FILTER_FLAGS
    $DsScopeInfosFilterFlags.flDownLevel = [DsDownlevelFilter]::DSOP_DOWNLEVEL_FILTER_USERS
    $DsScopeInfos.FilterFlags = $DsScopeInfosFilterFlags
    $DsScopeInfos.hr = 0
    
    $aDsScopeInfos += $DsScopeInfos
    
    $aDsScopeInfosPtr =
      [System.Runtime.InteropServices.Marshal]::AllocCoTaskMem(
        $aDsScopeInfos.Length * [System.Runtime.InteropServices.Marshal]::SizeOf([DSOP_SCOPE_INIT_INFO]))
    $aDsScopeInfosPtrTmp = $aDsScopeInfosPtr
    
    foreach ($DsScopeInfo in $aDsScopeInfos)
    {
      [System.Runtime.InteropServices.Marshal]::StructureToPtr($DsScopeInfo, $aDsScopeInfosPtrTmp, $false)
      $aDsScopeInfosPtrTmp = [IntPtr] ($aDsScopeInfosPtrTmp.ToInt64() +
        [System.Runtime.InteropServices.Marshal]::SizeOf([DSOP_SCOPE_INIT_INFO]))
    }
    
    $DsInitInfo = new-object DSOP_INIT_INFO
    $DsInitInfo.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf([DSOP_INIT_INFO])
    $DsInitInfo.pwzTargetComputer = $ComputerName
    $DsInitInfo.cDsScopeInfos = $aDsScopeInfos.Length
    $DsInitInfo.aDsScopeInfos = $aDsScopeInfosPtr
    $DsInitInfo.flOptions = [DsInitInfo]::DSOP_FLAG_MULTISELECT
    
    $DsObjectPicker = new-object DsObjectPicker
    $DsObjectPicker.Initialize([ref] $DsInitInfo)
    $DataObject = $DsObjectPicker.InvokeDialog((get-process -id $pid).MainWindowHandle)
    
    if (-not ($DataObject -eq $null))
    {
      $medium = new-object System.Runtime.InteropServices.ComTypes.STGMEDIUM
      $format = new-object System.Runtime.InteropServices.ComTypes.FORMATETC
      
      $format.cfFormat =
        [Int16]::Parse([DsObjectPicker]::RegisterClipboardFormat([DsObjectPicker]::CFSTR_DSOP_DS_SELECTION_LIST).ToString("X4"),
          [System.Globalization.NumberStyles]::HexNumber)
      $format.dwAspect = [System.Runtime.InteropServices.ComTypes.DVASPECT]::DVASPECT_CONTENT
      $format.lindex = -1
      $format.tymed = [System.Runtime.InteropServices.ComTypes.TYMED]::TYMED_HGLOBAL
      
      $DataObject.GetData([ref] $format, [ref] $medium)
      
      try
      {
        $DsSelectionListPtr = [DsObjectPicker]::GlobalLock($medium.unionmember)
        
        try
        {
          $DsSelectionList =
            [DS_SELECTION_LIST] [System.Runtime.InteropServices.Marshal]::PtrToStructure($DsSelectionListPtr, [DS_SELECTION_LIST])
          $DsSelectionPtr = [IntPtr] ($DsSelectionListPtr.ToInt64() + [System.Runtime.InteropServices.Marshal]::SizeOf([DS_SELECTION_LIST]))
    
          for ($i = 0; $i -lt $DsSelectionList.cItems; $i++)
          {
            $DsSelection = new-object DS_SELECTION
            $DsSelection = [DS_SELECTION] [System.Runtime.InteropServices.Marshal]::PtrToStructure($DsSelectionPtr, [DS_SELECTION])
            new-object System.DirectoryServices.DirectoryEntry($DsSelection.pwzADsPath)
            $DsSelectionPtr = [IntPtr] ($DsSelectionPtr.ToInt64() + [System.Runtime.InteropServices.Marshal]::SizeOf([DS_SELECTION]))
          }
        }
        finally
        {
          [DsObjectPicker]::GlobalUnlock($medium.unionmember) | out-null
        }
      }
      finally
      {
        [DsObjectPicker]::ReleaseStgMedium([ref] $medium)
      }
    }
    
    [System.Runtime.InteropServices.Marshal]::FreeCoTaskMem($aDsScopeInfosPtr)
    
    

    Trev

    • Proposed as answer by Trevor Scroggins Wednesday, June 08, 2011 6:55 AM
    • Marked as answer by thepip3r Thursday, July 14, 2011 11:12 AM
    Wednesday, June 08, 2011 6:45 AM

All replies

  • It's possible but not as straightforward as using predefined .NET classes. The DsObjectPicker COM class is not automation compatible and will require a wrapper to make it accessible from PowerShell. I posted a Visual Basic wrapper to microsoft.public.adsi.general around 16 September 2002, but Google doesn't have binaries in their Usenet archive. I still have it here somewhere, and it should work from PowerShell, VBScript, or any other automation client. I can post it somewhere if you want to play with it while I look at a C# solution.
    Sunday, May 29, 2011 10:18 AM
  • it's not exactly what i was looking for but it's working as needed:

    http://thepip3r.blogspot.com/2011/06/powershell-guis-active-directory.html

    • Marked as answer by thepip3r Thursday, June 02, 2011 6:46 PM
    Thursday, June 02, 2011 6:45 PM
  • I haven't had much free time to work on this, but I'm glad you found a workaround. Here's the beginnings of a script named Show-DsObjectPicker.ps1 that displays a down-level DsObjectPicker window for either the current host or the host passed to the -computername parameter. It demonstrates several key bits of PowerShell functionality and lots of silly workarounds for PowerShell behavior that's either unforgiving or something I don't quite grok. ;-) This should really go into an snap-in (maybe PSCX) as a full-featured cmdlet written in C#.

    # Show-DsObjectPicker.ps1
    
    param(
      [string]
      $ComputerName
    )
    
    add-type -typedefinition @"
      using System;
      using System.Runtime.InteropServices;
      using System.Runtime.InteropServices.ComTypes;
    
      public enum DsScope : uint
      {
        DSOP_SCOPE_TYPE_TARGET_COMPUTER = 0x00000001,
        DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN = 0x00000002,
        DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN = 0x00000004,
        DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN = 0x00000008,
        DSOP_SCOPE_TYPE_GLOBAL_CATALOG = 0x00000010,
        DSOP_SCOPE_TYPE_EXTERNAL_UPLEVEL_DOMAIN = 0x00000020,
        DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN = 0x00000040,
        DSOP_SCOPE_TYPE_WORKGROUP = 0x00000080,
        DSOP_SCOPE_TYPE_USER_ENTERED_UPLEVEL_SCOPE = 0x00000100,
        DSOP_SCOPE_TYPE_USER_ENTERED_DOWNLEVEL_SCOPE = 0x00000200
      };
    
      public enum DsScopeInitInfo : uint
      {
        DSOP_SCOPE_FLAG_STARTING_SCOPE = 0x00000001,
        DSOP_SCOPE_FLAG_WANT_PROVIDER_WINNT = 0x00000002,
        DSOP_SCOPE_FLAG_WANT_PROVIDER_LDAP = 0x00000004,
        DSOP_SCOPE_FLAG_WANT_PROVIDER_GC = 0x00000008,
        DSOP_SCOPE_FLAG_WANT_SID_PATH = 0x00000010,
        DSOP_SCOPE_FLAG_WANT_DOWNLEVEL_BUILTIN_PATH = 0x00000020,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS = 0x00000040,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS = 0x00000080,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_COMPUTERS = 0x00000100,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_CONTACTS = 0x00000200,
        DSOP_SCOPE_FLAG_DEFAULT_FILTER_SERVICE_ACCOUNTS = 0x00000400
      };
    
      public enum DsFilter : uint
      {
        DSOP_FILTER_INCLUDE_ADVANCED_VIEW = 0x00000001,
        DSOP_FILTER_USERS = 0x00000002,
        DSOP_FILTER_BUILTIN_GROUPS = 0x00000004,
        DSOP_FILTER_WELL_KNOWN_PRINCIPALS = 0x00000008,
        DSOP_FILTER_UNIVERSAL_GROUPS_DL = 0x00000010,
        DSOP_FILTER_UNIVERSAL_GROUPS_SE = 0x00000020,
        DSOP_FILTER_GLOBAL_GROUPS_DL = 0x00000040,
        DSOP_FILTER_GLOBAL_GROUPS_SE = 0x00000080,
        DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL = 0x00000100,
        DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE = 0x00000200,
        DSOP_FILTER_CONTACTS = 0x00000400,
        DSOP_FILTER_COMPUTERS = 0x00000800,
        DSOP_FILTER_SERVICE_ACCOUNTS = 0x00001000
      };
    
      public enum DsDownlevelFilter : uint
      {
        DSOP_DOWNLEVEL_FILTER_USERS = 0x80000001,
        DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS = 0x80000002,
        DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS = 0x80000004,
        DSOP_DOWNLEVEL_FILTER_COMPUTERS = 0x80000008,
        DSOP_DOWNLEVEL_FILTER_WORLD = 0x80000010,
        DSOP_DOWNLEVEL_FILTER_AUTHENTICATED_USER = 0x80000020,
        DSOP_DOWNLEVEL_FILTER_ANONYMOUS = 0x80000040,
        DSOP_DOWNLEVEL_FILTER_BATCH = 0x80000080,
        DSOP_DOWNLEVEL_FILTER_CREATOR_OWNER = 0x80000100,
        DSOP_DOWNLEVEL_FILTER_CREATOR_GROUP = 0x80000200,
        DSOP_DOWNLEVEL_FILTER_DIALUP = 0x80000400,
        DSOP_DOWNLEVEL_FILTER_INTERACTIVE = 0x80000800,
        DSOP_DOWNLEVEL_FILTER_NETWORK = 0x80001000,
        DSOP_DOWNLEVEL_FILTER_SERVICE = 0x80002000,
        DSOP_DOWNLEVEL_FILTER_SYSTEM = 0x80004000,
        DSOP_DOWNLEVEL_FILTER_EXCLUDE_BUILTIN_GROUPS = 0x80008000,
        DSOP_DOWNLEVEL_FILTER_TERMINAL_SERVER = 0x80010000,
        DSOP_DOWNLEVEL_FILTER_ALL_WELLKNOWN_SIDS = 0x80020000,
        DSOP_DOWNLEVEL_FILTER_LOCAL_SERVICE = 0x80040000,
        DSOP_DOWNLEVEL_FILTER_NETWORK_SERVICE = 0x80080000,
        DSOP_DOWNLEVEL_FILTER_REMOTE_LOGON = 0x80100000,
        DSOP_DOWNLEVEL_FILTER_INTERNET_USER = 0x80200000,
        DSOP_DOWNLEVEL_FILTER_OWNER_RIGHTS = 0x80400000,
        DSOP_DOWNLEVEL_FILTER_SERVICES = 0x80800000,
        DSOP_DOWNLEVEL_FILTER_LOCAL_LOGON = 0x81000000,
        DSOP_DOWNLEVEL_FILTER_THIS_ORG_CERT = 0x82000000,
        DSOP_DOWNLEVEL_FILTER_IIS_APP_POOL = 0x84000000
      };
    
      public enum DsInitInfo : uint
      {
        DSOP_FLAG_MULTISELECT = 0x00000001,
        DSOP_FLAG_SKIP_TARGET_COMPUTER_DC_CHECK = 0x00000002
      };
    
      [StructLayout(LayoutKind.Sequential)]
      public struct DSOP_UPLEVEL_FILTER_FLAGS
      {
        //public DsFilter flBothModes;
        //public DsFilter flMixedModeOnly;
        //public DsFilter flNativeModeOnly;
        public uint flBothModes;
        public uint flMixedModeOnly;
        public uint flNativeModeOnly;
      }
    
      [StructLayout(LayoutKind.Sequential)]
      public struct DSOP_FILTER_FLAGS
      {
        public DSOP_UPLEVEL_FILTER_FLAGS Uplevel;
        //public DsDownlevelFilter flDownlevel;
        public uint flDownlevel;
      }
    
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
      public struct DSOP_SCOPE_INIT_INFO
      {
        public uint cbSize;
        //public DsScope flType;
        public uint flType;
        //public DsScopeInitInfo flScope;
        public uint flScope;
        public DSOP_FILTER_FLAGS FilterFlags;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzDcName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzADsPath;
        public uint hr;
      }
    
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
      public struct DSOP_INIT_INFO
      {
        public uint cbSize;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzTargetComputer;
        public uint cDsScopeInfos;
        public IntPtr aDsScopeInfos;
        //public DsInitInfo flOptions;
        public uint flOptions;
        public uint cAttributesToFetch;
        public IntPtr apwzAttributeNames;
      };
    
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
      public struct DS_SELECTION
      {
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzADsPath;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzClass;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string pwzUPN;
        public IntPtr pvarFetchedAttributes;
        public uint flScopeType;
      };
    
      [StructLayout(LayoutKind.Sequential)]
      public struct DS_SELECTION_LIST
      {
        public uint cItems;
        public uint cFetchedAttributes;
        //public IntPtr aDsSelection;
      };
    
      [Guid("0c87e64e-3b7a-11d2-b9e0-00c04fd8dbf7"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      public interface IDsObjectPicker
      {
        void Initialize(
          [In] ref DSOP_INIT_INFO pInitInfo);
    
        void InvokeDialog(
          [In] IntPtr hwndParent,
          [Out, MarshalAs(UnmanagedType.Interface)] out object ppdoSelections);
      }
    
      [Guid("e2d3ec9b-d041-445a-8f16-4748de8fb1cf"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      public interface IDsObjectPickerCredentials
      {
        void SetCredentials(
          [In, MarshalAs(UnmanagedType.LPWStr)] string szUserName,
          [In, MarshalAs(UnmanagedType.LPWStr)] string szPassword);
      }
    
      [ComImport, Guid("17d6ccd8-3b7b-11d2-b9e0-00c04fd8dbf7")]
      public class __DsObjectPicker
      {
      }
    
      public class DsObjectPicker
      {
        private __DsObjectPicker p;
    
        public static string CFSTR_DSOP_DS_SELECTION_LIST = "CFSTR_DSOP_DS_SELECTION_LIST";
    
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr GlobalLock([In] IntPtr handle);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern uint GlobalUnlock([In] IntPtr handle);
    
        [DllImport("ole32.dll")]
        public static extern void ReleaseStgMedium([In] ref STGMEDIUM pmedium);
        
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern uint RegisterClipboardFormat(string lpszFormat);
    
        public DsObjectPicker()
        {
          p = new __DsObjectPicker();
        }
    
        public void Initialize(ref DSOP_INIT_INFO pInitInfo)
        {
          IDsObjectPicker i = p as IDsObjectPicker;
          i.Initialize(ref pInitInfo);
        }
    
        public DataObject InvokeDialog(IntPtr hwndParent)
        {
          object pdoSelections;
          IDsObjectPicker i = p as IDsObjectPicker;
          i.InvokeDialog(hwndParent, out pdoSelections);
          return new DataObject(pdoSelections as IDataObject);
        }
    
        public void SetCredentials(string szUserName, string szPassword)
        {
          IDsObjectPickerCredentials i = p as IDsObjectPickerCredentials;
          i.SetCredentials(szUserName, szPassword);
        }
      }
      
      public class DataObject
      {
        private IDataObject p;
        
        public DataObject(IDataObject i)
        {
          p = i;
        }
        
        public void GetData(ref FORMATETC format, out STGMEDIUM medium)
        {
          p.GetData(ref format, out medium);
        }
      }
    "@
    
    $aDsScopeInfos = @()
    
    $DsScopeInfos = new-object DSOP_SCOPE_INIT_INFO
    $DsScopeInfos.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf([DSOP_SCOPE_INIT_INFO])
    $DsScopeInfos.flType = [DsScope]::DSOP_SCOPE_TYPE_TARGET_COMPUTER
    $DsScopeInfosFilterFlags = new-object DSOP_FILTER_FLAGS
    $DsScopeInfosFilterFlags.flDownLevel = [DsDownlevelFilter]::DSOP_DOWNLEVEL_FILTER_USERS
    $DsScopeInfos.FilterFlags = $DsScopeInfosFilterFlags
    $DsScopeInfos.hr = 0
    
    $aDsScopeInfos += $DsScopeInfos
    
    $aDsScopeInfosPtr =
      [System.Runtime.InteropServices.Marshal]::AllocCoTaskMem(
        $aDsScopeInfos.Length * [System.Runtime.InteropServices.Marshal]::SizeOf([DSOP_SCOPE_INIT_INFO]))
    $aDsScopeInfosPtrTmp = $aDsScopeInfosPtr
    
    foreach ($DsScopeInfo in $aDsScopeInfos)
    {
      [System.Runtime.InteropServices.Marshal]::StructureToPtr($DsScopeInfo, $aDsScopeInfosPtrTmp, $false)
      $aDsScopeInfosPtrTmp = [IntPtr] ($aDsScopeInfosPtrTmp.ToInt64() +
        [System.Runtime.InteropServices.Marshal]::SizeOf([DSOP_SCOPE_INIT_INFO]))
    }
    
    $DsInitInfo = new-object DSOP_INIT_INFO
    $DsInitInfo.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf([DSOP_INIT_INFO])
    $DsInitInfo.pwzTargetComputer = $ComputerName
    $DsInitInfo.cDsScopeInfos = $aDsScopeInfos.Length
    $DsInitInfo.aDsScopeInfos = $aDsScopeInfosPtr
    $DsInitInfo.flOptions = [DsInitInfo]::DSOP_FLAG_MULTISELECT
    
    $DsObjectPicker = new-object DsObjectPicker
    $DsObjectPicker.Initialize([ref] $DsInitInfo)
    $DataObject = $DsObjectPicker.InvokeDialog((get-process -id $pid).MainWindowHandle)
    
    if (-not ($DataObject -eq $null))
    {
      $medium = new-object System.Runtime.InteropServices.ComTypes.STGMEDIUM
      $format = new-object System.Runtime.InteropServices.ComTypes.FORMATETC
      
      $format.cfFormat =
        [Int16]::Parse([DsObjectPicker]::RegisterClipboardFormat([DsObjectPicker]::CFSTR_DSOP_DS_SELECTION_LIST).ToString("X4"),
          [System.Globalization.NumberStyles]::HexNumber)
      $format.dwAspect = [System.Runtime.InteropServices.ComTypes.DVASPECT]::DVASPECT_CONTENT
      $format.lindex = -1
      $format.tymed = [System.Runtime.InteropServices.ComTypes.TYMED]::TYMED_HGLOBAL
      
      $DataObject.GetData([ref] $format, [ref] $medium)
      
      try
      {
        $DsSelectionListPtr = [DsObjectPicker]::GlobalLock($medium.unionmember)
        
        try
        {
          $DsSelectionList =
            [DS_SELECTION_LIST] [System.Runtime.InteropServices.Marshal]::PtrToStructure($DsSelectionListPtr, [DS_SELECTION_LIST])
          $DsSelectionPtr = [IntPtr] ($DsSelectionListPtr.ToInt64() + [System.Runtime.InteropServices.Marshal]::SizeOf([DS_SELECTION_LIST]))
    
          for ($i = 0; $i -lt $DsSelectionList.cItems; $i++)
          {
            $DsSelection = new-object DS_SELECTION
            $DsSelection = [DS_SELECTION] [System.Runtime.InteropServices.Marshal]::PtrToStructure($DsSelectionPtr, [DS_SELECTION])
            new-object System.DirectoryServices.DirectoryEntry($DsSelection.pwzADsPath)
            $DsSelectionPtr = [IntPtr] ($DsSelectionPtr.ToInt64() + [System.Runtime.InteropServices.Marshal]::SizeOf([DS_SELECTION]))
          }
        }
        finally
        {
          [DsObjectPicker]::GlobalUnlock($medium.unionmember) | out-null
        }
      }
      finally
      {
        [DsObjectPicker]::ReleaseStgMedium([ref] $medium)
      }
    }
    
    [System.Runtime.InteropServices.Marshal]::FreeCoTaskMem($aDsScopeInfosPtr)
    
    

    Trev

    • Proposed as answer by Trevor Scroggins Wednesday, June 08, 2011 6:55 AM
    • Marked as answer by thepip3r Thursday, July 14, 2011 11:12 AM
    Wednesday, June 08, 2011 6:45 AM
  • I'll add to this as time allows. In the meantime, see the MSDN Library documentation for the DSOP_SCOPE_INIT_INFO and DSOP_INIT_INFO structures for more information on manipulating the object picker. I should add that I'm not requesting attribute values via the object picker, although that's certainly possible. Instead, I'm placing new System.DirectoryServices.DirectoryEntry objects onto the pipeline based on the returned ADSI paths. You can manipulate the returned objects just as you would any other directory object.
    Wednesday, June 08, 2011 6:50 AM
  • Fix for DataObject::InvokeDialog not returning null after clicking Cancel in the object picker:

        public DataObject InvokeDialog(IntPtr hwndParent)
        {
          object pdoSelections;
          IDsObjectPicker i = p as IDsObjectPicker;
          i.InvokeDialog(hwndParent, out pdoSelections);
          
          if (pdoSelections != null)
            return new DataObject(pdoSelections as IDataObject);
          else
            return null;
        }
    
    Wednesday, June 08, 2011 6:50 PM
  • Trevor,

    This is excellent, and thank you for sharing. I am able to object pick local users and users for other hosts using the -computername param, but I do not see a way to enable my search to include my AD forest and trusts. Am I missing a flag that can be set?

     

    Thank you,

    Adam

    Wednesday, July 13, 2011 8:05 PM
  • Adam,

    You'll need to add additional DSOP_SCOPE_INIT_INFO structures to the $aDsScopeInfos array for each new scope type, e.g. a global catalog, you want to search. You might also have success adding (with -bor) additional types to $DsScopeInfos.flType. Interdependence between different scope types isn't well documented--at least, not publicly--and you'll need to experiment with different combinations of structures and values to find settings that work correctly.

    Trev

    Thursday, July 14, 2011 2:26 AM
  • Cant seem to make this work for Domain lookups.

    I specify $DsScopeInfos.flType=DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN but script fails.

    Please help making this work on Domain environment.

    Friday, September 28, 2012 6:55 PM
  • Cant seem to make this work for Domain lookups.

    I specify $DsScopeInfos.flType=DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN but script fails.

    Please help making this work on Domain environment.

    The topic is closed.  Please start a new topic and wexpalin what it is you are doing and what script you are using.


    ¯\_(ツ)_/¯

    Friday, September 28, 2012 7:23 PM
  • it's not exactly what i was looking for but it's working as needed:

    http://thepip3r.blogspot.com/2011/06/powershell-guis-active-directory.html

    I've used thepiper's script as a base for my own version of an AD OU picker that looks very much like the native OU picker. Give it a try!

    http://itmicah.wordpress.com/2013/10/29/active-directory-ou-picker-in-powershell/


    • Edited by MicaH_Z Tuesday, October 29, 2013 2:50 PM
    • Proposed as answer by MicaH_Z Tuesday, October 29, 2013 2:51 PM
    Tuesday, October 29, 2013 2:49 PM
  • Hi, here is a very easy solution for Powershell: http://www.silogix.fr/developpement/outils/Ressources-PowerShell/Directory-Object-Picker-en-PowerShell.aspx

    You only Need a provided DLL and the provided PowerShell files.


    JR

    Thursday, May 15, 2014 4:21 PM
  • Hi, here is a very easy solution for Powershell: http://www.silogix.fr/developpement/outils/Ressources-PowerShell/Directory-Object-Picker-en-PowerShell.aspx

    You only Need a provided DLL and the provided PowerShell files.


    JR

    Hi JR,

    this doesnt´t seem to work in Powershell V3/V4, always getting on ShowDialog() an OverflowException.

    Any ideas anyone?

    Wednesday, May 28, 2014 8:12 AM
  • Hi, here is a very easy solution for Powershell: http://www.silogix.fr/developpement/outils/Ressources-PowerShell/Directory-Object-Picker-en-PowerShell.aspx

    You only Need a provided DLL and the provided PowerShell files.


    JR

    Hi JR,

    this doesnt´t seem to work in Powershell V3/V4, always getting on ShowDialog() an OverflowException.

    Any ideas anyone?


    This topic has been answered and closed for a more than a year.  Please start your own question if you need assistance.  If you have questions about third party components you must ask about them in the third party's forum.

    ¯\_(ツ)_/¯

    Wednesday, May 28, 2014 1:15 PM