【问题标题】:Get OU (Organizational Unit) name that a local computer belongs to using C++使用 C++ 获取本地计算机所属的 OU(组织单位)名称
【发布时间】:2012-01-24 20:15:34
【问题描述】:

我需要使用 WinAPI/C++ 找出本地计算机(连接到 Active Directory)所属的 OU 的名称。有什么想法吗?

【问题讨论】:

标签: c++ winapi active-directory ou


【解决方案1】:

理论上,这相当简单:使用ADsOpenObject 连接到服务器,实例化IDirectorySearch 并调用其ExecuteSearch 方法,然后使用GetFirstRowGetNextRow 遍历结果数据(但对于此查询,您只会期望一行)。

然而,实际上,所有这些都是 COM —— 所以预计这六个(左右)函数调用会在至少一百行 COM 粗略的代码中丢失(到代码稳定时)并且健壮,如果它接近 1000 行,请不要感到惊讶,其中大部分与 Active Directory 没有明显的联系)。

我应该补充一点,几乎可以肯定还有其他方法可以做到这一点——我记得,MS 至少提供了两种或三种不同的方法来访问 LDAP 类型的数据。当我为此编写一些代码时,我最初试图找到最干净的,但沮丧地放弃了。似乎没有最干净的希望 - 至少在那时,我选择了“丑陋但有点记录”。

【讨论】:

  • 杰瑞,如果你能分享你的“丑陋”代码,即使是一堆笨拙的 COM 等等,这真的很有帮助......我放弃了为 WinAPI/C++ 寻找解决方案的尝试。
  • @ahmd0:不幸的是,我不能,至少不合理。它是为前雇主写的,获得发布许可可能比重写它更费力。
【解决方案2】:

有关在 C 或 C++ 中访问 Active Directory 的简单 WINAPI(非 COM)方法,请参阅 Lightweight Directory Access Protocol


void AfficheErreurLdap(char *fonction, ULONG rc);

/*
*
*       Fonction d'entrée du programme 
*
*/

void main(int argc, char* argv[])
{
  LDAP *pSessionLdap;    // Pointeur vers la session LDAP
  char *pHote;           // Pointeur vers la chaîne représentant le nom de l'hôte   
  char *pUtilisateur;    // Pointeur vers la chaîne représentant l'utilisateur  
  char *pMotDePasse;     // Pointeur vers la chaîne représentant le mot de passe
  char *pRacineLdap;     // Pointeur vers la racine Ldap
  ULONG rc;                // Récupération du code de retour des appels
  LDAPMessage   *pResultat; // Pointeur vers le message résultat de la réquête LDAP
  LDAPMessage   *pEntree;     // Utilisée lors du parcours du résultat pour l'affichage

  char *pDN;                 // Pointeur vers le DN d'une entrée du résultat
  char *pAttribut;     // Pointeur vers la chaîne représentant l'attribut
  BerElement *pBer = NULL;// "curseur" interne à l'API LDAP pour le parcours des elts 
  char **pValeurs;            // Valeurs de l'attribut lors de l'affichage du résultat
  int    i;                             // Indice pour la parcours des valeurs  d'attribut

  /* Analyse des Paramètres de lancement et affichage d’un message d’erreur si incorrect */
  if (argc != 5)
  {
    fprintf(stderr,"Syntaxe :\n\tex_cldap_1 Hote Utilisateur MotDePasse RacineLdap\n");
    exit (1);
  }
  /* Récupération des paramètres des lancement  */
  pHote = argv[1];
  pUtilisateur = argv[2];
  pMotDePasse = argv[3];
  pRacineLdap = argv[4];

  /* Ouverture de la session LDAP et récupération du handle de session */
  pSessionLdap = ldap_open( pHote, 389);    /* 389 est le numéro de port standard LDAP */

  if ( pSessionLdap == NULL ) 
  {
    // En cas d'erreur : affichage du message d'erreur adéquat 
    perror( "ldap_open" );
    exit( 2 );
  }

  printf("Ouverture de la session réalisée\n");

  /* Authentification du client                                                                                                             */
  /* Pour l'exemple, l'authentification est faite en tant qu'anonyme    */
  rc = ldap_simple_bind_s(pSessionLdap, pUtilisateur, pMotDePasse);
  if ( rc != LDAP_SUCCESS ) 
  {
    // Erreur lors de l'authentification, on termine après affichage d'un message
    AfficheErreurLdap("ldap_simple_bind_s", rc);

    exit( 3 );
  }

  printf("Authentification réalisée\n");

  /*                                                                                                                                */
  /* Recherche des données dans l'annuaire                  */
  /*                                                                                                                                */
  rc = ldap_search_s(pSessionLdap,            // Session LDAP
    pRacineLdap,                    // Base de la recherche
    LDAP_SCOPE_SUBTREE, // Sccpe : LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE  
    "(objectClass=*)",      // Filtre de recherche
    NULL,                               // Attributs que l'on souhaite visualiser
    0,                                      // Indique si l'on souhaite uniquement les types (1) ou 
    // Les attributs et les valeurs (0)
    &pResultat ) ;              // Pointeur vers le résultat

  if (rc != LDAP_SUCCESS ) 
  {
    // Erreur lors de la recherche, on termine après affichage du message d'erreur
    AfficheErreurLdap("ldap_search_s", rc);
    exit (4);
  }

  printf("Requête réalisée\n");


  /* On va maintenant parcourir le résultat et afficher les couples */
  /* attributs, valeurs                                                                                                                         */

  pEntree = ldap_first_entry( pSessionLdap, pResultat );

  while (pEntree != NULL)
  {
    // Récupération du DN, et affichage de celui-ci
    pDN = ldap_get_dn( pSessionLdap, pEntree );
    if ( pDN != NULL ) 
    {
      printf( "dn: %s\n", pDN );

      // Libération de la mémoire allouée par l'API LDAP
      ldap_memfree( pDN );  
    }


    // Pour chaque attribut, on va lire le couple attribut, valeur 
    pAttribut = ldap_first_attribute( pSessionLdap, pEntree, &pBer );
    while (  pAttribut != NULL)
    {
      // Récupération des valeurs associées à un attribut 
      pValeurs = ldap_get_values( pSessionLdap, pEntree, pAttribut);

      if (pValeurs  != NULL ) 
      {
        for ( i = 0; pValeurs[i] != NULL; i++ ) 
          printf( "%s: %s\n", pAttribut, pValeurs[i]);

        // Libération des valeurs lues 
        ldap_value_free( pValeurs ); 
      }

      // Libération de la mémoire utilisée par l'attribut 
      ldap_memfree( pAttribut );    

      // Lecture de l'attribut suivant
      pAttribut = ldap_next_attribute( pSessionLdap, pEntree, pBer );
    }

    // Passage à la ligne dans l'affichage
    printf( "\n\n" );

    // Récupération de l'entrée suivante de l'annuaire
    pEntree = ldap_next_entry( pSessionLdap, pEntree );
  }

  // Libération du message de résultat
  ldap_msgfree( pResultat );

  /* Fin de la session LDAP     */
  ldap_unbind( pSessionLdap );
}


