سكريبت Powershell لمسؤول النظام لتنزيل النسخ الاحتياطية بانتظام من الخادم إلى الكمبيوتر

في الآونة الأخيرة، واجهت صديقتي مشكلة مزود خدمة الخادم الافتراضي الخاص (VPS) الذي أفلس فجأة دون سابق إنذار. للأسف، من أجل التوفير، اختارت مزودًا غير معروف - لم يكن يقدم حتى تنزيل البيانات. والأسوأ من ذلك أنها لا تملك عادة تنزيل النسخ الاحتياطية بانتظام. بين عشية وضحاها، اختفى موقعها، إلى جانب جميع البيانات الموجودة عليه.

صُدمت من هذا، كتبت برنامج PowerShell نصي يقوم بتنزيل النسخ الاحتياطية تلقائيًا من خادمك إلى جهاز الكمبيوتر المحلي الخاص بك بانتظام دون الحاجة إلى شراء أي خدمات تخزين إضافية أو إنفاق فلس واحد على أشياء أخرى. كل ما تحتاجه هو جهاز كمبيوتر يعمل بنظام Windows تستخدمه بانتظام (ولديه مساحة كافية على القرص الصلب) ومتصل بالإنترنت.

سيقوم البرنامج النصي تلقائيًا بتنظيف النسخ الاحتياطية من 5 أيام مضت. يمكنك تعيين فاصل النسخ الاحتياطي التلقائي وأقدم وقت للنسخ الاحتياطي محفوظ محليًا وفقًا لاحتياجاتك.


$ssh_port = 22
$ssh_address = "username@your.site"


Write-Output "Starting Discourse backup download task..."
Write-Output '------------------------'
Write-Output "Fetching the latest backup file..."
Write-Output ''

while ($true) {

    $filename = ''

    while ($true) {
        try {
            Write-Output "> ssh -p $ssh_port $ssh_address 'cd /var/discourse/shared/standalone/backups/default/ & ls -t | head -n 1'"
            Write-Output ''
            $filename = ssh -p $ssh_port "$ssh_address" 'cd /var/discourse/shared/standalone/backups/default/ & ls -t | head -n 1'
            break
        }
        catch {
            $filename = ''
    
            Write-Output "Failed to fetch... Here is the log:"
            Write-Output '-------------'
            Write-Output $_
            
            $answer = Read-Host "Do you want to re-fetch? (y/N)"
            if ($answer -ne 'y') {
                break
            }
            Write-Output ''
        }
    }
    
    
    if ([String]::IsNullOrEmpty($filename)) {
        Write-Output "Error: Failed to fetch file name $filename"
        Write-Output ''
        $answer = Read-Host 'Retry?(y/N)'
  
        if ($answer -eq 'y') {
  
        }
        else {
      
            exit 1
        }
  
    }
    else {

        Write-Output "Latest backup: $filename"
        Write-Output ''
        
        $need_download = $true
        if (Test-Path ".\backups\$filename") {
            $answer = Read-Host ".\backups\$filename already exists. Do you want to download it again?(y/N)"
            Write-Output ''
            if ($answer -ne 'y') {
                $need_download = $false
            }
        }
        if ($need_download) {
            Write-Output "Start downloading..."
            Write-Output ''
            
            while ($true) {
                try {
                    Write-Output "scp -p $ssh_port ${ssh_address}:/var/discourse/shared/standalone/backups/default/$filename .\\backups\\"
                    Write-Output ''

                    scp -p $ssh_port "${ssh_address}:/var/discourse/shared/standalone/backups/default/$filename" .\\backups\
                    
                    Write-Output "Download completed"
                    Write-Output ''
                    
                    break
                }
                catch {

                    Write-Output "Download failed >_<... The following is the log:"
                    Write-Output ''

                    Write-Output $_
                    
                    $answer = Read-Host "Download again? (y/N)"
                    Write-Output ''
                    if ($answer -ne 'y') {
                        break
                    }
                }
            }

        }
  
        Write-Output "Start trying to clean old backup files..."
        Write-Output ''

        $count = 0
        $backupfiles = Get-ChildItem -Path .\\backups\
  
        foreach ($file in $backupfiles) {
            if ($file.CreationTime -le (Get-Date).AddDays(-5)) {
                try {
                    Write-Output "Delete old backup file $file ..."
                    Write-Output ''
                    $file.Delete()
                    $count = $count + 1
                } catch {
                    Write-Output "An error occurred while deleting old backup file $file >_<"
                    Write-Output '-------------------'
                    Write-Output $_
                    Write-Output '-------------------'
                }
            }
        }

        if ($count -ge 0) {
            Write-Output "Cleaned $count old backup files"
            Write-Output ''
        }
        else {
            Write-Output 'No old backup files need to clean up'
            Write-Output ''
        }

        Pause
  
        exit 0
  
    }
  
  
}


احفظ البرنامج النصي أعلاه باسم scriptname.ps1 في المسار الذي ترغب في تنزيل النسخة الاحتياطية منه. جرب “تشغيل باستخدام PowerShell”. إذا نجح الأمر، يمكنك المتابعة إلى الخطوة التالية.

