Backing up and Restoring Domain-Based DFS Namespaces

Backing up and Restoring Domain-Based DFS Namespaces

  • Comments 4
  • Likes

I had a question for a customer recently which needed some investigation, as the seemingly “easy steps” to export and import DFSN configurations didn’t do what either of us expected.

KB969382 lists the actions to take in the event of your DFS Namespace going west. Option 2 was the one we were looking at as we wanted to create regular DFS-N backups to be used in any DFS-N related emergency.

It seemed simple enough, run this command to backup your configuration:

dfsutil root export \\domain.name\DFSN DFSN-root.txt

And when disaster strikes, just run this command to put it all back again:

dfsutil  root import set DFSN-Root.txt \\domain.name\DFSN

However, no matter what the DFS-N emergency we created in the lab, the import would always fail citing “element not found”.

The problem was that we were breaking the DFS-N root (on purpose), but the export/import scenario requires you to have a working DFS-N root. And to get that, you’d need good system-state backups of both a DC and a DFS Namespace server. Which isn’t going to provide for a fast, efficient restore scenario in a large organisation.

So I started experimenting, and it seems that the objects in AD are easily copied and imported again using ldifde – there is no attachment to the object GUIDs (like there is say in a failover cluster). And once all the objects are back in AD, all the links and targets start working again as expected.

The same applies to the share and DFSN root information in the registry – a simple ‘reg save’ followed by a ‘reg restore’ will get that information back with the registry ACLs in tact.

So, I wrote 2 scripts (each fires of a second script to run directly on the DFS Namespace servers):

  1. The scheduled backup script deployed as a scheduled task to a central management server
  2. A restore script to be used in the case of any DFS-N emergency

Now, while the restore could be more targeted to allow you to chose the scenario to recover from (e.g. restore ONLY the objects in AD or DFS-N registry information on just 1 DFS-N server, or only one DFS-N root), I’ll leave it to you good reader to add that intelligence. This restore script restore the entire DFS-N configuration for all roots and to all DFS-N servers.

This will backup and restore both Windows 2000/2003 roots and Windows Server 2008 roots. It uses psexec from Sysinternals, available here. The reason it does this is to use reg save/reg restore, which capture ACLs on the registry keys and restores exactly the configuration which was backed up, rather than merging the configuration. While my testing shows that these reg keys do not have explicit permissions defined, you’re better safe than sorry.

Make sure and change any instances of “dc=domain,DC=name” and “\\domain.name” to the domain name in your environment.

Backup

Main Job

rem Setup input file

if not exist .\backupfiles mkdir .\backup-files
if exist root-servers.txt del root-servers.txt

setlocal

if exist servers.txt del servers.txt
dsquery * "CN=DFS-Configuration,CN=System,DC=domain,dc=name" -filter "(|(objectClass=fTDfs)(objectClass=msDFS-Namespacev2))" -attr name > allRoots.txt
for /F "tokens=1-3 skip=1 delims= " %%i IN (allRoots.txt) DO (
        dfsutil root \\domain.name\%%i | find /i "target" | find /i "%%i" >> %%i-serversRAW.txt
        for /F "tokens=2 delims=\" %%u IN (%%i-serversRAW.txt) do  echo %%i;%%u >> root-servers.txt
        del %%i-serversRAW.txt
        )

for /F "tokens=1,2 delims=; " %%i IN (root-servers.txt) DO echo %%j>> serversRAW.txt
sort serversRAW.txt /O serversSORTED.txt
for /F "Tokens=*" %%s in ('type serversSORTED.txt') do set record=%%s&call :output

del serversRAW.txt
del serversSORTED.txt

endlocal
 

rem Backup

for /F %%i IN (servers.txt) DO (
    if not exist \\%%i\c$\temp mkdir \\c$\temp
    copy .\NSserverBackup.bat \\%%i\c$\temp /Y
    psexec \\%%i C:\temp\NSserverBackup.bat
    copy \\%%i\c$\TEMP\%%i-dfsroots.hiv .\backup-files\%%i-dfsroots.hiv /Y
    copy \\%%i\c$\TEMP\%%i-CCS-shares.hiv .\backup-files\%%i-CCS-shares.hiv /Y
    copy \\%%i\c$\TEMP\%%i-CS1-shares.hiv .\backup-files\%%i-CS1-shares.hiv /Y
    )

