Compartilhar via


Detectando o mestre de esquema

Os Serviços de Domínio Active Directory têm um sistema de atualização com vários mestres; Cada controlador de domínio contém uma cópia gravável do diretório. As atualizações de esquema são propagadas para todos os domínios que pertencem à mesma árvore ou floresta. Como é difícil reconciliar atualizações conflitantes com o esquema, as atualizações de esquema só podem ser executadas em um único servidor. O servidor com o direito de realizar atualizações pode mudar, mas apenas um servidor terá esse direito a qualquer momento. Esse servidor é chamado de mestre de esquema. O primeiro controlador de domínio instalado em uma empresa é, por padrão, o mestre de esquema.

As alterações de esquema só podem ser feitas no nível mestre de esquema. Para detectar qual controlador de domínio é o mestre de esquema, execute as etapas a seguir.

Detectando o mestre de esquema de DC

  1. Leia o atributo fsmoRoleOwner do contêiner de esquema em qualquer DC. O atributo fsmoRoleOwner retorna o nome distinto (DN) do objeto nTDSDSA para o mestre de esquema.
  2. Vincule-se ao objeto nTDSDSA cujo DN você acabou de recuperar. O pai desse objeto é o objeto de servidor para o controlador de domínio que contém o mestre de esquema.
  3. Obtenha o ADsPath para o pai do objeto nTDSDSA . O pai é um objeto de servidor.
  4. Vincular ao objeto do servidor.
  5. Obtenha o atributo dNSHostName do objeto de servidor. Esse é o nome DNS do controlador de domínio que contém o mestre de esquema.
  6. Especifique o nome DNS do mestre de esquema como o servidor e o DN como o DN do contêiner de esquema a ser vinculado ao mestre de esquema. Por exemplo, se o servidor fosse "dc1.fabrikam.com" e o DN do contêiner de esquema fosse "cn=schema,cn=configuration,dc=fabrikam,dc=com", o ADsPath seria o seguinte.
    LDAP://dc1.fabrikam.com/cn=schema,cn=configuration,dc=fabrikam,dc=com
    

É recomendável localizar o mestre de esquema e vinculá-lo para fazer alterações no esquema. No entanto, você pode mover o mestre de esquema para outro servidor.

Para tornar outro servidor o mestre de esquema, um usuário adequadamente privilegiado pode:

  • Use o snap-in MMC do Gerenciador de Esquemas.

    Observação

    O snap-in MMC do Esquema do Active Directory deve ser registrado manualmente. Para registrar o snap-in Esquema, você deve executar o seguinte comando no prompt de comando no diretório System32 do Windows.

    regsvr32.exe schmmgmt.dll

     

  • Use o utilitário de linha de comando NTDSUTIL.

  • Use um aplicativo de terceiros (um aplicativo que emite a gravação LDAP apropriada).

Para se tornar o mestre de esquema programaticamente, um aplicativo em execução no contexto de um usuário adequadamente privilegiado pode emitir uma gravação LDAP do atributo operacional becomeSchemaMaster para o rootDSE nesse DC. Isso inicia uma transferência atômica do direito mestre de esquema do titular atual para o DC local.

O exemplo de código a seguir localiza o mestre de esquema. A função a seguir se vincula ao contêiner de esquema no computador que é o mestre de esquema.

