Objektumok átalakítása (Select-Object)

A Select-Object  a PowerShell svájci bicskája! Alapvetően három különböző funkciója van:

objektumokat csonkít meg és/vagy tesz hozzájuk újabb tulajdonságokat,

objektumokat nyel el vagy enged át magán,

tulajdonságként tárolt objektumokat emel fel és készít belőlük legmagasabb szinten levő objektumokat.

Nézzük ezeket a funkciókat egyesével!

Objektumok csonkolása és kiegészítése

A Select-Object a bemenetén kapott objektumokból képes levágni tulajdonságokat és csak azokat meghagyni, amire kifejezetten kérjük. Ezzel még azt is megtehetjük, hogy olyan tulajdonságot kérünk, amivel az objektum eredetileg nem is rendelkezik, de így ezeket ő fogja nekünk létrehozni.

Példaként alakítsuk át a Get-Process-től érkező objektumokat úgy, hogy csak a folyamat nevét, gyártóját és leírását tartalmazzák! A Select-Object cmdletnek egyszerűen azt kell megadnunk, hogy melyik tulajdonságokat szeretnénk megtartani:

PS C:\> Get-Process | Select-Object -Property name, company, description

 

Name                     Company                  Description

----                     -------                  -----------

ctfmon                   Microsoft Corporation    CTF Loader

CTHELPER                 Creative Technology Ltd  CtHelper MFC Application

CTSVCCDA                 Creative Technology Ltd  Creative Service for ...

csrss

explorer                 Microsoft Corporation    Windows Intéző

...

Mi is történik ebben az esetben? A Get-Process processz objektumokat dobál a csőbe, ezeket kapja meg a Select-Object, amely a paraméterlista által meghatározott tulajdonságokat egy újonnan létrehozott egyedi objektum azonos nevű tulajdonságaiba másolja. Ezek az objektumok fognak aztán tovább vándorolni a csövön.

Természetesen nemcsak azt mondhatjuk meg, hogy mely tulajdonságokra van szükségünk, hanem azt is, hogy melyekre nincs: az -excludeproperty paraméter után felsorolt tulajdonságok nem fognak szerepelni a kimenő objektumokban, ehhez viszont azt kell kérni a -property * paraméterrel, hogy a többi viszont jelenjen meg:

 PS C:\> Get-Variable | Select-Object -Property * -ExcludeProperty attributes, d

escription, value, module

 

Name                       Visibility ModuleName            Options

----                       ---------- ----------            -------

$                              Public                          None

?                              Public            ReadOnly, AllScope

^                              Public                          None

args                           Public                          None

ConfirmPreference              Public                          None

ConsoleFileName                Public            ReadOnly, AllScope

DebugPreference                Public                          None

Error                          Public                      Constant

A kimenő objektumok szerkezetét egy Get-Member hívás mutatja meg:

PS C:\> get-process | select-object -property name, description, company | get-

member

 

 

   TypeName: Selected.System.Diagnostics.Process

 

Name        MemberType   Definition

----        ----------   ----------

Equals      Method       bool Equals(System.Object obj)

GetHashCode Method       int GetHashCode()

GetType     Method       type GetType()

ToString    Method       string ToString()

Company     NoteProperty System.String Company=Microsoft Corporation

Description NoteProperty System.String Description=Application Frame Host

Name        NoteProperty string Name=ApplicationFrameHost

Látszik, hogy ez már nem az eredeti System.Diagnostics.Process objektum, hanem annak egy Selected változata. Ez azt jelenti, hogy a típusa már csak nyomokban emlékeztet az eredeti objektumra, valójában ez egy teljesen új objektum, csak a legalapvetőbb metódusokkal és a kiválasztott tulajdonságokkal, amelyek ráadásul mindenképpen NoteProperty-k lettek, függetlenül attól, hogy például eredetileg esetleg ScriptProperty-k voltak.

De nem csak csonkolhatjuk az objektumokat, hanem új tulajdonságokkal is kiegészíthetjük azokat:

PS C:\> Get-ChildItem C:\PowerShell | Select-Object Name, Length, @{n="NévHossz

"; e={$_.Name.Length}}

 

Name                 length NévHossz

----                 ------ --------

20150923                           8

Carbon                             6

Ascii.txt            11            9

BigEndianUnicode.txt 24           20

BigEndianUTF32.txt   48           18

BreakAll.ps1         67           12

A fenti példában a Name és Length „gyári” tulajdonságok mellett egy újabb, NévHossz névre hallgató tulajdonságot hoztam létre, ami az eredeti Name tulajdonság hosszát adja meg. Ezt egy hashtáblával definiáltam, ahol az „n” kulcs értéke adja meg a tulajdonság nevét (a kulcs neve lehet „Name” is), az „e” kulcsban (lehet „Expression” is) pedig azt a szabályt adjuk meg szkriptblokk formájában, ami ennek az új tulajdonságnak megadja az értékét. Itt is a futószalagon érkező aktuális objektumot szimbolizálja a $_ változó.

Nézzünk egy összetettebb számolt tulajdonságot is. Itt most a jobb értelmezhetőség kedvéért áttördeltem a kódot:

dir c:\old | Select-Object name,

@{   n = "Méret";

     e =   {switch ($m = $_.Length)

                {     {$m -lt 1kb} {"Pici"; break}

                      {$m -lt 3kb} {"Közepes"; break}

                      {$m -lt 100kb} {"Nagy"; break}

                      default {"Óriási"}

                }

           }

 }

A fenti példában a dir, azaz a get-childitem által a fájloknál megmutatott tulajdonságok helyett nekem kellene egy pici/közepes/nagy/óriási besorolása a fájloknak. Ehhez a Select-Object-nek a fájlok „igazi” name tulajdonsága mellett egy „képzett” tulajdonságot, a „Méret”-et is megadom.

És nézzük a kimenetet:

Name                                  Méret

----                                  -----

alice.txt                             Pici

coffee.txt                            Pici

lettercase.txt                        Pici

numbers.txt                           Pici

presidents.txt                        Pici

readme.txt                            Közepes

skaters.txt                           Nagy

symbols.txt                           Pici

vertical.txt                          Pici

votes.txt                             Nagy

wordlist.txt                          Óriási

Objektumok szűrése Select-Object-el

A fentieken kívül a Select-Object néhány más funkcióval is rendelkezik: nemcsak objektumokat képes átalakítani („vertikális” változtatás), hanem gyűjteményeket is átalakít („horizontális” változtatás). Például képes a bemenetként kapott tömb elejéről vagy végéről meghatározott számú elemet leválasztani (-first és ‑last paraméter):

PS C:\> "egy", "kettő", "három", "négy", "öt" | Select-Object -First 2 -Last 1

egy

kettő

öt

Vagy azt is megadhatjuk a -skip-pel, hogy mennyit hagyjon ki:

PS C:\> "egy", "kettő", "három", "négy", "öt" | Select-Object -Skip 3

négy

öt

Vagy akár a végéről is elhagyhatunk elemeket:

PS C:\> "egy", "kettő", "három", "négy", "öt" | Select-Object -SkipLast 4

egy

Illetve képes egy gyűjtemény elemei közül csak a különbözőket (vagyis az egyforma elemek közül csak egyet) továbbadni a –unique kapcsoló segítségével:

PS C:\> PS C:\> 1,1,3,56,3,1,1,1,3 | Select-Object -unique

1

3

56

Mindezen változatoknál a gyűjtemény, tömb egyes elemei természetesen megőrzik az eredeti típusukat.

De vajon mi számít a –unique kapcsoló használata mellett egyformának és mi különbözőnek? Nézzünk erre egy példát:

PS C:\> Get-Process s*

 

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

-------  ------    -----      ----- -----   ------     -- -----------

    681      91   107680     134448   735    14,52   3640 ScriptEditor

    145      14     4708       9080    67            1240 SDWinSec

   1094      70    45188      33320   162            3008 SearchIndexer

    225      13     5888       9120    42             524 services

    348      26    40220      36316   191    18,19   2776 sidebar

     87      10     3168       6484    72     0,14   2416 SJelite3Launch

     30       2      456       1052     5             276 smss

    322      20     7120      12052    94            1360 spoolsv

    371      14     4440       9400    54             660 svchost

    369      16     4744       8736    42             756 svchost

    513      25    17420      19168    90             900 svchost

    671      33   108432     115488   240             932 svchost

   1564      80    32140      48064   481             960 svchost

    286      20     6136      10852    49            1108 svchost

    761      51    32136      38768   174            1220 svchost

    306      33    12540      14112    69            1556 svchost

    319      26     6580      13072    90            1704 svchost

     95       8     1864       5164    33            1996 svchost

     91       8     1640       4408    47            2496 svchost

    769       0      124       6300    11               4 System

Nézzük ezeket „megegyelve”:

PS C:\> Get-Process s* | Select-Object -Unique

 

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

-------  ------    -----      ----- -----   ------     -- -----------

    681      91   107680     134448   735    14,52   3640 ScriptEditor

    145      14     4708       9080    67            1240 SDWinSec

   1094      70    45188      33320   162            3008 SearchIndexer

    225      13     5888       9120    42             524 services

    348      26    40220      36316   191    18,16   2776 sidebar

     87      10     3168       6484    72     0,14   2416 SJelite3Launch

     30       2      456       1052     5             276 smss

    322      20     7120      12052    94            1360 spoolsv

    369      14     4388       9380    53             660 svchost

    769       0      124       6300    11               4 System

Láthatólag a sok svchost lett összevonva, de vajon milyen alapon? Pusztán a nevük alapján? És az olyan objektumok esetében, amelyeknek nincs nevük, ott mi lesz? Az algoritmus nagyon egyszerű: az a két objektum egyforma, amelyeknek meghívva a ToString metódusát egyforma lesz a kimenet. Ez két különböző svchost-példány esetében is ugyanaz, ezért lettek összevonva:

PS C:\> Get-Process svchost | ForEach-Object {$_.tostring()}

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

System.Diagnostics.Process (svchost)

Sajnos itt csak azon az áron tudjuk testre szabni a „megegyelést”, hogy közben lemetsszük az egyformaságot meghatározó tulajdonságokat:

[4] PS C:\> Get-process | Select-Object -Unique -Property name, id | Format-Tab

le -AutoSize

 

Name            Id

----            --

audiodg        596

conhost       2136

csrss          416

csrss          496

daemon        2744

dwm           2932

explorer      2992

FcsSas        1592

FlashUtil10e  1892

Idle             0

ielowutil     1484

iexplore      1444

iexplore      2104

IoctlSvc      1796

Ha a teljes eredeti objektumokat meg akarjuk őrizni, akkor erre a Sort-Object cmdlet fog majd megoldást nyújtani.

PowerShell 3.0-vel jelentős optimalizálás történt a „horizontális” szelektálás üzemmódban. Korábban, ha a következő kifejezést futtattam:

PS C:\> 1..1000000 | Select-Object -First 2

1

2

Jónéhány másodpercet kellett várni, míg az eredmény megjelent, mivel hiába kértem csak az 1.000.000 szám első két elemét, a háttérben az összes elem rákerült a futószalagra, csak a Select-Object elnyelte a második elem utáni összeset.

Az új üzemmódban viszont a harmadik és a későbbi elemek el sem indulnak, így sokkal gyorsabban megkapom az eredményt. Ha mégis az eredeti működés kell nekem, mert például van még egy korábbi futószalag-szakasz, ahol fontos, hogy az összes elem feldolgozásra kerüljön, akkor a -Wait kapcsoló használatával a korábbi működést is kérhetjük:

PS C:\> $összeg = 0

PS C:\> 1..400000 | %{$összeg += $_; $_} | Select-Object -First 2 -Wait

1

2

PS C:\> $összeg

80000200000

Látható a nagy $összeg-ből, hogy tényleg minden elem elindult és a Select-Object nyelte csak el őket. Összehasonlításuk, ugyanez a -Wait nélkül:

PS C:\> $összeg = 0

PS C:\> 1..400000 | %{$összeg += $_; $_} | Select-Object -First 2

1

2

PS C:\> $összeg

3

Itt csak tényleg az első két elem indult útnak.

Még tud a Select-Object az –Index paraméterrel valahányadik elemet kiválasztani a gyűjteményből:

PS C:\> 1..10 | Select-Object -Index 5,8

6

9

PS C:\> 1..10 | Select-Object -Index 8

9

Tulajdonságok kiemelése

Még egy gyakori felhasználási területe van a select-object-nek. Ennek felvezetésére nézzünk egy egyszerű példát:

PS C:\> get-service a* | Group-Object -Property status

 

Count Name                      Group

----- ----                      -----

    5 Running                   {AdobeARMservice, AppHostSvc, Appinfo, Audi...

    8 Stopped                   {AJRouter, ALG, AppIDSvc, AppMgmt...}

Az első sorban lekérdezem az „a” betűvel kezdődő szolgáltatásokat, majd csoportosítottam őket a status paraméterük alapján. A kimeneten az egyes csoportokat alkotó szolgáltatások tömbbe rendezve (kapcsos zárójelek között) láthatók.

Ez kevés szolgáltatásnál akár jó is lehet, de már a fenti példában is a nem nagyon fért ki az egyes csoportok listája. A kibontásban segíthet a select‑object az ‑expandproperty paraméterrel:

PS C:\> get-service a* | Group-Object -Property status | Select-Object -ExpandP

roperty group

 

Status   Name               DisplayName

------   ----               -----------

Running  AdobeARMservice    Adobe Acrobat Update Service

Running  AppHostSvc         Application Host Helper Service

Running  Appinfo            Application Information

Running  AudioEndpointBu... Windows Audio Endpoint Builder

Running  Audiosrv           Windows Audio

Stopped  AJRouter           AllJoyn Router Service

Stopped  ALG                Application Layer Gateway Service

Stopped  AppIDSvc           Application Identity

Stopped  AppMgmt            Application Management

Stopped  AppReadiness       App Readiness

Stopped  AppXSvc            AppX Deployment Service (AppXSVC)

Stopped  aspnet_state       ASP.NET State Service

Stopped  AxInstSV           ActiveX Installer (AxInstSV)

Itt a sor utolsó tagjában a select-object kifejti a group tulajdonságot, eredményeképpen visszakapjuk a szolgáltatások listáját, immár csoportosítás utáni sorrendben. Gyakorlatilag ugyanahhoz az eredményhez jutottunk, mint Get-Service | Sort-Object –property Status kifejezéssorral (lásd következő fejezet).

Másik gyakori példa az -ExpandProperty használatára, ha egy tulajdonság maga is egy összetettebb objektum, aminek több tulajdonsága van, mint például a fájlok verzióinformációi:

PS C:\> dir C:\Windows -Filter w*.exe | Select-Object -Property versioninfo

 

VersionInfo

-----------

File:             C:\Windows\winhlp32.exe...

File:             C:\Windows\Word to HTML Converter Uninstaller.exe...

File:             C:\Windows\write.exe...

Ha a -Property üzemmóddal nézzük, akkor nem igazán látjuk a verziókat. Ezzel szemben, ha ‑ExpandProperty-vel futtatjuk, akkor mindjárt láthatóvá válnak a részletek:

PS C:\> dir C:\Windows -Filter w*.exe | Select-Object -ExpandProperty versionin

fo

 

ProductVersion   FileVersion      FileName

--------------   -----------      --------

10.0.10240.16384 10.0.10240.16... C:\Windows\winhlp32.exe

                                  C:\Windows\Word to HTML Converter Uninsta...

10.0.10240.16384 10.0.10240.16... C:\Windows\write.exe

Csőelemek tulajdonságainak összefűzése a PipelineVariable paraméter segítségével

A cmdletek egyik u.n. common parameter-e a -PipelineVariable . Ez azt a célt szolgálja, hogy a $_ változó mellett milyen egyéb változóban is tegye elérhetővé a csőbe tett elemet. Miért jó ez? Nézzük a következő „kígyót”:

PS C:\> Get-Process p* | Where-Object {$_.path} | Get-Item | Select-Object -Exp

andProperty versioninfo | Select-Object -Property Language

Kiindulunk a P betűvel kezdődő processz objektumokból, majd azokból, amelyeknek van Path tulajdonsága, megragadjuk a fájl objektumát, majd kiemeljük a fájlokból azok VersionInfo tulajdonságát, majd ezeknek vesszük a Language tulajdonságát. De hogyan tudnánk a végeredményben a Language tulajdonság mellé berakni a processz ID tulajdonságát és a fájl méretét? Azaz ezek az adatok a csővezeték különböző szakaszain keresztülhaladó objektumokon állnak rendelkezésre. A legvégén elkapható $_ változóban a VersionInfo objektum áll csak rendelkezésre. Itt jön be minden szakasz cmdletjének a -PipelineVariable paramétere, amelyekkel a Get-Process eredményét a $Processz változóba, a Get-Item eredményét a $Fájl változóba tesszük és a végén ezekből szedegetjük össze a megfelelő tulajdonságokat:

PS C:\> Get-Process p* -PipelineVariable Processz | Where-Object {$_.path} | Ge

t-Item -PipelineVariable Fájl | Select-Object -ExpandProperty versioninfo | Sel

ect-Object -Property @{n= "Id"; e={$Processz.Id}}, Language, @{n="Mode"; e={$Fá

jl.Length}}

 

   Id Language                  Mode

   -- --------                  ----

14592 Language Neutral        358128

 5240 Language Neutral        346040

18468 English (United States) 492032



Word To HTML Converter