Invoke-Expression: الفوائد، العيوب، وأفضل الممارسات

يمكن أن يكون أمر Invoke-Expression في PowerShell سهلاً للفهم عندما يجب استخدامه ومتى يجب عدم استخدامه. في هذه المقالة ، قمت بتجميع عدد من أسئلة المرجعية الأعلى. سأقسمها وسأضمن تضمين العديد من الأمثلة المفيدة التي يمكنك الرجوع إليها في أي وقت تحتاج فيه إليها. هذا يعني أنه يجب عليك وضع هذه الصفحة في المفضلة الآن!

ترغب في المزيد من النصائح مثل هذه؟ تحقق من مدونتي الشخصية لـ PowerShell على: https://www.nkasco.com/

ما هو الأمر Invoke-Expression؟

الوصف الرسمي ، حسب شركة مايكروسوفت ، هو “يقيم أمر Invoke-Expression أو يشغل سلسلة محددة كأمر ويعيد نتائج التعبير أو الأمر. بدون Invoke-Expression ، ستعاد السلسلة المقدمة في سطر الأوامر كما هي (مكررة) دون تغيير.”

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

أبسط مثال لاستخدام Invoke-Expression هو تحديد نص برمجي وتمرير تلك السلسلة إلى معلمة Command. يقوم Invoke-Expression بتنفيذ تلك السلسلة بعد ذلك.

#تشغيل أمر PowerShell عبر Invoke-Expression
$Command = 'Get-Process'
Invoke-Expression -Command $Command

#تنفيذ نص عبر Invoke-Expression
$MyScript = '.\MyScript.ps1'
Invoke-Expression -Command $MyScript

ماذا لو كانت هناك مسافات في مسار النص؟

تأكد من تضمين السلاسل بين علامات الاقتباس الفردية أو المزدوجة.

على سبيل المثال، إذا كنت ترغب في تنفيذ سلسلة تحتوي على مسافة في المسار، فلن تعمل هذه الخيارات:

# هذه لا تعمل
$MyScript = "C:\Folder Path\MyScript.ps1"
#أو
$MyScript = "'C:\Folder Path\MyScript.ps1'"
Invoke-Expression $MyScript

لماذا؟ لأن هذا بالضبط نفس الشيء الذي يتم كتابته مباشرةً في وحدة التحكم PowerShell:

PS51> C:\Folder Path\MyScript.ps1

ومع ذلك، إذا قمت بتضمين عنصر المسار بين علامات الاقتباس الفردية أو المزدوجة مع تضمين السلسلة بأكملها بين علامات الاقتباس، ستقوم Invoke-Expression بتنفيذ النص كما هو متوقع.

$MyScript = "C:\'Folder Path'\MyScript.ps1"
Invoke-Expression $MyScript

Q. How do you pass parameters to scripts invoked with Invoke-Expression?

المعامل الوحيد الذي يحتويه Invoke-Expression هو Command. ليس هناك طريقة أصلية لتمرير المعاملات باستخدام Invoke-Expression. ومع ذلك، بدلاً من ذلك، يمكنك تضمينها في النص الذي تمرره إلى معامل Command.

ربما يكون لديك نص يحتوي على معاملين يسمى Path و Force. بدلاً من استخدام معامل محدد عبر Invoke-Expression، يمكنك تمرير المعاملات إلى ذلك النص عن طريق تمريرها كما تفعل عادةً عبر وحدة التحكم.

إذا كنت تقوم عادةً بالاتصال بهذا النص بهذه الطريقة عبر وحدة التحكم:

PS51> & 'C:\Scripts\MyScript.ps1' -Path 'C:\file.txt' -Force

عليك تضمين تلك السطر بأكمله في سلسلة ثم تمرير تلك السلسلة إلى معامل Command.

$scriptPath = 'C:\Scripts\MyScript.ps1'
$params = '-Path "C:\file.txt" -Force'
Invoke-Expression "$scriptPath $params"
# أو
$string = 'C:\Scripts\MyScript.ps1 -Path "C:\file.txt" -Force'
Invoke-Expression $string

هل يكون استخدام try/catch منطقيًا مع Invoke-Expression؟

لا حقا. هذا يعني أنك بحاجة إلى استخدام معالجة الأخطاء داخل معلمة Command الخاصة بك.

مثال:

# لا يعمل - لا يعمل Invoke-Expression كمعالج أخطاء عالمي!
try{
    $Command = 'Get-Process powerhell'
    Invoke-Expression $Command -ErrorAction Stop
} catch {
    Write-Host "Oops, something went wrong!"
}

