أساسيّات أوامر PowerShell ── العمليّات الأولى الواجب تعلّمها والاستخدام الآمن

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

1. ما ينبغي معرفته أوّلاً

PowerShell هو بيئة أوامر يمكن استخدامها للتحقّق من إعدادات Windows، وترتيب الملفّات، وتحقيق السجلّات (logs)، ومعالجة CSV، والتحكّم في الخدمات (services)، وأتمتة الأعمال الروتينيّة.

لكن لا حاجة لكتابة سكربتات معقّدة منذ البداية. يكفي في البداية تذكّر التدفّق التالي لتصبح قادراً على الاستفادة منه إلى حدّ كبير في العمل الفعليّ.

البحث  العرض  التصفية  الترتيب  الإخراج  التغيير عند الحاجة

أساس PowerShell ليس «حفظ الأوامر الطويلة عن ظهر قلب». المهمّ هو الأمور الثلاثة التالية:

  1. القدرة على البحث عن الأوامر عبر Get-Command وGet-Help
  2. القدرة على تمرير النتائج إلى الأمر التالي عبر خطّ الأنابيب |
  3. التحقّق من الأثر عبر -WhatIf أو -Confirm قبل الحذف أو الإيقاف أو التغيير

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

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

powershell-command-basics - komurasoft-blog-samples (GitHub)

2. الفرق بين PowerShell وموجّه الأوامر

يبدو PowerShell شبيهاً بموجّه الأوامر التقليديّ (cmd.exe)، لكنّ الفكرة الداخليّة مختلفة.

المحور موجّه الأوامر PowerShell
الإخراج الرئيسيّ نصّ كائن (object)
اسم الأمر dir، copy وما شابه Get-ChildItem، Copy-Item وما شابه
معالجة النتائج تتمحور حول معالجة النصّ التصفية والترتيب باستخدام الخصائص (properties)
الأتمتة ملفّ batch سكربت .ps1
مجال التفوّق التوافق مع أصول الأوامر القديمة إدارة Windows، وCSV، وJSON، وAPI، والأعمال الروتينيّة

فمثلاً، عند الحصول على قائمة الملفّات، غالباً ما يُكتفى في cmd.exe بتأمّل نتيجة عرض dir كنصّ. أمّا في PowerShell فتُعامَل الملفّات ككائنات لها خصائص مثل Name وLength وLastWriteTime.

Get-ChildItem

عند فهم هذا الفرق، يصبح من الطبيعيّ كتابة معالجة مثل «عرض الملفّات التي حُدِّثت خلال 7 أيّام فقط، مرتَّبة من الأحدث إلى الأقدم بحسب تاريخ التحديث»:

Get-ChildItem -File |
  Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) } |
  Sort-Object LastWriteTime -Descending |
  Select-Object Name, Length, LastWriteTime

3. Windows PowerShell 5.1 وPowerShell 7.x

يوجد في Windows إصداران: Windows PowerShell 5.1 الموجود منذ القديم، وسلسلة جديدة هي PowerShell 7.x.

في العمل الفعليّ، من المفيد التفكير على النحو التالي.

النوع الملفّ التنفيذيّ الاستخدام الرئيسيّ
Windows PowerShell 5.1 powershell.exe الوحدات (modules) القديمة الخاصّة بـ Windows، والسكربتات القائمة، وصيانة أصول الشركة
PowerShell 7.x pwsh.exe السكربتات الجديدة، والعمل عبر منصّات متعدّدة، والتحسين المستمرّ للميزات

عند التعلّم من جديد، لا مشكلة في اتّخاذ PowerShell 7.x أساساً. لكن سكربتات الإدارة القديمة داخل الشركة والوحدات الخاصّة بـ Windows قد تكون مبنيّة على افتراض Windows PowerShell 5.1.

لذلك، من المهمّ في العمل الفعليّ التحقّق من الإصدار أوّلاً.

$PSVersionTable

بالنسبة للسكربتات التي يُراد تشغيلها بإصدار معيّن فأعلى، يقلِّل كتابة شرط في بدايتها من الأعطال.

#Requires -Version 7.0

4. أسماء الـ cmdlets بصيغة فعل-اسم

أوامر PowerShell القياسيّة تأخذ أساساً صيغة فعل-اسم (Verb-Noun).

Get-Process
Get-Service
Get-ChildItem
Copy-Item
Remove-Item
Export-Csv

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

الفعل المعنى مثال
Get الحصول على Get-Process
Set الضبط Set-Location
New الإنشاء New-Item
Copy النسخ Copy-Item
Move النقل Move-Item
Remove الحذف Remove-Item
Start البدء Start-Service
Stop الإيقاف Stop-Process
Import القراءة Import-Csv
Export الكتابة إلى خارج Export-Csv

