فئات PowerShell: البداية

PowerShell هي لغة موجهة للكائنات. عند تشغيل الأوامر، سترى النتائج على الشاشة، وهذه النتائج هي كائنات. الكائنات لا تظهر من العدم؛ المطورون يقومون بإنشائها، أو بالأحرى بتكوينها باستخدام الفئات. فئات PowerShell تمثل تعريفات أو مخططات لتلك الكائنات.

رغم أنك قد تكون معتادًا على إنشاء الكائنات باستخدام أوامر مثل New-Object واستخدام مسرع النوع pscustomobject، إلا أن هذه ليست كائنات “جديدة”. أنواع الكائنات التي تنتجها هذه الأساليب هي من نوع معين. فئات PowerShell تحدد هذا النوع.

في هذا البرنامج التعليمي، ستتعلم كيفية البدء في استخدام فئات PowerShell. ستقوم بإنشاء أول فئة مع بنائها، وستتعلم كيفية إنشاء كائنات من الفئة الخاصة بك، وستزود فئتك بخصائص وطرق.

لمزيد من المعلومات حول مصطلحات مثل الكائنات والخصائص والطرق، راجع المقالة في المدونة العودة إلى الأساسيات: فهم كائنات PowerShell.

المتطلبات المسبقة

إنشاء أول فئة وكائن

قبل أن تتمكن من فهم تفاصيل فئة PowerShell بشكل كامل، يجب أن تقوم أولاً بإنشاء فئة بسيطة. ستتعلم عن المواضيع المتقدمة لاحقًا.

إن إنشاء فئتك الأولى سيشعر قليلاً كأنك تقوم بإنشاء وظيفة. بناء الجملة الأساسي هو نفسه. يتم إنشاء فئة من تعريف مثل الوظيفة. على عكس الوظائف ، فإن السطر الأول لا يبدأ بـ function تليه اسم الوظيفة ، بل يبدأ بـ class تليه اسم نوع الكائن الخاص بك.

فيما يلي سترى هيكل الفئة الأساسي لـ الطالب.

class student {

}

تحتوي الفئات على خصائص تبدو مثل المعاملات وهي سمات تصف تلك الفئة. يوضح المثال أدناه فئة تسمى الطالب مع خاصيتين ؛ FirstName و LastName.

عند تحديد خاصية ، يجب عليك دائمًا تحديد نوع يحدد “مخططًا” محددًا لقيم الخاصية التي يمكن أن تحتوي عليها. في المثال أدناه ، يتم تحديد كلا الخاصيتين كـ strings.

يجب عليك دائمًا تحديد أنواع الخصائص. سترى السبب لاحقًا.

class student {
    [string]$FirstName
    [string]$LastName
}

بعد تحديد فئة ، أنشئ كائنًا منها أو قم بتثبيت كائن. هناك طرق متعددة لتثبيت الكائنات من الفئات ؛ واحدة من الطرق الشائعة هي استخدام مسرعات النوع مثل [student] التي تمثل الفئة ، تليها طريقة افتراضية تأتي مع كل فئة تسمى new().

استخدام اختصار مسرع النوع هو نفسه كإنشاء كائن باستخدام أمر New-Object.

New-Object -TypeName student

بمجرد إنشاء كائن من تلك الفئة ، قم بتعيين قيم للخصائص. يتم تعيين قيم Tyler و Muir لخصائص FirstName و LastName في المثال أدناه.

class student {
    [string]$FirstName
    [string]$LastName
}
$student1 = [student]::new()
$student1.FirstName = 'Tyler'
$student1.LastName = 'Muir'
$student1

بمجرد إنشاء الكائن وتعيين قيم للخصائص ، قم بتفقد الكائن عن طريق استدعاء المتغير الذي قمت بتعيين الكائن له ، كما هو موضح أدناه.

Creating an object from the student class.

