1

I am trying to extract two words from filenames. The names have the format:

__XXXXXXXX_XXX_XXXXXXX_XXXX_XXXXX_XXXX XXX_Aircraft 017_XXXXXXXX-XXXXXXX_XXXXXXX-XXXXXXX-XXXXXX-01Apr2021-XXXXX

With the X's being replaced with different words. I need to extract the aircraft number and the date so that I can rename the files with just that information. Using help from this site I have tried the following to isolate the aircraft number:

$names = gci -Path "H:\Path\to\Logs" *.log -Recurse | select @{n="Name"; e={if ($_.Name -match "Aircraft (\w+)") { 
  $matches[1] }}}

However, it doesn't seem to give me the match I need. However, I am very inexpert in programming and may be going down the wrong path. My hope is that the same logic used to isolate the aircraft number also applies for the date.

Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • Based on your example you would like to extract __Aircraft 017__ or just __017__ and __01Apr2021__ correct? – Santiago Squarzon Jul 27 '21 at 15:34
  • Aircraft 017 would be preferable to just 017, but either works. – Chris Clement Jul 27 '21 at 15:42
  • you are testing to see if the entire `.Name` matches your pattern. that will give you the WHOLE `.Name` when it finds a match. if you want only part of the item, you will need to split it and then grab the part you want. – Lee_Dailey Jul 27 '21 at 15:48
  • How do I split it and grab that part? I have only about a month of light powershell experience. – Chris Clement Jul 27 '21 at 15:56
  • You're already grabbing _one_ part of interest, and accessing it via `$Matches[1]`; you simply need to extend the regex to also grab the other, and access that via `$Matches[2]`, as shown in my answer. – mklement0 Jul 27 '21 at 16:06

1 Answers1

2
# Create a sample file.
$file = New-Item '__XXXXXXXX_XXX_XXXXXXX_XXXX_XXXXX_XXXX XXX_Aircraft 017_XXXXXXXX-XXXXXXX_XXXXXXX-XXXXXXX-XXXXXX-01Apr2021-XXXXX'

# Substitute your `Get-ChildItem` command for $file
$file |
 Rename-Item -WhatIf -NewName {
   if ($_.Name -match '_(Aircraft \w+?)_.+(\d{2}[a-z]{3}\d{4})-') {
     # Synthesize the new file name from the extracted substrings.
     '{0} - {1}' -f $Matches[1], $Matches[2]
   } else {
     # Input file name didn't match, (effectively) do nothing.
     $_.Name
   }
 }

Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.

For an explanation of the regex used with the -match operator above, see this regex101.com page.[1]

The above uses two capture groups ((...)) to capture the substrings of interest, which can be accessed via indices 1 and 2 of the automatic $Matches variable.

-f, the format operator is then used to build the output file name from the captured substrings. Tweak the LHS format string as needed.

Thanks to -WhatIf, you'll see output such as the following, which is the preview of what would happen when you remove -WhatIf - note the new file name in the Destination: path:

What if: Performing the operation "Rename File" on target 
"Item: /tmp/__XXXXXXXX_XXX_XXXXXXX_XXXX_XXXXX_XXXX XXX_Aircraft 017_XXXXXXXX-XXXXXXX_XXXXXXX-XXXXXXX-XXXXXX-01Apr2021-XXXXX
Destination: /tmp/Aircraft 017 - 01Apr2021".

Note how a script block ({ ... }) is passed as an argument to Rename-Item's -NewName parameter, which then acts on each input file via the automatic automatic $_ variable and outputs the argument value to use for the input object at hand. Such script blocks are called delay-bind script blocks.


[1] Note that even though regex101.com, a site for visualizing, explaining and experimenting with regexes, doesn't support the .NET regex engine used by PowerShell, choosing a similar engine, such as Java's, usually exhibits the same behavior, at least fundamentally.

mklement0
  • 382,024
  • 64
  • 607
  • 775