How to reorder date format in filename - date

I've been looking all over stackoverflow and other forums online for any help with PowerShell variables and the rename function. I've had no luck.
The filename convention I use is: CompanyName 12.31.15 FS
(The "FS" describes the content of the file, in this case financial statements). Single digit months are preceded by 3 spaces so that the "FS" always ends up in the same column visually in windows explorer.)
The date format is m.dd.yy though I would like to change it to yy.mm.dd. The problem is I have over 30 folders with myriad of files in them- Some don't follow this file naming convention but if they use the m.dd.yy format, then the filename certainly does follow the convention.
So here's what I'm looking for:
A way to switch around only the date part of the file name from m.dd.yy to yy.mm.dd
In so doing, to also remove 2 of the leading spaces (where there are currently 3) and only have one space between CompanyName, date, and content.
The files must be changed in several directories within the "companies" folder
Examples:
Currently:
CocaCola 12.31.15 FS
CocaCola 6.30.15 FS
I want:
CocaCola 15.12.31 FS
CocaCola 15.06.31 FS

Retrieve the files using the Get-ChildItem cmdlet. Rename it using Rename-Item.
To switch the date you could parse it and format it to your desired output. However you could also do everything using a regex:
$yourCompanyPath = 'C:\tmp'
$callback = {
param($match)
'{0} {1}.{2:D2}.{3} {4}' -f $match.Groups["CompanyName"].Value,
$match.Groups["Year"].Value,
[int]$match.Groups["Month"].Value,
$match.Groups["Day"].Value,
$match.Groups["FS"].Value
}
$rex = [regex]'(?<CompanyName>\S+)\s+(?<Month>\d+)\.(?<Day>\d+)\.(?<Year>\d+)\s+(?<FS>FS)'
Get-ChildItem $yourCompanyPath | Foreach {
$_ | Rename-Item -NewName ('{0}{1}' -f $rex.Replace($_.BaseName, $callback), $_.Extension)
}
Source example:
CocaCola 6.30.15 FS.csv
CocaCola 12.31.15 FS.csv
Output:
CocaCola 15.06.30 FS.csv
CocaCola 15.12.31 FS.csv

Related

Rename files in a folder using powershell, keeping the start and end of string in original filename

Currently trying to create a script that renames specific files within a chosen folder so that the resulting renamed files look like the following:
Original Filename: 45.09 - WrapperA12_rev1.DXF
Resultant Filename: 45.09_1.DXF
So the rev number is included as a suffix to the base filename, the extension is kept and the first 5 characters of the filename is kept (including the ".").
I can get fairly close by removing the hyphens, spaces and letters from the original filename using the -replace argument, but the resultant filename using the example above would be "45.0912_1", where the file extension is ".0912_1". This makes sense, but any attempt I've made to append the file extension (".DXF") to the filename hasn't worked.
$listdxf=gci -path $pathfolder -Filter *.DXF | Select-Object
$prenameDXF=$listdxf|rename-item -WhatIf -newname {$_.name -replace('[a-z]') -replace('-') -
replace('\s','')}
$prenameDXF
Any feedback on how I would go about doing this would be greatly appreciated.
For further clarification; the original filenames will always have the 4 numbers and the dot at the start of the filename - these need to be kept for the output name, the only other number I want is the number at the end of the filename that will always refer to the revision number, however this number may be variable (i.e; it could be 0 or 0.1,1,1.1 etc.). The Rev number will ALWAYS follow the underscore in the original filename. All other numbers and letters etc. in the original filename need to be removed. I'm assuming the solution might include assigning a variable to just return the first 4 numbers (i.e; XX.XX) as a substring maybe, while assigning a variable to the last few characters that follow the "_". Then maybe combine the two and add the ".DXF" file extension.
LATEST UPDATE: Following the responses here, I've been able to get the functionality nearly exactly where I need it to be.
I've been using the regex provided below, and with some slight changes adapted it to allow for some other things (to allow for spaces after "rev" and to allow for the rev number to be separated by a dot if present, i.e; rev1.1 etc.), but currently struggling to find a way of simply returning "0" if no "rev" is present in the file name. For example, if a filename is as follows: 31.90 - SADDLE SHIM.DXF - I wish for the rename regex script to return 31.90_0. The expression I'm currently using is as follows: '(\d{2}\.\d{2}).*?rev(\s?\d+\.\d+|\s?\d+).*(?=\.DXF)', '$1_$2'
I have tried putting a pipeline (if) after the capture block following the "rev" and then putting (0) in a new capture block, but that's not working. Any feedback on this would be greatly appreciated. Thanks again for the replies.
It looks like this regex could do the trick to rename your files with your desired format: (?<=\.\d+)\s.+(?=_rev)|rev.
Get-ChildItem -Filter *-*_rev*.dxf |
Rename-Item -NewName { $_.Name -replace '(?<=\.\d+)\s.+(?=_rev)|rev' }
However the above assumes all files will start with some digits followed by a dot followed by more digits and may or may not be 5 digits including dots. It also assumes there will be a white space after the remaining digits. It also assumes the files will end with rev followed by more digits after it's dxf extension.
This regex could work too (?<=^[\d.]{5})\s.+(?=_rev)|rev, however this one assumes only will capture the first 5 digits including one or more dots.
Per your update, you could try using switch with the -regex option. $Matches will contain the matches and you can reference the match groups by using the group number as the key (e.g. $Matches[1]). You may also reference as a property (e.g., $Matches.1)
Get-ChildItem c:\temp\powershell\testrename -File |
Rename-Item -NewName {
switch -Regex ($_.Name) {
'(\d{2}\.\d{2}).*?rev(\s?\d+\.\d+|\s?\d+).*(?=\.DXF)' {
"$($Matches.1)_$($Matches.2).DXF"
break
}
'(\d{2}\.\d{2}).*(?=\.DXF)' {
"$($Matches.1)_0.DXF"
break
}
default {
$_
}
}
} -WhatIf
Remove -WhatIf once done testing to perform rename action

