We help IT Professionals succeed at work.

pre-stage user profile

Hi
I tried the script provided by "sgdought" to pre-stage user profile (http://www.experts-exchange.com/Software/Server_Software/File_Servers/Active_Directory/A_3035-vbscript-to-pre-stage-a-profile.html?sfQueryTermInfo=1+10+30+pre+stage)  but did not have any luck. I got "...no domain available...." message after running your script and when I tried to logon.
I am providing user's logon name as input to the script. The script finds the user account in AD, creates the profile folder and all the registry values properly except HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-x-xx-yyyyyyyyy-zzzzzzzzzz-xxxxxxxxxx-zzzzz\Guid. The HexToDecStr function is not properly converting the GUID value. So instead of {xxxxxxxx-zzzzz-yyyy-xxxx-zzzzzzzzzzzz} format I am seeing {xxxxxxxxzzzzzyyyyxxxxzzzzzzzzzzzz} and the left side of xx & zz string set are not correct, and the reason why I am saying that is because I did a GUID comparison for the same domain user on two different PCs, one where I ran this script and the other where I actually logged on using that same domain user account.
Any ideas on how to fix this?
thanks
Comment
Watch Question

Most Valuable Expert 2012
Top Expert 2014

Commented:
Hi, it looks like the functions generate the correct SID strings to me.  When you see the output:
StrSidDec is xxxx-xxxx-xxxx

is it correct?

Anyway, try replacing the OctetToHexStr and HexStrToDecStr functions with these, which are working functions I've been using for years.

Regards,

Rob.
'Working VBScript Active Directory Binary SID conversion to String SID
' Source: http://forums.techarena.in/showthread.php?t=588078
'Function to convert OctetString (byte array) to Hex string.
Function OctetToHexStr(arrbytOctet)
Dim k
OctetToHexStr = ""
For k = 1 To Lenb(arrbytOctet)
OctetToHexStr = OctetToHexStr & Right("0" & Hex(Ascb(Midb(arrbytOctet, k, 1))), 2)
Next
End Function

Function HexStrToDecStr(strSid)
' Function to convert Hex string Sid to Decimal string (SDDL) Sid.


' SID anatomy:
' Byte Position
' 0 : SID Structure Revision Level (SRL)
' 1 : Number of Subauthority/Relative Identifier
' 2-7 : Identifier Authority Value (IAV) [48 bits]
' 8-x : Variable number of Subauthority or Relative Identifier (RID) [32 bits]
'
' Example:
'
' <Domain/Machine>\Administrator
' Pos : 0 | 1 | 2 3 4 5 6 7 | 8 9 10 11 | 12 13 14 15 | 16 17 18 19 | 20 21 22 23 | 24 25 26 27
' Value: 01 | 05 | 00 00 00 00 00 05 | 15 00 00 00 | 06 4E 7D 7F | 11 57 56 7A | 04 11 C5 20 | F4 01 00 00
' str : S- 1 | | -5 | -21 | -2138918406 | -2052478737 | -549785860 | -500


Const BYTES_IN_32BITS = 4
Const SRL_BYTE = 0
Const IAV_START_BYTE = 2
Const IAV_END_BYTE = 7
Const RID_START_BYTE = 8
Const MSB = 3 'Most significant byte
Const LSB = 0 'Least significant byte


Dim arrbytSid, lngTemp, base, offset, i


ReDim arrbytSid(Len(strSid)/2 - 1)


' Convert hex string into integer Array
For i = 0 To UBound(arrbytSid)
      arrbytSid(i) = CInt("&H" & Mid(strSid, 2 * i + 1, 2))
Next


' Add SRL number
HexStrToDecStr = "S-" & arrbytSid(SRL_BYTE)


' Add Identifier Authority Value
lngTemp = 0
For i = IAV_START_BYTE To IAV_END_BYTE
      lngTemp = lngTemp * 256 + arrbytSid(i)
Next
HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)


' Add a variable number of 32-bit subauthority or
' relative identifier (RID) values.
' Bytes are in reverse significant order.
' i.e. HEX 01 02 03 04 => HEX 04 03 02 01
' = (((0 * 256 + 04) * 256 + 03) * 256 + 02) * 256 + 01
' = DEC 67305985
For base = RID_START_BYTE To UBound(arrbytSid) Step BYTES_IN_32BITS
      lngTemp = 0
      For offset = MSB to LSB Step -1
            lngTemp = lngTemp * 256 + arrbytSid(base + offset)
      Next
      HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)
Next
End Function ' HexStrToDecStr

Open in new window

Author

Commented:
Thanks. I will give it a shot and post back the results.

Author

Commented:
Same result:
The value of
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-x-xx-yyyyyyyyy-zzzzzzzzzz-xxxxxxxxxx-zzzzz\Guid
is not properly formatted. So instead of {yyyyyyyy-xxxx-zzzz-vvvv-ssssssssssss} I am getting {yyyyyyyyxxxxzzzzvvvvssssssssssss}

Also I see the same GUID (as a sub-key) under the \ProfileGuid key
Most Valuable Expert 2012
Top Expert 2014

Commented:
OK, so the SID is correct, the GUID is not.  You should be able to just change this line:
strGuid = "{" & strGuid & "}"

to this:
      strGuid = "{" & Mid(strGuid, 1, 8) & "-" & Mid(strGuid, 9, 4) & "-" & Mid(strGuid, 13, 4) & "-" & Mid(strGuid, 17, 4) & "-" & Mid(strGuid, 21, 15) & "}"

Regards,

Rob.

Author

Commented:
Thanks Rob. I modified the "strGuid" in the script as you suggested and it did at least insert the "-" within the strGuid but I got "...no domain available...." message when tried to logon.
This is the script that I am using.

Option Explicit
'On Error Resume Next
Dim objUser, objTrans, objOU, objRegistry, objFSO, objWShell, objExecObject, curWorkDir
Dim arrSid, strSidHex
Dim strUserDN, strSidDec, strSelectTemp, strKeyPath, strComputer
Dim strSamAccountName, strSubPath, strValueName, strValue, strProfileFolder
Dim strGuidPath, strGuid, strQuote, strCommand, strTemp, strProfileName
Const ADS_NAME_INITTYPE_GC = 3
Const ADS_NAME_TYPE_1779 = 1
Const ADS_NAME_TYPE_SID_OR_SID_HISTORY_NAME = 12
Const HKEY_LOCAL_MACHINE = &H80000002
Const OverwriteExisting = True
strComputer = "."
strQuote = Chr(34)

Set objRegistry=GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
Set objFSO = CreateObject("Scripting.FileSystemObject")
curWorkDir = objFSO.GetAbsolutePathName(" .")

strKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
strGuidPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileGuid"
strProfileName = InputBox("Type in user's logon name:")
strSelectTemp = "LDAP://CN=" & strProfileName & ",OU=Test Users,DC=test,DC=devdomain,DC=com"
'WScript.Echo strSelectTemp
Err.Clear
Set objUser=GetObject(strSelectTemp)
If Err.Number <> 0 Then
        WScript.Echo "The connect to container error was " & Err.Description
End If  
'WScript.Echo "The user distinguished name is " & objUser.distinguishedName
arrSid = objUser.objectSid
strSidHex = OctetToHexStr(arrSid)
'Wscript.Echo "StrSidHex is " & strSidHex
strSidDec = HexStrToDecStr(strSidHex)
'Wscript.Echo "StrSidDec is " & strSidDec
'WScript.Echo "The samAccountName is " & objUser.samAccountName
strSamAccountName = objUser.samAccountName
'WScript.Echo "The distinguishedName is " & objUser.distinguishedName
strProfileFolder = "C:\Documents and Settings\" & strSamAccountName
strValueName = "ProfileImagePath"
strValue = "%systemDrive%\Documents and Settings\" & strSamAccountName
strSubPath = strKeyPath & "\" & strSidDec
   
objRegistry.CreateKey HKEY_LOCAL_MACHINE, strSubPath
objRegistry.SetExpandedStringValue HKEY_LOCAL_MACHINE, strSubPath, strValueName, strValue
strValueName = "SID"
objRegistry.SetBinaryValue HKEY_LOCAL_MACHINE, strSubPath, strValueName, arrSid

If Not (objFSO.FolderExists (strProfileFolder)) Then
      objFSO.CreateFolder(strProfileFolder)
End If      
   
strCommand = curWorkDir & "\subinacl.exe /subdirectories "  & strQuote & strProfileFolder & strQuote & " /grant=test.devdomain.com\" & objUser.samAccountName  & "=F "
WScript.Echo strCommand    
Set objWShell = WScript.CreateObject("WScript.Shell")
Set objExecObject = objWShell.Exec(strCommand)
Do While objExecObject.Status <> 1
      WScript.Sleep 100