يمكن استخدام أسماء قصيرة مثل dir، ls، cat، cd، لكنّ معظمها أسماء مستعارة (aliases).

Get-Command dir

عند حفظ السكربت، يُفضَّل استخدام الاسم الرسميّ بدل الاسم المستعار من أجل السلامة.

# مقروءة، لكن يُفضَّل تجنّبها في السكربتات
ls *.log

# النيّة واضحة
Get-ChildItem -Filter *.log

5. ثلاثة أوامر تحقيق أساسيّة تُحفَظ أوّلاً

عدد أوامر PowerShell كبير، لذا فإنّ حفظ «طريقة البحث» أهمّ عمليّاً من الحفظ عن ظهر قلب.

1. Get-Command ── البحث عن الأوامر المتاحة

Get-Command أمر للبحث عن الأوامر، والدوال (functions)، والأسماء المستعارة، والتطبيقات المثبَّتة.

# البحث عن الأوامر التي اسمها (الاسم = noun) هو Process
Get-Command -Noun Process

# البحث عن الأوامر المتعلّقة بـ Service
Get-Command *Service*

# البحث عن الأوامر المتعلّقة بـ CSV
Get-Command *Csv*

عندما يكون اسم الأمر غير واضح في الذاكرة، استخدم أحرف البدل (wildcards).

Get-Command *Item*
Get-Command *Content*
Get-Command *Json*

2. Get-Help ── الاطّلاع على طريقة الاستخدام

Get-Help أمر للتحقّق من شرح الأمر، ومعاملاته (parameters)، وأمثلته.

Get-Help Get-ChildItem
Get-Help Get-ChildItem -Examples
Get-Help Get-ChildItem -Full
Get-Help Get-ChildItem -Online

في البداية، يكون -Examples مفيداً.

Get-Help Where-Object -Examples

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

Update-Help

حسب البيئة، قد يلزم اتّصال بالإنترنت وصلاحيّات معيّنة. في أجهزة الشركة، قد يفشل ذلك بسبب البروكسي (proxy) أو سياسات الإدارة.

3. Get-Member ── الاطّلاع على محتوى الكائن

غالباً ما يكون إخراج PowerShell «كائناً» (object) لا «نصّاً». باستخدام Get-Member يمكن التحقّق من الخصائص (properties) والطرائق (methods) التي يملكها ذلك الكائن.

Get-Process | Get-Member
Get-Service | Get-Member
Get-ChildItem | Get-Member

فمثلاً، للخدمة (service) خصائص مثل Status وName.

Get-Service | Select-Object Name, Status

وللملفّ خصائص مثل Name، وLength، وLastWriteTime.

Get-ChildItem -File | Select-Object Name, Length, LastWriteTime

عندما لا تعرف «بأيّ خاصيّة تُصفِّي»، تحقّق أوّلاً من أسماء الخصائص عبر Get-Member.

6. أساسيّات خطّ الأنابيب (pipeline)

يمرِّر رمز | في PowerShell نتيجة الأمر الموجود على اليسار إلى الأمر الموجود على اليمين.

Get-Process | Sort-Object CPU -Descending | Select-Object -First 10

ينفِّذ هذا المثال المعالجة التالية من اليسار إلى اليمين:

الحصول على قائمة العمليّات (processes)
   الترتيب تنازليّاً حسب استخدام CPU
   عرض أفضل 10 فقط

التركيبات الشائعة الاستخدام هي كالتالي:

الأمر الدور مثال
Where-Object التصفية بشرط الحصول على الخدمات المتوقّفة فقط
Sort-Object الترتيب الترتيب من الأحدث تحديثاً
Select-Object اختيار الأعمدة أو العدد عرض الاسم والحجم فقط
ForEach-Object معالجة كلّ عنصر معالجة كلّ ملفّ
Export-Csv الإخراج إلى CSV حفظ نتيجة التحقيق

Where-Object ── التصفية بشرط

# عرض الخدمات المتوقّفة فقط
Get-Service | Where-Object { $_.Status -eq "Stopped" }

# عرض الملفّات التي يتجاوز حجمها 100 ميغابايت فقط
Get-ChildItem -File |
  Where-Object { $_.Length -gt 100MB }

# عرض الملفّات التي يحتوي اسمها على backup فقط
Get-ChildItem -File |
  Where-Object { $_.Name -like "*backup*" }

يمثِّل $_ الكائن الحاليّ المتدفِّق عبر خطّ الأنابيب.

Where-Object { $_.Length -gt 100MB }

هذا يعني الحكم على «هل خاصيّة Length للملفّ الحاليّ المعروض أكبر من 100 ميغابايت».

ابتداءً من PowerShell 3.0 يمكن أيضاً استخدام الصيغة المختصرة.

