How To Get The Active User's SID - windows

The scope is running from the user's local computer.
You can use this to get the active user's SID.
Then you could use this with the HKU registry hive.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO GET THE NAME OF THE ACTIVELY LOGGED ON USER
FOR /F "skip=1" %%G IN ('wmic computersystem get username') DO (
SET aUSER=%%G
GOTO EXITLOOP1
)
:EXITLOOP1
ECHO %aUSER%
ECHO[
REM ECHO TRIM THE USERNAME
SET tUSER=%aUSER:~4%
REM ECHO %tUSER%
ECHO[
ECHO GET SID FOR USER: %tUSER%
FOR /F "usebackq skip=1" %%a IN (`WMIC USERACCOUNT WHERE NAME^='%%tUSER%%' GET SID`) DO (
SET SID=%%a
GOTO EXITLOOP2
)
:EXITLOOP2
ECHO %SID%

BTW, if you wanted to do it without a For loop, you could ask powershell to assist:
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "(%SystemRoot%\System32\whoami.exe /User /Fo CSV | ConvertFrom-Csv).SID"
Or even without whoami.exe:
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "Add-Type -AssemblyName System.DirectoryServices.AccountManagement;$([System.DirectoryServices.AccountManagement.UserPrincipal]::Current).SID.Value"

In a cmd.exe console the following command can be used.
powershell -NoLogo -NoProfile -Command ^
"Add-Type -AssemblyName System.DirectoryServices.AccountManagement;" ^
"([System.DirectoryServices.AccountManagement.UserPrincipal]::Current).Sid.AccountDomainSid.Value"
To get the result into a variable, use a FOR loop. (Yeah, I know, it's crazy, right?)
FOR /F "delims=" %%A IN ('powershell -NoLogo -NoProfile -Command ^
"Add-Type -AssemblyName System.DirectoryServices.AccountManagement;" ^
"([System.DirectoryServices.AccountManagement.UserPrincipal]::Current).Sid.AccountDomainSid.Value"') DO (
SET "USER_SID=%%~A"
)
ECHO USER_SID is set to %USER_SID%
There are many other things that can be accessed in this way.
powershell -NoLogo -NoProfile -Command ^
"Add-Type -AssemblyName System.DirectoryServices.AccountManagement;" ^
"[System.DirectoryServices.AccountManagement.UserPrincipal]::Current |" ^
"Format-List * -Force"

As you've raised a question, and in it decided to post some code, I'll offer a quicker and more simple alternative, regardless of whether you decide to post yours as a solution:
From cmd:
For /F Tokens^=3^ Delims^=^" %G In ('%SystemRoot%\System32\whoami.exe /User /Fo CSV /NH') Do #Echo %G
From a batch-file:
#For /F Tokens^=3^ Delims^=^" %%G In ('%SystemRoot%\System32\whoami.exe /User /Fo CSV /NH') Do #Echo %%G

Related

Issues when getting a list of user profiles using WMIC

I was using the following batch command to retrieve all local user profiles (including domain users too) :
for /f "delims=" %%I in ('dir /a:d-h /b "%SystemDrive%\Users\*" 2^>nul ^| %SystemRoot%\System32\findstr.exe /i /l /x /v /g:"%bin%\exclude_users.txt"') do (
The problem is that this command has its limits: it doesn't really check if the users in question do actually have an account.
The user Compo provided me a methodology for retrieving the profile names, using WMIC.
So I ended up writing the following command:
#For /F "tokens=* skip=1" %%I In ('%__AppDir__%wbem\WMIC.exe UserAccount Get Name ^|%__AppDir__%findstr.exe /i /l /x /v /g:"%bin%\exclude_users.txt"') do (
The problem is: it ignores my exclusion file (which contains one user per line) and it ends up a profile without any name.
Any idea How I can solve these issues ?
#echo off
setlocal
set "bin=%~dp0"
for /f "tokens=* skip=1" %%I in ('
%__AppDir__%wbem\WMIC.exe UserAccount where Disabled^="FALSE" get Name ^|
%__AppDir__%WindowsPowerShell\v1.0\powershell -noprofile -command "$input.trim()" ^|
%__AppDir__%findstr.exe /i /l /x /v /g:"%bin%\exclude_users.txt"
') do echo "%%~I"
The wmic output is piped to powershell to be trimmed and then piped to findstr.
The wmic command will exclude disabled accounts by use of the where clause.
Change the setting of bin as needed.
If you want a solution which still uses WMIC, and your exclusion list, then the following should do as you require.
#For /F Tokens^=4Delims^=^" %%G In ('%__AppDir__%wbem\WMIC.exe UserAccount Where "LocalAccount='TRUE'" Assoc:List /ResultRole:Name 2^>NUL')Do #Echo %%G|%__AppDir__%findstr.exe /VXLIG:"%~dp0exclude_users.txt"
You can split that over multiple lines for easier reading too:
#For /F Tokens^=4Delims^=^" %%G In ('%__AppDir__%wbem\WMIC.exe UserAccount^
Where "LocalAccount='TRUE'" Assoc:List /ResultRole:Name 2^>NUL'
)Do #Echo %%G|%__AppDir__%findstr.exe /VXLIG:"%~dp0exclude_users.txt"

How to find latest 'n' files in a directory from cmd?

I want to get the latest 5 files in a directory.
This gave me the latest file:
FOR /F "delims=|" %%I IN ('DIR "*.yaml" /B /O:D') DO SET NewestFile=%%I
Any help is greatly appreciated
The following example is intended to perform the task as laid out in your question and as implied by my advisory comment:
#Echo Off
SetLocal DisableDelayedExpansion
For /F "Delims==" %%A In ('"Set Newest[ 2>NUL"')Do Set "%%A="
For /F "Tokens=1* Delims=:" %%A In (
'"Dir /B/A:-D/O:-D/T:W "*.yaml" 2>NUL|FindStr /LINE ".yaml""'
)Do If %%A LEq 5 (Set "Newest[%%A]=%%B")Else GoTo :Next
:Next
Set Newest[ 2>NUL&&Pause
I have used the most recently written in the above example and the last line was included just to show you any variables set within the For loop.
Here is another way to get the five (5) newest files according to "last write time." Be sure to change the -Path directory to yours.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "delims=" %%f IN ('powershell -NoLogo -NoProfile -Command ^
"Get-ChildItem -Path "C:\src\t" -Filter '*.yaml' |" ^
"Sort-Object -Property LastWriteTime -Descending |" ^
"Select-Object -First 5 |" ^
"ForEach-Object { $_.FullName }"') DO (
SET "NEWFILE=%%~f"
ECHO Do something with "!NEWFILE!"
)

Delete certain folders from C:\Users\%username%\AppData\Local via list of hostnames

I have a snippet of code this site helped me with and I would like to alter to behave in a different way if possible?
Running the file on a local PC directly will scan the user profile folders, omits system profiles (to avoid unnecessary scanning) and deletes 2 specified folders from every users app data local folder.
What I need to do now is run it across the network where I have a list of hostnames and do it that way. The below is working running directly on the PC.
For /F "Skip=1 Delims=" %%A In (
'"WMIc Path Win32_UserProfile Where (Special!='True') Get LocalPath"'
) Do For /F "Delims= " %%B In ("%%A") Do (
For %%I In (Folder1 Folder_2) Do (If Exist "%%B\AppData\Local\%%I\" (
RMDIR "%%B\AppData\Local\%%I" /S /Q >nul 2>&1)
)
)
I would like to change it to something like
for /f "usebackq tokens=*" %%A in ("%~dp0hostnames.txt") do (
For /F "Skip=1 Delims=" %%A In (
'"WMIc Path Win32_UserProfile Where (Special!='True') Get LocalPath"'
) Do For /F "Delims= " %%B In ("%%A") Do (
For %%I In (Folder1 Folder_2) Do (If Exist "\\%%B\C$\AppData\Local\%%I\" (
RMDIR "\\%%B\C$\AppData\Local\%%I" /S /Q >nul 2>&1)
)
)
I have had a go but it's getting beyond my limited knowledge, I think I need delayedexpansion and also move on the variable letter further along the alphabet but I dont know in which direction :-
Any help appreciated ..thanks
This is completely untested, but I'm assuming that you can utilise the /Node option of WMIC:
#Echo Off
For /F "UseBackQ Delims=" %%Z In ("%~dp0hostnames.txt"
) Do For /F "UseBackQ Skip=1 Delims=" %%X In (`WMIC /Node:'%%~Z' Path^
Win32_UserProfile Where "Special='False'" Get LocalPath`
) Do For /F "Delims=" %%Y In ("%%X") Do Call :Sub "%%~Z" %%Y
Exit/B
:Sub
For /F "Tokens=1* Delims=:\" %%V In ("%~2") Do For %%U In (Folder1 Folder_2
) Do If Exist "\\%~1\%%~V$\%%~W\AppData\Local\%%~U"^
RD/S/Q "\\%~1\%%~V$\%%~W\AppData\Local\%%~U"
GoTo :EOF
Here is a way to do it in PowerShell. When you are confident that the correct directories will be removed, remove the -WhatIf switch from the Remove-Item command.
$dirlist = 'dir1', 'dir2'
$userdirs = (Get-CimInstance -ClassName Win32_UserProfile -Filter "Special=$false").LocalPath
foreach ($ud in $userdirs) {
foreach ($d in $dirlist) {
if (Test-Path -Path "$ud\$d") {
Remove-Item -Path "$ud\$d" -Recurse -WhatIf
}
}
}
Using Invoke-Command will allow you to run the script on all computers simultaneously. This assumes that the previous script was saved as udscan.ps1.
Invoke-Command -ComputerName 'host1', 'host2' -FilePath .\udscan.ps1

Collect each service's display name and status

I want to get list of services with their display name and their status.
This is what I have tried:
for /f "tokens=2" %s in ('SC query state^= all ^| find "DISPLAY_NAME"') do #(for /f "tokens=4" %t in ('SC query %s ^| find "STATE"') do #echo %s is %t)
But this returns only limited services such as disk, etc.
This is a perfect task for the built-in WMI command line executable, WMIC.exe.
From the cmd.exe prompt:
For /F "Skip=1 Delims=" %A In ('"WMIC Service Get DisplayName, Name, State"') Do #For /F "Delims=" %B In ("%A") Do #Echo(%B
From a batch file:
#For /F "Skip=1 Delims=" %%A In ('"WMIC Service Get DisplayName, Name, State"'
) Do #For /F "Delims=" %%B In ("%%A") Do #Echo(%%B
#Pause
Try getting help from powershell directly in your batch file, like this for example (save as .bat and run it). In the example i type it to the screen and give you ALL services, RUNNING ONLY, and STOPPED ONLY but you could do basically what you want with the content of that txt file (search it with a loop, save a part to a variable, etc.).
#echo off&cls
pushd %~dp0
echo.
echo List ALL services
pause
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "powershell Get-Service | Out-File services.txt"
type services.txt
echo.
echo List services that are RUNNING only
pause
find "Running" services.txt
echo.
echo List services that are STOPPED only
pause
find "Stopped" services.txt
pause
:cleanup
del /f services.txt

PowerShell command in batch script condition

I need a line of script that does something like this:
if (results from PowerShell command not empty) do something
The PowerShell command is basically
powershell -command "GetInstalledFoo"
I tried if (powershell -command "GetInstalledFoo" != "") echo "yes" but get the error -command was unexpected at this time. Is this possible to accomplish? This command will eventually be run as the command to cmd /k.
BartekB's answer works as long as at least one line of output does not start with the FOR /F eol character (defaults to ;) and does not consist entirely of delimiter characters (defaults to space and tab). With appropriate FOR /F options it can be made to always work.
But here is a simpler (and I believe faster) way to handle multiple lines of output that should always work.
for /f %%A in ('powershell -noprofile -command gwmi win32_process ^| find /v /c ""') do if %%A gtr 0 echo yes
Another alternative is to use a temp file.
powershell -noprofile -command gwmi win32_process >temp.txt
for %%F in (temp.txt) if %%~zF gtr 0 echo yes
del temp.txt
Third way: set an environment variable from your PowerShell script and test it in your batch file?
I guess if won't be the best solution for that. I would use for /f instead:
for /f %R in ('powershell -noprofile -command echo foo') do #echo bar
That should give you 'bar', while this:
for /f %R in ('powershell -noprofile -command $null') do #echo bar
... should not. In actual .bat/ .cmd file you have to double % (%%R)
or better yet, if you don't want to many bar's returned...:
(for /f %R in ('powershell -noprofile -command gwmi win32_process') do #echo bar) | find "bar" > nul && echo worked

Resources