Loop
strTemp = objExecObject.StdOut.ReadAll() & objExecObject.StdErr.ReadAll()
'WScript.Echo"The results of SubInACL.exe are " & strTemp    
strGuid = objUser.GUID
'WScript.Echo "The GUID is " & strGuid
strGuid = "{" & Mid(strGuid, 1, 8) & "-" & Mid(strGuid, 9, 4) & "-" & Mid(strGuid, 13, 4) & "-" & Mid(strGuid, 17, 4) & "-" & Mid(strGuid, 21, 15) & "}"
'WScript.Echo "The strGuid is now " & strGuid
strValueName = "Guid"
objRegistry.SetStringValue HKEY_LOCAL_MACHINE, strSubPath, strValueName, strGuid      
strValueName = "CentralProfile"
objRegistry.SetStringValue HKEY_LOCAL_MACHINE, strSubPath, strValueName, ""   
strValueName = "Flags"
objRegistry.SetDWordValue HKEY_LOCAL_MACHINE, strSubPath, strValueName, "1"
strValueName = "State"
objRegistry.SetDWordValue HKEY_LOCAL_MACHINE, strSubPath, strValueName, "0"
strSubPath = strGuidPath &  "\" & strGuid
'WScript.Echo " The strGuidPath is " & strSubPath
objRegistry.CreateKey HKEY_LOCAL_MACHINE, strSubPath        
objRegistry.SetStringValue HKEY_LOCAL_MACHINE, strGuidPath, strValueName, strValue
Wscript.Quit

Function OctetToHexStr(arrbytOctet)
      Dim k
      OctetToHexStr = ""
      For k = 1 To Lenb(arrbytOctet)
            OctetToHexStr = OctetToHexStr & Right("0" & Hex(Ascb(Midb(arrbytOctet, k, 1))), 2)
      Next
End Function

Function HexStrToDecStr(strSid)
      Const BYTES_IN_32BITS = 4
      Const SRL_BYTE = 0
      Const IAV_START_BYTE = 2
      Const IAV_END_BYTE = 7
      Const RID_START_BYTE = 8
      Const MSB = 3 'Most significant byte
      Const LSB = 0 'Least significant byte

      Dim arrbytSid, lngTemp, base, offset, i
      ReDim arrbytSid(Len(strSid)/2 - 1)
      ' Convert hex string into integer Array
      For i = 0 To UBound(arrbytSid)
            arrbytSid(i) = CInt("&H" & Mid(strSid, 2 * i + 1, 2))
      Next
      ' Add SRL number
      HexStrToDecStr = "S-" & arrbytSid(SRL_BYTE)
      ' Add Identifier Authority Value
      lngTemp = 0
      For i = IAV_START_BYTE To IAV_END_BYTE
            lngTemp = lngTemp * 256 + arrbytSid(i)
      Next
      HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)
      For base = RID_START_BYTE To UBound(arrbytSid) Step BYTES_IN_32BITS
            lngTemp = 0
            For offset = MSB to LSB Step -1
                  lngTemp = lngTemp * 256 + arrbytSid(base + offset)
            Next
            HexStrToDecStr = HexStrToDecStr & "-" & CStr(lngTemp)
      Next
End Function ' HexStrToDecStr

Author

Commented:
Few more thing that I am noticing are:

The "SidString" value does not get created under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileGuid\{aabbccdd-eeff-gghh-iijj-kkllmmnnoopp}

The first three parts (the left side - under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileGuid) of the key are being created in reverse order. So instead of {aabbccdd-eeff-gghh-iijj-kkllmmnnoopp} I am seeing {ddccbbaa-ffee-hhgg-iijj-kkllmmnnoopp}

And I see the same under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-21-yyyyyyyyy-xxxxxxxxxx-zzzzzzzzzz-vvvvv\Guid (the first three parts of the Guid are in reverse order)

I also tried to manually change all the guids with correct guids but no go.
Most Valuable Expert 2012
Top Expert 2014

Commented:
How much pre-staging do you need to do?  In my environment, when we swap a computer, I export this key for a user:
HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\<SID>

out to a .reg file, then copy the "C:\Documents and Settings\<username>" folder to a network share.  Then we just import the .reg file on the new computer, copy the profile back, and it works.

Are you restoring user profiles, or are you just trying to have the user account placed in a specific location at first logon?  In either case, I don't think you need the ProfileGuid part of the script, and only need to set the ProfileList key for the users SID.

Rob.

Author