Get-Service | Where-Object Status -EQ "Stopped"

لكن في مرحلة المبتدئين، يكون تتبُّع المعنى مع صيغة كتلة السكربت (scriptblock) أسهل.

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

Sort-Object ── الترتيب

# من الأكبر استخداماً للذاكرة
Get-Process |
  Sort-Object WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet

# من الأحدث تحديثاً
Get-ChildItem -File |
  Sort-Object LastWriteTime -Descending |
  Select-Object -First 20 Name, LastWriteTime

Select-Object ── اختيار الأعمدة اللازمة فقط

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

يُستخدَم أيضاً لتقييد العدد.

Get-Process | Select-Object -First 5
Get-Process | Select-Object -Last 5

قبل الإخراج إلى CSV، يصبح التعامل أسهل بترتيب الأعمدة اللازمة فقط عبر Select-Object.

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

7. استخدم أوامر Format في النهاية

توجد في PowerShell أوامر لتنسيق العرض.

Format-Table
Format-List
Format-Wide

هذه الأوامر «لعرض الشاشة». إن استُخدِمت قبل الإخراج إلى CSV أو قبل التمرير إلى معالجة لاحقة، يتحوّل الكائن إلى كائن عرض بدل الخاصيّات الأصليّة.

# تجنَّب هذا: تختلط معلومات العرض في CSV
Get-Process |
  Format-Table Name, CPU |
  Export-Csv .\process.csv -NoTypeInformation

# صحيح: اختر الخصائص أوّلاً ثمّ أخرِج إلى CSV
Get-Process |
  Select-Object Name, CPU |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

احفظ قاعدة أنّ Format-* «مخصَّص لعرض الشاشة أخيراً»؛ فذلك يقلِّل الأخطاء.

8. أساسيّات معالجة الملفّات والمجلّدات

الأكثر استخداماً في PowerShell هو معالجة الملفّات والمجلّدات.

ما تريد فعله الأمر
عرض الموقع الحاليّ Get-Location
الانتقال إلى موقع Set-Location
عرض القائمة Get-ChildItem
إنشاء ملفّ أو مجلّد New-Item
النسخ Copy-Item
النقل Move-Item
تغيير الاسم Rename-Item
الحذف Remove-Item
التحقّق من الوجود Test-Path

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

Get-Location

الانتقال.

Set-Location C:\Work

إن كان المسار يحتوي على مسافة، ضعه بين علامتَي اقتباس.

Set-Location "C:\Work Files\Reports"

عرض قائمة الملفّات

Get-ChildItem
Get-ChildItem -File
Get-ChildItem -Directory
Get-ChildItem -Recurse

عند التصفية حسب الامتداد، يكون -Filter مفيداً.

Get-ChildItem -Filter *.log

عند البحث بما في ذلك المجلّدات الفرعيّة، استخدم -Recurse.

Get-ChildItem C:\Logs -Filter *.log -Recurse

في الأماكن التي يوجد فيها كمّ هائل من الملفّات، لا تستخدم -Recurse مباشرةً، بل حدِّد المجلّد المستهدَف أوّلاً ثمّ نفِّذ.

الإنشاء

# إنشاء مجلّد
New-Item -ItemType Directory -Path .\archive

# إنشاء ملفّ فارغ
New-Item -ItemType File -Path .\memo.txt

إن كان يُحتمَل أن يكون موجوداً بالفعل، تحقّق أوّلاً.

if (-not (Test-Path .\archive)) {
  New-Item -ItemType Directory -Path .\archive
}

النسخ

Copy-Item .\report.xlsx .\backup\report.xlsx

عند نسخ مجلّد بأكمله، استخدم -Recurse.

Copy-Item .\data .\backup\data -Recurse

عندما يتعلّق الأمر بالكتابة فوق ملفّات موجودة، تحقّق من الأثر مسبقاً.

Copy-Item .\data .\backup\data -Recurse -WhatIf

النقل

Move-Item .\old.log .\archive\old.log

عند نقل عدّة ملفّات بشرط، ضع -WhatIf أوّلاً.

Get-ChildItem .\logs -Filter *.log |
  Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
  Move-Item -Destination .\archive -WhatIf

إن لم توجد مشكلة، أزِل -WhatIf.

Get-ChildItem .\logs -Filter *.log |
  Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
  Move-Item -Destination .\archive

الحذف

يُعامَل الحذف بحذر خاصّ.

Remove-Item .\old.log -WhatIf

نفِّذ بعد التحقّق من صحّة الهدف.

Remove-Item .\old.log

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

# تحقَّق من الهدف أوّلاً
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
  Select-Object FullName, Length, LastWriteTime

# ثمّ تحقَّق من خطّة الحذف
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
  Remove-Item -WhatIf

