Windows 기반 도메인 컨트롤러의 분산 링크 추적

이 문서에서는 Windows의 분산 링크 추적 서비스를 사용하여 NTFS 형식의 볼륨 및 서버에서 연결된 파일의 생성 및 이동을 추적하는 방법을 설명합니다.

적용 대상: Windows Server 2012 R2
원래 KB 번호: 312403

분산 링크 추적 서버 서비스 및 분산 링크 추적 클라이언트 서비스를 사용하여 NTFS 형식 파티션의 파일에 대한 링크를 추적할 수 있습니다. 분산 링크 추적은 셸 바로 가기 및 OLE 링크와 같은 NTFS 볼륨의 파일에 대한 링크가 만들어지는 시나리오에서 링크를 추적합니다. 해당 파일의 이름을 바꾸거나, 같은 컴퓨터의 다른 볼륨으로 이동하거나, 다른 컴퓨터로 이동하거나, 다른 유사한 시나리오에서 이동한 경우 Windows는 분산 링크 추적을 사용하여 파일을 찾습니다. 이동한 링크에 액세스하면 분산 링크 추적에서 링크를 찾습니다. 파일이 이동했거나 이동된 파일을 찾는 데 분산 링크 추적이 사용된다는 사실을 알지 못합니다.

분산 링크 추적은 클라이언트 서비스 및 서버 서비스로 구성됩니다. 분산 링크 추적 서버 서비스는 Windows Server 기반 도메인 컨트롤러에서만 실행됩니다. Active Directory에 정보를 저장하고 분산 링크 추적 클라이언트 서비스에 도움이 되는 서비스를 제공합니다. 분산 링크 추적 클라이언트 서비스는 작업 그룹 환경 또는 작업 그룹에 없는 컴퓨터를 포함하여 모든 Windows 2000 기반 및 Microsoft Windows XP 기반 컴퓨터에서 실행됩니다. 분산 링크 추적 서버와의 유일한 상호 작용을 제공합니다.

분산 링크 추적 클라이언트는 분산 링크 추적 서버 서비스가 Active Directory에 저장하는 파일 링크에 대한 정보를 분산 링크 추적 서버 서비스에 가끔 제공합니다. 또한 분산 링크 추적 클라이언트는 셸 바로 가기 또는 OLE 링크를 확인할 수 없는 경우 분산 링크 추적 서버 서비스에서 해당 정보를 쿼리할 수 있습니다. 분산 링크 추적 클라이언트는 분산 링크 추적 서버에 30일마다 링크를 업데이트하라는 메시지를 표시합니다. 분산 링크 추적 서버 서비스는 90일 동안 업데이트되지 않은 개체를 청소합니다.

링크에서 참조하는 파일이 다른 볼륨(동일한 컴퓨터 또는 다른 컴퓨터)으로 이동되면 분산 링크 추적 클라이언트는 Active Directory에서 linkTrackOMTEntry 개체를 만드는 분산 링크 추적 서버에 알릴 수 있습니다. linkTrackVolEntry 개체는 도메인의 모든 NTFS 볼륨에 대해 Active Directory에 만들어집니다.

참고

Windows Server 2008 이상에서는 분산 링크 추적 서버 서비스가 더 이상 Windows에 포함되지 않습니다. 따라서 Active Directory에서 개체를 안전하게 제거할 수 있습니다.

분산 링크 추적 개체는 컴퓨터 계정 및 포리스트의 모든 글로벌 카탈로그 서버를 호스팅하는 도메인의 모든 도메인 컨트롤러 간에 복제됩니다. 분산 링크 추적 서버 서비스는 다음과 같은 고유 이름 경로에 개체를 만듭니다.

CN=FileLinks,CN=System,DC= Active Directory의 도메인 이름 컨테이너

분산 링크 추적 개체는 CN=FileLinks,CN=System 폴더 아래의 다음 두 테이블에 있습니다.

  • CN=ObjectMoveTable,CN=FileLinks,CN=System,DC= 도메인 이름:

이 개체는 도메인에서 이동된 연결된 파일에 대한 정보를 저장합니다.

  • CN=VolumeTable,CN=FileLinks,CN=System,DC= 도메인 이름:

    이 개체는 도메인의 각 NTFS 볼륨에 대한 정보를 저장합니다.

분산 링크 추적 개체는 개별적으로 공간을 거의 사용하지 않지만 시간이 지남에 따라 누적될 수 있는 경우 Active Directory에서 많은 공간을 사용할 수 있습니다.

분산 링크 추적을 사용하지 않도록 설정하고 Active Directory에서 분산 링크 추적 개체를 삭제하면 다음 동작이 발생할 수 있습니다.

  • Active Directory 데이터베이스 크기를 줄일 수 있습니다(이 동작은 개체가 삭제되고 가비지가 수집된 후 오프라인 조각 모음 절차를 수행한 후에 발생함).
  • 도메인 컨트롤러 간의 복제 트래픽을 줄일 수 있습니다.

Windows 2000, Windows XP 및 Windows Server 2003에서는 분산 링크 추적 클라이언트 서비스의 시작 값이 자동으로 설정됩니다. Windows 2000 기반 서버에서 분산 링크 추적 서버 서비스는 기본적으로 수동으로 시작됩니다. 그러나 Dcpromo.exe 사용하여 서버를 도메인으로 승격하는 경우 분산 링크 추적 서버 서비스가 자동으로 시작되도록 구성됩니다.

Windows Server 2003 기반 서버의 경우 분산 링크 추적 서버 서비스는 기본적으로 사용하지 않도록 설정됩니다. Dcpromo.exe 사용하여 서버를 도메인으로 승격하는 경우 분산 링크 추적 서버 서비스가 자동으로 시작되도록 구성되지 않습니다. Windows 2000 기반 도메인 컨트롤러가 Windows Server 2003으로 업그레이드되면 업그레이드 중에 분산 링크 추적 서버 서비스도 비활성화됩니다. 관리자이고 분산 링크 추적 서버 서비스를 사용하려는 경우 그룹 정책 사용하거나 서비스를 자동으로 시작하도록 수동으로 설정해야 합니다. 또한 Windows Server 2003 또는 Windows XP SP1을 실행하는 컴퓨터의 분산 링크 추적 클라이언트 서비스는 기본적으로 분산 링크 추적 서버 서비스를 사용하지 않습니다. 분산 링크 추적 서버 서비스를 활용하도록 해당 컴퓨터를 구성하려면 분산 링크 추적 클라이언트에서 도메인 리소스를 사용하도록 허용 정책 설정을 사용하도록 설정합니다. 이렇게 하려면 그룹 정책 컴퓨터 구성/관리 템플릿/시스템 노드를 엽니다.

