서비스의 복제본 열거Enumerating the Replicas of a Service

이 항목에는 엔터프라이즈 전체의 여러 호스트 컴퓨터에 복제 된 서비스의 설치 된 인스턴스를 열거 하는 코드 예제가 포함 되어 있습니다.This topic includes a code example that enumerates the installed instances of a replicated service on different host computers throughout an enterprise. 복제 된 서비스의 각 인스턴스에 대 한 서비스 계정 암호를 변경 하려면 서비스의 사용자 계정에 대 한 암호 변경 항목의 코드 예제와 함께이 코드 예제를 사용 합니다.To change the service account password for each instance of a replicated service, use this code example in conjunction with the code example in the Changing the Password on a Service's User Account topic.

이 코드 예제에서는 각 서비스 인스턴스가 디렉터리에 고유한 SCP (서비스 연결 지점) 개체를 포함 하 고 있다고 가정 합니다.The code example assumes that each service instance has its own service connection point (SCP) object in the directory. SCP는 serviceConnectionPoint 클래스의 개체입니다.An SCP is an object of the serviceConnectionPoint class. 이 클래스에는 포리스트의 각 GC (글로벌 카탈로그)에 복제 되는 다중 값 특성인 keywords 특성이 있습니다.This class has a keywords attribute, which is a multi-valued attribute replicated to each global catalog (GC) in the forest. 각 인스턴스의 SCP 특성에는 서비스 의 제품 GUID가 포함 되어 있습니다.The keywords attribute of each instance's SCP contains the service's product GUID. 이렇게 하면 product GUID와 일치 하는 키워드 특성이 있는 개체의 GC를 검색 하 여 다양 한 서비스 인스턴스에 대 한 모든 scp를 찾을 수 있습니다.This enables finding all of the SCPs for the various service instances by searching a GC for objects with a keywords attribute that equals the product GUID.

이 코드 예제에서는 GC에 대 한 idirectorysearch 포인터를 가져오고 Idirectorysearch:: executesearch 메서드를 사용 하 여 scp를 검색 합니다.The code example obtains an IDirectorySearch pointer to a GC, and uses the IDirectorySearch::ExecuteSearch method to search for the SCPs. GC에는 각 SCP에 대 한 부분 복제본이 포함 되어 있습니다.Be aware that the GC contains a partial replica for each SCP. 즉, 일부 SCP 특성도 포함 하지만 일부는 포함 하지 않습니다.That is, it contains some of the SCP attributes, but not all. 이 코드 예제에서는 해당 서비스 인스턴스에 대 한 호스트 서버의 DNS 이름을 포함 하는 serviceDNSName 특성에 대해 집중적으로 다룹니다.In this code example, focus on the serviceDNSName attribute, which contains the DNS name of the host server for that service instance. ServiceDNSName 는 GC에서 복제 되는 특성 중 하나가 아니므로 코드 예제에서는 2 단계 프로세스를 사용 하 여이를 검색 합니다.Because serviceDNSName is not one of the attributes replicated in a GC, the code example uses a two-step process to retrieve it. 먼저 GC 검색을 사용 하 여 SCP의 DN (고유 이름)을 가져온 다음 해당 DN을 사용 하 여 SCP에 직접 바인딩하여 serviceDNSName 속성을 검색 합니다.First, it uses the GC search to get the distinguished name (DN) of the SCP, then it uses that DN to bind directly to the SCP to retrieve the serviceDNSName property.

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;
 
}