Vista’s MoveUser.exe replacement

Vista’s MoveUser.exe replacement

  • Comments 24
  • Likes

Hi Rob here again. I recently had a customer that needed the functionality of MoveUser.exe from the Windows 2000 Resource Kit available in Windows Vista. The customer had quite a few Windows Vista machines that were not joined to the domain but were now migrating to Active Directory. For their own business reasons they were previously unable to join the machines to the domain, instead all the users logged on with local user accounts. Since they had this new fancy Active Directory they created user accounts in AD for the users and joined the machines to the domain. They then found that they needed a way to attach the users’ existing local profile to their Active Directory user accounts so that the users would have their normal setup and desktop when they logged in-a seamless experience. Now if you have been around forever like most of us here in support in Windows 2000 and up we used a utility named MoveUser.exe to accomplish this.

Well, in Windows Vista moveuser.exe is no longer supported. However, now we expose this functionality with a new WMI provider called Win32_UserProfile, which is discussed in KB930955. This is awesome because we expose things about user profiles in WMI now… and we can also move the profile to another user as well as delete user profiles. However, once I started looking at MSDN to understand what methods were available I quickly found that MSDN has not been updated as of yet for this new class. So we did some digging into the source code to find out how this works and what is supported.

I wrote a sample script that illustrates how you can leverage this provider to move an existing user profile to another user’s profile. I know that I could have made the script smaller by not listing out all the different properties available in the provider, but the different things exposed are just way too many and if you are planning on using this provider they are just way too cool.

Usage

Please keep in mind that this is a sample script-you will need to alter it and test it in your environment and for your needs. To use:

1. Copy the below script into Notepad then save as moveuser.vbs

2. You will need to modify the following variables within the script.

  • strComputer: The computer name that this script needs to run against
  • strSourceAcct: The user account that has the source profile on the system
  • strSourceAcctDomain: The domain of the source user account that the profile belongs to. If the source account that you want to move the profile from is a local computer user you put in the computers name for the domain. If this is another domain then you type in the domain name.
  • strTargetAcct: The user account that the source profile should be moved to.
  • strTargetDomain: The domain of the target user account that the profile should be moved to. If the target account that you want to move the profile to is a local computer user you put in the computers name. If this is another domain then you type in the domain name.
  • strDomainDN: The Target Account Domains Distinguished Name. This is done for the LDAP query to be built to find the target accounts SID. for example dc=contoso,dc=com

3. Run the script by typing cscript moveuser.vbs

Sample Script

'     This script is provided "AS IS" with no warranties, and confers no rights.
'     For more information please visit
'    
http://www.microsoft.com/info/cpyright.mspx to find terms of use.
'
Option Explicit
DIM strComputer, strSourceAcct, strSourceAcctDomain, strTargetAcct
DIM strTargetAcctDomain, strTargetAcctSID
DIM objProfile, objCommand, objRecordSet, objConnection, objWMIService, objSID
DIM dtStart, colProfiles, oSID, oUsr
DIM Revision, IssueAuthorities(11), strSDDL, subAuthorities
DIM strDomainDN

CONST ADS_SCOPE_SUBTREE=2

'  This script has hard coded variables in it that must be filled out.
'  strComputer = The computer name that this script needs to run against.
'                                   With WMI the "." means this computer.
'
'  strSourceAcct = user account that has the source profile on the system.
'
'  strSourceAcctDomain = The domain of the source user account that the profile belongs to.
'                                   If the source account that you want to move the profile from
'                                   is a local computer user you put in the computers name for the domain. 
'                                   If this is another domain then you type in the domain name.
'
' strTargetAcct = The user account that the source profile should be moved to.
'
' strTargetDomain = The domain of the target user account that the profile should be moved to
'                                   If the target account that you want to move the profile to.
'                                   is a local computer user you put in the computers name. 
'                                   If this is another domain then you type in the domain name.
'
' strDomainDN = The Target Account Domains Distinguished Name. 
'                                  This is done for the LDAP query to be built to find the target accounts SID
'

