DetailPage-MSS-KB

Microsoft small business knowledge base

Article ID: 973840 - Last Review: May 12, 2014 - Revision: 5.0

On This Page

INTRODUCTION

This article is for OEMs or customers who are interested in how to use Windows Server 2008 or Windows Storage Server 2008 as a network file system (NFS) File Server for UNIX clients in an environment where the Active Directory service does not exist. The article contains guidance about how to script the configuration of all the necessary components to enable user account mapping between the UNIX client and the Windows-based server.

More information

The scripts work in the following two phases.

Phase 1:

The first phase sets up the Active Directory Lightweight Directory Services (AD LDS) instance and configures the NFS that is required to support the user mapping service.

Some OEMs that ship Windows Storage Server 2008 may preconfigure the AD LDS service as part of their factory install process.

Customers who need to take advantage of the AD LDS service can use the same scripts to automate the configuration that is required for Windows Server 2008.

Phase 2:

The second phase creates local users and groups to match the AD LDS objects. This is typically done by the customer as a process to export and import the users for the UNIX clients to establish the appropriate account mapping in reference to the Windows-based server.

OEM or Customer side (Phase1)

OEMs or customers who install the service require the following files.

The factory-setup-adlds.cmd file

To create the factory-setup-adlds.cmd file, copy the following text into a Notepad file, and then save the text file with the name, factory-setup-adlds.cmd.
setlocal enabledelayedexpansion
set opt_insecure=0

for %%i in (%*) do (
if %%i equ insecure set opt_insecure=1
) 

rem === create set-defaultnamingcontext.ldf
echo dn: CN=NTDS Settings,CN=%COMPUTERNAME%$NFSInstance,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=X> set-defaultnamingcontext.ldf
echo changetype: modify>> set-defaultnamingcontext.ldf
echo replace: msDS-DefaultNamingContext>> set-defaultnamingcontext.ldf
echo msDS-DefaultNamingContext: CN=nfs,DC=nfs>> set-defaultnamingcontext.ldf
echo ->> set-defaultnamingcontext.ldf

rem === Install the ADAM role 
start /w servermanagercmd -i FS-NFS-Services
start /w servermanagercmd -i ADLDS 

rem === Create a ADAM instance for use by Services for NFS named NFSInstance 
%systemroot%\ADAM\adaminstall.exe /answer:nfs-instance-answer.txt 

rem === Set the default naming context 
ldifde -i -f set-defaultnamingcontext.ldf -s localhost:389 -c "cn=Configuration,dc=X" #configurationNamingContext 

rem === Extend the schema to add the uidNumber/gidNumber attributes to the user 
rem === class and the gidNumber attribute to the group class 
ldifde -i -f add-uidnumber-gidnumber.ldf -s localhost:389 -c "cn=Configuration,dc=X" #configurationNamingContext 

rem === Add Users container object 
ldifde -i -f add-users-container.ldf -s localhost:389 

rem === Provide read access to the NFS instance 
dsacls \\localhost:389\CN=nfs,DC=nfs /G everyone:GR /I:T 
if "!opt_insecure!" equ "1" ( 
dsacls \\localhost:389\CN=nfs,DC=nfs /G "anonymous logon":GR /I:T 
ldifde -i -f change-dsheuristics.ldf -s localhost:389 -j . -c "cn=Configuration,dc=X" #configurationNamingContext 
)

rem === Configure the Services for NFS mapping source to use ADAM
nfsadmin mapping config adlookup=yes addomain=%COMPUTERNAME%:389 

rem === Cleanup generated file
del set-defaultnamingcontext.ldf

The add-uidnumber-gidnumber.ldf file

To create the add-uidnumber-gidnumber.ldf file, copy the following text into a Notepad file, and then save the text file with the name, add-uidnumber-gidnumber.ldf.
dn: CN=User,CN=Schema,CN=Configuration,DC=X
changetype: ntdsSchemaModify
add: mayContain
mayContain: 1.3.6.1.1.1.1.0
mayContain: 1.3.6.1.1.1.1.1
-

dn: CN=Group,CN=Schema,CN=Configuration,DC=X
changetype: ntdsSchemaModify
add: mayContain
mayContain: 1.3.6.1.1.1.1.1
-

dn:
changetype: ntdsSchemaModify
add: schemaUpdateNow
schemaUpdateNow: 
-

The add-users-container.ldf file

To create the add-users-container.ldf file, copy the following text into a Notepad file, and then save the text file with the name, add-users-container.ldf.
dn: CN=Users,CN=nfs,DC=nfs
changetype: add
cn: Users
objectClass: container