جدولة مهمة

  1. ابحث عن “المهام المجدولة”.
  2. انقر نقرًا مزدوجًا فوق “إضافة مهمة مجدولة”. يظهر معالج المهام المجدولة.
  3. انقر فوق “التالي”، ثم انقر فوق “استعراض”. يظهر مربع حوار “تحديد برنامج للجدولة”.
  4. انتقل إلى البرنامج النصي الذي أنشأته، وانقر عليه، ثم انقر فوق “فتح”. تعود إلى معالج المهام المجدولة.
  5. قم بتوفير اسم للمهمة، أو احتفظ بالاسم الافتراضي، وهو اسم الملف، وحدد عدد مرات تشغيل البرنامج النصي، ثم انقر فوق “التالي”.
  6. حدد وقت البدء والتاريخ (إذا حددت يوميًا، أسبوعيًا، شهريًا، إلخ) والتكرار، ثم انقر فوق “التالي”. يجب أن يتطابق هذا العنصر مع دورة النسخ الاحتياطي التلقائي لـ discourse الخاص بك
  7. اكتب اسم المستخدم وكلمة المرور للحساب الذي سيقوم بتشغيل البرنامج النصي، ثم انقر فوق “التالي”.
  8. إذا كنت ترغب في تكوين خصائص متقدمة، فحدد مربع الاختيار، ثم انقر فوق “إنهاء”.
15 إعجابًا

تذكير جيد بمدى أهمية وجود نسخ احتياطية عن بُعد. مستخدم آخر في ميتا عانى من نفس المشكلة قبل بضعة أشهر.

إحدى مثيلاتي تستخدم ميزة النسخ الاحتياطي المدمجة في S3، وتستخدم المثيلات الأخرى Rclone ومهمة CRON لإرسال النسخ الاحتياطية إلى Google Drive. يوجد دليل لذلك: Use rclone to sync backups to Dropbox or Google Drive

شكرًا لمشاركة النص البرمجي الخاص بك يا Linca :+1:

3 إعجابات

بالتأكيد تذكير جيد جدًا. لقد اقترحت بالفعل (هنا) أن تتحقق وظيفة التحديث وتحذر إذا كانت ملفات النسخ الاحتياطي تحتوي على أوقات آخر وصول بعيدة جدًا في الماضي. نقوم بالتحديث كل شهرين أو ثلاثة أشهر، لذلك لن يعمل هذا الفحص كثيرًا، ووقت التحديث هو وقت جيد للتأكد من وجود نسخة احتياطية آمنة. أي وسيلة لنسخ ملف النسخ الاحتياطي إلى مكان آخر يجب أن تحدث طابع آخر وصول.

3 إعجابات

نقطة جيدة، شكراً على السكربت. دعني أشارك إصدار rsync :slight_smile: .

في المثال أدناه، تتم مزامنة sql والمرفقات بشكل منفصل. لا حاجة لتضمين المرفقات في ملف النسخ الاحتياطي. لا حاجة لحذف النسخ الاحتياطية القديمة أيضاً.

أستخدم Chocolatey لتثبيت cwrsync. بعد التثبيت، ما عليك سوى إضافة بعض الأسطر في نهاية ملف cmd + إنشاء جدول زمني:

C:\ProgramData\chocolatey\lib\rsync\tools\cwrsync.cmd

على سبيل المثال:

rsync -rvm --delete --ignore-errors --ignore-existing --size-only --chmod=ugo=rwX -e "ssh -i /cygdrive/c/Users/user1/.ssh/id_rsa" login@host:/var/discourse/shared/standalone/backups/default/ /cygdrive/d/backup/forum/db/

rsync -rvm --delete --ignore-errors --ignore-existing --size-only --chmod=ugo=rwX -e "ssh -i /cygdrive/c/Users/user1/.ssh/id_rsa" login@host:/var/discourse/shared/standalone/uploads/ /cygdrive/d/backup/forum/uploads/

ملاحظة 1: استخدم /cygdrive/c/ بدلاً من C:، اقرأ ملف cmd للمرجع والصيغة.

ملاحظة 2: يمكنك تعديل الأمر لاستخدام كلمة مرور بدلاً من مفتاح ssh (تنسيق PEM)

ملاحظة 3: إذا لم تضع شرطة مائلة بعد مجلد dump/، فسيقوم rsync بنسخ المجلد، ولكن إذا فعلت ذلك، فسيقوم فقط بنسخ محتويات المجلد.

ملاحظة 4: إذا قام chocolatey بترقية cwrsync، فإنه ينشئ نسخة احتياطية من cmd السابقة في نفس المجلد. تحتاج إلى نسخ أوامرك إلى cmd الجديد يدوياً لمتابعة النسخ الاحتياطي.

هام: قم بتعيين نفس القاعدة في المجدول كما كتب OP. سطر المجدول هو:

