Jump to content

ReProfiler


Anteaus
 Share

Recommended Posts

Update of May 10 2010: Version 0.3 now uploaded, several enhancements.

This utility allows for easy reassociation of a userprofile with its account, after any of the several kinds of mishap which can break that association.

Whilst the process can be done manually, it involved some fairly complex registry-hacking and permissions-changing. This GUI tool makes it easy enough for most beginners - although it should also save network admins some time and effort when joining or extracting computers from a domain.

Posted Image

Because of the diversity of profile-configs and the fundamental differences between XP and 7, getting this utility to work in all circumstances has proved something of a challenge. I imagine there are still a few cases which it can't cope with, although the new version should cover a lot more situations.

Relies heavily on Helge Klein's SetACL utility, which must be in the same folder.

A built version is available here. This contains all dependencies. To use, just expand the zip to any convenient place, and run reprofiler.exe

#RequireAdmin
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_icon=reprofiler.ico
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_UseAnsi=n
#AutoIt3Wrapper_Res_Description=Profile-association Repair Tool
#AutoIt3Wrapper_Res_Fileversion=0.3.0.0
#AutoIt3Wrapper_Res_LegalCopyright=IWR Consultancy, GPL v3
#AutoIt3Wrapper_Run_AU3Check=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
; ReProfiler
; Released by IWR Consultancy, under the GPL licence, v3.

#cs
Changelog:
v0.2->0.3
Now using 3.3.6.1 compiler and libraries, eliminates intermittent WMI bug causing "Error in line -1" message. Or, at least I hope it does!
Temporary registry SID assigned when account's hive is already in use, overcomes inability to set registry permissions in some circumstances.
Improved logic for handling changes to the active useraccount.
Using ICACLS to set filesystem permissions on Vista/7, as this handles the cyclic junctions better. Permissions are now set recursively on all supported OS's. 
v0.1->0.2
Now compiled with Autoit 3.3.0.0
New method of profile assignment, works in more situations. 
Several obscure problems with setting of registry-permissions fixed.
Erase Data now works for Windows 7.
Assignment of active user's profile now possible. 
(In most cases it is no longer necessary to logon as another user to change your own assignment)
Added detection of an attempt to delete the active profile. 
Properties panel is more informative.
#ce

opt ("TrayAutoPause",0)
opt ("TrayIconHide",1)
; #include "directives.au3"
#include <GUIConstants.au3>

global $appVersion = "0.3 alpha"
global $doswindow=@SW_MINIMIZE

if FileExists(@scriptdir & "\setacl.exe")=0 then
  local $msg=msgbox(52,"Missing Dependency","This utility requires setacl.exe to be present in its own folder. Without this, some functionality may not work correctly. You can download SetACL from http://setacl.sourceforge.net. Do you wish to continue without it?")
  if $msg<>6 then exit
endif

if $appVersion<1 then
  msgbox(48,"Development version " & $appVersion," Please be aware that this is a pre-production release. Whilst this version has been tested quite extensively, it has not yet been deployed in the field or used in real IT-support scenarios. Therefore, please use with caution and always back-up your data.")
endif

$logfile=@TempDir & "\ProfileReassignment.log"
if FileExists($logfile) then FileDelete($logfile)
$showSysItems=0
$showBy = "User Account"
$lvProfiles=-1
$lvUsers=-1
$prMode="user"

$SystemFolders="|Default User|All Users|NetworkService|LocalService|__sbs_netsetup__|"
$SystemUsers="|Default User|All Users|SBS Backup User|HelpAssistant|Administrator Tmpl|Power User Tmpl|guest|"

global $allowDelete="YES"
getprofiles()
getusers()
global $dirtyData=1 ; We got the data already, but we need to paint-in the GUI on first run.
; 0 no action, 1 repaint GUI only, 2 reload data and repaint GUI.

$ProfGUI=GUICreate("Profiles in: " & $profileroot,550,550, 100,200,-1)

$img1=GUICtrlCreateIcon(@ScriptFullPath,-1,34,12)
$Label1 = GUICtrlCreateLabel("ReProfiler", 94, 14, 249, 40)
GUICtrlSetFont(-1, 24, 800, 2, "Arial")
$Label2 = GUICtrlCreateLabel("Profile Link Repair Tool", 340, 18, 120, 17)
$Label4 = GUICtrlCreateLabel("By IWR Consultancy", 380, 38, 102, 17)

$inpSysItems=GUICtrlCreateCheckbox("Show System Items",300,235)
if $showSysItems then GuiCtrlSetState($inpSysItems,1)

$btnProperties=GuiCtrlCreateButton("Properties", 30, 450, 110, 30)
$btnExit=GuiCtrlCreateButton("Exit", 30, 500, 110, 30)
$btnAssign=GuiCtrlCreateButton("Assign", 180, 450, 110, 30)
$btnDetach=GuiCtrlCreateButton("Detach", 180, 500, 110, 30)
$btnDelete=GuiCtrlCreateButton("Erase Data", 320, 500, 110, 30)
$btnRefresh=GuiCtrlCreateButton("Refresh Views", 320, 450, 110, 30)

$lblUserList = GuiCtrlCreateLabel("User Accounts:", 10, 50, 105, 20)
$lblProfileList = GuiCtrlCreateLabel("Profile Folders:", 10, 250, 105, 20)

