다음을 통해 공유


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

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

원래 KB 번호: 312403

Distributed Link Tracking Server 서비스와 Distributed Link Tracking Client 서비스를 사용하여 NTFS 형식으로 포맷된 파티션의 파일에 대한 링크를 추적할 수 있습니다. Distributed Link Tracking은 셸 바로 가기 및 OLE 링크와 같은 NTFS 볼륨 파일에 대한 링크가 만들어지는 시나리오에서 링크를 추적합니다. 해당 파일의 이름이 변경되거나 같은 컴퓨터의 다른 볼륨으로 이동되거나 다른 컴퓨터로 이동되거나 유사한 시나리오로 이동되는 경우, Windows는 파일을 찾기 위해 배포된 링크 추적(Distributed Link Tracking)을 사용합니다. 이동된 링크에 접근할 때, 분산 링크 추적 기능은 그 링크를 찾아냅니다; 당신은 파일이 이동되었다는 것과, 그 이동된 파일을 찾는 데 분산 링크 추적 기능이 사용된다는 사실을 모릅니다.

분산 링크 추적은 클라이언트 서비스와 서버 서비스를 포함합니다. Distributed Link Tracking Server 서비스는 Windows Server 기반 도메인 컨트롤러에서만 실행됩니다. 이는 Active Directory에 정보를 저장하고, 분산 링크 추적 클라이언트 서비스를 지원하기 위한 서비스를 제공합니다. 분산 링크 추적 클라이언트 서비스는 작업 그룹 환경에 있는 컴퓨터들이나 작업 그룹에 속하지 않은 컴퓨터들을 포함하여 모든 Windows 2000 기반 및 Microsoft Windows XP 기반 컴퓨터에서 실행됩니다. 분산 링크 추적 서버와의 유일한 상호 작용을 제공합니다.

배포된 링크 추적 클라이언트는 때때로 배포된 링크 추적 서버 서비스에 파일 링크에 대한 정보를 제공합니다. 배포된 링크 추적 서버 서비스는 이 정보를 Active Directory에 저장합니다. Distributed Link Tracking 클라이언트는 셸 바로 가기나 OLE 링크를 해결할 수 없는 경우 그 정보를 Distributed Link Tracking Server 서비스에 문의할 수도 있습니다. 분산 링크 추적 클라이언트는 30일마다 링크를 업데이트하도록 분산 링크 추적 서버에 요청합니다. 분산 링크 추적 서버 서비스는 90일 동안 업데이트되지 않은 개체를 정리합니다.

링크에 의해 참조되는 파일이 다른 볼륨으로 이동될 때(컴퓨터가 동일하거나 다른 경우에도), 분산 링크 추적 클라이언트는 분산 링크 추적 서버에 알리며, Active Directory에 linkTrackOMTEntry 객체를 생성합니다. 도메인의 각 NTFS 볼륨마다 Active Directory에 linkTrackVolEntry 객체가 생성됩니다.

메모

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

도메인 내 컴퓨터 계정을 호스팅하는 도메인 컨트롤러와 포리스트 내 모든 글로벌 카탈로그 서버 사이에서 Distributed Link Tracking 객체가 복제됩니다. 분산 링크 추적 서버 서비스는 다음의 고유 이름 경로에 객체를 생성합니다.

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 데이터베이스 크기가 줄어들 수 있습니다. (이 동작은 객체가 Tombstone되고 가비지 수집된 후, 오프라인 조각모음 절차를 수행한 후 발생합니다.)
  • 도메인 컨트롤러 간의 복제 트래픽이 감소할 수 있습니다.

Windows 2000, Windows XP 및 Windows Server 2003에서 Distributed Link Tracking Client 서비스의 시작 값은 자동으로 설정됩니다. Windows 2000 기반 서버에서, 분산 링크 추적 서버 서비스는 기본적으로 수동으로 시작합니다. 그러나 Dcpromo.exe를 사용하여 서버를 도메인으로 승격시키면 분산 링크 추적 서버 서비스가 자동으로 시작되도록 구성됩니다.

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

Microsoft는 Windows 2000 기반 서버에서 분산 링크 추적을 사용할 때 다음 설정을 사용하는 것을 권장합니다:

  1. 모든 도메인 컨트롤러에서 분산 링크 추적 서버 서비스를 해제하십시오 (이것은 모든 Windows Server 2003 기반 서버에서의 기본 설정입니다).

    복제 오버헤드와 Active Directory에서 FileLinks 테이블이 사용하는 공간 때문에 Microsoft는 Active Directory 도메인 컨트롤러에서 분산 링크 추적 서버 서비스를 끌 것을 권장합니다. 서비스를 중지하려면 다음 방법 중 하나를 사용하십시오:

    • 서비스 스냅인(Services.msc 또는 compmgmt.msc)에서 Distributed Link Tracking Server 서비스를 더블 클릭한 다음, 시작 유형 상자에서 사용 안 함을 클릭하세요.

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

    • 모든 Windows 2000 도메인 컨트롤러를 포함하는 조직 단위의 정책 설정을 정의하십시오.

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

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

    분산 링크 추적 개체를 삭제하는 방법에 대한 자세한 내용은 이 문서의 "분산 링크 추적 개체를 삭제하는 방법" 섹션을 참조하세요. 분산 링크 추적 서버 서비스를 비활성화한 후에는 개체를 삭제할 것을 권장합니다.

    메모

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

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

      메모

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

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

    2. 가비지 컬렉션이 완료되었습니다.

    3. 당신은 Dsrepair 모드에서 Ntds.dit 파일을 조각 모음하기 위해 Ntdsutil.exe를 사용합니다.

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

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

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

  2. 해당 도메인에서 Dltpurge.vbs가 대상으로 지정한 모든 도메인 컨트롤러에서 Distributed Link Tracking Server 서비스를 중지합니다.

  3. 관리자 권한을 사용하여 Dltpurge.vbs가 대상으로 하고 있는 도메인의 도메인 컨트롤러 또는 멤버 컴퓨터의 콘솔에 로그인하세요.

  4. 다음 구문을 사용하여 명령줄에서 Dltpurge.vbs를 실행하십시오.

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

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

    • '-s'는 Distributed Link Tracking 객체를 삭제하려는 도메인 컨트롤러의 DNS 호스트 이름입니다.
    • -d는 Distributed Link Tracking 객체를 삭제하려는 도메인의 Distinguished Name 경로입니다.
  5. 객체가 무덤으로 이동되고 가비지 수집된 후, Ntds.dit 파일의 오프라인 조각 모음 절차를 수행하십시오. 더 많은 정보에 대해 쓰레기 수집 과정에 관한 기사를 읽으려면, 다음 기사 번호를 클릭하십시오. Microsoft 지식 베이스의 기사에서 확인할 수 있습니다.

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