ما الفرق بين Invoke-Expression والمشغل الدقيق (&

المشغل الدقيق (&) ممتاز لتشغيل أمر أو سكريبت أو كتلة سكريبت بسرعة. ولكن، المشغل الدقيق لا يقوم بتحليل الأمر. لا يمكنه تفسير معلمات الأمر كما يمكن لـ Invoke-Expression.

على سبيل المثال، ربما أود الحصول على عملية PowerShell Core باستخدام cmdlet Get-Process باستخدام الكود Get-Process -ProcessName pwsh. لن يعمل دمج Get-Process والمعلمة كما هو متوقع باستخدام المشغل الدقيق.

$a = "Get-Process"

## لا يعمل
& "$a pwsh"

لكن إذا نفذت هذا السلسلة باستخدام Invoke-Expression، سيعمل كما هو متوقع.

Invoke-Expression "$a pwsh"

ما الفرق بين Invoke-Expression وStart-Process؟

يقدم cmdlet Start-Process كود الخروج أو الإرجاع في الكائن المرجع. يتيح لك الانتظار حتى يكتمل تنفيذ العملية المطلوبة ويتيح لك تشغيل العملية تحت بيانات اعتماد ويندوز مختلفة. Invoke-Expression سريع وقذر في حين يمكن أن يكون Start-Process أكثر فائدة لتفسير نتائج العملية التي تم تنفيذها.

ما الفرق بين Invoke-Expression و Invoke-Command?

Invoke-Expression تقوم فقط بـ “تحويل” سلسلة نصية إلى كود قابل للتنفيذ. Invoke-Command، من ناحية أخرى، يستفيد من التحكم البعيد في PowerShell، مما يمنحك القدرة على استدعاء الكود محليًا أو عن بعد على أجهزة الكمبيوتر.

Invoke-Command هو الأفضل إذا كنت تكتب الأوامر المنفذة الآن، حيث تحتفظ بـ intellisense في بيئة التطوير المتكاملة (IDE) الخاصة بك بينما Invoke-Expression سيكون مفضلاً إذا كنت ترغب في استدعاء نص آخر من داخل النص الحالي الخاص بك.

مثال:

# تعمل هذه الأوامر بنفس الطريقة، لكننا فقدنا الـ intellisense في مثال Invoke-Expression.
Invoke-Command -ScriptBlock {
    Get-Process Chrome
    Get-Process Powershell
}

Invoke-Expression -Command "
Get-Process Chrome
Get-Process Powershell
"

ما الفرق بين Invoke-Expression و Invoke-Item?

أما Invoke-Item فإن أمر cmdlet يمنحك الدعم المباشر لعدة مسارات لفتح المستندات بإجراءها الافتراضي، مع معلمات لتضمين، استبعاد، إضافة بيانات اعتماد، وحتى تأكيد للأمان الإضافي.

هل Invoke-Expression آمن؟

A. If someone had malicious intent they might be able to trick some virus programs by masking malicious code that constructs itself during runtime. Invoke-Expression will happily execute whatever text is passed to it’s Command parameter.

مثال:

$Command = "(Invoke-Webrequest -Uri `"http://website.com/CompletelySafeCode`").Content"
Invoke-Expression $Command

ما هي بعض الممارسات الجيدة لتنفيذ الأوامر/التعبيرات المتعددة؟

إذا كان لديك أوامر متعددة لتنفيذها، حتى ولو كان Invoke-Expression يقبل فقط سلسلة نصية بدلاً من مصفوفة، يمكننا استخدام خط أنابيب PowerShell لإرسال الكائنات عبر الخط أحدها تلو الآخر.

مثال:

# لا يعمل
$MyCollection = @(
    'Get-Process Chrome',
    'Get-Service bits'
)
Invoke-Expression $MyCollection

# يعمل
'Get-Process Chrome', 'Get-Service bits' | Invoke-Expression

كيف يمكنني استخدام Invoke-Expression مع إدخال المستخدم؟

يجب أن تكون حذرًا للغاية عند استخدام Invoke-Expression مع إدخال المستخدم. إذا سمحت برسالة توجيه للمستخدم بطريقة تمنحهم الوصول خارج الأمر الذي تنوي تنفيذه، فقد يؤدي ذلك إلى إنشاء ثغرة غير مرغوب فيها. إليك طريقة واحدة يمكنك من خلالها تنفيذ إدخال المستخدم بأمان مع Invoke-Expression.

do{
    $Response = Read-Host "Please enter a process name"
    $RunningProcesses = Get-Process

    # قم بالتحقق من صحة إدخال المستخدم هنا قبل المتابعة
    if($Response -notin $RunningProcesses.Name){
        Write-Host "That process wasn't found, please try again.`n" # تجنب استخدام $Response هنا
    }
} until ($Response -in $RunningProcesses.Name)

$Command = "Get-Process $Response"
Invoke-Expression $Command

الاستنتاج

لكل cmdlet مكانه الخاص، و Invoke-Expression هو واحد منها الذي ستصادفه جميع الأطراف في نقطة ما. من المهم فهم مزايا وعيوب cmdlets المستخدمة بشكل متكرر بحيث تقوم بتنفيذها بطريقة تضمن نجاحك. أنا متشوق لسماع كيف استخدمت Invoke-Expression لحل بعض التحديات الخاصة بك، اترك تعليقًا أدناه وشارك قصتك!

هل ترغب في المزيد من النصائح مثل هذه؟ تفضل بزيارة مدونتي الشخصية حول PowerShell على: https://www.nkasco.com/

قراءة إضافية

Source:
https://adamtheautomator.com/invoke-expression/