# وأخيراً نفِّذ
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
  Remove-Item

9. قراءة الملفّات النصّيّة والبحث فيها والكتابة إليها

في تحقيق السجلّات (logs)، تُستخدَم معالجة الملفّات النصّيّة كثيراً.

قراءة ملفّ

Get-Content .\app.log

عند الاكتفاء برؤية النهاية فقط، استخدم -Tail.

Get-Content .\app.log -Tail 50

عند متابعة سجلّ يُضاف إليه باستمرار، استخدم -Wait.

Get-Content .\app.log -Tail 20 -Wait

البحث عن نصّ

Select-String -Path .\app.log -Pattern "ERROR"

يمكن استهداف عدّة ملفّات.

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

يمكن أيضاً استخراج اسم الملفّ ورقم السطر والمحتوى من نتيجة البحث وتحويلها إلى CSV.

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

الكتابة إلى ملفّ

"hello" | Set-Content .\memo.txt -Encoding UTF8
"next line" | Add-Content .\memo.txt -Encoding UTF8

عند حفظ نتيجة أمر، قد يكون Export-Csv أو ConvertTo-Json أسهل للتعامل لاحقاً من Out-File.

Get-Process |
  Select-Object Name, Id, CPU |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

10. أساسيّات التعامل مع CSV

يظهر CSV كثيراً جدّاً في أتمتة الأعمال. في PowerShell، يمكن التعامل مع CSV ليس كنصّ، بل كـ«كائن له أعمدة».

قراءة CSV

لنفترض وجود users.csv التالي:

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

اقرأه.

$users = Import-Csv .\users.csv
$users

تصبح أسماء الأعمدة خصائص (properties).

$users | Select-Object Name, Department

التصفية بشرط

$users |
  Where-Object { $_.Department -eq "Sales" }

بما أنّ قيم CSV تدخل غالباً كنصّ، احذر عند التعامل مع true / false أو الأرقام.

$users |
  Where-Object { $_.Enabled -eq "true" }

الإخراج إلى CSV

$users |
  Where-Object { $_.Department -eq "Sales" } |
  Export-Csv .\sales-users.csv -NoTypeInformation -Encoding UTF8

القاعدة الذهبيّة هي عدم إدراج Format-Table قبل Export-Csv.

# تجنَّب
$users | Format-Table | Export-Csv .\out.csv -NoTypeInformation

# صحيح
$users | Select-Object Name, Department, Enabled | Export-Csv .\out.csv -NoTypeInformation -Encoding UTF8

11. أساسيّات التعامل مع JSON

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

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

تحويل كائن إلى JSON.

[pscustomobject]@{
  Name = "BatchJob"
  Enabled = $true
  Retry = 3
} | ConvertTo-Json

عند وجود طبقات عميقة، حدِّد -Depth.

$config | ConvertTo-Json -Depth 10 | Set-Content .\settings.json -Encoding UTF8

12. أساسيّات العمليّات (processes) والخدمات (services)

الاطّلاع على العمليّات

Get-Process

التحقّق من العمليّات ذات الاستخدام الكبير للذاكرة.

Get-Process |
  Sort-Object WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet

التصفية بالاسم.

Get-Process -Name notepad

يُنفَّذ الإيقاف بحذر.

Stop-Process -Name notepad -WhatIf

نفِّذ إن لم توجد مشكلة.

Stop-Process -Name notepad

الاطّلاع على الخدمات

Get-Service

عند الاكتفاء برؤية الخدمات المتوقّفة فقط.

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

التصفية بالاسم.

Get-Service -Name "Spooler"

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

Get-Service -Name "Spooler"
Restart-Service -Name "Spooler" -WhatIf

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

13. أساسيّات سجلّ الأحداث (event log)

لا غنى عن سجلّ الأحداث في تحقيقات Windows.

التحقّق من الأخطاء الأخيرة.

Get-WinEvent -LogName System -MaxEvents 100 |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message

الاطّلاع على آخر 50 مدخلاً من سجلّ التطبيقات.

Get-WinEvent -LogName Application -MaxEvents 50 |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

عند التصفية حسب الفترة الزمنيّة.

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

Get-WinEvent -FilterHashtable @{
  LogName = "System"
  StartTime = $start
} |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, 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

14. المتغيّرات والمصفوفات وجداول التجزئة (hash tables)

يمكن العمل بأوامر قصيرة فقط، لكن عند إطالة السكربت قليلاً تصبح المتغيّرات مفيدة.

المتغيّر (variable)

$path = "C:\Logs"
Get-ChildItem $path

تبدأ متغيّرات PowerShell بـ $.

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

المصفوفة (array)

