I want to write a application that writes to all users on a local machine a specified key (eg: i want set the location for IE Favorites for all users to the same folder)
PS anybody used these functions? LoadUserProfile RegOpenCurrentUser CreateProcessAsUser
I've done this many times. The idea is to update the currently logged on user's HKCU (that's easy enough). Then you must enumerate every profile on the system and find their ntuser.dat file (that's easy enough too).
With the ntuser.dat file found, you load it into a temporary key in the HKLM hive (I usually use 'HKLM\TempHive'. Then edit away.
If there is more than 1 user logged on, their profile will be loaded under HKEY_USERS, by their SID. Simply update that location.
To modify the setting for any new users, simply modify the appropriate key under HKEY_USERS.DEFAULT, OR use the Delphi code below which will do this by loading the Default Users's HKCU registry hive (stored in ntuser.dat).
UPDATE: I found my Delphi code that demonstrates how to update the HKCU hives of users that are not logged onto the system.
This requires Russell Libby's 'Privilege' component, which is available here.
//NOTE: sPathToUserHive is the full path to the users "ntuser.dat" file.
//
procedure LoadUserHive(sPathToUserHive: string);
var
MyReg: TRegistry;
UserPriv: TUserPrivileges;
begin
UserPriv := TUserPrivileges.Create;
try
with UserPriv do
begin
if HoldsPrivilege(SE_BACKUP_NAME) and HoldsPrivilege(SE_RESTORE_NAME) then
begin
PrivilegeByName(SE_BACKUP_NAME).Enabled := True;
PrivilegeByName(SE_RESTORE_NAME).Enabled := True;
MyReg := TRegistry.Create;
try
MyReg.RootKey := HKEY_LOCAL_MACHINE;
MyReg.UnLoadKey('TEMP_HIVE'); //unload hive to ensure one is not already loaded
if MyReg.LoadKey('TEMP_HIVE', sPathToUserHive) then
begin
//ShowMessage( 'Loaded' );
MyReg.OpenKey('TEMP_HIVE', False);
if MyReg.OpenKey('TEMP_HIVE\Environment', True) then
begin
// --- Make changes *here* ---
//
MyReg.WriteString('KEY_TO_WRITE', 'VALUE_TO_WRITE');
//
//
end;
//Alright, close it up
MyReg.CloseKey;
MyReg.UnLoadKey('TEMP_HIVE');
//let's unload the hive since we are done with it
end
else
begin
WriteLn('Error Loading: ' + sPathToUserHive);
end;
finally
FreeAndNil(MyReg);
end;
end;
WriteLn('Required privilege not held');
end;
finally
FreeAndNil(UserPriv);
end;
end;
I also wrote a VBScript a while ago that accomplishes this task. I used it for modifying some Internet Explorer settings, but you can customize it to your needs. It also demonstrates the general process:
Option Explicit
Dim fso
Dim WshShell
Dim objShell
Dim RegRoot
Dim strRegPathParent01
Dim strRegPathParent02
Set fso = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.shell")
'==============================================
' Change variables here
'==============================================
'
'This is where our HKCU is temporarily loaded, and where we need to write to it
RegRoot = "HKLM\TEMPHIVE"
'
strRegPathParent01 = "Software\Microsoft\Windows\CurrentVersion\Internet Settings"
strRegPathParent02 = "Software\Microsoft\Internet Explorer\Main"
'
'======================================================================
Call ChangeRegKeys() 'Sets registry keys per user
Sub ChangeRegKeys
'Option Explicit
On Error Resume Next
Const USERPROFILE = 40
Const APPDATA = 26
Dim iResult
Dim iResult1
Dim iResult2
Dim objShell
Dim strUserProfile
Dim objUserProfile
Dim strAppDataFolder
Dim strAppData
Dim objDocsAndSettings
Dim objUser
Set objShell = CreateObject("Shell.Application")
Dim sCurrentUser
sCurrentUser = WshShell.ExpandEnvironmentStrings("%USERNAME%")
strUserProfile = objShell.Namespace(USERPROFILE).self.path
Set objUserProfile = fso.GetFolder(strUserProfile)
Set objDocsAndSettings = fso.GetFolder(objUserProfile.ParentFolder)
'Update settings for the user running the script
'(0 = default, 1 = disable password cache)
WshShell.RegWrite "HKCU\" & strRegPathParent01 & "\DisablePasswordCaching", "00000001", "REG_DWORD"
WshShell.RegWrite "HKCU\" & strRegPathParent02 & "\FormSuggest PW Ask", "no", "REG_SZ"
strAppDataFolder = objShell.Namespace(APPDATA).self.path
strAppData = fso.GetFolder(strAppDataFolder).Name
' Enumerate subfolders of documents and settings folder
For Each objUser In objDocsAndSettings.SubFolders
' Check if application data folder exists in user subfolder
If fso.FolderExists(objUser.Path & "\" & strAppData) Then
'WScript.Echo "AppData found for user " & objUser.Name
If ((objUser.Name <> "All Users") and _
(objUser.Name <> sCurrentUser) and _
(objUser.Name <> "LocalService") and _
(objUser.Name <> "NetworkService")) then
'Load user's HKCU into temp area under HKLM
iResult1 = WshShell.Run("reg.exe load " & RegRoot & " " & chr(34) & objDocsAndSettings & "\" & objUser.Name & "\NTUSER.DAT" & chr(34), 0, True)
If iResult1 <> 0 Then
WScript.Echo("*** An error occurred while loading HKCU: " & objUser.Name)
Else
WScript.Echo("HKCU loaded: " & objUser.Name)
End If
WshShell.RegWrite RegRoot & "\" & strRegPathParent01 & "\DisablePasswordCaching", "00000001", "REG_DWORD"
WshShell.RegWrite RegRoot & "\" & strRegPathParent02 & "\FormSuggest PW Ask", "no", "REG_SZ"
iResult2 = WshShell.Run("reg.exe unload " & RegRoot,0, True) 'Unload HKCU from HKLM
If iResult2 <> 0 Then
WScript.Echo("*** An error occurred while unloading HKCU: " & objUser.Name & vbcrlf)
Else
WScript.Echo(" unloaded: " & objUser.Name & vbcrlf)
End If
End If
Else
'WScript.Echo "No AppData found for user " & objUser.Name
End If
Next
End Sub
We had the exact same issue the other day.
We discovered that you can just open the HKEY_USERS hive and write the changes to each user's SID.
And, If you want the settings to be present for any new users, you should also apply the settings to the HKEY_USERS/.DEFAULT key.
That is to say, just write your settings to...
HKEY_USERS\S-1-5-XX-XXXXXXXX-XXXXXXXXX-XXXXXXXX-XXXX\Software\...
For each of the SIDs present and:
HKEY_USERS\.DEFAULT\Software\...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With