الآن بعد أن قمت بإنشاء كائن من الفئة ، قم بتوجيه هذا الكائن مثل أي كائن آخر في PowerShell إلى cmdlet Get-Member لفحصه. يمكنك أن ترى أدناه أن الكائن الذي يحتويه المتغير $student1 هو من النوع student.

سيكون اسم الفئة دائمًا متوافقًا مع نوع الكائن.

لاحظ أن Get-Member يعيد أربعة أساليب وخاصيتين. قد تبدو الخاصيات مألوفة ، ولكن الأساليب بالتأكيد ليست كذلك. تضيف PowerShell بعض الأساليب تلقائيًا ، ولكن يمكنك إضافة أساليب خاصة بك أو حتى تعديل الأساليب الافتراضية.

Showing members from custom student object.

إنشاء الأساليب

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

A method definition looks like below with an output type that defines what type of object is returned from this method, the name of the method, and the code to execute inside of a scriptblock.

[<output type>]<name>() {
	<code that runs when the method is executed>
}

لاحظ الأقواس () بعد الاسم. هنا يمكنك تعريف معلمات الأسلوب (التي سيتم التطرق إليها لاحقًا). تسمح لك معلمات الأسلوب بتغيير وظائف الأسلوب تمامًا كما يمكنك مع معلمات الوظيفة.

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

إرجاع القيمة هو أمر إلزامي

سوف تعيد وظائف PowerShell الكائنات ببساطة عن طريق وضع الكائن في أي مكان في الوظيفة مثل المثال أدناه.

function foo {
	$object = Get-Service
	$object ## فقط إرسال الكائن إلى خط الأنابيب
}

ومع ذلك، إذا كانت الأسلوب يعيد كائنًا، فيجب عليك استخدام هيكلة الـ return كما هو موضح أدناه.

[string]GetName() {
	return 'foo'
}

استخدام متغير $this

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

فيما يلي مثال لأسلوب يسمى GetName() يتم إضافته إلى فئة student والذي يقوم بدمج قيمة الخصائص FirstName و LastName وإرجاعهما.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
}

الآن يمكنك استدعاء طريقة GetName() باستخدام علامة النقطة كما هو موضح أدناه. إذا قمت بتعيين قيم للخصائص FirstName و LastName من قبل، ستقوم GetName() بإرجاعهما.

Creating a class with a method and showing to output.

إضافة معاملات للـأساليب

في المثال أعلاه، عندما قمت بتنفيذ السطر $student1.GetName()، كنت تستدعي طريقة GetName() كما هي. يمكنك تعريف معاملات داخل الأقواس تمامًا كما تفعل في الوظائف.

لقد أعادت طريقة GetName() فقط القيم التي تم تعيينها لخصائص FirstName و LastName. ولكن ماذا لو كنت تفضل أن يكون هناك طريقة لتعيين الخصائص التي يمكن لـ GetName() أن تحصل عليها بعد ذلك؟ في هذه الحالة ، تحتاج إلى تعريف معاملات الطريقة.

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

لاحظ نوع الإخراج [void]. عندما لا تقوم الطريقة بإخراج أي شيء ، فلست بحاجة إلى بنية return ، ويجب تعريف نوع الإخراج كـ [void] لإخبار PowerShell بأن الطريقة لا تُرجِع أي شيء.

[void]SetName([string]$Name) {

}

على سبيل المثال ، ربما تقبل طريقة SetName() اسمًا كاملاً (الاسم الأول والاسم الأخير). إذا كان الأمر كذلك ، في كتلة النص البرمجي ، يمكنك ثم تقسيم هذه السلسلة وتعيين الاسم الأول والاسم الأخير بهذه الطريقة.

عن طريق إدراج طريقة SetName() في فئة student ، هكذا يبدو الأمر الآن.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

الآن يمكنك تمرير اسمًا كاملاً كمعامل إلى طريقة SetName() ، والتي تعين خصائص FirstName و LastName للكائن الحالي.

Creating a class with a void method and showing the output when it is run.

التحميل الزائد للطرق