/*
*
* Fonction permettant d'afficher les erreurs des opérations LDAP 
*
*
*/
void AfficheErreurLdap(char *fonction, ULONG rc)
{
  fprintf(stderr,"Erreur LDAP dans la fonction '%s', Code : %ld (0x%xld)\n", fonction, rc,rc);
}

【讨论】:

  • 对不起,我不熟悉 LDAP。你能指出我应该使用的实际 API 吗?
  • @ahmd0,我添加了一些代码,对不起,它是原样的,cmets 是法语的。
  • 谢谢。这是一个有趣的方法。我需要看一下……用谷歌翻译;)
  • 我可能想出了一个更简单的方法来做到这一点。如果我调用 GetUserNameEx(NameFullyQualifiedDN, , );它以“CN=Jeff Smith,OU=Users,DC=Engineering,DC=Microsoft,DC=Com”的形式重新运行 FQDN,所以我想我可以将 OU= 部分与 FQDN 隔离开来。我唯一担心的是 OU= 部分是否会是法语和其他语言的部分?此外,能否在 OU 名称中包含逗号,换句话说,我们可以假设逗号分隔 FQDN 的各个部分吗?
  • 为了补充上面所说的,刚刚找到了这个关于在 DN 中转义“坏”字符的页面:msdn.microsoft.com/en-us/library/windows/desktop/…
【解决方案3】:
    ///////////////IDirectorySearch///////////////////////////////////////////////////////////
CComPtr<IDirectorySearch> pDSSearch;

hr = ADsGetObject( L"LDAP://DC=forest,DC=internal", 
    IID_IDirectorySearch, 
    (void**) &pDSSearch );

if ( !SUCCEEDED(hr) )
{
    return 0;
}

LPWSTR pszAttr[] = { L"description", L"Name", L"distinguishedname" };
ADS_SEARCH_HANDLE hSearch;
DWORD dwCount = 0;
ADS_SEARCH_COLUMN col;
DWORD dwAttrNameSize = sizeof(pszAttr)/sizeof(LPWSTR);

// Search for all objects with the 'cn' property  TESTCOMP.
hr = pDSSearch->ExecuteSearch(L"(&(objectClass=computer)(cn=TESTCOMP))",pszAttr ,dwAttrNameSize,&hSearch );

LPWSTR pszColumn;
while( pDSSearch->GetNextRow( hSearch) != S_ADS_NOMORE_ROWS )
{
    // Get the property.
    hr = pDSSearch->GetColumn( hSearch, L"distinguishedname", &col );

    // If this object supports this attribute, display it.
    if ( SUCCEEDED(hr) )
    { 
        if (col.dwADsType == ADSTYPE_CASE_IGNORE_STRING)
            wprintf(L"The description property:%s\r\n", col.pADsValues->CaseIgnoreString); 
        pDSSearch->FreeColumn( &col );
    }
    else
        puts("description property NOT available");
    puts("------------------------------------------------");
    dwCount++;
}
pDSSearch->CloseSearchHandle(hSearch);
///////////////IDirectorySearch///////////////////////////////////////////////////////////

在这个搜索中你会得到

(*((col).pADsValues)).DNString "CN=TESTCOMP,OU=OUnit3,OU=OUnit,DC=forest,DC=internal"

所以这是您的 TESTCOMP 的路径,我相信 OUnit3 是您想要的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    • 2015-02-07
    相关资源
    最近更新 更多