$ErrorActionPreference='Stop' $source=Read-Host 'Folder źródłowy (pełna ścieżka)' if(-not (Test-Path -LiteralPath $source -PathType Container)){throw 'Nie znaleziono źródła.'} $default=Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'Posegregowane' $target=Read-Host "Folder docelowy [Enter: $default]" if(-not $target.Trim()){$target=$default} $source=(Resolve-Path -LiteralPath $source).Path.TrimEnd('\') $target=[IO.Path]::GetFullPath([Environment]::ExpandEnvironmentVariables($target)).TrimEnd('\') if($source -eq $target){throw 'Źródło i cel nie mogą być identyczne.'} Write-Host 'Daty wg ostatniej modyfikacji, włącznie z datą końcową.' $f=Read-Host 'Od daty RRRR-MM-DD [Enter: bez ograniczenia]' $t=Read-Host 'Do daty RRRR-MM-DD [Enter: bez ograniczenia]' $culture=[Globalization.CultureInfo]::InvariantCulture $from=[datetime]::MinValue;$to=[datetime]::MaxValue if($f.Trim()){if(-not [datetime]::TryParseExact($f,'yyyy-MM-dd',$culture,[Globalization.DateTimeStyles]::None,[ref]$from)){throw 'Błędna data od.'}} if($t.Trim()){if(-not [datetime]::TryParseExact($t,'yyyy-MM-dd',$culture,[Globalization.DateTimeStyles]::None,[ref]$to)){throw 'Błędna data do.'};$to=$to.AddDays(1)} if($to -le $from){throw 'Zakres dat jest pusty.'} $ex=Read-Host 'Rozszerzenia bez kropek, po przecinku (np. jpg,png,pdf) [Enter: wszystkie]' $allowed=@();if($ex.Trim()){$allowed=@($ex.Split(',') | ForEach-Object {$_.Trim().TrimStart('.').ToLowerInvariant()} | Where-Object {$_})} $mode=Read-Host 'Kopia czy przeniesienie? [K/P, domyślnie K]' $move=($mode -match '^[Pp]') $groups=@{'.jpg'='Zdjecia';'.jpeg'='Zdjecia';'.png'='Zdjecia';'.heic'='Zdjecia';'.webp'='Zdjecia';'.gif'='Zdjecia';'.dng'='Zdjecia';'.mp4'='Wideo';'.mkv'='Wideo';'.avi'='Wideo';'.mov'='Wideo';'.webm'='Wideo';'.mp3'='Audio';'.flac'='Audio';'.wav'='Audio';'.ogg'='Audio';'.m4a'='Audio';'.pdf'='Dokumenty';'.docx'='Dokumenty';'.xlsx'='Dokumenty';'.doc'='Dokumenty';'.txt'='Dokumenty';'.csv'='Dokumenty';'.zip'='Archiwa';'.7z'='Archiwa';'.rar'='Archiwa';'.html'='Kod';'.js'='Kod';'.css'='Kod';'.ps1'='Kod';'.bat'='Kod';'.py'='Kod'} $files=@(Get-ChildItem -LiteralPath $source -File -Recurse -ErrorAction SilentlyContinue | Where-Object { -not ($_.Attributes -band [IO.FileAttributes]::ReparsePoint) -and $_.LastWriteTime -ge $from -and $_.LastWriteTime -lt $to -and (-not $allowed.Count -or $allowed -contains $_.Extension.TrimStart('.').ToLowerInvariant()) -and -not $_.FullName.StartsWith($target+'\',[StringComparison]::OrdinalIgnoreCase) }) Write-Host "Znaleziono $($files.Count) plików. Tryb: $(if($move){'PRZENOSZENIE'}else{'KOPIOWANIE'})." -ForegroundColor Green $files | Select-Object -First 30 FullName,LastWriteTime | Format-Table -AutoSize if($files.Count -gt 30){Write-Host 'Wyświetlono pierwsze 30.'} if(-not $files.Count){return} if((Read-Host 'Wpisz WYKONAJ, aby rozpocząć') -cne 'WYKONAJ'){return} [int]$n=0 foreach($item in $files){ try{ $group='Inne';if($groups.ContainsKey($item.Extension.ToLowerInvariant())){$group=$groups[$item.Extension.ToLowerInvariant()]} $dir=Join-Path (Join-Path $target $group) $item.LastWriteTime.ToString('yyyy-MM') New-Item -ItemType Directory -Force -Path $dir | Out-Null $dst=Join-Path $dir $item.Name;$i=1 while(Test-Path -LiteralPath $dst){$dst=Join-Path $dir ($item.BaseName+' ('+$i+')'+$item.Extension);$i++} if($move){Move-Item -LiteralPath $item.FullName -Destination $dst -ErrorAction Stop}else{Copy-Item -LiteralPath $item.FullName -Destination $dst -ErrorAction Stop} $n++ }catch{Write-Warning ("Niepowodzenie: "+$item.FullName+" — "+$_.Exception.Message)} } Write-Host "Gotowe: $n / $($files.Count) plików. Cel: $target" -ForegroundColor Green