The change-dsheuristics.ldf file

To create the change-dsheuristics.ldf file, copy the following text into a Notepad file, and then save the text file with the name, change-dsheuristics.ldf.
dn: CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=X
changetype: modify
replace: dsHeuristics
dsHeuristics: 0000002001001
-

The nfs-instance-answer.txt file

To create the nfs-instance-answer.txt file, copy the following text into a Notepad file, and then save the text file with the name, nfs-instance-answer.txt.
[ADAMInstall]
; The following line specifies to install a unique ADAM instance.
InstallType=Unique
; The following line specifies the name to be assigned to the new instance.
InstanceName=NFSInstance
; The following line specifies the communications port to use for LDAP.
LocalLDAPPortToListenOn=389
; The following line specifies an application partition to create
NewApplicationPartitionToCreate="cn=nfs,dc=nfs"
; The following line specifies the directory to use for ADAM data files.
;DataFilesPath=C:\Program Files\Microsoft ADAM\NFSInstance\data
; The following line specifies the directory to use for ADAM log files.
;LogFilesPath=C:\Program Files\Microsoft ADAM\NFSInstance\data
; The following line specifies the .ldf files to import into the ADAM schema.
ImportLDIFFiles="ms-inetorgperson.ldf" "ms-user.ldf" "MS-AdamSchemaW2K8.ldf"
The factory-setup-adlds.cmd script performs the following operations:
  1. It generates an ldf file to specify a default-naming context for the ADLDS instance that will be created later.
  2. It installs the NFS and AD LDS roles on the Windows Server 2008-based or Windows Storage Server 2008-based server.
  3. It creates a new AD LDS instance by using the nfs-instance-answer.txt file.

    Note This instance is named NFSInstance, the partition is "cn=nfs,dc=nfs," the instance runs on port 389, and the schema is extended with the following attributes:
    • ms-inetorgperson
    • ms-user
    • ms-adamschemaw2k8
  4. The set-defaultnamingcontext.ldf file that was generated in step 1 sets the default naming context of the NFSInstance instance.
  5. The add-uidnumber-gidnumber.ldf file extends the schema. To do this, it adds the uidNumber and gidNumber attributes to the user and group classes.
  6. The add-users-container.ldf file is used to add a container object that is called Users to hold user objects and group objects that customers will import.
  7. Security settings on the NFSInstance instance are changed to enable Read permissions to the Everyone group.
  8. If insecure was specified as a command-line argument when the factory-setup-adlds.cmd script was run, the security on the NFSInstance instance is relaxed further to allow for nonlocal access to the instance.

    Note Typically, you do not have to add the insecure parameter in most common scenarios.
  9. The NFS mapping source is set to use the NFSInstance instance.
In phase 1, follow these steps:
  1. Copy the factory-setup-adlds.cmd file together with the following related files to the computer on which you run NFS:
    • add-uidnumber-gidnumber.ldf
    • add-users-container.ldf
    • change-dsheuristics.ldf
    • nfs-instance-answer.txt
  2. Run the factory-setup-adlds.cmd file.
After you run the factory-setup-adlds.cmd file, the NFSInstance instance is ready to have user objects and group objects imported.

Customer side (Phase2)

On the customer side, the following script is required

The nfs-adlds-config.js script

To create this file, copy the following script into a Notepad file, and then save the text file with the name, nfs-adlds-config.js.
var passwdFilename, groupFilename;
var passwdFile, groupFile;
var pStr, gStr;
var pLines, gLines;
var pFields, gFields;
var executeCommands = false;

var fso = new ActiveXObject ("Scripting.FileSystemObject");




args = WScript.Arguments;

namedArgs = WScript.Arguments.Named;


passwdFilename = namedArgs.Item("passwd");
groupFilename = namedArgs.Item("group");
ldifFilename = namedArgs.Item("ldf");
usercmdFilename = namedArgs.Item("usercmd");
logFilename = namedArgs.Item("log");
userPassword = namedArgs.Item("userpassword");


for (i = 0; i < args.length; i++)
    {
    if (args(i) == "/execute")
        executeCommands = true;
    }



function Print (x)
    {
    WScript.Echo (x);
    }