strComputer ="."
strSourceAcct="User1"
strSourceAcctDomain="Contoso-Vista"
strTargetAcct="User1"
strTargetAcctDomain="CONTOSO"
strDomainDN="dc=contoso,dc=com"
strTargetAcctSID=""
dtStart = TimeValue(Now())
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection

' We need the proper Active Directory domain name where the user exists in a DN format.  You can
' modify the strDomainDN variable to you Active Directory domain name is in DN format.

objCommand.CommandText = _
    "SELECT AdsPath, cn FROM 'LDAP:// "+strDomainDN+"' WHERE objectCategory = 'user'" & _
         "And sAMAccountName= '"+strTargetAcct+"'"
objcommand.Properties("searchscope") = ADS_SCOPE_SUBTREE 
Set objRecordSet = objCommand.Execute
If objRecordset.RecordCount = 0 Then
    WScript.Echo "sAMAccountName: " & strTargetAcct & " does not exist."
ElseIf objRecordset.RecordCount > 1 Then
    WScript.Echo "There is more than one account with the same sAMAccountName"
Else
    WScript.Echo "Found account:  "+strTargetAcctDomain+"\"+strTargetAcct + " in the domain."
    objRecordSet.MoveFirst
    Do Until objRecordSet.EOF
        Set Ousr = GetObject(objRecordSet.Fields("AdsPath").Value)
        strTargetAcctSID = SDDL_SID(oUsr.Get("objectSID"))
        WScript.echo "SID for  "+ strTargetAcctDomain+"\"+strTargetAcct + _
" is:  "+strTargetAcctSID
        WScript.Echo VBNewLine
        WScript.Echo VBNewLine

        objRecordSet.MoveNext
    Loop

objConnection.Close

Set objWMIService = GetObject("winmgmts:\\" & strComputer &"\root\cimv2")
Set colProfiles = objWMIService.ExecQuery("Select * from Win32_UserProfile")
For Each objProfile in colProfiles
    Set objSID = objWMIService.Get("Win32_SID.SID='" & objProfile.SID &"'")
    Wscript.Echo"======================================================"& VBNewLine _
        &"Sid:" & objProfile.Sid & VBNewLine _
        &"User Name:" & objSID.AccountName & VBNewLine _
        &"User Domain:" & objSID.ReferencedDomainName & VBNewLine _
        &"LocalPath:" & objProfile.LocalPath & VBNewLine _
        &"Loaded:" & objProfile.Loaded & VBNewLine _
        &"RefCount:" & objProfile.RefCount & VBNewLine _
        &"RoamingConfigured:" & objProfile.RoamingConfigured & VBNewLine _
        &"RoamingPath:" & objProfile.RoamingPath & VBNewLine  _
        &"RoamingPreference:" & objProfile.RoamingPreference & VBNewLine _
        &"Status:" & objProfile.Status & VBNewLine _
        &"LastUseTime:" & objProfile.LastUseTime & VBNewLine  _
        &"LastDownloadTime:" & objProfile.LastDownloadTime & VBNewLine  _
        &"LastUploadTime:" & objProfile.LastUploadTime & VBNewLine 

