Enumerando as réplicas de um serviço
Este tópico inclui um exemplo de código que enumera as instâncias instaladas de um serviço replicado em diferentes computadores host em toda a empresa. Para alterar a senha da conta de serviço para cada instância de um serviço replicado, use este exemplo de código em conjunto com o exemplo de código no tópico Alterando a senha em uma conta de usuário de serviço.
O exemplo de código pressupõe que cada instância de serviço tem seu próprio objeto SCP (ponto de conexão de serviço) no diretório. Um SCP é um objeto da classe serviceConnectionPoint. Essa classe tem um atributo de palavras-chave, que é um atributo de vários valores replicado para cada catálogo global (GC) na floresta. O atributo keywords do SCP de cada instância contém o GUID do produto do serviço. Isso permite localizar todos os SCPs para as várias instâncias de serviço pesquisando um GC por objetos com um atributo de palavras-chave igual ao GUID do produto.
O exemplo de código obtém um ponteiro IDirectorySearch para um GC e usa o método IDirectorySearch::ExecuteSearch para procurar os SCPs. Lembre-se de que o GC contém uma réplica parcial para cada SCP. Ou seja, ele contém alguns dos atributos SCP, mas não todos. Neste exemplo de código, concentre-se no atributo serviceDNSName , que contém o nome DNS do servidor host para essa instância de serviço. Como serviceDNSName não é um dos atributos replicados em um GC, o exemplo de código usa um processo de duas etapas para recuperá-lo. Primeiro, ele usa a pesquisa GC para obter o nome distinto (DN) do SCP e, em seguida, usa esse DN para vincular diretamente ao SCP para recuperar a propriedade serviceDNSName .
HRESULT EnumerateServiceInstances(
LPWSTR szQuery, // Search string filter.
LPWSTR *pszAttribs, // An array of attributes
// to retrieve.
DWORD dwAttribs, // # of attributes requested.
DWORD *pdwAttribs, // # of attributes retrieved.
ADS_ATTR_INFO **ppPropEntries // Returns a pointer to the
// retrieved attributes.
)
{
HRESULT hr;
IEnumVARIANT *pEnum = NULL;
IADsContainer *pCont = NULL;
VARIANT var;
IDispatch *pDisp = NULL;
BSTR bstrPath = NULL;
ULONG lFetch;
IADs *pADs = NULL;
int iRows=0;
static IDirectorySearch *pSearch = NULL;
static ADS_SEARCH_HANDLE hSearch = NULL;
// Parameters for IDirectoryObject.
IDirectoryObject *pSCP = NULL;
// Structures and parameters for IDirectorySearch.
DWORD dwPref;
ADS_SEARCH_COLUMN Col;
ADS_SEARCHPREF_INFO SearchPref[2];
// First time through; set up the search.
if (pSearch == NULL)
{
// Bind to the GC: namespace container object. The GC DN
// is a single immediate child of the GC: namespace, which must
// be obtained through enumeration.
hr = ADsGetObject(L"GC:",
IID_IADsContainer,
(void**) &pCont );
if (FAILED(hr)) {
_tprintf(TEXT("ADsGetObject(GC) failed: 0x%x\n"), hr);
goto Cleanup;
}
// Obtain an enumeration interface for the GC container.
hr = ADsBuildEnumerator(pCont,&pEnum);
if (FAILED(hr)) {
_tprintf(TEXT("ADsBuildEnumerator failed: 0x%x\n"), hr);
goto Cleanup;
}
// Enumerate. There is only one child of the GC: object.
hr = ADsEnumerateNext(pEnum,1,&var,&lFetch);
if (( hr == S_OK ) && ( lFetch == 1 ) )
{
pDisp = V_DISPATCH(&var);
hr = pDisp->QueryInterface( IID_IADs, (void**)&pADs);
if (hr == S_OK)
hr = pADs->get_ADsPath(&bstrPath);
}
if (FAILED(hr)) {
_tprintf(TEXT("Enumeration failed: 0x%x\n"), hr);
goto Cleanup;
}
// Now bstrPath contains the ADsPath for the current GC.
// Bind the GC to get the search interface.
hr = ADsGetObject(bstrPath,
IID_IDirectorySearch,
(void**)&pSearch);
if (FAILED(hr)) {
_tprintf(TEXT("Failed to bind search root: 0x%x\n"), hr);
goto Cleanup;
}
// Set up a deep search.
// Thousands of objects are not expected
// in this example; request 1000 rows per page.
dwPref=sizeof(SearchPref)/sizeof(ADS_SEARCHPREF_INFO);
SearchPref[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPref[0].vValue.dwType = ADSTYPE_INTEGER;
SearchPref[0].vValue.Integer = ADS_SCOPE_SUBTREE;
SearchPref[1].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
SearchPref[1].vValue.dwType = ADSTYPE_INTEGER;
SearchPref[1].vValue.Integer = 1000;
hr = pSearch->SetSearchPreference(SearchPref, dwPref);
if (FAILED(hr)) {
_tprintf(TEXT("Failed to set search prefs: 0x%x\n"), hr);
goto Cleanup;
}
// Execute the search. From the GC, get the distinguished name
// of the SCP. Use the DN to bind to the SCP and get the other
// properties.
hr = pSearch->ExecuteSearch(szQuery, pszAttribs, 1, &hSearch);
if (FAILED(hr)) {
_tprintf(TEXT("ExecuteSearch failed: 0x%x\n"), hr);
goto Cleanup;
}
}
// Get the next row.
hr = pSearch->GetNextRow(hSearch);
// Process the row.
if (SUCCEEDED(hr) && hr !=S_ADS_NOMORE_ROWS)
{
// Get the distinguished name of the object in this row.
hr = pSearch->GetColumn(hSearch, L"distinguishedName", &Col);
if FAILED(hr) {
_tprintf(TEXT("GetColumn failed: 0x%x\n"), hr);
goto Cleanup;
}
// Bind to the DN to get the properties.
if (Col.dwADsType == ADSTYPE_CASE_IGNORE_STRING)
{
LPWSTR szSCPPath =
new WCHAR[7 + lstrlenW(Col.pADsValues->CaseIgnoreString) + 1];
wcscpy_s(szSCPPath, L"LDAP://");
wcscat_s(szSCPPath, Col.pADsValues->CaseIgnoreString);
hr = ADsGetObject(szSCPPath,
IID_IDirectoryObject,
(void**)&pSCP);
delete szSCPPath;
if (SUCCEEDED(hr))
{
hr = pSCP->GetObjectAttributes(pszAttribs, dwAttribs,
ppPropEntries, pdwAttribs);
if(FAILED(hr)) {
_tprintf(TEXT("GetObjectAttributes Failed."), hr);
goto Cleanup;
}
}
}
pSearch->FreeColumn(&Col);}
Cleanup:
if (bstrPath)
SysFreeString(bstrPath);
if (pSCP)
pSCP->Release();
if (pCont)
pCont->Release();
if (pEnum)
ADsFreeEnumerator(pEnum);
if (pADs)
pADs->Release();
if (pDisp)
pDisp->Release();
return hr;
}