I am trying to create a batch file that I can use to type in a name of a folder and search multiple directories, then display the results in a new window. Example: I want to search for "tcash" in 3 separate directories, ie; \vm-xa01\users, vm-xa02\users and vm-xa03\users. How can I do this?
The original question had Powershell tag, so the answer is Powershell. For cmd (batch) script, I'd strongly suggest you to move into Powershell anyway. It's 2018 and cmd scripts require lots of tweaking.
In Powershell, there's a built-in cmdlet Out-GridView that might be suitable. For example, to display all txt files in c:\some\path and its subdirectories requires just a few commands. Like so,
gci c:\some\path -Recurse | ? { $_.extension -eq ".txt" } | ogv
First off, get a recursive list of all files
gci c:\some\path -Recurse
Then select those that have extension .txt
| ? { $_.extension -eq ".txt" }
Finally, pass the results to out-gridview aka ogv
| ogv
I also think PowerShell is the better script language for your task.
You can do a dir/Get-ChildItem with ranges [1-3] similar to a Regular Expression, so:
Get-ChildItem "\vm-xa0[1-3]\users\tcash" -File -Recurse | Out-Gridview
should enumerate all matching files and display in a gui window.
Related
I have a folder with files of different naming patterns. For example:
S012344
S00abcd
DA01234
DAL1230
D13459A
MOV0001
M123004
Now I need to move all the files except the one which have the following naming patterns: (** means regular expression)
- S00****
- Starts with D and ends with A
- MOV****
I need to do this as part of a batch file, I searched a lot but didn't find any apt solutions to address this problem.
There are ambiguities in your question. But, here is a possible way to do it. If you are on a supported Windows system, then it will have PowerShell. When you are satisfied that the files will be moved correctly, remove the -WhatIf from the Move-Item command.
=== Move-FilesIWant.ps1
Get-ChildItem -File -Path 'C:\src\t\' |
Where-Object { $_.BaseName -notmatch '(^S00....$|^D.*A$|^MOV....$)' } |
ForEach-Object { Move-Item -Path $_.FullName -Destination 'C:\new\dir' -WhatIf }
If you must run it from a cmd.exe shell or .bat file script, use:
powershell -NoLogo -NoProfile -File '.\Move-FilesIWant.ps1'
I am renaming several hundred files, all which vary with an item ID and then a bunch of text after. For example...
BBAT300_abcdefg.xls
BBAT400_abcdefg.xls
I need to delete everything from the underscore, and including the underscore on, so the result is this:
BBAT300.xls
BBAT400.xls
I found this bit of code earlier...
Get-ChildItem -Name -Filter *.xls | foreach {[Regex]::Match($_,"^[^_]*").Value}
and it appears to work, but I can't get it to actually rename the files. My knowledge of scripting is little to none, so this may be an easy fix, I just can't seem to find it. Powershell will show the results in powershell, but not actually rename the files.
You can just pipe this line to the rename item command:
Get-ChildItem -Filter *.txt | Foreach-Object -Process {
$NewName = [Regex]::Match($_.Name,"^[^_]*").Value + '.txt'
$_ | Rename-Item -NewName $NewName
}
EDIT: Changed it to support any location
I'm trying to use Powershell ISE to help me do the following:
Perform a search for many files (with an extension of *props.tmpl) under a certain folder and to include all sub-directories.
When found, I want to copy that file to its current location, but with an extension of *.tmpl2 (what I really want is to skip this step and copy *props.tmpl to a file called *props)
Then rename all *.tmpl2 files and remove the tmpl2 entirely, leaving just the *.props extension.
Ideally, what I want is to copy existing files to the same directory with a new name. It seems like all of the searches I've ran on Powershell ISE are not coming up with the right info I need (or I'm not searching for the right way to do it - trying 'powershell ise copy many files with new names' didn't help.
I had the replacement piece down and working, but I no longer want to eliminate the original tmpl files (they are templates so I may want to review them later for their original content).
What I was doing to replace them was this:
Get-ChildItem -Filter "*props.tmpl" -Recurse |
Rename-Item -NewName { $_.name -replace '.tmpl',''}
Which works great other than completely removing the original file.
I started trying to piece something together, but I'm not understanding how to properly name the copy and stopped at this point with just an error (this was an attempt to skip the extra copy and just simply rename the copy instead of adding the extra step of '*.tmpl2'):
# Get all *props.tmpl files
Get-ChildItem -Filter "*props.tmpl" -Recurse |
# Iterate through each found file
ForEach-Object {
Copy-Item $_.name |
Rename-Item -NewName { $_.name -replace '.props.tmpl','.props' }
}
Any help would be really appreciated (not much of a Powershell guy, but I'm trying to learn since powershell tends to be a little more dynamic then oldschool batch scripts).
Thanks in advance
Final version of this script per help from #ssennett
Here's my final version:
# Get all *props.tmpl files
Get-ChildItem -Filter "*props.tmpl" -Recurse |
# Iterate through each found file and copy it to non-template form in same location
ForEach-Object {
Copy-Item $_.FullName ($_.Name -replace '.tmpl','')
}
You're not too far from the answer! It's just how Copy-Item is being handled.
Without a Destination being specified, the Copy-Item will effectively try and copy the file onto itself. Instead of piping it to Rename-Item, you can handle the renaming with the -Destination parameter, as below.
$files = Get-ChildItem -Filter "*props.tmpl" -Recurse
$files | % { Copy-Item -Path $_.FullName -Destination ($_.Name -replace 'props.tmpl','.props') }
This would copy a file called RandomFileprops.tmpl into another file RandomFile.props. If you want to remove the original, you can use the Move-Item cmdlet with the same parameters, which effectively renames the original file.
I am trying to convert my batch file syntax to PowerShell v3.0. I need to pull all the file names from a mapped network drive and save it to a folder on my root C:
Everything works except when it comes to saving the file names. If I do
dir /s > C:\2\filename.txt
In a batch file it will output the file's name (along with the extension) and the date modified to a .txt file. However I cannot get the PowerShell v3.0 equvalent to work. It just creates a txt file but nothing is saved within the file. Here is my PowerShell v3.0 code.
Get-ChildItem -Path K:\Transactions\Processed\Audit-Images\Lane` 12\$date\done > C:\2\$date-LaneServer12ImagesDONE.txt
In the examples below, you may want to add some parameters to Get-ChildItem depending on what you're looking for. "-Force" to have it list hidden files, "-Attributes !Directory" to exclude directory names.
I would find the output most useful in a csv.
Get-ChildItem -Path K:\Transactions\Processed\Audit-Images\Lane` 12\$date\done -Recurse | Select-Object Name,LastWriteTime | Export-CSV "C:\2\filename.csv"
Same line, in a text file:
Get-ChildItem -Path K:\Transactions\Processed\Audit-Images\Lane` 12\$date\done -Recurse | Select-Object #{n='File';e={$_.Name + " " + $_.LastWriteTime}} | Out-File "C:\2\filename.txt"
Code below works when I am in a directory:
gci | % {rni $_.Name ($_.Name -replace '120', '121')}
How do I create a batch file with powershell code that will work in every directory without errors. I just want to start file.bat that will rename all files in every folder where file.bat is located?
powershell -C "gci | % {rni $_.Name ($_.Name -replace '120', '121')}"
That doesn't work, here is error:
Expressions are only permitted as the first element of a pipeline.
At line:1 char:52 + gci | {rni $_.Name ($_.Name -replace '501', '121')} <<<<
Comedy answer:
echo Hi
is a batch file that will "work in any directory without errors", which is literally what you asked for.
Half serious answer, here is a batch file which will do the equivalent renaming of 120 to 121 in files in the current folder, what your PowerShell does, which is plausibly what you ask for:
#echo off
setlocal ENABLEDELAYEDEXPANSION
for %%f in (*120*) do (
set _f=%%f
ren "%%f" "!_f:120=121!"
)
Although even though you asked about Batch files and tagged the question about batch files, I suspect that's not what you want. Maybe you mean "how can I specify the directory for it to run against?" Then maybe this:
powershell -C "gci '%1' | % {rni $_.Name ($_.Name -replace '120', '121')}"
Where you save this as a batch file to run from a command prompt, %1 is the parameter you give to the batch file which is embedded in the PowerShell code, quoted as the input to gci. Then you could run myscript.bat "c:\data files" which would launch PowerShell and rename files in "c:\data files\".
Or maybe if you are asking more about the "with no errors" part from your title, then you need to accept that you might not have permission to list folder contents, or permission to rename files, or renaming files might lead to clashing names, in that case what you need is to add
`-ErrorAction -Ignore`
to gci and to rni, which will make them "run without errors", in a sense.
Serious answer: % is a special character in batch files, you need to escape it by writing it twice.
powershell -C "gci | %% {rni $_.Name ($_.Name -replace '120', '121')}"
Otherwise it gets swallowed and you get the error "Expressions are only allowed as the first element of a pipeline."
NB. You are trying to rename every file in the folder, regardless of whether it has 120 in the name or not, this is horrible. Follow Nikhil Gupta's suggestions on how to avoid doing that.
You could have been a little more specific. I'm making assumptions now to try and solve your issue -
You want to rename all the files with 120 in the name to now have 121.
You want to do it in a specific directory but want to run the script from any location on the cmd.
The current script would run in any directory, get all the child items in that directory and replace 120 with 121. It wouldn't work if the name doesn't have 120.
Based on this I suggest 2 modifications -
Add a filter while gci to get only the items with 120 in the name.
Add a first line to go to the directory you need the script to run under.
Here is the sample code -
Set-location <dir>
gci -Filter "*120*" | % {rni $_.Name ($_.Name -replace '120', '121')}