potęgą PowerShell jest jego obiektowość, dzięki czemu cały język jest bardzo elastyczny. np filtrowanie wyjścia staje się bardzo proste:

ps|? name -match 'svc'

proste, jasne i przyjemne… i łatwo znaleźć na setkach tysiącach stron…

dla tego inne pytanie – a jak przefiltrować po wartościach wszystkich parametrów? np. „pokaż wszystkie parametry obiektu, które mają 'name’ w nazwie”, albo „pokaż wszystkie wartości parametrów, które zawierają 'abc'”. tego już tak łatwo zrobić się nie da. to będzie nieco nieprzyjemna przejażdżka, bo wymaga rozebrania obiektu na kawałki – czyli tracimy automatykę PS, która tak ślicznie pomaga w 'normalnych’ zapytaniach, i grzebiemy we flakach.

aby osiągnąć cel trzeba skorzystać z ukrytego parametru 'psobject’, który pokazuje wnętrzności obiektu. dodatkowo sprawę kompliqje fakt, że wyjście jest często tablicą obiektów a nie pojedynczym obiektem. pobawmy się 'get-service’ i zrealizujmy takie zadania:

  • wyświetlmy wszystkie nazwy i wartości parametrów, które mają w nazwie 'name’
  • wyświetlmy wszystkie nazwy i wartości parametrów, dla których wartość jest równa 'true’

w pierwszej kolejności zobaczmy jak taki obiekt wygląda wewnątrz. najpierw klasycznie…:

PS C:\_scriptZ> Get-Service|gm


   TypeName: System.ServiceProcess.ServiceController

