‫PowerShell 7.x - قسمت چهارم - نوشتن اولین اسکریپت

ساخت وبلاگ
دستوراتی که درون کنسول مینویسیم، تک خطی یا one-linear هستند؛ هر چند میتوان با زدن کلیدهای Shift + Enter دستورات چندخطی هم نوشت یا حتی با گذاشتن semicolon بعد از هر دستور میتوانیم دریک خط چندین دستور را پشت‌سر هم بنویسیم. اما برای نوشتن دستورات طولانی‌تر بهتر است دستورات را درون فایل‌های جدایی قرار دهیم و از VSCode یا PowerShell ISE (فقط در ویندوز) نیز برای نوشتن اسکریپت‌ها استفاده کرد. اسکریپت‌های PowerShell با پسوند ps1 و psm1 (برای نوشتن ماژول) هستند؛ هر چند چندین پسوند دیگر نیز برای فایل‌های PowerShell وجود دارند که در اینجا میتوانید لیست آنها را مشاهده کنید. درون یک فایل ps1 امکان نوشتن و ترکیب دستورات مختلف را داریم. همچنین میتوانیم از امکانات زبان سی‌شارپ هم استفاده کنیم؛ زیرا PowerShell در واقع اپلیکیشنی است که توسط NET Core. و با زبان #C نوشته شده‌است. در نتیجه میتوانیم بگوئیم زبان اسکریپتی که در PowerShell استفاده میشود، یک DSL برای زبان #C است. در PowerShell همه چیز یک آبجکت محسوب میشود. برای تست این مورد میتوانید درون کنسول PowerShell دستور زیر را وارد کنید:
PS> "" | Get-Member
دستور فوق یک لیست از تمامی توابع و پراپرتی‌های نوع System.String را نمایش خواهد داد:
 TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