function Usage ()
    {
    Print (WScript.ScriptName + " /passwd:passwdfile /group:groupfile /ldf:out.ldf\n" +
           "    /usercmd:generateusers.cmd [/execute] [/log:logname]\n" +
           "\n" +
           "/passwd       - location of passwd file\n" +
           "/group        - location of group file\n" +
           "/ldf          - output generated ldf file\n" +
           "/usercmd      - output cmd file to generate local users and groups\n" +
           "/userpassword - provide a password to be used for all user accounts created\n" +
           "/execute      - import user objects to ADAM using the generated files\n" +
           "/log          - specify a filename to log operations\n" +
           "\n" +
           "Both /passwd and /group must be specified.\n" +
           "At least one of /ldf or /usercmd must be specified.\n" +
           "If /userpassword is not specified all local accounts created must have\n" +
           "passwords set manually before NFS mapping will succeed.\n");
    }


function ValidatePasswdGroup ()
    {
    var i, j;

    for (i = 0; i < pLines.length; i++)
        {
        pFields = pLines[i].split(":");

        if (0 == pFields[0].length)
            continue;

        for (j = 0; j < gLines.length; j++)
            {
            gFields = gLines[j].split(":");

            if (0 == gFields[0].length)
                continue;

            if (pFields[0] == gFields[0])
                {
                Print ("The name " + pFields[0] + " occurs in both passwd and group files\n\n");

                return false;
                }
            }
        }

    return true;
    }


function GenerateLdif (s)
    {
    var i;

    for (i = 0; i < pLines.length; i++)
        {
        pFields = pLines[i].split(":");

        if (0 == pFields[0].length)
            continue;

        s.Write ("dn: CN=" + pFields[0] + ",CN=Users,CN=nfs,DC=nfs\n");
        s.Write ("changetype: add\n");
        s.Write ("cn: " + pFields[0] + "\n");
        s.Write ("objectClass: user\n");
        s.Write ("uidNumber: " + pFields[2] + "\n");
        s.Write ("gidNumber: " + pFields[3] + "\n");
        s.Write ("sAMAccountName: " + pFields[0] + "\n");
        s.Write ("\n");
        }

    for (i = 0; i < gLines.length; i++)
        {
        gFields = gLines[i].split(":");

        if (0 == gFields[0].length)
            continue;

        s.Write ("dn: CN=" + gFields[0] + ",CN=Users,CN=nfs,DC=nfs\n");
        s.Write ("changetype: add\n");
        s.Write ("cn: " + gFields[0] + "\n");
        s.Write ("objectClass: group\n");
        s.Write ("gidNumber: " + gFields[2] + "\n");
        s.Write ("sAMAccountName: " + gFields[0] + "\n");
        s.Write ("\n");
        }
    }


function GenerateUserGroupCmd (s)
    {
    var i, j;

    if (!userPassword || 0 == userPassword.length)
        {
        Print ("WARNING: No /userpassword option was specified, after local accounts\n" +
               "are created, passwords must be set on these accounts manually before\n" +
               "they can be used for ADLDS mapping for NFS components.\n");
        }


    //
    // Create local groups based on group file
    //
    for (i = 0; i < gLines.length; i++)
        {
        gFields = gLines[i].split(":");

        if (0 == gFields[0].length)
            continue;

        s.Write ("net localgroup " + gFields[0] +
                 " /add /comment:\"Group for GID:" + gFields[2] + "\"\n");
        }
    s.Write ("\n");


    //
    // Create local users from passwd file
    //
    for (i = 0; i < pLines.length; i++)
        {
        pFields = pLines[i].split(":");

        if (0 == pFields[0].length)
            continue;

        if (userPassword && 0 != userPassword.length)
            {
            s.Write ("net user " + pFields[0] + " /add /comment:\"User for UID:" +
                     pFields[2] + " GID:" + pFields[3] + "\" && net user " + pFields[0] + " " + userPassword + "\n");
            }
        else
            {
            s.Write ("net user " + pFields[0] + " /add /comment:\"User for UID:" +
                     pFields[2] + " GID:" + pFields[3] + "\"\n");
            }

        //
        // Add users to their primary groups
        //
        for (j = 0; j < gLines.length; j++)
            {
            gFields = gLines[j].split(":");

            if (0 == gFields[0].length)
                continue;

            if (gFields[2] == pFields[3])
                {
                s.Write ("net localgroup " + gFields[0] + " " + pFields[0] +
                         " /add\n");
                }
            }

        s.Write ("\n");
        }
    s.Write ("\n");


    //
    // Add users to supplementary groups
    //
    for (i = 0; i < gLines.length; i++)
        {
        gFields = gLines[i].split(":");

        if (4 == gFields.length && 0 != gFields[3].length)
            {
            supUsers = gFields[3].split(",");

            for (j = 0; j < supUsers.length; j++)
                {
                s.Write ("net localgroup " + gFields[0] + " " + supUsers[j] + " /add\n");
                }
            }
        }
    s.Write ("\n");
    }