Windows 2000 기반 서버에서 분산 링크 추적에서 다음 설정을 사용하는 것이 좋습니다.

  1. 모든 도메인 컨트롤러에서 분산 링크 추적 서버 서비스를 끕니다(모든 Windows Server 2003 기반 서버의 기본 구성).

    복제 오버헤드 및 FileLinks 테이블이 Active Directory에서 사용하는 공간 때문에 Microsoft는 Active Directory 도메인 컨트롤러에서 분산 링크 추적 서버 서비스를 해제하는 것이 좋습니다. 서비스를 중지하려면 다음 방법 중 일부를 사용합니다.

    • 서비스 스냅인(Services.msc 또는 compmgmt.msc)에서 분산 링크 추적 서버 서비스를 두 번 클릭한 다음 시작 유형 상자에서 사용 안 함을 클릭합니다.

    • 그룹 정책의 컴퓨터 구성/Windows 설정/시스템 서비스 노드에서 시작 값을 정의합니다.

    • 모든 Windows 2000 도메인 컨트롤러를 호스트하는 조직 구성 단위에서 정책 설정을 정의합니다.

    정책이 적용되도록 정책이 복제된 후 도메인 컨트롤러를 다시 시작합니다. 도메인 컨트롤러를 다시 시작하지 않으면 각 도메인 컨트롤러에서 서비스를 수동으로 중지해야 합니다.

  2. Active Directory 도메인 컨트롤러에서 분산 링크 추적 개체를 삭제합니다.

    분산 링크 추적 개체를 삭제하는 방법에 대한 자세한 내용은 이 문서의 "분산 링크 추적 개체를 삭제하는 방법" 섹션을 참조하세요. 분산 링크 추적 서버 서비스를 사용하지 않도록 설정한 후에는 개체를 삭제하는 것이 좋습니다.

    참고

    도메인 컨트롤러의 DIT(디렉터리 정보 트리) 크기는 다음 작업이 완료될 때까지 줄어들지 않습니다.

    1. 개체는 디렉터리 서비스에서 삭제됩니다.

      참고

      삭제된 개체는 삭제 표시 수명이 만료될 때까지 Deleted Objects 컨테이너에 저장됩니다. 삭제 표시 수명에 대한 기본값은 60일입니다. 최소값은 2일입니다. 기본적으로 값은 Windows Server 2003 서비스 팩 1 이상 버전의 Windows Server 2003과 함께 설치된 새 포리스트의 경우 180일입니다.

      강력한 Active Directory 복제 모니터링이 없는 한 180일 값을 사용하는 것이 좋습니다. DIT 크기 문제를 처리하려면 이 값을 줄이지 마세요. 데이터베이스 크기에 문제가 있는 경우 Microsoft 고객 지원 서비스에 문의하세요.

    2. 가비지 수집이 완료될 때까지 실행되었습니다.

    3. Ntdsutil.exe 사용하여 Dsrepair 모드에서 Ntds.dit 파일을 조각 모음합니다.

이러한 개체에서 사용 중인 디스크 공간을 최대한 빨리 회수해야 하는 경우가 아니면 분산 링크 추적 서버 서비스를 중지한 후 분산 링크 추적 개체를 수동으로 삭제하는 것은 중요하지 않습니다. 분산 링크 추적 클라이언트는 분산 링크 추적 서버에 30일마다 링크를 업데이트하라는 메시지를 표시합니다. 분산 링크 추적 서버 서비스는 90일 동안 업데이트되지 않은 개체를 청소합니다.

Dltpurge.vbs VBScript를 실행하면 분산 링크 추적 서버 서비스에서 사용하는 모든 Active Directory 개체가 스크립트가 실행되는 도메인에서 삭제됩니다. 포리스트의 각 도메인에 대해 하나의 도메인 컨트롤러에서 스크립트를 실행해야 합니다. Dltpurge.vbs 실행하려면 다음을 수행합니다.

  1. Microsoft 제품 지원에서 Dltpurge.vbs 스크립트를 가져옵니다.

  2. Dltpurge.vbs 대상으로 하는 도메인의 모든 도메인 컨트롤러에서 분산 링크 추적 서버 서비스를 중지합니다.

  3. 관리자 권한을 사용하여 도메인 컨트롤러의 콘솔 또는 Dltpurge.vbs 대상으로 하는 도메인의 구성원 컴퓨터에 로그온합니다.

  4. 명령줄에서 Dltpurge.vbs 실행하려면 다음 구문을 사용합니다.

    cscript dltpurge.vbs -s myserver -d dc=mydomain,dc=mycompany,dc=com  
    

    이 명령줄에서 다음을 수행합니다.

    • -s는 분산 링크 추적 개체를 삭제하려는 도메인 컨트롤러의 DNS 호스트 이름입니다.
    • -d는 분산 링크 추적 개체를 삭제하려는 도메인의 고유 이름 경로입니다.
  5. 개체가 삭제되고 가비지가 수집된 후 Ntds.dit 파일의 오프라인 조각 모음 프로시저를 수행합니다. 가비지 수집 프로세스에 대한 자세한 내용은 다음 문서 번호를 클릭하여 Microsoft 기술 자료에서 문서를 확인합니다.

    Active Directory 데이터베이스 가비지 수집 프로세스 198793

샘플 고객 환경

이 섹션에 설명된 최악의 시나리오는 대규모 프로덕션 도메인에서 많은 수의 분산 링크 추적 개체를 삭제할 때 고려해야 할 몇 가지 문제를 보여 줍니다.