Renaming several files using CSV in Powershell

I have a special need and I feel stuck on that..
Some user will put some file in a directory with several different name, and I need to rename them regarding a special pattern for those files to be consume by another app.
Example:
In directory -> Target
file1-dd-mm-yyyy -> file1
file2 -> thisfile2
flie45224 -> file123
So as you can see this can be some variables, dates, ID etc..
The target will always be the same but the file in source can be different because of date for example.
So first I had 2 files, so I write the script in plain text "If test-path blabla do this else go out" but it seems that now I will have 37 different files with all differents name. So I thought about using an excel sheet(CSV?), but I can't really find any help on this need.
The goal is to have a sheet as "pattern" like if you found file like in 'A1' then rename as in 'A2' etc...
Do you guys have an idea ?
Thanks by advance :)
I understand you need a csv with the following columns:
A1: regex/pattern to match
A2: transform rule which should be
dynamic
The trick is to use scriptblock if you want to use variables like the file name.
Basically, your csv will be:
A1;A2
"^file1-\d\d-\d\d-\d\d\d\d$";"file1"
"^file2$";"this$($file.Name)"
"^flie*";"file123"
And the code would be:
$myRules = Import-Csv "C:\xxx\test.csv" -Delimiter ";"
$files = gci C:\temp\
foreach ($file in $files) {
foreach ($rule in $myRules) {
if ($file.Name -match $rule.A1) {
Write-host "$($file.Name) is matching pattern ""$($rule.A1)"". Applying rename to ""$($rule.A2)"""
$NewScriptBlock = [scriptblock]::Create("rename-item -Path $($file.FullName) -NewName ""$($rule.A2)""")
$NewScriptBlock.Invoke()
}
}
}
Which gives before:
file1-01-02-0344
file2
flie45224
Output during the execution:
file1-01-02-0344 is matching pattern "^file1-\d\d-\d\d-\d\d\d\d$". Applying rename to "file1"
file2 is matching pattern "^file2$". Applying rename to "this$($file.Name)"
flie45224 is matching pattern "^flie*". Applying rename to "file123"
And after:
file1
thisfile2
file123
Explanations
The first foreach is parsing the files. Then for each of those files, we are checking if one of the rule is matching thanks to the -match $rule.A1.
With the first example, you can use regexp (\d to match digits). For the other cases, I kept it simple as you didn't clarify the rules but this will be your homework :)
Then in the transform rules, you can use the filename variable as shown in the second transform rule: this$($file.Name)
NB: it could be a good idea to add a flag to leave the loop for the current file once it has been renamed to avoid unecessary check and to display a message if the file hasn't match any pattern.
Seems a bit odd, I suspect you should be able to use a regex pattern instead but can't say without seeing the csv contents. Otherwise try this. Assumes the CSV has a column headers called First and Second, First matches the basename (no extension) of the file and Second contains the basename you want it changed to.
$csv = Import-Csv -Path c:\filenames.csv
Get-ChildItem -Path c:\temp | %{if($csv.First -contains $_.BaseName){Rename-Item -Path $_.FullName -NewName "$($csv.Second[$csv.First.IndexOf($_.BaseName)]+$_.Extension)"}}

How to pull strings from multiple .txt files based on file name and append them to a new file?