if (!passwdFilename || !groupFilename ||
    (!ldifFilename && !usercmdFilename))
    {
    Usage ();
    }
else
    {
    passwdFile = fso.OpenTextFile (passwdFilename, 1);
    groupFile = fso.OpenTextFile (groupFilename, 1);

    pStr = passwdFile.ReadAll ();
    gStr = groupFile.ReadAll ();

    passwdFile.Close ();
    groupFile.Close ();

    pLines = pStr.split ("\n");
    gLines = gStr.split ("\n");


    if (!ValidatePasswdGroup ())
        {
        Print ("error: passwd and group files must not have names that overlap\n" +
               "       Please edit the files to create unique names.\n");
        }
    else
        {
        if (ldifFilename)
            {
            ldifS = fso.OpenTextFile (ldifFilename, 2, true);

            GenerateLdif (ldifS);

            ldifS.Close ();
            }


        if (usercmdFilename)
            {
            usercmdS = fso.OpenTextFile (usercmdFilename, 2, true);

            GenerateUserGroupCmd (usercmdS);

            usercmdS.Close ();
            }

        if (executeCommands)
            {
            var oShell = WScript.CreateObject("WScript.Shell");
            var command = "cmd /k ";

            if (ldifFilename)
                {
                command = command + "echo Importing user objects & ldifde -i -f " + ldifFilename + " -s localhost:389 ";

                if (logFilename)
                    {
                    command = command + ">>" + logFilename + " 2>&1 ";
                    }

                command = command + "& echo command complete ";

                if (usercmdFilename)
                    {
                    command = command + "& ";
                    }
                }

            if (usercmdFilename)
                {
                command = command + "echo Creating local users & " + usercmdFilename + " ";

                if (logFilename)
                    {
                    command = command + ">>" + logFilename + " 2>&1 ";
                    }

                command = command + "& echo command complete ";
                }

            oShell.Run (command);
            }
        }

    }
In phase 2, the customer runs the nfs-adlds-config.js script. This script populates the NFSInstance instance with user objects and group objects that are based on the passwd file and the group file. Then, this script creates local users and groups to match the AD LDS objects.

Before you run the script

Copy the Nfs-adlds-config.js script to the computer that is running Server for NFS and that requires user mappings. Copy the passwd file and the group file that contain the users and groups to be mapped from a UNIX-based computer to the computer that is running Server for NFS.

Then, edit the passwd file and group file to remove the users or groups that you do not want to map. Some UNIX users and groups have identical names, such as user:root/group:root. The script will fail and prompt a warning if the passwd file and the group file contain identical names for users and groups. Therefore, these names must be changed to make sure that all names are unique. For example, you have to edit the group file and change the name of the group "root" to "rootgrp."

The nfs-adlds-config.js script performs the following operations:
  • The script takes the passwd file and the group file as input and generates an ldf file that imports all the user objects and group objects into the NFSInstance instance.
  • The script sets the uidNumber attribute and the gidNumber attribute, based on the passwd file and the group file.
  • The script generates a cmd file that contains commands to create local users and groups, and the script adds the users to their primary group.
  • The script optionally executes the commands to import user objects and group objects, and the script creates the local users and groups.

Common scenario for customers

Generally, after the script is copied, and the passwd and group files are modified, the customer must run the following command:
Nfs-adlds-config.js /passwd:passwd /group:group /ldf:users.ldf /usercmd:create-local-users-groups.cmd /execute /log:configure-adlds.txt
If the /execute argument is not specified, the users.ldf and create-local-users-groups.cmd are created. The customer can run create-local-users-groups.cmd, and then run the following command to import the users and groups into the NFSInstance instance:
ldifde -I -f users.ldf -s localhost:389
After customers run the script, customers must set passwords for the local users that were created, based on whatever password policy that they use in their environment, for the local users. Or, you must specify the /userpassword argument when you run the nfs-adlds-config.js script. This argument helps you generate a password that can be used for all user accounts. Until a password is specified, the user accounts are not active, and the Server for NFS component cannot use these accounts.

Applies to
  • Windows Server 2008 Datacenter
  • Windows Server 2008 Enterprise
  • Windows Server 2008 Standard
Keywords: 
kbexpertiseadvanced kbsurveynew kbinfo KB973840
Share
Additional support options
Ask The Microsoft Small Business Support Community
Contact Microsoft Small Business Support
Find Microsoft Small Business Support Certified Partner
Find a Microsoft Store For In-Person Small Business Support