샘플 고객 경험

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

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

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

Trey Research는 향후 10일 이내에 Windows Server 2003을 배포하고자 하나, 업그레이드를 시작하기 전에 데이터베이스 파티션에 최소 1.5GB의 사용 가능한 디스크 공간이 필요합니다. 그들은 Adprep.exe가 설치된 핫픽스와 서비스 팩에 따라 3개에서 5개의 상속된 접근제어항목(ACE)을 추가하는 것으로 알려져 있기 때문에 이만한 디스크 공간이 필요합니다. 다음 조건들은 대규모 글로벌 카탈로그 크기 또는 디스크 공간 부족에 기여합니다:

  • 조건 1: Trey Research는 Windows 2000의 초기 사용 업체였으며, 선호하는 하드웨어 공급업체로부터 받은 가장 큰 드라이브는 RAID 배열로 구성될 때 9 GB 또는 18 GB였습니다. 현재 드라이브는 크기가 두 배로 커졌으며 가격은 절반으로 줄었습니다.

  • 조건 2: 포리스트의 각 도메인에 위임된 Active Directory 통합 DNS 영역에서 DNS 스캐빈지가 활성화되지 않았습니다.

  • 조건 3: 도메인 사용자들이 도메인 내에서 컴퓨터 계정을 생성할 수 있도록 허용되었습니다. 관리자는 고아 컴퓨터 계정을 식별하고 삭제하기 위한 반복적인 프로세스를 가지고 있지 않았습니다.

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

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

  • 조건 6: 가장 큰 도메인의 CN=FileLinks,CN=System,DC=도메인 이름 컨테이너를 검토했을 때, 70만 개 이상의 분산 링크 추적 개체가 발견되었습니다. 각 Distributed Link Tracking 개체의 보안 설명자는 약 2킬로바이트(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(시스템 액세스 제어 목록)을 다시 정의하면 찾고 있는 결과를 얻을 수 있다는 것을 깨달았지만 크기 감소, 복제 오버헤드 및 가장 중요한 것은 프로덕션 환경을 미러링하는 랩 시나리오에서 프로그램/관리 호환성을 철저히 테스트할 때까지 이 절차를 구현하는 데 시간이 오래 걸릴 것이라고 결정했습니다.

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

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

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

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

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

Trey Research는 새로운 복제품 Windows 2000 기반 도메인 컨트롤러를 도메인에 승격시켰고, 컴퓨터 계정을 그들이 일반적으로 사용하는 것과 다른 조직 단위에 배치했습니다. 2일 만에 약 8,000개의 분산 링크 추적 개체가 Windows 2000 기반 도메인 컨트롤러에 존재했습니다. Trey Research는 Distributed Link Tracking을 중지하거나 서비스를 중지하도록 정책을 만들고, 그런 다음 Windows 2000 기반 도메인 컨트롤러가 호스팅하는 조직 단위에 정책을 연결했습니다. 마지막으로 Trey Research는 Dltpurge.vbs를 사용하여 나머지 분산 링크 추적 개체를 삭제하도록 표시했습니다.

DLT 객체 삭제의 해부학

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

링크 추적 개체의 경우 삭제할 개체를 표시하는 것은 제거되는 두 특성인 dscorepropagationdata 및 objectcategory에 불과합니다. 두 속성을 삭제하면 초기 34바이트를 절약할 수 있습니다. 삭제용으로 링크 추적 객체를 표시하는 과정은 또한 IS_DELETED 속성(4바이트)을 추가하고 RDN 및 "일반 이름" 속성을 망가뜨림으로써 객체를 업데이트하며, 이로 인해 각 속성이 약 80바이트 정도 증가하게 됩니다. 또한, 이 "복제 메타데이터" 속성도 이 객체에서 수행된 업데이트를 반영하기 위해 약 50바이트 만큼 증가합니다. 삭제를 위해 링크 추적 객체를 표시하면 객체는 약 200바이트 증가하게 됩니다. 삭제된 객체가 톰스톤(tombstoned) 처리되고 가비지 수집된 후, 오프라인 조각 모음을 수행할 때까지 NTDS.DIT의 크기가 줄어들지 않습니다.

메모

이 기사가 권장하는 대로 서비스를 종료하면 자동 정리가 발생하지 않습니다.

Dltpurge.vbs의 텍스트 버전

이 스크립트를 사용하려면:

  1. 이 기사에서 <Start Copy Here> 태그와 <End Copy Here> 태그 사이의 모든 텍스트를 복사한 다음, ASCII 텍스트 편집기 파일(예: 마이크로소프트 메모장 파일)에 붙여넣으세요.
  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>