This is actually working but not in the format I prefer. The code below will achieve what I want. Makes a folder in any writable standard User Profile (I am aware it wont work in some system profiles like Default etc.) that some software needs and also gives it relevant permission.
for /d %%A in ("C:\Users\*") do mkdir "%%~fA\AppData\Local\Folder1"
for /d %%A in ("C:\Users\*") do mkdir "%%~fA\AppData\Local\Folder1_Ltd"
for /d %%A in ("C:\Users\*") do icacls "%%~fA\AppData\Local\Folder1" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
for /d %%A in ("C:\Users\*") do icacls "%%~fA\AppData\Local\Folder1_Ltd" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
This seems a bit over the top though. I am wanting to just have the one loop through the user folders and then use brackets to list the commands, saving a user loop for every function. However when I try the below, it doesn't even make the folders. If I debug using command line it stops at "everyone" was unexpected at this time. I'm not sure why? Any advice be welcome, thanks.
for /d %%A in ("C:\Users\*") do (
mkdir "%%~fA\AppData\Local\Folder1"
mkdir "%%~fA\AppData\Local\Folder1_Ltd"
icacls "%%~fA\AppData\Local\Folder1" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
icacls "%%~fA\AppData\Local\Folder1_Ltd" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
)
pause
You've to escape all the closing parentheses inside the (code block) to not being interpreted as the end of the block.
for /d %%A in ("C:\Users\*") do (
mkdir "%%~fA\AppData\Local\Folder1"
mkdir "%%~fA\AppData\Local\Folder1_Ltd"
icacls "%%~fA\AppData\Local\Folder1" /T /C /grant(:r^) "Everyone":(OI^)(CI^)(F^) /inheritance:e
icacls "%%~fA\AppData\Local\Folder1_Ltd" /T /C /grant(:r^) "Everyone":(OI^)(CI^)(F^) /inheritance:e
)
pause
Edit as eryksun suggested using a subroutine is an alternative (albeit using an editor to insert the ^ escapes is no big deal)
#Echo off
for /d %%A in ("C:\Users\*") do Call :Sub "%%~fA"
pause
Goto :Eof
:Sub
mkdir "%~f1\AppData\Local\Folder1"
mkdir "%~f1\AppData\Local\Folder1_Ltd"
icacls "%~f1\AppData\Local\Folder1" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
icacls "%~f1\AppData\Local\Folder1_Ltd" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
Another alternative could be to remove unneeded parenthesis and quote required ones
#echo off
setlocal enableextensions disabledelayedexpansion
for /d %%A in ("C:\Users\*") do (
for %%F in ("%%~fA\AppData\Local\Folder1" "%%~fA\AppData\Local\Folder1_Ltd") do (
mkdir "%%~fF"
icacls "%%~fF" /T /C /grant:r "Everyone":"(OI)(CI)(F)" /inheritance:e
)
)
If you want to keep the parenthesis in the grant switch, then you can
#echo off
setlocal enableextensions disabledelayedexpansion
for /d %%A in ("C:\Users\*") do (
for %%F in ("%%~fA\AppData\Local\Folder1" "%%~fA\AppData\Local\Folder1_Ltd") do (
mkdir "%%~fF"
icacls "%%~fF" /T /C "/grant(:r)" "Everyone":"(OI)(CI)(F)" /inheritance:e
)
)
note: Both cases tested on windows 10. I can not test at this moment if the icacls hability to deal with quoted arguments (in the /grant case) is present in previous OS versions.
note2: Tested without problems (well, /inheritance switch did not exist) with the Windows 2003 server SP2 version of the icacls.exe (the first version published). As pointed by eryksun, the additional quotes are removed by the CRT.
You could use WMI to access only normal users profiles too:
#Echo Off
For /F "Skip=1 Delims=" %%A In (
'"WMIc Path Win32_UserProfile Where (Special!='True') Get LocalPath"'
) Do For /F "Delims=" %%B In ("%%A") Do Call :Sub %%B
Pause>Nul
GoTo :EOF
:Sub
For %%A In (Folder1 Folder1_Ltd) Do (If Not Exist "%*\AppData\Local\%%A\" (
MD "%*\AppData\Local\%%A")
ICACLS "%*\AppData\Local\%%A" /T /C /Q /grant:r Everyone:(OI^)(CI^)F /inheritance:e)
Related
This is a sample code that allows me to delete all folders with the name ".RemoveAsap" attached to them
#echo on
set dir="\\TestPC2\c$\Users"
FOR /D /R %dir% %%X IN (*.RemoveAsap) DO RMDIR /S /Q "%%X"
pause
exit
Simply running the code as is runs perfectly but when I try to make the code more interactive, I get the error
#echo on
cd C:\Users\User1\Desktop\Test\
TYPE con >> LowDASD.txt
For /F %%A in (LowDASD.txt) do echo "\\%%A\c$\users\" >> LowDASD2.txt
set "LwDs"="LowDASD2.txt"
FOR /D /R "%LwDs%" %%X IN (*.RemoveAsap) DO RMDIR /S /Q "%%X"
pause
LowDASD2.txt would be the address/ directory location where the directories will be deleted, IE \\TestPC2\c$\Users
The code does not delete anything or give an error that "the path is too long" at least it was doing that with the previous variations that I was trying. If someone can help me with this, i would greatly appreciate it.
Try using FORFILES, instead of the command FOR, this way you can make it work like this:
:: forfiles /p "folder_location" 'args' '/c "cmd /c del /f /q #path"'
:: So...
cd C:\Users\User1\Desktop\Test\
TYPE con >> LowDASD.txt
For /F %%A in (LowDASD.txt) do echo "\\%%A\c$\users\" >> LowDASD2.txt
set "LwDs=LowDASD2.txt"
forfiles /p %LwDs% /s /c "cmd /c del /f /q #path"
:: You can use '/d -90' to delete files older than 90 days in the folder
FOR /D /R "%LwDs%" %%X IN (*.RemoveAsap) DO RMDIR /S /Q "%%X"
Simply will not work, as %LwDs% is a filename.
FOR /F "usebackq delims=" %%j in ("%LwDs%") do FOR /D /R "%%j" %%X IN (*.RemoveAsap) DO RMDIR /S /Q "%%X"
You would think might work - %%j being assigned to each entry in the %LwDs% file in turn; usebackq used because the filename is "quoted" (see for /? from the prompt for documentation)
But it doesn't - the for /d /r syntax doesn't accept metavariables...
So - try
FOR /F "usebackq delims=" %%j in ("%LwDs%") do set "target=%%j"&call :expunge
Where expunge is an internal subroutine. The colon is required
:expunge
echo target="%target%"
FOR /d /r "%target%" %%X IN (*.RemoveAsap) DO echo RMDIR /S /Q "%%X"
echo ====================
goto :eof
An internal subroutine should be placed after an unconditional goto, which should in your case follow the pause
pause
goto :eof
Where :eof (compulsory colon again) is defined as the physical end-of-file and should not be used as a user-label. Reaching physical end-of-file returns from a call.
Always verify against a test directory before applying to real data.
Note that the rmdir is merely being echoed for testing purposes - remove the echo keyword after testing to activate.
=== Extension
The full code should thus be
#echo on
set dir="\\TestPC2\c$\Users"
FOR /F "usebackq delims=" %%j in ("%LwDs%") do set "target=%%j"&call :expunge
pause
exit
:expunge
echo target="%target%"
FOR /d /r "%target%" %%X IN (*.RemoveAsap) DO echo RMDIR /S /Q "%%X"
echo ====================
goto :eof
ECHO ===FILES TO TRANSFER===
FOR /f "usebackq tokens=*" %%G IN (`DIR /B /S "%~dp0Files"`) DO #ECHO %%G
The output is the full path of the file/dir but I want to make it simpler by removing %~dp0's path from the output
This is the methodology I'd suggest you incorporate, which protects filenames which may include ! characters and limits the output to files, as per your stated requirement:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
For /F Delims^=^ EOL^= %%G In ('Dir /B/S/A-D "%~dp0Files" 2^>NUL')Do (
Set "_=%%G" & SetLocal EnableDelayedExpansion
Echo(!_:*%~dp0Files=.! & EndLocal)
Pause
If you'd prefer not to have a relative path type output then change !_:*%~dp0Files=.! to !_:*%~dp0Files\=!
Alternatively, you could grab the relative paths using the slower, forfiles.exe utility:
%__AppDir__%forfiles.exe /P "%~dp0Files" /S /C "%__AppDir__%cmd.exe /D/Q/C If #IsDir==FALSE Echo #RelPath"
If you prefer it without doublequotes then this modification should do that:
%__AppDir__%forfiles.exe /P "%~dp0Files" /S /C "%__AppDir__%cmd.exe /D/Q/C If #IsDir==FALSE For %%G In (#RelPath)Do Echo %%~G"
And if you wanted it without the leading .\ then perhaps:
%__AppDir__%forfiles.exe /P "%~dp0Files" /S /C "%__AppDir__%cmd.exe /D/Q/C If #IsDir==FALSE For /F 0x22Tokens=1*Delims=\0x22 %%G In (#RelPath)Do Echo %%H"
You could also do this by leveraging powershell.exe:
%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoProfile Get-ChildItem -Path "%~dp0Files" -File -Force -Name -Recurse
which could possibly be done, (not recommended), in as short a line as:
powershell -NoP ls "%~dp0Files" -File -Fo -Na -Rec
just remove %~dp0 from each entry (Note: that doesn't work with %%G metavariables, you have to use a "normal" environment variable):
#echo off
setlocal enabledelayedexpansion
ECHO ===FILES TO TRANSFER===
FOR /f "usebackq tokens=*" %%G IN (`DIR /B /S "%~dp0"`) DO (
set "file=%%G"
echo !file:%~dp0=!
)
To retrieve the relative path to a given root without string manipulation, you could use the xcopy command with its /L option, which lists relative paths to files it would copy without /L:
pushd "%~dp0" && (
for /F "delims= eol=|" %%G in ('xcopy /L /S /Y /I "Files" "%TEMP%" ^| find "\"') do (
echo(%%G
)
popd
)
pushd and popd are used to change into and return from the root directory, respectively.
The find command is used to suppress xcopy's summary line # File(s).
I have a folder which contains the following files:
How can I delete all files with extension .rst (File1.rst, File2.rst, File3.rst, File4.rst, File5.rst) except the file "index.rst" from a batch file.
I have tried this, but it's not working:
for /f "skip=1 delims=" %%i in ('D:\hfTools\Projects\Validation-Source\Docs\source /b "*.rst"') do #(if "%i" neq "index.rst" echo %i)
Any help would be welcome. Thank you.
Here's an example of how to perform the task using the ForFiles command, forfiles.exe:
#%__AppDir__%forfiles.exe /P "D:\hfTools\Projects\Validation-Source\Docs\source" /M "*.rst" /C "%__AppDir__%cmd.exe /D /C If #IsDir==FALSE If /I Not #FName==0x22index0x22 Del /A /F #File"
Here's an example of how to perform the task using the Dir command:
#Echo Off
SetLocal EnableExtensions
If Exist "D:\hfTools\Projects\Validation-Source\Docs\source\*.rst" (
PushD "D:\hfTools\Projects\Validation-Source\Docs\source" && (
For /F "EOL=? Delims=" %%G In ('Dir /B /A:-D "*.rst" ^
^| %__AppDir__%findstr.exe /E /I /L ".rst" ^
^| %__AppDir__%findstr.exe /I /L /V /X "index.rst"'
) Do Del /A /F "%%G"
PopD
)
)
My preference however would be to use the Where command, where.exe:
Example batch-file
#Echo Off
SetLocal EnableExtensions
For /F "EOL=? Delims=" %%G In ('%__AppDir__%where.exe ^
"D:\hfTools\Projects\Validation-Source\Docs\source":"*.rst" ^
^| %__AppDir__%findstr.exe /E /I /L /V "\index.rst"'
) Do Del /A /F "%%G"
You could even do that as a single line batch-file:
#For /F "EOL=?Delims=" %%G In ('%__AppDir__%where.exe "D:\hfTools\Projects\Validation-Source\Docs\source":"*.rst"^|%__AppDir__%findstr.exe /EILV "\index.rst"')Do #Del /A/F "%%G"
Or directly from a cmd window:
For /F "EOL=?Delims=" %G In ('%__AppDir__%where.exe "D:\hfTools\Projects\Validation-Source\Docs\source":"*.rst"^|%__AppDir__%findstr.exe /EILV "\index.rst"')Do #Del /A/F "%G"
And for an off topic bonus, because for general use it seems easier; use powershell instead:
Remove-Item -Path "D:\hfTools\Projects\Validation-Source\Docs\source\*.rst" -Exclude "index.rst" -Force
You could even run that using a one line batch file, if you really needed to:
#%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoP "RI 'D:\hfTools\Projects\Validation-Source\Docs\source\*.rst' -E 'index.rst' -Fo"
Not tested:
forfiles /M *.rst /C "cmd /c if #file!=index.rst del #file"
Explanation:
/M *.rst # only consider *.rst
if ... # #file is the filename as found by forfiles
# != is this the correct way say "does not equal"?
You are actually quite close, you just forgot to double a few %-signs and you missed the dir command:
rem // Change to target directory, because `dir /B` only returns pure file names:
pushd "D:\hfTools\Projects\Validation-Source\Docs\source" && (
rem // Capture the output of `dir /B` and loop through the lines/files:
for /f "delims= eol=|" %%i in ('
dir /B /A:-D-H-S "*.rst"
') do #(
rem // Check file name against predefined exception:
if /I not "%%i"=="index.rst" (
rem // Actually delete the currently iterated file:
ECHO del "%%i"
)
)
popd
)
Once you are satisfied with the output, remove the upper-case ECHO command to actually delete files.
Note that the pattern *.rst in the dir /B command line is actually checked against both long and short file names (if the latter is enabled), so it actually matches files whose extensions begin with rst (if applicable).
If the files to delete always match the pattern File*.rst you do not even need the if condition:
rem // Change to target directory, because `dir /B` only returns pure file names:
pushd "D:\hfTools\Projects\Validation-Source\Docs\source" && (
rem // Capture the output of `dir /B` and loop through the lines/files:
for /f "delims= eol=|" %%i in ('
dir /B /A:-D-H-S "File*.rst"
') do #(
rem // Actually delete the currently iterated file:
ECHO del "%%i"
)
popd
)
This is easily done using PowerShell. If you are on a supported version of Windows, PowerShell will be available. When you are confident that the correct files will be removed, remove the -WhatIf from the command.
Remove-Item -Path './*' -Include '*.rst' -Exclude 'index.rst' -WhatIf
Id you must do it from a cmd.exe (.bat file) script:
powershell -NoLogo -NoProfile -Command ^
"Remove-Item -Path './*' -Include '*.rst' -Exclude 'index.rst' -WhatIf"
I've written a batch file that will do some tests then copy the results to a network drive. This use to work fine for me but over the last few days I have noticed it doesn't work for me and other people have said it has never worked for them.
This is the section that I am calling to copy to M: which all computers on our network can see. The section is being called and the archived results folder is being created but nothing is being sent to the destination drive.
Can anybody see what I've done wrong?
:CopyResults
SET CLASSPATH=%CLASSPATH_ORIGINAL%
For /f "tokens=1-4 delims=/ " %%a in ('date /t') do (set mydate=%%a-%%b-%%c)
For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set mytime=%%a%%b)
set source="target"
set Archive= "Archived Results\Test Results - %CLIENTCHOICE% %mydate% At %mytime% Using %BROWSEROPTION%"
set ScreenshotDestination= "Archived Results\Test Results - %CLIENTCHOICE% %mydate% At %mytime% Using %BROWSEROPTION%\Screenshots"
mkdir %Archive%
echo %Archive%
echo d | xcopy %source% %Archive% /k /e /d /y /h /i
rem copy screenshots
set screenshots="Screenshots"
echo d | xcopy %screenshots% %ScreenshotDestination% /k /e /d /y /h /i
%Archive%\site\index.html
rem copy accross to M:
set Destination= "M:\ProductTesting\AutomationResults\%CLIENTCHOICE%\%mydate% At %mytime% Using %BROWSEROPTION% Ran By %username%"
set ScreenshotDestination= "M:\ProductTesting\AutomationResults\%CLIENTCHOICE%\%mydate% At %mytime% Using %BROWSEROPTION%\Screenshots"
set source="target"
mkdir %Destination%
echo %Destination%
echo d | xcopy %source% %Destination% /k /e /d /y /h /i
rem copy screenshots
set screenshots="Screenshots"
echo d | xcopy %screenshots% %ScreenshotDestination% /k /e /d /y /h /i
GOTO Del
I'm in D:\User Profiles\ and I need to delete directorys located in
D:\User Profiles\---USERNAME---\UPM_Profile\AppData\Local\Mozilla\Firefox\Profiles\*.default
Now here's the question. How can I do this dynamic ?
If I type
dir /ad /b /s D:\User Profiles\*\UPM_Profile\AppData\Local\Mozilla\Firefox\Profiles\*.default
it fails.
---USERNAME--- and *.default needs to be dynamic.
Any ideas `?
Something like:
#echo off
for /d %%i in ("D:\User Profiles\*") do (
call :remove_dirs %%i
)
goto :eof
:remove_dirs
echo %1
for /d %%j in ("%1\UPM_Profile\AppData\Local\Mozilla\Firefox\Profiles") do rmdir %%j
goto :eof