C:\ProgramData\chocolatey\lib\rsync\tools\cwrsync.cmd >> d:\backup\cwrsync.txt 2>&1

سيقوم بإلحاق الإخراج بالملف cwrsync.txt. هذا كل شيء.

3 إعجابات

لدي عادة إعداد rclone لنسخ النسخ الاحتياطية تلقائيًا إلى جهاز بعيد (NAS مستضاف ذاتيًا في المنزل) بسبب جنون الارتياب بشأن هذا النوع من الأشياء الذي يحدث فجأة. هذه المشاركة بمثابة تذكير جيد بأنه لا ينبغي لنا وضع كل البيض في سلة واحدة.

5 إعجابات

في حين أنك في ذلك، يجب عليك أيضًا الحصول على نسخة من كل شيء في /var/discourse/containers.

4 إعجابات

فكرة جيدة! سيتم نشر تحديث

3 إعجابات

أين أبحث عن “المهام المجدولة”؟ (مبتدئ يطلب المساعدة، شكراً)

“المهام المجدولة” هي “جدولة المهام”، في نظام التشغيل ويندوز 10 والإصدارات الأحدث، يمكنك البحث عنها مباشرة بالضغط على مفتاح ويندوز وكتابة الاسم.

إعجابَين (2)

مرحباً. كيف أحصل على هذا الخطأ؟

لكل من يقرأ هذا، إليك تعليمات أفضل/أكثر حداثة نظرًا لأنني واجهت صعوبة طفيفة مع تعليمات OP:

  1. قم بإنشاء/استخدام مجلد حيث سيتم تخزين هذا البرنامج النصي. ثم، قم بإنشاء مجلد يسمى backup داخل هذا المجلد.

  2. انسخ/الصق البرنامج النصي في المفكرة. ملاحظة: إذا كنت تستخدم VPS، فاستخدم اسم مستخدم VPS الخاص بك وعنوان IP العام لسطر $ssh_address = \"username@your.site\". احفظ باسم anyname.ps1 ولا تنسَ تعيين القائمة المنسدلة إلى “كافة الملفات”، كما هو موضح أدناه.
    hhhh

  3. اضغط على مفتاح Windows ⊞ واكتب “Tasks”، ثم انقر فوق “Task Scheduler”.

  4. على الجانب الأيمن، انقر فوق “Create basic task”.

  5. أعطِ أي اسم/وصف.

  6. اختر ما إذا كنت تريد يوميًا/أسبوعيًا/سنويًا/إلخ. أوصي بيومي.

  7. قم بتعيين التاريخ والوقت الذي تريد القيام بذلك فيه. احتفظ بـ Recur عند 1. تأكد من الانتقال إلى إعدادات المسؤول لموقع Discourse الخاص بك > Backups. حدد المربع بجوار automatic backups enabled.
    ثم، قم بتعيين backup frequency إلى ما تريده. أوصي بـ 1 ولكن المفتاح هنا هو جعله يتطابق مع إعدادات Task Scheduler الخاصة بك. اجعل تواريخ النسخ الاحتياطي متطابقة. مثال: إذا قمت بتعيين Task Scheduler للنسخ الاحتياطي يوميًا، فقم بتعيين إعدادات backup frequency للنسخ الاحتياطي للمسؤول إلى 1.

  8. اترك الإعداد الافتراضي على “start a program” وانقر فوق Next.

  9. انقر فوق Browse وابحث عن البرنامج النصي الذي حفظته. انقر فوق Next.

  10. انقر فوق Finish.
    إذا كنت تريد اختباره، فانقر بزر الماوس الأيمن على البرنامج النصي واختر “Run with Powershell”.

ملاحظة: إذا حصلت على “the system cannot find the file specified”، فأدخل كلمة المرور الخاصة بك كما هو موضح في PowerShell وسيعثر عليها على أي حال.

إعجاب واحد (1)

عندما قمت بحفظ البرنامج النصي لـ PS (فقط قمت بتحرير اسم المستخدم وعنوان IP الخاص بي في السطر الثاني)، ثم نقرت بزر الماوس الأيمن واخترت “تشغيل باستخدام PowerShell”، فلن يحدث شيء.
يحدث وميض. وإذا كان لدي طرفية مفتوحة بالفعل في نظام التشغيل Windows 11 الخاص بي، فسيتم جلب تلك الطرفية إلى المقدمة. لا شيء آخر. مجرد وميض.

كنت أتساءل، على الرغم من أنني أعطيت اسم المستخدم وعنوان IP الخاص بي للبرنامج النصي، كيف سيستخدم مفتاح SSH الخاص بي لتسجيل الدخول وسحب النسخة الاحتياطية؟

شكرا.!

لقد جربت كلاً من OP وحل 45thj5ej وكلاهما لم ينجح معي. عند تشغيل البرنامج النصي باستخدام Powershell، لن يتم العثور على “/backups/” وعنصر الطفل. أيضًا، لا يمكنني العثور على المكان الذي يقصد فيه OP إدخال اسم المستخدم وكلمة المرور. أقوم بتشغيل Discourse على VPS.