PowerShell: Перемешиваем файлы

в 13:55, , рубрики: powershell, Песочница, метки:

Доброго времени суток, читатель!
Недавно мне подкинули довольно простенькую на первый взгляд задачку: Надо перемешать около 1000 фотографий для системы голосований.
Вручную заниматься этим — дело неблагодарное. Нужен какой-нибудь миленький скрипт.
PowerShell оказался идеальным вариантом: ставить что-то стороннее вроде python не хотелось, а с .bat файлами я за свою жизнь так и не подружился.

Пожалуй начнем.
Названия фотографий были важны и их хотелось сохранить. Я решил убрать их в свойства файла («Сводка» для WinXp, «Подробно» для Win7). Тем более голосовалка написана на sharepoint, а он умеет подхватывать «Название» из свойств файла. Оказалось очень удобно.
Для редактирования свойств файла был использован компонент OLE File Property Reader 2.1 (В папке с примерами vb7 есть обертка библиотеки для .net), благо уже был установлен на машине. Компонент предназначен для офисных документов, но и для картинок подошел.

Собственно скрипт:

[System.Reflection.Assembly]::LoadFrom('c:DsoFileSourceVb7DemobinInterop.DSOFile.dll')
function SetSummary-Name([string] $folder, [string]$pattern = '*.*')
{
    $files = [System.IO.Directory]::GetFiles($folder, $pattern)
    
    foreach ($f in $files)
    {
        $oled = New-Object -TypeName DSOFile.OleDocumentPropertiesClass
        $oled.Open($f, $false, [DSOFile.dsoFileOpenOptions]::dsoOptionDefault)
        $sp =  $oled.SummaryProperties
        
        $sp.Title = $f.Substring($f.lastindexof('') + 1, $f.lastindexof('.') - $f.lastindexof('') - 1)
        
        $oled.close($true)
    }
}

SetSummary-Name -folder 'c:photo'

Далее перейдем к перемешиванию:
Можно было генерировать числовые имена, но вдруг очень сильно захотелось изобрести велосипед сложной конструкции.

# Заменяет имя файла на произвольный набор букв
function RandomName([string]$path)
{
    $length = 20 # длинна нового имени
    $sb = New-Object -TypeName System.Text.StringBuilder
    
    for($i=0; $i -lt $length; $i++)
    {
        # Тут меня отпустило, велосипед удался...
        [char]$ch = [Convert]::ToChar([Convert]::ToInt32([Math]::Floor(26 * $rand.NextDouble() + 65)))
        $tmp = $sb.Append($ch) # Append возвращает ненужную нам информацию, выкидываем ее в $tmp
    }
    
    $name = $path.Substring($path.lastindexof('') + 1, $path.lastindexof('.') - $path.lastindexof('') - 1)
    $sb = $sb.ToString().ToLower()
    return $path.Replace($name, $sb)
}

function MixFiles([string]$From, [string]$pattern = '*.*')
{
    $files = [System.IO.Directory]::GetFiles($from, $pattern)
    
    foreach($f in $files)
    {
        $path = RandomName -path $f
        
        # На всякий случай проверим, 
        while([System.IO.File]::Exists($path))
        {
            # Чтобы знать, если такое случится
            $path
            $path = RandomName -path $f
        }
        
        # Для красоты покажем старые и новые имена
        Write-Host ($f +  ' -> ' + $path)
        
        [System.IO.File]::Move($f, $path)
    }
}

$rand = New-Object -TypeName Random
MixFiles -from 'c:test' -pattern '*.jpg'

Спасибо за внимание, надеюсь буду кому-нибудь полезен.

Автор: Halflling


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js