$extensions = @("*.log", "*.txt", "*.csv")
foreach ($ext in $extensions) {
  Get-ChildItem C:\Work -Filter $ext
}

جدول التجزئة (hash table)

جدول التجزئة هو تركيبة من المفتاح (key) والقيمة (value).

$params = @{
  Path = "C:\Logs"
  Filter = "*.log"
  Recurse = $true
}

Get-ChildItem @params

تُسمَّى طريقة الكتابة هذه باستخدام @params بـ«splatting». وهي تجعل الأمر أسهل قراءةً عند تزايد المعاملات (parameters).

15. تنسيق النتائج عبر PSCustomObject

عند الرغبة في تجميع نتيجة التحقيق بصورة جدوليّة، يكون [pscustomobject] مفيداً.

[pscustomobject]@{
  ComputerName = $env:COMPUTERNAME
  UserName     = $env:USERNAME
  CheckedAt    = Get-Date
}

يمكن إنشاء عدّة نتائج وتحويلها إلى CSV.

Get-ChildItem C:\Logs -Filter *.log |
  ForEach-Object {
    [pscustomobject]@{
      Name          = $_.Name
      FullName      = $_.FullName
      SizeMB        = [math]::Round($_.Length / 1MB, 2)
      LastWriteTime = $_.LastWriteTime
    }
  } |
  Export-Csv .\log-files.csv -NoTypeInformation -Encoding UTF8

16. أساسيّات ملفّ السكربت .ps1

اجعل المعالجة المستخدَمة كثيراً ملفّ .ps1.

كمثال، لنُنشئ سكربتاً يسرد السجلّات القديمة.

# Find-OldLogs.ps1
param(
  [string]$Path = "C:\Logs",
  [int]$Days = 30,
  [string]$OutputPath = ".\old-logs.csv"
)

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

Get-ChildItem -Path $Path -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -lt $limit } |
  Select-Object FullName, Length, LastWriteTime |
  Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8

Write-Host "Exported: $OutputPath"

مثال على التنفيذ.

.\Find-OldLogs.ps1 -Path C:\Logs -Days 60 -OutputPath .\old-logs.csv

عند استقبال المعاملات (arguments) عبر param()، يسهُل تغيير الشروط لاحقاً.

17. أساسيّات سياسة التنفيذ (execution policy)

عند محاولة تنفيذ .ps1، قد يظهر خطأ كالتالي.

تعذّر تنفيذ هذا السكربت على هذا النظام لأنّ تنفيذ السكربتات معطَّل...

في هذه الحالة، تحقَّق من سياسة التنفيذ الحاليّة.

Get-ExecutionPolicy
Get-ExecutionPolicy -List

على جهاز تطوير شخصيّ، إذا أردتَ فقط تنفيذ سكربتات أُنشئت محلّيّاً، فمن الشائع ضبطها إلى RemoteSigned ضمن نطاق (scope) المستخدم الحاليّ.

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

لكن في أجهزة الشركة، قد تكون مضبوطة عبر سياسة المجموعة (Group Policy). لا تحاول التحايل قسراً، بل تحقَّق من المسؤول أو قواعد التشغيل.

سياسة التنفيذ هي ميزة أمان تتحكّم في شروط تنفيذ سكربتات PowerShell. لكنّها ليست حدّاً أمنيّاً كاملاً (security boundary). في المؤسّسات، يلزم التفكير فيها بالاقتران مع التوقيع الرقميّ (signing) وAppLocker وMicrosoft Defender وإدارة الصلاحيّات وتدقيق السجلّات (log audit).

18. أساسيّات معالجة الأخطاء

قد يستمرّ PowerShell في المعالجة حتّى مع ظهور خطأ.

في المعالجات المهمّة، استخدم -ErrorAction Stop مع try/catch.

try {
  Copy-Item .\source.txt .\backup\source.txt -ErrorAction Stop
  Write-Host "Copy succeeded"
}
catch {
  Write-Error "Copy failed: $($_.Exception.Message)"
}

عند معالجة عدّة ملفّات، فإنّ تسجيل الفشل يتيح التتبُّع لاحقاً.

$results = foreach ($file in Get-ChildItem .\input -File) {
  try {
    Copy-Item $file.FullName .\backup -ErrorAction Stop

    [pscustomobject]@{
      FileName = $file.Name
      Status   = "OK"
      Message  = ""
    }
  }
  catch {
    [pscustomobject]@{
      FileName = $file.Name
      Status   = "NG"
      Message  = $_.Exception.Message
    }
  }
}

$results | Export-Csv .\copy-result.csv -NoTypeInformation -Encoding UTF8

19. الترتيب الآمن لتنفيذ الأوامر المُغيِّرة

في PowerShell، مهمّ الحفاظ على الإجراءات التي تتعامل بأمان مع الأوامر المُغيِّرة (change commands) مثل الحذف والنقل والإيقاف.