ldifde -f .\backup-files\dfs-export.ldf -v -d "CN=Dfs-Configuration,CN=System,DC=domain,dc=name" -l objectClass,remoteServerName,pKTGuid,pKT,msDFS-SchemaMajorVersion,msDFS-SchemaMinorVersion,msDFS-GenerationGUIDv2,msDFS-NamespaceIdentityGUIDv2,msDFS-LastModifiedv2,msDFS-Propertiesv2,msDFS-TargetListv2,msDFS-Ttlv2,msDFS-LinkPathv2,msDFS-LinkSecurityDescriptorv2,msDFS-Ttlv2,msDFS-Commentv2,msDFS-ShortNameLinkPathv2,msDFS-LinkIdentityGUIDv2 > .\backup-files\ldf-export.log

goto :EOF

:output
if not defined previous_record goto write
if "%record%" EQU "%previous_record%" goto :EOF

:write
@echo %record%>>servers.txt
set previous_record=%record%

NSserverBackup.bat

C:
cd \
cd temp

reg save HKLM\Software\Microsoft\Windows\DFS\Roots C:\TEMP\%COMPUTERNAME%-dfsroots.hiv /y
reg save HKLM\System\CurrentControlSet\Services\lanmanserver\shares C:\temp\%COMPUTERNAME%-CCS-shares.hiv /y
reg save HKLM\System\ControlSet001\Services\lanmanserver\shares C:\temp\%COMPUTERNAME%-CS1-shares.hiv /y

The main backup job copies NSserverBackup.bat to each Namespace server and runs it from there.

 

Restore

Main Job

rem Check input files

if not exist allRoots.txt goto :EOF
if not exist servers.txt goto :EOF


rem clean up before restore

dsquery * "CN=DFS-Configuration,CN=System,DC=DC=domain,dc=name" -filter "(|(objectClass=fTDfs)(objectClass=msDFS-NamespaceAnchor))" | dsrm -q -subtree -noprompt
for /F %%i IN (servers.txt) DO (
               reg delete \\%%i\HKLM\Software\Microsoft\Windows\DFS\Roots /f
               reg delete \\%%i\HKLM\System\CurrentControlSet\Services\lanmanserver\shares /f
               reg delete \\%%i\HKLM\System\ControlSet001\Services\lanmanserver\shares /f
               reg add \\%%i\HKLM\Software\Microsoft\Windows\DFS\Roots /f
               reg add \\%%i\HKLM\System\CurrentControlSet\Services\lanmanserver\shares /f
               reg add \\%%i\HKLM\System\ControlSet001\Services\lanmanserver\shares /f
               )

rem restore

ldifde -I -f .\backup-files\dfs-export.ldf -k -v > .\backup-files\dfs-import.log
for /F %%i IN (servers.txt) DO (
        copy .\backup-files\%%i-dfsroots.hiv \\%%i\c$\temp\%%i-dfsroots.hiv /Y
        copy .\backup-files\%%i-CCS-shares.hiv \\%%i\c$\temp\%%i-CCS-shares.hiv /Y
        copy .\backup-files\%%i-CS1-shares.hiv \\%%i\c$\temp\%%i-CS1-shares.hiv /Y
    copy .\NSserverRestore.bat \\%%i\c$\temp\NSserverRestore.bat /Y
    copy .\allRoots.txt \\%%i\c$\temp\allRoots.txt /Y
    )
psexec @servers.txt C:\temp\NSserverRestore.bat

NSserverRestore.bat

reg restore HKLM\Software\Microsoft\DFS\Roots C:\temp\%COMPUTERNAME%-dfsroots.hiv
reg restore HLLM\System\CurrentControlSet\Services\lanmanserver\shares C:\temp\%COMPUTERNAME-CSS-shares.hiv
reg restore HLLM\System\ControlSet001\Services\lanmanserver\shares C:\temp\%COMPUTERNAME-CS1-shares.hiv
for /F "tokens=1-3 skip=1 delims= " %%i IN (allRoots.txt) DO dfsutil root forcesync \\domain.name\%%i
net stop dfs && net start dfs

The main backup job copies NSserverRestore.bat to each Namespace server and runs it from there.

Comments
  • Made it work, thanks for the great post man. It is awesome

  • @Aldo - great to hear, thanks for the feedback

  • Thanks Craig, this helped me a lot and saved me sometime :-)

  • as per: http://support.microsoft.com/kb/969382
    It will fail on element not found if you don't create the root first "Attempting the import before the root has been created will result in the error "Element not found." "

    Hope this helps someone - but great info nevertheless.

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment