I have a batch script that lists all services,takes the BINARY_PATH, removes any lines that contain c"\windows" and provides a list of BINARY_PATHS.
The idea is to then pass that list into ICACLS to determine the permissions set on each of those executables.
The problem I have is that some BINARY_PATHS contain leading and trailing ". So I have had to account for this by adding the delims=" to my for /f statement.
Below is the batch file that outputs to ECHO
for /f "tokens=2" %%n in ('sc query state^= all ^| findstr SERVICE_NAME') do (
for /f "delims=: tokens=1*" %%r in (
'sc qc "%%~n" ^| findstr BINARY_PATH_NAME'
) do (
for /f tokens^=1-2^ delims^=^" %%x in ('echo %%~s^| findstr /V /I "c:\windows\system32"') do (
echo "%%~x%%~y"
)
)
)
The ECHO output is as following - a nice clean list it would seem apart from the leading space
" C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_state.exe"
" C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorsvw.exe"
" C:\Windows\Microsoft.Net\Framework\v3.0\WPF\PresentationFontCache.exe"
" C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\infoc
ard.exe"
" C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\SMSvc
Host.exe"
" C:\Program Files\Photodex\ProShow Producer\ScsiAccess.exe"
" C:\Windows\servicing\TrustedInstaller.exe"
" C:\Program Files\VMware\VMware Tools\vmtoolsd.exe"
When I try and pass the output to icacls without the leading and trailing ", it breaks down because there are spaces in some of the PATHs.
ICACLS batch file:
for /f "tokens=2" %%n in ('sc query state^= all ^| findstr SERVICE_NAME') do (
for /f "delims=: tokens=1*" %%r in (
'sc qc "%%~n" ^| findstr BINARY_PATH_NAME'
) do (
for /f tokens^=1-2^ delims^=^" %%x in ('echo %%~s ^| findstr /V /I "c:\windows\system32"') do (
icacls %%~x%%~y
)
)
)
Some output from ICACLS batch:
C:\Windows\Microsoft.Net\Framework\v3.0\WPF\PresentationFontCache.exe NT SERVICE
\TrustedInstaller:(F)
BUILTIN\Ad
ministrators:(RX)
NT AUTHORI
TY\SYSTEM:(RX)
BUILTIN\Us
ers:(RX)
Successfully processed 1 files; Failed processing 0 files
Invalid parameter "Communication"
Invalid parameter "Communication"
Invalid parameter "Files\Photodex\ProShow"
C:\Windows\servicing\TrustedInstaller.exe NT SERVICE\TrustedInstaller:(F)
BUILTIN\Administrators:(RX)
NT AUTHORITY\SYSTEM:(RX)
BUILTIN\Users:(RX)
Successfully processed 1 files; Failed processing 0 files
Invalid parameter "Files\VMware\VMware"
Any ideas?
You are absolutely right to enclose paths in between quotation marks in order to avoid trouble with white-spaces.
But instead of removing and leading and trailing spaces which are also contained within the ""
, I would try to not produce them rather than to eliminate them later.
The leading space comes from the middle for /f
loop:
for /f "delims=: tokens=1*" %%r in ('sc qc "%%~n" ^| findstr BINARY_PATH_NAME') do ( ... )
The filtered sc qc
command produces output lines like:
BINARY_PATH_NAME : C:\Windows\System32\spoolsv.exe BINARY_PATH_NAME : "C:\Program Files\iPod\bin\iPodService.exe"
With your "delims=: tokens=1*"
option, the part after the delimiter (:
) holds a leading space.
To overcome this, add the space as another delimiter, but make sure it is the very last character in the option string: "tokens=1* delims=: "
.
The trailing space comes from the piped echo
command line parsed by the inner for /f
loop:
for /f tokens^=1-2^ delims^=^" %%x in ('echo %%~s ^| findstr /V /I "c:\windows\system32"') do ( ... )
The space between echo %%~s
and ^|
is also included in the output. Therefore simply remove it.
It is not necessary to define the option string tokens^=1-2^ delims^=^"
, because the for /f
loop should not receive any quotation marks to parse anyway (due to the ~
modifier in %%~s
), so "delims="
is enough. Hence use %%~x
in the loop body only.
Furthermore, I suggest to write echo(%%~s
instead of echo %%~s
in order to avoid ECHO is on/off.
messages if %%~s
is empty (although this should never happen).
Another problem is that service names retrieved by sc query state= all
may contain white-spaces as well; for example:
SERVICE_NAME: iPod Service
So for the outer for /f
loop, the "tokens=2"
option is not optimal; in the above example, only iPod
would be returned. Therefore correct it to "tokens=1*"
and ignore the first token.
Since literal strings are searched only, I replaced the findstr
instances by find
, except the last one, because find
supports a single search string only.
I added another search string to the remaining findstr
instance in order to cover also 64-bit Windows systems where a directory C:\Windows\SysWOW64
also exists, which I assume you want to filter out too.
Here is the fixed code:
@echo off
for /f "tokens=1*" %%m in ('sc query state^= all ^| find "SERVICE_NAME"') do (
for /f "tokens=1* delims=: " %%r in ('sc qc "%%~n" ^| find "BINARY_PATH_NAME"') do (
for /f "delims=" %%x in ('echo(%%~s^| findstr /L /V /I /C:"%SystemRoot%\System32" /C:"%SystemRoot%\SysWOW64"') do (
ECHO icacls "%%~x"
)
)
)
Remove the upper-case ECHO
after successful testing in order to execute the icacls
command line.