是否有用于选择 Active Directory 用户的通用对话框?

Posted

技术标签:

【中文标题】是否有用于选择 Active Directory 用户的通用对话框?【英文标题】:Is there a common dialog for selecting Active Directory users? 【发布时间】:2012-03-13 20:15:19 【问题描述】:

是 Windows 选择用户、服务帐户或组对话框:

可通过 API 向 3rd 方开发者提供?

是否有“AD 浏览器”常用对话框?

【问题讨论】:

【参考方案1】:

如果您正在寻找 .NET 解决方案,我们已经创建了一个 NuGet,地址为https://github.com/Tulpep/Active-Directory-Object-Picker。

它基于此项目https://adui.codeplex.com/,但已针对 x64 计算机进行了更新。

【讨论】:

【参考方案2】:

Directory Object Picker

示例伪代码:

String SelectUsers(HWND hwndParent, IList<String> usersLdapPaths)

   IDsObjectPicker objPicker;
   IDataObject objData;
   PDSOP_INIT_INFO pInfo;
   LPWSTR[0..2] attr;
   HRESULT hr;

   /*
      Returns the LDAP path to the selected user, e.g.:
         LDAP://***.com/CN=Ian Boyd,OU=Stack Users,DC=***,DC=com

      usersLdapPaths can be null. 
      If not null then the user can mutli-select users, 
      and the selected user's LDAP paths will be returned in usersLdapPaths 
      (with the function result containing just the first user)

      If the user cancels the dialog, then the result (and usersLdapPaths ) will be empty
   */
   Result := '';

   objPicker = CreateComObject(CLSID_DsObjectPicker) as IDsObjectPicker;

   System.New(pInfo);
   try
   
      ZeroMemory(pInfo, SizeOf(DSOP_INIT_INFO));
      pInfo.cbSize = SizeOf(DSOP_INIT_INFO);
      pInfo.pwzTargetComputer = nil; //local computer

      pInfo.cDsScopeInfos := 1;
      System.New(pInfo.aDsScopeInfos);
      try
      
         ZeroMemory(pInfo.aDsScopeInfos, SizeOf(DSOP_SCOPE_INIT_INFO));
         pInfo.aDsScopeInfos.cbSize = SizeOf(pInfo.aDsScopeInfos);
         pInfo.aDsScopeInfos.flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN;  //or DSOP_SCOPE_TYPE_TARGET_COMPUTER;
         pInfo.aDsScopeInfos.flScope = DSOP_SCOPE_FLAG_WANT_PROVIDER_LDAP;
         pInfo.aDsScopeInfos.FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS;
         pInfo.aDsScopeInfos.FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS;

         if (UsersLdapPaths != null)
            pInfo.flOptions = DSOP_FLAG_MULTISELECT;

         pInfo.cAttributesToFetch := 3;
         attr[0] = "description";
         attr[1] = "name";
         attr[2] = "fullName";
         pInfo.apwzAttributeNames = @attr;

         hr = objPicker.Initialize(pInfo);
         OleCheck(hr);
         hr = objPicker.InvokeDialog(hwndParent, objData);
         OleCheck(hr);

         //the result is false if the user cancelled the dialog
         if hr = S_FALSE then
            return '';

         return ReadAttributes(objData, UsersLdapPaths);
      
      finally
      
         System.Dispose(pInfo.aDsScopeInfos);
            
   
   finally
   
      Dispose(pInfo);
   

还有辅助函数(我不会费心将一种伪代码语言转码为另一种伪代码语言):

function TActiveDirectory.ReadAttributes(ADataObject: IDataObject; AValues: TStrings): string;
var
    fmtIn: TFormatEtc;
    stgOut: TStgMedium;
    pSelList: PDS_SELECTION_LIST;
    i: Integer;
    path: string;
//  x: LongWord;
//  pVar: POleVariant;
    items: PDsSelectionArray;
begin
    Result := '';

    if Assigned(AValues) then
        AValues.Clear;

    if not Assigned(ADataObject) then
        Exit;

    stgOut.tymed := TYMED_HGLOBAL;
    fmtIn.tymed := TYMED_HGLOBAL;
    fmtIn.cfFormat := RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
    fmtIn.dwAspect := DVASPECT_CONTENT;
    fmtIn.lindex := -1;

    if (ADataObject.GetData(fmtIn, stgOut) <> S_OK) then
        Exit;

    pSelList := GlobalLock(stgOut.hGlobal);
    try
        if pSelList.cItems > 0 then
            items := PDsSelectionArray(@pSellist.aDsSelection)
        else
            items := nil;

        for i := 0 to pSelList^.cItems-1 do
        begin
//          path := TDsSelectionArray(pSellist.aDsSelection)[i].pwzADsPath;
            path := items[i].pwzADsPath;

            if Assigned(AValues) then
                AValues.Add(path);

            if Result = '' then
                Result := path;

           Result := pSelList^.aDsSelection[i].pwzName+' ('+pSelList.aDsSelection[i].pwzADsPath+')';
            AValues.Add(Result);
            AValues.Add('   Class: '+pSelList^.aDsSelection[i].pwzClass); //"user"
            AValues.Add('   UPN: '+pSelList^.aDsSelection[i].pwzUPN );    //e.g. "ian@***.com"
            pVar := pSelList^.aDsSelection[i].pvarFetchedAttributes;
            for x := 0 to pSelList^.cFetchedAttributes-1 do
            begin
                AValues.Add('   '+VarToStr(pVar^));
                if x < pSelList^.cFetchedAttributes then
                    Inc(pVar);
            end;
        end;
    finally
        GlobalUnlock(stgOut.hGlobal);
    end;
end;

【讨论】:

【参考方案3】:

对于 .NET 和 C#:

.NET wrapper for Director Object Picker at Codeplex

AD Object Picker project at CodeProject

【讨论】:

以上是关于是否有用于选择 Active Directory 用户的通用对话框?的主要内容,如果未能解决你的问题,请参考以下文章

powershell 用于将Active Directory组添加到Active Directory的Powershell脚本

Azure Active Directory B2C - 更改通知

win7 中 active directory在哪里可以找到?

Azure Active Directory 是不是具有 OAuth/OpenID Connect 令牌自检终结点?

Active Directory 和 Active Directory LDS 中的字段

Windows Server 2012中安装Active Directory域服务