ربما ترغب في تعريف مجموعات معاملات مختلفة لطريقة. على غرار كيفية عمل مجموعات المعاملات في الوظائف والأدوات النصية ، يمكنك تعريف “سياقات” معامل مختلفة أو توقيعات الطريقة المختلفة.

ربما تود تعيين معلمات FirstName و LastName عن طريق تمرير اسم كامل إلى طريقة SetName() أو تمرير الاسم الأول والاسم الأخير بشكل منفصل. ليس عليك اختيار واحد فقط؛ يمكنك تعريف كلاهما باستخدام توقيعات الطرق.

عند تعريف أكثر من توقيع للطرق في صنف، يُطلق عليه السم overloaded.

باستخدام المثال المعاد استخدامه من الفقرة السابقة، يمكنك إنشاء تحميل زائد للطريقة SetName() لقبول سلسلتين بدلاً من سلسلة واحدة. عند تمرير سلسلتين بدلاً من سلسلة واحدة، تفترض طريقة SetName() أن السلسلة الأولى هي FirstName والسلسلة الثانية هي LastName. مع هذا التحميل الزائد، سيبدو الصنف على النحو التالي.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
    
    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}
Showing that the method overload works by providing either one or two strings.

بناء الطوب

عندما تقوم بت實例ة كائن باستخدام طريقة new() أو طريقة أخرى، يمكنك إخبار PowerShell بتشغيل بعض الشيفرة المحددة من قبل المستخدم تسمى بناء الطوب. بناء الطوب يشبه الطرق، ولكنها تعمل تلقائياً عندما يقوم PowerShell بتشغيل كائن.

كل صنف لديه بناء طوب افتراضي. هذا البناء الطوب الافتراضي لا يفعل الكثير؛ فهو فقط مسؤول عن إنشاء الكائن. يمكنك رؤية بناء الطوب الافتراضي عن طريق عرض نتيجة طريقة New. يمكنك أن ترى هنا أن هذا السطر يعيد طريقة new() واحدة فقط.

[student]::New
Default PowerShell constructor

تحميل زائد لبناء الطوب

ربما تود تعيين قيمة لخصائص FirstName و LastName فور إنشاء الكائن، بدلاً من استخدام العلامة النقطية التقليدية. في هذه الحالة، يمكنك إنشاء مُنشئ يحتوي على معامل يستدعي بعدها الدالة SetName().

فيما يلي مثال على مُنشئ لفئة student. لاحظ أن المُنشئ ليس له اسم محدد أو يسبقه نوع الإخراج. يستخدم المُنشئات دائمًا نفس اسم الفئة.

يسمح لنا استدعاء الدالة الموجودة بالمُنشئ باستخدام إعادة استخدام الدالة التي كتبناها بالفعل للتعامل مع تعيين المتغيرات.

student([string]$Name) {
	$this.SetName($Name)
}

وفيما يلي ستجد المُنشئ المُضاف إلى فئة student.

class student {
    [string]$FirstName
    [string]$LastName
    
    student([string]$Name) {
        $this.SetName($Name)
    }

    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

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

Showing the output from using the constructor with a string

يمكنك الآن رؤية المُنشئ المُعَوَّض مرة أخرى باستخدام [student]::New. لاحظ الآن أن المُنشئ المُعَوَّض الجديد معرف بمعامل Name.

Overloaded constructor

تحديد مُنشئ افتراضي ومعَوَّض

الآن بعد أن أضفت مُنشئًا مُعَوَّضًا إلى فئة student، يقوم PowerShell بالكتابة فوق المُنشئ الافتراضي. ولكن يمكنك استعادته عن طريق إنشاءه يدويًا بدون معاملات.

student() {}

يمكنك رؤية ما يبدو عليه ذلك في فئة student أدناه.

class student {
    [string]$FirstName
    [string]$LastName

    student([string]$Name) {
        $this.SetName($Name)
    }