Name                      MemberType    Definition
----                      ----------    ----------
Name                      AliasProperty Name = ServiceName
RequiredServices          AliasProperty RequiredServices = ServicesDependedOn
Disposed                  Event         System.EventHandler Disposed(System.Object, System.EventArgs)
Close                     Method        void Close()
Continue                  Method        void Continue()
CreateObjRef              Method        System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Dispose                   Method        void Dispose(), void IDisposable.Dispose()
Equals                    Method        bool Equals(System.Object obj)
ExecuteCommand            Method        void ExecuteCommand(int command)
GetHashCode               Method        int GetHashCode()
GetLifetimeService        Method        System.Object GetLifetimeService()
GetType                   Method        type GetType()
InitializeLifetimeService Method        System.Object InitializeLifetimeService()
Pause                     Method        void Pause()
Refresh                   Method        void Refresh()
Start                     Method        void Start(), void Start(string[] args)
Stop                      Method        void Stop()
WaitForStatus             Method        void WaitForStatus(System.ServiceProcess.ServiceControllerStatus desiredStat...
CanPauseAndContinue       Property      bool CanPauseAndContinue {get;}
CanShutdown               Property      bool CanShutdown {get;}
CanStop                   Property      bool CanStop {get;}
Container                 Property      System.ComponentModel.IContainer Container {get;}
DependentServices         Property      System.ServiceProcess.ServiceController[] DependentServices {get;}
DisplayName               Property      string DisplayName {get;set;}
MachineName               Property      string MachineName {get;set;}
ServiceHandle             Property      System.Runtime.InteropServices.SafeHandle ServiceHandle {get;}
ServiceName               Property      string ServiceName {get;set;}
ServicesDependedOn        Property      System.ServiceProcess.ServiceController[] ServicesDependedOn {get;}
ServiceType               Property      System.ServiceProcess.ServiceType ServiceType {get;}
Site                      Property      System.ComponentModel.ISite Site {get;set;}
StartType                 Property      System.ServiceProcess.ServiceStartMode StartType {get;}
Status                    Property      System.ServiceProcess.ServiceControllerStatus Status {get;}
ToString                  ScriptMethod  System.Object ToString();

a potem… od środka:

PS C:\_scriptZ> (get-service).psobject

Members : {Count = Length, int Length {get;}, long LongLength {get;}, int Rank {get;}...}
Properties : {Count = Length, int Length {get;}, long LongLength {get;}, int Rank {get;}...}
Methods : {void Set(int , System.Object ), System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, Publ
          icKeyToken=b77a5c561934e089 Address(int ), System.Object Get(int ), System.Object GetValue(Params
          int[] indices), System.Object GetValue(int index), System.Object GetValue(int index1, int index2
          ), System.Object GetValue(int index1, int index2, int index3), System.Object GetValue(long index)
          , System.Object GetValue(long index1, long index2), System.Object GetValue(long index1, long inde
          x2, long index3), System.Object GetValue(Params long[] indices)...}
ImmediateBaseObject : {aciseagent, AdobeARMservice, AdobeFlashPlayerUpdateSvc, agiptd...}
BaseObject : {aciseagent, AdobeARMservice, AdobeFlashPlayerUpdateSvc, agiptd...}
TypeNames : {System.Object[], System.Array, System.Object}

nas będą interesować 'properties’, których nazwy zawierają 'name’. nie będę się bawił w step-by-step, myślę, że taki początek wystarczy, a całą resztę trzeba po prostu usiąść i się pobawić. mamy podstawy więc teraz trzeba po PowerShellowemu zapisać zadanie „wyświetl wszystkie usługi (obiekty), następnie dla każdej usługi przefiltruj te parametry, który mają w nazwie 'name’ a następnie wyświetl tylko nazwę i wartość”. po takim zapisie to już bułka z masłem:

Get-Service|%{$_.psobject.properties|? name -match 'name'}|ft name,value

a teraz drugie zadanie – i tu robi się na prawdę pasqdnie, bo wartości mogą być różnych typów i też są obiektami. ponadto samo 'property, value’ będzie bezużyteczne bez dodatkowej informacji – nazwy usługi dla której je znaleźliśmy. poniżej rozwiązanie, zachęcam do zrozumienia – czyli samodzielnych testów:

get-service|%{$sn=$_.name;$_.psobject.members|?{$_.membertype -eq 'property' -and $_.value -eq $true}}|select @{N='ServiceName';E={$sn}},name,value

żeby nie było za łatwo… i tego nie potrafię wyjaśnić – z jakiegoś powodu 'Stopped’ jest traktowany jako $true. fragment wyjścia:

ServiceName Name Value
----------- ---- -----
aciseagent CanStop True
AdobeARMservice CanStop True
AdobeFlashPlayerUpdateSvc Status Stopped
agiptd CanStop True
AJRouter Status Stopped
ALG Status Stopped
ApHidMonitorService CanS... True
ApHidMonitorService CanStop True
AppHostSvc CanP... True
AppHostSvc CanS... True
AppHostSvc CanStop True
AppIDSvc Status Stopped
Appinfo CanStop True
AppMgmt Status Stopped
AppReadiness Status Stopped

… ale już nie chce mi się zagłębiać dalej.

sztuka dla sztuki? niekoniecznie. często trafiam na scenariusz, prostszy niż zaprezentowane, gdzie dostaję obiekt o dużej liczbie parametrów – np. obiekty EXO – i chcę sprawdzić czy gdzieś nie siedzi jakaś wartość, przy czym nie mam pojęcia jak może nazywać się parametr. o ile w ogóle istnienie. np. wyświetlmy wszystkie URI jakie są skonfigurowane dla grupy o365:

PS C:\_scriptZ> (Get-UnifiedGroup -Identity GuestGroupTest).psobject.Members.value|Select-String 'http'

https://outlook.office365.com/owa/?path=/group/GuestGroupTest@w-files.pl/calendar
https://outlook.office365.com/owa/?path=/group/GuestGroupTest@w-files.pl/mail
https://outlook.office365.com/owa/?path=/group/GuestGroupTest@w-files.pl/people
https://outlook.office365.com/EWS/Exchange.asmx/s/GetUserPhoto?email=GuestGroupTest@w-files.pl

to tak w ramach przygotowań do ShareCon365 (; zapraszam na moją sesję!

PS. aahhh… jeśli ktoś czytał z uwagą, to powinien zadać pytanie – „a jakie jeszcze ukryte parametry mają obiekty?„. i jeśli ktoś takie pytanie by zadał, otrzymałby zapewne odpowiedź: „<your-command>|gm -force

eN.

 

 

 

 

-o((:: sprEad the l0ve ::))o-

Comments (4)

  1. ziembor

    Odpowiedz

    a czasem w odrywaniu prosciej wroci do basha lupanego: get-service | select * | out-string | select-string name
    (twoje podejscie mi sie podoba… ale moje jest bardziej bezmyslne)

    • Odpowiedz

      bardzo słuszna uwaga! faktycznie mam tendencję do szukania rozwiązań, które potem można dalej skryptować, i zapominam o prostym out-string. dzięki!

  2. Odpowiedz

    Ciekawy wpis. Dodam od siebie, że pierwsze zadanie najłatwiej wykonać: Get-Service | Select *Name* Drugie faktycznie nie należy do tych trywialnych.

    Co do 'Stopped’ jako true, wydaje mi się, że to wynika, z niejawnej konwersji liczbowej wartości tego statusu (1) do typu [Bool]
    [System.ServiceProcess.ServiceControllerStatus]::Stopped.value__ -eq $true
    [System.ServiceProcess.ServiceControllerStatus]::Running.value__ -eq $false

    • Odpowiedz

      hahaah racja (: wyszedłem z innego problemu i szukałem przykładu na siłę. ale mam nadzieję że przekaz czytelny. dzięki za uzupełnienie!

Zostaw komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Time limit is exhausted. Please reload CAPTCHA.