전 세계 40,000명 이상의 직원을 둔 가상의 Fortune 500 고객인 Trey Research는 세계의 주요 지리적 지역(북아메리카, 아시아, 유럽 등)을 매핑하는 자식 도메인이 있는 빈 루트 도메인으로 구성된 단일 Active Directory 포리스트를 배포합니다. 포리스트에서 가장 큰 도메인에는 약 35,000개의 사용자 계정과 동일한 수의 컴퓨터 계정이 포함됩니다.

Ntds.dit 파일은 18GB(기가바이트) Raid 배열에 배치되었습니다. Windows 2000의 초기 배포 이후 글로벌 카탈로그 파일은 17GB로 증가했습니다.

Trey Research는 향후 10일 이내에 Windows Server 2003을 배포하려고 하지만 업그레이드를 시작하기 전에 데이터베이스 파티션에 1.5GB 이상의 사용 가능한 디스크 공간이 필요합니다. Adprep.exe 이전에 설치한 핫픽스 및 서비스 팩에 따라 상속된 3~5개의 에이스를 추가하는 것으로 알려져 있기 때문에 디스크 공간이 많이 필요합니다. 다음 조건은 글로벌 카탈로그 크기가 크거나 디스크 공간이 부족합니다.

  • 조건 1: Trey Research는 Windows 2000의 얼리 어답터였으며, 선호하는 하드웨어 공급업체로부터 받은 가장 큰 드라이브는 Raid 배열로 구성되었을 때 9GB 또는 18GB였습니다. 현재 드라이브는 비용의 절반 크기로 두 배입니다.

  • 조건 2: 포리스트의 각 도메인에 위임된 Active Directory 통합 DNS 영역에서 DNS 청소를 사용할 수 없습니다.

  • 조건 3: 도메인 사용자가 도메인에 컴퓨터 계정을 만들 수 있었습니다. 관리자는 분리된 컴퓨터 계정을 식별하고 삭제하는 반복 프로세스가 없었습니다.

  • 조건 4: 시간이 지남에 따라 Active Directory에서 수천 개의 개체를 호스트하는 NC(루트 명명 컨텍스트) 헤드(cn=schema, cn=configuration, cn= domain) 및 기타 컨테이너에 대한 관리자, 서비스 팩 및 핫픽스가 보안 설명자를 정의했습니다. 또한 동일한 파티션에서 감사를 사용하도록 설정했습니다. 권한을 설정하고 Active Directory의 개체에 대한 감사를 사용하도록 설정하면 데이터베이스 크기가 증가합니다. Windows Server 2003 기반 도메인 컨트롤러(Adprep)용 Windows 2000 포리스트 및 도메인을 준비하는 도구는 상속된 에이스도 추가합니다. 따라서 Trey Research는 도메인을 업그레이드하기 전에 디스크 드라이브의 공간을 확보해야 했습니다.

  • 조건 5: Trey Research는 Dsrepair 모드에서 Ntds.dit 파일의 오프라인 조각 모음 절차를 정기적으로 수행하지 않았습니다.

  • 조건 6: 가장 큰 도메인의 CN=FileLinks,CN=System,DC= 도메인 이름 컨테이너를 검토했을 때 700,000개 이상의 분산 링크 추적 개체가 표시되었습니다. 각 Distributed Link Tracking 개체의 보안 설명자는 약 2KB(KB)였습니다. 이러한 각 조건은 17GB .dit 파일에 대한 기여도에 대해 평가되었습니다.

  • 조건 1: Trey Research는 비용과 시간 때문에 새 드라이브를 배포하지 않기로 결정했습니다. 또한 Windows Server 2003으로 업그레이드하고 SIS(단일 인스턴스 저장소) 프로세스가 완료된 후 Active Directory 데이터베이스가 축소될 것으로 예상했기 때문에 디스크 공간이 일시적으로만 필요했습니다(SIS는 Active Directory 데이터베이스에서 보다 효율적인 사용 권한 스토리지를 구현).

  • 조건 2 및 3: Trey Research는 이러한 조건이 모범 사례라고 결정했습니다. 그러나 Trey Research가 구현하더라도 필요한 결과를 달성하지 못했습니다. 쉽게 구현할 수 있으므로 DNS 청소를 사용하도록 설정하기로 결정했습니다.

  • 조건 4: Trey Research는 보안 설명자와 SACL(시스템 액세스 제어 목록)을 다시 정의하면 찾고 있는 결과를 얻을 수 있다는 것을 깨달았지만, 이 절차는 크기 감소, 복제 오버헤드 및 가장 중요한 것은 프로덕션 환경을 미러링하는 랩 시나리오에서 프로그램/관리 호환성을 철저히 테스트할 수 있을 때까지 구현하는 데 시간이 오래 걸릴 것이라고 결정했습니다.

    Trey Research는 Windows 2000 SP2 및 몇 가지 핫픽스를 배포했기 때문에 Adprep(도메인 NC의 개체)에 의해 추가된 증분 상속된 에이스가 300MB(MB)만큼 작을 수 있다고 예상했습니다. 프로덕션 포리스트의 업그레이드를 테스트하는 데 사용되는 랩 환경에서 이 동작을 확인할 수 있습니다.

  • 조건 5: Trey Research는 오프라인 조각 모음 절차를 수행한 경우 Ntds.dit 파일에서 "공백"을 복구하지 못할 수 있음을 깨달았습니다. 실제로 Trey Research 관리자는 오프라인 조각 모음 절차를 완료한 직후 데이터베이스 크기가 증가하는 것을 발견했습니다. 이 동작은 Windows 2000 데이터베이스 엔진의 비효율성으로 인해 발생했습니다. 이 엔진은 Windows Server 2003에서 향상되었습니다.

  • 조건 6: Trey Research는 포리스트의 각 도메인에 있는 도메인 컨트롤러의 CN=FileLinks,CN=System,DC= 도메인 이름 컨테이너에서 모든 분산 링크 추적 개체를 단순하게 대량 삭제하는 것이 명백한 작업 과정이라는 데 동의했습니다. 그러나 이렇게 하면 개체가 삭제되고 가비지가 수집될 때까지, 그리고 해당 도메인의 각 도메인 컨트롤러에서 오프라인 조각 모음 절차를 완료할 때까지 추가 디스크 공간이 확보되지 않는다는 것을 깨달았습니다. 삭제 표시 수명 값을 2일의 낮은 값으로 설정할 수 있지만 Trey Research 포리스트의 여러 도메인 컨트롤러는 하드웨어 및 소프트웨어 업데이트를 기다리는 동안 오프라인 상태였습니다. 종단 간 복제가 수행되기 전에 개체가 삭제된 경우 삭제된 개체가 다시 애니메이션되거나 포리스트의 글로벌 카탈로그 서버 간에 일관되지 않은 데이터가 보고될 수 있습니다. 즉각적인 구호를 제공하기 위해 Trey Research는 다음 절차를 수행했습니다.

  1. 분산 링크 추적 스키마 클래스 개체에 대한 기본 보안 설명자를 제거하고 단일 보안 주체(사용자 계정)로 대체했습니다.
  2. 기존 보안 설명자를 모두 제거한 다음 단일 보안 주체에 대한 명시적 에이스로 대체하는 VBScript 프로그램을 작성했습니다.
  3. 각 개체 삭제 사이에 3시간 지연이 있는 분산 링크 추적 개체를 10,000단위 단위로 삭제했습니다.
  4. 모든 분산 링크 추적 개체가 삭제된 후 도메인의 각 도메인 컨트롤러에서 오프라인 조각 모음 절차를 수행했습니다. Trey Research가 설명자를 제거하고 조각 모음 절차를 수행했을 때 데이터베이스는 도메인의 모든 도메인 컨트롤러에서 약 1.5GB의 디스크 공간을 복구했습니다. 이 공간은 Adprep 도구를 편안하게 실행하고 모든 Windows 2000 기반 도메인 컨트롤러 및 글로벌 카탈로그를 Windows Server 2003으로 업그레이드하기에 충분했습니다.

