\documentclass{ictlab}

\RCS $Revision: 1.4 $

\usepackage{key,verbatim,alltt}
\usepackage[pdfpagemode=None,pdfauthor={Nick Urbanik}]{hyperref}

\newcommand*{\labTitle}{Creating User Accounts in Windows 2000 with Perl}

\begin{document}

\subsection*{Background:}

We will use code that is for the most part written by David N.
Blank-Edelman in his excellent book, \emph{Perl for System
  Administration}, on pages 84 and 85.  I have modified it to make it
more general, in that we can use it to easily create accounts from the
data provided by the \VTC \acro{GRS} (Grade Reporting System)\@.

There are two additional Perl modules required for this, however.  We
need to download and install them.  I have downloaded one,
\texttt{Win32::Lanman}\@.  You will install the other,
\texttt{Win32::Perms} yourself using the \acro{PPM} (Perl Package
Manager) progam.  You can read about \acro{PPM} from the
\textsf{ActiveState ActivePerl} documentation.

I downloaded \texttt{Win32::Lanman} from
\url{ftp://ftp.roth.net/pub/ntperl/Others/Lanman/}. 

\subsection*{Procedure:}

\subsubsection*{Installing the two Perl modules}

\paragraph{Setting the PPM proxy:}

Set the environment variable \texttt{HTTP\_proxy} to the value
\url{http://proxy.vtc.edu.hk:8080}, or what value actually works.  To
do this:
\begin{enumerate}
\item right click on ``\texttt{My Computer}'' (No, yours, not mine).
  
\item Click on \textsf{Properties}

\item Click on \textsf{Advanced} (yes, we are advanced in so many
  ways!)
  
\item Click on \textsf{Environment Variables}
    
\item Click on the \key{\textsf{New\ldots}} button under
  \textsf{System variables}

\item in \textsf{Variable \underline{N}ame}, enter
  \texttt{HTTP\_proxy}
  
\item in \textsf{Variable \underline{V}alue}. enter the proxy that
  works for you:
  \begin{itemize}
  \item \texttt{http://hqproxy.vtc.edu.hk:8080}
  \end{itemize}

\item Click on all appropriate \key{\textsf{OK}} buttons.
\end{enumerate}


\paragraph{Installing \texttt{Win32::Lanman}}

\begin{enumerate}
\item Download
  \url{http://nicku.org/ftp/perl/lanman_1_09_1.zip} and
  unzip it into a subdirectory of \texttt{D:\bs temp}.
\item Open a command prompt and change to \texttt{D:\bs temp} (I
  assume that you have installed \textsf{ActiveState ActivePerl} from
  \url{http://nicku.org/ftp/perl/ActivePerl-5.6.1.635-MSWin32-x86.msi}).
  Any 5.6.x version of Perl will do fine, but the \texttt{Lanman}
  module does not work with 5.8.x.
\item Type (at the \texttt{C:\bs{}temp>} prompt):
\begin{alltt}
D:\bs{}temp\bs{}lanman>\textbf{ppm install win32-lanman --location=.}
Installing package 'win32-lanman'...
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}auto\bs{}win32\bs{}lanman\bs{}lanman.dll
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}auto\bs{}win32\bs{}lanman\bs{}lanman.exp
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}auto\bs{}win32\bs{}lanman\bs{}lanman.lib
Installing D:\bs{}Perl\bs{}html\bs{}site\bs{}lib\bs{}win32\bs{}lanman.html
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}win32\bs{}lanman.pm
\end{alltt}

\item Note that the documentation for the \texttt{Win32::Lanman} module is now
  installed with the documentation for \textsf{ActiveState ActivePerl}\@.
\end{enumerate}

\paragraph{Installing \texttt{Win32::Perms}}

Here we are going to use the \texttt{ppm} program to download and
install the package from Internet\@.  There is one additional
complication here: we need to install the package from David Roth's
web site instead of from the default, ActiveState's web site.
\begin{enumerate}
\item In the \texttt{Command Prompt}, type at the
  \texttt{D:\bs{}temp>} prompt:
\begin{alltt}
D:\bs{}temp> \textbf{ppm install http://www.roth.net/perl/packages/win32-perms.ppd}
\end{alltt}
You will see something like this:
\begin{alltt}
D:\bs{}temp>\textbf{ppm install http://www.roth.net/perl/packages/win32-perms.ppd}
Installing package 'http://www.roth.net/perl/packages/win32-perms.ppd'...
Downloading http://www.roth.net/perl/packages/x86/Win32/Perms_5006.tar.gz ...
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}auto\bs{}Win32\bs{}Perms\bs{}Perms.DLL
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms.PM
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms\bs{}COPY.PL
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms\bs{}History.txt
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms\bs{}noinher.pl
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms\bs{}README
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms\bs{}RECURSE.PL
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms\bs{}ShowPerm.pl
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms\bs{}TEST.PL
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms\bs{}test2.pl
Installing D:\bs{}Perl\bs{}site\bs{}lib\bs{}Win32\bs{}Perms\bs{}Win32-Perms.ppd
\end{alltt}
%% C:\temp>ppm install http://www.roth.net/perl/packages/win32-perms.ppd
%% Installing package 'http://www.roth.net/perl/packages/win32-perms.ppd'...
%% Bytes transferred: 96068
%% Installing C:\Perl\site\lib\auto\Win32\Perms\Perms.DLL
%% Installing C:\Perl\site\lib\Win32\PERMS.PM
%% Installing C:\Perl\site\lib\Win32\Perms\COPY.PL
%% Installing C:\Perl\site\lib\Win32\Perms\Dacl.pl
%% Installing C:\Perl\site\lib\Win32\Perms\NOINHER.PL
%% Installing C:\Perl\site\lib\Win32\Perms\README
%% Installing C:\Perl\site\lib\Win32\Perms\RECURSE.PL
%% Installing C:\Perl\site\lib\Win32\Perms\ShowPerm.pl
%% Installing C:\Perl\site\lib\Win32\Perms\TEST.PL
%% Installing C:\Perl\site\lib\Win32\Perms\TEST2.PL
%% Writing C:\Perl\site\lib\auto\Win32\Perms\.packlist

\item Note that the documentation for the \texttt{Win32::Perms} module
  is the file \texttt{D:\bs Perl\bs site\bs lib\bs Win32\bs Perms\bs README}
\end{enumerate}


\subsection*{The code to create user accounts}
\label{sec:user-acct-create}

This code (from David N. Blank-Edleman) implements adds a user:
\begin{verbatim}
use strict;
#*
#* basic local user account creation routine for NT/2000
#*
use Win32::Lanman;   # for account creation
use Win32::Perms;    # to set the permissions on the home directory

# our $homeNTdirs = "\\\\servername\\home";         # home directory root dir
our $homeNTdirs = "D:\\home";         # home directory root dir

# returns false if successful, true and an error message if there is a
# problem.  Rather un-Perl like, more like C.
sub CreateNTAccount
{
    my ( $account, $password, $fullname, $group ) = @_;

    # create this account on the local machine 
    # (i.e. empty first parameter)
    my $result
        = Win32::Lanman::NetUserAdd(
                                    "", 
                                    {
                                      name         => $account,
                                      password     => $password,
                                      home_dir     => "$homeNTdirs\\$account",
                                      full_name    => $fullname,
                                      # expires in 60 days from now:
                                      acct_expires => 3600 * 24 * 60 + time()
                                    }
                                   );
    return Win32::Lanman::GetLastError() unless $result;

    my @info;
    # add to appropriate LOCAL group (first get the SID of the account)
    die "SID lookup error: ".Win32::Lanman::GetLastError()."\n" unless
        Win32::Lanman::LsaLookupNames( "", [ $account ], \@info );
    $result = Win32::Lanman::NetLocalGroupAddMember( "", $group, 
                                                     ${$info[0]}{sid} );
    return Win32::Lanman::GetLastError() unless $result;

    # create home directory
    mkdir $homeNTdirs, 0777 unless -d $homeNTdirs;
    mkdir "$homeNTdirs\\$account", 0777 or return "Unable to make homedir:$!";

    # now set the ACL and owner of the directory
    my $acl = new Win32::Perms( "$homeNTdirs\\$account" );
    $acl->Owner( $account );

    # we give the user full control of the directory and all of the 
    # files that will be created within it (hence the two separate calls)
    $acl->Allow( $account, FULL, DIRECTORY|CONTAINER_INHERIT_ACE );
    $acl->Allow( $account, FULL, 
                           FILE|OBJECT_INHERIT_ACE|INHERIT_ONLY_ACE);
    $result = $acl->Set();
    $acl->Close();

    return $result ? "" : $result;
}
\end{verbatim}%$
\ldots and this code (also from David) implements delete a user:
\begin{verbatim}
#*
#* basic account deletion routine for NT/2000
#*

use Win32::Lanman;   # for account deletion
use File::Path;      # for recursive directory deletion

sub DeleteNTAccount
{
    my $account = shift;
    my @info;
    # remove user from LOCAL groups only. If we wanted to also 
    # remove from global groups we could remove the word "Local" from 
    # the two Win32::Lanman::NetUser* calls *e.g. NetUserGetGroups)
    die "SID lookup error: ".Win32::Lanman::GetLastError()."\n" unless
       ( Win32::Lanman::LsaLookupNames( "", [ $account ], \@info ) );
    my @groups;
    Win32::Lanman::NetUserGetLocalGroups( "", $account, '', \@groups );
    foreach my $group ( @groups )
    {
        print "Removing user from local group ".$group->{name}."...";
        print( Win32::Lanman::NetLocalGroupDelMember( "", 
                                                      $group->{name},
                                                      ${$info[0]}{sid} )
               ? "succeeded\n" : "FAILED\n"
             );
    }

    # delete this account on the local machine 
    # (i.e. empty first parameter)
    my $result = Win32::Lanman::NetUserDel( "", $account );

    return Win32::Lanman::GetLastError() if $result;

    # delete the home directory and its contents
    $result = rmtree( "$homeNTdirs\\$account", 0, 1 );
        
    # rmtree returns the number of items deleted, 
    # so if we deleted more than 0,it is likely that we succeeded 
    return $result;
}
\end{verbatim}%$
And here is a bit of code to test it with:
\begin{verbatim}
my $result
    = CreateNTAccount( "test", "testpasswd", "The Test User", "Users" );
unless ( $result )
{
    print "good, it worked\n";
}
else
{
    print "Cannot create test account: $result";
}
\end{verbatim}

Okay, these subroutines use some features of the Perl programming
language that we didn't cover in lectures.  But we never aimed to
cover every feature of Perl in just five weeks.  For example,
\texttt{\$\{\$info[0]\}\{sid\}} is a hash entry in an array that we
refer to by a reference.  And no, I won't explain that here; you can
find that out for yourself, or ask me out of class hours.

\subsection*{Now Create Those Thousands of Accounts on the Windows server}
\label{sec:create-accounts}

Use these two subroutines and the file
\url{http://nicku.org/snm/lab/regular-expressions/artificial-student-data.txt}
to generate accounts for all those thousands of students.

\end{document}
