# BackupFolder.ps1 # Script to backup and compress folders from Windows context menu param( [Parameter(Mandatory=$true)] [string]$FolderPath ) # Function to show message function Show-Message { param( [string]$Message, [string]$Title = "Klasör Yedekleme", [int]$Type = 0 # 0=Info, 1=Error, 2=Warning ) switch ($Type) { 0 { $icon = 64 } # Information 1 { $icon = 16 } # Error 2 { $icon = 48 } # Warning default { $icon = 64 } } [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null [System.Windows.Forms.MessageBox]::Show($Message, $Title, 0, $icon) | Out-Null } # Function to show confirmation dialog with Yes/No options function Show-Confirmation { param( [string]$Message, [string]$Title = "Klasör Yedekleme" ) [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null $result = [System.Windows.Forms.MessageBox]::Show($Message, $Title, 4, 64) # 4 = YesNo buttons, 64 = Information icon return ($result -eq "Yes") } # Function to show advanced options dialog function Show-AdvancedOptions { param( [string]$Message, [string]$Title = "Geliştirme Klasörleri Bulundu" ) # Create a form with custom buttons Add-Type -AssemblyName System.Windows.Forms $form = New-Object System.Windows.Forms.Form $form.Text = $Title $form.Size = New-Object System.Drawing.Size(400, 200) $form.StartPosition = "CenterScreen" $form.FormBorderStyle = "FixedDialog" $form.Topmost = $true # Add label with message $label = New-Object System.Windows.Forms.Label $label.Location = New-Object System.Drawing.Point(10, 20) $label.Size = New-Object System.Drawing.Size(360, 80) $label.Text = $Message $label.Font = New-Object System.Drawing.Font("Microsoft Sans Serif", 9) $form.Controls.Add($label) # Add "Include All" button $buttonIncludeAll = New-Object System.Windows.Forms.Button $buttonIncludeAll.Location = New-Object System.Drawing.Point(10, 120) $buttonIncludeAll.Size = New-Object System.Drawing.Size(100, 30) $buttonIncludeAll.Text = "Tümünü Dahil Et" $buttonIncludeAll.DialogResult = "OK" $form.Controls.Add($buttonIncludeAll) # Add "Skip Dev Folders" button $buttonSkip = New-Object System.Windows.Forms.Button $buttonSkip.Location = New-Object System.Drawing.Point(120, 120) $buttonSkip.Size = New-Object System.Drawing.Size(120, 30) $buttonSkip.Text = "Dev Klasörleri Atla" $buttonSkip.DialogResult = "Yes" $form.Controls.Add($buttonSkip) # Add "Cancel" button $buttonCancel = New-Object System.Windows.Forms.Button $buttonCancel.Location = New-Object System.Drawing.Point(250, 120) $buttonCancel.Size = New-Object System.Drawing.Size(100, 30) $buttonCancel.Text = "İptal" $buttonCancel.DialogResult = "No" $form.Controls.Add($buttonCancel) # Set default button $form.AcceptButton = $buttonIncludeAll $form.CancelButton = $buttonCancel # Show dialog and return result $result = $form.ShowDialog() return $result } # Check if folder exists if (-not (Test-Path $FolderPath)) { Show-Message -Message "Belirtilen klasör mevcut değil: $FolderPath" -Type 1 exit 1 } # Define common development folders that should be excluded $ExcludedFolders = @("node_modules", "vendor", "build", "dist", ".git", ".svn", "bin", "obj") # Check if the folder contains any development directories $HasDevFolders = $false $FoundDevFolders = @() $SkipDevFolders = $false foreach ($excludedFolder in $ExcludedFolders) { $devFolderPath = Join-Path $FolderPath $excludedFolder if (Test-Path $devFolderPath) { $HasDevFolders = $true $FoundDevFolders += $excludedFolder } } # If development folders are found, prompt user for action if ($HasDevFolders) { $folderList = ($FoundDevFolders -join ", ") $message = "Bu klasör aşağıdaki geliştirme klasörlerini içeriyor:`n$folderList`n`nBu klasörleri yedeklemeye ne yapmak istersiniz?" $userChoice = Show-AdvancedOptions -Message $message -Title "Geliştirme Klasörleri Bulundu" switch ($userChoice) { "No" { # Cancel backup Show-Message -Message "Yedekleme iptal edildi." -Type 2 exit 0 } "Yes" { # Skip dev folders $SkipDevFolders = $true } "OK" { # Include all folders - continue normally } default { # Cancel backup for any other response Show-Message -Message "Yedekleme iptal edildi." -Type 2 exit 0 } } } # Get folder name $FolderName = Split-Path $FolderPath -Leaf # Get current date in YYYYMMDD format $Date = Get-Date -Format "yyyyMMdd" # Determine output directory (same as source folder) $OutputDir = Split-Path $FolderPath -Parent # Find existing backups with same name and date to determine next number $Pattern = "^${FolderName}_${Date}_\d{3}\.(rar|zip)$" $ExistingBackups = Get-ChildItem -Path $OutputDir -Filter "${FolderName}_${Date}_*" | Where-Object { $_.Name -match $Pattern } $NextNumber = 1 if ($ExistingBackups) { $Numbers = $ExistingBackups.Name | ForEach-Object { if ($_ -match "_([0-9]{3})\.(rar|zip)$") { [int]$matches[1] } } | Sort-Object if ($Numbers) { $NextNumber = ($Numbers | Select-Object -Last 1) + 1 } } $NumberFormatted = "{0:D3}" -f $NextNumber # Try WinRAR first $WinRarPath = "${env:ProgramFiles}\WinRAR\rar.exe" $UseWinRar = Test-Path $WinRarPath # If WinRAR not found, try 7-Zip $SevenZipPath = "${env:ProgramFiles}\7-Zip\7z.exe" $UseSevenZip = Test-Path $SevenZipPath # If neither found, use PowerShell Compress-Archive $UsePowerShellArchive = -not ($UseWinRar -or $UseSevenZip) # Create backup filename if ($UseWinRar) { $OutputFile = Join-Path $OutputDir "${FolderName}_${Date}_${NumberFormatted}.rar" } else { $OutputFile = Join-Path $OutputDir "${FolderName}_${Date}_${NumberFormatted}.zip" } try { if ($UseWinRar -and -not $SkipDevFolders) { # Use WinRAR (full backup) # Change to the parent directory and use relative path to avoid full path in archive Push-Location $OutputDir try { $Arguments = "a -r `"$OutputFile`" `".\$FolderName`"" Start-Process -FilePath $WinRarPath -ArgumentList $Arguments -Wait -NoNewWindow } finally { Pop-Location } } elseif ($UseWinRar -and $SkipDevFolders) { # Use WinRAR with exclusion patterns Push-Location $OutputDir try { # Build exclusion arguments for each dev folder $ExcludeArgs = "" foreach ($excludedFolder in $ExcludedFolders) { $ExcludeArgs += " -x`".\$FolderName\$excludedFolder\*`"" } $Arguments = "a -r $ExcludeArgs `"$OutputFile`" `".\$FolderName`"" Start-Process -FilePath $WinRarPath -ArgumentList $Arguments -Wait -NoNewWindow } finally { Pop-Location } } elseif ($UseSevenZip -and -not $SkipDevFolders) { # Use 7-Zip (full backup) # Change to the parent directory and use relative path to avoid full path in archive Push-Location $OutputDir try { $Arguments = "a `"$OutputFile`" `".\$FolderName`"" Start-Process -FilePath $SevenZipPath -ArgumentList $Arguments -Wait -NoNewWindow } finally { Pop-Location } } elseif ($UseSevenZip -and $SkipDevFolders) { # Use 7-Zip with exclusion patterns Push-Location $OutputDir try { # Build exclusion arguments for each dev folder $ExcludeArgs = "" foreach ($excludedFolder in $ExcludedFolders) { $ExcludeArgs += " -x!$FolderName\$excludedFolder\*" } $Arguments = "a $ExcludeArgs `"$OutputFile`" `".\$FolderName`"" Start-Process -FilePath $SevenZipPath -ArgumentList $Arguments -Wait -NoNewWindow } finally { Pop-Location } } else { # Use PowerShell built-in Compress-Archive # Fix the path issue by changing to the parent directory and using relative path Push-Location $OutputDir try { if ($SkipDevFolders) { # For PowerShell, we need to manually filter out dev folders # Get all items except the excluded ones $ItemsToCompress = Get-ChildItem -Path ".\$FolderName" -Recurse | Where-Object { $itemPath = $_.FullName.Substring((Resolve-Path ".\$FolderName").Path.Length) $shouldExclude = $false foreach ($excludedFolder in $ExcludedFolders) { if ($itemPath -like "\$excludedFolder*" -or $itemPath -like "*\$excludedFolder*" -or $itemPath -like "*\$excludedFolder\*") { $shouldExclude = $true break } } -not $shouldExclude } if ($ItemsToCompress) { Compress-Archive -Path $ItemsToCompress.FullName -DestinationPath $OutputFile -Force } else { # If no items left after filtering, create an empty archive with just the folder structure Compress-Archive -Path ".\$FolderName" -DestinationPath $OutputFile -Force # Then remove the dev folders from the archive (this is complex, so we'll just warn the user) Show-Message -Message "NOT: PowerShell ile dev klasörlerini atlamak tam olarak mümkün değildir. Tüm klasörler yedeklendi.`n`nGelecek sürümlerde bu özellik WinRAR veya 7-Zip ile daha iyi çalışacaktır." -Type 2 } } else { Compress-Archive -Path ".\$FolderName" -DestinationPath $OutputFile -Force } } finally { Pop-Location } } Show-Message -Message "Yedekleme başarıyla tamamlandı!`n`nDosya: $OutputFile" } catch { Show-Message -Message "Yedekleme sırasında hata oluştu:`n$($_.Exception.Message)" -Type 1 }