Trey Research가 운영 체제를 Windows Server 2003으로 업그레이드한 후 Windows Server 2003의 단일 instance 저장소 기능이 데이터베이스 크기를 약 8GB로 줄이면 디스크 공간이 더 확보되었습니다(이러한 결과를 얻으려면 오프라인 조각 모음 절차를 수행해야 합니다). TSL 간격이 만료된 후 더 많은 공간이 복구되고, 분산 링크 추적 개체가 가비지 수집되었으며, 오프라인 조각 모음 절차를 수행했습니다.

Trey Research는 새로운 복제본(replica) Windows 2000 기반 도메인 컨트롤러를 도메인으로 승격하고 컴퓨터 계정을 일반적으로 사용하는 것과 다른 조직 구성 단위에 배치했습니다. 이틀 만에 Windows 2000 기반 도메인 컨트롤러에 약 8,000개의 분산 링크 추적 개체가 있었습니다. Trey Research는 분산 링크 추적을 중지하거나 서비스를 중지하는 정책을 만든 다음 Windows 2000 기반 도메인 컨트롤러를 호스트하는 조직 단위에 정책을 연결했습니다. 마지막으로 Trey Research는 Dltpurge.vbs 사용하여 삭제할 나머지 분산 링크 추적 개체를 표시했습니다.

