<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Automation on kenji.blog</title><link>http://kenji.blog/ar/tags/automation/</link><description>Recent content in Automation on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ar</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 06:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ar/tags/automation/index.xml" rel="self" type="application/rss+xml"/><item><title>أمثلة عملية على أتمتة المهام اليومية الروتينية بالكامل باستخدام برامج PowerShell النصية</title><link>http://kenji.blog/ar/p/powershell-daily-task-automation-scripts/</link><pubDate>Sun, 13 Sep 2026 06:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/powershell-daily-task-automation-scripts/</guid><description>&lt;img src="http://kenji.blog/p/powershell-daily-task-automation-scripts/img/eyecatch.jpg" alt="Featured image of post أمثلة عملية على أتمتة المهام اليومية الروتينية بالكامل باستخدام برامج PowerShell النصية" />&lt;h2 id="مقدمة-لماذا-نستخدم-powershell-لأتمتة-المهام">مقدمة: لماذا نستخدم PowerShell لأتمتة المهام
&lt;/h2>&lt;p>في البنى التحتية لتكنولوجيا المعلومات وبيئات التطوير الحديثة، تُعد &amp;ldquo;المهام اليومية الروتينية&amp;rdquo; تحديًا لا مفر منه للمستخدمين الذين يعتمدون على نظام التشغيل Windows كمنصة أساسية. القيام بهذه المهام يدويًا، مثل النسخ الاحتياطي للملفات، ومراقبة سجلات النظام، وتحديث وبناء موارد التطوير (مستودعات Git)، يُعد بيئة خصبة للأخطاء البشرية ويؤدي إلى إهدار وقت ثمين.&lt;/p>
&lt;p>في الماضي، كانت تُستخدم الملفات الدفعية (&lt;code>.bat&lt;/code> أو &lt;code>.cmd&lt;/code>) أو VBScript، ولكن في الوقت الحاضر، الحل الأمثل بلا شك هو &lt;strong>PowerShell&lt;/strong>. لا يُعد PowerShell مجرد غلاف (shell) يعتمد على النصوص، بل هو مبني على أساس متين موجه للكائنات في إطار عمل .NET Framework (و .NET Core). نظرًا لأن البيانات التي يتم تمريرها عبر خط الأنابيب (pipeline) ليست &amp;ldquo;سلاسل نصية&amp;rdquo; بل &amp;ldquo;كائنات&amp;rdquo;، فلا توجد حاجة لتنفيذ تحليلات نصية معقدة (مثل عمليات grep أو awk أو sed) بنفسك؛ حيث يمكنك الوصول بسهولة إلى البيانات فقط من خلال تحديد الخصائص.&lt;/p>
&lt;p>في هذه المقالة، سنقدم ثلاثة أمثلة عملية لبرامج نصية (scripts) للأتمتة الكاملة ترتبط مباشرة بالعمل الفعلي باستخدام PowerShell (النسخ الاحتياطي إلى NAS وتدوير السجلات، ومراقبة سجلات الأحداث وإشعارات Slack، والتحديث المجمع والبناء لمستودعات Git المتعددة). وقبل ذلك، سنشرح بالتفصيل التقنيات الأساسية المطلوبة مثل سياسات تنفيذ PowerShell، وتحويل التعليمات البرمجية إلى وحدات (modularization)، والتكامل مع جدولة المهام (Task Scheduler).&lt;/p>
&lt;hr>
&lt;h2 id="إعداد-البنية-التحتية-لأتمتة-powershell">إعداد البنية التحتية لأتمتة PowerShell
&lt;/h2>&lt;p>لكي تعمل برامج الأتمتة النصية بأمان وموثوقية في بيئة الإنتاج، لا بد من بعض الترتيبات المسبقة. سنشرح هنا بالتفصيل فهم سياسات التنفيذ، والتقسيم إلى وحدات لزيادة قابلية إعادة الاستخدام، ومعالجة الأخطاء القوية.&lt;/p>
&lt;h3 id="1-سياسة-تنفيذ-powershell-execution-policy">1. سياسة تنفيذ PowerShell (Execution Policy)
&lt;/h3>&lt;p>في نظام التشغيل Windows، لضمان عدم تنفيذ البرامج النصية الضارة عن طريق الخطأ في الحالة الافتراضية، تم إعداد &amp;ldquo;سياسة تنفيذ&amp;rdquo;، وفي الحالة الأولية (&lt;code>Restricted&lt;/code>) لا يمكن تنفيذ أي برنامج نصي (ملف &lt;code>.ps1&lt;/code>). لتشغيل الأتمتة، من الضروري تغيير هذا إلى مستوى مناسب.&lt;/p>
&lt;p>تشمل سياسات التنفيذ الأنواع التالية:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Restricted&lt;/strong>: لا يسمح بتشغيل أي برامج نصية. (الافتراضي)&lt;/li>
&lt;li>&lt;strong>AllSigned&lt;/strong>: يسمح فقط بتشغيل البرامج النصية الموقعة من قبل ناشر موثوق.&lt;/li>
&lt;li>&lt;strong>RemoteSigned&lt;/strong>: يمكن تشغيل البرامج النصية التي تم إنشاؤها محليًا كما هي، لكن البرامج النصية التي تم تنزيلها من الإنترنت تتطلب توقيعًا.&lt;/li>
&lt;li>&lt;strong>Unrestricted&lt;/strong>: يمكن تشغيل جميع البرامج النصية، لكن سيتم عرض تحذير عند محاولة تشغيل البرامج النصية التي تم تنزيلها من الإنترنت.&lt;/li>
&lt;li>&lt;strong>Bypass&lt;/strong>: لا يتم حظر أي شيء، ولا تُعرض أي تحذيرات. يُستخدم غالبًا لتنفيذ البرامج النصية المؤقتة (مثل خطوط أنابيب CI/CD).&lt;/li>
&lt;/ul>
&lt;p>عند تشغيل البرامج النصية التي تم إنشاؤها ذاتيًا في بيئة محلية للشركات باستخدام جدولة المهام وما إلى ذلك، فإن الإعداد الأكثر واقعية وأمانًا هو &lt;code>RemoteSigned&lt;/code>. قم بتشغيل PowerShell بصلاحيات المسؤول (Administrator) ونفذ الأمر التالي:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Set-ExecutionPolicy&lt;/span> &lt;span class="n">RemoteSigned&lt;/span> &lt;span class="n">-Scope&lt;/span> &lt;span class="n">LocalMachine&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>سيسمح هذا بتشغيل البرامج النصية مثل نصوص النسخ الاحتياطي التي تم إنشاؤها محليًا دون أن يتم حظرها.&lt;/p>
&lt;h3 id="2-إعادة-استخدام-التعليمات-البرمجية-من-خلال-التقسيم-إلى-وحدات-psm1--psd1">2. إعادة استخدام التعليمات البرمجية من خلال التقسيم إلى وحدات (.psm1 / .psd1)
&lt;/h3>&lt;p>عند إجراء عمليات أتمتة معقدة، لا يُنصح بكتابة جميع العمليات في ملف &lt;code>.ps1&lt;/code> واحد ضخم من منظور قابلية الصيانة. الوظائف المستخدمة بشكل متكرر (مثل إخراج السجلات، إرسال خطافات الويب (Webhook) إلى Slack، معالجة الأخطاء، إلخ) يجب فصلها كـ &amp;ldquo;وحدات&amp;rdquo;.&lt;/p>
&lt;p>تتكون وحدات PowerShell بشكل أساسي من ملف وحدة برمجية نصية (&lt;code>.psm1&lt;/code>) وملف بيان الوحدة (&lt;code>.psd1&lt;/code>).&lt;/p>
&lt;p>مثال على &lt;strong>CommonUtils.psm1&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">function&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">Write-CustomLog&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">CmdletBinding&lt;/span>&lt;span class="p">()]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">param&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">Parameter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="na">Mandatory&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="vm">$true&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="no">string&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="nv">$Message&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="nb">ValidateSet&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;WARNING&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;ERROR&amp;#39;&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">[&lt;/span>&lt;span class="no">string&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="nv">$Level&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$timestamp&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-Date&lt;/span> &lt;span class="n">-Format&lt;/span> &lt;span class="s2">&amp;#34;yyyy-MM-dd HH:mm:ss&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$logLine&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;[&lt;/span>&lt;span class="nv">$timestamp&lt;/span>&lt;span class="s2">] [&lt;/span>&lt;span class="nv">$Level&lt;/span>&lt;span class="s2">] &lt;/span>&lt;span class="nv">$Message&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># تنفيذ الإخراج على الشاشة والإخراج إلى الملف&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="nv">$logLine&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Add-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\logs\automation.log&amp;#34;&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="nv">$logLine&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Export-ModuleMember&lt;/span> &lt;span class="n">-Function&lt;/span> &lt;span class="nb">Write-CustomLog&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>لاستدعاء هذه الوحدة من برامج نصية أخرى، استخدم &lt;code>Import-Module&lt;/code> في بداية البرنامج النصي.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Import-Module&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Modules\CommonUtils.psm1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-CustomLog&lt;/span> &lt;span class="n">-Message&lt;/span> &lt;span class="s2">&amp;#34;بدء عملية النسخ الاحتياطي.&amp;#34;&lt;/span> &lt;span class="n">-Level&lt;/span> &lt;span class="s1">&amp;#39;INFO&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-معالجة-الأخطاء-القوية-try--catch">3. معالجة الأخطاء القوية (try / catch)
&lt;/h3>&lt;p>أهم شيء في الأتمتة هو &amp;ldquo;كيفية التصرف عند حدوث فشل&amp;rdquo;. في PowerShell، من خلال تعيين المتغير المدمج &lt;code>$ErrorActionPreference&lt;/code>، يمكنك التحكم في السلوك الافتراضي عند فشل أمر ما. السلوك الافتراضي هو &lt;code>Continue&lt;/code> (عرض الخطأ ومتابعة المعالجة)، ولكن في برامج الأتمتة النصية، فإن أفضل ممارسة هي تعيينه إلى &lt;code>Stop&lt;/code> والتقاط الاستثناءات صراحةً باستخدام كتل &lt;code>try / catch&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># معالجة قد تفشل&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$content&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\NonExistentFile.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">System.Management.Automation.ItemNotFoundException&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># التقاط خطأ محدد&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;الملف غير موجود: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Red&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># التقاط جميع الأخطاء الأخرى&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;حدث خطأ غير متوقع: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Red&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">finally&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># عملية تنظيف تُنفذ دائمًا بغض النظر عن النجاح أو الفشل&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;إنهاء المعالجة.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>من خلال الاستفادة من هذه البنية التحتية، يمكنك بناء برامج نصية آمنة وقابلة للتتبع حتى عند تشغيلها بدون تدخل بشري أثناء الليل.&lt;/p>
&lt;hr>
&lt;h2 id="التكامل-مع-جدولة-المهام-register-scheduledtask">التكامل مع جدولة المهام (Register-ScheduledTask)
&lt;/h2>&lt;p>بمجرد اكتمال البرنامج النصي، ستحتاج بعد ذلك إلى آلية لتشغيله بشكل دوري. الأداة الأكثر موثوقية في Windows هي &amp;ldquo;جدولة المهام&amp;rdquo; (Task Scheduler). في حين أنه من الممكن إعداده من واجهة المستخدم الرسومية (&lt;code>taskschd.msc&lt;/code>)، سنشرح هنا كيفية تسجيل المهام باستخدام أوامر PowerShell، وذلك من منظور تحويل أدلة البنية التحتية إلى تعليمات برمجية (Infrastructure as Code).&lt;/p>
&lt;p>يحتوي PowerShell على وحدة &lt;code>ScheduledTasks&lt;/code> الجاهزة للاستخدام، والتي تتيح لك تحديد المشغلات (متى يتم التنفيذ)، والإجراءات (ما يتم تنفيذه)، والأساسيات (تحت أي صلاحيات مستخدم يتم التنفيذ) بالتفصيل.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. تحديد الإجراء (تشغيل PowerShell بشكل مخفي وتمرير البرنامج النصي المحدد)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$action&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskAction&lt;/span> &lt;span class="n">-Execute&lt;/span> &lt;span class="s2">&amp;#34;powershell.exe&amp;#34;&lt;/span> &lt;span class="n">-Argument&lt;/span> &lt;span class="s2">&amp;#34;-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Scripts\DailyTasks.ps1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 2. تحديد المشغل (يعمل يوميًا في الساعة 3:00 صباحًا)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$trigger&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskTrigger&lt;/span> &lt;span class="n">-Daily&lt;/span> &lt;span class="n">-At&lt;/span> &lt;span class="s2">&amp;#34;3:00AM&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 3. تحديد الصلاحية (التنفيذ بصلاحيات SYSTEM)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$principal&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskPrincipal&lt;/span> &lt;span class="n">-UserId&lt;/span> &lt;span class="s2">&amp;#34;NT AUTHORITY\SYSTEM&amp;#34;&lt;/span> &lt;span class="n">-LogonType&lt;/span> &lt;span class="n">ServiceAccount&lt;/span> &lt;span class="n">-RunLevel&lt;/span> &lt;span class="n">Highest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 4. بناء إعدادات المهمة&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$settings&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-ScheduledTaskSettingsSet&lt;/span> &lt;span class="n">-AllowStartIfOnBatteries&lt;/span> &lt;span class="n">-DontStopIfGoingOnBatteries&lt;/span> &lt;span class="n">-StartWhenAvailable&lt;/span> &lt;span class="n">-DontStopOnIdleEnd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 5. تسجيل المهمة&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$taskName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;MyDailyAutomationTask&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Register-ScheduledTask&lt;/span> &lt;span class="n">-TaskName&lt;/span> &lt;span class="nv">$taskName&lt;/span> &lt;span class="n">-Action&lt;/span> &lt;span class="nv">$action&lt;/span> &lt;span class="n">-Trigger&lt;/span> &lt;span class="nv">$trigger&lt;/span> &lt;span class="n">-Principal&lt;/span> &lt;span class="nv">$principal&lt;/span> &lt;span class="n">-Settings&lt;/span> &lt;span class="nv">$settings&lt;/span> &lt;span class="n">-Description&lt;/span> &lt;span class="s2">&amp;#34;مهمة لتنفيذ الأعمال الروتينية اليومية تلقائيًا&amp;#34;&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>بمجرد تشغيل هذا البرنامج النصي، سيتم تسجيل الوظيفة في جدولة المهام، وسيتم تشغيل البرنامج النصي يوميًا في الوقت المحدد بصلاحيات النظام (SYSTEM) (أعلى الصلاحيات الممكنة في الخلفية دون إظهار شاشة).&lt;/p>
&lt;hr>
&lt;h2 id="المثال-العملي-1-النسخ-الاحتياطي-إلى-nas-خارجي-وتدوير-السجلات">المثال العملي 1: النسخ الاحتياطي إلى NAS خارجي وتدوير السجلات
&lt;/h2>&lt;p>النسخ الاحتياطي اليومي لبيانات العمل أمر إلزامي، لكن النسخ اليدوي غير وارد. هنا سنقوم بإنشاء برنامج نصي يستدعي &lt;code>Robocopy&lt;/code>، وهو أقوى أمر نسخ مدمج في Windows، من خلال PowerShell، ويُخرج سجلات لنتائج التنفيذ، ويحذف السجلات القديمة تلقائيًا (التدوير).&lt;/p>
&lt;h3 id="القيمة-النظرية-لوقت-التنفيذ-في-نقل-الشبكة-math">القيمة النظرية لوقت التنفيذ في نقل الشبكة (Math)
&lt;/h3>&lt;p>عند تصميم برنامج نصي للنسخ الاحتياطي، من المهم تشغيليًا تقدير الوقت الذي ستستغرقه العملية حتى تكتمل. يمكن تقريب الوقت المقدر $T_{backup}$ المطلوب للنسخ الاحتياطي عبر شبكة إلى وحدة تخزين متصلة بالشبكة (NAS) باستخدام المعادلة التالية:&lt;/p>
$$ T_{backup} = \frac{S_{total}}{B \times (1 - \alpha)} + C \times L $$&lt;p>حيث تكون المتغيرات كالتالي:&lt;/p>
&lt;ul>
&lt;li>$S_{total}$ : إجمالي حجم البيانات المراد نسخها احتياطيًا (بالبت)&lt;/li>
&lt;li>$B$ : عرض النطاق الترددي للشبكة (بت في الثانية، مثال: 1 جيجابت في الثانية = $10^9$ بت/ثانية)&lt;/li>
&lt;li>$\alpha$ : الحمل الزائد للشبكة والبروتوكولات (عادةً ما يتراوح بين 0.1 و 0.2 في بروتوكولات TCP/IP أو SMB)&lt;/li>
&lt;li>$C$ : العدد الإجمالي للملفات&lt;/li>
&lt;li>$L$ : وقت الاستجابة لمعالجة الملف الواحد (بالثواني)&lt;/li>
&lt;/ul>
&lt;p>بشكل خاص، عند إجراء نسخ احتياطي لعدد كبير من الملفات الصغيرة (مثل التعليمات البرمجية المصدر)، فإن عامل التأخير الناتج عن عدد الملفات $C$ ($C \times L$) يكون هو المهيمن. لهذا السبب، في عمليات النسخ الاحتياطي، من الأفضل استخدام &lt;code>Robocopy&lt;/code>، الذي يدعم النقل متعدد الخيوط، بدلاً من أداة نسخ ملفات بسيطة.&lt;/p>
&lt;h3 id="تدفق-عملية-البرنامج-النصي-للنسخ-الاحتياطي">تدفق عملية البرنامج النصي للنسخ الاحتياطي
&lt;/h3>&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;بدء البرنامج النصي للنسخ الاحتياطي&amp;#34;] --&amp;gt; B{&amp;#34;هل NAS متاح للوصول؟&amp;#34;}
B -- نعم --&amp;gt; C[&amp;#34;تنفيذ Robocopy (متعدد الخيوط)&amp;#34;]
B -- لا --&amp;gt; D[&amp;#34;كتابة سجل الأخطاء والخروج&amp;#34;]
C --&amp;gt; E{&amp;#34;هل نجح Robocopy؟&amp;#34;}
E -- نعم (ExitCode &amp;lt; 8) --&amp;gt; F[&amp;#34;تدوير السجلات (الاحتفاظ بآخر 30 يومًا)&amp;#34;]
E -- لا (ExitCode &amp;gt;= 8) --&amp;gt; D
F --&amp;gt; G[&amp;#34;إنهاء البرنامج النصي للنسخ الاحتياطي&amp;#34;]
D --&amp;gt; G
&lt;/pre>
&lt;h3 id="مثال-على-تنفيذ-برنامج-powershell-النصي-backup-tonasps1">مثال على تنفيذ برنامج PowerShell النصي (&lt;code>Backup-ToNas.ps1&lt;/code>)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># قيم الإعداد&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$SourceDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\WorkData&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$TargetNasDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;\\NAS01\Backup\WorkData&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$LogDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Logs&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$DateStr&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-Date&lt;/span> &lt;span class="n">-Format&lt;/span> &lt;span class="s2">&amp;#34;yyyyMMdd&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$LogFile&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Join-Path&lt;/span> &lt;span class="nv">$LogDir&lt;/span> &lt;span class="s2">&amp;#34;Backup_&lt;/span>&lt;span class="nv">$DateStr&lt;/span>&lt;span class="s2">.log&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$RetainDays&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mf">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 1. فحص مسبق: هل يمكن الوصول إلى NAS؟&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">-not&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="s2">&amp;#34;لا يمكن الوصول إلى المسار المستهدف في NAS: &lt;/span>&lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;بدء النسخ الاحتياطي: &lt;/span>&lt;span class="nv">$SourceDir&lt;/span>&lt;span class="s2"> -&amp;gt; &lt;/span>&lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 2. تنفيذ Robocopy&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /MIR : عكس (Mirroring) (حذف الملفات التي ليست في المصدر)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /MT:16 : نسخ متعدد الخيوط مع 16 خيطًا&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /NP : عدم طباعة تقدم العملية (%) (لتجنب فوضى السجلات)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># /R:2 /W:2 : عدد مرات إعادة المحاولة عند حدوث خطأ 2، ووقت الانتظار 2 ثانية&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$roboArgs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$SourceDir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$TargetNasDir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/MIR&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/MT:16&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/NP&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/R:2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/W:2&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;/LOG+:&lt;/span>&lt;span class="nv">$LogFile&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># عند استدعاء أمر خارجي من PowerShell، يُفضل استخدام Start-Process لضمان الموثوقية&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$process&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Start-Process&lt;/span> &lt;span class="n">-FilePath&lt;/span> &lt;span class="s2">&amp;#34;robocopy.exe&amp;#34;&lt;/span> &lt;span class="n">-ArgumentList&lt;/span> &lt;span class="nv">$roboArgs&lt;/span> &lt;span class="n">-Wait&lt;/span> &lt;span class="n">-NoNewWindow&lt;/span> &lt;span class="n">-PassThru&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$exitCode&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$process&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ExitCode&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># مواصفات كود خروج Robocopy: 0-7 تعني نجاحًا أو سلوكًا متوقعًا. 8 فما فوق تعني خطأ&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$exitCode&lt;/span> &lt;span class="o">-ge&lt;/span> &lt;span class="mf">8&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="s2">&amp;#34;انتهى Robocopy بوجود خطأ. كود الخروج: &lt;/span>&lt;span class="nv">$exitCode&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;اكتمل النسخ الاحتياطي بنجاح. كود الخروج: &lt;/span>&lt;span class="nv">$exitCode&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># 3. تدوير السجلات&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;جارٍ حذف ملفات السجل القديمة (فترة الاحتفاظ: &lt;/span>&lt;span class="nv">${RetainDays}&lt;/span>&lt;span class="s2"> يومًا)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$limitDate&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Get-Date&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="py">AddDays&lt;/span>&lt;span class="p">(-&lt;/span>&lt;span class="nv">$RetainDays&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Get-ChildItem&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$LogDir&lt;/span> &lt;span class="n">-Filter&lt;/span> &lt;span class="s2">&amp;#34;Backup_*.log&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Where-Object&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">LastWriteTime&lt;/span> &lt;span class="o">-lt&lt;/span> &lt;span class="nv">$limitDate&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Remove-Item&lt;/span> &lt;span class="n">-Force&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;اكتمل تنظيف السجلات.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$errorMessage&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;حدث خطأ أثناء عملية النسخ الاحتياطي: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="nv">$errorMessage&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># كتابة الخطأ في ملف سجل الأخطاء الفعلي&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Add-Content&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Join-Path&lt;/span> &lt;span class="nv">$LogDir&lt;/span> &lt;span class="s2">&amp;#34;Error.log&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">-Value&lt;/span> &lt;span class="s2">&amp;#34;[(Get-Date -Format &amp;#39;yyyy-MM-dd HH:mm:ss&amp;#39;)] &lt;/span>&lt;span class="nv">$errorMessage&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># الخروج برمز غير صفري لإخطار جدولة المهام بوجود خطأ&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span> &lt;span class="mf">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>هذا البرنامج النصي، عند اقترانه بجدولة المهام، يحقق أتمتة كاملة للنسخ الاحتياطي اليومي. التعامل مع كود خروج &lt;code>Robocopy&lt;/code> هو أمر بالغ الأهمية. حتى عند نجاح العملية، يقوم Robocopy بإرجاع 1 إذا &amp;ldquo;تم نسخ ملفات جديدة&amp;rdquo;، و 2 إذا &amp;ldquo;تم حذف ملفات إضافية&amp;rdquo;، إلخ. لذلك، يجب الانتباه إلى أن الفحص البسيط مثل &lt;code>$LASTEXITCODE -eq 0&lt;/code> لن يعمل بشكل صحيح.&lt;/p>
&lt;hr>
&lt;h2 id="المثال-العملي-2-مراقبة-سجل-أحداث-النظام-وإشعارات-slack-webhook">المثال العملي 2: مراقبة سجل أحداث النظام وإشعارات Slack (Webhook)
&lt;/h2>&lt;p>في خوادم Windows أو محطات عمل المبدعين، من الأهمية بمكان اكتشاف علامات أخطاء الأقراص التي تنذر بشاشة الموت الزرقاء (BSoD) أو أعطال التطبيقات (Application Error) في أقرب وقت ممكن.
هنا سنقوم بإنشاء برنامج نصي يستخرج سجلات مستوى &amp;ldquo;الخطأ&amp;rdquo; (Error) و&amp;quot;الخطير&amp;quot; (Critical) من سجلات أحداث &lt;code>System&lt;/code> و &lt;code>Application&lt;/code> للساعة الماضية، وإرسال إشعار إلى Slack في حالة العثور على أي منها.&lt;/p>
&lt;h3 id="مخطط-تسلسل-لعملية-الإشعارات">مخطط تسلسل لعملية الإشعارات
&lt;/h3>&lt;pre class="mermaid">
sequenceDiagram
participant S as &amp;#34;المهمة المجدولة&amp;#34;
participant P as &amp;#34;برنامج PowerShell النصي&amp;#34;
participant W as &amp;#34;سجل أحداث Windows&amp;#34;
participant Sl as &amp;#34;واجهة برمجة تطبيقات Slack&amp;#34;
S-&amp;gt;&amp;gt;P: &amp;#34;تشغيل البرنامج النصي (كل ساعة)&amp;#34;
P-&amp;gt;&amp;gt;W: &amp;#34;Get-WinEvent (أخطاء/حرجة في الساعة الماضية)&amp;#34;
W--&amp;gt;&amp;gt;P: &amp;#34;إرجاع كائنات السجل&amp;#34;
alt &amp;#34;تم العثور على أخطاء&amp;#34;
P-&amp;gt;&amp;gt;P: &amp;#34;تنسيق الرسالة (JSON)&amp;#34;
P-&amp;gt;&amp;gt;Sl: &amp;#34;Invoke-RestMethod (POST webhook_url)&amp;#34;
Sl--&amp;gt;&amp;gt;P: &amp;#34;200 OK&amp;#34;
else &amp;#34;لا توجد أخطاء&amp;#34;
P-&amp;gt;&amp;gt;P: &amp;#34;خروج آمن&amp;#34;
end
&lt;/pre>
&lt;h3 id="مثال-على-تنفيذ-برنامج-powershell-النصي-monitor-eventlogps1">مثال على تنفيذ برنامج PowerShell النصي (&lt;code>Monitor-EventLog.ps1&lt;/code>)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># رابط Slack Webhook (تم الحصول عليه مسبقًا من خلال دمج Incoming Webhooks في Slack)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$SlackWebhookUrl&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXXXXXXX&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># النطاق الزمني للبحث (الساعة الماضية)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$startTime&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Get-Date&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="py">AddHours&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">-1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># استخدام مرشح XPath للبحث في سجل الأحداث بسرعة&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># المستوى 1: خطير (Critical)، 2: خطأ (Error)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$xmlFilter&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="sh">@&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;lt;QueryList&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Query Id=&amp;#34;0&amp;#34; Path=&amp;#34;System&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Select Path=&amp;#34;System&amp;#34;&amp;gt;*[System[(Level=1 or Level=2) and TimeCreated[@SystemTime&amp;amp;gt;=&amp;#39;&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$startTime&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToUniversalTime&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="py">ToString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;o&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="sh">&amp;#39;]]]&amp;lt;/Select&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;/Query&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Query Id=&amp;#34;1&amp;#34; Path=&amp;#34;Application&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;Select Path=&amp;#34;Application&amp;#34;&amp;gt;*[System[(Level=1 or Level=2) and TimeCreated[@SystemTime&amp;amp;gt;=&amp;#39;&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$startTime&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToUniversalTime&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="py">ToString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;o&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="sh">&amp;#39;]]]&amp;lt;/Select&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> &amp;lt;/Query&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;lt;/QueryList&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;#34;@&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># جلب السجلات باستخدام Get-WinEvent&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># -ErrorAction SilentlyContinue يُستخدم لتجاهل الأخطاء عندما لا يتم العثور على سجلات&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$events&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-WinEvent&lt;/span> &lt;span class="n">-FilterXml&lt;/span> &lt;span class="nv">$xmlFilter&lt;/span> &lt;span class="n">-ErrorAction&lt;/span> &lt;span class="n">SilentlyContinue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$events&lt;/span> &lt;span class="o">-and&lt;/span> &lt;span class="nv">$events&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Count&lt;/span> &lt;span class="o">-gt&lt;/span> &lt;span class="mf">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$eventCount&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$events&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Count&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;تم العثور على &lt;/span>&lt;span class="nv">$eventCount&lt;/span>&lt;span class="s2"> سجلات لأخطاء/أحداث خطيرة في الساعة الماضية.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># بناء نص الإشعار&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;*تنبيه نظام Windows* :rotating_light:&lt;/span>&lt;span class="se">`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;تم اكتشاف &lt;/span>&lt;span class="nv">$eventCount&lt;/span>&lt;span class="s2"> أخطاء في الساعة الماضية.&lt;/span>&lt;span class="se">`n`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># تفصيل آخر 3 أحداث فقط (مع مراعاة الحد الأقصى لعدد الأحرف)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$events&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Select-Object&lt;/span> &lt;span class="n">-First&lt;/span> &lt;span class="mf">3&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">ForEach-Object&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;*&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">LogName&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">* - &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ProviderName&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2"> (معرف الحدث: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Id&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">)&lt;/span>&lt;span class="se">`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;&amp;gt; &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Message&lt;/span> &lt;span class="o">-replace&lt;/span> &lt;span class="s1">&amp;#39;`n&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39; &amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="se">`n`n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$eventCount&lt;/span> &lt;span class="o">-gt&lt;/span> &lt;span class="mf">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$messageBody&lt;/span> &lt;span class="p">+=&lt;/span> &lt;span class="s2">&amp;#34;※ هناك &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$eventCount&lt;/span> &lt;span class="p">-&lt;/span> &lt;span class="mf">3&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2"> أخطاء أخرى. يرجى التحقق من عارض الأحداث (Event Viewer).&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># إنشاء حمولة JSON للإرسال إلى Slack&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$payload&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$messageBody&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">username&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;SystemMonitor&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">icon_emoji&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;:desktop_computer:&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$jsonPayload&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$payload&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">ConvertTo-Json&lt;/span> &lt;span class="n">-Depth&lt;/span> &lt;span class="mf">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># استدعاء REST API للإرسال إلى Slack&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Invoke-RestMethod&lt;/span> &lt;span class="n">-Uri&lt;/span> &lt;span class="nv">$SlackWebhookUrl&lt;/span> &lt;span class="n">-Method&lt;/span> &lt;span class="n">Post&lt;/span> &lt;span class="n">-Body&lt;/span> &lt;span class="nv">$jsonPayload&lt;/span> &lt;span class="n">-ContentType&lt;/span> &lt;span class="s2">&amp;#34;application/json; charset=utf-8&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;تم إرسال الإشعار إلى Slack.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;لم يتم العثور على سجلات أخطاء/أحداث خطيرة. النظام طبيعي.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="s2">&amp;#34;حدث خطأ في البرنامج النصي لمراقبة سجل الأحداث: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span> &lt;span class="mf">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>النقطة الفنية الرئيسية في هذا البرنامج النصي هي استخدام &lt;code>Get-WinEvent -FilterXml&lt;/code>. إن الأسلوب التقليدي باستخدام &lt;code>Get-EventLog&lt;/code> أو التصفية بواسطة &lt;code>Where-Object&lt;/code> في خط الأنابيب يعد بطيئًا للغاية؛ لأنه يحمّل جميع كائنات الأحداث في الذاكرة قبل معالجتها. باستخدام تصفية XML، تتم التصفية على جانب خدمة سجل أحداث Windows، مما يؤدي إلى تحسن هائل في الأداء مع بقاء وقت التنفيذ في حدود بضع ثوانٍ.&lt;/p>
&lt;hr>
&lt;h2 id="المثال-العملي-3-التحديث-المجمع-وبناء-الأتمتة-لمستودعات-git-المتعددة">المثال العملي 3: التحديث المجمع وبناء الأتمتة لمستودعات Git المتعددة
&lt;/h2>&lt;p>بالنسبة للمطورين، يُعد مزامنة مستودعات Git المتعددة (مثل الواجهة الأمامية، والخلفية، ومستودعات البنية التحتية) الموجودة على حواسيب العمل الخاصة بهم مع أحدث إصدار من فرع &lt;code>main&lt;/code> كل صباح، وتثبيت الحزم اللازمة (مثل &lt;code>npm install&lt;/code>) وإجراء عمليات البناء (build) مهمة شاقة.
سنقوم بإنشاء أداة تؤدي هذه المهام دفعة واحدة باستخدام برنامج PowerShell النصي.&lt;/p>
&lt;p>يقوم هذا البرنامج النصي باكتشاف كافة مستودعات Git تلقائيًا ضمن دليل رئيسي محدد، وإذا لم تكن هناك تغييرات غير ملتزم بها (uncommitted changes)، فإنه يقوم بتنفيذ أمر &lt;code>git pull&lt;/code>. وعلاوة على ذلك، إذا تم سحب تغييرات جديدة، فإنه يقوم بإصدار أمر بناء تلقائيًا.&lt;/p>
&lt;h3 id="البرنامج-النصي-للتحديث-التلقائي-للمستودعات-المتعددة-update-gitreposps1">البرنامج النصي للتحديث التلقائي للمستودعات المتعددة (&lt;code>Update-GitRepos.ps1&lt;/code>)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$ErrorActionPreference&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s1">&amp;#39;Stop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># قائمة بالأدلة الرئيسية حيث توجد المستودعات&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$TargetDirectories&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">@&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;C:\Dev\FrontendProjects&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;C:\Dev\BackendProjects&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># استكشاف كل دليل&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$parentDir&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">$TargetDirectories&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">-not&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="nv">$parentDir&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Warning&lt;/span> &lt;span class="s2">&amp;#34;الدليل غير موجود: &lt;/span>&lt;span class="nv">$parentDir&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># الحصول على قائمة بالأدلة الفرعية&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$subDirs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-ChildItem&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$parentDir&lt;/span> &lt;span class="n">-Directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$repoDir&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">$subDirs&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$repoPath&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nv">$repoDir&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">FullName&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$gitDir&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Join-Path&lt;/span> &lt;span class="nv">$repoPath&lt;/span> &lt;span class="s2">&amp;#34;.git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># التحقق مما إذا كان مجلد .git موجودًا (ما إذا كان مستودع Git)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="nv">$gitDir&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;---------------------------------&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;تتم معالجة المستودع: &lt;/span>&lt;span class="nv">$repoPath&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Cyan&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># تغيير دليل العمل الحالي في PowerShell&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Set-Location&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="nv">$repoPath&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># التحقق مما إذا كانت هناك تغييرات غير ملتزم بها&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$status&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">git&lt;/span> &lt;span class="n">status&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-porcelain&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$status&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;تخطي نظرًا لوجود تغييرات غير ملتزم بها.&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Yellow&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># الحصول على الفرع الحالي&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$branch&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">git&lt;/span> &lt;span class="nb">rev-parse&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-abbrev-ref&lt;/span> &lt;span class="n">HEAD&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$branch&lt;/span> &lt;span class="o">-ne&lt;/span> &lt;span class="s2">&amp;#34;main&amp;#34;&lt;/span> &lt;span class="o">-and&lt;/span> &lt;span class="nv">$branch&lt;/span> &lt;span class="o">-ne&lt;/span> &lt;span class="s2">&amp;#34;master&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;تخطي لأن الفرع الحالي هو &lt;/span>&lt;span class="nv">$branch&lt;/span>&lt;span class="s2"> (مستهدف فقط main/master).&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Yellow&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">continue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># تنفيذ عملية Pull وتخزين النتيجة في متغير&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;جارٍ الحصول على أحدث التحديثات من الخادم البعيد (git pull)...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$pullResult&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">git&lt;/span> &lt;span class="n">pull&lt;/span> &lt;span class="n">origin&lt;/span> &lt;span class="nv">$branch&lt;/span> &lt;span class="mf">2&lt;/span>&lt;span class="p">&amp;gt;&amp;amp;&lt;/span>&lt;span class="mf">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># إخراج إلى وحدة التحكم أيضًا&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$pullResult&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">ForEach-Object&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34; &lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># إذا كانت النتيجة تحتوي على نصوص بخلاف &amp;#34;Already up to date.&amp;#34;، فيُعتبر أن هناك تحديثًا&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$isUpdated&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">$false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">foreach&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$line&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nv">$pullResult&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$line&lt;/span> &lt;span class="o">-notmatch&lt;/span> &lt;span class="s2">&amp;#34;Already up to date&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$isUpdated&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="vm">$true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$isUpdated&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;تم تحديث المستودع. جارٍ بدء مهمة البناء...&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Green&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># إذا كان هناك package.json، قم بتنفيذ npm install و npm run build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">Test-Path&lt;/span> &lt;span class="s2">&amp;#34;package.json&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;جارٍ تنفيذ npm install...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">npm&lt;/span> &lt;span class="n">install&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;جارٍ تنفيذ npm run build...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">npm&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># إذا كان هناك ملف .sln (Visual Studio Solution)، قم بتنفيذ msbuild أو dotnet build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">$slnFiles&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Get-ChildItem&lt;/span> &lt;span class="n">-Filter&lt;/span> &lt;span class="s2">&amp;#34;*.sln&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$slnFiles&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Count&lt;/span> &lt;span class="o">-gt&lt;/span> &lt;span class="mf">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;جارٍ بناء تطبيق .NET...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dotnet&lt;/span> &lt;span class="n">build&lt;/span> &lt;span class="nv">$slnFiles&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mf">0&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="py">FullName&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">catch&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Error&lt;/span> &lt;span class="s2">&amp;#34;حدث خطأ أثناء معالجة المستودع &lt;/span>&lt;span class="nv">$repoPath&lt;/span>&lt;span class="s2"> : &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$_&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Exception&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Message&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;---------------------------------&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;اكتملت عملية تحديث جميع المستودعات.&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Green&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>تم تصميم هذا البرنامج النصي بحيث يمكنه الاستمرار في المعالجة من خلال &lt;code>try / catch&lt;/code> وحلقة &lt;code>foreach&lt;/code> حتى في حالة حدوث أخطاء، دون التأثير على معالجة المستودع التالي. بالإضافة إلى ذلك، يتم استخدام خيار &lt;code>git status --porcelain&lt;/code> المخصص لمعالجة البرامج النصية لتحديد نظافة شجرة العمل بشكل موثوق. إذا قمت بوضع هذا البرنامج النصي في مجلد بدء التشغيل أو قمت بتسجيله في جدولة المهام عند تسجيل دخول المستخدم، فستكون جميع بيئات التطوير الخاصة بك محدثة بالكامل بحلول الوقت الذي تقوم فيه بتشغيل جهاز الكمبيوتر وتحضير فنجان من القهوة.&lt;/p>
&lt;hr>
&lt;h2 id="ملاحظات-تشغيلية-وتقنيات-متقدمة">ملاحظات تشغيلية وتقنيات متقدمة
&lt;/h2>&lt;p>عند تشغيل برامج أتمتة PowerShell النصية على المدى الطويل، هناك بعض أفضل الممارسات التي ينبغي أخذها في الاعتبار.&lt;/p>
&lt;h3 id="1-الإدارة-الآمنة-لبيانات-الاعتماد">1. الإدارة الآمنة لبيانات الاعتماد
&lt;/h3>&lt;p>من المخاطر الأمنية الكبيرة تضمين كلمات المرور أو مفاتيح واجهة برمجة التطبيقات (مثل رابط Slack Webhook وسلاسل اتصال قواعد البيانات) كنص صريح داخل البرنامج النصي. يحتوي PowerShell على ميزات مضمنة مثل &lt;code>Export-Clixml&lt;/code> و &lt;code>ConvertFrom-SecureString&lt;/code> التي تشفر بيانات الاعتماد قبل حفظها.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># ينفذ يدويًا في المرة الأولى فقط (سيظهر مربع حوار لإدخال كلمة المرور)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Get-Credential | Export-Clixml -Path &amp;#34;C:\Scripts\Creds\admin.xml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># القراءة داخل برنامج الأتمتة النصي&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$cred&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">Import-Clixml&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Creds\admin.xml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># استخدام $cred للاتصال بخادم بعيد وما إلى ذلك&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>يضمن هذا أن بيانات المصادقة آمنة ولا يمكن فك تشفيرها إلا في ملف تعريف المستخدم الذي يُشغل البرنامج النصي.&lt;/p>
&lt;h3 id="2-التسجيل-الكامل-لسجل-التنفيذ-من-خلال-النصوص-transcript">2. التسجيل الكامل لسجل التنفيذ من خلال النصوص (Transcript)
&lt;/h3>&lt;p>في الأمثلة السابقة، قمنا بإخراج السجلات بشكل فردي باستخدام أوامر مثل &lt;code>Add-Content&lt;/code>، لكن PowerShell يتمتع بميزة &amp;ldquo;Transcript&amp;rdquo; التي تسجل تلقائيًا كافة المعلومات المعروضة على الشاشة (بما في ذلك رسائل الخطأ والإخراج القياسي) إلى ملف.&lt;/p>
&lt;p>فقط من خلال إضافة ما يلي إلى بداية البرنامج النصي ونهايته، يمكنك إنشاء سجل تدقيق قوي.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Start-Transcript&lt;/span> &lt;span class="n">-Path&lt;/span> &lt;span class="s2">&amp;#34;C:\Scripts\Logs\Execution_&lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nb">Get-Date&lt;/span> &lt;span class="n">-Format&lt;/span> &lt;span class="s1">&amp;#39;yyyyMMdd_HHmmss&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="s2">.log&amp;#34;&lt;/span> &lt;span class="n">-Append&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># (محتوى البرنامج النصي هنا)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Stop-Transcript&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-النهج-الرياضي-للمراقبة-واكتشاف-الحالات-الشاذة-math">3. النهج الرياضي للمراقبة واكتشاف الحالات الشاذة (Math)
&lt;/h3>&lt;p>في الأتمتة واسعة النطاق، لا يكفي اكتشاف الأخطاء ببساطة؛ بل من الفعال استخدام أساليب إحصائية لاكتشاف &amp;ldquo;الأشياء غير المعتادة&amp;rdquo;. على سبيل المثال، إذا كان وقت النسخ الاحتياطي اليومي ينحرف بشكل كبير عن متوسطه المعتاد، فقد يكون هذا مؤشرًا مبكرًا على مشاكل في الشبكة أو عطل وشيك في القرص.&lt;/p>
&lt;p>إذا كان وقت النسخ الاحتياطي اليومي $x_1, x_2, \dots, x_n$، فيمكن حساب متوسط العينة $\mu$ والانحراف المعياري $\sigma$ كالتالي:&lt;/p>
$$ \mu = \frac{1}{n} \sum_{i=1}^n x_i $$$$ \sigma = \sqrt{ \frac{1}{n-1} \sum_{i=1}^n (x_i - \mu)^2 } $$&lt;p>إذا تجاوز وقت التنفيذ لليوم $x_{today}$ قيمة $\mu + 3\sigma$ (قاعدة الثلاثة سيغما)، يمكنك بناء منطق يعتبر أن هناك &amp;ldquo;شذوذًا إحصائيًا&amp;rdquo; ويرسل إشعارًا تحذيريًا. باستخدام أمر &lt;code>Measure-Object&lt;/code> في PowerShell، يمكن تنفيذ مثل هذه المعالجات الإحصائية في بضعة أسطر فقط.&lt;/p>
&lt;h2 id="الخلاصة">الخلاصة
&lt;/h2>&lt;p>في هذه المقالة، قمنا بشرح كيفية استخدام PowerShell في بيئة Windows لأتمتة المهام اليومية الروتينية بالكامل مع تقديم أمثلة عملية.
بدءًا من إعداد سياسات التنفيذ وبناء البنية الأساسية من خلال التقسيم إلى وحدات، وصولًا إلى تقديم برامج نصية جاهزة للاستخدام في العمل الحقيقي، مثل النسخ الاحتياطي وتدوير السجلات، ومراقبة سجلات الأحداث مع إشعارات Slack، وعمليات البناء التلقائية لمستودعات Git المتعددة.&lt;/p>
&lt;p>يُعد PowerShell أداة عميقة جدًا؛ وعلى الرغم من كونه أداة سطر أوامر، إلا أنه محرك أتمتة قوي قادر على الوصول إلى كافة ميزات .NET تقريبًا. بالاعتماد على البرامج النصية المقدمة في هذه المقالة، يمكنك تخصيص المسارات ومنطق المعالجة ليتناسب مع بيئة عملك، وتوفير وقتك للإبداع بدلًا من القيام بمهام يدوية مملة.&lt;/p>
&lt;p>نجاح الأتمتة يعتمد على &amp;ldquo;البدء ببرنامج نصي صغير وزيادة قوته تدريجيًا من خلال إضافة معالجة الأخطاء وإخراج السجلات وما إلى ذلك&amp;rdquo;. لمَ لا تبدأ رحلة الأتمتة باستخدام PowerShell عن طريق إجراء نسخ احتياطي لمجلد واحد فقط على جهاز الكمبيوتر الخاص بك؟&lt;/p></description></item><item><title>التكامل بين PowerShell و C++: تقنيات أتمتة إدارة النظام</title><link>http://kenji.blog/ar/p/powershell-cpp-system-automation/</link><pubDate>Sat, 12 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/powershell-cpp-system-automation/</guid><description>&lt;img src="http://kenji.blog/p/powershell-cpp-system-automation/img/eyecatch.jpg" alt="Featured image of post التكامل بين PowerShell و C++: تقنيات أتمتة إدارة النظام" />&lt;h2 id="مقدمة">مقدمة
&lt;/h2>&lt;p>في إدارة أنظمة Windows والأتمتة، أصبح PowerShell الأداة القياسية الفعلية. يمكنك كتابة نصوص برمجية (سكربتات) لأي مهمة تقريبًا، مثل إدارة Active Directory، ومعالجة نظام الملفات، وتغيير تكوين الشبكة. ومع ذلك، على الرغم من أن PowerShell متعدد الاستخدامات، إلا أن هناك أوقاتًا تعاني فيها من قيود الأداء الخاصة بلغات السكربتات أو صعوبة الوصول إلى واجهات برمجة تطبيقات Windows (Windows API) ذات المستوى المنخفض جدًا.&lt;/p>
&lt;p>هنا يأتي &amp;ldquo;التكامل مع C++&amp;rdquo; كحل قوي. توفر لغة C++ سرعة تنفيذ أصلية (native) ووصولاً كاملاً إلى واجهات برمجة تطبيقات Win32 وكائنات COM. من خلال الجمع بين &amp;ldquo;الإنتاجية العالية والمرونة&amp;rdquo; لـ PowerShell مع &amp;ldquo;الأداء الفائق والتحكم منخفض المستوى&amp;rdquo; لـ C++، يصبح من الممكن تحسين مهام إدارة النظام المعقدة والواسعة النطاق للغاية في بيئات المؤسسات.&lt;/p>
&lt;p>في هذه المقالة، سنشرح بالتفصيل المعمارية المحددة، وتقنيات التنفيذ، وأفضل الممارسات لإدارة الذاكرة وتحويل السلاسل النصية (strings) لربط PowerShell و C++ ثنائي الاتجاه.&lt;/p>
&lt;h2 id="لماذا-ندمج-بين-powershell-و-c">لماذا ندمج بين PowerShell و C++؟
&lt;/h2>&lt;h3 id="1-تجاوز-قيود-الأداء">1. تجاوز قيود الأداء
&lt;/h3>&lt;p>يعمل PowerShell على إطار عمل .NET Framework (أو .NET Core / .NET) ويحتوي على عناصر لغة مفسرة ومكتوبة ديناميكيًا. لذلك، عند معالجة كميات كبيرة من النصوص، أو إجراء عمليات تشفير معقدة، أو تحليل سجلات الأحداث التي تصل إلى ملايين الأسطر، يمكن أن تصبح سرعة التنفيذ واستهلاك الذاكرة بمثابة عنق زجاجة (bottleneck).&lt;/p>
&lt;p>دعونا نفكر في نموذج لحجم الحساب ووقت المعالجة. بافتراض أن وقت المعالجة الإجمالي للمهمة هو $T_{total}$، فإن وقت المعالجة باستخدام PowerShell وحده، ووقت المعالجة عند نقل الحمل (offloading) إلى C++ يمكن صياغته على النحو التالي.&lt;/p>
$$ T_{total}^{(PS)} = N \times (t_{overhead} + t_{compute}^{(PS)}) $$$$ T_{total}^{(C++)} = t_{interop} + N \times t_{compute}^{(C++)} $$&lt;p>حيث $N$ هو عدد العناصر التي يتم معالجتها، و $t_{overhead}$ هو العبء الإضافي (overhead) المرتبط بمعالجة الحلقات (loops) في PowerShell، و $t_{compute}$ هو وقت الحساب النقي لكل عنصر، و $t_{interop}$ هو العبء الإضافي لاستدعاء الحدود مثل P/Invoke.&lt;/p>
&lt;p>عندما يكون $N$ كبيرًا بما يكفي، وبما أن $t_{overhead} \gg 0$ و $t_{compute}^{(PS)} > t_{compute}^{(C++)}$، فإن تفويض المعالجة إلى C++ (نقل الحمل) حتى مع دفع التكلفة الأولية $t_{interop}$ يقلل من زمن الوصول الإجمالي (latency) بشكل كبير.&lt;/p>
&lt;h3 id="2-الوصول-إلى-واجهات-برمجة-تطبيقات-win32-الأصلية">2. الوصول إلى واجهات برمجة تطبيقات Win32 الأصلية
&lt;/h3>&lt;p>على الرغم من أنه من الممكن استدعاء Win32 API عبر C# باستخدام &lt;code>Add-Type&lt;/code> في PowerShell وحده، إلا أنه من الصعب جدًا تعريف واجهات برمجة التطبيقات (APIs) التي تتضمن هياكل (structures) معقدة أو دوال رد الاتصال (callback functions) (مثل: التحكم في برامج تشغيل الفلتر المصغر، والمعالجة المتقدمة لذاكرة العملية) مباشرة في C# / PowerShell. من خلال إنشاء ملف DLL أصلي مغلف في C++ واستدعائه من PowerShell، يصبح التحكم في النظام آمنًا من حيث النوع وموثوقًا به ممكنًا.&lt;/p>
&lt;h2 id="استدعاء-ملف-dll-أصلي-بلغة-c-من-powershell">استدعاء ملف DLL أصلي بلغة C++ من PowerShell
&lt;/h2>&lt;p>نمط التكامل الأكثر شيوعًا هو تنفيذ المعالجة الثقيلة أو المعالجة الخاصة بالنظام كملف DLL بلغة C++، واستدعاء ذلك من سكربت PowerShell.&lt;/p>
&lt;h3 id="تنفيذ-ملف-dll-من-جانب-c-لـ-win32-api-والمنطق-المخصص">تنفيذ ملف DLL من جانب C++ (لـ Win32 API والمنطق المخصص)
&lt;/h3>&lt;p>أولاً، قم بإنشاء ملف DLL بلغة C++ يحتوي على دوال مُصدَّرة (exported functions) يمكن استدعاؤها من PowerShell. نعرض هنا رمز C++ بسيطًا يفترض &amp;ldquo;دالة تقوم بتشفير وفك تشفير بيانات السلاسل النصية الكبيرة الحجم، أو إجراء حسابات تجزئة (hash) معقدة&amp;rdquo; كمثال.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// NativeLib.cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;windows.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// تحديد رابط C و __stdcall لتسهيل الاستدعاء باستخدام P/Invoke
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">extern&lt;/span> &lt;span class="s">&amp;#34;C&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">__declspec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dllexport&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="kr">__stdcall&lt;/span> &lt;span class="n">ComputeHeavyTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">multiplier&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">dataSize&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// محاكاة لمعالجة ثقيلة متعمدة
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">dataSize&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">multiplier&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// دالة لمعالجة السلاسل النصية (استخدام LPWSTR لدعم Unicode)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">__declspec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dllexport&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="kr">__stdcall&lt;/span> &lt;span class="n">ProcessSystemString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">LPCWSTR&lt;/span> &lt;span class="n">inputString&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">LPWSTR&lt;/span> &lt;span class="n">outputBuffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">bufferSize&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">inputString&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">outputBuffer&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">inputString&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// بعض معالجات السلاسل النصية المعقدة (مثال: إضافة مُعرّف النظام)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;PROCESSED_&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">size_t&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">bufferSize&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// منع تجاوز سعة المخزن المؤقت (buffer overrun)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">wcscpy_s&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">outputBuffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bufferSize&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="إدارة-الذاكرة-وتحويل-السلاسل-النصية-bstr-lpwstr">إدارة الذاكرة وتحويل السلاسل النصية (&lt;code>BSTR&lt;/code>، &lt;code>LPWSTR&lt;/code>)
&lt;/h3>&lt;p>عند تبادل البيانات بين C++ و PowerShell (.NET)، فإن أهم ما يجب الانتباه إليه هو &lt;strong>ترميز السلاسل النصية (string encoding)&lt;/strong> و &lt;strong>إدارة الذاكرة&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>LPCWSTR&lt;/code> / &lt;code>LPWSTR&lt;/code>&lt;/strong>: مؤشر سلسلة نصية عريضة (UTF-16LE) في C/C++. يُستخدم بشكل قياسي في دوال نظام Windows API من نوع &lt;code>W&lt;/code>. في P/Invoke، من خلال تحديد &lt;code>CharSet = CharSet.Unicode&lt;/code>، يتم تنظيمه (marshaling) تلقائيًا باستخدام &lt;code>String&lt;/code> و &lt;code>StringBuilder&lt;/code> في .NET.&lt;/li>
&lt;li>&lt;strong>&lt;code>BSTR&lt;/code>&lt;/strong>: سلسلة نصية عريضة ببادئة الطول (length-prefixed) تُستخدم في COM (Component Object Model). يجب إدارة الذاكرة باستخدام &lt;code>SysAllocString&lt;/code> و &lt;code>SysFreeString&lt;/code>. حدد &lt;code>[MarshalAs(UnmanagedType.BStr)]&lt;/code> في P/Invoke.&lt;/li>
&lt;/ul>
&lt;p>عند تخصيص ذاكرة جديدة في جانب C++ وإعادتها إلى جانب PowerShell، تظهر مشكلة تحديد مَن سيقوم بتحرير الذاكرة (الملكية). في الدالة &lt;code>ProcessSystemString&lt;/code> أعلاه، نعتمد النمط القياسي لـ Win32 API حيث &amp;ldquo;يقوم C++ بكتابة النتيجة في المخزن المؤقت (buffer) (&lt;code>outputBuffer&lt;/code>) الذي تم تخصيصه مسبقًا بواسطة المتصل (PowerShell)&amp;rdquo;. هذا يمنع تسرب الذاكرة (memory leaks).&lt;/p>
&lt;h3 id="إضافة-الأنواع-بـ-add-type-و-pinvoke-من-جانب-powershell">إضافة الأنواع بـ &lt;code>Add-Type&lt;/code> و P/Invoke من جانب PowerShell
&lt;/h3>&lt;p>بمجرد تجميع ملف DLL الخاص بـ C++ (&lt;code>NativeLib.dll&lt;/code>)، استدعه من سكربت PowerShell. يمكنك الاستفادة من توقيع C# الخاص بـ P/Invoke وتجميعه ديناميكيًا باستخدام &lt;code>Add-Type&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># PowerShell Script: Invoke-NativeDLL.ps1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$signature&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="sh">@&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">using System;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">using System.Runtime.InteropServices;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">using System.Text;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">public class NativeInterop
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">{
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> // تعريف الدالة ComputeHeavyTask في C++
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> [DllImport(&amp;#34;NativeLib.dll&amp;#34;, CallingConvention = CallingConvention.StdCall)]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> public static extern int ComputeHeavyTask(int multiplier, int dataSize);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> // تعريف الدالة ProcessSystemString في C++
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> [DllImport(&amp;#34;NativeLib.dll&amp;#34;, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> public static extern bool ProcessSystemString(string inputString, StringBuilder outputBuffer, int bufferSize);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">}
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;#39;@&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># تجميع كود C# وإضافته إلى جلسة PowerShell&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Add-Type&lt;/span> &lt;span class="n">-TypeDefinition&lt;/span> &lt;span class="nv">$signature&lt;/span> &lt;span class="n">-PassThru&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Out-Null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. استدعاء العملية الحسابية الثقيلة&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">NativeInterop&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">ComputeHeavyTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">7&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">100000000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Compute Task Result: &lt;/span>&lt;span class="nv">$result&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 2. استدعاء معالجة السلسلة النصية&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$input&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;SYSTEM_NODE_001&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$bufferSize&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mf">256&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># استخدام StringBuilder كمخزن مؤقت للكتابة عليه من جانب C++&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$outputBuffer&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-Object&lt;/span> &lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">StringBuilder&lt;/span> &lt;span class="n">-ArgumentList&lt;/span> &lt;span class="nv">$bufferSize&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$success&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">NativeInterop&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">ProcessSystemString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nv">$input&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$outputBuffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$bufferSize&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$success&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Processed String: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$outputBuffer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToString&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;String processing failed.&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Red&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="عرض-المعمارية-مرئيا">عرض المعمارية مرئيًا
&lt;/h3>&lt;p>يوضح مخطط التسلسل (sequence diagram) التالي تدفق الاستدعاءات وتبادل الذاكرة من PowerShell إلى ملف C++ DLL.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant PS as &amp;#34;سكربت PowerShell&amp;#34;
participant CLR as &amp;#34;.NET CLR (P/Invoke)&amp;#34;
participant CPP as &amp;#34;ملف C++ Native DLL&amp;#34;
PS-&amp;gt;&amp;gt;CLR: &amp;#34;استدعاء ProcessSystemString&amp;#34;
note right of CLR: &amp;#34;تنظيم (Marshal) System.String إلى LPCWSTR&amp;#34;
note right of CLR: &amp;#34;تمرير مرجع StringBuilder&amp;#34;
CLR-&amp;gt;&amp;gt;CPP: &amp;#34;ProcessSystemString(LPCWSTR, LPWSTR, int)&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;تنفيذ معالجة السلسلة النصية الأصلية&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;كتابة النتيجة في المخزن المؤقت LPWSTR&amp;#34;
CPP--&amp;gt;&amp;gt;CLR: &amp;#34;إرجاع قيمة منطقية (نجاح)&amp;#34;
note left of CLR: &amp;#34;قراءة المخزن المؤقت StringBuilder المُعدَّل&amp;#34;
CLR--&amp;gt;&amp;gt;PS: &amp;#34;إرجاع التحكم في التنفيذ&amp;#34;
PS-&amp;gt;&amp;gt;PS: &amp;#34;إخراج السلسلة النصية المُعالَجة&amp;#34;
&lt;/pre>
&lt;h2 id="استدعاء-powershell-من-c">استدعاء PowerShell من C++
&lt;/h2>&lt;p>الآن سنتناول النهج العكسي. قد ترغب في تنفيذ سكربت PowerShell ديناميكيًا والحصول على النتيجة من خدمة نظام أو تطبيق سطح مكتب مبني باستخدام C++. على سبيل المثال، السيناريو الذي يتم فيه تنفيذ سكربت إصلاح عبر PowerShell عندما يكتشف وكيل المراقبة في C++ خللًا معينًا.&lt;/p>
&lt;p>هناك نهجان رئيسيان:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>بدء العملية (&lt;code>CreateProcess&lt;/code> / &lt;code>_popen&lt;/code>)&lt;/strong>: تشغيل &lt;code>powershell.exe&lt;/code> كعملية مستقلة وربط الإدخال والإخراج القياسي عبر الأنابيب (pipes).&lt;/li>
&lt;li>&lt;strong>واجهة برمجة تطبيقات استضافة PowerShell (عبر C++/CLI)&lt;/strong>: استضافة بيئة تشغيل PowerShell داخل نفس العملية.&lt;/li>
&lt;/ol>
&lt;p>في هذه المقالة، سنشرح طريقة &lt;strong>CreateProcess باستخدام خطوط الأنابيب (pipelines)&lt;/strong>، وهي الطريقة الأكثر قوة وتنوعًا في برمجة النظام.&lt;/p>
&lt;h3 id="التنفيذ-عبر-الأنابيب-المجهولة-و-createprocess">التنفيذ عبر الأنابيب المجهولة و CreateProcess
&lt;/h3>&lt;p>يقوم كود C++ التالي بإنشاء أنابيب مجهولة (Anonymous Pipes)، وتشغيل &lt;code>powershell.exe&lt;/code> كعملية فرعية لتنفيذ سكربت، ثم قراءة النتيجة من الإخراج القياسي.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;windows.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">ExecutePowerShellScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">script&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">HANDLE&lt;/span> &lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SECURITY_ATTRIBUTES&lt;/span> &lt;span class="n">sa&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">nLength&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">SECURITY_ATTRIBUTES&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">bInheritHandle&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TRUE&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// توريث مقبض الأنبوب للعملية الفرعية
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">sa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lpSecurityDescriptor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. إنشاء الأنبوب
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">CreatePipe&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">sa&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s">&amp;#34;Error: CreatePipe failed.&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. إعداد معلومات بدء التشغيل للعملية الفرعية (PowerShell)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">STARTUPINFOA&lt;/span> &lt;span class="n">si&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ZeroMemory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">si&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">STARTUPINFOA&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">cb&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">STARTUPINFOA&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">dwFlags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">STARTF_USESTDHANDLES&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">STARTF_USESHOWWINDOW&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hStdOutput&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hStdError&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">wShowWindow&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SW_HIDE&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// إخفاء النافذة
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROCESS_INFORMATION&lt;/span> &lt;span class="n">pi&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ZeroMemory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PROCESS_INFORMATION&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// بناء سطر الأوامر (نسخة مبسطة تتجنب تشفير Base64 وما إلى ذلك باستخدام سياسة Bypass)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">cmd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;powershell.exe -NoProfile -NonInteractive -Command &lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">script&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">cmdBuffer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cmd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">begin&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">cmd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">end&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cmdBuffer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push_back&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sc">&amp;#39;\0&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. إنشاء العملية
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">CreateProcessA&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cmdBuffer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TRUE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">si&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s">&amp;#34;Error: CreateProcess failed.&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// إغلاق أنبوب الكتابة في جانب العملية الأصلية لأنه غير مطلوب (عدم إغلاقه سيؤدي إلى حظر عملية القراءة)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 4. قراءة النتائج
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">DWORD&lt;/span> &lt;span class="n">bytesRead&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4096&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">ReadFile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buffer&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">bytesRead&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">bytesRead&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">buffer&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">bytesRead&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sc">&amp;#39;\0&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. التنظيف (Cleanup)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">WaitForSingleObject&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hProcess&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">INFINITE&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hProcess&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hThread&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// أمر PowerShell للحصول على قائمة العمليات وفرزها حسب استخدام وحدة المعالجة المركزية (CPU)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">psCommand&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 | Format-Table Name, CPU, Id&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Executing PowerShell from C++...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ExecutePowerShellScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">psCommand&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Result:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="التكامل-بين-سجل-windows-و-powershell">التكامل بين سجل Windows و PowerShell
&lt;/h3>&lt;p>عند تنفيذ سكربت من C++، يجب تجنب الترميز الثابت (hardcoding) لقيم الإعدادات الديناميكية أو مسارات التنفيذ. في كثير من الأحيان، تقرأ تطبيقات C++ إعداداتها من &lt;strong>سجل Windows (Windows Registry)&lt;/strong>.&lt;/p>
&lt;p>تُفضَّل معمارية في أنظمة المؤسسات حيث يستخدم جانب C++ &lt;code>RegOpenKeyEx&lt;/code> و &lt;code>RegQueryValueEx&lt;/code> لاسترداد مسار سكربت PowerShell من &lt;code>HKLM\SOFTWARE\MyApp&lt;/code> وتمريره كوسيطة لـ &lt;code>CreateProcess&lt;/code> المذكور أعلاه.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;خدمة وكيل C++&amp;#34;] --&amp;gt;|RegQueryValueEx| B[&amp;#34;سجل Windows&amp;#34;]
B --&amp;gt;|إرجاع مسار السكربت| A
A --&amp;gt;|CreateProcess| C[&amp;#34;powershell.exe&amp;#34;]
C --&amp;gt;|تنفيذ| D[&amp;#34;سكربت الإدارة (مثال: Restart-Service)&amp;#34;]
D --&amp;gt;|الإخراج القياسي (stdout) عبر الأنبوب| C
C --&amp;gt;|ReadFile| A
A --&amp;gt;|تسجيل| E[&amp;#34;عارض الأحداث / ملف السجل (Log)&amp;#34;]
&lt;/pre>
&lt;h2 id="تحليل-الأداء-ومزايا-نقل-الحمل-offloading">تحليل الأداء ومزايا نقل الحمل (Offloading)
&lt;/h2>&lt;p>لماذا نعتمد مثل هذه المعمارية المعقدة؟ كسيناريو محدد، دعونا نفكر في &amp;ldquo;تحليل ملفات سجل IIS المخصصة التي تصل مساحتها إلى عدة جيجابايت&amp;rdquo;.&lt;/p>
&lt;p>عند استخدام &lt;code>Get-Content&lt;/code> في PowerShell وتحليل سطر بسطر باستخدام التعبيرات النمطية (Regular Expressions)، يتم استهلاك قدر كبير من وقت وحدة المعالجة المركزية بسبب العبء الإضافي لإنشاء الكائنات وجمع القمامة (Garbage Collection أو GC).&lt;/p>
&lt;p>يتناسب عدد مرات تخصيص الذاكرة $A$ ومرات تشغيل GC $G$ في تنفيذ السكربت على النحو التالي.&lt;/p>
$$ G \propto \sum_{i=1}^{N} A_i $$&lt;p>عند نقل المعالجة إلى كود أصلي في C++، يمكن استخراج الملف بأكمله مباشرة في الذاكرة باستخدام تخطيط الذاكرة (Memory Mapping) (&lt;code>CreateFileMapping&lt;/code>, &lt;code>MapViewOfFile&lt;/code>)، وإجراء بحث عن السلاسل النصية بنسخ صفري (Zero-copy) عبر عمليات المؤشرات. في هذه الحالة، يصبح العبء الإضافي لإنشاء الكائنات فعليًا صفرًا، ويكتمل التحليل بسرعة تقترب من الحد الأقصى النظري لعرض النطاق الترددي للذاكرة.&lt;/p>
&lt;p>من خلال إرجاع النتيجة التي تم تحليلها فقط (مثال: قائمة عناوين IP للوصول غير المصرح به) إلى جانب PowerShell، يمكن أيضًا تقليل تكلفة تنظيم P/Invoke إلى الحد الأدنى.&lt;/p>
&lt;h2 id="سيناريوهات-عملية-لأتمتة-إدارة-النظام">سيناريوهات عملية لأتمتة إدارة النظام
&lt;/h2>&lt;h3 id="السيناريو-1-فحص-نظام-الملفات-وتغيير-الصلاحيات-بسرعة-فائقة">السيناريو 1: فحص نظام الملفات وتغيير الصلاحيات بسرعة فائقة
&lt;/h3>&lt;p>مهمة على خادم ملفات ضخم لاستخراج الملفات ذات الامتدادات المعينة والتي تم إعدادها بقائمة التحكم في الوصول (ACL) محددة، ثم تغيير أذوناتها دفعة واحدة.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>دور C++&lt;/strong>: اجتياز (traverse) شجرة الدلائل بسرعة فائقة باستخدام &lt;code>FindFirstFile&lt;/code> / &lt;code>FindNextFile&lt;/code> وتعدد مؤشرات الترابط (Multithreading)، وإنشاء قائمة بمسارات الملفات التي تستوفي الشروط.&lt;/li>
&lt;li>&lt;strong>دور PowerShell&lt;/strong>: تطبيق الأذونات دفعة واحدة على القائمة المستلمة من C++ باستخدام &lt;code>Set-Acl&lt;/code> (أو معالجة متكاملة مع Active Directory).&lt;/li>
&lt;/ul>
&lt;h3 id="السيناريو-2-جمع-معلومات-الأجهزة-المخصصة">السيناريو 2: جمع معلومات الأجهزة المخصصة
&lt;/h3>&lt;p>مراقبة معلومات الأجهزة المخصصة (مثل بطاقات PCIe الخاصة أو المستشعرات) التي لا يمكن استردادها بواسطة WMI (Windows Management Instrumentation) أو CIM (Common Information Model).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>دور C++&lt;/strong>: ملف DLL يستدعي &lt;code>DeviceIoControl&lt;/code> لبرامج تشغيل الأجهزة لاسترداد وتحليل البيانات الثنائية.&lt;/li>
&lt;li>&lt;strong>دور PowerShell&lt;/strong>: استدعاء ملف DLL بانتظام، وتنسيق نتائج التحليل بتنسيق JSON، وإرسالها إلى REST API الخاص بخادم المراقبة.&lt;/li>
&lt;/ul>
&lt;h2 id="أفضل-الممارسات-لإدارة-الذاكرة-واستكشاف-الأخطاء-وإصلاحها">أفضل الممارسات لإدارة الذاكرة واستكشاف الأخطاء وإصلاحها
&lt;/h2>&lt;p>أكثر الأخطاء (bugs) شيوعًا في عملية التكامل هي &lt;strong>تسرب الذاكرة (Memory Leaks)&lt;/strong> و &lt;strong>انتهاكات الوصول (Access Violation: 0xC0000005)&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>صلاحية المؤشر (Pointer Lifetime)&lt;/strong>: عند تمرير &lt;code>[ref]&lt;/code> أو &lt;code>StringBuilder&lt;/code> في جانب PowerShell، يقوم P/Invoke بتثبيت (Pin) هذه الذاكرة فقط أثناء الاستدعاء. يجب ألا تحفظ هذا المؤشر في متغير عام على جانب C++ للوصول إليه لاحقًا. إذا كنت تجري استدعاءات غير متزامنة (asynchronous callbacks)، فيجب عليك استخدام &lt;code>GCHandle&lt;/code> لتثبيت الذاكرة بشكل صريح.&lt;/li>
&lt;li>&lt;strong>حجم المؤشر في بيئة 64 بت&lt;/strong>: أنظمة Windows الحديثة تعتمد بشكل أساسي على 64 بت (x64). حجم المؤشر في جانب C++ هو 8 بايت، ويجب استخدام &lt;code>IntPtr&lt;/code> في جانب PowerShell (.NET). نظرًا لأن &lt;code>long&lt;/code> في C++ يبلغ 4 بايت في Windows، فإن الكود القديم الذي يحول المؤشرات إلى &lt;code>long&lt;/code> ويمررها سيؤدي إلى انهيار النظام.&lt;/li>
&lt;li>&lt;strong>عدم تطابق ترميز السلاسل النصية&lt;/strong>: يستخدم PowerShell ترميز UTF-16 داخليًا. إذا حاولت استلام السلسلة كسلسلة ANSI (&lt;code>std::string&lt;/code>، &lt;code>char*&lt;/code>) في جانب C++، فستظهر أحرف غير مفهومة (Mojibake). استخدم دائمًا السلاسل العريضة (&lt;code>std::wstring&lt;/code>، &lt;code>wchar_t*&lt;/code>) وحدد &lt;code>CharSet = CharSet.Unicode&lt;/code> على جانب P/Invoke أيضًا.&lt;/li>
&lt;/ol>
&lt;h2 id="الخلاصة">الخلاصة
&lt;/h2>&lt;p>يعد التكامل بين PowerShell و C++ المزيج الأمثل في أتمتة إدارة النظام، حيث يجمع بين سهولة لغات السكربتات وقوة اللغات الأصلية (Native).&lt;/p>
&lt;p>من خلال استدعاء C++ DLLs باستخدام P/Invoke، يمكنك نقل المهام التي تتطلب قوة حوسبة عالية (offload) وتقليل وقت التنفيذ بشكل كبير. على العكس من ذلك، يمكنك تقليل تكاليف التطوير بشكل كبير من خلال الاستفادة من وحدات إدارة النظام الغنية في PowerShell من تطبيقات C++ عبر إطلاق العمليات أو الأنابيب.&lt;/p>
&lt;p>وعلى الرغم من الحاجة إلى الحذر فيما يتعلق بإدارة الذاكرة وتحويل السلاسل النصية عند نقاط الحدود (boundaries)، فإن إتقان أنماط المعمارية وتقنيات التنفيذ المقدمة في هذه المقالة سيمكنك من بناء أدوات إدارة نظام Windows أكثر تقدمًا وقوة.&lt;/p>
&lt;hr>
&lt;p>&lt;em>في هذه المدونة التقنية، سنستمر في تغطية مواضيع عميقة تتعلق بالبنية الداخلية لنظام Windows والأتمتة المتقدمة. إذا كان لديك أي أسئلة أو تعليقات، فلا تتردد في تركها في قسم التعليقات.&lt;/em>&lt;/p></description></item><item><title>ما يجب على المهندسين فعله لزيادة الزيارات الشهرية للمدونات التقنية</title><link>http://kenji.blog/ar/p/tech-blog-growth-strategies-for-engineers/</link><pubDate>Sat, 12 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/tech-blog-growth-strategies-for-engineers/</guid><description>&lt;img src="http://kenji.blog/p/tech-blog-growth-strategies-for-engineers/img/eyecatch.jpg" alt="Featured image of post ما يجب على المهندسين فعله لزيادة الزيارات الشهرية للمدونات التقنية" />&lt;h2 id="مقدمة-نمو-المدونات-التقنية-الذي-يمكن-للمهندسين-فقط-تحقيقه">مقدمة: نمو المدونات التقنية الذي يمكن للمهندسين فقط تحقيقه
&lt;/h2>&lt;p>يبدأ العديد من مهندسي البرمجيات في إنشاء مدونات تقنية، ولكن الحالات التي تنجح في جذب عدد معين من الزيارات والحفاظ عليها وتوسيعها على المدى الطويل ليست كثيرة. إن كتابة مقالات تقنية عالية الجودة هي شرط أساسي، ولكن عصر &amp;ldquo;اكتب مقالاً جيداً وسيُقرأ بشكل طبيعي&amp;rdquo; قد انتهى بالفعل. أصبحت خوارزميات محركات البحث الحالية أكثر تعقيداً، كما أصبح تدفق المعلومات على وسائل التواصل الاجتماعي أسرع من أي وقت مضى.&lt;/p>
&lt;p>ومع ذلك، يتمتع المهندسون بنقاط قوة لا يمتلكها أصحاب المهن الأخرى. وهي &amp;ldquo;فهم بنية الأنظمة، والجمع بين الأدوات للأتمتة، وتحليل البيانات برمجياً&amp;rdquo;. في هذا المقال، بدلاً من الاقتصار على مجرد تقنيات الكتابة، سنتعامل مع المدونة التقنية كـ &amp;ldquo;منتج&amp;rdquo; واحد، وسنشرح بتفصيل شديد وعملي استراتيجيات لزيادة الزيارات الشهرية بشكل كبير باستخدام قوة الهندسة.&lt;/p>
&lt;hr>
&lt;h2 id="1-بنية-seo-للمدونات-التقنية-الموجهة-للمهندسين">1. بنية SEO للمدونات التقنية الموجهة للمهندسين
&lt;/h2>&lt;p>يعد النظام الأساسي للمدونة (مثل مولدات المواقع الثابتة) وهيكل HTML من أهم العوامل لمحركات البحث لتفسير المحتوى بشكل صحيح.&lt;/p>
&lt;h3 id="11-تحسين-core-web-vitals">1.1 تحسين Core Web Vitals
&lt;/h3>&lt;p>تستخدم Google تجربة الصفحة كعامل ترتيب، ولا يمكن تجاهل &lt;strong>Core Web Vitals (LCP, FID/INP, CLS)&lt;/strong> في المدونات التقنية بشكل خاص.
في المدونات التقنية، يتم استخدام الكثير من كتل التعليمات البرمجية المصدرية والمعادلات الرياضية (MathJax / KaTeX) والرسوم التوضيحية. هذه العوامل تؤخر عرض الصفحة.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LCP (Largest Contentful Paint)&lt;/strong>: سرعة تحميل المحتوى الرئيسي في شاشة العرض الأولى. استخدم WebP أو AVIF للصورة البارزة (eyecatch)، وقم بالتحميل المسبق لها عن طريق إضافة خاصية &lt;code>fetchpriority=&amp;quot;high&amp;quot;&lt;/code>. بالإضافة إلى ذلك، اجعل ملفات CSS أو JS الضخمة المستخدمة في تمييز بناء الجملة (syntax highlighting) تُحمل بشكل غير متزامن، أو صممها بحيث تُحمل فقط في الصفحات التي تحتاج إليها.&lt;/li>
&lt;li>&lt;strong>CLS (Cumulative Layout Shift)&lt;/strong>: انزياح التخطيط أثناء تحميل المقال. من خلال تخصيص مساحة عرض المعادلات والصور مسبقاً باستخدام &lt;code>aspect-ratio&lt;/code> في CSS وما إلى ذلك، يمكنك منع الاهتزاز الذي يحدث عند إدراج DOM لاحقاً.&lt;/li>
&lt;li>&lt;strong>INP (Interaction to Next Paint)&lt;/strong>: الاستجابة لتفاعلات المستخدم. من الضروري عدم تشغيل JavaScript الثقيلة (على سبيل المثال، البحث الديناميكي عن النص الكامل من جانب العميل، أو تنفيذ محلل Markdown ضخم) في السلسلة (thread) الرئيسية، بل نقلها إلى Web Worker أو إنشائها كـ HTML ثابت (SSG) أثناء عملية البناء.&lt;/li>
&lt;/ul>
&lt;h3 id="12-تنفيذ-البيانات-المنظمة-json-ld">1.2 تنفيذ البيانات المنظمة (JSON-LD)
&lt;/h3>&lt;p>لإبلاغ محركات البحث بشكل صريح بأن الصفحة عبارة عن &amp;ldquo;مقال&amp;rdquo; ومن هو &amp;ldquo;المؤلف&amp;rdquo;، نقوم بتنفيذ البيانات المنظمة بتنسيق JSON-LD. من خلال الاستفادة من المخططات (schemas) مثل &lt;code>TechArticle&lt;/code> و &lt;code>SoftwareSourceCode&lt;/code>، يصبح من الأسهل ظهورها في النتائج المنسقة (Rich Results) لـ Google، مما يحسن نسبة النقر إلى الظهور (CTR).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;application/ld+json&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@context&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://schema.org&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;TechArticle&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;headline&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ما يجب على المهندسين فعله لزيادة الزيارات الشهرية للمدونات التقنية&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;image&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;https://example.com/img/eyecatch.jpg&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;datePublished&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;2026-09-14T10:00:00+09:00&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;author&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Person&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Kenji&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://example.com/about/&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;publisher&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Organization&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Kenji&amp;#39;s Tech Blog&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;logo&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;@type&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;ImageObject&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;url&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://example.com/img/logo.png&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="13-تحسين-html-الدلالي-وهيكل-المستند">1.3 تحسين HTML الدلالي وهيكل المستند
&lt;/h3>&lt;p>يعد التداخل المناسب للعناوين (&lt;code>h1&lt;/code> إلى &lt;code>h6&lt;/code>) من الأساسيات، ولكن في المدونات التقنية، يُطلب الاستخدام الدقيق للعلامات الدلالية في HTML5 مثل &lt;code>article&lt;/code>، &lt;code>section&lt;/code>، &lt;code>aside&lt;/code>، و &lt;code>nav&lt;/code>. بالإضافة إلى ذلك، من خلال الاستخدام المناسب لـ &lt;code>&amp;lt;code&amp;gt;&lt;/code> و &lt;code>&amp;lt;pre&amp;gt;&lt;/code> للإشارة إلى التعليمات البرمجية المصدرية، و &lt;code>&amp;lt;kbd&amp;gt;&lt;/code> لإدخال لوحة المفاتيح، و &lt;code>&amp;lt;var&amp;gt;&lt;/code> للمتغيرات، يمكنك تقديم HTML قابل للقراءة آلياً. وتُعد هذه أيضاً وسيلة فعّالة جداً لفهرسة المحتوى بواسطة الذكاء الاصطناعي (جمع بيانات التدريب لنماذج LLM أو أنظمة RAG).&lt;/p>
&lt;hr>
&lt;h2 id="2-سيكولوجية-نية-البحث-search-intent-واستراتيجية-الكلمات-المفتاحية">2. سيكولوجية نية البحث (Search Intent) واستراتيجية الكلمات المفتاحية
&lt;/h2>&lt;p>لتحقيق أقصى قدر من الزيارات القادمة من محركات البحث (الزيارات العضوية)، من الضروري الفهم الدقيق لنية البحث، أي &amp;ldquo;لماذا بحث المستخدم بهذه الكلمة المفتاحية&amp;rdquo;. يمكن تقسيم نية البحث في المجال التقني إلى فئتين رئيسيتين.&lt;/p>
&lt;h3 id="21-نوع-حل-الأخطاء-ونوع-التعلم-المنهجي-والمراجعة">2.1 &amp;ldquo;نوع حل الأخطاء&amp;rdquo; و&amp;quot;نوع التعلم المنهجي والمراجعة&amp;quot;
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>نوع حل الأخطاء (Troubleshooting Intent)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>أمثلة على الكلمات المفتاحية للبحث: &lt;code>Docker &amp;quot;no space left on device&amp;quot; حل&lt;/code>, &lt;code>Python IndexError list index out of range سبب&lt;/code>&lt;/li>
&lt;li>الحالة النفسية: المستخدم عالق بسبب خطأ أثناء التطوير، ويبحث عن أوامر أو مقتطفات برمجية لتكون كعلاج فوري.&lt;/li>
&lt;li>الاستراتيجية: قدم &amp;ldquo;الاستنتاج (التعليمات البرمجية أو الأوامر لحل المشكلة)&amp;rdquo; في بداية المقال (شاشة العرض الأولى). ضع شرح الخلفية والآليات التفصيلية بعد ذلك، وقم بتلبية رغبة المستخدم في &amp;ldquo;إصلاح المشكلة فوراً&amp;rdquo; أولاً. هذا يمكن أن يقلل من معدل الارتداد (Bounce Rate).&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>نوع التعلم المنهجي والمراجعة (Learning &amp;amp; Review Intent)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>أمثلة على الكلمات المفتاحية للبحث: &lt;code>React مقابل Vue 2026 مقارنة&lt;/code>, &lt;code>مقدمة في المعالجة غير المتزامنة Rust&lt;/code>, &lt;code>تصميم بنية الشبكة GCP&lt;/code>&lt;/li>
&lt;li>الحالة النفسية: يفكر المستخدم في اختيار حزمة تقنية جديدة، أو تعميق فهمه من الأساسيات، وهو مستعد لقضاء بعض الوقت في القراءة.&lt;/li>
&lt;li>الاستراتيجية: قم بإثراء جدول المحتويات (TOC)، واستخدم الكثير من الرسوم التوضيحية ومخططات البنية (Mermaid وغيرها). من خلال المقارنة الموضوعية بين الإيجابيات والسلبيات، وتضمين حالات الاستخدام حول كيفية استخدامها في العمل الفعلي، يمكنك زيادة وقت البقاء في الصفحة.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h3 id="22-نموذج-التدهور-الأسي-للزيارات-واستراتيجية-الذيل-الطويل-long-tail">2.2 نموذج التدهور الأسي للزيارات واستراتيجية الذيل الطويل (Long-Tail)
&lt;/h3>&lt;p>تميل أعداد الزيارات للمقالات التقنية إلى تشكيل ذروة مفاجئة (spike) بسبب انتشارها الواسع على وسائل التواصل الاجتماعي فور نشرها، ثم تنخفض بشكل أسي بعد ذلك. يمكن تقريب هذه الزيارات $V(t)$ بالنموذج الرياضي التالي.&lt;/p>
$$ V(t) = V_0 e^{-\lambda t} + C $$&lt;p>حيث:&lt;/p>
&lt;ul>
&lt;li>$V(t)$: حجم الزيارات في الوقت $t$&lt;/li>
&lt;li>$V_0$: حجم ذروة الزيارات الأولية الناتجة عن الانتشار على وسائل التواصل الاجتماعي فور النشر&lt;/li>
&lt;li>$\lambda$: ثابت التدهور المصاحب لتقادم المحتوى أو النسيان على وسائل التواصل الاجتماعي (يعتمد على سرعة تغير الاتجاهات التقنية)&lt;/li>
&lt;li>$C$: الزيارات العضوية المستقرة القادمة من محركات البحث (خط الأساس للزيارات)&lt;/li>
&lt;/ul>
&lt;p>إن مفتاح زيادة الزيارات على المدى الطويل لا يكمن في استهداف الانتشار المؤقت ($V_0$)، بل في &lt;strong>كيفية تكبير الحد الثابت $C$ (الزيارات المستمرة من محركات البحث)&lt;/strong>. من خلال تغطية عدد كبير من &amp;ldquo;الكلمات المفتاحية ذات الذيل الطويل&amp;rdquo; التي تتميز بحجم بحث منخفض ولكن لا توجد منافسة عليها، مثل أخطاء متخصصة معينة أو طرق ربط بين أدوات معينة، نقوم بتنمية مجموع $C$ ليصبح ضخماً.&lt;/p>
&lt;hr>
&lt;h2 id="3-تحليل-المحتوى-الموجه-بالبيانات-باستخدام-gsc-api">3. تحليل المحتوى الموجه بالبيانات باستخدام GSC API
&lt;/h2>&lt;p>لبناء قاعدة زيارات مستقرة $C$، من الضروري الاستفادة من بيانات Google Search Console (GSC) وتحليل &amp;ldquo;كيف يتم تقييمنا من قبل Google&amp;rdquo; بشكل موضوعي. ومع ذلك، هناك حدود للاعتماد على النقرات اليدوية في واجهة مستخدم الويب لـ GSC. بصفتك مهندساً، يجب عليك أتمتة التحليل باستخدام GSC API و Python.&lt;/p>
&lt;h3 id="31-نهج-الأتمتة-باستخدام-gsc-api-و-python">3.1 نهج الأتمتة باستخدام GSC API و Python
&lt;/h3>&lt;p>سنقوم بإنشاء برنامج نصي يكتشف تلقائياً كيفية انخفاض ترتيب البحث لمقال معين بمرور الوقت (Decaying Content)، أو يكتشف &amp;ldquo;المقالات المهدرة&amp;rdquo; التي تحظى بعدد مرات ظهور كبير (impressions) ولكن نسبة النقر إلى الظهور (CTR) منخفضة بشكل غير طبيعي.
لهذا سنستخدم &lt;code>google-api-python-client&lt;/code> و &lt;code>pandas&lt;/code>.&lt;/p>
&lt;h3 id="32-الكود-البرمجي-بـ-python-الاستخراج-التلقائي-للمحتوى-ذي-الـ-ctr-المنخفض">3.2 الكود البرمجي بـ Python: الاستخراج التلقائي للمحتوى ذي الـ CTR المنخفض
&lt;/h3>&lt;p>فيما يلي مثال لبرنامج نصي يجلب بيانات أداء البحث لآخر 30 يوماً من API، ويستخرج &amp;ldquo;الكلمات المفتاحية وروابط المقالات التي لديها مجال كبير لتحسين العناوين أو الأوصاف&amp;rdquo;، حيث تكون مرات الظهور 1000 أو أكثر ونسبة CTR أقل من 2٪.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pandas&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">pd&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">google.oauth2&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">service_account&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">googleapiclient.discovery&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. المصادقة وبناء خدمة API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">KEY_FILE_LOCATION&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;path/to/your-service-account-key.json&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SCOPES&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;https://www.googleapis.com/auth/webmasters.readonly&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SITE_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s1">&amp;#39;https://your-tech-blog.com/&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">credentials&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">service_account&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Credentials&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_service_account_file&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">KEY_FILE_LOCATION&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">scopes&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">SCOPES&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">webmasters_service&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">build&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;searchconsole&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;v1&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">credentials&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">credentials&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. حساب فترة الطلب (آخر 30 يوماً)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">today&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">date&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">today&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">end_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">today&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timedelta&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">days&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">start_date&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">today&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">datetime&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">timedelta&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">days&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strftime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;%Y-%m-&lt;/span>&lt;span class="si">%d&lt;/span>&lt;span class="s1">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. تنفيذ طلب API&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">request&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;startDate&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">start_date&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;endDate&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">end_date&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;dimensions&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;query&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;rowLimit&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">5000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">webmasters_service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">searchanalytics&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">siteUrl&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">SITE_URL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">body&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">request&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. معالجة البيانات وتصفيتها باستخدام Pandas DataFrame&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="s1">&amp;#39;rows&amp;#39;&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rows&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;rows&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">row&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">rows&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">append&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Query&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;keys&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;URL&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;keys&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Clicks&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;clicks&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Impressions&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;impressions&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;CTR&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;ctr&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;Position&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">row&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;position&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pd&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DataFrame&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># شروط التصفية: مرات الظهور 1000 أو أكثر و CTR أقل من 2٪&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">df&lt;/span>&lt;span class="p">[(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;Impressions&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">df&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;CTR&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mf">0.02&lt;/span>&lt;span class="p">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># الترتيب التصاعدي للموضع (إعطاء الأولوية لتلك التي ترتيبها عالٍ ولكن لا يتم النقر عليها)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_df&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">target_df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sort_values&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">by&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;Position&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ascending&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【القائمة الموصى بها لتحسين العنوان/الوصف التعريفي】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">target_df&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">head&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># تصدير إلى CSV وغيرها عند الحاجة&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># target_df.to_csv(&amp;#39;improve_candidates.csv&amp;#39;, index=False)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;لم يتم العثور على بيانات.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>من خلال تشغيل هذا البرنامج النصي كوظيفة دورية في cron أو GitHub Actions، يمكنك دائماً اتخاذ قرار يعتمد على البيانات حول &amp;ldquo;المقالات التي يجب إعادة كتابة عناوينها&amp;rdquo;. بدلاً من الاعتماد على الحدس، من المهم إجراء تحسين مستمر بناءً على البيانات (التحسين المستمر للمحتوى Continuous Content Improvement وليس فقط CI/CD).&lt;/p>
&lt;hr>
&lt;h2 id="4-إدارة-دورة-حياة-المقال-واستراتيجية-إعادة-الكتابة">4. إدارة دورة حياة المقال واستراتيجية إعادة الكتابة
&lt;/h2>&lt;p>لا تنتهي المقالة التقنية بمجرد نشرها. مع تطور التكنولوجيا (تحديث إصدارات إطارات العمل، إيقاف واجهات برمجة التطبيقات وما إلى ذلك)، يصبح المحتوى قديماً بسرعة. الاستمرار في تقديم معلومات قديمة لا يضر بمصداقية المدونة فحسب، بل يؤثر سلباً على تقييم SEO.&lt;/p>
&lt;h3 id="41-إدارة-دورة-حياة-المحتوى-مخطط-جانت">4.1 إدارة دورة حياة المحتوى (مخطط جانت)
&lt;/h3>&lt;p>يوضح مخطط جانت بـ Mermaid دورة الحياة المثالية لتشغيل المحتوى.&lt;/p>
&lt;pre class="mermaid">
gantt
title إدارة دورة حياة المحتوى الموجهة بالبيانات
dateFormat YYYY-MM-DD
axisFormat %m/%d
section &amp;#34;المرحلة 1: التخطيط والكتابة&amp;#34;
&amp;#34;تحليل الكلمات المفتاحية والاتجاهات للبحث&amp;#34; :a1, 2026-09-01, 3d
&amp;#34;المسودة والتحقق من الكود&amp;#34; :a2, after a1, 5d
&amp;#34;المراجعة والتدقيق&amp;#34; :a3, after a2, 2d
section &amp;#34;المرحلة 2: النشر والترويج&amp;#34;
&amp;#34;النشر باستخدام مسار CI/CD&amp;#34; :p1, 2026-09-11, 1d
&amp;#34;التوزيع التلقائي على وسائل التواصل (X, LinkedIn, RSS)&amp;#34; :p2, 2026-09-11, 1d
&amp;#34;الانتشار إلى إشارات مرجعية مثل Hatena Bookmark&amp;#34; :p3, after p2, 3d
section &amp;#34;المرحلة 3: المراقبة والتحليل&amp;#34;
&amp;#34;فترة تجميع بيانات GSC&amp;#34; :m1, 2026-09-14, 28d
&amp;#34;تقييم الأداء باستخدام Python API&amp;#34;:m2, after m1, 2d
section &amp;#34;المرحلة 4: التحسين (إعادة الكتابة)&amp;#34;
&amp;#34;تعديل عناوين المقالات ذات CTR المنخفض&amp;#34; :r1, after m2, 3d
&amp;#34;تحديث الأكواد لأحدث الإصدارات&amp;#34;:r2, after r1, 4d
&lt;/pre>
&lt;p>بهذه الطريقة، فإن التعامل مع إنشاء المقال كمشروع تطوير برمجيات واحد، وإدراج مرحلة التشغيل والصيانة (إعادة الكتابة) بعد الإصدار في الخطة، هو سر الحفاظ على الزيارات وتحسينها.&lt;/p>
&lt;h3 id="42-النموذج-الرياضي-للعائد-على-الاستثمار-roi-لإنشاء-المحتوى">4.2 النموذج الرياضي للعائد على الاستثمار (ROI) لإنشاء المحتوى
&lt;/h3>&lt;p>بما أن المهندس يخصص وقته الثمين لكتابة مقال، فيجب أن يكون واعياً بالعائد على هذا الاستثمار (ROI).
يمكن صياغة ROI في المدونة على النحو التالي.&lt;/p>
$$ ROI = \frac{\sum_{t=1}^{T} \left( Rev_{ad}(t) + Val_{brand}(t) + Val_{skill}(t) \right) - Cost_{time}}{\text{Cost}_{time}} \times 100 \ (\%) $$&lt;ul>
&lt;li>$T$: العمر الافتراضي الفعال للمقال (الفترة حتى يصبح قديماً)&lt;/li>
&lt;li>$Rev_{ad}(t)$: العوائد المباشرة من إيرادات الإعلانات أو إيرادات التسويق بالعمولة أو الرعاية&lt;/li>
&lt;li>$Val_{brand}(t)$: القيمة المالية المحولة للتأثير الإيجابي على المسار المهني (زيادة قيمة العروض عند تغيير الوظيفة، طلبات إلقاء محاضرات، إلخ) نتيجة إبراز المهارات التقنية&lt;/li>
&lt;li>$Val_{skill}(t)$: القيمة المضافة لتطوير مهاراتك الذاتية نتيجة التعلم والبحث الذي قمت به من أجل كتابة المقال&lt;/li>
&lt;li>$Cost_{time}$: الوقت المستغرق في كتابة المقال، وإنشاء الرسوم التوضيحية، والتحقق من الكود (محسوباً بأجرك بالساعة)&lt;/li>
&lt;/ul>
&lt;p>الشيء الرائع في المدونات التقنية هو أنه حتى لو كان $Rev_{ad}$ صغيراً، فإن $Val_{brand}$ و $Val_{skill}$ يميلان إلى أن يكونا كبيرين جداً. على وجه الخصوص، الشروحات التقنية عالية الجودة تصبح بحد ذاتها ملف أعمال (Portfolio)، ولها تأثير هائل في البحث عن عمل أو الحصول على أعمال جانبية.&lt;/p>
&lt;hr>
&lt;h2 id="5-التوزيع-باستخدام-github-actions-والتكامل-مع-أدوات-الأتمتة-الخارجية">5. التوزيع باستخدام GitHub Actions والتكامل مع أدوات الأتمتة الخارجية
&lt;/h2>&lt;p>بعد إنشاء المحتوى، يصبح التحدي هو كيفية إيصاله بكفاءة إلى الجمهور المستهدف (التوزيع). من غير الفعال نشر الروابط يدوياً على كل شبكة اجتماعية في كل مرة، وهذا ليس من شيم المهندسين.&lt;/p>
&lt;h3 id="51-بنية-أتمتة-مشاركة-وسائل-التواصل-الاجتماعي">5.1 بنية أتمتة مشاركة وسائل التواصل الاجتماعي
&lt;/h3>&lt;p>سنقوم ببناء بنية أتمتة كاملة تبدأ من لحظة دمج ملف Markdown في فرع main في مستودع GitHub، لتشمل البناء والنشر والإعلان عبر منصات متعددة.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;المطور (Git Push)&amp;#34;] --&amp;gt; B[&amp;#34;مستودع GitHub&amp;#34;]
B --&amp;gt;|Webhook| C[&amp;#34;GitHub Actions (CI/CD)&amp;#34;]
C --&amp;gt;|Build| D[&amp;#34;مولد المواقع الثابتة (Hugo/Gatsby)&amp;#34;]
D --&amp;gt;|Deploy| E[&amp;#34;الاستضافة (Vercel / Cloudflare Pages)&amp;#34;]
D --&amp;gt;|Generate| F[&amp;#34;موجز RSS (index.xml)&amp;#34;]
F --&amp;gt;|Polled by| G[&amp;#34;Zapier / IFTTT / Make&amp;#34;]
G --&amp;gt;|API Call| H[&amp;#34;نشر تلقائي على X (Twitter)&amp;#34;]
G --&amp;gt;|API Call| I[&amp;#34;نشر مقال على LinkedIn&amp;#34;]
G --&amp;gt;|API Call| J[&amp;#34;Webhook لمجتمع Discord / Slack&amp;#34;]
C --&amp;gt;|Actions Script| K[&amp;#34;API النشر المتبادل عبر Qiita / Zenn&amp;#34;]
&lt;/pre>
&lt;h3 id="52-النقاط-الأساسية-في-بناء-مسار-الأتمتة">5.2 النقاط الأساسية في بناء مسار الأتمتة
&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>البناء والنشر باستخدام GitHub Actions&lt;/strong>
إذا كنت تستخدم مولد مواقع ثابتة، فاستخدم GitHub Actions لأتمتة إنشاء HTML ونشره على وجهة الاستضافة (Vercel، Netlify، Cloudflare Pages، وما إلى ذلك). في هذه الحالة، كتدبير لـ Core Web Vitals المذكور سابقاً، من الفعال أيضاً دمج عملية تحسين الصور (مثل التحويل التلقائي إلى WebP) في مسار البناء.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>ربط وسائل التواصل الاجتماعي عبر مشغلات RSS باستخدام Zapier/IFTTT&lt;/strong>
يقوم مولد الموقع بإنشاء أحدث موجز RSS (XML) أثناء البناء. يمكنك إدخال هذا في منصات iPaaS مثل Zapier أو Make (المعروفة سابقاً باسم Integromat) وإنشاء سير عمل يقول &amp;ldquo;عند إضافة عنصر جديد إلى RSS، قم بنشر العنوان والرابط على X (Twitter) و LinkedIn&amp;rdquo;. بهذه الطريقة، يتم إشعار المتابعين تلقائياً في نفس اللحظة التي يتم فيها نشر المقال.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>النشر المتبادل إلى Qiita/Zenn (استخدام العلامات الأساسية Canonical tags)&lt;/strong>
بينما لا تزال قوة نطاق مدونتك الخاصة أو الشخصية ضعيفة، فإن إحدى الاستراتيجيات هي استعارة قوة الجذب لمنصات تقنية مثل Qiita و Zenn. ومع ذلك، فإن مجرد النسخ واللصق يحمل خطر التعرض لعقوبة من قِبل محركات البحث (SEO) بسبب المحتوى المكرر.
يمكن حل هذه المشكلة عن طريق تعيين &lt;strong>علامة Canonical&lt;/strong> في البيانات الوصفية لمقالات Qiita أو Zenn، وتحديد عنوان URL للمقال الأصلي على مدونتك. من خلال برمجة نصية تستدعي واجهات برمجة التطبيقات لمختلف المنصات من GitHub Actions وتولد مقالات تلقائياً من Markdown، يمكنك أتمتة النشر بالكامل عبر قنوات متعددة.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="خاتمة-تدوير-عجلة-التحسين-المستمر">خاتمة: تدوير عجلة التحسين المستمر
&lt;/h2>&lt;p>من أجل زيادة الزيارات الشهرية للمدونة التقنية بشكل كبير، فإنه بالإضافة إلى فعل &amp;ldquo;الكتابة&amp;rdquo;، من الضروري اتباع نهج هندسي مثل الذي قدمناه هذه المرة.&lt;/p>
&lt;ol>
&lt;li>بناء بنية موقع و HTML قوية مع مراعاة SEO&lt;/li>
&lt;li>تصميم مقالات تتفهم نية بحث المستخدم (حل الأخطاء مقابل التعلم المنهجي)&lt;/li>
&lt;li>تحليل البيانات باستخدام Google Search Console API و Python&lt;/li>
&lt;li>إدارة دورة حياة المحتوى وإعادة كتابته مع مراعاة ROI&lt;/li>
&lt;li>الأتمتة الكاملة للتوزيع باستخدام تكامل CI/CD و Zapier&lt;/li>
&lt;/ol>
&lt;p>إذا تمكنت من تجميع هذه العناصر في نظام متكامل، فستصبح مدونتك التقنية أقوى أصل (Asset) يدعم مسيرتك المهنية بقوة. بالنسبة للمهندسين الذين يعانون من ركود في أعداد الزيارات، نرجو منكم البدء بـ &amp;ldquo;نمو المدونة (Growth Hack)&amp;rdquo; من اليوم. إن مهارات البرمجة وقدرات تصميم البنية التي اكتسبتها من أعمال التطوير ستكون بلا شك أقوى سلاح لك في إدارة المدونة.&lt;/p></description></item></channel></rss>