I have a task coming up where I have to manually enter an HKEY_USER key value and string value for every single Windows profile on all computers. This could take some time. I have leant to automate them all, or at least, some of the processes.
I have the adding key process (from a list of sids.txt) working:
#echo off
pushd %~dp0
for /f "usebackq tokens=*" %%A in ("SIDS.txt") do (
REG ADD "%%A\create\key\here" /f
REG ADD "%%A\create\key\here" /t REG_SZ /d "add string value here" /f
)
pause
To further speed things up I was hoping to get some help getting the SID from each user profile from here:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
For each SID listed e.g.:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-21-2686047782-4092528985-2296408390-1413
Within the keys there is a profile-image-path value which contains the name of the Windows user profile.
What I would like to be able to do is pump the Windows profile name and the sid into a text file formatted like the following, then I can edit fairly quickly, remove non-Windows user profile entries (like default or system accounts) and run my working code above against the listings - edited to have just a list of SIDS like in the working code above.
S-1-5-21-2686047782-4092528985-2296408390-1413 mickey.mouse
S-1-5-21-2686047782-4092528985-2296408390-1411 Donald.duck
Simplest method would beto do it with wmic useraccount query:
wmic useraccount get name,sid | findstr /vi "SID">somefile.txt
type somefile.txt
This would list every account and redirect output to a file called somefile.txt and it will simply type the file to show you the content of the file.
Another way is to see if the userprofile directory exists. which should eliminate system accounts.
#for /f "delims=" %i in ('wmic useraccount get name^,sid ^| findstr /vi "SID"') do #for /F %a in ("%i") do if exist "C:\users\%a" #echo(%i>>somefile.txt
Related
Trying to record a user client IP for a remote session. Currently have a little batch file recording logon times, and hostname. Need to also include the client IP address;
Currently using this;
reg query "HKEY_CURRENT_USER\Volatile Environment" /s > %temp%\IPINFO.txt
findstr /L ViewClient_IP_Address %temp%\IPINFO.txt > %temp%\IPRESULTS.txt
FOR /F “tokens=* delims= ” %%a in (%temp%\IPRESULTS.txt) do set IP=%%a
del %temp%\IPRESULTS.txt
set IP=%IP%
echo Login ,%Date%,%Time%,%computername%,%clientname%,%IP% >> Y:\%username%.csv
The registry key viewclient_ip_Address has the information I need, but the registry folder it sits within changes name each time so I'm having to export the whole directory and then filter for the key itself.
I just need to add the information from that IPRESULTS.txt into my end .csv file but struggling with writing it up.
Any help appreciated.
Is this what you're looking for? (The for-loop runs the command and parses it's output in memory)
For /F "EOL=HTokens=2*" %%H In ('^""%__AppDir__%reg.exe" Query "HKCU\Volatile Environment" /V ViewClient_IP_Address 2^>NUL^"')Do Set "IP=%%~I"
To find out more about how to use reg.exe with query, open up a Command Prompt window and enter reg query /?
If, as you've stated in your question, the required value and data is located under HKEY_CURRENT_USER\Volatile Environment but within a variable/unknown, subkey name, the help information should show you that you can use the /F option to locate your known value name, ViewClient_IP_Address, if you specify that the search is to locate a value using /V, it should retrieve the line you need.
For example, at the Command Prompt:
Reg Query "HKCU\Volatile Environment" /S /F "ViewClient_IP_Address" /V
Returns:
C:\Users\smith_ll>Reg Query "HKCU\Volatile Environment" /S /F "ViewClient_IP_Add
ress" /V
HKEY_CURRENT_USER\Volatile Environment\UnknownSubKey
ViewClient_IP_Address REG_SZ 192.168.1.15
End of search: 1 match(es) found.
You can then put that command into your for-loop, and pass its output through find.exe to isolate the line you need to parse. The underscore, for instance, looks unique to just the line you need. As we're already excluding any line beginning with H ,(with EOL=H), it will not match the End of search: 1 match(es) found. line:
Example:
For /F "EOL=HTokens=2*" %%H In ('^""%__AppDir__%reg.exe" Query "HKCU\Volatile Environment" /S /F "ViewClient_IP_Address" /V 2^>NUL^|"%__AppDir__%find.exe" "_"^"')Do #Set "IP=%%~I"
If you don't like the super long line, you can split into more using the caret:
For /F "EOL=HTokens=2*" %%H In ('^""%__AppDir__%reg.exe" Query^
"HKCU\Volatile Environment" /S /F "ViewClient_IP_Address" /V 2^>NUL^
^|"%__AppDir__%find.exe" "_"^"')Do #Set "IP=%%~I"
edit re explanation to improve answers.
Project
As a third party engineer I am attending a site to install a piece of Software. The Infrastructure is "very" locked down. I will be supplied with an admin account for the day to install the software. However, to make the software work properly FOR ALL USERS (not just admin logged in) I have been instructed by IT dept. to manually create a KEY and then add a string value within created key for every user account on the PC. Our software in a standard environment caters for this with an all users reg key but it doesn't run (not allowed - don't ask!) in these specific places.
The location of where they want the the KEY is within the HKEY_USERS path in the reg:-
HKEY_USERS\S-1-5-21-XXXXXXXXX-XXXXXXXXX-XXXXXXXXXX-XXXXX\Software\Microsoft\
so lets say 2 people logged in this PC and they need to use our software later on
john.jones
mary.shelley
I need to find the sid relating to john jones and go and add the key to his section in HKEY_USERS
I then need to find mary.shelley sid and then go and the key to her HKEY_USERS section, etc.
Now I know from the environments I work in there could be 20 + user acounts on there so really would like to avoid manually adding they keys over and over for all the accounts on every PC I'm installing at.
A log on script would be better, but this all I have to deal with at present.
State of Script Now
#echo off
REM Read file with user names
FOR /F "usebackq tokens=*" %%G in ("users.txt") do (
REM use user name to find SID
FOR /F "delims=" %%H IN ('"wmic useraccount where name='%%~G' get sid| findstr /vi "SID""') DO (
REM Strip trailing line with CR
FOR /F "delims= " %%I IN ("%%~H") DO (
REM %%I is now the SID of the USER
REG ADD "HKEY_USERS\%%I\Software\Microsoft\addstuffhere" /f
REG ADD "HKEY_USERS\%%I\Software\Microsoft\addstuffhere" /t REG_SZ /d "addstuffhere"" /f
)
)
)
This is pretty much automating the whole thing as planned; loops through a text file of user names of users who use the PC, grabs the SID, applies sid as variable, then is used to write the key in the right place for that user, and on through the list doing to same for every account listed.
The only part that may need altering is the WMIC section is not finding certain users who have bona fide windows accounts.
when I tested the working code on my laptop it worked fine for my administrator account, but me logged in as joe_blogs (e.g.) came up with "no instance available". Because in isolation the WMIC code just brought up only a few not all, so couldn't do what it needed to do.
I know from previous questions this WMIC code brings up every account:-
WMIC Path Win32_UserProfile Where "Special='False' And Not LocalPath='Null'" Get LocalPath,SID | find /v ""
Perhaps that can be incorporated into current working code to make sure every account is catered for.
I know the users all need to have logged in at each PC for this to work, so with regards to the list of user profiles, I can garner that on the day asking "who of your users needs to use our stuff on the PC's" and make the users.txt
thanks - hope that really explains it :/
edit instructions for what I have been asked to do (altered key names slightly for privacy)
1. Log on to the PC with a standard technician admin account
2. Open regedit.exe
3. Navigate to* HKEY_USERS\S-1-5-21-XXXXXXXXX-XXXXXXXXX-XXXXXXXXXX- XXXXX\Software\Microsoft\Terminal Server Client\Default\Addins\
a. Right-click Addins > New > Key and create foo
b. Right-click foo > New > String Value and create Name
c. Double-click Name and in Value Data enter† C:\foo\file\foo.dll
4. Repeat step 3 for each user: it should be possible to edit the SID in an exported key by right-clicking on the next
HKEY_USERS entry > Rename > Ctrl+C > Esc then replacing the SID in the exported reg key – this has not been tested but may be worth trying
*The user SID is unique so this has to be done per user. If there are a lot of users listed in the registry it is possible to find which SID belongs to which user by checking the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
After reading your edit, it sounds like there's some room to wiggle here. If we take 2 small liberties, this could be done in a single command line. If one or both liberties can't be taken, let me know.
If WMIC isn't required, and if we can target all SIDs present rather than trying to match names to SIDs, then 'reg.exe' and 'for' can do this quickly. Here's an example with sample output:
(Optional) Enum Profiles:
cmd:
for /f "delims=\ tokens=2" %A in ('reg query hku ^| findstr /i "S-1-5-21-" ^| findstr /v /i "_Classes"') do #echo ;[i] Profile Found: {%A}
output:
;[i] Profile Found: {S-1-5-21-277974881-2357464463-7727422770-1001}
;[i] Profile Found: {S-1-5-21-277974881-2357464463-7727422770-1002}
;[i] Profile Found: {S-1-5-21-277974881-2357464463-7727422770-1007}
Add Key+Value
cmd:
for /f "delims=\ tokens=2" %A in ('reg query hku ^| findstr /i "S-1-5-21-" ^| findstr /v /i "_Classes"') do #(reg add "hku\%A\Software\Microsoft\Terminal Server Client\Default\Addins\FooKey" /v FooName /t REG_SZ /d "C:\foo\file\foo.dll" /f >nul 2>&1 && (echo ;[i] Reg Key Added {%A}) || (echo ;[i] Reg Key Failed To Add {%A}))
output:
;[i] Reg Key Added {S-1-5-21-277974881-2357464463-7727422770-1001}
;[i] Reg Key Added {S-1-5-21-277974881-2357464463-7727422770-1002}
;[i] Reg Key Added {S-1-5-21-277974881-2357464463-7727422770-1007}
(Optional) Verify Success:
cmd:
for /f "delims=\ tokens=2" %A in ('reg query hku ^| findstr /i "S-1-5-21-" ^| findstr /v /i "_Classes"') do #(reg query "hku\%A\Software\Microsoft\Terminal Server Client\Default\Addins\FooKey" /v FooName 2>nul || echo ;[e] Couldn't Find Key {%A})
output:
HKEY_USERS\S-1-5-21-277974881-2357464463-7727422770-1001\Software\Microsoft\Terminal Server Client\Default\Addins\FooKey
FooName REG_SZ C:\foo\file\foo.dll
HKEY_USERS\S-1-5-21-277974881-2357464463-7727422770-1002\Software\Microsoft\Terminal Server Client\Default\Addins\FooKey
FooName REG_SZ C:\foo\file\foo.dll
HKEY_USERS\S-1-5-21-277974881-2357464463-7727422770-1007\Software\Microsoft\Terminal Server Client\Default\Addins\FooKey
FooName REG_SZ C:\foo\file\foo.dll
Not sure if I am understanding your question. My first comment should have made it quite clear. You need to use a FOR /F command to capture the WMIC output. That is the only way you can assign the SID to a variable.
#echo off
REM Read file with user names
FOR /F "usebackq tokens=*" %%G in ("users.txt") do (
REM use user name to find SID
FOR /F "delims=" %%H IN ('"wmic useraccount where name='%%~G' get sid| findstr /vi "SID""') DO (
REM Strip trailing line with CR
FOR /F "delims= " %%I IN ("%%~H") DO (
REM %%I is now the SID of the USER
REG ADD "HKEY_USERS\%%I\Software\Microsoft\addstuffhere" /f
REG ADD "HKEY_USERS\%%I\Software\Microsoft\addstuffhere" /t REG_SZ /d "addstuffhere"" /f
)
)
)
I have created a .cmd script that runs an uninstall on a specific piece of software as follows:
Title LEAP Office Accounting Client for 64-Bit Operating Systems
Echo LEAP Office Accounting Client for 64-Bit Operating Systems
WMIC Product Where "Name='LEAP Office Accounting Client for 64-Bit Operating Systems'" Call Uninstall /NoInteractive
This results in a remaining entry in the uninstall control panel and I have linked this to a registry key still remaining after the uninstall is called:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\InstallShield_{7BF4C2E2-96B9-4E84-B0FC-0C084B4068F1}
What can I add to my script, so it ensures this is removed either via the uninstall command or a separate delete command?
The last part of the registry key {7BF4C2E2-96B9-4E84-B0FC-0C084B4068F1} is unique (GUID). So I would need to find the correct registry key each time as the script is made to remove this software more than once.
Since {7BF4C2E2-96B9-4E84-B0FC-0C084B4068F1} is dynamic and will change based on installation, we can use /s /f "Key value data" to search the \Uninstall\ directory and its sub-keys for the key-values based on the value data of the DisplayName. To do this we can use a for statement along with REG QUERY to set a string with the path of the sub-directory the key belongs to.
To remove a key, we will want to use REG DELETE - reg delete /?
The Parameter /f will remove the entry without asking for confirmation.
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "tokens=2 delims={}" %%a in ('
REG QUERY HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s /f "Put your programs DisplayName's value here"
') do REG DELETE "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{%%a}" /f
pause
This script will remove your key based off the value of DisplayName. You will want to search your registry for this value and insert it in the script. Be sure to run this script as administrator.
#echo off
setlocal
call :del_uninstall_key "LEAP Office Accounting Client for 64-Bit Operating Systems"
exit /b
:del_uninstall_key
setlocal
set "key="
for /f "tokens=*" %%A in ('
reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
/s /f "%~1"
^|find "HKEY_LOCAL_MACHINE"
') do if not defined key set "key=%%~A"
if not defined key (
>&2 echo Reg key not found.
exit /b 1
)
reg delete "%key%" /f
exit /b
The label :del_uninstall_key is called with the displayname value.
reg query searches for the value and gets the 1st line of the
returned text which is expected to be the key. Use of find
limits the returned value to those with HKEY_LOCAL_MACHINE.
If the variable key is defined, the reg delete command will execute.
Use for /?, reg /? and exit /? for command help.
Here's an idea, based of the assumption that you can also determine the unique GUID from the same Win32_Product result.
#Echo Off
Set "GUID="
Set "RKEY=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
Set "PROD=LEAP Office Accounting Client for 64-Bit Operating Systems"
For /F "Tokens=2Delims==}" %%A In ('WMIC Product Where "Name='%PROD%'" Get IdentifyingNumber /Value 2^>Nul') Do Set "GUID=%%A}"
If Not Defined GUID Exit /B
WMIC Product Where "Name='%PROD%'" Call Uninstall
Reg Delete "%RKEY%\InstallShield_%GUID%" /F>Nul
I do think however that if you're accessing the registry, you could probably uninstall the software using the UnistallString value data from that location.You may even be able to parse the data for the switches it uses and optionally add you own to make the process less interactive.
I have found a solution to the issue avoiding the registry key removal
#Echo Off
Set "GUID="
Set "PROD=LEAP Office Accounting Client for 64-Bit Operating Systems"
For /F "Tokens=2Delims==}" %%A In ('WMIC Product Where "Name='%PROD%'" Get
IdentifyingNumber /Value 2^>Nul') Do Set "GUID=%%A}"
If Not Defined GUID Exit /B
WMIC Product Where "Name='%PROD%'">
"C:\Program Files (x86)\InstallShield Installation
Information\%GUID%\setup.exe" /m:uninstall
Running this installer correctly removes the key unlike the WMIC command although it does prompt the user. Is it possible to run the uninstall silently? I have attempted to add /quiet but that didn't work.
I have been trying to find away to search for the existence of my company's software on PC's by searching hostnames on the network \\computername\c$\Program Files\Foo, and if it finds it, copy over an updated config etc.
I've seen that net view will out put all the PC's on the network, something like this:
\\DISKSTATION
\\JWLAPTOP
\\TEST
\\XP
The command completed successfully.
I was wondering if there was a way to just get the computer names in a clean list (without "command completed" etc.):
\\DISKSTATION
\\JWLAPTOP
\\TEST
\\XP
Then run some commands against it, for everything in hostnames.txt, if exist:
\\JWLAPTOP\c$\Program Files\Foo --> do copy xyz to wherever
I can take care of the part \c$\Program Files\Foo as a variable to add after the computer names in the text file.
Hope that makes sense, thanks for any tips.
edit
Been re thinking this perhaps there is a more direct way to do this....
I need to see the list of PC's on customers network.....net view is a good way of getting this info so far, but I further need to see which ones are online. Any online, query for folder and update a *.CFG file, any offline, output to text for reference.
So at the minute....
FOR /F "tokens=1 delims= " %%G IN ('net view ^|findstr /L /B /C:"\\"')
this is working great, I then made it output to a text file..
FOR /F "tokens=1 delims= " %%G IN ('net view ^|findstr /L /B /C:"\\"') DO (echo %%G>>%~dp0netview.txt)
However, the %%G echo's back \somecomputer which means I am struggling to get a new line..
for /f %%G in (%~dp0netview.txt) DO (ping etc......
to ping because of the \ before the computer name. So was wonder if we can make the list 'just" have the PC name without the \ before it.
Also this is the content of the .cfg file I need to edit...
<?xml version="1.0" encoding="utf-8"?>
<ClientConfigurationFile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ServerPath>**\\server\shared\data**</ServerPath>
<ApplicationMode>Workstation</ApplicationMode>
<VRPath />
<ServicePollingInterval>0</ServicePollingInterval>
</ClientConfigurationFile>
perhaps there is a way of editing a certain section of this directly once its existence is found. \server\shared\data...in bold is what I need to update often when clients have new servers and things and involves having to go round lots of rooms to update manually. This batch could save hours upon hours of unnecessary work.
over writing the existing .cfg file is still a good way of doing it if it's too tricky or not possible directly.
Hope it makes sense, thanks for the replies!!!
Assuming none of your computer names have spaces in them.
#echo off
FOR /F "tokens=1 delims= " %%G IN ('net view ^|findstr /L /B /C:"\\"') DO (
IF EXIST "%%~G\c$\Program Files\Foo" copy "C:\folder\xyz.txt" "C:\other folder\"
)
If you want the leading back slashes stripped then use it as a delimiter just like I am using the space as a delimiter to get rid of all the extraneous NET VIEW output.
#echo off
FOR /F "tokens=1 delims=\ " %%G IN ('net view ^|findstr /L /B /C:"\\"') DO (
PING %%G
IF EXIST "\\%%~G\c$\Program Files\Foo" copy "C:\folder\xyz.txt" "C:\other folder\"
)
You could do the following:
#echo off
setlocal EnableExtensions
set "TARGET=C$\Program Files\Foo"
for /F "eol=| delims=" %%C in ('
net view ^| find "\\"
') do (
pushd "%%C\%TARGET%"
if not ErrorLevel 1 (
rem do your operations here...
copy "\your\source\path\xyz" "."
popd
)
)
endlocal
The for /F loop walks through all host names returned by net view (supposing each one starts with \\ and there are only the host names).
Since the resulting path (for instance \\TEST\C$\Program Files\Foo) is a UNC path which is not supported by several commands, pushd is used, which is capable of connecting to the given resource by establishing a temporary drive letter like Z:, and changing the working directory to its root immediately (if the command extensions are on, which is the Windows default).
The query if not ErrorLevel 1 is used to skip over the remaining commands in case pushd could not connect to the resource for some reason.
After all your operations, popd ensures that the temporary drive created by pushd is unmounted and that the former working directory is restored.
I want to be able to run just one instance of xcopy rather than many, from a usb drive to .\admin\desktop on the computer I have plugged it in, however there might be some computers I get on that have the admin username changed to the name of the person. Is there a generic batch namimg convention for the admin user account for windows? If so I'd like to just use that whatever it may be instead of listing everyone's username for every computer and guessing what it might be without looking everytime.
Here is what I have so far, it works well if I know for a fact that the "Admin" user is still labeled "Admin."
#echo off
xcopy "%~dp0M1k_SWPCB\*.*" "C:\Documents and Settings\Admin\Desktop\SWPCB\" /d /s /h /v /c /f /k /y
pause
I tried 'All Users' as well, but in some cases the directory doesn't exist and it will not work. Plus if the computer has multiple users I don't want it on everyones' desktop.
Any help would be much appreciated.
Thanks
All users have a SID identifier and the local admin account always ends with the -500 suffix, so you can get the Admin username by checking the SID's on the Registry:
#Echo OFF
FOR /F "Tokens=*" %%# IN ('Reg Query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" ^| FIND "-500"') DO (
FOR /F "Tokens=2,*" %%A IN ('Reg Query "%%#" /v "ProfileImagePath" ^| FIND /V "%%#"') DO (
Echo Admin SID: %%~n#
Echo Admin Folder: %%B
)
)
Pause>NUL&Exit
Output:
Admin SID: S-1-5-21-148789306-3749789949-2179752015-500
Admin Folder: C:\Users\Administrador
Another way to do it is with an VBScript, you can use it in your Batch file and write the Admin name to a textfile, then next you will set a variable with the content of the textfile. (I don't wrote this function):
Set objNetwork = CreateObject("Wscript.Network")
objComputerName = objNetwork.ComputerName
Set objwmi = GetObject("winmgmts:{impersonationLevel=impersonate}!//" & objComputerName)
qry = "SELECT * FROM Win32_Account where Domain = '" & cstr(objComputerName) & "'"
For Each Admin In objwmi.ExecQuery(qry)
If (Left(Admin.sid, 6) = "S-1-5-" And Right(Admin.sid,4) = "-500") Then MsgBox Admin.name)
Next
PS: Maybe someone will post other solution saying that listing the group names is another choice... but groupnames is not a generic solution 'cause the native language.