DLT 개체 삭제 분석

DLT 개체 자체에는 몇 가지 특성이 포함되어 있으며 Active Directory에서 공간을 거의 사용하지 않습니다. 개체가 삭제(삭제)로 표시되면 Active Directory에서 제거될 때까지 개체를 추적하는 데 필요한 특성을 제외하고 모든 불필요한 특성이 제거됩니다.

링크 추적 개체의 경우 삭제할 개체를 표시하는 것은 제거되는 두 특성인 dscorepropagationdata 및 objectcategory에 불과합니다. 두 특성을 삭제하면 초기 34바이트 절감이 발생합니다. 그러나 삭제를 위해 링크 추적 개체를 표시하는 프로세스는 IS_DELETED 특성(4바이트)을 추가하고 RDN 및 "일반 이름" 특성을 망가뜨려 각 특성이 약 80바이트 증가하도록 하여 개체를 업데이트합니다. 또한 "복제 메타데이터" 특성은 이 개체에서 수행된 업데이트를 반영하기 위해 약 50바이트 증가합니다. 따라서 삭제할 링크 추적 개체를 표시하면 개체가 약 200바이트 증가합니다. NTDS입니다. DIT는 삭제된 개체가 삭제되고, 가비지 수집되고, 오프라인 조각 모음이 수행될 때까지 크기가 감소하지 않습니다.

참고

이 문서에서 권장하는 대로 서비스가 꺼져 있으면 자동 수집이 발생하지 않습니다.

텍스트 버전의 Dltpurge.vbs

이 스크립트를 사용하려면 다음을 수행합니다.

  1. 이 문서의 여기 복사> 시작 태그와 <여기에 복사 끝 태그 사이에 <있는 모든 텍스트를 복사>한 다음, ASCII 텍스트 편집기 파일(예: Microsoft 메모장 파일)에 텍스트를 붙여넣습니다.
  2. 파일을 "Dltpurge.vbs"로 저장합니다. 3 분산 링크 추적 개체를 삭제하는 방법에 설명된 절차를 완료합니다.
<Start Copy Here>
'==============================================================================
'==============================================================================
'
' Copyright (C) 2001 by Microsoft Corporation.  All rights reserved.
'
' This script deletes all Active Directory objects used by the
' Distributed Link Tracking Server service.
'
' It is assumed that the DLT Server service has been disabled,
' and you wish to recover the DIT space these objects occupy.
'
' Usage:   cscript DltPurge.vbs <options>
' Options: -s ServerName
'          -d distinguishedname dc=mydomain,dc=mycompany,dc=com
'          -b BatchSize  BatchDelayMinutes
'          -t (optional test mode)
'
' The objects are deleted in batches - BatchSize objects are deleted,
' then there is a BatchDelayMinutes delay before the next batch.
'
'==============================================================================
'==============================================================================