الترتيب الأساسيّ هو كالتالي:

1. اعرض الهدف عبر أوامر Get
2. صفِّه عبر Where-Object
3. تحقَّق من قائمة الأهداف عبر Select-Object
4. سجِّله عبر Export-Csv
5. تحقَّق من خطّة التغيير عبر -WhatIf
6. نفِّذ فعليّاً

كمثال، حالة حذف ملفّات .tmp الأقدم من 30 يوماً.

الخطوة 1: عرض الهدف

Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse

الخطوة 2: التصفية بشرط

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

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

الخطوة 3: عرض الأعمدة اللازمة فقط

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

$targets |
  Select-Object FullName, Length, LastWriteTime

الخطوة 4: ترك أثر (audit trail)

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

الخطوة 5: التحقّق عبر WhatIf

$targets | Remove-Item -WhatIf

الخطوة 6: التنفيذ

$targets | Remove-Item

هذا الترتيب يقلِّل الأعطال من نوع «لا أعرف ما الذي حذفتُه».

20. قائمة الأوامر الأساسيّة الشائعة الاستخدام

الموقع والملفّات

الغرض مثال على الأمر
عرض المجلّد الحاليّ Get-Location
الانتقال إلى مجلّد Set-Location C:\Work
عرض القائمة Get-ChildItem
عرض الملفّات فقط Get-ChildItem -File
عرض المجلّدات فقط Get-ChildItem -Directory
البحث في المجلّدات الفرعيّة أيضاً Get-ChildItem -Recurse
التحقّق من الوجود Test-Path .\file.txt
إنشاء مجلّد New-Item -ItemType Directory .\backup
النسخ Copy-Item .\a.txt .\backup\a.txt
النقل Move-Item .\a.txt .\archive\a.txt
التحقّق من خطّة الحذف Remove-Item .\a.txt -WhatIf

معالجة الكائنات

الغرض مثال على الأمر
التصفية بشرط Where-Object { $_.Status -eq "Running" }
الترتيب Sort-Object LastWriteTime -Descending
اختيار الأعمدة Select-Object Name, LastWriteTime
عرض الأعلى فقط Select-Object -First 10
معالجة كلّ عنصر ForEach-Object { $_.Name }
التحقّق من المحتوى Get-Member

الإدخال والإخراج

الغرض مثال على الأمر
قراءة نصّ Get-Content .\app.log
رؤية النهاية Get-Content .\app.log -Tail 50
البحث عن نصّ Select-String -Path .\app.log -Pattern "ERROR"
قراءة CSV Import-Csv .\users.csv
إخراج CSV Export-Csv .\out.csv -NoTypeInformation -Encoding UTF8
قراءة JSON Get-Content .\a.json -Raw \| ConvertFrom-Json
إخراج JSON $obj \| ConvertTo-Json -Depth 10

تحقيق Windows

الغرض مثال على الأمر
قائمة العمليّات Get-Process
قائمة الخدمات Get-Service
سجلّ الأحداث Get-WinEvent -LogName System -MaxEvents 100
متغيّرات البيئة Get-ChildItem Env:
إصدار PowerShell $PSVersionTable
سياسة التنفيذ Get-ExecutionPolicy -List

21. عيّنة عمليّة: تحقيق السجلّات وإصدار تقرير

لنفترض المتطلّب التالي:

نريد البحث في ملفّات .log الموجودة تحت C:\App\Logs عن الأسطر التي حُدِّثت خلال آخر 7 أيّام وتحتوي على ERROR، وتجميعها في CSV.

بدل كتابة الصيغة النهائيّة مباشرةً، نبنيها تدريجيّاً.

الخطوة 1: البحث عن ملفّات السجلّ

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse

الخطوة 2: التصفية بآخر 7 أيّام

$since = (Get-Date).AddDays(-7)

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since }

الخطوة 3: البحث عن ERROR

$since = (Get-Date).AddDays(-7)

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-String -Pattern "ERROR"

الخطوة 4: الإخراج إلى CSV

$since = (Get-Date).AddDays(-7)

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-String -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-report.csv -NoTypeInformation -Encoding UTF8

الخطوة 5: تحويلها إلى سكربت

# Export-ErrorReport.ps1
param(
  [string]$LogPath = "C:\App\Logs",
  [int]$Days = 7,
  [string]$Pattern = "ERROR",
  [string]$OutputPath = ".\error-report.csv"
)

$since = (Get-Date).AddDays(-$Days)

Get-ChildItem $LogPath -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-String -Pattern $Pattern |
  Select-Object Path, LineNumber, Line |
  Export-Csv $OutputPath -NoTypeInformation -Encoding UTF8

