Below is some of the newer Perl code that has been included in the current approach of migrating profiles and security. I do not have time to write it in KiXtart so I will provide the Perl source to those of you that might want to understand the process. You may be able to translate it to KiXtart. I will try to answer any questions.

Here is how I modify the registry to preserve the profile. I load ALL the profiles that are listed in my migration scope as defined by my SID map of old SID to new SID.

code:
sub LoadProfileHives
{
# Open HKEY_USERS key
my $HKEY_Users = $Registry->Open("Users/");
my @oldOpts= $HKEY_Users->SetOptions( AllowLoad=>1 );

# Open ProfileList key
my $ProfileList = $Registry->Open("LMachine/Software/Microsoft/Windows NT/CurrentVersion/ProfileList/");
my @ProfileKeys = $ProfileList->SubKeyNames;

my %LoadedKey;
foreach my $Pkey (@ProfileKeys)
{
#&LogText($LogFile, "Reg: $Pkey");
if (exists $SidMap{$Pkey})
{
&LogText($LogFile, "Profile Match: $Pkey");
# Load user registry hives into HKEY_USERS if they are not currently loaded.
if (! exists $HKEY_Users->{$Pkey . "/"})
{
my $file = $ProfileList->{"$Pkey//ProfileImagePath"} . "\\NTUSER.DAT";

# Correct path for both NT and W2K
$file =~s/\%(SystemRoot|SystemDrive)\%/$ENV{$1}/i;

$LoadedKey{$Pkey} = $HKEY_Users->Load($file, $Pkey);
if (exists $LoadedKey{$Pkey})
{
&LogText($LogFile, "Loaded: $file, $Pkey");
}
else
{
&LogText($LogFile, "Failed to load: $file, $Pkey");
}
}
else
{
&LogText($LogFile, "Reg: $Pkey already loaded in HKEY_USERS");
}

# Copy old OldSid key to NewSid key
@oldOpts= $ProfileList->SetOptions( ArrayValues=>1 );
$ProfileList->{"$SidMap{$Pkey}/"} = $ProfileList->{"$Pkey/"};
&LogText($LogFile, "Copy $Pkey key to $SidMap{$Pkey} key");
# Set NewBinarySid to Sid value in new key
$ProfileList->{"$SidMap{$Pkey}//Sid"} = [Win32::Lanman::StringToSid($SidMap{$Pkey}), "REG_BINARY" ];
@oldOpts= $ProfileList->SetOptions( ArrayValues=>0 );
}
}
# Call SubInACL
&CallSubInACL;

The current version of SubInACL is a must. The resource kit does not contain the current version.

Subinacl command line:
code:
sub CallSubInACL
{
my $cmdline = "$PerlServer\\subinacl\\subinacl.exe " .
"/offlinesam=$ENV{'TEMP'}\\OfflineSAM.txt " .
"/errorlog=$ENV{'TEMP'}\\subinaclerror.log " .
"/playfile $ENV{'TEMP'}\\playfile.txt";
&LogText($LogFile,"EXEC: $cmdline");
system $cmdline;
}

The playfile is a list of commands that subinacl will execute.

code:
sub BuildSubinaclPlayfile
{
unless (open(PLAYFILE, ">$ENV{'TEMP'}\\playfile.txt" ))
{
&LogText($LogFile, "Error opening $ENV{'TEMP'}\\playfile.txt");
exit 1;
}

my $options = "\n/noverbose\n";
my $migratelines;
my @ObjArray = ( "+subkeyreg HKEY_USERS\*",
"+share *",
"+printer *" );


my @drives = Win32API::File::getLogicalDrives();
my %Types =
(
0 => 'DRIVE_UNKNOWN',
1 => 'DRIVE_NO_ROOT_DIR',
2 => 'DRIVE_REMOVABLE',
3 => 'DRIVE_FIXED',
4 => 'DRIVE_REMOTE',
5 => 'DRIVE_CDROM',
6 => 'DRIVE_RAMDISK',
);

foreach my $drive ( @drives ) {
my $DriveType = Win32API::File::GetDriveType($drive);
next if($Types{$DriveType} ne 'DRIVE_FIXED');
push(@ObjArray, "+subdirectories $drive\*\.\*");
push(@ObjArray, "+onlyfile $drive");
}

# Build array of lines for /migratetodomain option.
# Copy Mapping file to %temp% so that subinacl can access it locally.
if (-e "$DataPath\\$MapCFG")
{
unless (open(MAPCFG, "<$DataPath\\$MapCFG"))
{
&LogText($LogFile, "Fatal Error: Failed to open $DataPath\\$MapCFG: " . $^E);
exit 1;
}

while (<MAPCFG>)
{
chomp;
my ($MapFile, $OldDomain, $NewDomain) = split /\t/;
if (Win32API::File::CopyFile("$DataPath\\$MapFile", "$ENV{'TEMP'}\\$MapFile", 0))
{
&LogText($LogFile, "$DataPath\\$MapFile copied to $ENV{'TEMP'}");
}
else
{
&LogText($LogFile, "Error copying $DataPath\\$MapFile " . $^E);
}
$migratelines .= "/migratetodomain=$OldDomain=$NewDomain=$ENV{'TEMP'}\\$MapFile\n";
}
}
else
{
&LogText($LogFile, "Fatal Error: Require file ( $DataPath\\$MapCFG ) could not be found.");
exit 1;
}

foreach my $obj (@ObjArray)
{
print PLAYFILE $obj . $options . $migratelines . "\n";
}
close PLAYFILE;
}

This code replaces the use of DumpACL and directly manipulate the local group memberships.
code:
sub ProcessLocalGroups
{
#---------------------------------------------------------------------------------------------------------
# Perform security migration on local groups utilizing the SidMap hash.
# Enumerate local groups.
# Get members of each group.
# Check to see if the Sid for the member is in the SidMap hash.
# If it is, add the NewSid as a member to the group.
#---------------------------------------------------------------------------------------------------------
my @Groups;
my $Error;
if (!Win32::Lanman::NetLocalGroupEnum("", \@Groups))
{
$^E = $Error = Win32::Lanman::GetLastError();
&LogText($LogFile, "Error (Lanman::NetLocalGroupEnum(\"\"): $Error :" . $^E);
&LogText($LogFile, "Exiting program: ABEND.");
exit 1;
}
foreach my $Group (@Groups)
{
&LogText($LogFile, "Processing localgroup: ${$Group}{'name'}");
my @members;
if(!Win32::Lanman::NetLocalGroupGetMembers("", ${$Group}{'name'}, \@members))
{
$^E = $Error = Win32::Lanman::GetLastError();
&LogText($LogFile, "Error (Lanman::NetLocalGroupGetMembers(\"\", ${$Group}{'name'}): $Error :" . $^E );
&LogText($LogFile, "Exiting program: ABEND.");
exit 1;
}

foreach my $member (@members)
{
my $OldTextSid = Win32::Lanman::SidToString(${$member}{'sid'});
if (exists $SidMap{$OldTextSid})
{
my $NewBinarySid = Win32::Lanman::StringToSid($SidMap{$OldTextSid});
if(!Win32::Lanman::NetLocalGroupAddMember("", ${$Group}{'name'}, $NewBinarySid))
{
$^E = $Error = Win32::Lanman::GetLastError();
&LogText($LogFile, "Error adding:\t$SidMap{$OldTextSid}\tOldMember: ${$member}{'domainandname'} $Error :" . $^E );
}
else
{
&LogText($LogFile, "Added:\t$SidMap{$OldTextSid}\tOldMember: ${$member}{'domainandname'}");
}
}
else
{
#&LogText($LogFile, "Not in SidMap:\t${$Group}{'name'} Member: ${$member}{'domainandname'}\t$OldTextSid");
}
}
}
undef @Groups;
}

_________________________
Home page: http://www.kixhelp.com/hb/