Option Explicit

'
' Globals, also local to main.
'
Dim oProvider
Dim oTarget
Dim sServer
Dim sDomain
Dim bTest

Dim BatchSize
Dim BatchDelayMinutes

'
' Set defaults
'

BatchSize = 1000
BatchDelayMinutes = 15
bTest = False

'==============================================================================
'
'   ProcessArgs
'
'   Parse the command-line arguments.  Results are set in global variables
'   (oProvider, oTarget, sServer, sDomain, BatchSize, and BatchDelayMinutes).
'
'==============================================================================


public function ProcessArgs

    Dim iCount
    Dim oArgs

    on error resume next

    '
    ' Get the command-line arguments
    '
    
    Set oArgs = WScript.Arguments

    if oArgs.Count > 0 then

        '
        ' We have command-line arguments.  Loop through them.
        '

        iCount = 0
        ProcessArgs = 0

        do while iCount < oArgs.Count

            select case oArgs.Item(iCount)

                '
                ' Server name argument
                '
                
                case "-s"

                    if( iCount + 1 >= oArgs.Count ) then
                        Syntax
                        ProcessArgs = -1
                        exit do
                    end if

                    sServer = oArgs.Item(iCount+1)
                    if Len(sServer) > 0 then sServer = sServer & "/"
                    iCount = iCount + 2

                '
                ' Enable testing option
                '
                
                case "-t"

                    iCount = iCount + 1
                    bTest  = True

                '
                ' Domain name option
                '
                
                case "-d"

                    if( iCount + 1 >= oArgs.Count ) then
                        Syntax
                        ProcessArgs = -1
                        Exit Do
                    end if

                    sDomain = oArgs.Item(iCount+1)
                    iCount = iCount + 2

                '
                ' Batching option (batch size, batch delay)
                '

                case "-b"

                    if( iCount + 2 >= oArgs.Count ) then
                        Syntax
                        ProcessArgs = -1
                        exit do
                    end if

                    Err.Clear
                    
                    BatchSize = CInt( oArgs.Item(iCount+1) )
                    BatchDelayMinutes = CInt( oArgs.Item(iCount+2) )
                    
                    if( Err.Number <> 0 ) then 
                        wscript.echo "Invalid value for -b argument" & vbCrLf
                        Syntax
                        ProcessArgs = -1
                        exit do
                    end if
                    
                    iCount = iCount + 3

                '
                ' Help option
                '
                
                case "-?"
                    Syntax
                    ProcessArgs = -1
                    exit do

                '
                ' Invalid argument
                '
                
                case else
                
                    ' Display the syntax and return an error

                    wscript.echo "Unknown argument: " & oArgs.Item(iCount) & vbCrLf
                    Syntax
                    ProcessArgs = -1
                    Exit Do
                    
            end select
      loop

    else
    
        '
        ' There were no command-line arguments, display the syntax
        ' and return an error.
        '

        Syntax
        ProcessArgs = -1

    end if

    Set oArgs = Nothing

end function ' ProcessArgs

'==============================================================================
'
'   Syntax
'
'   Show the command-line syntax
'
'==============================================================================

public function Syntax

    wscript.echo    vbCrLf & _
                    "Purpose:   Delete Active Directory objects from Distributed Link Tracking" & vbCrLf & _
                    "           Server service (Assumes that DLT Server has been disabled" & vbCrLf & _
                    "           on all DCs)" & vbCrLf & _
                    vbCrLf & _
                    "Usage:     " & wscript.scriptname & " <arguments>" & vbCrLf & _
                    vbCrLf & _
                    "Arguments: -s Server" & vbCrLf & _
                    "           -d FullyQualifiedDomain" & vbCrLf & _
                    "           -b BatchSize BatchDelayMinutes (default to 1000 and 15)" & vbCrLf & _
                    "           -t (optional test mode, nothing is deleted)" & vbCrLf & _
                    vbCrLf & _
                    "Note:      Objects are deleted in batches, with a delay between each" & vbCrLf & _
                    "           batch.  The size of the batch defaults to 1000 objects, and" & vbCrLf & _
                    "           the length of the delay defaults to 15 minutes.  But these" & vbCrLf & _
                    "           values can be overridden using the -b option." & vbCrLf & _
                    vbCrLf & _
                    "Example:   " & wscript.scriptname & "  -s  myserver  -d distinguishedname dc=mydomain,dc=mycompany,dc=com "

