How to split string and rename files in PowerShell? - powershell

I want to bulk rename the files in my folder, and all of them have the format of FilenameYeara\b.pdf, for example, TestData2001a.pdf, File2015b.pdf. I want to rename all of them to something like [Yeara\b]Filename, such as [2001a]TestData. The problem is that I don't know how can I split my filename into two parts (actually three if we count the extension, .pdf part), such that I put that second part as the first part of the file name.
Get-ChildItem | Rename-Item {$_.name -replace ‘current’, ’old’ }
How can I achieve this?

This does the regex match "anything, four digits, one character, .pdf" and replaces it with those items in the new ordering.
PS D:\t> gci | ren -newname { $_ -replace '(.*)(\d{4})(.)\.pdf', '[$2$3]$1.pdf' }
Directory: D:\t
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 13/05/2016 02:54 0 File2015b.pdf
-a--- 13/05/2016 02:53 0 TestData2001a.pdf
becomes
Directory: D:\t
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 13/05/2016 02:53 0 [2001a]TestData.pdf
-a--- 13/05/2016 02:54 0 [2015b]File.pdf
(Maybe try it with -Whatif before running for real)

This should get you started
$Matches.Clear()
Get-Item | % {
$_.BaseName -match "(\D+)([0-9]{4}[ab])"
Rename-Item -Path $_.FullName -NewName "$($Matches[2])$($Matches[1])$($_.Extension)"
}

Related

I want to import a csv to use as filter in the powershels gci command