'    Testing to verify that the current profile handle is for the Source Account that we want to
'    Move to the domain user.
if UCase(objsid.referencedDomainName+"\"+objsid.AccountName)= _ 
UCase(strSourceAcctDomain+"\"+strSourceAcct) Then
    ' Making sure that the source profile is currently not in use.  If it is we will bail out.
        If objProfile.RefCount < 1 Then
WScript.echo "Change Profile for:  "+ strSourceAcctDomain+"\"+ _
strSourceAcct+" to: "+ strTargetAcctDomain+"\"+strTargetAcct
        ' ChangeOwner method requires to String SID of Target Account and a Flag setting

        ' Flag 1 = Change ownership of the source profile to target account
' even if the target account  already has a profile on the system.

        ' Flag 2 = Delete the target account Profile and change ownership
'  of the source user account profile to the target account.

        '  To use the ChangeOwner method, both the source and
'  target account profiles (If it exists) must not be loaded.

            ObjProfile.ChangeOwner strTargetAcctSID,1
     Else 
            Wscript.echo "Could not move the users profile, because " + _
            strSourceAcctDomain+"\"+strSourceAcct+" profile is currently loaded"
        End If   
     End If
Next
End If
Sub Init_IssueAuthorities( )
    'DIM IssueAuthorities(11)
    IssueAuthorities(0) = "-0-0"
    IssueAuthorities(1) = "-1-0"
    IssueAuthorities(2) = "-2-0"
    IssueAuthorities(3) = "-3-0"
    IssueAuthorities(4) = "-4"
    IssueAuthorities(5) = "-5"
    IssueAuthorities(6) = "-?"
    IssueAuthorities(7) = "-?"
    IssueAuthorities(8) = "-?"
    IssueAuthorities(9) = "-?"

end sub

function SDDL_SID ( oSID )
    DIM Revision, SubAuthorities, strSDDL, IssueIndex, index, i, k, p2, subtotal
    DIM j, dblSubAuth
'
' First byte is the revision value
'
    Revision = "1-5"
'
' Second byte is the number of sub authorities in the
' SID
'
    SubAuthorities = CInt(ascb(midb(oSID,2,1)))
    strSDDL = "S-" & Revision
    IssueIndex = CInt(ascb(midb(oSID,8,1)))
'
' BYtes 2 - 8 are the issuing authority structure
' Currently these values are in the form:
' { 0, 0, 0, 0, 0, X}
'
' We use this fact to retrieve byte number 8 as the index
' then look up the authorities for an array of values
'
    strSDDL = strSDDL & IssueAuthorities(IssueIndex)
'
' The sub authorities start at byte number 9. The are 4 bytes long and
' the number of them is stored in the Sub Authorities variable.
'
    index = 9
    i = index
    for k = 1 to SubAuthorities
        '
        ' Very simple formula, the sub authorities are stored in the
        ' following order:
        ' Byte Index Starting Bit
        ' Byte 0 - Index 0
        ' Byte 1 - Index + 1 7
        ' Byte 2 - Index + 2 15
        ' Byte 3 - Index + 3 23
        ' Bytes0 - 4 make a DWORD value in whole. We need to shift the bits
        ' bits in each byte and sum them all together by multiplying by powers of 2
        ' So the sub authority would be built by the following formula:
        '
        ' SUbAuthority = byte0*2^0 + Byte1*2^8 + byte2*2^16 + byte3*2^24
        '
        ' this be done using a simple short loop, initializing the power of two
        ' variable ( p2 ) to 0 before the start an incrementing by 8 on each byte
        ' and summing them all together.
        '
        p2 = 0
        subtotal = 0
        for j = 1 to 4
        dblSubAuth = CDbl(ascb(midb(osid,i,1))) * (2^p2)
        subTotal = subTotal + dblSubAuth
        p2 = p2 + 8
        i = i + 1
    next
'
' Convert the value to a string, add it to the SDDL Sid and continue
'
    strSDDL = strSDDL & "-" & cstr(subTotal)
    next
    SDDL_SID = strSDDL
end function

Please keep in mind if you have not installed Service Pack 1 for Vista, you will need to download the MSI installer to get the new WMI Profile provider since it was released after Vista shipped.

Well, I hope that you find this functionality helpful. Happy scripting.

- Rob Greene

  • Hey Ron,

    So I took a look at you site listed above.  Top notch, I really like how you took the concept of the script and totally made it into something that you as well as other customers can use.  

    I have to give you the extra kodos of adding all the documentation around how to use the script on the website.  

    Thank you for taking interest in our blogging efforts and giving back to the community with the additions to the script.

  • Auch das Active Directory Team betreibt ein Blog , dass ich interessant zu lesen finde. Gestolpert dar&#252;ber

  • We’ve been at this for over a year (since August 2007), with more than 100 posts (127 to be exact), so

  • I know it has been a while, and this thread is likely dead - but I recently tested my current version of the script on a Windows 7 beta installation and after a couple of minor tweaks to the error checking bits, it now works with Windows 7 just fine. (Though I still haven't gone back to try to fit in the 'move back to a local account' option...)

    Oh,... and our mass migration of the Novell users went beautifully.

  • For what it's worth, I ran into some trouble with the VBScript replacement and ended up using the following PowerShell script instead.  As Rob Greene suggested, I pulled the SIDs from Win32_UserAccount.  

    [code]

    $original_user = get-wmiobject -class "Win32_UserAccount" -namespace "root\cimv2" -filter "Name='user1' AND LocalAccount=True"

    $new_user = get-wmiobject -class "Win32_UserAccount" -namespace "root\cimv2" -filter "Name='user1' AND Domain='CONTOSO'"

    $profile = get-wmiobject -class "Win32_UserProfile" -namespace "root\cimv2" -filter "SID='$($original_user.SID)'"

    $profile.ChangeOwner($new_user.SID, [uint32]0)

    [/code]

    Which could be even shorter:

    [code]

    $original_user = get-wmiobject "Win32_UserAccount WHERE Name='user1' AND LocalAccount=True"

    $new_user = get-wmiobject "Win32_UserAccount WHERE Name='user1' AND Domain='CONTOSO'"

    $profile = get-wmiobject "Win32_UserProfile WHERE SID='$($original_user.SID)'"

    $profile.ChangeOwner($new_user.SID, 0)

    [/code]

  • Hey perennialmind,

    Thats great coding.

    I am sorry to hear that you had issues with the VBScript.

    Rob Greene

  • thank's a lot, i will try your script Rob, but if it's doesn't works with my park, this powerShell Scritp works ? (I just change in row 2 "Domain='Tralala'"

    [code]

    $original_user = get-wmiobject "Win32_UserAccount WHERE Name='user1' AND Domain='Tralala'"

    $new_user = get-wmiobject "Win32_UserAccount WHERE Name='user1' AND Domain='CONTOSO'"

    $profile = get-wmiobject "Win32_UserProfile WHERE SID='$($original_user.SID)'"

    $profile.ChangeOwner($new_user.SID, 0)

    [/code]

    And i have a another question for both script (vbs and PowerShell), when do I run the script ? when I'm the admin of the first domain (source) or the final domain (target), after created a user profil in the new domain ?

    by default, your script doesn't delete the source account I guess ?

    Rob, Do you marry me ?

    I have no further question.

    the shrimp's stell

  • Hey Shrimp's Stell,

    I have to be honest here with you, I have not really taken the time to learn anything at this point about Powershell scripting in general.

    However, I think your script is going to have a problem unless both the source and target accounts have logged onto the machine at least once.  Since you are calling the WMI Win32_UserAccount class.

    Rob Greene

  • Hi:

    I have modified the script to let move user from domain to local. Also assumed that only one domain involved, so don't have to change script for domain.

    Tested working fine, feel free to report any errors

    '===========================================================================

    '  MoveUser.vbs

    '  Rob Greene of Technet created the original script

    '  Ron Williams expanded it to have similar functionality to the previous Moveuser.exe

    '  Harvey Chen modified it so it can move users from and to domain and

    '  removed hard cocded domain veriable, instead look at command line to find  

    '  domain/user format and use the domain part.

    '===========================================================================

    Option Explicit

    Dim strComputer, strSourceAcct, strSourceAcctDomain, strTargetAcct

    Dim strTargetAcctDomain, strTargetAcctSID, objComputer, objOs

    DIM objProfile, objCommand, objRecordSet, objConnection, objWMIService

    DIM dtStart, colProfiles, oSID, oUsr, strDomain, objSID

    DIM Revision, IssueAuthorities(11), strSDDL, subAuthorities

    DIM strDomAcctLength, strCompName, strSlashPos, strContinue

    DIM strDomainAcct, strLocalAcct, strLocalAcctLength, strArg3

    DIM strKeepuser, strArg4, colOperatingSystems, strSrcDom, strOSVer

    Dim strTargetAcctCommand, strSourceAcctCommand, strTargetAcctExist

    Dim strSourceAcctLength, strTargetAcctLength, strSourceAcctExist

    CONST ADS_SCOPE_SUBTREE=2

    'If arguments are not two then promt for Syntax

    If WScript.Arguments.Count >= 2 Then

    strSourceAcctCommand = WScript.Arguments.Item(0)

    strTargetAcctCommand = WScript.Arguments.Item(1)

    Else

    Call Syntax

    End If

    'Process arg 1 for source profile

    If InStr (strSourceAcctCommand, "\") = 0 Then

    Set strCompName = WScript.CreateObject("WScript.Network")

    strSourceAcctDomain = strCompName.ComputerName

    strComputer = "."

    strSourceAcct = strSourceAcctCommand

    Else

    strSourceAcctLength = Len(strSourceAcctCommand)

    strSlashPos = InStr (strSourceAcctCommand, "\")

    strSourceAcct = Right(strSourceAcctCommand,strSourceAcctLength - strSlashPos)

    strSourceAcctDomain = Left(strSourceAcctCommand,strSlashPos - 1)

    strDomain = "dc=" & Left(strSourceAcctCommand,strSlashPos - 1) &",dc=com"

    End If

    'Process arg 2 for target profile

    If InStr (strTargetAcctCommand, "\") = 0 Then

    Set strCompName = WScript.CreateObject("WScript.Network")

    strTargetAcctDomain = strCompName.ComputerName

    strTargetAcct = strTargetAcctCommand

    'Call function to get target account SID

    strTargetAcctSID = LocalAcctSID(strTargetAcct)

    Else

    strTargetAcctLength = Len(strTargetAcctCommand)

    strSlashPos = InStr (strTargetAcctCommand, "\")

    strTargetAcct = Right(strTargetAcctCommand,strTargetAcctLength - strSlashPos)

    strTargetAcctDomain = Left(strTargetAcctCommand,strSlashPos - 1)

    ' Don't know if I can do different domains.

    If Not strDomain = "" Then

    If UCase (strTargetAcctDomain) <> UCase (strSourceAcctDomain) Then

    WScript.Echo "Sorry source domain " & Ucase (strSourceAcctDomain) &_

    " is different then target domain " & UCase (strSourceAcctDomain) &_

    ". Please check your spelling!"

    WScript.Quit

    Else

    'Suppose only do it on local computer

    strComputer ="."

    End If

    Else

    strDomain = strTargetAcctDomain

    End If  

    'Call function to get target account SID

    strTargetAcctSID = DomainAcctSID (strTargetAcct)

    End If

    'This part is looking the source profile

    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

    Set colProfiles = objWMIService.ExecQuery("Select * from Win32_UserProfile")

    For Each objProfile in colProfiles

       Set objSID = objWMIService.Get("Win32_SID.SID='" & objProfile.SID &"'")

    '    Testing to verify that the current profile handle is for

    '    the Source Account that we want to move to the domain user.

    If UCase(objsid.referencedDomainName + "\" + objsid.AccountName)= _  

    UCase(strSourceAcctDomain + "\" + strSourceAcct) Then

       ' Making sure that the source profile is currently not in use.  If it is we will bail out.

           strSourceAcctExist = "Yes"

           If objProfile.RefCount < 1 Then

               strContinue = MsgBox("Do you want to move Profile form:  " & vbNewLine & UCase (strSourceAcctDomain) + "\" & _

                             UCase (strSourceAcct) & vbNewLine & " to: " + UCase (strTargetAcctDomain) & "\" & UCase (strTargetAcct) & "?", _

                             vbYesNo & vbQuestion, "Move This Profile?")

               If strContinue = 6 Then   '6=Yes, Move the Profile.

    ' ChangeOwner method requires the String SID of Target Account and a Flag setting

    ' Flag 1 = Change ownership of the source profile to target account even if the target account  already has a profile on the system.

    ' Flag 2 = Delete the target account Profile and change ownership of the source user account profile to the target account.

    ' To use the ChangeOwner method, both the source and target account profiles (If it exists) must not be loaded.

    ObjProfile.ChangeOwner strTargetAcctSID,1

    WScript.Echo "Congratulations!" & vbNewLine & "User Profile is moved from: "& vbnewline & UCase (strSourceAcctDomain) + "\" & _

                             UCase (strSourceAcct) & vbNewLine & " to: " & UCase (strTargetAcctDomain) & "\" & UCase (strTargetAcct) & _

                              vbNewLine & "Process Complete."

                 ElseIf strContinue = 7 Then  '7=No, Cancel the move.

                   Wscript.Quit

                 Else

                   Wscript.Quit

               End If

        Else

               Wscript.echo "Could not move the users profile, because " & _

               UCase (strSourceAcctDomain) + "\" & UCase (strSourceAcct) & " profile is currently loaded"

      End If

    End If

    Next      

    If strSourceAcctExist <> "Yes" Then

    WScript.Echo "Please check source account! Coundn't find " & _

    UCase (strSourceAcctDomain) & "\" & UCase (strSourceAcct)

    End If

    Sub Init_IssueAuthorities( )

       'DIM IssueAuthorities(11)

       IssueAuthorities(0) = "-0-0"

       IssueAuthorities(1) = "-1-0"

       IssueAuthorities(2) = "-2-0"

       IssueAuthorities(3) = "-3-0"

       IssueAuthorities(4) = "-4"

       IssueAuthorities(5) = "-5"

       IssueAuthorities(6) = "-?"

       IssueAuthorities(7) = "-?"

       IssueAuthorities(8) = "-?"

       IssueAuthorities(9) = "-?"

    end sub

    Sub Syntax

     Wscript.Echo "Usage: Moveuser.vbs FromUser ToUser" _

     & VBNewLine _

     & VBNewLine _

     & vbNewLine & "Sample 1: Moveuser.vbs Fred Domain\Smithf" _

     & vbNewLine & "Sample 2: Moveuser.vbs Domain\John JaneDow" _

     & vbNewLine & "There should be no SPACE in account names!"

     Wscript.Quit

    End Sub

    Function DomainAcctSID (strAcct)

    Dim strAcctSID, strLDAPQuery

    strAcctSID=""

    Set objConnection = CreateObject("ADODB.Connection")

    objConnection.Provider = "ADsDSOObject"

    objConnection.Open "Active Directory Provider"

    Set objCommand = CreateObject("ADODB.Command")

    objCommand.ActiveConnection = objConnection

    strLDAPQuery = "SELECT AdsPath, cn FROM 'LDAP://" + strDomain + "' WHERE objectCategory='user'" & _

            " And sAMAccountName='" + strAcct + "'"

    objcommand.Properties("searchscope") = ADS_SCOPE_SUBTREE

    objCommand.CommandText = strLDAPQuery

    Set objRecordSet = objCommand.Execute

    If objRecordset.RecordCount = 0 Then

       WScript.Echo "Please check your target account! " & UCase (strAcct) & _

        " does not exist on " & UCase (strDomain) & "."

       WScript.Quit

    ElseIf objRecordset.RecordCount > 1 Then

       WScript.Echo "There is more than one account with the same sAMAccountName"

       WScript.Quit

    Else

       objRecordSet.MoveFirst

       Do Until objRecordSet.EOF

           Set Ousr = GetObject(objRecordSet.Fields("AdsPath").Value)

           strAcctSID = SDDL_SID(oUsr.Get("objectSID"))

           objRecordSet.MoveNext

       Loop

    objConnection.Close

    End If

    DomainAcctSID = strAcctSID

    End Function

    function SDDL_SID ( oSID )

       DIM Revision, SubAuthorities, strSDDL, IssueIndex, index, i, k, p2, subtotal

       DIM j, dblSubAuth

    '

    ' First byte is the revision value

    '

       Revision = "1-5"

    '

    ' Second byte is the number of sub authorities in the

    ' SID

    '

       SubAuthorities = CInt(ascb(midb(oSID,2,1)))

       strSDDL = "S-" & Revision

       IssueIndex = CInt(ascb(midb(oSID,8,1)))

    '

    ' BYtes 2 - 8 are the issuing authority structure

    ' Currently these values are in the form:

    ' { 0, 0, 0, 0, 0, X}

    '

    ' We use this fact to retrieve byte number 8 as the index

    ' then look up the authorities for an array of values

    '

       strSDDL = strSDDL & IssueAuthorities(IssueIndex)

    '

    ' The sub authorities start at byte number 9. The are 4 bytes long and

    ' the number of them is stored in the Sub Authorities variable.

    '

       index = 9

       i = index

       for k = 1 to SubAuthorities

           '

           ' Very simple formula, the sub authorities are stored in the

           ' following order:

           ' Byte Index Starting Bit

           ' Byte 0 - Index 0

           ' Byte 1 - Index + 1 7

           ' Byte 2 - Index + 2 15

           ' Byte 3 - Index + 3 23

           ' Bytes0 - 4 make a DWORD value in whole. We need to shift the bits

           ' bits in each byte and sum them all together by multiplying by powers of 2

           ' So the sub authority would be built by the following formula:

           '

           ' SUbAuthority = byte0*2^0 + Byte1*2^8 + byte2*2^16 + byte3*2^24

           '

           ' this be done using a simple short loop, initializing the power of two

           ' variable ( p2 ) to 0 before the start an incrementing by 8 on each byte

           ' and summing them all together.

           '

           p2 = 0

           subtotal = 0

           for j = 1 to 4

           dblSubAuth = CDbl(ascb(midb(osid,i,1))) * (2^p2)

           subTotal = subTotal + dblSubAuth

           p2 = p2 + 8

           i = i + 1

       next

    '

    ' Convert the value to a string, add it to the SDDL Sid and continue

    '

       strSDDL = strSDDL & "-" & cstr(subTotal)

       next

       SDDL_SID = strSDDL

    end Function

    Function LocalAcctSID(strAcct)

    strComputer ="."

    Set objWMIService = GetObject("winmgmts:\\" & strComputer &"\root\cimv2")

    Set colProfiles = objWMIService.ExecQuery("Select * from Win32_UserProfile")

    For Each objProfile in colProfiles

       Set objSID = objWMIService.Get("Win32_SID.SID='" & objProfile.SID &"'")

       If UCase (strAcct) = UCase(objSID.AccountName) Then

           strTargetAcctExist = "Yes"

    If UCase(strTargetAcctDomain)= UCase(objSID.ReferencedDomainName) Then

        LocalAcctSID = objProfile.Sid

        Exit Function

    End If

       End If

    Next

    If strTargetAcctExist <> "Yes" Then

    WScript.Echo "Please check your target account!  Can not find " & UCase (strAcct) & _

    "'s profile on " & UCase (strTargetAcctDomain) & "." & vbNewLine & _

    "If the account does exist, you need to log in as " & UCase (strAcct) & " on this computer first."

    WScript.Quit

    End If

    End Function