end function    ' Syntax



'==============================================================================
'
'   PurgeContainer
'
'   Delete all objects of the specified class in the specified container.
'   This subroutine is called once for the volume table and once for
'   the object move table.
'
'==============================================================================

sub PurgeContainer(ByRef oParent, ByVal strClass)

    dim oChild
    dim iBatch
    dim iTotal

    On Error Resume Next

    iTotal = 0
    iBatch = 0

    ' Loop through the children of this container

    For Each oChild in oParent

        ' 
        ' Is this a DLT object?
        '

        
        if oChild.Class = strClass Then

            '
            ' Yes, this is a DLT object, it may be deleted
            '
            
            iTotal = iTotal + 1
            iBatch = iBatch + 1

            '
            ' Delete the object
            '
            
            if bTest then
                wscript.echo "Object that would be deleted: " & oChild.adspath
            else
                oParent.Delete oChild.Class, oChild.Name
            end if

            '
            ' If this is the end of a batch, delay to let replication
            ' catch up.
            '
            
            if iBatch = BatchSize then
            
                iBatch = 0
                
                wscript.stdout.writeline "" ' ignored by wscript
                wscript.echo "Deleted " & BatchSize & " objects"
                wscript.echo "Pausing to allow processing (will restart at " & DateAdd("n", BatchDelayMinutes, Time) & ")"
                
                wscript.sleep BatchDelayMinutes * 60 * 1000
                wscript.echo "Continuing ..."
                
            end if
            
        else
        
            ' oChild.Class didn't match strClass
            wscript.echo "Ignoring unexpected class: " & oChild.Class
            
        end if

        oChild = NULL

    Next


    wscript.echo "Deleted a total of " & iTotal & " objects"

end sub ' PurgeContainer


'==============================================================================
'
' Main
'
'==============================================================================

if (ProcessArgs=-1) then wscript.quit

on error resume next

'
' Explain what's about to happen
'

wscript.stdout.writeline "" ' ignored by wscript
wscript.echo "This script will purge all objects from the Active Directory" & vbCrLf & _
             "used by the Distributed Link Tracking Server service (trksvr)." & vbCrLf & _
             "It is assumed that this service has already been disabled on" & vbCrLf & _
             "all DCs in the domain."

'
' When running in cscript, pause to give an opportunity to break out
' (These 3 lines are for cscript and ignored by wscript.)
'

wscript.stdout.writeline ""
wscript.stdout.writeline "Press Enter to continue ..."
wscript.stdin.readline

'
' Get an ADSI object
'

Set oProvider = GetObject("LDAP:")

'
' Purge the System/FileLinks/ObjectMoveTable
'

wscript.stdout.writeline "" ' ignored by wscript
wscript.echo "Purging ObjectMoveTable"

Set oTarget = oProvider.OpenDSObject( "LDAP://" & sServer  & "cn=ObjectMoveTable,CN=FileLinks,CN=System," & sDomain ,_
                                      vbNullString, vbNullString, _
                                      1) ' ADS_SECURE_AUTHENTICATION

call PurgeContainer( oTarget, "linkTrackOMTEntry" )
oTarget = NULL

'
' Purge the System/FileLinks/VolumeTable
'

wscript.stdout.writeline "" ' ignored by wscript
wscript.echo "Purging VolumeTable"

Set oTarget = oProvider.OpenDSObject("LDAP://" & sServer  & "cn=VolumeTable,CN=FileLinks,CN=System," & sDomain  ,_
                                     vbNullString, vbNullString, _
                                     1) ' ADS_SECURE_AUTHENTICATION
call PurgeContainer( oTarget, "linkTrackVolEntry" )
oTarget = NULL

oProvider = NULL
<END Copy Here>