| Platform SDK: Active Directory, ADSI, and Directory Services |
The following examples bind to the partitions container and enumerate all crossRef objects.
// This application enumerates crossrefs in the partitions container.
//
#include <objbase.h>
#include <wchar.h>
#include <activeds.h>
//Make sure you define UNICODE
//Need to define version 5 for Windows 2000
#define _WIN32_WINNT 0x0500
#include <sddl.h>
HRESULT FindCrossRefs(IDirectorySearch *pConfigNC, //IDirectorySearch pointer to Partitions container.
LPOLESTR szFilter, //Filter for finding specific crossrefs.
//NULL returns all attributeSchema objects.
LPOLESTR *pszPropertiesToReturn, //Properties to return for crossRef objects found
//NULL returns all set properties.
BOOL bIsVerbose //TRUE means all properties for the found objects are displayed.
//FALSE means only the RDN
);
void wmain( int argc, wchar_t *argv[ ])
{
//Handle the command line arguments.
LPOLESTR pszBuffer = new OLECHAR[MAX_PATH*2];
wcscpy(pszBuffer, L"");
BOOL bReturnVerbose = FALSE;
wprintf(L"\nFinding all crossRef objects in the Partitions container\n");
//Intialize COM
CoInitialize(NULL);
HRESULT hr = S_OK;
//Get rootDSE and the config container's DN.
IADs *pObject = NULL;
IDirectorySearch *pConfigNC = NULL;
LPOLESTR szPath = new OLECHAR[MAX_PATH];
VARIANT var;
hr = ADsOpenObject(L"LDAP://rootDSE",
NULL,
NULL,
ADS_SECURE_AUTHENTICATION, //Use Secure Authentication
IID_IADs,
(void**)&pObject);
if (FAILED(hr))
{
wprintf(L"Could not execute query. Could not bind to LDAP://rootDSE. HR: %x\n",hr);
if (pObject)
pObject->Release();
return;
}
if (SUCCEEDED(hr))
{
hr = pObject->Get(L"configurationNamingContext",&var);
if (SUCCEEDED(hr))
{
//Build path to the partitions container.
wcscpy(szPath,L"LDAP://cn=Partitions,");
wcscat(szPath,var.bstrVal);
hr = ADsOpenObject(szPath,
NULL,
NULL,
ADS_SECURE_AUTHENTICATION, //Use Secure Authentication
IID_IDirectorySearch,
(void**)&pConfigNC);
if (SUCCEEDED(hr))
{
hr = FindCrossRefs(pConfigNC, //IDirectorySearch pointer to Partitions container.
NULL, //Find all
NULL, //Return all properties
TRUE //Display all properties
);
if (SUCCEEDED(hr))
{
if (S_FALSE==hr)
wprintf(L"No crossRef object could be found.\n");
}
else if (0x8007203e==hr)
wprintf(L"Could not execute query. An invalid filter was specified.\n");
else
wprintf(L"Query failed to run. HRESULT: %x\n",hr);
}
else
{
wprintf(L"Could not execute query. Could not bind to the schema container.\n");
}
if (pConfigNC)
pConfigNC->Release();
}
VariantClear(&var);
}
if (pObject)
pObject->Release();
// Uninitialize COM
CoUninitialize();
return;
}
HRESULT FindCrossRefs(IDirectorySearch *pConfigNC, //IDirectorySearch pointer to Partitions container.
LPOLESTR szFilter, //Filter for finding specific crossrefs.
//NULL returns all attributeSchema objects.
LPOLESTR *pszPropertiesToReturn, //Properties to return for crossRef objects found
//NULL returns all set properties.
BOOL bIsVerbose //TRUE means all properties for the found objects are displayed.
//FALSE means only the RDN
)
{
if (!pConfigNC)
return E_POINTER;
//Create search filter
LPOLESTR pszSearchFilter = new OLECHAR[MAX_PATH*2];
LPOLESTR szCategory = NULL;
wsprintf(pszSearchFilter, L"(&(objectCategory=crossRef)%s)",szFilter);
//Attributes are one-level deep in the schema container so only need to search one level.
ADS_SEARCHPREF_INFO SearchPrefs;
SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs.vValue.Integer = ADS_SCOPE_ONELEVEL;
DWORD dwNumPrefs = 1;
// COL for iterations
LPOLESTR pszColumn = NULL;
ADS_SEARCH_COLUMN col;
HRESULT hr;
// Interface Pointers
IADs *pObj = NULL;
IADs * pIADs = NULL;
// Handle used for searching
ADS_SEARCH_HANDLE hSearch = NULL;
// Set the search preference
hr = pConfigNC->SetSearchPreference( &SearchPrefs, dwNumPrefs);
if (FAILED(hr))
return hr;
LPOLESTR pszBool = NULL;
DWORD dwBool;
PSID pObjectSID = NULL;
LPOLESTR szSID = NULL;
LPOLESTR szDSGUID = new WCHAR [39];
LPGUID pObjectGUID = NULL;
FILETIME filetime;
SYSTEMTIME systemtime;
DATE date;
VARIANT varDate;
LARGE_INTEGER liValue;
LPOLESTR *pszPropertyList = NULL;
LPOLESTR pszNonVerboseList[] = {L"lDAPDisplayName",L"cn"};
LPOLESTR szCNValue = new OLECHAR[MAX_PATH];
LPOLESTR szLDAPDispleyNameValue = new OLECHAR[MAX_PATH];
int iCount = 0;
DWORD x = 0L;
if (!bIsVerbose)
{
//Return non-verbose list properties only
hr = pConfigNC->ExecuteSearch(pszSearchFilter,
pszNonVerboseList,
sizeof(pszNonVerboseList)/sizeof(LPOLESTR),
&hSearch
);
}
else
{
if (!pszPropertiesToReturn)
{
//Return all properties.
hr = pConfigNC->ExecuteSearch(pszSearchFilter,
NULL,
0L,
&hSearch
);
}
else
{
//specified subset.
pszPropertyList = pszPropertiesToReturn;
//Return specified properties
hr = pConfigNC->ExecuteSearch(pszSearchFilter,
pszPropertyList,
sizeof(pszPropertyList)/sizeof(LPOLESTR),
&hSearch
);
}
}
if ( SUCCEEDED(hr) )
{
// Call IDirectorySearch::GetNextRow() to retrieve the next row
//of data
hr = pConfigNC->GetFirstRow( hSearch);
if (SUCCEEDED(hr))
{
while( hr != S_ADS_NOMORE_ROWS )
{
//Keep track of count.
iCount++;
if (bIsVerbose)
wprintf(L"----------------------------------\n");
// loop through the array of passed column names,
// print the data for each column
while( pConfigNC->GetNextColumnName( hSearch, &pszColumn ) != S_ADS_NOMORE_COLUMNS )
{
hr = pConfigNC->GetColumn( hSearch, pszColumn, &col );
if ( SUCCEEDED(hr) )
{
// Print the data for the column and free the column
if(bIsVerbose)
{
// Get the data for this column
wprintf(L"%s\n",col.pszAttrName);
switch (col.dwADsType)
{
case ADSTYPE_DN_STRING:
for (x = 0; x< col.dwNumValues; x++)
{
wprintf(L" %s\r\n",col.pADsValues[x].DNString);
}
break;
case ADSTYPE_CASE_EXACT_STRING:
case ADSTYPE_CASE_IGNORE_STRING:
case ADSTYPE_PRINTABLE_STRING:
case ADSTYPE_NUMERIC_STRING:
case ADSTYPE_TYPEDNAME:
case ADSTYPE_FAXNUMBER:
case ADSTYPE_PATH:
case ADSTYPE_OBJECT_CLASS:
for (x = 0; x< col.dwNumValues; x++)
{
wprintf(L" %s\r\n",col.pADsValues[x].CaseIgnoreString);
}
break;
case ADSTYPE_BOOLEAN:
for (x = 0; x< col.dwNumValues; x++)
{
dwBool = col.pADsValues[x].Boolean;
pszBool = dwBool ? L"TRUE" : L"FALSE";
wprintf(L" %s\r\n",pszBool);
}
break;
case ADSTYPE_INTEGER:
for (x = 0; x< col.dwNumValues; x++)
{
wprintf(L" %d\r\n",col.pADsValues[x].Integer);
}
break;
case ADSTYPE_OCTET_STRING:
if ( _wcsicmp(col.pszAttrName,L"objectSID") == 0 )
{
for (x = 0; x< col.dwNumValues; x++)
{
pObjectSID = (PSID)(col.pADsValues[x].OctetString.lpValue);
//Convert SID to string.
ConvertSidToStringSid(pObjectSID, &szSID);
wprintf(L" %s\r\n",szSID);
LocalFree(szSID);
}
}
else if ( (_wcsicmp(col.pszAttrName,L"objectGUID") == 0)
|| (_wcsicmp(col.pszAttrName,L"schemaIDGUID") == 0)
|| (_wcsicmp(col.pszAttrName,L"attributeSecurityGUID") == 0) )
{
for (x = 0; x< col.dwNumValues; x++)
{
//Cast to LPGUID
pObjectGUID = (LPGUID)(col.pADsValues[x].OctetString.lpValue);
//Convert GUID to string.
::StringFromGUID2(*pObjectGUID, szDSGUID, 39);
//Print the GUID
wprintf(L" %s\r\n",szDSGUID);
}
}
else if ( _wcsicmp(col.pszAttrName,L"oMObjectClass") == 0 )
{
//TODO:
wprintf(L" TODO:No conversion for this.");
}
else
wprintf(L" Value of type Octet String. No Conversion.");
break;
case ADSTYPE_UTC_TIME:
for (x = 0; x< col.dwNumValues; x++)
{
systemtime = col.pADsValues[x].UTCTime;
if (SystemTimeToVariantTime(&systemtime, &date) != 0)
{
//Pack in variant.vt
varDate.vt = VT_DATE;
varDate.date = date;
VariantChangeType(&varDate,&varDate,VARIANT_NOVALUEPROP,VT_BSTR);
wprintf(L" %s\r\n",varDate.bstrVal);
VariantClear(&varDate);
}
else
wprintf(L" Could not convert UTC-Time.\n",pszColumn);
}
break;
case ADSTYPE_LARGE_INTEGER:
for (x = 0; x< col.dwNumValues; x++)
{
liValue = col.pADsValues[x].LargeInteger;
filetime.dwLowDateTime = liValue.LowPart;
filetime.dwHighDateTime = liValue.HighPart;
if((filetime.dwHighDateTime==0) && (filetime.dwLowDateTime==0))
{
wprintf(L" No value set.\n");
}
else
{
//Check for properties of type LargeInteger that represent time
//if TRUE, then convert to variant time.
if ((0==wcscmp(L"accountExpires", col.pszAttrName))|
(0==wcscmp(L"badPasswordTime", col.pszAttrName))||
(0==wcscmp(L"lastLogon", col.pszAttrName))||
(0==wcscmp(L"lastLogoff", col.pszAttrName))||
(0==wcscmp(L"lockoutTime", col.pszAttrName))||
(0==wcscmp(L"pwdLastSet", col.pszAttrName))
)
{
//Handle special case for Never Expires where low part is -1
if (filetime.dwLowDateTime==-1)
{
wprintf(L" Never Expires.\n");
}
else
{
if (FileTimeToLocalFileTime(&filetime, &filetime) != 0)
{
if (FileTimeToSystemTime(&filetime,
&systemtime) != 0)
{
if (SystemTimeToVariantTime(&systemtime,
&date) != 0)
{
//Pack in variant.vt
varDate.vt = VT_DATE;
varDate.date = date;
VariantChangeType(&varDate,&varDate,VARIANT_NOVALUEPROP,VT_BSTR);
wprintf(L" %s\r\n",varDate.bstrVal);
VariantClear(&varDate);
}
else
{
wprintf(L" FileTimeToVariantTime failed\n");
}
}
else
{
wprintf(L" FileTimeToSystemTime failed\n");
}
}
else
{
wprintf(L" FileTimeToLocalFileTime failed\n");
}
}
}
else
{
//Print the LargeInteger.
wprintf(L" high: %d low: %d\r\n",filetime.dwHighDateTime, filetime.dwLowDateTime);
}
}
}
break;
case ADSTYPE_NT_SECURITY_DESCRIPTOR:
for (x = 0; x< col.dwNumValues; x++)
{
wprintf(L" Security descriptor.\n");
}
break;
default:
wprintf(L"Unknown type %d.\n",col.dwADsType);
}
}
else
{
//Verbose handles only the two single-valued attributes: cn and ldapdisplayname
//so this is a special case.
if (0==wcscmp(L"cn", pszColumn))
{
wcscpy(szCNValue,col.pADsValues->CaseIgnoreString);
}
if (0==wcscmp(L"lDAPDisplayName", pszColumn))
{
wcscpy(szLDAPDispleyNameValue,col.pADsValues->CaseIgnoreString);
}
}
pConfigNC->FreeColumn( &col );
}
FreeADsMem( pszColumn );
}
if (!bIsVerbose)
wprintf(L"%s (%s)\n",szLDAPDispleyNameValue,szCNValue);
//Get the next row
hr = pConfigNC->GetNextRow( hSearch);
}
}
// Close the search handle to clean up
pConfigNC->CloseSearchHandle(hSearch);
}
if (SUCCEEDED(hr) && 0==iCount)
hr = S_FALSE;
return hr;
}
'''''''''''''''''''''''''''''''''''''''
'Parse the arguments
'''''''''''''''''''''''''''''''''''''''
On Error Resume Next
msgbox "This script enumerates crossRef objects in the partitions container."
sPrefix = "LDAP://"
'Get distinguished name for config container and build ADsPath to partitions container.
Set root= GetObject(sPrefix & "rootDSE")
If (Err.Number <> 0) Then
BailOnFailure Err.Number, "on GetObject method for rootDSE"
End If
sConfigDN = root.Get("configurationNamingContext")
If (Err.Number <> 0) Then
BailOnFailure Err.Number, "on Get method"
End If
sContainerDN = "cn=Partitions," & sConfigDN
'''''''''''''''''''''''''''''''''''''''
'Bind to the container
'''''''''''''''''''''''''''''''''''''''
Set cont= GetObject(sPrefix & sContainerDN)
If (Err.Number <> 0) Then
BailOnFailure Err.Number, "on GetObject method for partitions container"
End If
'''''''''''''''''''''''''''''''''''''''
'Enumerate the container.
''''''''''''''''''''''''''''''''''''''
For Each obj In cont
strText = strText & "Name: " & obj.Get("name") & vbCrLf
values = obj.GetEx("objectClass")
For Each value In values
sValue = value
Next
strText = strText & " objectClass: " & sValue & vbCrLf
strText = strText & " DnsRoot: " & obj.Get("dnsRoot") & vbCrLf
strText = strText & " NCName: " & obj.Get("NCName") & vbCrLf
sTrustParent = obj.Get("trustParent")
If (Err.Number = 0) Then
strText = strText & " TrustParent: " & sTrustParent & vbCrLf
Else
Err.Clear
End If
sNetBIOSName = obj.Get("nETBIOSName")
If (Err.Number = 0) Then
strText = strText & " NETBIOSName: " & sNetBIOSName & vbCrLf
Else
Err.Clear
End If
Next
show_items strText, "Display crossRef"
'''''''''''''''''''''''''''''''''''''''
'Display subroutines
'''''''''''''''''''''''''''''''''''''''
Sub show_items(strText, strName)
MsgBox strText, vbInformation, "Create CrossRef"
End Sub
Sub BailOnFailure(ErrNum, ErrText) strText = "Error 0x" & Hex(ErrNum) & " " & ErrText
MsgBox strText, vbInformation, "ADSI Error"
WScript.Quit
End Sub