أساسيّات أوامر PowerShell ── العمليّات الأولى الواجب تعلّمها والاستخدام الآمن
· آخر تحديث: · غو كومورا · PowerShell, Windows, سطر الأوامر, الأتمتة, الاستفادة من الأصول القائمة
1. ما ينبغي معرفته أوّلاً
PowerShell هو بيئة أوامر يمكن استخدامها للتحقّق من إعدادات Windows، وترتيب الملفّات، وتحقيق السجلّات (logs)، ومعالجة CSV، والتحكّم في الخدمات (services)، وأتمتة الأعمال الروتينيّة.
لكن لا حاجة لكتابة سكربتات معقّدة منذ البداية. يكفي في البداية تذكّر التدفّق التالي لتصبح قادراً على الاستفادة منه إلى حدّ كبير في العمل الفعليّ.
البحث ← العرض ← التصفية ← الترتيب ← الإخراج ← التغيير عند الحاجة
أساس PowerShell ليس «حفظ الأوامر الطويلة عن ظهر قلب». المهمّ هو الأمور الثلاثة التالية:
- القدرة على البحث عن الأوامر عبر
Get-CommandوGet-Help - القدرة على تمرير النتائج إلى الأمر التالي عبر خطّ الأنابيب
| - التحقّق من الأثر عبر
-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 وتحقيقها وأتمتتها.
روابط مرجعيّة
- مجموعة العيّنات الكاملة لهذا المقال (سكربتات مبوَّبة حسب الموضوع، واختبارات Pester) - komurasoft-blog-samples (GitHub)
- PowerShell Documentation - Microsoft Learn
- Install PowerShell on Windows - Microsoft Learn
- Differences between Windows PowerShell 5.1 and PowerShell 7.x - Microsoft Learn
- Get-Command - Microsoft Learn
- Get-Help - Microsoft Learn
- Get-Member - Microsoft Learn
- about_Pipelines - Microsoft Learn
- Where-Object - Microsoft Learn
- Select-Object - Microsoft Learn
- Import-Csv - Microsoft Learn
- Export-Csv - Microsoft Learn
- about_Execution_Policies - Microsoft Learn
مقالات ذات صلة
- ترتيب ترميزات الأحرف ونهايات الأسطر في Windows
- دليل الترحيل استعداداً لإلغاء دعم VBScript
- مطبّات تطوير COM/OCX/ActiveX
الخدمات المرتبطة بهذا الموضوع
تطوير تطبيقات Windows
ندعم تطوير برمجيّات Windows، بما في ذلك تطبيقات الأعمال، والتكامل مع الأجهزة، وأدوات الاتّصال.
الاستفادة من الأصول القائمة ودعم الترحيل
ندعم جرد الأصول القائمة من الدُفعات القديمة (batch) وVBScript وVBA وPowerShell وCOM / ActiveX، وإصلاحها، وترحيلها.
مقالات ذات صلة
أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.
مجموعة أوامر PowerShell العمليّة ── إضافة وظائف صغيرة شائعة الاستخدام في العمل اليوميّ
نرتّب هنا أوامر PowerShell العمليّة المستخدَمة في العمل اليوميّ، مثل مواضع استخدام Measure-Object وGroup-Object وSelect-String وCompare-O...
طريقة تشغيل PowerShell من C# (CSharp) واستقبال النتيجة ككائن
نرتّب من منظور عمليّ طريقة تشغيل PowerShell من C# واستقبال النتيجة ككائن PSObject بدل نصّ، بدءًا من PowerShell SDK وAddCommand وAddParame...
تهيئة اختبارات PowerShell عبر Pester ── الأسلوب العمليّ لجعل سكربتات التشغيل أقلّ عرضةً للكسر
نُنظِّم الإجراءات العمليّة لاختبار سكربتات PowerShell عبر Pester v5، بدءاً من معالجة التواريخ وعمليّات الملفّات وعمليّات الحذف، مروراً با...
معالجة الأخطاء وتصميم إعادة التنفيذ في PowerShell ── من فخّ عدم نجاعة try/catch إلى قواعد exit code وإعادة المحاولة
نرتّب من منظور عمليّ الفرق بين الأخطاء المُنهِية وغير المُنهِية في PowerShell، والفخّ الذي يجعل try/catch غير فعّال والقاعدة الثابتة لـ -...
سياسة تنفيذ PowerShell وتوقيع السكربتات ── دليل عمليّ للتخلّص من تشغيل «السدّ بـ Bypass»
سياسة تنفيذ PowerShell هي «جهاز أمان لا حدّ أمنيّ (security boundary)». نرتّب الفروق بين RemoteSigned وغيرها، وأولويّة النطاقات (scopes)،...
أين يتصل هذا الموضوع
ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.
تطوير تطبيقات ويندوز
ندعم تطوير برامج ويندوز للأعمال، وتكامل الأجهزة، وأدوات التواصل.
الأسئلة الشائعة
أسئلة شائعة حول موضوع هذه المقالة.
- من أين ينبغي أن أبدأ تعلّم 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 يُنفِّذ التحقيق والتغيير على الشاشة نفسها، فإنّ عادة البدء بالتحقّق للقراءة فقط أمر مهمّ.
الملف الشخصي للمؤلف
صفحة الملف الشخصي لمؤلف المقالة.
غو كومورا
مؤسّس شركة كومورا سوفت ذ.م.م.
يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.
روابط عامة