There are files named year / month yyyymm , and I need to rename them on the contrary mmyyyy , but the month mm in the name should be one less. And the whole difficulty lies in the fact that I need to do it in one line.

I can rename using regex replace abc2017 06 .txt to abc 06 2017.txt using a pattern

'abc201706.txt' -replace '^(.*)([0-9]{4})([0-9]{2})(\..*)$','$1$3$2$4'

But how can I rename it to abc 05 2017.txt ?
In other words, I need in this line to subtract one month from $3 , which corresponds to the initial month.

  • Did my solution work? - Wiktor Stribiżew

1 answer 1

Just one line can not. If you need to do everything with a single Regex.Replace() method, you need to use the callback function as a replacement argument. By passing a match argument to this method, you must convert the date string to a DateTime object in order to correctly calculate the new date. Imagine the file is named 012017.txt , and if you just take 01 and subtract one, you get a zero month, which does not make sense.

Therefore, use the following approach (a slightly modified version of Tomalak ):

 Get-ChildItem 'C:\1\*.txt' | Rename-Item -NewName { [Regex]::Replace($_.Name, '([0-9]{6})\.txt$', { try { [DateTime]::ParseExact($args[0].Groups[1].Value, "MMyyyy", $null).AddMonths(-1).ToString("MMyyyy") + ".txt" } catch { $args[0] } }) } 

You cannot do without the callback function.

note

  • $args[0] is an integer match ( Match object)
  • ([0-9]{6})\.txt$ is a regular expression that captures 6 digits in the first exciting group, and then the dot and the text txt at the end of the line $ .
  • [DateTime]::ParseExact - [DateTime]::ParseExact contents of the first exciting group ( $args[0].Groups[1].Value ) to the DateTime object in the format "MMyyyy", and .AddMonths(-1) subtracts 1, a .ToString("MMyyyy") converts the date to string again.

Test:

enter image description here