Write-Host "Exported: $OutputPath"

مثال على التنفيذ.

.\Export-ErrorReport.ps1 -LogPath C:\App\Logs -Days 14 -Pattern "ERROR|FATAL" -OutputPath .\errors.csv

22. عيّنة عمليّة: أرشفة الملفّات القديمة

المثال التالي ينقل بدل أن يحذف.

نقل ملفّات .xlsx التي لم تُحدَّث منذ 90 يوماً فأكثر من C:\Work\Reports إلى C:\Work\Archive.

التحقّق من الهدف

$source = "C:\Work\Reports"
$dest = "C:\Work\Archive"
$limit = (Get-Date).AddDays(-90)

$targets = Get-ChildItem $source -Filter *.xlsx -File |
  Where-Object { $_.LastWriteTime -lt $limit }

$targets | Select-Object FullName, Length, LastWriteTime

إنشاء وجهة الأرشفة

if (-not (Test-Path $dest)) {
  New-Item -ItemType Directory -Path $dest
}

إخراج الأثر (audit trail)

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

التحقّق عبر WhatIf

$targets | Move-Item -Destination $dest -WhatIf

التنفيذ

$targets | Move-Item -Destination $dest

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

23. المطبّات الشائعة

العرض السبب المعالجة
الأمر طويل ويصعب تذكّره محاولة الحفظ عن ظهر قلب البحث عبر Get-Command، Get-Help -Examples
لا أفهم $_ نقص فهم القيمة الحاليّة في خطّ الأنابيب احفظ الصيغة Where-Object { $_.Name -like "*log*" }
محتوى CSV غريب تنفيذ Export-Csv بعد Format-Table نفِّذ Export-Csv بعد Select-Object
الفشل عند وجود مسافة في المسار عدم وجود علامات اقتباس ضع المسار بين علامتَي اقتباس مثل "C:\Work Files\a.txt"
تعذّر تنفيذ السكربت سياسة التنفيذ تحقَّق عبر Get-ExecutionPolicy -List
أهداف الحذف كثيرة جدّاً الشرط واسع جدّاً تحقَّق أوّلاً عبر Select-Object FullName و-WhatIf
لا أعرف اسم الخاصيّة عدم النظر في بنية الكائن استخدم Get-Member
تشويه في الأحرف (mojibake) افتراض ترميز مختلف تحقَّق من -Encoding في الإدخال والإخراج ومن التطبيق المستخدَم

24. ترتيب حفظ الأوامر

لا حاجة لحفظ جميع الأوامر منذ البداية.

الترتيب التالي مُوصى به.

المرحلة الأولى: العرض والبحث

Get-Command
Get-Help
Get-Member
Get-Location
Set-Location
Get-ChildItem
Get-Content
Select-String

المرحلة الثانية: التصفية والترتيب

Where-Object
Sort-Object
Select-Object
ForEach-Object
Format-Table
Format-List

المرحلة الثالثة: الإدخال والإخراج

Import-Csv
Export-Csv
ConvertFrom-Json
ConvertTo-Json
Set-Content
Add-Content
Out-File

المرحلة الرابعة: التغيير

New-Item
Copy-Item
Move-Item
Rename-Item
Remove-Item
Start-Service
Stop-Service
Restart-Service
Stop-Process

احفظ أوامر التغيير مع أوامر التحقّق دائماً معاً.

# العرض
Get-ChildItem .\logs -Filter *.tmp

# عرض خطّة الحذف
Get-ChildItem .\logs -Filter *.tmp | Remove-Item -WhatIf

# التنفيذ
Get-ChildItem .\logs -Filter *.tmp | Remove-Item

25. قائمة تحقّق للتشغيل الفعليّ في الميدان

عند استخدام PowerShell في العمل، من الآمن التحقّق من النقاط التالية.

  • تأكّدتُ ممّا إذا كان PowerShell المُشغَّل هو powershell.exe أم pwsh.exe
  • تحقّقتُ من الإصدار عبر $PSVersionTable
  • عرضتُ الهدف بأوامر Get-* قبل التغيير
  • تحقّقتُ على الشاشة من شرط Where-Object
  • استخدمتُ -WhatIf قبل الحذف أو النقل أو الإيقاف
  • حفظتُ قائمة الأهداف قبل التنفيذ في CSV
  • تحقّقتُ في بيئة الإنتاج من النسخ الاحتياطيّ أو إجراء الاستعادة
  • تحقّقتُ من سياسة تنفيذ السكربت وقواعد الشركة
  • جهّزتُ إخراج سجلّ عند حدوث خطأ
  • استخدمتُ اسم الأمر الرسميّ بدل الاسم المستعار في السكربتات المُشارَكة

26. الخلاصة

