Skip to Content

IT nieuczesane.
category

Category: DevOps/Scripting

skrypty, programy, command line i inne

konwersja XLSX do CSV metodą przeciągnij i upuść

drag’n’drop wygląda jakoś bardziej naturalnie… ale co tam. niech będzie po polsq (;

taka sytuacja…

spora część mojej pracy to zbieranie i analiza danych z systemów – AD, AAD, Ex, EXO, SfB i tak dalej. piszę sobie do tego pałerszelki i wrzucam to do CSV. no niestety – ale cały czas nie mogę się przestawić na jakąś sensowną bazę danych, ale to nie na dziś. potem takie CSVki łatwo jest otworzyć, edytować, analizować w Excel – oczywiście już jako xlsx. wszyscy Excel znają (LoL, raczej potrafią go otworzyć i coś wpisać, bo niestety poziom obsługi podstawowych narzędzi jest niestety, na równie podstawowym poziomie), dzięki o365 mamy wspaniałe funkcje koedycji – a więc w prosty sposób cały zespół może pracować na pojedynczym źródle.

żeby odświeżyć dane w excel, znów muszę wyeksportować go do CSV. czyli:

  • otworzyć arkusz
  • zrobić export (kilka kliknięć, wybór formatu, nie pomylić się, bo jest kilka formatów CSV itd…)
  • zamknąć.

nie lubię klikać, a więc fajnie byłoby mieć ikonkę na pulpicie, przeciągam plik XLS i voila! CSVka sobie czeka w ustalonym miejscu.

taki przydługi wstęp, ale taki dzień. jak to zrobić?

automatyczna konwersja XLSX2CSV via drag’n’drop

  1. trzeba sobie machnąć prosty skrypcik PS, który konwersji dokona. np taki:

convert-XLSX2CSV.ps1

nic skomplikowanego. jeśli ma być auto trzeba pamiętać, że ścieżki muszą być zahardcodowane, a parametry wejścia najlepiej ograniczyć do nazwy pliq.

2. zrobić skrót na pulpicie, który przyjmie plik drag’n’drop. jeśli zrobimy skrót do ps1 – nie zadziała. skrót musi być do pliq exe. a więc proste:

  • utwórz nowy skrót
  • jako plik do uruchomienia:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noprofile -file C:\_scriptZ\convert-xlsx2csv.ps1

…no i w zasadzie tyle. teraz wystarczy upuścić plik Excel na skrócie i życie jest dłuższe o kilka ładnych kliqw (=

bezpośrednia edycja XLSX

a nie można by tak bezpośrednio na excelu pracować? ano możnaby. nawet na serwerze. jest taka fajna biblioteka, która pozwala zaimportować się bez instalacji samego excel. nawet kiedyś o tym pisałem. ale obsługa tego skryptem, jest mówiąc oględnie – mało przyjemna. praca na zwykłych obiektach to czysta przyjemność.

eN.

 

przekazanie zmiennych

przekazanie zmiennej

to w jaki sposób przekazywane są zmienne – przez wartość, czy przez referencję – znacząco wpływa na to, jak łatwo/trudno będzie potem pisać skrypt, oraz żeby nie zrobić sobie krzywdy. oto jak to działa w PS.

najpierw najprostszy możliwy przykład:

co pojawi się na ekranie? będzie to:

czyli zmienna była przekazana przez wartość – $a i $b są niezależnymi zmiennymi, modyfikacja jednej, nie wpływa na drugą.

ALE

inny przykład – tym razem zmienną jest tablica:

i na ekranie pojawi się:

a to oznacza, że $b=$a jest przekazaniem referencji a nie kopią zmiennej. to hiper ważne, bo może zarówno pomóc ale i nieźle rozwalić całą logikę skryptu.

bardziej złożony scenariusz, gdzie takie przekazanie jest przydatne: „jest długa lista elementów. dla tych elementów, które nie mają wartości, trzeba wykonać jakąś [czasochłonną] operację, następnie trzeba wyeksportować całą listę”

przykładowa lista [list.csv]

prosty kawałek skryptu [test-reference.ps1]

podstawowe pytanie: co zwróci $data?

cały myk polega na tym, że:

  • importuję wszystkie dane.
  • tworzę zmienną stanowiącą ich podzbiór czyli elementy bez wartości [$data przefiltrowane -not $_.value]
  • wykonuję operacje na podzbiorze – foreach($d in $partialData)
  • i na końcu chcę wszystkie wartości, a nie tylko część, wyeksportować.

pomimo, że na końcu nie ma nigdzie przepisania $partialData z powrotem do $data, wynik jest:

dzięki temu, że $partialData tylko wskazuje na elementy tej samej tablicy, operacje wykonywały się bezpośrednio. nie muszę nic kombinować i mogę teraz zrobić po prostu „$data|export-csv”.

czasem jednak scenariusz może być zupełnie odwrotny – chcemy zrobić kopię danych i na nich się pobawić, nie wpływając na ‚master copy’. w takim przypadq można użyć kilq metod – np. klonowania:

eN.

 

przekazywanie wartości – c.d.

jakiś czas temu pisałem o tym, jak powinno się/można przekazywać wartości via pipeline. krótki komentarz…

clue jest takie, że:

  • trzeba włączyć funkcje zaawansowane cmdletbinding()
  • użyć bloku ‚process {}’ dzięki czemu każdy element będzie automatycznie procesowany przez ten blok kodu za każdym razem po ‚wpadnięciu’ do potoku.
  • dzięki temu można usunąć ‚foreach’ bo blok ‚process’ i tak wykona się dla każdego elementu.

warto się sqpić nad konsekwencją tego faktu. tablice przekazywać na [co najmniej] dwa podstawowe sposoby – jako potok oraz jako parametr:

… ale po usunięciu ‚foreach’ ze skryptu, przestanie działać prawidłowo przekazanie przez zmienną wyliczaną…

aby przekonać się o tym, można uruchomić poniższy skrypt, na oba sposoby, różniący się od poprzedniego wpisu tylko weryfikacją czy element jest tablicą:

reasumując

dla zachowania możliwości wykonania zarówno poprzez potok jak i przez zmienną, lepiej zostawić pętlę foreach – nic złego nie robi.

eN.

foreach valuefrompipeline

*EDITED

mały tutorial o przetwarzaniu przekazywanych wartości, który może radykalnie zmienić czas przetwarzania skryptu. wiadomka – pipelining jest podstawowym mechanizmem PS a przy przetwarzaniu wielu elementów, czasem wręcz odruchowo, wpisuje się ‚%’ czyli foreach-object. przykładowo – znajdź wszystkich, którzy mają nazwisko na ‚x’ i wyślij im wiadomość:

a teraz standardowy scenariusz z życia codziennego: dostajemy jakieś listy w postaci pliqw tekstowych. załóżmy, że są w nim nazwy kont, z którymi coś trzeba zrobić. szkielet jest trywialny:

…mija czas i okazuje się, że nasze ‚do-something’ rozbudowaliśmy do postaci skryptu, ponieważ ilość wykonywanych czynności rośnie i oneliner jest zbyt mało wygodny. wartości można do skryptu przekazywać na dwa sposoby – bezpośrednio, jako parametr lub – tak jak powyżej – przez pipelining. druga metoda nie działa ‚od ręki’, wymaga włączenia poprzez specjalny parametr: ‚valueFromPipeline‚ [lub valueFromPipelineByPropertyName… ale to na inny wpis].

żeby pokazać co się będzie działo załóżmy, że mamy listę komputerów i operacja wymaga uwierzytelnienia się do zdalnego zasobu:

w takim przypadq, aby uruchomić skrypt dla całej listy, należy przekazać listę przez parametr:

polecenie w nawiasach ‚( )’ zostanie przetworzone, listing pliq zwraca tablicę stringów string[] i to zostanie przetworzone w skrypcie. jak na razie oczywiste oczywistości. nuda… ale zadanie nad którym pracujemy chcemy coraz bardziej automatyzować, cały proces do którego piszemy skrypty jest dość rozbudowany, a więc nasze skrypty muszą ze sobą gadać – output z jednego chcemy móc przekierować na kolejny. czyli trzeba włączyć pipelining:

jeśli przekażemy wartości przez parametr tak, jak do tej pory, to nic się nie zmieni. ale jeśli przekażemy przez pipe … coś nie halo:

..wyświetli tylko dla ostatniego elementu /: [zwróć uwagę, że skrypt ‚do-something’ wywołany jest bez parametru – valueFromPipeline oznacza ‚jeśli potok wyjściowy jest przekierowany, przekaż go do tej zmiennej oznaczonej valueFromPipeline’ ]

ah! no oczywiście! zapomnieliśmy foreach:

[tutaj już musi być parametr – $_ . a to dla tego, że nawiasy klamrowe ‚{ }’ definiują blok danych, separując potok od polecenia. niby niuans ale pokazuje, że totalnie zmienia się mechanika pod spodem]

hmm… no ale mamy kolejny problem – teraz skrypt przed każdym wywołaniem prosi o dane uwierzytelniające. lama poradzi sobie dodając parametr ‚credential’ i przekazując go podczas wywołania. ale to nie jest zawsze dobry sposób i dobrze wiedzieć czemu tak się dzieje. błąd został popełniony w momencie dodania ‚foreach’ (2). parametr ‚identities’ w skrypcie został sprytnie zadeklarowany jako tablica, a więc powinien tablicę przyjąć. ale dodając ‚foreach’, rozbijamy tablicę na poszczególne elementy i uruchamiamy skrypt wiele razy, przekazując każdą kolejną wartość jako parametr wywołania. a nie o to chodziło.

rozwiązaniem jest dodanie składni ‚begin-process-end’ do skryptu. standardowo skrypt czeka na pojedynczą wartość, po dodaniu tego bloq tworzy ‚pułapkę’ zawartą w bloq ‚process’, która będzie się uruchamiać dla każdego kolejnego elementu. co więcej, ‚process’ zostanie wykonany dla każdego przekazywanego elementu dokładnie tak, jak ‚foreach’, a więc można się pozbyć tego fragmentu:

teraz jeśli uruchomi się ‚do-sthelse | do-something’ – zostaniemy zapytanie o credsy tylko raz, po czym wykonana zostanie część ‚process’, a na koniec jednokrotnie wykona się klauzula ‚end’. wyrzucam ‚gwmi’ żeby pokazać przetwarzanie i zostawiam tylko write-host:

o to chodziło.

co zapamiętać

czym innym jest przekazanie tablicy a czym innym kolejne przekazywanie parametrów tablicy – czyli foreach. jeśli skrypt jest duży, to można dużo oszczędzić. dla tego przy pokaźnych operacjach warto zajrzeć do pomocy, opisu parametrów skryptu i sprawdzić czy deklaracja:

  • pozwala na przekazanie tablicy – np. [string[]]
  • pozwala na przekazanie przez pipe – valueFromPipeline

ponadto trzeba pamiętać, że ponieważ ‚valueFromPipeline’ jest pewnego rodzaju wskaźnikiem ‚TU PRZEKIERUJ WSZYSTKO CO WPADA’ – to może być zadeklarowane tylko raz. zadeklarowanie wielokrotnie nie spowoduje błędu składniowego, skrypt uruchomi się, ale wyniki będą mocno niedeterministyczne…

eN.

transformacja listy do csv

dane przekazywane są w różny, czasem dość dziwny sposób. ostatnio potrzebowałem danych do migracji w office365 i dane zostały przedstawione jako spis, gdzie jedynym wiążącym elementem była ilość wpisów dla każdego obiektu. coś takiego (example.txt):

takich wpisów było prawie 1oo a w efekcie chodziło o stworzenie tabeli, i dokonanie transpozycji:

nazwa parametr coś linia bez znacznika
jakaś nazwa wartość parametru tutaj jakaś wartość a tutaj kolejna wartość
inna nazwa inna wartość parametru coś i tu znów wartość
nazwa 3 parametr 3 tralalala blablabla
znów coś ciągle coś innego przykadowy ciąg znaków a tutaj kolejna wartość

 

jak widać zapis wygenerowany na stronie był dość luźny w stosunq do tego, co chciałbym mieć na końcu. tutaj poradziłem sobie przepisując ręcznie, ale przy dużej ilości wpisów…

wszystkiego nie ma sensu automatyzować, ale podstawowym zadaniem będzie owa transpozycja. w sumie to dwie linijki kodu:

pierwsza linijka to po prostu odczytanie zawartości pliq do zmiennej. a cała ‚transpozycja’ to de facto zauważenie, że:

  • każdy obiekt zapisany jest na 5 liniach
  • następnie jest pusta linia oddzielająca
  • kiedy sklei się wszystkie 5 linii średnikami.. to w zasadzie już

cały myk jak ładnie skleić wartości tabeli do stringa? wystarczy wskazać tabelę, i użyć ‚join’. ot – PowerShell. nie trzeba żadnych pętli ani wynalazków, wszystko zrobi za nas (; dodajmy do tego, że substrakt tabeli można uzyskać wskazując konkretne elementy, a jeśli są w zapisie ciągłym to wystarczy użyć ‚..’ . czyli tak:

inkrementując w pętli $i+=6 – to przeskakiwanie co 6 kolejnych linii.

‚podtabela’ma natomiast podane $i+5 aby ominąć ostatnią, pustą wartość.

…teraz wystarczy otworzyć w excelu i sobie resztę doklikać i uporządkować. voila.

eN.

 

Misja na Marsa

pół żartem, pół serio, przed chwilą pisałem, że moim marzeniem jest wziąć udział w projekcie interplanetarnym. a tu proszę – Misja na Marsa.

eN.

compare uncomparable

*UPDATED

bardzo często korzystam z ‚compare-object’ ale ma niestety jedną bardzo, bardzo poważną skazę. pomimo swojej nazwy, wcale nie potrafi porównywać obiektów, a raczej wykrywać różne obiekty w tablicy. oto przykład:

$t1 i $t2 są takimi samymi obiektami, różnią się niektórymi wartościami atrybutów – np. Paged Memory [PM(K)]. compare różnicy nie widzi. oczywiście można porównać konkretne atrybuty [properties]:

ale kiedy poda się kilka parametrów, to compare-object traktuje je jako logiczny OR –
„czy którykolwiek z nich się różni?”:

moje odczucie jest takie, że compare-object został napisany z myślą o tabelach, gdzie dla kolejnych wierszy pokazuje różnice w kolumnach. w przypadq obiektów jest odwrotnie – każdy wiersz jest unikalny i ma wartość. więc albo trzeba byłoby skonwertować to do tablicy i dokonać transpozycji, albo obejść się bez compare-object /: jak się okazuje nawet PowerShell ma wady i nie jest idealny. ten przypadek jest szczególnie bolesny i niezrozumiały, zarówno ze względu na obiektowość PS, jak i zwodniczą nazwę.

jeden ze scenariuszy: szukałem różnic w wartości obiektów po migracji między usługami, żeby wykryć, gdzie była zmiana. dla ułatwienia zrobiłem sobie zrzut obiektu do CSV [ale to nie ma znaczenia]. efekt był dokładnie taki jak opisywany powyżej, czyli nie pokazywał mi różnic. i trzeba było sobie to ręcznie oprogramować:

PS szybko rozleniwia /:

/UPDATE

okazuje się, że Tatuśkowi też zabrakło takiej funkcjonalności więc napisał piękną funkcję do jej obsługi: Compare-ObjectProperty.

dzięki Kacper za linka (:

eN.

 

 

 

unikaty i duplikaty

Duplikaty

łatwo jest przefiltrować listę tak, aby mieć tylko unikalne elementy – jest zarówno commandlet ‚get-unique’ oraz parametr ‚-unique’ przy select-object, ale jak wyłuskać duplikaty?

sposobów jest oczywiście wiele a ten, który mi się podoba to:

lub w hiperpoprawnym zapisie:

plik:

a teraz sprawdźmy duplikaty:

można jeszcze upiększyć output, pozbywając się śmieci:

Unikaty

powracając jeszcze do unikatów… wydawałoby się, że skoro jest oddzielne polecenie – get-unique, to powinno mieć większe możliwości i być bardziej elastyczne niż jakiś tam parametr do innego polecenia.

o dziwo jest odwrotnie. osobiście traktuję get-unique jako ciekawostkę i nie miałem scenariusza, w którym bym go użył. a to dla tego iż [msdn]:

The Get-Unique cmdlet compares each item in a sorted list to the next item, eliminates duplicates, and returns only one instance of each item. The list must be sorted for the cmdlet to work properly.

Get-Unique is case-sensitive. As a result, strings that differ only in character casing are considered to be unique.

eN.

conditional switch

Windows_PowerShell_iconczęsto zamiast budowy skomplikowanych IFów lepiej jest skorzystać ze switcha. czyli zamienić złożoną składnię bazowaną na wielu ‚if-then-else’ dużo czytelniejszym i prostszym blokiem ‚switch’. to oczywista oczywistość ale jest coś bardziej ‚zaawansowanego’ co jeszcze bardziej ułatwia życie – PowerShellowy Switch pozwala nie tylko na proste porównania, czy definicje wildcardów, które można znaleźć w manualu, ale również na tworzenie złożonych wyrażeń logicznych.

przykład takiego switcha:

test-switch.ps1

uwagę należy zwrócić na:

  • zastosowanie ‚break’ – standardowo switch wykona *wszystkie* bloki, spełniające warunek. w przypadku wywołania test-switch z parametrem 1 lub 2 pojawi się dodatkowo informacja ‚mniejsze niż 4 [ale nie większe niż 2]‚ . jeśli liczba będzie większa niż 3, wpadnie w klauzulę z ‚break’ i ostatni krok nie zostanie wykonany. dla tego należy pamiętać, że *kolejność ma znaczenie*.
  • dzięki temu, że switch wykonuje wszystkie bloki spełniające warunek, można zrobić krok typu ‚catch all’ – który wykona się zawsze. ale warto umieścić go jako pierwszy tak, żeby nie przerwał go jakiś break. najlepiej użyć ‚switch -wildcard’ -> manual.
  • w instrukcji [man switch] można znaleźć bardzo fajne przykłady dla wyrażeń regularnych i wildcardów, dla tego pomijam go w tym prostym przykładzie. ale warto wiedzieć, że można wykonywać również zaawansowane porównania na ciągach znaków.
  • to czego zabrakło w manualu to właśnie przykład wyrażenia logicznego. klauzulą może być dowolne wyrażenie zamknięte w nawiasach klamrowych {} . oczywiście dla determinizmu zachowania powinno zwracać true/false.
  • PS switch nie pozwala na definiowane tego samego bloku dla kilq wartości [listy] tak, jak to się robi np. w VBS, czyli nie da się zdefiniować ‚ 1,2 { blok } ‚ . w zamian można użyć warunku logicznego ‚{1 -or 2} {blok} ‚ . trochę mniej wygodne, ale działa tak samo (:

proste i wydajne. proponuję dla gimnastyki rozpisać to sobie na IFach… (;

eN.

 

szkolenie PowerShell – jak pisać skrypty

MVAw końcu! materiał na długo utknął w postprodukcji (; ale w końcu jest – 3cia część szkolenia, tym razem już dla mniej-początqjących – ‚jak pisać skrypty/funkcje’. szkolenie jest na pewno ciekawsze, ponieważ towarzyszy mi Darek Porowski, który pilnuje żebym nie przynudzał za bardzo. i to [chyba] zadziałało q:

zachęcam do zapoznanie się z materiałem i oceny ::))o- PowerShell dla zaawansowanych – http://aka.ms/plmva-psadv

eN.