Perform action on first file in each subdirectory - batch-file

I'm trying to perform a command on the alphabetically first file in a set of subdirectories using
for /R "parentfolder" %%a in (*.doc) do "%winword%" /mRTF "%%a"
in a batch file. The actual command and macro work fine, but it performs the action on each file in the directories instead of just the ones I want.
Is there a way to set the -on flags in this context?
Any help will be highly appreciated.
Thank you that got me a good bit further.
Currently I'm struggling with opening word and running the Macro through powershell. My code looks like this now:
$word = new-object -comobject word.application
$path = 'C:\Users\---\Desktop\Download\'
$folders = Get-ChildItem -Path $path -recurse | SELECT Attributes, Name | where-Object{ $_.Attributes -eq 'Directory'} | ForEach-Object{$_.name}
foreach ($folder in $folders){
Get-ChildItem -Path $path$folder |
Select-Object -First 1 |
ForEach-Object { notepad $_.FullName }
}
I try to change notepad to word and call the macro but so far no luck

Here is a way to do it in PowerShell. I used notepad.exe, but you can use whatever you want.
Get-ChildItem -Path '../' -Filter '*.doc' |
Select-Object -First 1 |
ForEach-Object { notepad "$_.FullName" }
If you -must- do this from a cmd shell .bat script, you could:
powershell -NoProfile -Command Get-ChildItem -Path '../' -Filter '*.doc' ^| ^
Select-Object -First 1 ^| ^
ForEach-Object { notepad \"$($_.FullName)\" }
HT to mklement0 for the escape.

Based upon your example code and subsequent comments, the below example may run your Word macro on each of the files you require:
SetLocal EnableDelayedExpansion
For /D %%A In ("parentfolder\*") Do (Set "_="
For /F "Delims=" %%B In ('Dir/B/A-D-S-L/O-N "%%A\*.doc" 2^>Nul'
) Do Set "_=%%B"
If Defined _ "%winword%" /mRTF "%%A\!_!")

Related

batch script to rename the most recent file in all subfolders?

#echo off
for /f %%i in ('dir /b /a-d /od /t:c "*.pdf"') do (
set LastFileCreated=%%i
)
echo The Last File Created is %LastFileCreated%
pause
:: ren %LastFileCreated% "decs365.pdf"
pause
all I have is this script, but unfortunately it needs to be copied in each and every sub folder, thus defeating the purpose, and it wont even rename the files. Is there any way to add a specified path "D:\Monthly Report" and have it rename the most recently created file in all of the sub folders to "decs365"
I'd suggest you leverage powershell.exe, from your batch-file for this task:
#%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoProfile "Get-ChildItem -Filter '*.pdf' -File -Recurse | Sort-Object CreationTime -Descending | Select-Object -First 1 | Rename-Item -NewName 'Decs365.pdf'"
Obviously, if you're not running the command in the same working directory, as you are in your question, you'd need to add that directroy to the command above, e.g. Get-ChildItem -Path 'C:\MyDirectoryPath' -Filter …

How to find folders that containt a certain string using CMD?

I need to find the path of every folder that contains the words "test" or "Test" or "TEST" in a specific location. The file tree is huge.
This is to remove every folder that contains "test". I've tried using
the findstr function.
findstr /i "test"
I expect to get every folder path that contains "test"
The list of directories can be generated and iterated over using a FOR loop. When you are satisfied that the correct directories will be deleted, remove the echo from the line containing rmdir.
#echo off
pushd \
for /f "delims=" %%a in ('dir /s /b /a:d "*test*"') do (
echo if exist "%%~a" (rmdir /s /q "%%~a")
)
popd
If you wanted to push ahead into Powershell, which Microsoft says is the future, something like this might work. When you are satisfied that the correct directories will be removed, remove the -WhatIf from the Remove-Item cmdlet.
=== Remove-TestDirectories.ps1
$previousdir = ":" # set to impossible filesystem name
Get-ChildItem -Directory -Recurse -Path "C:\" -Filter "*test*" -Force -ErrorAction SilentlyContinue |
Sort-Object -Property FullName |
ForEach-Object {
#"{0} and {1} and {2}" -f #($previousdir, $_.FullName, $_.FullName.StartsWith($previousdir))
if (-not $_.FullName.StartsWith($previousdir)) {
$previousdir = $_.FullName
if (Test-Path -Path $_.FullName) { Remove-Item -Path $_.FullName -Recurse -WhatIf}
}
}
This can be run from a cmd.exe shell.
powershell -NoLogo -NoProfile -File Remove-TestDirectories.ps1

xCopy into the top folder of a directory

I running an xcopy command to transfer from one file to the other.
xcopy /s "c:\users\documents\thisfile.txt" "d:\otherfiles\1.2.1"
I'd like to be able to just copy the file into the most recent folder in the otherfiles directory rather than hard coding it every time a new version folder is created. These are versions numbers and these tend to just increase.
Is this entirely possible?
If you wanted to do this in PowerShell, it is possible. This would require PowerShell 3.0 or higher. It can be done with 2.0, but would require changes. Hopefully, you are on or can upgrade to a modern-day version of PowerShell.
When you are confident that the file will be copied correctly, remove the -WhatIf from the Copy-Item cmdlet.
$fn = 'C:/src/t/xxx.txt'
$destbasedir = 'C:/src/t/lastdir'
Get-ChildItem -Directory -Path $destbasedir |
Sort-Object -Property Name |
Select-Object -Last 1 |
ForEach-Object { Copy-Item -Path $fn -Destination $_.FullName -Whatif }
This could be put into a .bat file script.
SET "FN=C:\src\t\xxx.txt"
SET "DESTBASEDIR=C:\src\t\lastdir"
powershell -NoProfile -Command ^
"Get-ChildItem -Directory -Path %DESTBASEDIR% |" ^
"Sort-Object -Property Name |" ^
"Select-Object -Last 1 |" ^
"ForEach-Object { Copy-Item -Path "%FN%" -Destination "$_.FullName" -Whatif }"
Ok, it is possible to check the versions of the directories, but that will take a bit more code as we cannot simply remove the dots to get a numeric value and compare to the next. The reason being, considering versions 1.2.3 and 1.23 if we remove the dots to make it a matchable numeric value, both these will end up being being 123 therefore each version section would need to be tested.
However, based on your comments to my questions, you create new versions as folders, and therefor it ia sortable by date, so simply run a dir command and sort by created date. It will set the latest folder as the variable you need:
#echo off
for /f "delims=" %%i in ('dir /b /ad /o:d D:\otherfiles') do set "myvar=%%i"
xcopy /s "c:\users\documents\thisfile.txt" "d:\otherfiles\%myvar%"

Batch Command Error

#echo off
setlocal
set Folder=C:\Test
set FileMask=*.txt
set OldestFile=
for /f "delims=" %%a in ('dir /b /o:d %Folder%\%FileMask%" 2^>NUL') do (
set OldestFile=%%a
goto Break
)
:Break
if "%OldestFile%"=="" (
echo No files found in '%Folder%' matching '%FileMask%'!
) else (
del "%Folder%\%OldestFile%"
)
Hi, I am trying to delete the oldest file in the Test directory using batch file but I am getting an error after running it with or without an Admin Privilege where 'dir /b /o:d "C\Test" 2>NUL' is not recognized as an internal or external command, operable program or batch file. I am trying to run it on Windows Server 2012 R2 x64 bit. Please help. Thank you.
PowerShell seems a bit more concise. Once you are satisfied that it is deleting the correct file, remove the -WhatIf switch.
C:\src\t>type xxx.bat
#ECHO OFF
SET "Folder=C:\src\t"
SET "FileMask=*.txt"
powershell -noprofile -command "dir %Folder% -filt %FileMask% -file |"^
"sort -p LastWriteTime -d |"^
"select -l 1 |"^
"del -WhatIf"
C:\src\t>xxx.bat
What if: Performing the operation "Remove File" on target "C:\src\t\th.txt".
If you are running PowerShell, the syntax is much cleaner.
PS C:\src\t> type .\xxx.ps1
$Folder = 'C:\src\t'
$FileMask = '*.txt'
Get-ChildItem -Path $Folder -Filter $FileMask -File |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -Last 1 |
Remove-Item -WhatIf
PS C:\src\t> .\xxx.ps1
What if: Performing the operation "Remove File" on target "C:\src\t\th.txt".

Rename folders, subfolders, and files

I am new to coding / programming and trying to create a simple robocopy routine that automates the duplication of a template project folder from one location to the main project drive, then renames the "00-000" portion of the folder (which is always at the beginning of the name) and contained subfolders and files based on a user specified variable. Here is what my robocopy routine looks like.
echo off
robocopy "C:\Program Files\Autodesk\ACAD_Config\00-000-NewProject" "T:\Projects" /xd Dfsrprivate /s /e /W:0 /xd DfsrPrivate /r:0 /np
The rename portion is where I get lost. Once the 00-000-NewProject folder has been created on the T:\ drive, it should be time to rename the folder and contained sub-folders and files.
For example,
Routine prompts to set variableA "Enter project number:"
User enters variableA definition, "EP-001"
Routine verifies changes that are about to be made "The Project Number for all folders and files will be renamed to: 'EP-001' is this correct Y/N ?"" (y = confirm changes and on to step 4. n = reenter project number)
This routine replaces any instance of (00-000) contained within the 00-000-NewProject folder with VariableA
Is my idea possible with windows CMD? I would like to avoid installing any 3rd party applications as updates and maintenance can get hairy in a 100 person firm. Any help would be greatly appreciated but further explanation of any suggested code would be most useful in teaching myself how to program. Thank you in advance!
I believe this is what you are trying to do, but as #Guildencrantz mentions, you may need to clarify further about your project structure, files, did you mean file names only, directories, etc.
Example batch file
To use, rename d:\test to your t: directory, remove the echo statements so commands execute, etc.
#echo off
setlocal enabledelayedexpansion
set variableA=EP-001
set newfolder=%variableA%-NewProject
echo robocopy "C:\Program Files\Autodesk\ACAD_Config\00-000-NewProject" "D:\test\Projects\%newfolder%" /xd Dfsrprivate
::: rename all files under T:\Projects\%newfolder% that start with 00-000 prefix with the variableA prefix
for /r D:\test\Projects\%newfolder%\ %%f in (*) do (
::: #echo Found: %%f
set newname=%%f
call set newname=!newname:00-000=%variableA%!
#echo ren %%f !newname!
)
endlocal
Sample Output:
D:\test>rename1.cmd
robocopy "C:\Program Files\Autodesk\ACAD_Config\00-000-NewProject" "D:\test\Projects\EP-001-NewProject" /xd Dfsrprivate
ren D:\test\Projects\EP-001-NewProject\00-000-one.txt D:\test\Projects\EP-001-NewProject\EP-001-one.txt
ren D:\test\Projects\EP-001-NewProject\00-000-two.txt D:\test\Projects\EP-001-NewProject\EP-001-two.txt
I see that this is old. It may not matter now, but it was interesting to work out. The difficult spot was renaming the directories from the furthest leaf back to the root.
$project_base = 'C:/src/t/bn'
$template_dir = "$($project_base)/00-000-NewProject"
$project_name_approved = $false
do {
$pn = Read-Host 'Please enter the new project name'
$new_project_dir = "$($project_base)/$($pn)-NewProject"
if (Test-Path -Path $new_project_dir) {
Write-Host "Project $($pn) already exists. Please choose another project name."
} else {
$ap = Read-Host "Rename new project to $($pn)? (Y/N)"
if ($ap -match '^y') { $project_name_approved = $true }
}
} until ($project_name_approved)
# Create the new project directory and copy template files
New-Item -ItemType Directory -Path $new_project_dir | Out-Null
Copy-Item -Path "$($template_dir)\*" -Destination $new_project_dir -Recurse -Exclude DfsrPrivate
# Rename directories first, from the longest leaf in the tree back to the shortest
$dir_names = Get-ChildItem -Recurse -Directory -Path $new_project_dir |
Sort-Object -Property Length -Descending |
ForEach-Object {
$fn = Split-Path $_ -Leaf
if ($fn -match '^00-000') {
Rename-Item -Path $_.FullName -NewName "$($fn -replace '^00-000', $pn)"
}
}
Get-ChildItem -Path $new_project_dir -File -Recurse |
ForEach-Object {
Rename-Item -Path $_.FullName -NewName $($_.Name -replace '00-000', $pn)
}

Resources