Commented:
If I can make this script to it would be a great help to all my field users who (currently) have to make a special trip to the branch to get the new/reimaged laptops just so they could logon (while on wire) to get their profile created.

Exporting/importing user's existing profile is not an option for me.

BTW, I tried just the ProfileList and it did not work.
Most Valuable Expert 2012
Top Expert 2014

Commented:
OK, can you explain the scenario to me?  What is it you are doing exactly?  Issuing a new computer?  Recreating the user profile?  Re-imaging an existing computer?

If you're re-imaging an existing computer, do you send out a CD or something for field users to run?

Rob.

Author

Commented:
Ok, let me try to explain:
In cases like where field user's existing laptop is broken or when there is a hardware refresh (new laptop etc.), we image the laptop with our company standard image, ask users to come to the branch office to logon so the profile gets created. If I ship the laptop without having these users first logon (while the laptop is on LAN), these users cannot logon because there is no cached profile.

What I am trying to achieve is save these users the trip to the branch offices. So, when I image a laptop, I simply run the script to pre-stage user's profile and ship the laptop to users. When users receive the laptop, they just simply logon using cached credentials and use VPN etc. to connect to company's network.

Please let me know if it is still not clear.

 
Most Valuable Expert 2012
Top Expert 2014

Commented:
Hmmm, I'm not actually sure that this pre-staging is going to cache the logon credentials, so I don't know if it will work the way you intend.  From reading a few posts around, it's not possible to do this because of all of the other things that happen at logon.  Some options thrown about are
1) configure the VPN to dial and connect before login, which will connect and therefore cache the credentials
2) if the remote user can use another computer while in the field, get them to Remote Desktop to their new computer in your office so they log in and set up the credentials
3) change their password on your domain and log in yourself
4) get them to tell you their password so you can log in

I think it's just a (very wise) security feature that means you must authenticate to a domain controller to make sure your credentials are correct.

Rob.

Author

Commented:
Thanks Rob but none of the four options you mentioned are feasible in my environment. So I guess I am stuck with having the users come to the branch office to have their initial profile created/cached.
Most Valuable Expert 2012
Top Expert 2014

Commented:
Yes, unfortunately so.  It appears that you simply cannot have the ability to log in with a domain account, without having a domain controller available in the first instance to authenticate to, and then cache the credentials.  It's all related to security.  Have a look here for a good explanation:
http://blog.webactivedirectory.com/2011/06/09/windows-active-directory-cached-user-credentials/

In terms of the pre-staging you have tried to implement, the pre-staging in this respect is only to pre-stage the user's profile folder or destination.

I'll try to illustrate it in this sense:
When you first log on to a computer, the normal user profile is created (on XP for example) at C:\Documents and Settings\username
If you move computers, and you only copy the profile folder from Computer A to Computer B, when the user logs into Computer B, then because the folder already exists, the profile will be brand new, and created at something like C:\Documents and Settings\username.001 or username.domain
So, to avoid that, and actually use the original profile folder (along with all the contents), you pre-stage it before the user logs on by making the registry modifications that are happening here.  This is what I do when I'm replacing PCs, to avoid users having to log in to Computer B before copying their profile back.

There is perhaps one more option as stated here:
http://forums.techguy.org/windows-xp/1007028-solved-no-locally-cached-credentials.html

in which you could give the field user a local account as well, with just enough rights to run a VPN connection, so they connect, and then log off the local account, and log into the VPN domain with their domain account.

Regards,

Rob.

Author

Commented:
Thanks Rob for the suggestions but none of these apply in my environment.
Most Valuable Expert 2012
Top Expert 2014
Commented:
Unfortunately then, as far as I know, particularly for security reasons, there is no other option.

Regards,

Rob.

Author

Commented:
Hi Admins
Since there is no acceptable solution, please close this question.
thanks

Author

Commented:
Admins
I do not see the option to "Close Question" but rather I see "Delete Question" so that is why I am asking you to close the question. If "Delete" is actually "Close" then I can do that. Please advise.
thanks
Most Valuable Expert 2012
Top Expert 2014

Commented:
Hi NewbieTechi,

Sometimes an answer of "no answer" is a viable solution (in terms of the question asked), so you could accept my comment ID 37590780 as the answer.  However, if you do not wish to accept one of my comments, then you can accept one of your own comments, which will put the question into a four day closing period, allowing for any objections.

I think there is some good information in this thread so I would recommend that you close it in some fashion, rather than delete it.

Regards,

Rob.

Author

Commented:
No acceptable solution was provided