How to make CMD show result instead of string in SET variable - windows

I am looking to implement a simple batch file that will rename the current local profile folder, backup registry keys then delete profile list SID keys.
Therefore allowing the computer to create a new local profile that is not temporary.
Where %U% is the account name
set a=wmic useraccount where name="%U%" get sid /value
and so when I execute the below(Where %a% is the above command):
reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\%a% /f
it interprets it as:
reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\wmic useraccount where name="%U%" get sid /value"
But I want:
"HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\SID=S-1-5-21-3519583588-1143172139-1479499458-1001"
If I call %a%, it displays
SID=S-1-5-21-3519583588-1143172139-1479499458-1001
and if I echo %a%, it displays
wmic useraccount where name="%U%" get sid
If I just enter %a%, it displays
SID=S-1-5-21-3519583588-1143172139-1479499458-1001
Just an explanation for why this happens would be great.

set does not have the built-in ability to execute a command and store the result, as you intend with the line:
set a=wmic useraccount where name="%U%" get sid /value
Instead, a simple hack is:
#echo off
for /f %%A in ('wmic useraccount where "name='%USERNAME%'" get sid /value ^| findstr SID') do ( set %%A )
echo The SID is %SID%
After that, you should be able to:
reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\%SID%" /f

Unlike Unix where you use backticks for an expression which evaluates to the stdout of an external command there is no such syntax in batches. What you need to do instead is to use a for loop over the output lines to assign it to a variable, like discussed here.
for /f "delims=" %%i in ('wmic...') do set A=%%i

Related

Deleting user profile registry key based on profile name with Batch file

I am attempting to write a batch script to delete a registry key for a user profile. The user profile will always have the same name, but the key is different for every computer and increments each time the username is created, even though the previous one was deleted.
I'm guessing that it would require some type of for loop to identify the key value for the ProfileImagePath as C:\Users\Username.
I know wildcards don't work so reg delete 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-21-*' /f won't work.
I'm aware of some PS scripts that can do this, but I would like to keep this in a batch file.
Here's a single line example of the methodology I'd suggest, (which will not become obsolete when WMIC.exe is removed from Windows 11).
#For /F "EOL= Delims=" %%G In ('%SystemRoot%\System32\reg.exe Query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" /S /F "C:\Users\Username" /D /E 2^>NUL ^| %SystemRoot%\System32\find.exe "S-1-5-21-"') Do #%SystemRoot%\System32\reg.exe Delete "%%G" /V "ProfileImagePath" /F 1>NUL 2>&1
Please take account of my commented advice too.

How do I pipe each line from a cmd output to a column in a table created from Microsoft SQL?

I have tried this particular command and I know that it works.
for /f "usebackq skip=1 tokens=*" %i in (`wmic/node:'+adr+' product get installdate ^| findstr /r /v "^$"`) do #echo %i
The "adr" would be replaced with an IP address, and the concatenation and extra apostrophes would be removed. When I use it in Python, I do use the subprocess.call() method, and it works in the console as well.
However, here's the problem I have with this. The main command itself (the wmic/node thing) would print everything out on different lines. This is expected behavior, but I want to do this so that each install date writes to the next row in the same column of a table created in a database on Microsoft SQL Server 2014 Management Studio, rather than just one line. I have tried to look online for a case closely similar to this one, but I've had no such luck.
Here is what my code looks like, I'm not sure if I should change anything to get the desired result.
installdate = subprocess.call('for /f "usebackq skip=1 tokens=*" %i in (`wmic/node:'+adr+' product get installdate ^| findstr /r /v "^$"`) do #echo %i', shell=True)
cur.execute("INSERT INTO InstalledApps (InstallDate) VALUES (?)", installdate)

Batch file, query the registry

Hello People of StackoverFlow,
I am trying to query the follow registry location(every folder in here)
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
In there are random numbers like so:
{071c9b48-7c32-4621-a0ac-3f809523288f}
In each of these random numbers, I need to check if the key 'DisplayName' that is in each of these locations contains a certain text, lets say 'OverFlow'.
I've done some querys but not like this, if anyone can help that would be great!
EDIT: I've made some progress but am encountering a problem( I have done alot of research...)
Below is what I have so far:
#echo off
setlocal
:RemoveCVCP
set PythonReg=
for /f "tokens=1" %%A in ('reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s /v "DisplayName" ^| find "Python"') do set "PythonReg=%%A"
if %ERRORLEVEL% neq 0 (
GOTO RemovePyCP)
echo %PythonReg%
endlocal
pause
What I'm trying to do is loop through 'KLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall', and look at the 'DisplayName' key, if the data contains 'Python' then delete it. and keep going till there are no longer any more.
Right Now I am testing this with an echo, but it will evetually delete it.
(I'm just using python as an example, I have already removed everything else that is related to the software I'm trying to remove, this is the last location.)
Thanks, Michael
First, list all values that contain python, two lines will be printed for each entry:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{E43BBAEB-4914-44C6-88C0-E7A1DBD20A91}
DisplayName REG_SZ Some application title with python in its name
then delete those keys where the printed value name is DisplayName:
#echo off
setlocal enableDelayedExpansion
for /f "tokens=1,2*" %%A in ('^
reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s /d /f "python"^
') do (
if "%%A"=="DisplayName" (
echo Deleting %%C
reg delete !key! /f
) else (
set str=%%A
if "!str:~0,4!"=="HKEY" set key=%%A
)
)
pause
This code assumes there are no spaces in the key name.

Full name to variable in CMD

this should be pretty basic, but I can't figure it out.
I trying to set the full name of the user to a variable to use further in the my batch script.
I thought it should be something like this:
SET VAR=NET USER %username% /DOMAIN | FIND /I "Full name";
echo "%VAR%"
The NET USER %username% /DOMAIN | FIND /I "Full name" works on its own, but not when I try to set it to a variable.
Maybe this is more a general question..
You can use a temporary file or for /f to achieve this:
temporary file solution:
NET USER %username% /DOMAIN | FIND /I "Full name" >tmp.txt
set /p VAR=<tmp.txt
echo %VAR%
del tmp.txt
for /f solution:
for /f "tokens=*" %i in ('NET USER %username% /DOMAIN ^| FIND /I "Full name"') do set VAR=%i
Note:
Replace % with %% if using the above command in a batch file.
Use "tokens=*" to match all of the output from the command
^ is used because the | (pipe) must be escaped.
You could use the already specified %username% and %userdomain%.
Type set for a list of values.
Type set /? for a list of dynamic variables.

'cut' like feature for Windows batch file

It's been a while since I've done Windows batch files, and I seem to have forgotten everything. What I want to do is look for services where the path has spaces but the string isn't quoted. Boy, this would be easy with bash, but...
So, in a nutshell, I start with sc query | findstr SERVICE_NAME and dump that to a temp file. Then I read it back in to a variable with for /F "tokens=2" %%f in (temp_file) do set services=!services! %%f That gets me a variable with a space-delimited list of all services on my host. Now, in a FOR loop against that variable, I run sc qc %%s | findstr BINARY_PATH_NAME and dump THAT to a temp file. It winds up containing something like (quotes are mine to preserve all the spaces):
" BINARY_PATH_NAME : C:\Windows\system32\svchost.exe -k LocalSystemNetworkRestricted"
I've been reading and Googling and testing and trying everything, trying to wind up cutting that output at the : so I can just wind up with the path itself, and then start figuring out the abomination that must be regular expressions under Windows. But I just cannot get that string split.
You can do the following if you want the binary path for all services:
for /f "tokens=2" %%n in ('sc query ^| findstr SERVICE_NAME') do (
for /f "delims=: tokens=1*" %%r in (
'sc qc "%%~n" ^| findstr BINARY_PATH_NAME'
) do (
echo %%~s
)
)
Change echo %%~s to echo %%~n:%%~s if you want the binary path prepended with the name of the service.
Ansgar Wiechers has a good solution using SC to get the info for running services. It also demonstrates how to use the FOR /F delims option to break at the :.
Another option is to use WMIC to get the same information in a more direct manner.
If all you want is a list of binary paths for all active (running) services, then all you need is:
wmic service where "state='Running'" get pathname
If you want the list of service names as well as the binary paths:
wmic service where "state='Running'" get name, pathname
There are many more properties that can be listed. Type wmic service get /? from the command prompt to get a complete list.
If you want to get the values into variables within a batch process so that you can take action, then a FOR /F loop is used. I append the state property at the end to avoid an odd FOR /F quirk that appends an unwanted <CR> to the end of each line of WMIC output. The unwanted <CR> will be attached to the state value, which we don't care about. I also use the state with FINDSTR to weed out unwanted lines, so there is no need for the WMIC WHERE clause. In this example I simply echo the values, but obviously you could do whatever is needed with them.
for /f "tokens=2,3 delims=," %%A in (
'"wmic service get name, pathname, state /format:csv|findstr /e Running"'
) do echo %%A: %%B
Something like this?
#echo off
for /f "tokens=2 delims=: " %%a in ('sc query ^| findstr SERVICE_NAME') do (
sc qc %%a | findstr BINARY_PATH_NAME
)
pause

Resources