Files
hfbackup/BackupFolder.ps1
2025-12-15 03:00:11 +03:00

289 lines
10 KiB
PowerShell

# 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
}