CompareTo Method int CompareTo(System.Object value), int CompareTo(strin…
Contains Method bool Contains(string value), bool Contains(string value…
CopyTo Method void CopyTo(int sourceIndex, char[] destination, int de…
EndsWith Method bool EndsWith(string value), bool EndsWith(string value…
EnumerateRunes Method System.Text.StringRuneEnumerator EnumerateRunes()
Equals Method bool Equals(System.Object obj), bool Equals(string valu…
GetEnumerator Method System.CharEnumerator GetEnumerator(), System.Collectio…
GetHashCode Method int GetHashCode(), int GetHashCode(System.StringCompari…
GetPinnableReference Method System.Char&, System.Private.CoreLib, Version=6.0.0.0, …
GetType Method type GetType()
GetTypeCode Method System.TypeCode GetTypeCode(), System.TypeCode IConvert…
IndexOf Method int IndexOf(char value), int IndexOf(char value, int st…
IndexOfAny Method int IndexOfAny(char[] anyOf), int IndexOfAny(char[] any…
Insert Method string Insert(int startIndex, string value)
IsNormalized Method bool IsNormalized(), bool IsNormalized(System.Text.Norm…
LastIndexOf Method int LastIndexOf(string value, int startIndex), int Last…
LastIndexOfAny Method int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(ch…
Normalize Method string Normalize(), string Normalize(System.Text.Normal…
PadLeft Method string PadLeft(int totalWidth), string PadLeft(int tota…
PadRight Method string PadRight(int totalWidth), string PadRight(int to…
Remove Method string Remove(int startIndex, int count), string Remove…
Replace Method string Replace(string oldValue, string newValue, bool i…
ReplaceLineEndings Method string ReplaceLineEndings(), string ReplaceLineEndings(…
Split Method string[] Split(char separator, System.StringSplitOption…
StartsWith Method bool StartsWith(string value), bool StartsWith(string v…
Substring Method string Substring(int startIndex), string Substring(int …
ToBoolean Method bool IConvertible.ToBoolean(System.IFormatProvider prov…
ToByte Method byte IConvertible.ToByte(System.IFormatProvider provide…
ToChar Method char IConvertible.ToChar(System.IFormatProvider provide…
ToCharArray Method char[] ToCharArray(), char[] ToCharArray(int startIndex…
ToDateTime Method datetime IConvertible.ToDateTime(System.IFormatProvider…
ToDecimal Method decimal IConvertible.ToDecimal(System.IFormatProvider p…
ToDouble Method double IConvertible.ToDouble(System.IFormatProvider pro…
ToInt16 Method short IConvertible.ToInt16(System.IFormatProvider provi…
ToInt32 Method int IConvertible.ToInt32(System.IFormatProvider provide…
ToInt64 Method long IConvertible.ToInt64(System.IFormatProvider provid…
ToLower Method string ToLower(), string ToLower(cultureinfo culture)
ToLowerInvariant Method string ToLowerInvariant()
ToSByte Method sbyte IConvertible.ToSByte(System.IFormatProvider provi…
ToSingle Method float IConvertible.ToSingle(System.IFormatProvider prov…
ToString Method string ToString(), string ToString(System.IFormatProvid…
ToType Method System.Object IConvertible.ToType(type conversionType, …
ToUInt16 Method ushort IConvertible.ToUInt16(System.IFormatProvider pro…
ToUInt32 Method uint IConvertible.ToUInt32(System.IFormatProvider provi…
ToUInt64 Method ulong IConvertible.ToUInt64(System.IFormatProvider prov…
ToUpper Method string ToUpper(), string ToUpper(cultureinfo culture)
ToUpperInvariant Method string ToUpperInvariant()
Trim Method string Trim(), string Trim(char trimChar), string Trim(…
TrimEnd Method string TrimEnd(), string TrimEnd(char trimChar), string…
TrimStart Method string TrimStart(), string TrimStart(char trimChar), st…
TryCopyTo Method bool TryCopyTo(System.Span[char] destination)
Chars ParameterizedProperty char Chars(int index) {get;}
Length Property int Length {get;}
در واقع میتوانیم بگوئیم هرچیزی در PowerShell یک آبجکت NET. است. در ادامه لیستی را از قابلیت‌های PowerShell به عنوان یک زبان اسکریپتی، بررسی خواهیم کرد.

تعریف متغیر
برای تعریف یک متغیر از علامت $ قبل از نام متغیر استفاده میکنیم. نوع متغیر نیز براساس مقداری که به آن انتساب داده میشود، تعیین خواهد شد: 
$stringVariable = "Hello World"
$letter = 'A'
$isEnabled = $false
$age = 33
$height = 76
$doubleVar = 54321.21
$singleVar = 76549.11
$longVar = 2382.22
$dateVar = "July 24, 1986"
$arrayVar = "A", "B", "C"
$hashtableVar = @{ Name = "Sirwan"; Age = 33; }
همچنین میتوانیم نوع متغیر را نیز به صورت صریح تعیین کنیم: 
[string]$stringVariable = "Hello World"
[char]$letter = 'A'
[bool]$isEnabled = $false
[int]$age = 33
[decimal]$height = 76
[double]$doubleVar = 54321.21
[single]$singleVar = 76549.11
[long]$longVar = 2382.22
[DateTime]$dateVar = "July 24, 1986"
[array]$arrayVar = "A", "B", "C"
[hashtable]$hashtableVar = @{ Name = "Sirwan"; Age = 33; }
لازم به ذکر است scope متغیرها در حالت پیش‌فرض به local تنظیم میشود. به این معنا که در جایی که تعریف میشوند، قابل دسترسی خواهند بود. قاعدتاً اگر متغیرها را در ابتدای اسکریپت تعریف کنید، میدان دید آن به صورت سراسری خواهد بود و در هرجایی از کد در دسترس خواهند بود. اما برای اینکه به صورت صریح یک متغیر را به صورت سراسری تعریف کنیم میتوانیم از کلمه‌کلیدی global بعد از تعیین نوع متغیر و قبل از علامت $ استفاده کنیم: 
$global:stringVariable = "Hello World"
// Or
[string]$global:stringVariable = "Hello World"

عبارات شرطی
همانند دیگر زبان‌های اسکریپتی، در PowerShell نیز قابلیت تعریف ساختارهای شرطی وجود دارد: 
$guess = 20
switch ($guess) { {$_ -eq 20} { Write-Host "You guessed right!" } {$_ -gt 20} { Write-Host "You guessed too high!" } {$_ -lt 20} { Write-Host "You guessed too low!" } default { Write-Host "You didn't guess a number!" }
}
$guess = 20
if ($guess -eq 20) { Write-Host "You guessed right!"
}
elseif ($guess -gt 20) { Write-Host "You guessed too high!"
}
elseif ($guess -lt 20) { Write-Host "You guessed too low!"
}
else { Write-Host "You didn't guess a number!"
}
همانطور که مشاهده میکنید از یکسری اپراتور برای بررسی شرط‌ها استفاده شده است. در اینجا میتوانید لیست کامل آنها را مشاهده کنید. لازم به ذکر است که از PowerShell 7.0 به بعد نیز Ternary Operator اضافه شده است: 
$message = (Test-Path $path) ? "Path exists" : "Path not found"

حلقه‌ها
همچنین از حالت‌های مختلف loop نیز پشتیبانی میشود: 
[int]$num = 10
for ($i = 1; $i -le $num; $i++) { Write-Host "`n" for ($j = 1; $j -le $num; $j++) { Write-Host -NoNewline -ForegroundColor Green ($i * $j).ToString().PadLeft(6) }
}
Write-Host "`n`n"
[int]$counter = 1
while ($counter -le 10) { Write-Host "Hello World" $counter++
}
do { Write-Host "Hello World" $counter++
} while ($counter -le 10)
foreach ($i in 1..10) { Write-Host "Hello World"
}
$items = "Hello", "World"
$items | ForEach-Object { Write-Host $_
}

لازم به ذکر است برای ForEach-Object از % نیز میتوانید استفاده کنید. اما بطور کلی بهتر است تا حد امکان از aliaseها استفاده نکنید؛ زیرا خوانایی کد را مقداری سخت میکند. این مورد توسط خود VSCode هم هشدار داده میشود: 


آرایه‌ها
در PowerShell به صورت پیش‌فرض آرایه‌ها از نوع []System.Object در نظر گرفته میشوند. در اینجا نیز آرایه‌ها immutable هستند. چندین روش برای ایجاد آرایه وجود دارد. در ادامه یک آرایه خالی را تعریف کرده‌ایم: 
$array = @()
یک روش دیگر تعریف آرایه اینگونه است: 
$myArray = [Object[]]::new(10)
$byteArray = [Byte[]]::new(100)
$ipAddresses = [IPAddress[]]::new(5)
$mylist = [System.Collections.Generic.List[int]]::new()
از PowerShell 5.0 به بعد میتوانیم سینتکس namespaceها را با کمک using خلاصه‌تر بنویسیم:
using namespace System.Collections.Generic
$mylist = [List[int]]::new()
از range operator هم میتوانیم برای مقداردهی یک آرایه استفاده کرد: 
$numbers = 1..10
$alphabet = "a".."z"
foreach ($item in 1..10) { Write-Host "Hello World"
}
برای دسترسی به عناصر یک آرایه نیز میتوانیم از range operator استفاده کنیم: 
$numbers = 1..10
$numbers
Write-Output "".PadRight(10, "-")
$numbers[1..2 + 2..4]
همانطور که مشاهده میکنید از اپراتور + برای append کردن یک بازه از اعداد، به آرایه استفاده کرده‌ایم. دقت داشته باشید که با هر بار اضافه/حذف آیتم‌ها، یک آرایه جدید ساخته میشود. این مورد در آرایه‌هایی با سایز بزرگ میتواند مشکل کارآیی ایجاد کند. بنابراین اگر عملیات اضافه کردن و حذف کردن از یک آرایه را زیاد انجام میدهید، بهتر است از ArrayList استفاده کنید. تفاوت آن نیز این است که برخلاف آرایه‌های عادی، سایز ArrayList ثابت نیست. تعریف ArrayList نیز اینگونه است: 
$colours = [System.Collections.ArrayList]@("Red", "Green", "Blue")
$colours.Add("Yellow")
$colours.Remove("Red")
از دیگر کالکشن‌های NET. نیز میتوانید استفاده کنید؛ به عنوان مثال در مثال زیر از List برای اضافه کردن ده هزار آیتم استفاده کرده‌ایم:
using namespace System.Collections.Generic
$mylist = [List[int]]::new()
Measure-Command { 1..100000 | ForEach-Object { $mylist.Add($_) } }
Measure-Command { $mylist.Where({ $_ -gt 10000 }) }
Measure-Command { $mylist.Contains(10000) }
نکته: کد فوق در حالت استفاده از ArrayList مقداری کندتر است. دلیل آن نیز این است که ArrayList امکان اضافه کردن هر آبجکتی را به ما میدهد. در نتیجه موقع جستجو باید یکبار عملیات unboxing را برای تشخیص نوع درخواست شده انجام دهد.

Hashtable
ساختار دیگری که میتوانید استفاده کنید Hash Tableها هستند؛ از این ساختار برای ایجاد custom objects و همچنین پاس دادن پارامترها به یک command استفاده میشود:
$sensors = @{ tempreture = "Temperature" humidity = "Humidity" pressure = "Pressure" light = "Light" noise = "Noise" co2 = "CO2" battery = "Battery" min_temp = "Min Temp" max_temp = "Max Temp"
}
با دستور زیر میتوانید لیستی از Commandهایی که ورودی‌شان از نوع Hash table است را مشاهده کنید:
PS> Get-Command -ParameterType Hashtable
CommandType Name Version Source
----------- ---- ------- ------
Function TabExpansion2
Cmdlet Add-Member 7.0.0.0 Microsoft.Powe…
Cmdlet ConvertTo-Html 7.0.0.0 Microsoft.Powe…
Cmdlet Get-Job 7.2.7.500 Microsoft.Powe…
Cmdlet Invoke-Command 7.2.7.500 Microsoft.Powe…
Cmdlet Invoke-RestMethod 7.0.0.0 Microsoft.Powe…
Cmdlet Invoke-WebRequest 7.0.0.0 Microsoft.Powe…
Cmdlet New-Object 7.0.0.0 Microsoft.Powe…
Cmdlet New-PSRoleCapabilityFile 7.2.7.500 Microsoft.Powe…
Cmdlet New-PSSession 7.2.7.500 Microsoft.Powe…
Cmdlet Remove-Job 7.2.7.500 Microsoft.Powe…
Cmdlet Select-Xml 7.0.0.0 Microsoft.Powe…
Cmdlet Set-PSReadLineOption 2.1.0 PSReadLine
Cmdlet Stop-Job 7.2.7.500 Microsoft.Powe…
Cmdlet Wait-Job 7.2.7.500 Microsoft.Powe…

توابع
برای ایجاد توابع در PowerShell میتوانید از سینتکس زیر استفاده کنید:
function Write-HelloWorld { Write-Host "Hello World"
}
برای نامگذاری توابع بهتر است از قالب verb-noun استفاده کنید. برای قسمت verb نیز بهتر است از یکسری افعال تائیدشده (approved verbs) که مستندات مایکروسافت پیشنهاد میدهد استفاده کنید (+) در این زمینه VSCode در صورت انتخاب یک نام نامناسب به شما هشدار خواهد:

تفاوت بین Function و Cmdlet چیست؟
توابع و cmdletها عملاً از لحاظ کاربرد باهم تفاوتی ندارند. تنها تفاوت آنها در نحوه ساخت‌شان است. cmdletها با #C ساخته میشوند. به این معنا که یکسری DLL کامپایل شده هستند که در نهایت از آنها استفاده خواهیم کرد. اما توابع در PowerShell با کمک سینتکسی که اشاره شد ایجاد میشوند. توسط دستور زیر میتوانیم لیستی از توابعی را که درون سشن PowerShellمان بارگذاری شده‌اند، ببینیم: 
PS> Get-Command -CommandType Function

در PowerShell نیز توابع قابلیت دریافت ورودی را نیز دارند. در ساده‌ترین حالت میتوانیم از آرایه args$ استفاده کنیم؛ دقیقاً چیزی مشابه arguments در JavaScript است:
function Write-HelloWorld { Write-Host "First Argument: $($args[0])" Write-Host "Second Argument: $($args[1])" Write-Host "Third Argument: $($args[2])" Write-Host "Fourth Argument: $($args[3])"
}
به این حالت Positional Parameters گفته میشود. یک روش دیگر تعریف پارامتر استفاده از Named Parameters است:
function Write-HelloWorld( [string]$first, [string]$second, [string]$third, [string]$fourth
) { Write-Host "First Argument: $($first)" Write-Host "Second Argument: $($second)" Write-Host "Third Argument: $($third)" Write-Host "Fourth Argument: $($fourth)"
}

در قسمت بعد در مورد Advanced Functionها صحبت خواهیم کرد و اجزای دیگر توابع را بیشتر توضیح خواهیم داد.

یک نکته در مورد خروجی دستورات درون کنسول
در ویندوز میتوانیم خروجی کنسول را به Out-GridView پایپ کنیم که در واقع یک GUI برای نمایش دادن خروجی کنسول است. این کامند فقط در ویندوز قابل استفاده است:

یک نسخه cross-platform آن نیز که مناسب کنسول است تهیه شده که میتوانید از آن استفاده کنید: 
Get-Command -ParameterType Hashtable | Out-ConsoleGridview
با این خروجی:

البته به صورت پیش‌فرض نصب نیست و باید از طریق PowerShell Gallery آن را نصب کنید:

Install-Module -Name Microsoft.PowerShell.ConsoleGuiTools


دانلود نرم افزار و برنامه...
ما را در سایت دانلود نرم افزار و برنامه دنبال می کنید

برچسب : نویسنده : دانلودی dld بازدید : 144 تاريخ : چهارشنبه 25 آبان 1401 ساعت: 14:10

خبرنامه