do ; Main UI loop
  if $dirtyData > 1 then
    ; reload data
    getprofiles()
    getusers()
  endif
  if $dirtyData > 0 then
    ; refill GUI values

    dim $lvCtrl[1000]
    $lvCtrl[0]=0
    if $lvProfiles<>-1 then
      GUICtrlDelete($lvProfiles)
    endif

    $lvProfiles = GUICtrlCreateListView (" Data Folder  |               Assigned User(s)         ",10,270,530,150);,$LVS_SORTDESCENDING)

    dim $plv[$profdirs[0]+1]
    for $ct=1 to $profdirs[0]
      $lvVarlist=$profdirs[$ct]
      if $showSysItems=0 and stringinstr($systemFolders,"|" & filename($profdirs[$ct]) & "|") then continueloop
      if $showSysItems=0 and stringinstr(filename($profdirs[$ct]),"SUPPORT_",1) then continueloop
      $thisPIP=$profdirs[$ct]
      $thisUsers=""
      $profileSID="{orphaned}"
      for $userct=1 to $users[0][0]
        if $users[$userct][2]=$thisPIP then
          if $thisUsers <> "" then $thisUsers=$thisUsers & ","
          $thisUsers=$thisUsers & $users[$userct][0] & "\" & $users[$userct][1]
          $profileSID=$users[$userct][3]
        endif
      next ; $userct
      if $thisUsers <>"" then
        $lvVarlist= $lvVarlist & "|" & $thisUsers 
      endif
      $plv[$ct]=GUICtrlCreateListViewItem($lvVarlist,$lvProfiles)
      $lvCtrl[$plv[$ct]]=$ct
      $plv[0]=$ct
    next ; $ct
    GUICtrlSendMsg($lvProfiles, 0x1000 + 30, 0, 280)
    GUICtrlSendMsg($lvProfiles, 0x1000 + 30, 1, 230)

    if $lvUsers<>-1 then
      GUICtrlDelete($lvUsers)
    endif

    $lvUsers = GUICtrlCreateListView ("    Host     |          User          |**|               Assigned Folder        | SID  ",10,70,530,150)
    dim $ulv[$users[0][0]+1]
    for $ct=1 to $users[0][0]
      if $showSysItems=0 and stringinstr($systemUsers,"|" & $users[$ct][1] & "|") then continueloop
      if $showSysItems=0 and stringinstr($users[$ct][1],"SUPPORT_",1) then continueloop
      if $users[$ct][0]=@computername then
        $lvVarlist="Local"
      else
        $lvVarlist="Domain"
      endif
      $uFlags="  "
      $lvVarlist= $lvVarlist & "|" & $users[$ct][1]
      if $users[$ct][5]>0 then $uFlags=StringReplace($uFlags,1, "A")
      if $users[$ct][6]>0 then $uFlags=StringReplace($uFlags,2, "X")
      $lvVarlist= $lvVarlist & "|" & $uFlags
      $lvVarlist= $lvVarlist & "|" & $users[$ct][2]
      $lvVarlist= $lvVarlist & "|" & $users[$ct][3]
      $ulv[$ct]=GUICtrlCreateListViewItem($lvVarlist,$lvUsers)
      $lvCtrl[$ulv[$ct]]=$ct
      $ulv[0]=$ct
    next

    GUICtrlSendMsg($lvUsers, 0x1000 + 30, 0, 100)
    GUICtrlSendMsg($lvUsers, 0x1000 + 30, 1, 160)
    GUICtrlSendMsg($lvUsers, 0x1000 + 30, 2, 25)
    GUICtrlSendMsg($lvUsers, 0x1000 + 30, 3, 220)
    GUISetState()
    $dirtyData=0
  endif ; End of data reload/paint sections

  $msg = GUIGetMsg()

  Select
    Case $msg = $btnRefresh
      $dirtyData = 2
    Case $msg = $btnAssign
      $dirtyData = 2
      prAssign()
    Case $msg = $btnDetach
      prDetach()
    Case $msg = $btnDelete
      prDelete()
    Case $msg = $btnProperties
      prProperties($prMode)
    Case $msg= $inpSysItems
      if GUICtrlRead($inpSysItems)= 1 then
        $showSysItems=1
      else
        $showSysItems=0
      endif
      $dirtyData=1
    Case $msg=$GUI_EVENT_CLOSE or $msg=$btnExit
      exitloop
  EndSelect
until 0

GUIDelete($ProfGUI)
exit