HRESULT BindToSchemaMaster(IADsContainer **ppSchemaMaster)
{
HRESULT hr = E_FAIL;
// Get rootDSE and the schema container DN.
IADs *pObject = NULL;
IADs *pTempSchema = NULL;
IADs *pNTDS = NULL;
IADs *pServer = NULL;
BSTR bstrParent;
LPOLESTR szPath = new OLECHAR[MAX_PATH];
VARIANT var, varRole,varComputer;
hr = ADsOpenObject(L"LDAP://rootDSE",
         NULL,
         NULL,
         ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
         IID_IADs,
         (void**)&pObject);
if (hr == S_OK)
{
  hr = pObject->Get(CComBSTR("schemaNamingContext"), &var);
  if (hr == S_OK)
  {
    wcscpy_s(szPath,L"LDAP://");
    wcscat_s(szPath,var.bstrVal);
    hr = ADsOpenObject(szPath,
             NULL,
             NULL,
             ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
             IID_IADs,
             (void**)&pTempSchema);
 
    if (hr == S_OK)
    {
      /*
      Read the fsmoRoleOwner attribute to identify which server is 
      the schema master.
      */  
      hr = pTempSchema->Get(CComBSTR("fsmoRoleOwner"), &varRole);
      if (hr == S_OK)
      {
        // The fsmoRoleOwner attribute returns the nTDSDSA object.
        // The parent is the server object.
        // Bind to NTDSDSA object and get parent.
        wcscpy_s(szPath,L"LDAP://");
        wcscat_s(szPath,varRole.bstrVal);
        hr = ADsOpenObject(szPath,
             NULL,
             NULL,
             ADS_SECURE_AUTHENTICATION,
             IID_IADs,
             (void**)&pNTDS);
        if (hr == S_OK)
        {
          hr = pNTDS->get_Parent(&bstrParent);
          if (hr == S_OK)
          {
            /*
            Bind to server object and get the DNS name of 
            the server.
            */
            wcscpy_s(szPath,bstrParent);
            hr = ADsOpenObject(szPath,
               NULL,
               NULL,
               ADS_SECURE_AUTHENTICATION,
               IID_IADs,
               (void**)&pServer);
            if (hr == S_OK)
            {
              // Get the dns name of the server.
              hr = pServer->Get(CComBSTR("dNSHostName"), 
                  &varComputer);
              if (hr == S_OK)
              {
                    wcscpy_s(szPath,L"LDAP://");
                    wcscat_s(szPath,varComputer.bstrVal);
                    wcscat_s(szPath,L"/");
                    wcscat_s(szPath,var.bstrVal);
                    hr = ADsOpenObject(szPath,
                         NULL,
                         NULL,
                         ADS_SECURE_AUTHENTICATION,
                         IID_IADs,
                         (void**)ppSchemaMaster);
                    if (FAILED(hr))
                    {
                      if (*ppSchemaMaster)
                      {
                        (*ppSchemaMaster)->Release();
                        (*ppSchemaMaster) = NULL;
                      }
                    }
              }
              VariantClear(&varComputer);
            }
            if (pServer)
              pServer->Release();
          }
          SysFreeString(bstrParent);
        }
        if (pNTDS)
          pNTDS->Release();
      }
      VariantClear(&varRole);
    }
    if (pTempSchema)
      pTempSchema->Release();
  }
  VariantClear(&var);
}
if (pObject)
    pObject->Release();
 
return hr;
}

O exemplo de código a seguir exibe o nome DNS do computador que é o mestre de esquema.

On Error Resume Next
 
'''''''''''''''''''
' Bind to the rootDSE
''''''''''''''''''''
sPrefix = "LDAP://"
Set root= GetObject(sPrefix & "rootDSE")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method"
End If
 
'''''''''''''''''''
' Get the DN for the schema
''''''''''''''''''''
sSchema = root.Get("schemaNamingContext")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on Get method"
End If
 
'''''''''''''''''''
' Bind to the schema container
''''''''''''''''''''
Set Schema= GetObject(sPrefix & sSchema )
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method to bind to schema"
End If
''''''''''''''''''''
' Read the fsmoRoleOwner attribute to see which server is the 
' schema master.
''''''''''''''''''''
sMaster = Schema.Get("fsmoRoleOwner")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on IADs::Get method for fsmoRoleOwner"
End If
''''''''''''''''''''
' The fsmoRoleOwner attribute returns the nTDSDSA object.
' The parent is the server object.
' Bind to NTDSDSA object and get the parent object.
''''''''''''''''''''
Set NTDS = GetObject(sPrefix & sMaster)
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method for NTDS"
End If
sServer = NTDS.Parent
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on IADs::get_Parent method"
End If
''''''''''''''''''''
' Bind to server object
' and get the reference to the computer object.
''''''''''''''''''''
Set Server = GetObject(sServer)
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method for " & sServer
End If
sComputer = Server.Get("dNSHostName")
''''''''''''''''''''
' Display the DNS name for the computer.
''''''''''''''''''''
strText = "Schema master has the following DNS name: "& sComputer
WScript.echo strText
 
 
 
''''''''''''''''''''
' Display subroutines
''''''''''''''''''''
 
Sub BailOnFailure(ErrNum, ErrText)
    strText = "Error 0x" & Hex(ErrNum) & " " & ErrText
    MsgBox strText, vbInformation, "ADSI Error"
    WScript.Quit
End Sub