so basically I have a series of .txt files following the same nomenclature, such as:
1111210803_3CE_080977851__006908818__21110300013442021110420211105_20211110_120447_35418862_820
1111210933_3CE_006908818__2111040001442021110520211108_20211110_120447_35418860_820
The naming convention on these all files always starts with the date, ie 111121. Inside these files, you have lines of strings. I am interested in pulling a specific string in the first line from each of these files. Here is an example of the first line:
123456789012345678901234567890123 I 696969CCHKCTX 12345678901 DA 22758287
In particular, I am interested in the 696969CCHKCTX string. All files will have some numbers followed by the CCHKCTX value. I want to pull the 696969 part of the 696969CCHKCTX string from each .txt file and append them all into a new file.
If possible, I would like to sum those strings and add the appropriate decimal place, as they are to actually be dollar values ie 696969 is actually representing 6969.69 and the last two numbers in that string always represent the cent amount. This rule applies to all the .txt files. I want to be able to apply this to all files that are the same date (ie all files starting with 111121)
How would I go about this?
Try the following, which combines Get-ChildItem, Group-Object, and ForEach-Object, as well as the -replace operator:
Get-ChildItem -File | # get files of interest; add path / filter as needed.
Group-Object { $_.Name.Substring(0, 6) } | # group by shared date prefix
ForEach-Object {
$firstLines = $_.Group | Get-Content -First 1 # get all 1st lines
# Extract the cents amounts and sum them.
$sumCents = 0.0
$firstLines.ForEach({
$sumCents += [double] ($_ -replace '.+\b(\d+)CCHKCTX\b.+', '$1')
})
# Output an object with the date prefix and the sum dollar amount.
[pscustomobject] #{
Date = $_.Name
Sum = $sumCents / 100
}
}
The above outputs a table-formatted representation to the display. You can save it to a file with > / Out-File, for instance, though it's better to use a structured text format for later processing, such as Export-Csv.

Powershell how to bulk rename files containing DTS 1080p 720p x264 etc

I am trying to create a powershell script to rename media files that have a bunch of descriptions in the file name like DTS,1080P,720P,x264,DVD etc...
Is there some sort of or condition that can be used in the replace option?
To be honest, I'd probably just do it the lazy way and replace all the terms you don't want with nothing, do the same with underscores if desired (included in my example code), trim spaces from the end, and then rename the file (I just use the .MoveTo method).
gci "C:\Movies" | %{$_.MoveTo("$($_.Directory)\$(($_.BaseName -replace '(?i)(1080p|720p|DTS|DVD|x264|_)').TrimEnd(" "))$($_.Extension)")}
Use the -filter parameter
$count = 0
ls -filter "*1080p*" | % { Rename-item $_ "NewFile$count.ext";$count++}
Careful, that will rename all files in current directory with "1080p" in the name to newfile0.ext.. just an example

Powershell - Splitting string into separate components

I am writing a script which will basically do the following:
Read from a text file some arguments:
DriveLetter ThreeLetterCode ServerName VolumeLetter Integer
Eg. W MSS SERVER01 C 1
These values happen to form a folder destination W:\MSS\, and a filename which works in the following naming convention:
SERVERNAME_VOLUMELETTER_VOL-b00X-iYYY.spi - Where The X is the Integer above
The value Y I need to work out later, as this happens to be the value of the incremental image (backups) and I need to work out the latest incremental.
So at the moment --> Count lines in file, and loop for this many lines.
$lines = Get-Content -Path PostBackupCheck-Textfile.txt | Measure-Object -Line
for ($i=0; $i -le $lines.Lines; $i++)
Within this loop I need to do a Get-Content to read off the line I am currently looking at i.e. line 0, line 1, line 2, as there will be multiple lines in the format I wrote at the beginning and split the line into an array, whereby each part of the file, as seen above naming convention, is in a[0], a[1], a[2]. etc
The reason for this is because, I need to then sort the folder that contains these, find the latest file, by date, and take the _iXXX.spi part and place this into the array value a[X] so I then have a complete filename to mount. This value will replace iYYY.spi
It's a little complex because I also have to make sure when I do a Get-ChildItem with -Include before I sort it all by date, I am only including the filename that matches the arguments fed to it from the text file :
So,
SERVER01_C_VOL-b001-iYYY.spi and not anything else.
i.e. not SERVER01_D_VOL-b001-iYYY.spi
Then take the iYYY value from the sort on the Get-ChildItem -Include and place that into the appropriate array item.
I've literally no idea where to start, so any ideas are appreciated!
Hopefully I've explained in enough detail. I have also placed the code on Pastebin: http://pastebin.com/vtFifTW6
This doesn't need to be that complex. You can start by operating over lines in your file with a simple pipeline:
Get-Content PostBackupCheck-Textfile.txt |
Foreach-Object {
$drive, $folder, $server, $volume, [int]$i = -split $_
...
}
The line inside the loop splits the current input line at spaces and assigns appropriate variables. This saves you the trouble of handling an array there. Everything that follows needs to be in said loop as well.
You can then construct the file name pattern:
$filename = "$server_$drive_VOL-b$($i.ToString('000'))-i*.spi"
which you can use to find all fitting files and sort them by date:
$lastFile = Get-ChildItem $filename | sort LastWriteTime | select -last 1