    student() {}

    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

الآن تحقق مرة أخرى من المُنشئات. سترى الآن ظهور كلا المُنشئين.

[student]::New
Creating a default and custom constructor

وراثة الفئات

مثل جميع اللغات الموجهة لكائن، يمكنك بناء فئات PowerShell بشكل تسلسلي مع وجود عدة فئات. يمكن لكل فئة أن تحتوي على فئات “أب” و”ابن” تبدأ من أغراض أقل تحديدًا وأكثر تعميمًا وتزيد من التحديد.

على سبيل المثال، تمثل فئة “طالب” لدينا طالبًا جامعيًا (ابن / محدد بشكل أكثر). هذا الطالب الجامعي هو شخص (أب / عام). هاتين المفاهيمتين مرتبطتين وتشكلان تسلسلًا.

A child class can inherit a parent class which means it can hold all properties and methods (members) defined via a parent class. We know that a person class may have properties like eye_color, height, and weight and perhaps a method called SetHeight().

إذا كان الطالب هو شخص، فإن للطالب لا يزال تلك الخصائص والطرق. سيؤدي تنفيذ نفس الأعضاء على فئة “الطالب” التي تمتلكها فئة “الشخص” إلى تكرار الجهد. يمكنك تعريف توريث الفئة لتعريف جميع أعضاء فئة “الشخص” تلقائيًا على فئة “الطالب”.

إذا لم يكن هذا منطقيًا الآن، فإنه سيكون كذلك عندما نتابع العرض التوضيحي.

عرض توضيحي لتوريث الفئة

أولاً، أنشئ نسخة من فئة “الطالب” التي قمت بإنشائها سابقًا، واحذف المُنشئات وغير اسمها إلى فئة “الشخص”. يجب أن تبدو فئة “الشخص” الخاصة بك كما يلي.

A student, of course, has a first name and last name, but the class can be described more accurately by labeling it as a person. When creating a more “generic” class like this, you can create more specific “child” classes from it.

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

الآن، أنشئ عدة فئات تمثل شخصًا لكن لها دور أكثر تحديدًا. على سبيل المثال، في مقتطف الشفرة أدناه، لديك الآن فئة “المعلم” وفئة “الطالب”.

class teacher {
    [int]$EmployeeId
}

class student {
    [int]$StudentId
}

على هذا النحو، تكون فئات “المعلم” و”الطالب” منفصلة تمامًا عن فئة “الشخص”. ليس لديهم أي علاقة ولا يمكنهما توريث أي أعضاء من فئة “الشخص”. دعنا نغير ذلك.

الآن قم بتحديد هذا التسلسل بتعريف فئتي teacher و student كفئات “أولاد” لفئة person باستخدام التوريث. يمكنك تحديد التوريث عن طريق إضافة علامة الاقتباس (:) بعد اسم الفئة تليها اسم الفئة الأصل كما هو موضح أدناه.

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

يجب أن يبدو نص الفئة الكامل الآن على النحو التالي:

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

في هذه النقطة ، عندما تنشئ كائنًا من فئة teacher أو student ، ستحتوي كلا الفئتين على نفس الأعضاء كفئة person.

Class Inheritance Demo

التوريث مع البنائيات

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

على سبيل المثال ، ربما قمت للتو بتعريف بنائي مكدس لفئة person ولم تحدد بنائيًا لفئة teacher ، كما هو موضح أدناه.

class person {
    [string]hidden $FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }

		person([string]$Name) {
			$this.SetName($Name)
		}
}

ثم قم بتعريف فئة فرعية ، على سبيل المثال ، teacher ، وحاول إنشاء كائن بدون معلمات منه ، كما هو موضح أدناه. لاحظ أن PowerShell يرجع خطأً لأنه لم يتم تحديد بناء للمعلم لا يحتوي على معلمات.

No class defined for child class

A constructor is not necessary in a child class if you’re only using it as a template. Alternatively, if you want to use the parent class as its own standalone class and as a parent class you can include constructors. But you have to make sure that the parent class has a constructor that matches the ones in the child classes.

سمات أعضاء الفئة

مثل معلمات أوامر PowerShell ، يمكن أن تحتوي الفئات على سمات الأعضاء. تعديل هذه السمات سلوك كل عضو.

أعضاء مخفية

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

لتعريف عضو مخفي، استخدم السمة hidden كما هو موضح أدناه.

class teacher {
    [int]hidden $EmployeeId
}

الآن عند استخدام Get-Member لفحص جميع أعضاء الكائن، لا يظهر تلك الخاصية.

Class Member Attributes

ضبط عضو صنف كمخفي لا يقيد الوصول إلى القيمة؛ بل يخفيها فقط عن العرض. يجب عدم إخفاء الخصائص لتخزين البيانات الحساسة.

الأعضاء الثابتة

تذكر في وقت سابق؛ استخدم هذا البرنامج التعليمي مصطلح “تثبيت” لوصف إنشاء كائن من صنف. عندما تقوم بتثبيت كائن، يتولى ذلك الكائن جميع الخصائص والطرق التي يعرفها الصنف. ولكن هذا ليس دائمًا الحال.

في بعض الأحيان، لا تحتاج إلى التكلفة الزائدة لتثبيت كائن بأكمله. بدلاً من ذلك، تحتاج إلى الإشارة إلى عضو واحد من الصنف بسرعة. في هذه الحالة، يمكنك ضبط عضو صنف كـثابت.

تمامًا كما هو الحال مع سمة hidden، قم بتعريف عضو صنف كثابت باستخدام كلمة الأساس static كما هو موضح أدناه.

class student {
	[int]static $MaxClassCount = 7
}

على عكس الأعضاء العادية للصنف، لا ينشئ PowerShell خصائص وطرق من الأعضاء الثابتة للصنف. عند تعريف عضو صنف كثابت، مثل الأعضاء المخفية، لا يظهر عند استخدام Get-Member.

Static Members

على سبيل المثال، ربما تود ربط أسماء فصول الجامعة بـ student وتحديد الحد الأقصى لعدد فصول الجامعة التي يمكن للطالب المشاركة فيها. للقيام بذلك، يتم إنشاء عنصر Classes كجزء من مصفوفة وعنصر MaxClassCount.

نظرًا لأن المستخدم نادراً ما يحتاج إلى تغيير عنصر MaxClassCount، فإنك تقرر تعريفه على أنه ثابت.

أخيرًا، يتم إنشاء طريقة AddClass() لإضافة فصل إلى جدول الطالب، ولكن فقط إذا كان أقل من MaxClassCount ذلك.

class student {
    [string[]]$Classes = @()
    [int]static $MaxClassCount = 7
    
    [void]AddClass ([string]$Name) {
        if ($this.Classes.Count -lt [student]::MaxClassCount) {
            $this.Classes += $Name
        }
    }
}

الآن عندما تحاول إنشاء كائن student جديد وتعيين عدد كبير جدًا من فصول الجامعة له، ستقوم PowerShell بتعيين الحد الأقصى الذي سيكون سبعة.

$student1 = [student]::new()
'PE','English','Math','History','Computer Science','French','Wood Working','Cooking' | ForEach-Object {
	$student1.AddClass($_)
}
$student1.Classes
Class Count

يمكنك تغيير قيم الأعضاء الثابتة في أي وقت. على سبيل المثال، إذا كنت ترغب في جعل عنصر MaxClassCount قيمته 5 بدلاً من 7، فيمكنك تغيير القيمة باستخدام [student]::MaxClassCount = 5. لن يؤدي تغيير القيمة إلى إزالة الفصول التي تتجاوز الحد الأقصى في هذا المثال.

الاستنتاج

تمتزج الفصول في PowerShell بين لغة البرمجة ولغة البرمجة النصية. الفصول هي وسيلة رائعة لتحديد علاقات الكائنات، وإضافة طرق للتفاعل وتنسيق الكائنات التي عادة ما يكون من الممكن فقط بكتابة وظائف متخصصة.

Source:
https://adamtheautomator.com/powershell-classes/