func prAssign()

  local $thisUser=$lvCtrl[GUICtrlRead($lvUsers)]
  local $thisProfile=$lvCtrl[GUICtrlRead($lvProfiles)]
  local $thisPath=$profdirs[$thisProfile]

  if $thisUser=0 or $thisProfile=0 then
    msgbox(48,"Input Error"," Please select a User and Profile from the respective lists before clicking Assign.")
    return -1
  endif

  select
  case ($profdirs[$thisProfile]=@userprofiledir) 
    $info="You are assigning a user to a profile which is currently in-use. Once completed you should RESTART the computer before attempting to test the result. Note that logging-off the current user is not sufficient, as this does not always fully unload the associated profile. Also be aware that if two users are assigned to the same profile, both accounts must never log-on simltaneously." & @lf & @lf & " - Do you wish to proceed?"
    local $msg=msgbox(52,"Please Note:", $info)
    $info=""
    if $msg <>6 then return 2
  case @username=$users[$thisUser][1] 
    $info="You are attempting to change the profile-assignment for the logged-on user. This may give rise to problems with the current user-session. It is suggested that you log-off and perform the reassignment under a separate account. If you elect to proceed with this change now, you should restart the computer immediately on completion." & @lf & @lf & " - Do you wish to proceed?"
    local $msg=msgbox(52,"Please Note:", $info)
    $info=""
    if $msg <>6 then return 2
  case else
    local $info="Do you wish to assign the User Account named:" & @crlf & $users[$thisUser][1] & @crlf & "As a trustee of the data stored in the profile folder:" & @crlf & $profdirs[$thisProfile]
    local $msg=msgbox(36,"Please Confirm your Choice:", $info)
    $info=""
    if $msg <>6 then return 2
  
  endselect

; Initialise new user if running Vista/7, as uninitialised users cannot have a profile assigned on these platforms:
 
do
    $thisDomain=$users[$thisUser][0]
    $thisName=$users[$thisUser][1]
    $thisSID=$users[$thisUser][3]
    $thisPIP=$users[$thisUser][2]
    if stringinstr("WIN_2003|WIN_XP|WIN_2000", @OSVersion) then exitloop
    if $thisPIP <> "" then exitloop
    $thisPwd=inputbox("User requires initialising","This user has not previously logged-on to this computer, or has been Detached from the profile since last logon. Please enter the user's password so that the account can be initialised")
    if @error>0 then exitloop
    $runstr=@comspec & " /c"
    $rtn=RunAs($thisName,$thisDomain,$thisPwd,1,$runstr,@ScriptDir,$doswindow)
    sleep(1000)
    getprofiles()
    $piploc = "HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\" & $thisSID
    $users[$thisUser][2] = RegRead($piploc,"ProfileImagePath")
  until 0
    $thisDomain=$users[$thisUser][0]
    $thisName=$users[$thisUser][1]
    $thisSID=$users[$thisUser][3]
    $thisPIP=$users[$thisUser][2]
