Казалось бы, что может быть проще - запускаем cmd.eхe и пользуемся командой ren (rename).

Попытка 1:
ren *.* *.*.ext

Результат:
filename => filename..ext
filename.aaa => filename.aaa.ext
filename.aaa.aaa => filename.aaa.aaa.ext

Как видно из примера, файлы не имевшие раширения, получили лишнюю точку.

Попытка 2:
ren * *.ext

Результат:
filename => filename.ext
filename.aaa => filename.ext (ошибка - файл уже существует)
filename.aaa.aaa => filename.aaa.ext

Снова проблема - для файлов с расширением, новое расширение не добавляется, а заменяется.

Попытка 3:
ren *? *.*.ext

Результат:
см. попытку 1

Попытка 4:
ren *? *.ext

Результат:
см. попытку 2

Попытка 5:
ren *? *?.ext

Результат:
filename => filename.ext
filename.aaa => filename.ааа.ext
filename.aaa.aaa => filename.aaa.ааа.ext

Ура! Работает!
Контрольный выстрел:
.aaa => .aaa.eхt

Аналогичная ситуация будет наблюдаться и для команд dir, del, copy, move и т.д. В чем причина столь причудливого поведения утилит командной строки? Утверждается, что корни проблемы уходят в прошлое чуть ли не на 25 лет назад во времена DOSа и его прородителя QDOSа, а кажущаяся текущая непредсказуемость толкования символов * и ? связанна с необходимостью обеспечивать обратную совместимость с некими древними приложениями командной строки.

Кстати, в проблеме с переименованиями существует еще и потенциальная возможность коллизии при добавлении разрешения (просто замените в нашем примере eхt на aaa) - так что если в вашем приложении нужна железная гарантия успешного переименования - прийдется писать код для выбора правильной последовательности переименований самостоятельно. (Думаю, будет достаточно просто упорядочить файлы по убыванию длины).