2009-10-21 6 views
3

J'essaie de récupérer une liste de noms d'ordinateurs et la date à laquelle ils ont été connectés pour la dernière fois à partir d'Active Directory et de les renvoyer dans une base de données. Obtenir le nom est assez facile, mais lorsque je tente d'ajouter le « lastLogon » ou « lastLogonTimestamp » comme indiqué ci-dessous, les seules valeurs que je reçois pour la lastLogonTimestamp est « System._ComObject »Comment lister tous les ordinateurs et la dernière fois qu'ils ont ouvert une session dans AD?

public DataTable GetListOfComputers(string domainName) 
{ 
    DirectoryEntry entry = new DirectoryEntry("LDAP://DC=" + domainName + ",DC=com"); 
    DirectorySearcher search = new DirectorySearcher(entry); 
    string query = "(objectclass=computer)"; 
    search.Filter = query; 

    search.PropertiesToLoad.Add("name"); 
    search.PropertiesToLoad.Add("lastLogonTimestamp"); 

    SearchResultCollection mySearchResultColl = search.FindAll(); 

    DataTable results = new DataTable(); 
    results.Columns.Add("name"); 
    results.Columns.Add("lastLogonTimestamp"); 

    foreach (SearchResult sr in mySearchResultColl) 
    { 
    DataRow dr = results.NewRow(); 
    DirectoryEntry de = sr.GetDirectoryEntry(); 
    dr["name"] = de.Properties["Name"].Value; 
    dr["lastLogonTimestamp"] = de.Properties["lastLogonTimestamp"].Value; 
    results.Rows.Add(dr); 
    de.Close(); 
    } 

    return results; 
} 

Si je fais une recherche AD en utilisant un outil comme LDP je peux voir que la propriété existe et est peuplée avec des données. Comment puis-je obtenir cette information?

Répondre

11

Il serait plus facile d'utiliser la classe ComputerPrincipal et un PrincipalSearcher de System.DirectoryServices.AccountManagement.

PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName); 
PrincipalSearcher ps = new PrincipalSearcher(new ComputerPrincipal(pc)); 
PrincipalSearchResult<Principal> psr = ps.FindAll(); 
foreach (ComputerPrincipal cp in psr) 
{ 
    DataRow dr = results.NewRow(); 
    dr["name"] = cp.Name; 
    dr["lastLogonTimestamp"] = cp.LastLogon;  
    results.Rows.Add(dr); 
} 
3

Essayez d'utiliser IADsLargeInteger (Source)

DirectoryEntry user = DirectoryEntry("LDAP://" + strDN); 
if (user.Properties.Contains("lastlogontimestamp")) 
{ 
    // lastlogontimestamp is a IADsLargeInteger 
    IADsLargeInteger li = (IADsLargeInteger) 
    user.Properties["lastlogontimestamp"][0]; 
    long lastlogonts = 
     (long)li.HighPart << 32 | (uint)li.LowPart; 
    user.Close(); 
    return DateTime.FromFileTime(lastlogonts); 
} 
+0

IADsLargeInteger: COM-objet dans "Active DS Type Library", espace de noms ActiveDs –

+0

Une meilleure utilisation 'DirectoryServices.AccountManagement' ni *** ActiveDS COM ***. _IMHO_ – Kiquenet

1

Une réponse simple à la question initiale est d'accéder à la propriété sur le résultat de votre recherche:

sr.Properties["lastLogonTimestamp"][0].ToString() 

DateTime.FromFileTimeUTC(long.Parse(sr.Properties["lastLogonTimestamp"][0].ToString())) pour obtenir une valeur datetime

Je vais avoir un problème similaire, je peut accéder à la propriété lastLogonTimestamp dans le SearchResult et obtenir une valeur dans le résultat indexé mais après avoir utilisé SearchResult.GetDirectoryEntry() je ne suis pas en mesure d'accéder à un résultat valide pour la propriété lastLogonTimestamp sur le DirectoryEntry.

Est-ce que quelqu'un d'autre a rencontré ce problème avec le DirectoryEntry retourné de SearchResult.GetDirectoryEntry() en ce qui concerne l'accès à la propriété lastLogonTimestamp?

+0

Je suis d'accord. Mieux utiliser 'DirectoryServices.AccountManagement' ni *** ActiveDS COM *** – Kiquenet

5

** La façon de traiter la propriété 'lastLogonTimestamp' extrait d'une DirectoryEntry est de le convertir en IADSLargeInteger

de: http://www.dotnet247.com/247reference/msgs/31/159934.aspx **

Le __ComObject est revenu pour ces types est IADsLargeInteger pour le valeurs numériques et IADsSecurityDescriptor pour SecurityDescriptors.

Vous pouvez inclure une référence dans l'onglet COM à Active DS Type Lib et obtenir la définition de ces interfaces ou les définir manuellement. Voici un exemple :

using System; 
using System.DirectoryServices; 
using System.Runtime.InteropServices; 

//This is the managed definition of this interface also found in 
ActiveDs.tlb 
[ComImport] 
[Guid("9068270B-0939-11D1-8BE1-00C04FD8D503")] 
[InterfaceType(ComInterfaceType.InterfaceIsDual)] 
internal interface IADsLargeInteger 
{ 
    [DispId(0x00000002)] 
    int HighPart{get; set;} 
    [DispId(0x00000003)] 
    int LowPart{get; set;} 
} 

class Class1 
{ 
    [STAThread] 
    static void Main(string[] args) 
    { 
     DirectoryEntry entry = new 
DirectoryEntry("LDAP://cn=user,cn=users,dc=domain,dc=com"); 
     if(entry.Properties.Contains("lastLogon")) 
     { 
      IADsLargeInteger li = 
(IADsLargeInteger)entry.Properties["lastLogon"][0];  
      long date = (long)li.HighPart << 32 | (uint)li.LowPart; 
      DateTime time = DateTime.FromFileTime(date); 
      Console.WriteLine("Last logged on at: {0}", time); 
     } 
    } 

} 

David Stucki Microsoft Developer support

+0

Je pense que j'ai besoin d'un IADSLargeInteger pour définir la propriété" accountExpires "aussi. Comment puis-je définir la classe "LargeInteger" - votre code ne spécifie pas. Est-ce que je crée juste une nouvelle classe et hérite/implémente IADsLargeInteger? –

+0

@Michael Bray Ajouter une référence à COM-Object "Bibliothèque de types Active DS", ActiveDs.IADsLargeInteger ISomeAdTime = (ActiveDs.IADsLargeInteger) Iter; long lngSomeAdTime = (long) ISomeAdTime.HighPart << 32 | (uint) ISomeAdTime.LowPart; System.DateTime someAdTime = System.DateTime.FromFileTime (lngSomeAdTime); –

+0

Pourquoi utiliser *** ActiveDs *** (COM) et non 'DirectoryServices.AccountManagement'? – Kiquenet