اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
هفت دقیقه
PowerShell برای نامگذاری Commandها، از ساختار verb-noun استفاده میکند. به عنوان مثال Get-Command, New-Service, Get-Help نمونههایی از این Commandها در PowerShell هستند. لازم به ذکر است که در PowerShell، منظور از cmdlet یا Command let، همان Commandهای native در PowerShell هستند؛ نه Commandهای عمومی مانند dir, cd, ipconfig و غیره. به عنوان مثال از Get-Help برای نمایش مستندات یک cmdlet میتوان استفاده کرد و دقیقاً مشابه man page در لینوکس است.
برای بیشتر cmdletها میتوانیم فیلتر نیز اعمال کنیم. به عنوان مثال با دستور زیر میتوان لیست تمام processهای سیستم را که به واژهی Process ختم میشوند، مشاهده کنیم:
خروجی دستور فوق، یک جدول به صورت زیر خواهد بود:
همچنین میتوانیم خروجی را با کمک Sort-Object مرتب کنیم:
یا اینکه خروجی را محدود به نمایش ۳ آیتم کنیم:
دستور فوق یک لیست از خواص Get-Process خواهد بود و خط اول این خروجی دقیقاً تایپی است که Get-Process برمیگرداند:
بنابراین این تایپی است که به عنوان ورودی، به Stop-Process درون pipeline ارسال میشود. در ادامه توسط دستور Get-Help Stop-Process -Full لیست پارامترهایی را که Stop-Process دریافت میکند، لیست خواهیم کرد:
Get-Help Get-Command
با فلگ Online میتوان مستندات cmdlet موردنظر را درون مرورگر مشاهده کرد:
Get-Help Get-Command -Online
Get-Command -Name '*Process'
CommandType Name Version Sour ce ----------- ---- ------- ---- Cmdlet Debug-Process 7.0.0.0 Mic… Cmdlet Enter-PSHostProcess 7.2.6.500 Mic… Cmdlet Exit-PSHostProcess 7.2.6.500 Mic… Cmdlet Get-Process 7.0.0.0 Mic… Cmdlet Start-Process 7.0.0.0 Mic… Cmdlet Stop-Process 7.0.0.0 Mic… Cmdlet Wait-Process 7.0.0.0 Mic… Application mysqltest_safe_process 0.0.0.0
Pipeline
توسط Pipeline میتوان خروجی یک command را به عنوان ورودی یک command دیگر ارسال کرد. در دیگر زبانهای اسکریپتی مانند bash یا batch (در ویندوز) چیزی که به command بعدی ارسال میشود، در واقع یک text است:
ls -l | grep "\.pdf$"
در مثال فوق، خروجی برنامه ls -1 را به ورودی برنامه grep ارسال کردهایم. در حالت عادی، خروجی دستورات به standard output یا به طور خلاصه stout ارسال میشوند. توسط pipe یا pipeline میتوانیم خروجی متنی را به اصطلاح redirect کنیم و به کامندهای بعدی به صورت یک زنجیره ارسال کنیم. اما در PowerShell این objectها هستند که ارسال (pipe) میشوند. به عنوان مثال میتوانیم با کمک Pipelineها، خروجی مثال قبل را محدود به نمایش ستونهای دلخواهی کنیم. به عبارتی تنها ستونهای Name و CommandType را در خروجی نمایش دهیم:
Get-Command -Name '*Process' | Select-Object Name,CommandType
Get-Command -Name '*Process' | Select-Object Name,CommandType | Sort-Object Name -Descending
PS /> Get-Command -Name '*Process' | Select-Object Name,CommandType -First 3 | Sort-Object Name -Descending Name CommandType ---- ----------- Exit-PSHostProcess Cmdlet Enter-PSHostProcess Cmdlet Debug-Process Cmdlet
همچنین میتوانیم از Where-Object برای اعمال شرط نیز استفاده کنیم. به عنوان مثال، در ادامه لیست ۵ پروسس سیستم را که مقدار CPU بیشتر از 1.24، در اختیار دارند نمایش دادهایم:
PS /> Get-Process | Where-Object CPU -gt 1.24 | Sort-Object WorkingSet -Descending | Select-Object -First 5
Pipelineها چطور کار میکنند؟
در PowerShell در واقع stdinی وجود ندارد که shell از آن استفاده کند؛ در نتیجه PowerShell باید بداند خروجی cmdlet قبلی را به کدام پراپرتی از cmdlet بعدی در pipeline ارسال کند:
PowerShell از مکانیزمی تحت عنوان pipeline binding برای انجام این نگاشت استفاده میکند. دو روش برای انجام این binding وجود دارد:
- ByValue
- ByPropertyName
در نظر داشته باشید که هر کدام از روشهای فوق توسط کسی که cmdlet موردنظر را پیادهسازی خواهد کرد میتواند پشتیبانی شود. برای درک بهتر این مکانیزم دستور زیر را در نظر بگیرید:
Get-Process Slack | Stop-Process
قبل از هر چیزی باید بدانیم خروجی cmdlet اول یعنی Get-Process چه چیزی است. اینکار را میتوانیم توسط دستور زیر انجام دهیم:
Get-Process | Get-Member
TypeName: System.Diagnostics.Process
PS /Users/sirwanafifi> Get-Help Stop-Process -Full NAME Stop-Process SYNTAX Stop-Process [-Id] <int[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>] Stop-Process -Name <string[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>] Stop-Process [-InputObject] <Process[]> [-PassThru] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>] PARAMETERS -Confirm Required? false Position? Named Accept pipeline input? false Parameter set name (All) Aliases cf Dynamic? false Accept wildcard characters? false -Force Required? false Position? Named Accept pipeline input? false Parameter set name (All) Aliases None Dynamic? false Accept wildcard characters? false -Id <int[]> Required? true Position? 0 Accept pipeline input? true (ByPropertyName) Parameter set name Id Aliases None Dynamic? false Accept wildcard characters? false -InputObject <Process[]> Required? true Position? 0 Accept pipeline input? true (ByValue) Parameter set name InputObject Aliases None Dynamic? false Accept wildcard characters? false -Name <string[]> Required? true Position? Named Accept pipeline input? true (ByPropertyName) Parameter set name Name Aliases ProcessName Dynamic? false Accept wildcard characters? false -PassThru Required? false Position? Named Accept pipeline input? false Parameter set name (All) Aliases None Dynamic? false Accept wildcard characters? false -WhatIf Required? false Position? Named Accept pipeline input? false Parameter set name (All) Aliases wi Dynamic? false Accept wildcard characters? false <CommonParameters> This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer, PipelineVariable, and OutVariable. For more information, see about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). INPUTS System.Int32[] System.String[] System.Diagnostics.Process[] OUTPUTS System.Diagnostics.Process ALIASES spps REMARKS Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only partial help. -- To download and install Help files for the module that includes this cmdlet, use Update-Help. -- To view the Help topic for this cmdlet online, type: "Get-Help Stop-Process -Online" or go to https://go.microsoft.com/fwlink/?LinkID=2097058.
از پارامترهای فوق تنها Id, Name و InputObject هستند که خاصیت Accept pipeline inputشان به true تنظیم شدهاست. همانطور که مشاهده میکنید InputObject از نوع ByValue است و Id و Name نیز از نوع ByPropertyName هستند:
-Id <int[]> Required? true Position? 0 Accept pipeline input? true (ByPropertyName) Parameter set name Id Aliases None Dynamic? false Accept wildcard characters? false -InputObject <Process[]> Required? true Position? 0 Accept pipeline input? true (ByValue) Parameter set name InputObject Aliases None Dynamic? false Accept wildcard characters? false -Name <string[]> Required? true Position? Named Accept pipeline input? true (ByPropertyName) Parameter set name Name Aliases ProcessName Dynamic? false Accept wildcard characters? false
نوع ورودی این پارامتر نیز یک آرایه از Processها میباشد. بنابراین در اینجا ByValue به این معنا است که اگر مقدار pipe شده از نوع Process بود، پراپرتی InputObject مقداردهی میشود. برای حالت ByPropertyName دستور زیر را در نظر بگیرید:
"Slack" | Stop-Process
با اجرای دستور فوق خطای زیر را دریافت خواهیم کرد:
Stop-Process: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
علت آن نیز مشخص است؛ چون هیچ پراپرتی از نوع ByValue که ورودی string یا آرایهایی از stringها را دریافت کند برای Stop-Process وجود ندارد، بنابراین pipeline binding اتفاق نخواهد افتاد. برای درک بهتر موضوع، یک شیء تستی ایجاد خواهیم کرد که شامل یک پراپرتی Name با مقدار Slack است؛ سپس شیء جدید را به Stop-Process ارسال میکنیم:
PS /Users/sirwanafifi> $newObject = [pscustomobject]@{ Name = "Slack" } PS /Users/sirwanafifi> $newObject | Stop-Process
با اجرای دستور فوق، پراسس موردنظر stop خواهد شد.
لازم به ذکر است که اگر یک پارامتر، هم ByValue و هم ByPropertyName باشد، PowerShell ابتدا سعی میکند ByValue را امتحان کند و اگر با شکست مواجه شد از ByPropertyName استفاده خواهد کرد.