;    $users[$thisUser][2] = RegRead($piploc,"ProfileImagePath")

  $profsz=regread("HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList","ProfilesDirectory")
  $thisAPath=$thisPath
  if stringinstr($thisPath,"\")=0 then $thisPath = $profsz & "\" & $thisPath
  ; (I see no reason to use an env string to determine location, as profiles are not relocatable anyway.) 
  $thisPath=stringreplace($thisPath,envget("SystemDrive"),"%SystemDrive%",1)
  $piploc = "HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\" & $thisSID
  $thisPIP=$thisPath
  
  ; Check for an  existing key with a temp PIP and warn user to log out before proceeding:
  $tempPIP=RegRead($piploc,"ProfileImagePath")
  if stringinstr($tempPIP,"temp") then
    $msg=msgbox(52,"Problem - Account in use", "This account is active with a temporary profile. If possible you should log this user off before trying to resssign the profile. Proceed anyway? ")
    if $msg <>6 then return 0
  endif

; Ideally should add check for any logon, not just temp. **
  
  ; Check for existence of Vista/7 '.bak' registry key:
  $thisPIPBak=RegRead($piploc & ".bak","ProfileImagePath")
  if @error=0 then 
    ; Probably best just to remove and re-create: 
    RegDelete($piploc & ".bak")
  endif

;  Check for an existing key with missing PIP entry and remove it if present: 
;  $existingKey=RegRead($piploc)
;  if @error=0 then
;    $existingPIP=RegRead($piploc","ProfileImagePath")
;    if @error then 
;      RegDelete($piploc)
;    endif
;  endif
  
 ; What follows is an undocumented hack which causes profile to be loaded if present, recreated from default if not:
  RegDelete($piploc,"ProfileLoadTimeHigh") 
  RegDelete($piploc,"ProfileLoadTimeLow")
  RegDelete($piploc,"RefCount") 
  RegDelete($piploc,"Sid") 
  RegWrite($piploc,"Flags","REG_DWORD",0xFFFFFFFF) 
  RegWrite($piploc,"ProfileImagePath","REG_EXPAND_SZ",$thisPIP)
  if @error=0 then
    $result= "Change ProfileImagePath for this user... OK" & @CRLF
  else
    $result= "Change ProfileImagePath for this user... FAIL" & @CRLF
  endif
  $thisHive=$thisAPath & "\NTUSER.DAT"
  $thisClassHive=$thisAPath & "\Local Settings\Application Data\Microsoft\Windows\UsrClass.dat"
  if $thisAPath<>@UserProfileDir then 
    $thisHKU=$thisSID
    $rlh=True
    $rlh1=RegLoadHive($thisHKU, $thisHive)
    $rlh2=RegLoadHive($thisHKU & "_Classes", $thisClassHive)
    if not $rlh1 then 
     $thisHKU="Reprofiler_HKU"
     $rlh1=RegLoadHive($thisHKU, $thisHive)
     $rlh2=RegLoadHive($thisHKU & "_Classes", $thisClassHive)
    endif
    $regUserSection='HKEY_USERS\' & $thisHKU
    ; msgbox(0,$thisAPAth & "apath>activeprofile" & @UserProfileDir,$thisHKU & "sid>hive" & $thisHive,10)
    if not $rlh1 then 
      msgbox(0,"User-Registry Load Failure","The attempt to load the registry-section for this user failed. This may be due to the useraccount already being active under a separate thread. This may result in permissions problems for the user, or problems saving settings under that account. It is suggested that you restart the computer and repeat the profile-assignment, ensuring that the useraccount is NOT active.",60 ) 
    endif
  Else
    $regUserSection='HKEY_CURRENT_USER'
    $rlh=False
    $rlh1=False
    $rlh2=False
    ; msgbox(0,"No Hive Load - " & $thisAPath & " - "  & @UserProfileDir,$rlh1 & " " & $rlh2) ;+msg
  EndIf
  FileDelete($logfile)
  if stringinstr("WIN_2003|WIN_XP|WIN_2000", @OSVersion) then
    $result = $result & "Change ownership of profile contents.. "
    $runstr = 'cmd /c setacl -ot file -on "' & $thisPIP & '\*" -ownr "n:' & $thisSID & ';s:y"  -actn setowner -rec cont_obj -log ' & $logfile
    $rtn1 = RunWait($Runstr,@scriptdir,$doswindow)
    if $rtn1=0 then 
      $rtn1="OK"
    else
      $rtn1="Warning: " & $rtn1
    endif
  else
  ; Because of Vista/7's cyclic symlinks, we use ICACLS here:
    $result = $result & "Add user ACL to profile contents with ICACLS.. "
;   $runstr = 'cmd /c setacl -ot file -on "' & $thisPIP & '" -ownr "n:' & $thisSID & ';s:y"  -actn setowner -log ' & $logfile
    $runstr = 'cmd /c icacls ' & $thisPIP & ' /grant *' & $thisSID & ':F /T /C >>icacls.' & $logfile
    $rtn1 = RunWait($Runstr,@scriptdir,$doswindow)
    if $rtn1=1 then 
      $rtn1="OK"
    else
      $rtn1="Warning: " & $rtn1
    endif
  endif
  $result = $result & $rtn1 & @CRLF
  $runstr = 'cmd /c setacl -ot file -on "' & $thisPIP & '" -ace "n:' & $thisSID & ';s:y;p:full"  -actn ace -log ' & $logfile
  $result = $result & "Add user as trustee of profile root... "
  $rtn2 = RunWait($Runstr,@scriptdir,$doswindow)
  if $rtn2=0 then $rtn2="OK"
  $result = $result & $rtn2 & @CRLF
  $runstr = 'cmd /c setacl -ot reg -on "' & $regUserSection & '" -ace "n:' & $thisSID & ';s:y;p:full"  -actn ace -log ' & $logfile
  $result = $result & "Add user as trustee of registry hive... "
  $rtn3 = RunWait($Runstr,@scriptdir,$doswindow)
  if $rtn3=0 then $rtn3="OK"
  $result = $result & $rtn3 & @CRLF
  ;$runstr = 'setacl -ot reg -on "' & $regUserSection & '_Classes" -ace "n:' & $thisSID & ';s:y;p:full"  -actn ace -silent -log ' & $logfile
  ;$result = $result & "Add user as trustee of classes registry hive... "
  ;$rtn4 = RunWait($Runstr,@scriptdir,$doswindow)
  ;if $rtn4=0 then $rtn4="OK"
  ;$result = $result & $rtn4 & @CRLF
  $ruh1="undefined"
  $ruh2="undefined"
  if $rlh1 then $ruh1=RegUnLoadHive($thisHKU)
  if $rlh2 then $ruh2=RegUnLoadHive($thisHKU & "_Classes")
  ; msgbox(0,"Hive Unload",$ruh1 & " " & $ruh2) ;+msg

  $result = $result & @CRLF & "Do you wish to see the log file?"

  $msg=msgbox (68,"Profile Reassigned",$result)
  if $msg=6 then
    $runstr="notepad " & $logfile
    Run($runstr)
  endif

endfunc   ;==>prAssign

func getprofiles($_pathtoscan="")

  $_listidx=0

  if $_pathtoscan="" then
    $profdir=regread("HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList","ProfilesDirectory")
    $profdir=StringReplace($profdir,"%SystemDrive%",envget("SystemDrive"))
    $_pathtoscan=$profdir
  endif

  global $profileRoot=$_pathtoscan

  if stringright($_pathtoscan,1)<>"\" then $_pathtoscan = $_pathtoscan & "\"

  global $profdirs[10000]

  $_thisMask = $_pathToScan & "*.*"
  $_spSearch = FileFindFirstFile ( $_thisMask )

  While 1
    If $_spSearch = -1 then ExitLoop
    $_file = FileFindNextFile($_spSearch)
    If @error Then ExitLoop

    $_FQSrcName = $_pathtoscan &  $_file
    $_srcFileAttribs = FileGetAttrib($_FQSrcName)

    if stringinstr($_srcFileAttribs,"D") then
      $_listidx=$_listidx+1
      $profdirs[$_listidx]=  $profileRoot & "\" & $_file
    endif

  WEnd
  $profdirs[0]=$_listidx
endfunc   ;==>getprofiles

func getusers()

  ; Return string array of useraccounts containing Domain, Name, ImagePath, SID, FolderExists
  ; Element 0,0 is total accounts.

  $wbemFlagReturnImmediately = 0x10
  $wbemFlagForwardOnly = 0x20
  $colItems = ""
  $strComputer = "localhost"
  $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
  if @error then
   msgbox(16,"WMI Error","Unable to connect to the Windows Management Interface service. This may be due to the WMI service having been disabled, or due to a third-party firewall or other security software which is preventing or interfering-with access. We suggest as a starting-point that you run services.msc and check the condition of the WMI service." & @crlf & @crlf & "Unable to continue, therefore Exiting.",60)
   Exit
  endif
  $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_UserAccount", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

  global $users[10000][7]
  $ct=0

  #cs
    0=domain
    1=name
    2=pip
    3=sid
    4=folderexists
    5=isLoggedOn  
    6=broken
  #ce

  If IsObj($colItems) then
    For $objItem In $colItems
      $ct=$ct+1
      $users[$ct][0] = $objItem.Domain
      $users[$ct][1] = $objItem.Name
      $users[$ct][3] = $objItem.SID
      $users[$ct][5] = 0
      $users[$ct][6] = 0
      $piploc = "HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\" & $users[$ct][3]
      $users[$ct][2] = RegRead($piploc,"ProfileImagePath")
      if @error or StringInStr($users[$ct][2],"\TEMP") then 
        ; msgbox(0,"pip","notfound")
        $piploc = "HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\" & $users[$ct][3] & ".bak"
        $tmp = RegRead($piploc,"ProfileImagePath")
        if @error=0 then 
            $users[$ct][2] = $tmp
            $users[$ct][6] = 1
        endif
      endif
      $users[$ct][2]=StringReplace($users[$ct][2],"%SystemDrive%",envget("SystemDrive"))
      if stringlen($users[$ct][2])>0 then
        if FileExists($users[$ct][2] & "\NTUSER.DAT") then
          $users[$ct][4]=1
        else
          $users[$ct][4]=0
        endif
      endif
      ;Find out if account is logged-on:      
      $users[$ct][5]=0
      $LogonItems = $objWMIService.ExecQuery("SELECT * FROM Win32_LoggedOnUser", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
      If IsObj($LogonItems) then
        For $LogonItem In $LogonItems
        $thisName=$LogonItem.Antecedent
         ; msgbox(0,"logon",$thisname)
         if stringinstr($LogonItem.Antecedent,'name="' & $users[$ct][1] & '"')then 
           $users[$ct][5]=1
         endif 
        next
      endif
    Next
    $users[0][0]= $ct
  Else
    Msgbox(16,"WMI Error","The WMI service is required for this tool to function, and does not appear to be running. Cannot continue." )
  Endif
    
endfunc   ;==>getusers

func filename ($_pathtostrip)
  return stringmid($_pathtostrip,stringinstr($_pathtostrip,"\",0,-1) +1 ,255)
endfunc   ;==>filename


; === RegLoadHive ===
; Loads a ntuser.dat file as a registry hive
; Requires SetPrivilege function.
;
; Inputs:   $hiveName       - name for the hive
;           $NTUSER_datFile - full path to ntuser.dat file to load
;           $RLH_key        - (optional) root for hive (defaults to HKU)
;
; Returns:  1 - Successful
;           0 - Error (sets @error)

Func RegLoadHive($hiveName, $NTUSER_datFile, $RLH_key = "HKU")
  If Not (@OSTYPE=="WIN32_NT") Then
    SetError(-1)
    Return 0
  EndIf
  Const $HKEY_LOCAL_MACHINE = 0x80000002
  Const $HKEY_USERS = 0x80000003
  Const $SE_RESTORE_NAME = "SeRestorePrivilege"
  Const $SE_BACKUP_NAME = "SeBackupPrivilege"
  Local $RLH_ret
  Local $aPriv[2]
  If $RLH_key = "HKLM" Then
    $RLH_key = $HKEY_LOCAL_MACHINE
  ElseIf $RLH_key = "HKU" Then
    $RLH_key = $HKEY_USERS
  Else
    SetError(-2)
    Return 0
  EndIf
  $aPriv[0] = $SE_RESTORE_NAME
  $aPriv[1] = $SE_BACKUP_NAME
  SetPrivilege($aPriv,1)
  $RLH_ret = DllCall("Advapi32.dll","int","RegLoadKey","int",$RLH_key,"str",$hiveName,"str",$NTUSER_datFile)
  SetError($RLH_ret[0])
  Return Not $RLH_ret[0]
EndFunc   ;==>RegLoadHive
; === END RegLoadHive ===


; === RegUnloadHive ===
; Unloads a registry hive
; Requires SetPrivilege function.
;
; Inputs:   $hiveName       - name for the hive
;           $RLH_key        - (optional) root for hive (defaults to HKU)
;
; Returns:  1 - Successful
;           0 - Error (sets @error)
Func RegUnloadHive($hiveName, $RUH_key = "HKU")
  If Not (@OSTYPE=="WIN32_NT") Then
    SetError(-1)
    Return 0
  EndIf
  Const $HKEY_LOCAL_MACHINE = 0x80000002
  Const $HKEY_USERS = 0x80000003
  Local $RUH_ret
  If $RUH_key = "HKLM" Then
    $RUH_key = $HKEY_LOCAL_MACHINE
  ElseIf $RUH_key = "HKU" Then
    $RUH_key = $HKEY_USERS
  Else
    SetError(-2)
    Return 0
  EndIf
  $RUH_ret = DllCall("Advapi32.dll","int","RegUnLoadKey","int",$RUH_key,"Str",$hiveName)
  Return Not $RUH_ret[0]
EndFunc   ;==>RegUnloadHive
; === RegUnloadHive ===


; === SetPrivilege ===
; Special function for use with registry hive functions
Func SetPrivilege( $privilege, $bEnable )
  Const $TOKEN_ADJUST_PRIVILEGES = 0x0020
  Const $TOKEN_QUERY = 0x0008
  Const $SE_PRIVILEGE_ENABLED = 0x0002
  Local $hToken, $SP_auxret, $SP_ret, $hCurrProcess, $nTokens, $nTokenIndex, $priv
  $nTokens = 1
  $LUID = DLLStructCreate("dword;int")
  If IsArray($privilege) Then    $nTokens = UBound($privilege)
  $TOKEN_PRIVILEGES = DLLStructCreate("dword;dword[" & (3 * $nTokens) & "]")
  $NEWTOKEN_PRIVILEGES = DLLStructCreate("dword;dword[" & (3 * $nTokens) & "]")
  $hCurrProcess = DLLCall("kernel32.dll","hwnd","GetCurrentProcess")
  $SP_auxret = DLLCall("advapi32.dll","int","OpenProcessToken","hwnd",$hCurrProcess[0], _
      "int",BitOR($TOKEN_ADJUST_PRIVILEGES,$TOKEN_QUERY),"int*",0)
  if @error then 
    msgbox(16,"Error","Unable to set permissions on user registry")
    return 0
  endif
  If $SP_auxret[0] Then
    $hToken = $SP_auxret[3]
    DLLStructSetData($TOKEN_PRIVILEGES,1,1)
    $nTokenIndex = 1
    While $nTokenIndex <= $nTokens
      If IsArray($privilege) Then
        $priv = $privilege[$nTokenIndex-1]
      Else
        $priv = $privilege
      EndIf
      $ret = DLLCall("advapi32.dll","int","LookupPrivilegeValue","str","","str",$priv, _
          "ptr",DLLStructGetPtr($LUID))
      If $ret[0] Then
        If $bEnable Then
          DLLStructSetData($TOKEN_PRIVILEGES,2,$SE_PRIVILEGE_ENABLED,(3 * $nTokenIndex))
        Else
          DLLStructSetData($TOKEN_PRIVILEGES,2,0,(3 * $nTokenIndex))
        EndIf
        DLLStructSetData($TOKEN_PRIVILEGES,2,DllStructGetData($LUID,1),(3 * ($nTokenIndex-1)) + 1)
        DLLStructSetData($TOKEN_PRIVILEGES,2,DllStructGetData($LUID,2),(3 * ($nTokenIndex-1)) + 2)
        DLLStructSetData($LUID,1,0)
        DLLStructSetData($LUID,2,0)
      EndIf
      $nTokenIndex += 1
    WEnd
    $ret = DLLCall("advapi32.dll","int","AdjustTokenPrivileges","hwnd",$hToken,"int",0, _
        "ptr",DllStructGetPtr($TOKEN_PRIVILEGES),"int",DllStructGetSize($NEWTOKEN_PRIVILEGES), _
        "ptr",DllStructGetPtr($NEWTOKEN_PRIVILEGES),"int*",0)
    $f = DLLCall("kernel32.dll","int","GetLastError")
  EndIf
  $NEWTOKEN_PRIVILEGES = 0
  $TOKEN_PRIVILEGES = 0
  $LUID = 0
  If $SP_auxret[0] = 0 Then Return 0
  $SP_auxret = DLLCall("kernel32.dll","int","CloseHandle","hwnd",$hToken)
  If Not $ret[0] And Not $SP_auxret[0] Then Return 0
  return $ret[0]
EndFunc   ;==>SetPrivilege
; === SetPrivilege ===


func ReLaunch()

  ; (Not used with later script versions)
  if isAdmin() then return 1

  $msg=MsgBox(52,"Administrative rights necessary","This utility needs adminstrative rights in order to perform its function, but has been started under an account with limited rights. Do you wish to attempt to re-start the app under the Administrator account?")
  if $msg=6 then
    $pwd=inputbox("Password Required","Please enter the Administrator password for this computer")
    RunAs("Administrator",@computername,$pwd,0,@scriptfullpath,@scriptdir)
    exit
  endif

  return 0
endfunc   ;==>ReLaunch

func prDelete()
  local $thisUser=$lvCtrl[GUICtrlRead($lvUsers)]
  local $thisProfile=$lvCtrl[GUICtrlRead($lvProfiles)]
  local $thisPath=$profdirs[$thisProfile]
  local  $thisDomain=$users[$thisUser][0]
  local  $thisName=$users[$thisUser][1]
  local  $thisSID=$users[$thisUser][3]
  local  $thisPIP=$users[$thisUser][2]

  if stringlen($thisPath)<5 then
    msgbox(64,"No action taken","Nothing selected to erase. Please highlight a profile-folder first.",10 )
    return 0
  endif
  if stringinstr(@AppDataDir,$thisPath) then
    msgbox(16,"Foot-Shooting Attempt Detected!","You are attempting to delete the active user's profile. If successful, this would cause system instability. Action blocked.",10 )
    return 0
  endif
  $msg=msgbox(52,"Caution - action removes data","Permanently ERASE " & $thisPath & "  and all of its contents?." & @cr & @cr & "This folder may contain personal documents, pictures, email, etc. Do not proceed unless you are CERTAIN the data it contains is no longer needed." & @cr & @cr & "Under Windows XP it is generally OK to delete active profiles, in which case they will be re-created from the Default profile at next log-on. " & @cr & @cr & "However, under Vista or Windows 7, deleting a profile with a user still attached may lead to trouble with the account. "& @cr & @cr & " Proceed? ")
  if $msg=6 then
    if $allowDelete<>"YES" then
      $allowDelete=inputbox("Delete Data","To confirm this action, please type YES into the box below. ")
      if $allowDelete <> "YES" then return 0
    endif
    $runstr="cmd /c rd /s /q " & $thisPath
    RunWait($runstr,@ScriptDir,$doswindow)
    $result=DirGetSize($thisPath)
    if $result=-1 then
      msgbox(64,"Profile Deleted","The selected profile-folder has been removed from the hard-disk.")
    else
      msgbox(48,"Profile Delete Attempted, " & $result / 1024 / 1024 & "MB Data Remaining","The attempt to remove the profile has not been entirely successful. This may be due to files being held-open by useraccounts which are presently logged-on, or to network shares within the profile-folder being accessed from other computers.It is suggested that a freah attempt is made after a restart, ensuring that only the Administrator account is allowed to log-on."  )
    endif
    $dirtyData=2
  endif
endfunc   ;==>prDelete

func prDetach()
  local $thisUser=$lvCtrl[GUICtrlRead($lvUsers)]
  local $thisProfile=$lvCtrl[GUICtrlRead($lvProfiles)]
  local $thisPath=$profdirs[$thisProfile]
  local  $thisDomain=$users[$thisUser][0]
  local  $thisName=$users[$thisUser][1]
  local  $thisSID=$users[$thisUser][3]
  local  $thisPIP=$users[$thisUser][2]
  $piploc = "HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\" & $thisSID
  $confPIP= RegRead($piploc,"ProfileImagePath")

  if stringlen($thisPath)<5 or stringlen($thisName)=0 then
    msgbox(48,"Items Not Selected","Unable to proceed. Please highlight a user-account and a profile-folder which you wish to dissociate from each other, then try again.")
    return 0
  endif

  if $thisPIP <> $thisPath then
    msgbox(48,"Not Associated","The specified user-account ("&$thisName&") is not presently a trustee of the selected data folder ("&$thisPath&") therefore no action has been taken.")
    return 0
  endif

  $msg=msgbox(36,"Detach profile from useraccount","Do you wish to cancel the ownership of the data stored in " & @cr & $thisPIP & @cr & " by user " & @cr & $thisDomain & "\" & $thisName & " ?" & @cr & "(This action will not delete data, but it might make the data inaccessible to the user.)")
  if $msg <>6 then return 0
  if $thisSID="" then return 0 ; Precaution against deleting profile-root key. 
  if @osbuild>5000 then 
    RegDelete($piploc)
  else
    RegDelete($piploc,"ProfileImagePath")
  endif
  $dirtyData=2
endfunc   ;==>prDetach

func prProperties($_mode="profile")
  local $thisUser=$lvCtrl[GUICtrlRead($lvUsers)]
  local $thisProfile=$lvCtrl[GUICtrlRead($lvProfiles)]
  local $thisPath=$profdirs[$thisProfile]
  local  $thisDomain=$users[$thisUser][0]
  local  $thisName=$users[$thisUser][1]
  local  $thisSID=$users[$thisUser][3]
  local  $thisPIP=$users[$thisUser][2]
  local $thisBAK=""
  local $thisON=""
  if $users[$thisUser][6] then  $thisBAK="Warning: Temporary profile - Indicates problem with associated profile, or with registry ProfileImagePath pointer." & @lf
  if $users[$thisUser][5] then $thisON="Note: This account is active. Best to log off before making changes." & @lf
  $pParams=""
  $uParams=""
  if stringlen($thisPath)<5 then
   $pParams="Unable to get profile information, possibly none selected from list, or data is incomplete." & @lf
  endif
  $size   = DirGetSize($thisPath,1)
  $tLL =  FileGetTime($thisPath & "\NTUSER.DAT", 0)
  if  @error =0 Then
   $lastLogon=$tLL[0] & "/" & $tLL[1] & "/" & $tLL[2]
    if IsArray($size) Then
     $pParams="Selected Profile Folder Information" & @lf & "Path: " & $thisPath & @lf & "Size: " & round($size[0]/1024/1024) & "MB" & @LF  & "Files: " & $size[1] & @LF & "Dirs: " & $size[2] & @LF & "Last Interactive Logon (YMD): " & $lastLogon
    endif
  else
    $pParams="No information available, possibly this profile has never been logged-on interactively." & @lf
  EndIf
 
  if $thisName <>"" then  
  if $thisPIP="" then $thisPIP="None Allocated"
  $uParams="Selected User Account Information" & @lf & "Name: " & $thisName & @LF  & "Domain: " & $thisDomain & @LF & "SID(GUID): " & $thisSID & @LF & "Profile Image Path: " & $thisPIP & @LF & $thisBAK & $thisON
  else
   $uParams="Unable to get user information, possibly none selected from list, or account is damaged." & @lf
  endif
 
   Msgbox(64,"User and Profile Information",$UParams & @lf & "-------------" & @lf & @lf & $pParams,120 )

endfunc   ;==>prProperties
 
Func WMIDateStringToDate($dtmDate)

    Return (StringMid($dtmDate, 5, 2) & "/" & _
    StringMid($dtmDate, 7, 2) & "/" & StringLeft($dtmDate, 4) _
    & " " & StringMid($dtmDate, 9, 2) & ":" & StringMid($dtmDate, 11, 2) & ":" & StringMid($dtmDate,13, 2))
EndFunc

As per most of my scripts this is a system-level utility, so use with care.

If compiling from source, use 3.3.6.1 Aut2EXE and libraries. Note that some features will NOT work correctly if run interpreted.

Edited by Anteaus
Link to comment
Share on other sites

Cool.Thanks for share & Respect.

But Anteaus this script is unable get users profile which enter 2 local groups:

Here is from console:(users => root and => user is restricted user and have not administrative rights)

SSID for user: S-1-5-21-436374069-299502267-839522115-1005

SSID for root:S-1-5-21-436374069-299502267-839522115-1003

and if i try get Properties for this users from your script:(and from compiled version of your script too)

script is terminated with error:Here is:

Posted Image

Please fix it.Thanks again

In this case if i try get properties for this users:

C:\Documents and Settings\user>net user

Учетные записи пользователей для \\compname

--------------------------------------------------------------------------
Admin                    ASPNET                   Domain
DroppedRights            HelpAssistant            root
SUPPORT_388945a0         user                     vmlinuz
Администратор            Гость
Команда выполнена успешно.


C:\Documents and Settings\user>net user root
Имя пользователя                       root
Полное имя
Комментарий
Комментарий пользователя
Код страны                             000 (Стандартный системный)
Учетная запись активна                 Yes
Учетная запись просрочена              Никогда

Последний пароль задан                 4/26/2009 2:22 PM
Действие пароля завершается            Никогда
Пароль допускает изменение             4/26/2009 2:22 PM
Требуется пароль                       Yes
Пользователь может изменить пароль     No

Разрешенные рабочие станции            Все
Сценарий входа
Конфигурация пользователя
Основной каталог
Последний вход                         8/20/2009 11:36 AM

Разрешенные часы входа                 Все

Членство в локальных группах           *hiddengroup
                                       *Пользователи
Членство в глобальных группах          *Отсутствует
Команда выполнена успешно.


C:\Documents and Settings\user>net user user
Имя пользователя                       user
Полное имя                             Non Identified restricted user
Комментарий                            Non Identified restricted user
Комментарий пользователя
Код страны                             000 (Стандартный системный)
Учетная запись активна                 Yes
Учетная запись просрочена              Никогда

Последний пароль задан                 4/8/2009 6:48 PM
Действие пароля завершается            Никогда
Пароль допускает изменение             4/8/2009 6:48 PM
Требуется пароль                       Yes
Пользователь может изменить пароль     No

Разрешенные рабочие станции            Все
Сценарий входа
Конфигурация пользователя
Основной каталог
Последний вход                         12/15/2009 10:58 PM

Разрешенные часы входа                 Все

Членство в локальных группах           *hiddengroup
                                       *Пользователи
Членство в глобальных группах          *Отсутствует
Команда выполнена успешно.



C:\Documents and Settings>net localgroup hiddengroup
Имя псевдонима     hiddengroup
Комментарий        Restricted users

Члены

---------------------------------------------------------------------
root
user
Команда выполнена успешно.
Edited by Sh3llC043r
[size="5"] [/size]
Link to comment
Share on other sites

Update; Found problem. It isn't anything to do with groups or character-sets, rather it's simply that a request for Properties doesn't always trap a situation where there are none to be retrieved, as with a folder which has no associated user.

Will flag for fixing with the next build. Thanks for pointing it out.

Also worth mentioning that there are a few SBC issues with this project (which I started a while back and shelved) which mean the latest compiler can't be used with this source. Will update to use 3.3x when I get around to it. For the moment best to use the built version.

--------------

You got me there. Hasn't been tested with international character-sets so I'm not sure what the issue is.

It would be useful to know what error is displayed using the interpreter to run the script, since that would include a line number. From the look of the message it must be coming from a function which normally returns an array of values, but in this case returns null.

I'll see if I can duplicate it, though I doubt if I can set-up the same test conditions here.

Edited by Anteaus
Link to comment
Share on other sites

  • 1 month later...
  • 3 months later...
  • 8 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...