3

I have a large document library stored on a Sharepoint server which has been migrated over from an old Access database, versioning of these documents was controlled by the user and appended at the end of the file name when changes were made.

e.g.

  1. Doc1-test(1.0).doc
  2. Doc1-test(1.1).doc
  3. Doc2-example(2.1).doc
  4. Doc2-example(2.2).doc

We are now using Sharepoint to control versioning and need to delete the version that is in the file name.

I have had moderate success with the following script;

gi * | % { rni $_ ($_.Name -replace '(1.0)', '') }

but I cannot get it to delete the brackets from the file name. So in my testing directory the files changed to the following

Doc1-doc(1.0).doc ----- Doc1-doc().doc

Numbers range from 1.0 to around 4.5, and there are over 1200 documents, so I don't mind having to use an individual script for each version number.

2
  • Do you just want to remove 5 characters from the file name? Like 'Doc1-doc(1.0).doc' becomes 'Doc1-doc.doc' ? Is the user-appended version number always 5 characters '(x.x)'?
    – Junkiebev
    Apr 7, 2015 at 12:10
  • For the vast majority of files yes, but there are some within the directory where this wouldn't work. e.g.there are some "templates" that don't have version numbers and do not require changing. All I'm really looking to do is remove the brackets and anything within them.
    – StewartM
    Apr 7, 2015 at 12:54

2 Answers 2

5

The problem you're running into is that PowerShell's -replace uses Regular Expressions for searching.

This means that the brackets (()) in your search query are being interpreted as a RegEx capture group.

In this case, you want to reference them as literal characters, so you need to escape the brackets. In RegEx, this is done with a backslash (\).

So -replace '\(1.0\)','' should do it.

Since you are using RegEx, you can take advantage of it and do them all at once by specifying a "number" character class or "set" of characters instead of an actual version numbers, as your search pattern

So something like:

gi * | % { rni $_ ($_.Name -replace '\(1.[0-9]\)', '') }

Will remove (1.<any number from 0 to 9>) from the file names.

If you want to remove the brackets and anything in between them you can use the "any character (.) any amount of times (*)" RegEx pattern:

ie: -replace '\(.*\)',''

Note: RegEx can surprise you (think outer and inner brackets in a single file name, in this scenario), so make backups of your files and run tests first. :)

1
  • 1
    Thanks! That worked, now using gi * | % { rni $_ ($_.Name -replace '\([0-9].[0-9]\)', '') }
    – StewartM
    Apr 7, 2015 at 14:19
2

but I cannot get it to delete the brackets from the file name. So in my testing directory the files changed to the following

Doc1-doc(1.0).doc ----- Doc1-doc().doc

This is because replace uses regex and parentheses (capturing group) should be escaped. The easiest way to escape all text is to use [regex]::Escape method:

gi * | % { rni $_ ($_.Name -replace [regex]::Escape('(1.0)'), '') }

Note, that just removing everything in parentheses will create conflicts for files such as Doc1-test(1.1).doc and Doc1-test(1.0).doc - they both will be mapped to Doc1-test.doc.

Here is my version with regex that will match only dot-separated digits inside parentheses at the end of the filename without extension. I don't handle filename conflicts in this code, because I don't know your desired result.

# Get all objects in current directory that match wildcard: *(*.*).doc
Get-ChildItem -Path '.\' -Filter '*(*.*).doc' |
    # Skip folders, because XXX(1.1).doc is a valid folder name
    Where-Object {!$_.PSIsContainer} |
        # For each file
        ForEach-Object {
            # New file name = 
            # File Directory + (File name w\o extension with regex pattern (\(\d+\.\d+\))$ replaced with empty string) + File extension

            # Note, that it will create confilcts for files such as Doc1-test(1.1).doc and Doc1-test(1.0).doc,
            # both of them will end with name Doc1-test.doc
            $NewFileName = Join-Path -Path $_.DirectoryName -ChildPath (($_.BaseName -replace '(\(\d+\.\d+\))$', [string]::Empty) + $_.Extension)

            # Basic logging
            Write-Host "Renaming: $($_.FullName) -> $NewFileName"

            # Rename file.
            Rename-Item -Path $_.FullName -NewName $NewFileName
        }

Explanation of the regex (\(\d+\.\d+\))$

1st Capturing group (\(\d+\.\d+\))

\( matches the character ( literally

\d+ match a digit [0-9]
Quantifier: + Between one and unlimited times,
as many times as possible, giving back as needed [greedy]

\. matches the character . literally

\d+ match a digit [0-9]
Quantifier: + Between one and unlimited times,
as many times as possible, giving back as needed [greedy]

\) matches the character ) literally

$ assert position at end of the string
1
  • Yeah my examples weren't the clearest, I forgot to mention that I've already removed all duplicates and only uploaded the most recent versions of each file. So when I run the script it will only remove the brackets and number, so there won't be any dupes. Thanks for the help!
    – StewartM
    Apr 7, 2015 at 14:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .