مجموعة أوامر PowerShell العمليّة ── إضافة وظائف صغيرة شائعة الاستخدام في العمل اليوميّ

· آخر تحديث: · · PowerShell, Windows, سطر الأوامر, الأتمتة, تحسين كفاءة العمل, الاستفادة من الأصول القائمة

1. الأساسيّات الواجب الإلمام بها أوّلاً

بعد إتقان أساسيّات PowerShell، تصبح الخطوة التالية هي زيادة «الوظائف الصغيرة الشائعة الاستخدام»، ما يجعله أسهل استخداماً في العمل الفعليّ.

المقصود هنا بالوظائف الصغيرة ليس الأسماء المستعارة (aliases) القصيرة. في هذا المقال، لن نستخدم اختصارات مثل ls أو cat، بل أسماء الأوامر الرسميّة مثل Get-ChildItem وGet-Content وSelect-String.

وبناءً على ذلك، سنجعل من الممكن تنفيذ الأعمال التالية بسطر واحد أو بضعة أسطر من الأوامر.

عدّ العناصر
معرفة الحجم الإجماليّ
حذف التكرارات
التجميع حسب النوع
استخراج القيم المطلوبة فقط
مقارنة نتيجتين
عرض الأسطر المحيطة في السجلّ (log)
الإرسال إلى الحافظة (clipboard)
حفظ نتيجة التنفيذ مع عرضها على الشاشة في آنٍ واحد
التحقّق من متغيّرات البيئة والشبكة

PowerShell مفيد حتّى دون كتابة سكربتات طويلة. لنبدأ بزيادة «القطع الشائعة الاستخدام»، بحيث يمكن تركيبها تدريجيّاً في العمل اليوميّ.

الأهمّ ليس حفظ الأوامر عن ظهر قلب، بل أن تتذكّر «في هذا الموقف يمكن استخدام هذه القطعة».

كما أنّ الشيفرة الواردة في هذا المقال منشورة على GitHub كمجموعة أمثلة كاملة قابلة للتنفيذ (سكربتات الوصفات واختبارات Pester)، مرتَّبة حسب الموضوع وفق تبويب الفصول.

powershell-practical-command-recipes - komurasoft-blog-samples (GitHub)

2. المنهجيّة المتَّبعة هنا

الافتراضات الثلاثة هي كالتالي.

  1. تُكتَب أسماء الأوامر بصيغتها الرسميّة
  2. التركيز على الأوامر القرائيّة (read)
  3. الأوامر التغييريّة تُدرَس دائماً مع تأكيد الهدف أو مع -WhatIf

على سبيل المثال، بدل حفظ أمر حذف الملفّات مباشرةً، من الأسلم اكتساب التسلسل التالي أوّلاً.

عرض الهدف
  → تضييقه بشرط
  → عدّ العناصر
  → حفظه في CSV عند الحاجة
  → تأكيد خطّة التغيير
  → التنفيذ

في هذا المقال، سنركِّز على التحقيق والتجميع والمقارنة والإخراج، أكثر من العمليّات القويّة كالحذف أو الإيقاف.

3. خريطة الأوامر الشائعة الاستخدام

هذه هي الأوامر الرئيسيّة المستخدَمة في هذا المقال.

ما تريد فعله الأمر
معرفة العدد أو الإجماليّ Measure-Object
ترتيب التكرارات Sort-Object -Unique
التجميع حسب النوع Group-Object
إخراج الأعمدة المطلوبة فقط Select-Object
معالجة كلّ عنصر ForEach-Object
البحث عن نصّ Select-String
مقارنة نتيجتين Compare-Object
حساب قيمة التجزئة (hash) Get-FileHash
استخدام الحافظة Set-Clipboard / Get-Clipboard
الإخراج إلى الشاشة والملفّ معاً Tee-Object
قياس زمن المعالجة Measure-Command
عرض تفاصيل الخطأ Get-Error
التحقّق من اتّصال الشبكة Test-Connection / Test-NetConnection

لا حاجة لحفظها جميعاً دفعةً واحدة. يُنصَح بحفظها مقترنةً بالغرض منها، مثل «للعدّ استخدم Measure-Object» و«للتجميع استخدم Group-Object» و«للمقارنة استخدم Compare-Object».

4. عدّ العناصر ── Measure-Object

أوّل عمليّة شائعة الاستخدام هي عدّ العناصر.

عدّ عدد الملفّات في المجلّد الحاليّ.

Get-ChildItem . -File | Measure-Object

في حال العدّ بما يشمل المجلّدات الفرعيّة.

Get-ChildItem . -File -Recurse | Measure-Object

Count في نتيجة Measure-Object هو العدد.

إن أردتَ معرفة الحجم الإجماليّ لحجم الملفّات، اجمع Length.

Get-ChildItem . -File -Recurse |
  Measure-Object -Property Length -Sum

لكن هذا يبقى بالبايت وصعب القراءة على الإنسان، فلنحوِّله إلى وحدة GB.

$size = Get-ChildItem . -File -Recurse |
  Measure-Object -Property Length -Sum

[math]::Round($size.Sum / 1GB, 2)

هذا مفيد عندما تريد نظرة سريعة على حجم المجلّد كلّه.

5. معرفة الحدّ الأقصى والمتوسّط أيضاً

لا يقتصر Measure-Object على الإجماليّ، بل يمكنه أيضاً إخراج القيمة القصوى والمتوسّط.

Get-ChildItem . -File |
  Measure-Object -Property Length -Sum -Average -Maximum -Minimum

يمكن استخدامه لرؤية تفاوت أحجام الملفّات.

يمكن أيضاً جمع زمن المعالج (CPU) التراكميّ للعمليّات. خاصيّة CPU في Get-Process ليست نسبة الاستخدام، بل عدد ثواني زمن المعالج المُستهلَك منذ بدء تشغيل العمليّة.

Get-Process |
  Measure-Object -Property CPU -Sum

لكنّ هذه القيمة تراكميّة وليست نسبة استخدام المعالج اللحظيّة، لذا تتغيّر حسب توقيت التنفيذ ومدّة تشغيل العمليّة.

تكفي هذه القيمة للاستخدام كتحقيق استكشافيّ، لكن إن أردتَ مراقبة دقيقة، فستحتاج أيضاً إلى أداة مراقبة مخصّصة أو تصميم سجلّات مخصّص.

6. استخراج القيمة فقط ── Select-Object -ExpandProperty

يُستخدَم Select-Object كثيراً عند اختيار الأعمدة.

Get-Process |
  Select-Object Name, Id, CPU

هذا يُخرِج «كائناً له أعمدة Name وId وCPU».

من ناحية أخرى، عند الرغبة باستخراج القيمة فقط، استخدم -ExpandProperty.

Get-Process -Name notepad -ErrorAction SilentlyContinue |
  Select-Object -ExpandProperty Id

الأمر نفسه عند استخراج اسم الملفّ فقط.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Name

عند الرغبة بتمرير نتيجة الأمر إلى أمر آخر أو ملفّ نصّي، فإنّ -ExpandProperty مفيد.

على سبيل المثال، لحفظ قائمة أسماء الملفّات فقط.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\file-names.txt -Encoding UTF8

يتشابه Select-Object Name وSelect-Object -ExpandProperty Name لكنّ شكل النتيجة مختلف.

Select-Object Name
  → جدول له عمود باسم Name

Select-Object -ExpandProperty Name
  → قيمة Name نفسها

إن أردتَ تحويلها إلى CSV، فمن الأفضل إبقاؤها كعمود، وإن أردتَ تمريرها إلى معالجة نصّيّة أخرى، فالقيمة وحدها أسهل تعاملاً.

7. حذف التكرارات ── Sort-Object -Unique

عند الرغبة بعرض امتدادات الملفّات فقط دون تكرار.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Extension |
  Sort-Object -Unique

عند التنفيذ، تظهر الامتدادات فقط دون تكرار، مثل .txt و.log و.csv.

يمكن أيضاً رؤية أنواع أسماء العمليّات فقط.

Get-Process |
  Select-Object -ExpandProperty ProcessName |
  Sort-Object -Unique

مثال على استخراج قائمة أسماء الأقسام فقط من CSV لقائمة المستخدمين.

Import-Csv .\users.csv |
  Select-Object -ExpandProperty Department |
  Sort-Object -Unique

عندما «تظهر نفس القيمة كثيراً في القائمة فيصعب القراءة»، من المفيد تذكّر Sort-Object -Unique أوّلاً.

8. التجميع حسب النوع ── Group-Object

عندما تريد معرفة «كم عنصراً من كلّ نوع» وليس مجرّد حذف التكرارات، استخدم Group-Object.

عدّ عدد الملفّات حسب الامتداد.

Get-ChildItem . -File |
  Group-Object -Property Extension -NoElement |
  Sort-Object -Property Count -Descending

بإضافة -NoElement، يمكن حذف محتوى كلّ مجموعة والاكتفاء بالعدد لسهولة القراءة.

العدّ حسب حالة الخدمة.

Get-Service |
  Group-Object -Property Status -NoElement

العدّ حسب مستوى سجلّ الأحداث.

Get-WinEvent -LogName System -MaxEvents 500 |
  Group-Object -Property LevelDisplayName -NoElement

Group-Object مناسب لأخذ نظرة عامّة في بداية التحقيق.

أيّ امتداد أكثر شيوعاً
أيّ حالة خدمة أكثر شيوعاً
أيّ مستوى خطأ أكثر شيوعاً
أيّ قسم لديه بيانات أكثر

يُستخدَم قبل النظر في التفاصيل، عندما تريد رؤية التوزيع أوّلاً.

9. إنشاء الأعمدة اللازمة ── إضافة عمود محسوب

يمكن الحصول على حجم الملفّ عبر Length، لكن الوحدة بايت. رؤية عدد البايتات في كلّ مرّة مرهقة، لذا من المفيد إنشاء عمود مُحوَّل إلى MB أو KB.

Get-ChildItem . -File |
  Select-Object Name, @{Name="SizeKB"; Expression={ [math]::Round($_.Length / 1KB, 1) }}, LastWriteTime

مثال على رؤية الملفّات الأكبر حجماً أوّلاً، بما فيها المجلّدات الفرعيّة.

Get-ChildItem . -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}, LastWriteTime

الصيغة @{Name="..."; Expression={ ... }} هي طريقة إنشاء عمود محسوب. تبدو طويلة بعض الشيء في البداية، لكنّها شائعة الاستخدام في العمل الفعليّ.

على سبيل المثال، يمكن عرض استهلاك الذاكرة للعمليّة بوحدة MB.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

عند الإخراج في تقرير، يكون عمود مثل SizeMB أسهل قراءة من Length الأصليّ.

10. العرض بالأحدث والأقدم والأكبر

في PowerShell، يتمّ الترتيب عبر Sort-Object.

عرض الملفّات المُحدَّثة مؤخّراً.

Get-ChildItem . -File |
  Sort-Object -Property LastWriteTime -Descending |
  Select-Object -First 10 Name, LastWriteTime

عرض الملفّات القديمة.

Get-ChildItem . -File |
  Sort-Object -Property LastWriteTime |
  Select-Object -First 10 Name, LastWriteTime

عرض الملفّات الكبيرة.

Get-ChildItem . -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 10 FullName, Length

هذه الأنماط الثلاثة شائعة الاستخدام.

الأحدث أوّلاً → LastWriteTime -Descending
الأقدم أوّلاً → LastWriteTime
الأكبر أوّلاً → Length -Descending

هذا التوليف كثير الاستخدام في تحقيق السجلّات، وتنظيف الملفّات غير الضروريّة، وتحقيق سعة القرص.

11. أوامر Format تُستخدَم فقط في آخر مرحلة عرض على الشاشة

عند الرغبة بعرض أوضح على الشاشة، استخدم Format-Table أو Format-List.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Format-Table -AutoSize

لرؤية تفاصيل عنصر واحد، Format-List مفيد.

Get-Process -Id $PID |
  Format-List *

لكن Format-Table وFormat-List أوامر «للعرض».

من الأسلم عدم استخدامها قبل الإخراج إلى CSV أو قبل المعالجة بأمر لاحق.

# تجنَّب هذا
Get-Process |
  Format-Table Name, Id |
  Export-Csv .\process.csv -NoTypeInformation

عند الإخراج إلى CSV، اختر الأعمدة عبر Select-Object.

# الصحيح
Get-Process |
  Select-Object Name, Id |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

عند التردّد، فكِّر كالتالي.

العرض على الشاشة فقط → Format-Table / Format-List
الاستخدام لاحقاً      → Select-Object

12. تحسين بحث السجلّات قليلاً ── Select-String

للبحث عن نصّ، استخدم Select-String.

Select-String -Path .\logs\*.log -Pattern "ERROR"

يمكن تحديد أنماط متعدّدة أيضاً.

Select-String -Path .\logs\*.log -Pattern "ERROR", "WARN", "FATAL"

عند الرغبة برؤية الأسطر المحيطة، استخدم -Context.

Select-String -Path .\logs\*.log -Pattern "ERROR" -Context 2

هذا يعرض أيضاً السطرين السابق واللاحق للسطر المطابق، مفيد عند الرغبة بالتحقّق من سياق الخطأ.

عند الرغبة بالبحث كنصّ بسيط، استخدم -SimpleMatch.

Select-String -Path .\logs\*.log -Pattern "[ERROR]" -SimpleMatch

يُعامَل -Pattern في Select-String عادةً كتعبير نمطيّ (regular expression). عند الرغبة بالبحث عن رموز مثل [ أو . كما هي، فإنّ إضافة -SimpleMatch يجعل الأمر أوضح.

عند الرغبة بالتمييز بين الأحرف الكبيرة والصغيرة.

Select-String -Path .\logs\*.log -Pattern "Error" -CaseSensitive

يمكن أيضاً حفظ نتيجة البحث في CSV.

Select-String -Path .\logs\*.log -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8

13. استبدال النصوص

لاستبدال جزء من نصّ، استخدم -replace.

"server01.example.com" -replace "\.example\.com$", ""

عند استبدال محتوى ملفّ، من الأسلم عدم الكتابة فوق الملفّ الأصليّ مباشرةً. أخرِج أوّلاً إلى ملفّ منفصل.

(Get-Content .\appsettings.json -Raw) -replace "localhost", "db01" |
  Set-Content .\appsettings.preview.json -Encoding UTF8

بعد التحقّق، طبِّق التغيير على الملفّ الأصليّ عند الحاجة.

في ملفّات الإعدادات أو الاستبدال الجماعيّ، يؤدّي كثرة عناصر الاستبدال إلى حوادث. من الأسلم التحقّق من الهدف أوّلاً عبر Select-String قبل الاستبدال.

Select-String -Path .\appsettings.json -Pattern "localhost" -SimpleMatch

14. مقارنة نتيجتين ── Compare-Object

Compare-Object هو أمر لرؤية الفرق بين قائمتين.

على سبيل المثال، مقارنة قائمة أسماء الملفّات قبل التغيير وبعده.

Compare-Object `
  -ReferenceObject (Get-Content .\before.txt) `
  -DifferenceObject (Get-Content .\after.txt)

معنى SideIndicator كالتالي.

العرض المعنى
<= موجود في الجانب الأيسر فقط، أي ReferenceObject
=> موجود في الجانب الأيمن فقط، أي DifferenceObject
== موجود في كليهما. يظهر عند إضافة -IncludeEqual

مثال على حفظ قائمة أسماء ملفّات المجلّد ومقارنتها.

Get-ChildItem .\before -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\before-list.txt -Encoding UTF8

Get-ChildItem .\after -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\after-list.txt -Encoding UTF8

Compare-Object `
  -ReferenceObject (Get-Content .\before-list.txt) `
  -DifferenceObject (Get-Content .\after-list.txt)

يمكن أيضاً رؤية التغيّر في قائمة الخدمات.

Get-Service |
  Select-Object Name, Status |
  Export-Csv .\services-before.csv -NoTypeInformation -Encoding UTF8

بعد التغيير، أخرِج مرّة أخرى.

Get-Service |
  Select-Object Name, Status |
  Export-Csv .\services-after.csv -NoTypeInformation -Encoding UTF8

قارِن.

Compare-Object `
  -ReferenceObject (Import-Csv .\services-before.csv) `
  -DifferenceObject (Import-Csv .\services-after.csv) `
  -Property Name, Status

حفظ الفرق قبل العمل وبعده يسهِّل التحقيق وإعداد التقارير.

15. التحقّق من قيمة تجزئة الملفّ ── Get-FileHash

عند الرغبة بالتحقّق من تطابق ملفّ تمّ تنزيله أو ملفّ توزيع، استخدم قيمة التجزئة (hash).

Get-FileHash .\installer.exe -Algorithm SHA256

مثال على التحقّق الجماعيّ من الملفّات داخل مجلّد.

Get-ChildItem .\downloads -File |
  ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 }

يمكن أيضاً حفظها في CSV.

Get-ChildItem .\downloads -File |
  ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 } |
  Select-Object Path, Hash |
  Export-Csv .\hashes.csv -NoTypeInformation -Encoding UTF8

قد تبدو أسماء الملفّات وحدها متطابقة لكنّ المحتوى مختلف. في التوزيعات والنسخ الاحتياطيّة وأعمال النقل، يسهِّل حفظ قيمة التجزئة عمليّة التحقّق.

16. الإرسال إلى الحافظة ── Set-Clipboard

عندما تريد لصق نتيجة الأمر في بريد إلكترونيّ أو محادثة، إرسالها إلى الحافظة مفيد.

Get-Service |
  Select-Object Name, Status |
  ConvertTo-Csv -NoTypeInformation |
  Set-Clipboard

لرؤية محتوى الحافظة.

Get-Clipboard

عند الرغبة بلصق البيانات في Excel بصيغة مفصولة بعلامات تبويب، اجعل الفاصل في ConvertTo-Csv علامة تبويب.

Get-Process |
  Select-Object Name, Id, CPU |
  ConvertTo-Csv -NoTypeInformation -Delimiter "`t" |
  Set-Clipboard

إن أردتَ فقط مشاركة النتيجة مؤقّتاً، فهذا أسهل من إنشاء ملفّ في كلّ مرّة. لكن إن أردتَ الحفاظ عليها كدليل، احفظها في ملفّ عبر Export-Csv.

17. العرض على الشاشة والحفظ في ملفّ معاً ── Tee-Object

عندما تريد رؤية النتيجة على الشاشة مع حفظها في ملفّ في آنٍ واحد، استخدم Tee-Object.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Tee-Object -FilePath .\top-process.txt

يُرسِل Tee-Object نتيجة الأنبوب (pipeline) في اتّجاهين.

العرض على الشاشة
الحفظ في ملفّ أيضاً

مناسب للاستخدام أثناء التحقيق عندما تريد «الرؤية مع التسجيل في آنٍ واحد». لكن إن أردتَ لاحقاً فتحها في Excel، فإنّ Export-Csv أسهل تعاملاً.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Export-Csv .\top-process.csv -NoTypeInformation -Encoding UTF8

من السهل التفكير كالتالي: للعرض على الشاشة استخدم Tee-Object، وللحفظ كبيانات جدوليّة استخدم Export-Csv.

18. حفظ سجلّ العمل ── Start-Transcript

عند الرغبة بتسجيل سلسلة من العمليّات، استخدم Start-Transcript.

Start-Transcript -Path .\work-log.txt

تُسجَّل بعد ذلك الأوامر المنفَّذة ومخرَجات الشاشة.

الإنهاء.

Stop-Transcript

في أعمال التحقيق، غالباً ما تحتاج لاحقاً إلى التحقّق من التالي.

أيّ أمر نُفِّذ
في أيّ مجلّد جرى العمل
ما النتيجة التي ظهرت
هل ظهر خطأ

يُعدّ Start-Transcript تأميناً ضدّ نسيان تدوين مذكّرات العمل. لكن انتبه في الأعمال التي تظهر فيها معلومات لا يجوز تسجيلها، مثل كلمات المرور أو الرموز المميّزة (tokens)، على الشاشة.

19. قراءة CSV وعرضه بشرط

في البيانات التجاريّة، كثيراً ما تظهر ملفّات CSV.

لنفترض وجود ملفّ users.csv كالتالي.

Name,Department,Enabled
Suzuki,Sales,true
Tanaka,Accounting,false
Sato,Sales,true

قراءته.

Import-Csv .\users.csv

عرض من يعمل في قسم Sales فقط.

Import-Csv .\users.csv |
  Where-Object { $_.Department -eq "Sales" }

إخراج المستخدمين النشِطين فقط إلى CSV منفصل.

Import-Csv .\users.csv |
  Where-Object { $_.Enabled -eq "true" } |
  Export-Csv .\enabled-users.csv -NoTypeInformation -Encoding UTF8

غالباً ما تُعامَل قيم CSV كنصوص، لذا عند مقارنة true/false أو الأرقام، فكِّر في تحويل النوع عند الحاجة.

مثال على عرض الصفوف التي درجتها 80 فأكثر فقط.

Import-Csv .\scores.csv |
  Where-Object { [int]$_.Score -ge 80 }

20. عرض قيم إعدادات JSON

يُستخدَم JSON كثيراً في ملفّات الإعدادات وواجهات Web API.

$config = Get-Content .\settings.json -Raw | ConvertFrom-Json
$config

يمكن أيضاً رؤية قيمة محدَّدة فقط.

$config.Database.Host

مثال على تغيير قيمة وحفظها في ملفّ منفصل.

$config.Database.Host = "db01"
$config |
  ConvertTo-Json -Depth 10 |
  Set-Content .\settings.updated.json -Encoding UTF8

عند التعامل مع JSON، يُستخدَم Get-Content -Raw كثيراً. بإضافة -Raw يُقرَأ الملفّ بأكمله كنصّ واحد، لذا يكون أوضح عند التعامل مع JSON متعدّد الأسطر.

21. عرض متغيّرات البيئة

تُستخدَم متغيّرات البيئة كثيراً في إعدادات التطبيقات والتحقّق من المسارات.

عرض القائمة.

Get-ChildItem Env:

عرض اسم المستخدم الحاليّ.

$env:USERNAME

عرض المجلّد المؤقّت.

$env:TEMP

تقسيم PATH لسهولة القراءة.

$env:PATH -split ";"

ضبط متغيّر بيئة لجلسة PowerShell الحاليّة فقط.

$env:APP_MODE = "Development"

هذا الضبط فعّال فقط داخل نافذة PowerShell المفتوحة حاليّاً.

للحفظ كمتغيّر بيئة على مستوى المستخدم، افعل كالتالي.

[Environment]::SetEnvironmentVariable("APP_MODE", "Development", "User")

هذه عمليّة تغيير للبيئة، لذا في أجهزة الشركة أو الخوادم الإنتاجيّة، تحقَّق من نطاق التأثير قبل التنفيذ.

22. التحقّق من ملفّ التعريف (profile)

يحتوي PowerShell على ملفّ تعريف (profile) يُقرَأ عند بدء التشغيل.

التحقّق من الموقع.

$PROFILE

التحقّق من وجوده.

Test-Path $PROFILE

إنشاؤه.

New-Item -ItemType File -Path $PROFILE -Force

فتحه بمفكّرة الملاحظات.

notepad $PROFILE

من المفيد كتابة الإعدادات أو الدوال الشائعة الاستخدام في ملفّ التعريف. لكن إن كتبتَ معالجة معقّدة أكثر من اللازم، فقد يبطئ بدء تشغيل PowerShell أو يصعب إعادة إنتاجه في بيئة أخرى، لذا يُنصَح بالاقتصار في البداية على المسارات وإعدادات العرض الشائعة الاستخدام.

23. عرض العمليّات (processes)

في تحقيق العمليّات، غالباً ما تبدأ برؤية الترتيب حسب استهلاك الذاكرة الأكبر.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

التضييق باسم محدَّد.

Get-Process -Name notepad -ErrorAction SilentlyContinue

عند إيقاف عمليّة، لا تُنفِّذ مباشرةً، بل تحقَّق أوّلاً عبر -WhatIf.

Stop-Process -Name notepad -WhatIf

نفِّذ إن لم تكن هناك مشكلة.

Stop-Process -Name notepad

في بيئة الإنتاج، قد يؤدّي إيقاف عمليّة إلى تأثير على العمل. تحقَّق من الهدف والمستخدِمين وطريقة الاستعادة قبل الإيقاف.

24. عرض الخدمات (services)

عرض قائمة الخدمات.

Get-Service

عرض الخدمات المتوقّفة فقط.

Get-Service |
  Where-Object { $_.Status -eq "Stopped" }

البحث عن الخدمات المتوقّفة رغم أنّها مضبوطة على التشغيل التلقائيّ.

Get-Service |
  Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
  Select-Object Name, DisplayName, Status, StartType

عند إعادة تشغيل خدمة، تحقَّق أوّلاً من الهدف.

Get-Service -Name "Spooler"

تنفيذ تجريبيّ.

Restart-Service -Name "Spooler" -WhatIf

لعمليّات الخدمات تأثير كبير، لذا نفِّذها بعد التحقّق من وقت الصيانة وإجراءات الاستعادة.

25. عرض سجلّ الأحداث (event log)

في تحقيقات Windows، كثيراً ما يُنظَر إلى سجلّ الأحداث.

عرض آخر 100 حدث في سجلّ النظام.

Get-WinEvent -LogName System -MaxEvents 100 |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

التضييق على الأخطاء والتحذيرات فقط.

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

عرض أخطاء آخر 24 ساعة فقط.

$start = (Get-Date).AddHours(-24)

Get-WinEvent -FilterHashtable @{ LogName = "System"; StartTime = $start } |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message

مثال على حفظ نتيجة التحقيق في CSV.

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message |
  Export-Csv .\system-events.csv -NoTypeInformation -Encoding UTF8

يميل عدد سجلّات الأحداث إلى الكِبر، لذا من المهمّ تضييق النطاق عبر -MaxEvents أو تحديد فترة زمنيّة.

26. التحقّق من الشبكة

للتحقّق من الاتّصال، استخدم Test-Connection.

Test-Connection example.com -Count 4

للتحقّق من اتّصال منفذ TCP في Windows، Test-NetConnection مفيد.

Test-NetConnection example.com -Port 443

للتحقّق من تحليل DNS.

Resolve-DnsName example.com

في تحقيق الشبكة، يُفصَل التحقيق كالتالي.

هل يمكن تحليل الاسم
هل يصل إلى عنوان IP
هل المنفذ المطلوب مفتوح
هل هناك تأثير من البروكسي أو جدار الحماية

بدل الاعتماد على PowerShell وحده للحكم على كلّ شيء، فإنّ استخدامه كمدخل للفصل بين الاحتمالات مفيد.

27. عرض نتائج الويب

لجلب صفحة ويب، استخدم Invoke-WebRequest.

Invoke-WebRequest https://example.com |
  Select-Object StatusCode, StatusDescription

للتعامل مع نتيجة واجهة API بصيغة JSON، Invoke-RestMethod مفيد.

Invoke-RestMethod https://api.github.com/repos/PowerShell/PowerShell |
  Select-Object full_name, stargazers_count, forks_count

غالباً ما تُعامَل نتيجة API منذ البداية ككائن PowerShell، ما يجعلها سهلة التركيب مع Select-Object وWhere-Object.

عند التحقيق في واجهة API داخليّة أيضاً، ابدأ أوّلاً بطلبات GET القرائيّة.

عند التعامل مع بيانات اعتماد أو رموز مميّزة (tokens)، انتبه لعدم ظهورها على الشاشة أو تسجيلها في transcript.

28. قياس زمن التنفيذ ── Measure-Command

عندما تريد معرفة المدّة التي تستغرقها معالجة ما، استخدم Measure-Command.

Measure-Command {
  Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
    Measure-Object
}

تحتوي النتيجة على TotalSeconds وTotalMilliseconds.

$result = Measure-Command {
  Get-ChildItem . -File -Recurse | Measure-Object
}

$result.TotalSeconds

عند الرغبة بتسريع سكربت، من المهمّ قياس الزمن بدل الاعتماد على الحدس. لكن النتيجة تتغيّر حسب عدد الملفّات وحالة القرص وحالة الشبكة، لذا لا تحكم بناءً على نتيجة واحدة فقط، بل تحقَّق عدّة مرّات.

29. تشغيل المعالجات الطويلة في الخلفيّة ── Start-Job

عندما تريد تنفيذ تحقيق يستغرق وقتاً طويلاً كمهمّة (job) منفصلة، استخدم Start-Job.

$job = Start-Job -ScriptBlock {
  Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
    Measure-Object
}

عرض حالة المهمّة.

Get-Job

استلام النتيجة.

Receive-Job $job

حذف المهمّة غير الضروريّة.

Remove-Job $job

Start-Job مفيد، لكن لا حاجة لاستخدامه بكثرة منذ البداية. من الأفضل التنفيذ العاديّ أوّلاً، وتحويل المعالجة البطيئة فقط إلى مهمّة، لتسهيل الفهم.

30. استخدام سجلّ الأوامر

لرؤية الأوامر المنفَّذة سابقاً، استخدم Get-History.

Get-History

عرض سطر الأمر فقط لسهولة القراءة.

Get-History |
  Select-Object Id, CommandLine

إعادة تنفيذ سجلّ محدَّد.

Invoke-History 12

السجلّ مفيد، لكن يمكن أيضاً إعادة تنفيذ أوامر خطِرة عن طريقه. عند إعادة تنفيذ أوامر تغييريّة من السجلّ مثل Remove-Item أو Stop-Process، تحقَّق من المحتوى قبل التنفيذ.

31. عرض تفاصيل الخطأ ── Get-Error

في PowerShell 7، يمكن استخدام Get-Error لرؤية تفاصيل الخطأ الأخير.

Get-Error

عند الرغبة برؤية رسالة الخطأ الأخيرة فقط.

$Error[0].Exception.Message

عند حدوث خطأ، لا تكتفِ برؤية النصّ الأحمر على الشاشة فقط، بل تحقَّق من النقاط التالية.

أيّ أمر فشل
أيّ مسار أو هدف فشل
هل هي مشكلة صلاحيّات
هل الملفّ غير موجود
هل هناك مشكلة شبكة أو قفل (lock)

عند الرغبة بحفظ نتيجة التحقيق، اجمعه مع Start-Transcript أو Export-Csv.

32. عوامل المقارنة الشائعة الاستخدام

في Where-Object، تُستخدَم عوامل المقارنة كثيراً.

العامل المعنى مثال
-eq يساوي $_.Status -eq "Running"
-ne لا يساوي $_.Status -ne "Running"
-gt أكبر من $_.Length -gt 10MB
-ge أكبر من أو يساوي $_.Length -ge 10MB
-lt أصغر من $_.Length -lt 10MB
-le أصغر من أو يساوي $_.Length -le 10MB
-like تطابق بأحرف البدل (wildcard) $_.Name -like "*.log"
-match تطابق تعبير نمطيّ $_.Name -match "^app"
-in القيمة موجودة في قائمة $_.Status -in @("Running", "Paused")
-contains القائمة تحتوي القيمة @("a", "b") -contains "a"

أمثلة.

Get-ChildItem . -File |
  Where-Object { $_.Length -gt 10MB }
Get-Service |
  Where-Object { $_.Status -in @("Running", "Paused") }
Get-ChildItem . -File |
  Where-Object { $_.Name -match "\.log$" }

في البداية، تكفي -eq و-ne و-gt و-lt و-like فقط. بعد التعوّد، يصبح استخدام -match أو -in أسهل لكتابة الشروط.

33. وصفات عمليّة صغيرة

من هنا فصاعداً، أمثلة يمكن استخدامها مباشرةً في العمل الفعليّ.

عرض عدد الملفّات حسب الامتداد

Get-ChildItem C:\Work -File -Recurse |
  Group-Object -Property Extension -NoElement |
  Sort-Object -Property Count -Descending

يُستخدَم عند الرغبة بفهم محتوى المجلّد بنظرة سريعة.

عرض أكبر 20 ملفّاً

Get-ChildItem C:\Work -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}

شائع الاستخدام في تحقيق سعة القرص.

عرض الملفّات المُحدَّثة خلال آخر 24 ساعة

$since = (Get-Date).AddHours(-24)

Get-ChildItem C:\Work -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-Object FullName, Length, LastWriteTime

يُستخدَم لرؤية أيّ ملفّ تحدَّث بعد وقوع عطل.

تحويل أسطر سجلّ تحتوي ERROR إلى CSV

Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8

يسهِّل مشاركة نتيجة التحقيق.

عرض السطرين المحيطين بـ ERROR

Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" -Context 2

يُستخدَم عند الرغبة برؤية سياق السبب.

عرض العمليّات ذات استهلاك الذاكرة الكبير

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

عرض الخدمات المتوقّفة رغم كونها تشغيلاً تلقائيّاً

Get-Service |
  Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
  Select-Object Name, DisplayName, Status, StartType

تحويل أخطاء سجلّ النظام إلى CSV

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message |
  Export-Csv .\system-errors.csv -NoTypeInformation -Encoding UTF8

إرسال نتيجة الأمر إلى الحافظة

Get-Service |
  Select-Object Name, DisplayName, Status |
  ConvertTo-Csv -NoTypeInformation |
  Set-Clipboard

مفيد عند اللصق في بريد إلكترونيّ أو محادثة.

مقارنة قائمة الملفّات قبل العمل وبعده

Get-ChildItem C:\Work -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\before.txt -Encoding UTF8

بعد العمل، خذها مرّة أخرى.

Get-ChildItem C:\Work -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\after.txt -Encoding UTF8

قارِن.

Compare-Object (Get-Content .\before.txt) (Get-Content .\after.txt)

عرض الحجم الإجماليّ للمجلّد بوحدة GB

$size = Get-ChildItem C:\Work -File -Recurse |
  Measure-Object -Property Length -Sum

[math]::Round($size.Sum / 1GB, 2)

34. تنبيه عند الجمع بين الأوامر التغييريّة

معظم ما ورد حتّى الآن أوامر قرائيّة، ويمكن تجربتها بأمان نسبيّ إن اقتصر الأمر عليها. في المقابل، هذه أوامر تغييريّة.

العمليّة الأمر
النسخ Copy-Item
النقل Move-Item
الحذف Remove-Item
تغيير الاسم Rename-Item
إيقاف العمليّة Stop-Process
إعادة تشغيل الخدمة Restart-Service
ضبط متغيّر البيئة بشكل دائم [Environment]::SetEnvironmentVariable()

تُستخدَم الأوامر التغييريّة بالترتيب التالي.

1. رؤية الهدف عبر أوامر Get
2. التضييق عبر Where-Object
3. رؤية قائمة الأهداف عبر Select-Object
4. عدّ العناصر عبر Measure-Object
5. الحفظ عبر Export-Csv عند الحاجة
6. التنفيذ التجريبيّ إن كان -WhatIf متاحاً
7. التنفيذ

على سبيل المثال، حالة حذف ملفّات .tmp القديمة.

انظر الهدف أوّلاً.

$limit = (Get-Date).AddDays(-30)

$targets = Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse |
  Where-Object { $_.LastWriteTime -lt $limit }

$targets |
  Select-Object FullName, Length, LastWriteTime

عدّ العناصر.

$targets | Measure-Object

احفظ في CSV.

$targets |
  Select-Object FullName, Length, LastWriteTime |
  Export-Csv .\delete-targets.csv -NoTypeInformation -Encoding UTF8

تأكَّد من خطّة الحذف.

$targets | Remove-Item -WhatIf

نفِّذ إن لم تكن هناك مشكلة.

$targets | Remove-Item

مجرّد الالتزام بهذا التسلسل يقلِّل الحوادث كثيراً.

35. طريقة الحفظ

محاولة حفظ الأوامر فرديّاً عن ظهر قلب أمر شاقّ، لذا حفظها حسب الغرض أسهل استخداماً.

الغرض الأمر الذي تتذكّره
أريد العدّ Measure-Object
أريد الجمع Measure-Object -Sum
أريد الرؤية حسب النوع Group-Object
أريد حذف التكرارات Sort-Object -Unique
أريد القيمة المطلوبة فقط Select-Object -ExpandProperty
أريد ترتيب الأعمدة Select-Object
أريد الرؤية بالأكبر أوّلاً Sort-Object -Descending
أريد البحث عن نصّ Select-String
أريد رؤية ما حوله Select-String -Context
أريد مقارنة اثنين Compare-Object
أريد حفظ الدليل Export-Csv / Start-Transcript
أريد العرض على الشاشة والملفّ معاً Tee-Object
أريد الإرسال إلى الحافظة Set-Clipboard
أريد قياس الزمن Measure-Command
أريد رؤية الخطأ بالتفصيل Get-Error

36. الخلاصة

PowerShell قويّ عندما تصبح قادراً على كتابة السكربتات. لكن الأكثر استخداماً في العمل الفعليّ هو، بشكل مفاجئ، توليفات الأوامر الصغيرة.

العدّ
الترتيب
التجميع
المقارنة
البحث
الاستخراج
الحفظ
الإرسال إلى الحافظة
حفظ سجلّ العمل

مجرّد القدرة على فعل هذه الأمور يجعل العمل اليوميّ أسهل بكثير. لا حاجة لاستهداف الأتمتة المعقّدة منذ البداية. لنبدأ أوّلاً بالأوامر القرائيّة لنتمكّن من رؤية الوضع بدقّة، ثمّ نستخدم عند الحاجة فقط الأوامر التغييريّة مثل Copy-Item وMove-Item وRemove-Item وRestart-Service.

سرّ استخدام PowerShell بأمان هو هذا الترتيب.

الرؤية → العدّ → الترتيب → الحفظ → التنفيذ التجريبيّ → التنفيذ

عند اكتساب هذا النمط، لن يعود PowerShell «أداة كتابة أوامر على شاشة سوداء»، بل أداة عمليّة تدعم التحقيق اليوميّ والتنظيم والتقارير.

أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.

ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.

الأسئلة الشائعة

أسئلة شائعة حول موضوع هذه المقالة.

كيف يمكن معرفة عدد الملفّات أو حجمها الإجماليّ في PowerShell؟
مرِّر نتيجة Get-ChildItem عبر أنبوب (pipe) إلى Measure-Object. يمكن التحقّق من عدد العناصر عبر خاصيّة Count في النتيجة، وإن أردتَ تضمين المجلّدات الفرعيّة أضِف -Recurse. أمّا الحجم الإجماليّ فيُجمَع عبر Measure-Object -Property Length -Sum، ولأنّ الرقم يبقى بالبايت وهو صعب القراءة، فإنّ تحويله إلى وحدة GB عبر [math]::Round($size.Sum / 1GB, 2) يجعله أوضح. وبإضافة -Average أو -Maximum يمكن الحصول على المتوسّط والحدّ الأقصى في آنٍ واحد.
ما الفرق بين -ExpandProperty في Select-Object والتحديد المعتاد؟
يُرجِع الأمر Select-Object Name «جدولاً (كائناً) يحتوي عموداً باسم Name»، بينما يُرجِع Select-Object -ExpandProperty Name «قيمة Name نفسها». عند الرغبة في الإخراج إلى CSV، يناسب التحديد المعتاد الذي يُبقي القيمة كعمود، أمّا عند تمرير القيم فقط إلى أمر آخر أو معالجة نصّية أو ملفّ نصّي، فإنّ -ExpandProperty أسهل في التعامل. يُختار الأسلوب حسب الغرض.
لماذا لا يجوز استخدام Format-Table قبل Export-Csv؟
لأنّ Format-Table وFormat-List أوامر مخصّصة للعرض على الشاشة، وتُحوِّل المخرَجات إلى كائنات عرض (display objects)، ما يمنع تنفيذ عمليّة الإخراج إلى CSV أو المعالجة اللاحقة بشكل صحيح. عند الإخراج إلى CSV أو المعالجة بأمر لاحق، اختر الأعمدة عبر Select-Object ثمّ مرِّرها إلى Export-Csv. تذكَّر القاعدة: «إن كان العرض على الشاشة فقط فاستخدم أوامر Format، وإن كان الاستخدام لاحقاً فاستخدم Select-Object»، ولن تتردّد بعدها.
هل توجد خطوات لاستخدام الأوامر التغييريّة مثل Remove-Item بأمان؟
لا تُنفِّذ الأمر مباشرةً، بل انظر أوّلاً إلى الهدف عبر أوامر Get، ثمّ ضيِّق النطاق بـ Where-Object، وتحقَّق من قائمة الأهداف عبر Select-Object، وعُدَّ العناصر بـ Measure-Object، واحفظ دليلاً (إن لزم) عبر Export-Csv. بعد ذلك، إن كان الأمر يدعم -WhatIf، فنفِّذه تجريبيّاً أوّلاً للتحقّق من خطّة الحذف أو النقل، وإن لم تكن هناك مشكلة فنفِّذه فعليّاً. مجرّد الالتزام بهذا الترتيب يقلِّل الحوادث كثيراً.

الملف الشخصي للمؤلف

صفحة الملف الشخصي لمؤلف المقالة.

غو كومورا

مؤسّس شركة كومورا سوفت ذ.م.م.

يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.

روابط عامة

العودة إلى المدونة