I have a csv file with extension and description.
I want to import that file and use it as the filter parameter in a gci command.
But I get no results.
I expect to get a list of the jpg files but get no results.
$extensions=Import-CSV -Path c:\scripts\Media-extension-foto.csv
#$extensions=Import-CSV -Path c:\scripts\Media-extension-foto.csv -header extension
$extensions.extension
$src = "c:\scripts\"
#gci c:\scripts\ -Include $Extensions.extension #-Force -recurse
#gci c:\scripts\ -filter $Extensions.extension #-Force -recurse
gci c:\scripts\|where{$_ -like $extensions.extension}`
my csv file looks like this (just made a small file for testing)
extension,"description"
*.JPEG,JPEG Image
*.JPF,JPEG 2000 Image
*.JPG,JPEG Image
*.JPG_LARGE,Twitter Large JPEG Image
There are jpg files in that folder :
Directory: C:\Scripts
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 23/11/2022 11:02 509592 nieuw9754560_02-10.jpg
-a--- 23/11/2022 11:02 576486 nieuw9754560_02-15.jpg
-a--- 23/11/2022 11:02 641802 nieuw9754560_02-20.jpg
-a--- 23/11/2022 11:01 705702 nieuw9754560_02-25.jpg
-a--- 23/11/2022 11:01 763249 nieuw9754560_02-30.jpg
I've just tested this - I think all you're missing is changing the $_ to $_.Extension for the Get-ChildItem, on the last line.
Hope that helps.
Doesn't directly fix the code but here's another way of getting the result using foreach to iterate through each extension in the array:
foreach($e in $extensions.extension) {
gci c:\scripts\ | where {$_ -like $e}
}

Powershell: How To Extract Binary File Attributes From Directory Listing

In PowerShell, I can get a nice list of files in descending sorted order using a filter:
$tt = gci -Path \\Munis2\musys_read\export_test\* -Include "ARLMA_*.csv" | sort LastWriteTime -Descending
PS H:\WindowsPowerShell\Scripts\ProductionScripts\Munis> $tt
Directory: \\Munis2\musys_read\export_test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 03/04/2022 3:09 AM 25545520 ARLMA_20220304030027.csv
.
.
.
Then, I can get just the name of the file for the purposes of transferring that file to an FTP site.
PS H:\WindowsPowerShell\Scripts\ProductionScripts\Munis> $tt[0].Name
ARLMA_20220304030027.csv
How can I parse $tt[0].LastWriteTime
PS H:\WindowsPowerShell\Scripts\ProductionScripts\Munis> $tt[0].LastWriteTime
Friday, March 4, 2022 3:09:14 AM
into something that looks like yymmddhhmmss, or is there a way to get the binary time of the file the last time it was accessed?
The ToString() method can be used to format the date into a string. Are you sure that a two digit year is appropriate?
$DateResult = (Get-ChildItem -Path \\Munis2\musys_read\export_test\* -Include "ARLMA_*.csv" |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -First 1).LastWriteTime.ToString('yyMMddHHmmss')

Foreach loop not reading files in numeric order

I have below files which i am reading using a foreach loop.
$GetGeneratedFiles = Get-ChildItem -Path "C:\Script\LF*.csv" -recurse | % { $_.FullName }
C:\Script\LF_Batch_1.csv
C:\Script\LF_Batch_10.csv
C:\Script\LF_Batch_11.csv
C:\Script\LF_Batch_12.csv
C:\Script\LF_Batch_13.csv
C:\Script\LF_Batch_14.csv
C:\Script\LF_Batch_15.csv
C:\Script\LF_Batch_16.csv
C:\Script\LF_Batch_17.csv
C:\Script\LF_Batch_18.csv
C:\Script\LF_Batch_19.csv
C:\Script\LF_Batch_2.csv
C:\Script\LF_Batch_20.csv
C:\Script\LF_Batch_21.csv etc...upto LF_Batch_.96.csv
Problem is it is reading the files like above not 1,2,3...and so on.
Please need idea how to read in ordered way
Solved using below approach
$GetGeneratedFiles = Get-ChildItem -Path "C:\Script\LF*.csv" -recurse | % { $_.FullName }
$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$GetGeneratedFiles = $GetGeneratedFiles | Sort-Object $ToNatural
Thanks #vonPryz for the reference.
Another way. It's funny how I just did another answer similar to this. A numeric sort on the names.
echo hi | set-content (1,2,10,20 | % tostring LF_Batch_0\.csv)
dir | sort {[void]($_ -match '\d+'); [int]$matches.0}
Directory: C:\Users\js\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 9/17/2020 9:14 AM 4 LF_Batch_1.csv
-a--- 9/17/2020 9:14 AM 4 LF_Batch_2.csv
-a--- 9/17/2020 9:14 AM 4 LF_Batch_10.csv
-a--- 9/17/2020 9:14 AM 4 LF_Batch_20.csv

Get-ChildItem -Path in NLog file

If I have this:
Get-ChildItem -Path $BACKUP_REG_PATH >> $TOT_LOG_FILE
I will get a fine list in my log file like this:
Directory: C:\WS\BACKUP\xxxx-Reg
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2016-05-17 11:04 494018 xxxxxx_REGISTRY_EVENTLOG__2016-05-17__11_04_38.reg
-a--- 2016-05-17 11:08 494018 xxxxxx_REGISTRY_EVENTLOG__2016-05-17__11_08_59.reg
-a--- 2016-05-17 11:10 494018 xxxxx_REGISTRY_EVENTLOG__2016-05-17__11_10_31.reg
I want to do this for NLog instead but I don't know how to get a nice list as above.
If I do this:
$regtxt=Get-ChildItem -Path $BACKUP_REG_PATH
$LOGGER.Trace("$regtxt");
I only get a long list on the same row with the Name column.
Any ideas how to solve this?
I don't know NLog but the Trace method probably output the trace in a single line. You could iterate over each item using the Foreach-Object cmdlet and write a trace:
Get-ChildItem -Path $BACKUP_REG_PATH | Foreach-Object {
$LOGGER.Trace($_);
}
Note: This will not output the name column, you may have to trace this yourself.
To solve this, you could pipe the output to the Out-String cmdlet which will give you a single string. You then have to split the string by [System.Environment]::NewLine to get an array to iterate over it:
((Get-ChildItem | select -first 4 | Out-String) -split [System.Environment]::NewLine) |
ForEach-Object {
$LOGGER.Trace($_);
}

"(" char doesn't work in PowerShell

I can't get this to work. It doesn't like the "(" char;
how do I fix it?
Dir | Rename-Item -NewName { $_.name -replace "(","" }
How do I handle this type of special character in PowerShell?
You've got a great explanation of the exact cause of your problem from #vonPryze, but there's a much simpler solution. The -replace operator uses regular expressions which need escaping, but the .Replace() string method just uses strings. So if you don't need a regex, just use the method and there's no need to escape anything:
dir | rename-item -NewName { $_.name.Replace("(","") }
Let's try analyzing the problem a bit. First off, create some dummy files that contain a parenthesis like so,
for($i=0;$i -le 4; ++$i) { set-content -path $("file($i).txt" -f $i) -value $i }
Output:
gci
Directory: C:\temp\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 17.2.2014 10:34 3 file(0).txt
-a--- 17.2.2014 10:34 3 file(1).txt
-a--- 17.2.2014 10:34 3 file(2).txt
-a--- 17.2.2014 10:34 3 file(3).txt
-a--- 17.2.2014 10:34 3 file(4).txt
Now that we have some test data, let's try to run the command that provied an error message like so,
Dir | Rename-Item -NewName { $_.name -replace "(","" }
Rename-Item : The input to the script block for parameter 'NewName' failed.
Invalid regular expression pattern: (.
At line:1 char:27
+ Dir | Rename-Item -NewName <<<< { $_.name -replace "(","" }
+ CategoryInfo : InvalidArgument: (file(0).txt:PSObject) [Rename-Item], ParameterBind ingException
+ FullyQualifiedErrorId : ScriptBlockArgumentInvocationFailed,Microsoft.PowerShell.Commands.Re nameItemCommand
Oops! The error message says that an invalid regular expression was used. That means -replace is not going to just replace strings but it supports regular expressions too!
In order to get -replace to treat the input as literal text instead of a regex, the input needs to be escaped. The simple way is to insert backslashes \, but this gets soon tedious. There luckily is an easier way, as .Net Regex class has a built-in escape method [Regex]::Excape(). Like so,
Dir | Rename-Item -NewName { $_.name -replace [regex]::escape("("),"" }
Output:
ls
Directory: C:\temp\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 17.2.2014 10:34 3 file0).txt
-a--- 17.2.2014 10:34 3 file1).txt
-a--- 17.2.2014 10:34 3 file2).txt
-a--- 17.2.2014 10:34 3 file3).txt
-a--- 17.2.2014 10:34 3 file4).txt
Dir | Rename-Item -NewName { $_.name -replace "\(","" } # This works