أساس PowerShell ليس حفظ كمّ هائل من الأوامر. ما يفيد في العمل الفعليّ هو إتقان النمط التالي:

البحث عبر Get-Command
الاطّلاع على الاستخدام عبر Get-Help
التحقّق من الخصائص عبر Get-Member
عرض الهدف عبر Get-*
التصفية عبر Where-Object
ترتيب الأعمدة عبر Select-Object
ترك الأثر عبر Export-Csv
التحقّق من خطّة التغيير عبر -WhatIf
التنفيذ أخيراً

بما أنّ PowerShell بيئة قويّة تصل إلى حذف الملفّات، وإيقاف الخدمات، وإنهاء العمليّات، وحتّى معالجة السجلّ (registry)، فإنّ أوّل ما ينبغي تعلّمه ليس «الأمر الخطِر»، بل «إجراء التحقّق الآمن من الهدف».

العرض  التصفية  التسجيل  التجربة  التنفيذ

بالالتزام بهذا الترتيب، لا يبقى PowerShell مجرّد شاشة سوداء، بل يصبح أداة عمليّة لتنظيم أعمال Windows وتحقيقها وأتمتتها.

روابط مرجعيّة

مقالات ذات صلة

الخدمات المرتبطة بهذا الموضوع

تطوير تطبيقات Windows

ندعم تطوير برمجيّات Windows، بما في ذلك تطبيقات الأعمال، والتكامل مع الأجهزة، وأدوات الاتّصال.

عرض الخدمة / التواصل معنا

الاستفادة من الأصول القائمة ودعم الترحيل

ندعم جرد الأصول القائمة من الدُفعات القديمة (batch) وVBScript وVBA وPowerShell وCOM / ActiveX، وإصلاحها، وترحيلها.

التواصل معنا

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

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

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

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

من أين ينبغي أن أبدأ تعلّم PowerShell؟
ليس بحفظ الأوامر، بل بتعلّم طريقة البحث عنها. الأمور المهمّة ثلاثة: القدرة على البحث عن الأوامر عبر Get-Command وGet-Help، وتمرير النتائج إلى الأمر التالي عبر خطّ الأنابيب (|)، والتحقّق من الأثر عبر -WhatIf أو -Confirm قبل الحذف أو الإيقاف أو التغيير. وعندما لا تعرف اسم خاصيّة (property) الكائن (object)، تحقّق من محتواه عبر Get-Member. التدفّق الأساسيّ هو «البحث ← العرض ← التصفية ← الترتيب ← الإخراج ← التغيير عند الحاجة».
ما الفرق بين PowerShell وموجّه الأوامر (Command Prompt)؟
الفرق الأكبر هو أنّ إخراج موجّه الأوامر يتمحور حول النصّ، بينما إخراج PowerShell عبارة عن كائنات (objects). فمثلاً، يُعامَل الملفّ ككائن له خصائص (properties) مثل Name وLength وLastWriteTime، ما يجعل التصفية عبر Where-Object والترتيب عبر Sort-Object أموراً طبيعيّة الكتابة. كما أنّ أسماء الأوامر موحَّدة بصيغة فعل-اسم مثل Get-ChildItem وCopy-Item، ما يسهِّل البحث حتّى عن الأوامر غير المعروفة.
أيّهما ينبغي استخدامه، Windows PowerShell 5.1 أم PowerShell 7.x؟
عند التعلّم من جديد، لا مشكلة في اتّخاذ PowerShell 7.x (pwsh.exe) أساساً. لكن سكربتات الإدارة القديمة داخل الشركة والوحدات (modules) الخاصّة بـ Windows قد تكون مبنيّة على افتراض Windows PowerShell 5.1 (powershell.exe). في العمل الفعليّ، من المفيد التحقّق أوّلاً من الإصدار عبر $PSVersionTable، وكتابة شرط مثل #Requires -Version 7.0 في بداية السكربتات التي يُراد تشغيلها بإصدار معيّن فأعلى، لتقليل الأعطال.
كيف يمكن تنفيذ الحذف أو التغيير بأمان في PowerShell؟
بالالتزام بترتيب «العرض ← التصفية ← التسجيل ← التجربة ← التنفيذ». وبالتحديد: اعرض الهدف أوّلاً بأوامر Get، ثمّ صفِّه عبر Where-Object، وتحقّق من قائمة الأهداف عبر Select-Object، واحفظ أثراً في CSV عبر Export-Csv، وتحقّق من التغيير المُزمَع عبر -WhatIf قبل التنفيذ الفعليّ. بما أنّ PowerShell يُنفِّذ التحقيق والتغيير على الشاشة نفسها، فإنّ عادة البدء بالتحقّق للقراءة فقط أمر مهمّ.

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

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

غو كومورا

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

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

روابط عامة

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