Jekyll2020-09-17T21:37:06+02:00http://zapytajemila.pl/feed.xmlEmil WasilewskiBlog o technologiachEmil WasilewskiCo na mym biurku piszczy, czyli czego używam do pracy w i z domu2020-09-07T11:00:00+02:002020-09-07T11:00:00+02:00http://zapytajemila.pl/blog/co-na-mym-biurku-piszczy<p>Dodając do tego “pracę” po godzinach na rozwój osobisty, aktywność w azurowej społeczności czy chociażby rozrywkę, okazuje się, że przed komputerem spędzam (Ty być może podobnie) po kilkanaście godzin dziennie.
To dużo, szczególnie gdy powie się o tym pani okulistce na badaniu :)</p>
<p>W związku z powyższym, w miarę możliwości, starałem się urządzić moje miejsce codziennej pracy jak najlepiej. Choć świadom jestem tego, że nie jest idealnie, to postanowiłem spisać to co mam obecnie przed (i pod) sobą piszcząc ów post.</p>
<h1 id="miejsce-pracy">Miejsce pracy</h1>
<h2 id="krzesło">Krzesło</h2>
<p>Tu nie ma żadnych fajerwerków, gdzieś kiedyś w X-KOM w “gorącym strzale” wychwyciłem krzesło “gamingowe” w okolicach 499zł - na ból pleców nie narzekam. Od czasu do czasu doceniam możliwość rozłożenia oparcia znacznie do tyłu - przydatna funkcjonalność w przypadku chęci odbycia krótkiego “power nap” po obiadku.</p>
<p><img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/krzeslo.jpg" alt="krzesło.jpg" /></p>
<p><em>jak widać, to nawet zaczęło się trochę zużywać w postaci naderwania</em> :(</p>
<h2 id="biurko">Biurko</h2>
<p>Od czasu gdy pierwszy raz miałem możliwość zasmakowania pracy przy regulowanym biurku u jednego z klientów, chęć posiadania własnego nie dawała mi spokoju. Na szczęście obecny gabinet, w którym urządziłem swoje gniazdko, pozwolił na spełnienie owego bądź co bądź marzenia.
I tak oto, łokcie swe opieram na biurku <a href="https://www.ikea.com/pl/pl/p/idasen-biurko-z-regulacja-wysokosci-czarny-bezowy-s99280978/">IDÅSEN</a> z IKEA (firma ta pojawi się poniżej jeszcze kilkukrotnie ;) ) w rozmiarze 160x80 - och jak się cieszę, że nie wziąłem mniejszego - i szczerze polecam wszystkim, którzy mogą sobie pozwolić na taki rozmiar - brać, nie zastanawiać się. W biurze mam klasyczne biurko 120x70cm - no i tak jakoś “strasznie ciasno”.
Biurko regulowane jest elektrycznie za pomocą przycisku - niestety sam przycisk nie ma wbudowanej pamięci wysokości. Z pomocą jednak przychodzi aplikacja LINAK, którą możemy sparować z naszym biurkiem i zapisać 3 ulubione wysokości. Zmiany możemy dokonać za pomocą strzałek góra dół, lub przytrzymując zapisaną wcześniej wysokość. Ogólnie z biurka jestem zadowolony.</p>
<h2 id="na-biurku">Na biurku</h2>
<h3 id="podkładka">Podkładka</h3>
<p>Na biurku leży podkładka pod klawiaturę i myszkę jednocześnie. W pierwszej kolejności skorzystałem z opcji “budżetowej” i drogą kupna nabyłem <a href="https://www.ikea.com/pl/pl/p/skrutt-podkladka-na-biurko-czarny-60291746/">SKRUTT</a> - tanią podkładkę z IKEA. To był błąd, bo to plastikowe *** z racji swej wagi i tworzywa nie leżało “spokojnie” na blacie. Czarę goryczy przelał kubek z kawą postawiony bez podstawki - się wybrzuszyła w tym miejscu. Zmieniłem czym prędzej na <a href="https://www.ikea.com/pl/pl/p/rissla-podkladka-na-biurko-czarny-40246156/">RISSLA</a> (ponownie IKEA) no i “jestem w domu”. Podkładka leży stabilnie, jej rdzeń jest stalowy, więc notatki można sobie magnesikami przypinać, żeby nie uciekały, a do tego jest sztywna i ciężka - leży w miejscu. Jest OK. Będzie przewijać się na zdjęciach w dalszej części.</p>
<h3 id="lampka">Lampka</h3>
<p>Tu w przeciwieństwie do podkładki, opcja budżetowa spisuje się prawidłowo. Wybór padł na lampkę <a href="https://www.ikea.com/pl/pl/p/tertial-lampa-biurkowa-ciemnoszary-50355395/">TERTIAL</a> - ponownie z IKEA. Ma gwint E27 (gruby) co pozwala na skorzystanie z większości “inteligentnych” żarówek .
Jak akurat umieściłem w niej żarówkę <a href="https://www.ikea.com/pl/pl/p/tradfri-zarowka-led-e27-600-lumenow-bezprzewodowy-przyciemniany-barwne-i-biale-spektrum-kolorowe-i-biale-spektrum-kula-opalowa-biel-00408612/">TRÅDFRI</a> RGB 600lm.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/lampka.jpg" alt="lampka.jpg" />
Dzięki temu mogę dostosowywać siłę światła do pory dnia. Za dnia pracuję na 100% (zasłony widoczne na zdjęciu z krzesłem są cały dzień zasłonięte), a wieczorem zmniejszam do ok. 20%, czasem nawet 10%. Zdarza się też, że ustawiam kolor czerwony wieczorem, aby nie męczyć oczu.</p>
<h3 id="organizer">Organizer</h3>
<p>Po mej lewej stronie, do brzegu biurka przytwierdzoną mam tablicę <a href="https://www.ikea.com/pl/pl/p/skadis-tablica-perforowana-bialy-10321618/">SKÅDIS</a> wraz z akcesoriami w postaci półek, pojemniczków czy haczyków - daje radę.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/tablica.jpg" alt="tablica.jpg" /></p>
<h3 id="głośnik">Głośnik</h3>
<p>Na zdjęciu tablicy widać także głośnik Harman Kardon Invoke z wbudowaną asystentką Microsoft - Cortaną. Przyjemny gadżet, szczególnie jesienią 2020 roku, gdy wiadome już jest, że w styczniu 2021 Microsoft wyłączy Cortanę na tym głośniku 🤣
Niemniej, sam głośnik gra bardzo przyzwoicie z uwagi na głośniki umieszczone dookoła urządzenia.</p>
<h1 id="sprzęt">Sprzęt</h1>
<h2 id="komputer">Komputer</h2>
<p>W połowie sierpnia 2020 porzuciłem po ponad dwudziestu latach platformę Microsoft (nie w pełni oczywiście) i przeniosłem się na system operacyjny od Apple.
Pisać o powodach zmiany tutaj nie będę. Na potrzeby postu przyjmijmy, że na Windows było OK, jednak postanowiłem spróbować czegoś ”innego”.
Do tej pory pracowałem na Surface Book 2, poprzednio na Surface 4 Pro, a kiedyś tam miałem jeszcze jakiegoś Della.
Pod biurkiem stoi stacjonarka - nie pamiętam kiedy ją uruchamiałem ostatni raz.</p>
<p>Wracając. Ostatni mój nabytek to MacBook Pro 16 2019 w specyfikacji jak poniżej.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/macOS.png" alt="macOS.png" /></p>
<p>Od strony wydajności nie mam co porównywać do Surface Book 2, bo to dwie inne konfiguracje (SB2 to i7 niskonapięciowy 15W vs. 45W w MacBook).
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/macbook.jpg" alt="macbook.jpg" /></p>
<h2 id="myszka">Myszka</h2>
<p>Dawno dawno temu (czyli w 2018 roku) będąc w Redmond, podczas wizyty w Microsoft Store nabyłem w okazyjnej cenie <a href="https://www.microsoft.com/pl-pl/p/surface-precision-mouse/8qc5p0d8ddjt">Surface Precision Mouse</a>. Genialna myszka. Szkoda, że gdzieś ją zapodziałem (najprawdopodobniej podczas innej wyprawy za ocean 😂 ). W związku ze stratą, zakupiłem myszkę <a href="https://www.logitech.com/pl-pl/products/mice/mx-master-3.910-005694.html">Logitech MX Master 3</a>. Całkiem fajna mysz. Przyjemna w obsłudze, nadgarstek nie boli po całodniowym użytkowaniu. Jedyny jej mankament (dla mnie) to mocno wysunięta część pod kciuk. Niby kilka milimetrów, a jednak powoduje to dość częste kolizje z klawiaturą. Tak poza tym, to spoko.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/myszka.jpg" alt="myszka.jpg" /></p>
<h2 id="klawiatura">Klawiatura</h2>
<p>Podobnie jak z myszką Microsoft, posiadałem <a href="https://www.microsoft.com/pl-pl/p/surface-keyboard/8r3rqvvflp4k">Surface Keyboard</a>. Świetna klawiatura. Długo trzymała na baterii, czuła, cicha. No miód malina.
Niestety, pod macOS nadaje się średnio, więc klawiatura trafiała na półkę, a na jej miejsce zawitała <a href="https://www.logitech.com/pl-pl/products/keyboards/mx-keys-wireless-keyboard.html">Logitech MX Keys</a>.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/klawiatura.jpg" alt="klawiatura.jpg" />
Wszyscy zachwalają tą klawiaturę…no ja nie mogę się nie zgodzić. Pracuje się na niej bardzo wygodnie. Przy czym ja mam nieco utrudnione “doznawanie” klawiatury, gdyż jednocześnie uczę się obsługi nowego systemu operacyjnego, a pamięć mięśniowa po ponad 20 latach…grrrr…</p>
<h2 id="stacja-dokująca">Stacja dokująca</h2>
<p>Element ten nie jest konieczny, gdyż monitor (o nim poniżej) zapewnia zasilanie MacBooka, ale chciałem uporządkować kable, a jednocześnie uzyskać trochę wygodniejszy dostęp do portów.
Po drobnej wpadce z zakupem pierwszej stacji (nie spojrzałem dokładnie na Serial Number i kupiłem wersję bez tzw. Power Delivery), zdecydowałem się na sprzęt od Belkina a mianowicie <a href="https://www.belkin.com/us/p/P-F4U097/">Belkin Thunderbolt™ 3 Dock Pro</a>.
Stacja działa bardzo sprawnie. Macbook nawet przy ciężkiej pracy (np. render video w Camtasia) nie traci baterii. Samo urządzenie trochę się nagrzewa (wg. pomiarów obudowa ma ok 40st Celsjusza).
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/stacja.jpg" alt="stacja.jpg" /></p>
<h2 id="monitor">Monitor</h2>
<p>Macbook po porcie Thunderbolt wpięty jest do stacji dokujące, a z niej po USB-C do monitora. Monitor kupiłem już ponad rok temu i mogę powiedzieć, że praca na “zwykłym” monitorze potrafi być wyzwaniem. Dlaczego? A no dlatego, że zdecydowałem się na <a href="https://www.dell.com/en-uk/shop/dell-ultrasharp-34-curved-usb-c-monitor-u3419w/apd/210-aqvq/monitors-monitor-accessories">Dell UltraSharp 34 Curved USB-C Monitor: U3419W</a>, czyli monitor szerokokątny o proporcjach 21:9.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/monitor.jpg" alt="monitor.jpg" />
Szeroki układ przydaje się w pracy na wielu oknach, czy w portalu Azure, gdzie kolejne zakładki konfiguracji “rozwijają” się w prawo. Dodatkowo, praca np. w Camtasia jest jak dla mnie przyjemniejsza - mam “dłuższy” pogląd na timeline. Nie bez znaczenia jest też widok zakładek w przeglądarce.
Co ciekawe, zauważyłem pewne zawirowanie w postrzeganiu płaskich monitorów. Jeśli po dłuższej pracy przesiądę się do “zwykłego” monitora, to odczuwam wrażenie, że monitor jest wypukły - tak jak kiedyś monitory CRT :)</p>
<h2 id="kamera">Kamera</h2>
<p>Jako, że przy pracy z domu nieuniknione są wideo konferencje, to dobre ujęcie naszej twarzy i czysty dźwięk podczas naszych wypowiedzi powinny stanowić istotny punkt podczas wyposażania stanowiska pracy.
Jako kamerę wybrałem <a href="https://www.logitech.com/en-us/product/c922-pro-stream-webcam">Logitech C922</a>, którą zakupiłem na początku roku 2020 - tuż przed kowidową paniką i żniwami sprzedawców. Choć kupując ją, nie spodziewałem się tego co urządzi nam covid, to miałem dużo szczęścia. Za kamerę zapłaciłem “zaledwie” 298.99 zł brutto. W “piku” widziałem tą samą kamerę w okolicach 800zł, a w momencie pisania posta najniższe ceny jakie widzę zaczynają się od 498zł :)
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/kamera.jpg" alt="kamera.jpg" /></p>
<h2 id="mikrofon">Mikrofon</h2>
<p>Mógłbym użyć tu np. mikrofonu z kamery - nie jest najgorszy. Korzystałem też z mikrofonu w słuchawkach, w których pracuję. Oba jednak mikrofony miały pewną “wadę” - a mianowicie zbierały dźwięki z otoczenia co było wyraźnie słychać w głośnikach moich rozmówców.</p>
<p>Jako, że na potrzeby nagrań na kanał <a href="https://www.youtube.com/c/AzureBezSciemy/">ABŚ - Azure Bez Ściemy</a> zakupiłem swego czasu rejestrator <a href="https://zoomcorp.com/en/jp/handy-recorders/handheld-recorders/h6-audio-recorder/">Zoom H6</a> pierwszej generacji (link prowadzi już do drugiej), to postanowiłem wykorzystać go jako główny odbiornik mojej mowy do nagrań i rozmów.
Zoom H6 posiada specjalne gniazdo rozszerzeń do którego pasują dedykowane akcesoria. Jednym z takich akcesoriów jest mikrofon kierunkowy o oznaczeniu <a href="https://www.zoom.co.jp/products/product-accessories/sgh-6-shotgun-microphone-capsule">SGH-6</a>. Dzięki niemu, mogę ustawić mikrofon skierowany na usta i przy niskiej czułości “nadawać” czysty dźwięk bez zbierania “tła” np. w postaci “bawiących” się w pokoju obok dzieci.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/zoom.jpg" alt="zoom.jpg" /></p>
<p>Dokupiłem też akcesorium do włączania i wyłączania “fizycznie” mikrofonu. Jest to pilot o oznaczeniu RCH-6 i można go zakupić w <a href="https://www.zoom.co.jp/products/product-accessories/aph-6-h6-accessory-pack">dedykowanym zestawie</a>.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/pilot.jpg" alt="pilot.jpg" /></p>
<h2 id="słuchawki">Słuchawki</h2>
<p>Przez długi czas korzystałem z klasycznych słuchawek “na kablu”. Miałem ich wiele, choć wszystkie “budżetowe”. Spełniały swoją rolę - grały.
Niemniej, gdy zacząłem trochę więcej latać samolotami to zrodziła się potrzeba słuchawek z aktywnym wyciszeniem otoczenia.
Ponownie będąc w USA i korzystając z okazyjnej “promocji” zakupiłem <a href="https://www.bose.pl/pl_pl/products/headphones/over_ear_headphones/quietcomfort-35-wireless-ii.html#v=qc35_ii_black">Bose QuietComfort 35 II</a>. Nie jestem audiofilem, dlatego nie oceniam aż tak kategorycznie dźwięku - mi pasuje. Pasuje mi również coś innego - czasem gdy je nałożę do pracy i całkiem przypadkiem zapomnę włączyć sobie muzykę, to zapominam również o tym, że mam coś na głowie - są na prawdę wygodne.
Do tego długi czas pracy na baterii i współpraca jednocześnie z dwoma urządzeniami (np. komputer i telefon).
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/sluchawki.jpg" alt="sluchawki.jpg" />
Po chyba dwóch latach intensywnego użytkowania naderwały się mocowania pianek - kupiłem zamienniki…i nie czuć różnicy (więc po co przepłacać?). Polecam.</p>
<h1 id="inne">Inne</h1>
<ul>
<li>Mam na biurku jeszcze poczciwego <a href="https://ark.intel.com/content/www/pl/pl/ark/products/81164/intel-nuc-kit-d54250wykh.html?q=D54250WYKH">Intel NUC</a> z i5 i 16GB RAM na którym stoi Windows 10 z Hyper-V.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/nuc.jpg" alt="nuc.jpg" /></li>
<li>Zdjęcia do wpisu pochodzą z <a href="https://www.panasonic.com/pl/consumer/kamery-i-aparaty/aparaty-cyfrowe/dc-gh5.html">Lumixa GH5</a> z obiektywem <a href="https://www.panasonic.com/pl/consumer/kamery-i-aparaty/obiektywy/h-es12060.html">Panasonic Leica DG Vario Elmarit 12-60</a></li>
<li>Monitor wisi na prostym ramieniu Ergosolid ® NF14, choć obecnie zdjąłem drugie ramię, gdyż MacBook stoi zamknięty podczas pracy</li>
<li>Od czasu do czasu posiłkuję się jednym z moich pierwszych “nabytków początkującego prelegenta”, a mianowicie monitorem zewnętrznym na USB <a href="https://www.asus.com/Monitors/MB169BPlus/">ASUS MB169B+</a> - przydaje się do udostępniania ekranu w natywnej rozdzielczości 1080p.
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/asus.jpg" alt="asus.jpg" />
<em>tak na drzwiach wisi koc - takie a’la profesjonalne wygłuszenie drzwi</em> :)</li>
<li>przewraca się też gdzieś iPad 2017 - przydatny jako podgląd tego “co widzą ludzie” (widoczny na zdjęciu powyżej)</li>
<li>pod biurkiem z kolei zamontowałem popularny organizer kabli z IKEA <a href="https://www.ikea.com/pl/pl/p/signum-maskownica-do-kabli-pozioma-srebrny-30200253/">SIGNUM</a>. Niestety jego wysokość nie pozwalała na wrzucenie tam listwy z zasilaczami, dlatego też, jedne z końców spiąłem “trytytką” i tak sobie wisi.</li>
<li>dla ukrycia bałaganu z tyłu biurka, zainwestowałem w ściankę <a href="https://www.ikea.com/pl/pl/p/eilif-scianka-do-biurka-ciemnoszary-20466936/">EILIF</a>
<img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/oslona.jpg" alt="oslona.jpg" /></li>
<li>Zoom H6 wisi na ramieniu od Manfrotto model <a href="https://www.manfrotto.com/global/heavy-duty-flexible-arm-520mm-237hd/">237HD</a></li>
</ul>
<h1 id="podsumowanie">Podsumowanie</h1>
<p>No to chyba byłoby tyle z tego mojego “domowego biura”. Tak jak pisałem we wstępie - nie jest jeszcze idealnie, ale jest na tyle komfortowo, że da się przyjemnie pracować z domu.</p>
<p><img src="/assets/images/posts/2020-09-07-co-na-mym-biurku-piszczy/calosc.jpg" alt="calosc.jpg" /></p>Emil WasilewskiWydarzenia roku 2020 sprawiły, że wiele osób zmuszonych zostało do pracy z domu. Ja i wielu moich znajomych z domu pracowaliśmy już wcześniej, może nie w pełnym wymiarze godzin, ale jednak.Microsoft PowerApps, SharePoint Online, Power Automate i te niesforne załączniki2020-08-12T09:00:00+02:002020-08-12T09:30:00+02:00http://zapytajemila.pl/blog/Microsoft-Power-Automate-Power-Apps-i-SharePoint-Online<p>W ostatnim czasie miałem okazję pracować trochę z PowerApps. Scenariusz jaki przyszło mi obsłużyć zakładał wrzucanie plików wraz z kilkoma informacjami do Listy w SharePoint Online.
Aby ograniczyć bezpośredni dostęp do SharePoint Online użytkownikom końcowym, postanowiłem jako interfejs “wejściowy” wykorzystać aplikację stworzoną w PowerApps.
Po pomyślnym umieszczeniu pliku na liście, użytkownik miał otrzymywać wiadomość e-mail wraz z wprowadzonymi przezeń informacjami, w tym także bezpośredni link do załącznika.</p>
<!--more-->
<p>Spis treści:</p>
<ul>
<li><a href="#1-integracja-sharepoint-online-i-power-automate">1. Integracja SharePoint Online i Power Automate</a></li>
<li><a href="#2-przepływ-power-automate">2. Przepływ Power Automate</a></li>
<li><a href="#3-powerapps-i-sharepoint-online">3. PowerApps i SharePoint Online</a></li>
<li><a href="#4-problemy-z-załącznikami">4. Problemy z załącznikami</a></li>
<li><a href="#5-rozwiązanie">5. Rozwiązanie</a></li>
<li><a href="#6-podsumowanie">6. Podsumowanie</a></li>
</ul>
<h3 id="1-integracja-sharepoint-online-i-power-automate">1. Integracja SharePoint Online i Power Automate</h3>
<p>“Na szczęście” z poziomu Listy SharePoint Online można w łatwy sposób dodać automatyzację wykorzystując do tego celu usługę Power Automate (dawniej Flow).</p>
<p><img src="/assets/images/posts/2020-08-11-Microsoft-Power-Automate-Power-Apps-i-SharePoint-Online/Image1.jpg" alt="SharePoint Online and Automate" />
W ramach dostępnych szablonów możemy wybrać opcję <strong>“<a href="https://docs.microsoft.com/en-us/connectors/sharepointonline/#when-an-item-is-created?WT.mc_id=M365-MVP-5001765">When an item is created</a>“</strong>. Działa to całkiem zadowalająco.
Po utworzeniu elementu listy w ciągu kilku/kilkunastu sekund odpowiedni wyzwalacz jest wywoływany i nasza automatyzacja może się zadziać.</p>
<h3 id="2-przepływ-power-automate">2. Przepływ Power Automate</h3>
<p>Gdy już mamy “połączenie” naszej Listy w SPO z Power Automate możemy przejść do działania.
Tworzymy prosty przepływ polegający na pobraniu listy załączników (2) z utworzonego elementu (1), a następnie umieszczeniu bezpośrednich adresów do tychże (4) w zmiennej <em>AttachmentURL</em> (3). W celu “weryfikacji”, czy załącznik został przesłany, sprawdzamy jeszcze warunek (5), czy zmienna <em>AttachmentURL</em> jest pusta czy też nie. Jeśli jest, to kończymy przepływ błędem i odpowiednim komunikatem (6). W przeciwnym razie kończymy sukcesem (7).</p>
<p><img src="/assets/images/posts/2020-08-11-Microsoft-Power-Automate-Power-Apps-i-SharePoint-Online/Image2.jpg" alt="Power Automate" /></p>
<p>Jako że SPO pozwala dodać wiele załączników do jednego elementu listy, wynikiem akcji <em>Get attachments</em> jest lista obiektów załączników - stąd też pętla <em>Apply to Each</em>. Jednak w moim scenariuszu występować miał tylko jeden załącznik per element listy.
OK, jak do tej pory wszystko idzie gładko. Przejdźmy zatem do PowerApps.</p>
<h3 id="3-powerapps-i-sharepoint-online">3. PowerApps i SharePoint Online</h3>
<p>PowerApps posiadają cały zestaw funkcji do obsługi List w SharePoint.
Dokładny opis można znaleźć oczywiście w <a href="https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/functions/function-form">dokumentacji</a>.</p>
<p>W tym wypadku użyjemy funkcji <strong>SubmitForm()</strong>, a konkretnie:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SubmitForm(Form1)
</code></pre></div></div>
<p><img src="/assets/images/posts/2020-08-11-Microsoft-Power-Automate-Power-Apps-i-SharePoint-Online/Image3.jpg" alt="SubmitForm" /></p>
<p>Poniżej wideo pokazujące jak wygląda ów proces w praktyce.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/FvimHu0oBxk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<p>Jak widać, w podstawowym scenariuszu wszytko idzie “jak po maśle”.
Niemniej, jak wiadomo, życie i realne przypadki potrafią płatać figla.
Bo wyobraźmy sobie scenariusz, gdzie osoba przesyłająca plik w taki właśnie sposób, ma bardzo słabe połączenie internetowe (niski Upload), a plik do wysłania znacznych rozmiarów (w chwili pisania ów posta, jest to maksymalnie 50MB).
Pytanie - co się wydarzy?</p>
<h3 id="4-problemy-z-załącznikami">4. Problemy z załącznikami</h3>
<p>Otóż z moich obserwacji i testów wynika, że dodając nowy wpis wraz z załącznikiem z poziomu portalu SPO wszystko działa tak jak powinno - Automate uruchamia się po zakończeniu przesyłania.</p>
<p><img src="/assets/images/posts/2020-08-11-Microsoft-Power-Automate-Power-Apps-i-SharePoint-Online/Image4.jpg" alt="SubmitForm" /></p>
<p>Natomiast z poziomu PowerApps funkcja <em>SubmitForm()</em> tworzy obiekt na liście niemal natychmiast, a następnie dosyła nasz załącznik. Tej akcji “nie widzimy” z poziomu portalu bo dzieje się “pod spodem”, a my cały czas widzimy okienko dodawania elementu do czasu przesłania załączników.
Zatem zdarzyć się może, że nasza Automatyzacja wystartuje jeszcze przed ostatecznym zapisaniem załącznika na liście.</p>
<p>Widać to na zrzucie poniżej - wartości Utworzony i Zmodyfikowane są jednakowe, bo mój załącznik cały czas się wysyłał, a przepływ został mimo to uruchomiony.
<img src="/assets/images/posts/2020-08-11-Microsoft-Power-Automate-Power-Apps-i-SharePoint-Online/Image5.jpg" alt="SubmitForm" /></p>
<p>Zobaczmy to na filmie.</p>
<p class="notice--info"><strong>Parametry testowe:</strong> W celu symulacji problemów z prędkością wysyłania ograniczyłem mój upload do 1Mbps</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/iH6fU-mlMIo" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<p>Jak widać na wideo, scenariusz z automatycznym wyzwalaniem automatyzacji nie do końca się sprawdza.
Oczywiście można by tu dodać jakiś <strong><a href="https://docs.microsoft.com/en-us/azure/connectors/connectors-native-delay?WT.mc_id=AZ-MVP-5001765">Delay</a></strong>, ale w sumie to nie wiemy ile czasu wystarczy. Nie możemy też czekać np. godziny - bo wtedy użytkownik czekałby tą godzinę na adres do załącznika. Można też spróbować skorzystać z <em>Trigger Conditions</em>, dzięki którym możemy sprawdzić czy załącznik jest, czy też go nie ma wykorzystując do tego funkcję <strong><a href="https://docs.microsoft.com/en-us/power-automate/use-expressions-in-conditions#use-the-empty-expression?WT.mc_id=M365-MVP-5001765">empty</a></strong>. I muszę przyznać, że faktycznie to działa… niemniej w przypadku braku załącznika, nasz przepływ w ogóle się nie uruchomi - zatem nie jest to to, czego potrzebujemy.</p>
<p class="notice--warning">Po napisaniu wpisu zauważyłem, że w moich testach pominąłem scenariusz “Wysyłanie dużego załącznika przez Portal z ograniczonym internetem”. Niemniej, do dalszej części wpisu ten scenariusz nie jest niezbędny.</p>
<h3 id="5-rozwiązanie">5. Rozwiązanie</h3>
<p>Jak wywnioskować można z powyższych testów, wyzwolenie przepływu nie może odbyć się automatycznie po utworzeniu wpisu na Liście.
Należy zatem wyzwolić taki przepływ z samej aplikacji.
Problem jaki tu się pojawia jest następujący - skąd będę wiedział, który element listy sprawdzić pod względem załącznika?
Na szczęście i na to jest sposób :)
Po krótkich poszukiwaniach można natrafić na jedną z ciekawych właściwości obiektu <em>Form</em>, a mianowicie parametr <strong><form_name>.LastSubmit</strong>.
Dzięki niemu możemy “wyciągnąć” informacje o ostatnim przesłanym elemencie na Liście.
Zobaczmy poniższe wideo:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/paJXz9mzmOM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<p>Już prawie jesteśmy w domu. Po utworzeniu elementu otrzymujemy informacje o nim, a w tym również unikalny identyfikator obiektu.
Posiadając ów identyfikator możemy przekazać go z PowerApps do Power Automate wykorzystując możliwość uruchomienia przepływu bezpośrednio z aplikacji.
W tym celu zamieniamy w istniejącym przepływie trigger z SharePoint na PowerApps.
A następnie dodajemy akcję uruchomienia tegoż przepływu po zakończeniu przesyłania załącznika.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>If(
SubmitForm(Form1),
'Nazwa_Przepływu'.Run(Value(Form1.LastSubmit.'Identyfikator (ID)'))
)
</code></pre></div></div>
<p class="notice--warning">Warto tu zwrócić uwagę na wykorzystanie funkcji <strong><a href="https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/functions/function-value?WT.mc_id=M365-MVP-5001765">Value</a></strong>, która to zamienia typ <em>Text</em> na <em>Number</em>. W przypadku jej pominięcia, otrzymalibyśmy informację o błędzie, gdyż akcja <em>Get Item</em> wymaga Identyfikatora elementu, który jest liczbą.</p>
<p>Poniżej cały proces na wideo.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/aCVjK4ZJb2A" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<p>Mając już działające rozwiązanie, które “czeka” na zakończenie przesyłania załącznika wystarczy rozbudować nasz przepływ o akcję “<em>Wyślij email</em>” wraz z adresem do załącznika wykorzystując do tego np. connector <strong><a href="https://docs.microsoft.com/en-us/connectors/smtp/#send-email-(v3)?WT.mc_id=AZ-MVP-5001765">SMTP</a></strong>.</p>
<h3 id="6-podsumowanie">6. Podsumowanie</h3>
<p>Jak widać, “ready to use” rozwiązania podstawiane nam niemal na tacy przez platformę nie zawsze muszą spełnić nasze wymagania. Warto więc rozpisać możliwie dokładnie tzw. User Stories i wypunktować możliwe problemy. Dzięki temu można uniknąć “dużego” przemodelowania logiki aplikacji w przyszłości ;)</p>Emil WasilewskiW ostatnim czasie miałem okazję pracować trochę z PowerApps. Scenariusz jaki przyszło mi obsłużyć zakładał wrzucanie plików wraz z kilkoma informacjami do Listy w SharePoint Online. Aby ograniczyć bezpośredni dostęp do SharePoint Online użytkownikom końcowym, postanowiłem jako interfejs “wejściowy” wykorzystać aplikację stworzoną w PowerApps. Po pomyślnym umieszczeniu pliku na liście, użytkownik miał otrzymywać wiadomość e-mail wraz z wprowadzonymi przezeń informacjami, w tym także bezpośredni link do załącznika.Azure Resource Graph - przydatne kwerendy2020-06-25T00:00:00+02:002020-06-25T00:00:00+02:00http://zapytajemila.pl/blog/Azure-Resource-Graph-przydatne-kwerendy<p>Poniżej znajdziesz wpisy z mojego gist’a, w którym umieszczam ku pamięci przydatne zapytania do <a href="https://docs.microsoft.com/en-us/azure/governance/resource-graph?WT.mc_id=AZ-MVP-5001765">Azure Resource Graph’a</a>.</p>
<script src="https://gist.github.com/eklime/a43ba2fd5b6e2e525d65892a132f33d5.js"></script>Emil WasilewskiPoniżej znajdziesz wpisy z mojego gist’a, w którym umieszczam ku pamięci przydatne zapytania do Azure Resource Graph’a.Nowy kanał na YouTube2018-01-25T00:00:00+01:002018-01-25T00:00:00+01:00http://zapytajemila.pl/blog/nowy-kanal-yt<p>Ni z tego ni z owego razem z Markiem Grabarzem i Michałem Smereczyńskim wpadliśmy na pomysł odpalenia kanału na YouTube. Tematyka oczywiście około azurowa. Rozmawiać będziemy o codziennych naszych poczynaniach z platformą. Forma dość luźna, bez ściemy. Stąd też nazwa kanału <a href="https://www.youtube.com/c/AzureBezSciemy"><em>“ABŚ - Azure Bez Ściemy”</em></a>.</p>
<p>Zapraszam do obejrzenia pierwszego odcinka wprowadzającego. Kolejne już wkrótce.</p>
<!-- Courtesy of embedresponsively.com //-->
<div class="responsive-video-container">
<iframe src="https://www.youtube-nocookie.com/embed/_M4JlsgL5_A" frameborder="0" allowfullscreen=""></iframe>
</div>Emil WasilewskiNi z tego ni z owego razem z Markiem Grabarzem i Michałem Smereczyńskim wpadliśmy na pomysł odpalenia kanału na YouTube. Tematyka oczywiście około azurowa. Rozmawiać będziemy o codziennych naszych poczynaniach z platformą. Forma dość luźna, bez ściemy. Stąd też nazwa kanału “ABŚ - Azure Bez Ściemy”.Eksport danych z Active Directory do pliku CSV2015-09-09T08:00:00+02:002015-09-09T08:00:00+02:00http://zapytajemila.pl/blog/eksport-danych-z-active-directory-do-pliku-csv<h2 id="problem">Problem</h2>
<p>Środowisko klienta składa się m.in. z kontrolerów domeny opartych o Windows Server 2008 R2, serwerów Exchange 2013, SharePoint 2013, Lync 2013.
Struktura organizacyjna w AD nie jest mocno skomplikowana, niemniej jednak konta użytkowników zostały umieszczone w jednostkach organizacyjnych (Organizational Unit) odpowiadających fizycznej przynależności do odpowiednich wydziałów.
<!--more--></p>
<p>Liczba kont użytkowników – ok 600
Osoba odpowiedzialna za zarządzanie zasobami IT otrzymała polecenie dostarczenia pliku CSV z bieżącymi informacjami o użytkownikach.
Wraz z poleceniem otrzymała ona przykładowy plik CSV. Zawierał on m.in takie pola jak:</p>
<p class="notice--info">objectClass, cn, description, distinguishedName, sAMAccountName, displayName, givenName, sn, title, Office, telephoneNumber, department, company, mail, manager</p>
<p>Logicznym i w zasadzie pierwszym, które przychodzi na myśl rozwiązaniem było wykorzystanie do tego celu PowerShell.
Sprawa nie była w prawdzie “na wczoraj” ale była dość priorytetowa, a ów osoba nie czuła się za dobrze w “niebieskiej konsoli”.</p>
<h2 id="rozwiązanie">Rozwiązanie</h2>
<p>I w tym właśnie momencie rozbrzmiał dzwonek w mej komórce i po krótkim wprowadzeniu oraz otrzymaniu wzorcowego pliku CSV zabrałem się do pracy.
W wyniku wysłałem mniej więcej takie polecenie:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">Get-ADuser</span><span class="w"> </span><span class="nt">-Filter</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nt">-SearchBase</span><span class="w"> </span><span class="s2">"DC=ad,DC=zapytajemila,DC=pl"</span><span class="w"> </span><span class="nt">-Properties</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="o">|</span><span class="nf">select</span><span class="w"> </span><span class="nx">objectClass</span><span class="p">,</span><span class="w"> </span><span class="nx">cn</span><span class="p">,</span><span class="w"> </span><span class="nx">description</span><span class="p">,</span><span class="w"> </span><span class="nx">distinguishedName</span><span class="p">,</span><span class="w"> </span><span class="nx">sAMAccountName</span><span class="p">,</span><span class="w"> </span><span class="nx">displayName</span><span class="p">,</span><span class="w"> </span><span class="nx">givenName</span><span class="p">,</span><span class="w"> </span><span class="nx">sn</span><span class="p">,</span><span class="w"> </span><span class="nx">title</span><span class="p">,</span><span class="w"> </span><span class="nx">Office</span><span class="p">,</span><span class="w"> </span><span class="nx">telephoneNumber</span><span class="p">,</span><span class="w"> </span><span class="nx">department</span><span class="p">,</span><span class="w"> </span><span class="nx">company</span><span class="p">,</span><span class="w"> </span><span class="nx">mail</span><span class="p">,</span><span class="w"> </span><span class="nx">manager</span><span class="w"> </span><span class="o">|</span><span class="nf">Export-Csv</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nx">C:\Temp\users.csv</span><span class="w"> </span><span class="nt">-NoTypeInformation</span><span class="w"> </span><span class="nt">-Delimiter</span><span class="w"> </span><span class="s2">";"</span><span class="w"> </span><span class="nt">-Encoding</span><span class="w"> </span><span class="nx">UTF8</span><span class="w">
</span></code></pre></div></div>
<p>Powyższe polecenie realizujące to zadanie mieści się w jednej linijce zatem jest tzw. One-Linerem. Jednak wytrawne oko zauważy i zarzucić mi może, że powyższe polecenie jest DOŚĆ NIEWYDAJNE. No cóż, zgadzam się z tym i dlatego za chwilę pokażę skąd wzięły się poszczególne polecenia i jak finalnie można zapisać powyższe polecenie aby działało znacznie wydajniej.</p>
<h3 id="środowisko-testowe">Środowisko testowe</h3>
<p>Wprawdzie środowisko Klienta posiadało w okolicach 600 kont, ja do celów testowych i aby dosadniej pokazać niuanse w sposobie wykonywania poleceń PowerShell przygotowałem środowisko Active Directory z ponad 21 000 użytkowników.</p>
<p><em>obrazek przepadł podczas migracji</em></p>
<h3 id="moduł-powershell--activedirectory">Moduł PowerShell – ActiveDirectory</h3>
<p>Jako, że informacje chcemy pozyskać z Active Directory musimy skorzystać z odpowiednich komend. Znajdują się one w module PowerShell o nazwie ActiveDirectory.
W Windows Server 2008 R2 import odpowiednich modułów należy wymusić ręcznie, zatem w konsoli PowerShell należy wpisać:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">Import-Module</span><span class="w"> </span><span class="nx">ActiveDirectory</span><span class="w">
</span></code></pre></div></div>
<h3 id="pobieranie-informacji-z-active-directory---get-aduser">Pobieranie informacji z Active Directory - Get-ADUser</h3>
<p>Aby uzyskać informacje o użytkownikach w Active Directory należy wykorzystać cmdlet o nazwie <a href="https://docs.microsoft.com/en-us/powershell/module/addsadministration/get-aduser"><strong>Get-ADUser</strong></a>.
Aby podejrzeć co zwraca takie polecenie można napisać polecenie:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">Get-ADUser</span><span class="w"> </span><span class="err">–</span><span class="nx">Identity</span><span class="w"> </span><span class="nx">emilwasilewski</span><span class="w">
</span></code></pre></div></div>
<p>Powyższe polecenie zwróci nam podstawowe informacje o konkretnym użytkowniku:</p>
<p><em>obrazek przepadł podczas migracji</em></p>
<p>Jak widać, wynik ten nie zwraca nam m.in. takich informacji jak adres e-mail, numer telefonu czy opis użytkownika.
Sprawdźmy zatem jak zachowa się polecenie:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="nf">Get-ADUser</span><span class="w"> </span><span class="nt">-Identity</span><span class="w"> </span><span class="nx">emilwasilewski</span><span class="w"> </span><span class="o">|</span><span class="nf">select</span><span class="w"> </span><span class="nx">name</span><span class="p">,</span><span class="nx">mail</span><span class="p">,</span><span class="nx">telephoneNumber</span><span class="p">,</span><span class="nx">Description</span><span class="w">
</span></code></pre></div></div>
<p>W teorii powinniśmy ujrzeć wynik w którym uzyskamy informacje o adresie email, numerze telefonu i opisie użytkownika emilwasilewski.
Jednak rzeczywistość jest inna i w takim zapisie wynik będzie wyglądał następująco:</p>
<p><em>obrazek przepadł podczas migracji</em></p>
<p>Jak zatem zapisać tą komendę aby jednak uzyskać te informacje?
Otóż najprostszym rozwiązaniem jest najpierw pobranie do pamięci wszystkich właściwości użytkownika poprzez wykorzystanie parametru -<em>*Properties **</em> a następnie wyselekcjonowanie ich w następnym kroku:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="nf">Get-ADUser</span><span class="w"> </span><span class="nt">-Identity</span><span class="w"> </span><span class="nx">emilwasilewski</span><span class="w"> </span><span class="err">–</span><span class="nx">Properties</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="o">|</span><span class="nf">select</span><span class="w"> </span><span class="nx">name</span><span class="p">,</span><span class="nx">mail</span><span class="p">,</span><span class="nx">telephoneNumber</span><span class="p">,</span><span class="nx">Description</span><span class="w">
</span></code></pre></div></div>
<p>I jak widać, pożądane przez nas informacje pojawiły się:
<em>obrazek przepadł przy migracji</em></p>
<p>Aby uzyskać takie informacje o wszystkich użytkownikach w AD parametr -<strong>Identity</strong> należy zamienić parametrem -<strong>Filter *:</strong></p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">Get-ADUser</span><span class="w"> </span><span class="nt">-Filter</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nt">-Properties</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="o">|</span><span class="nf">select</span><span class="w"> </span><span class="nx">name</span><span class="p">,</span><span class="nx">mail</span><span class="p">,</span><span class="nx">telephoneNumber</span><span class="p">,</span><span class="nx">Description</span><span class="w">
</span></code></pre></div></div>
<p>I wynik tego zapytania będzie wyglądał mniej więcej tak:
<em>obrazek przepadł przy migracji</em></p>
<p>Myślę, że na chwilę obecną taka postać polecenia nam wystarczy.
Otrzymaliśmy listę wszystkich użytkowników w Active Directory oraz wylistowaliśmy ich trzy parametry.
Do optymalizacji tej części polecenia jeszcze wrócimy a tymczasem przejdźmy do eksportu danych do pliku CSV.</p>
<h3 id="eksport-do-csv">Eksport do CSV</h3>
<p>Wynik polecenia w PowerShell, który widzimy w naszej konsoli możemy przekierować w inne miejsce.
Może to plik tekstowy, plik CSV, czy też tzw. /dev/null (Out-Null).
W rozpatrywanym problemie wynik zapytania miał się znaleźć w pliku CSV. Zatem wykorzystać musimy cmdlet <a href="https://docs.microsoft.com/en-gb/powershell/module/microsoft.powershell.utility/export-csv"><strong>Export-CSV</strong></a>.
W wysłanym poleceniu użyłem składni:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="err">…</span><span class="w"> </span><span class="o">|</span><span class="nf">Export-Csv</span><span class="w"> </span><span class="nt">-Path</span><span class="w"> </span><span class="nx">C:\Temp\users.csv</span><span class="w"> </span><span class="nt">-NoTypeInformation</span><span class="w"> </span><span class="nt">-Delimiter</span><span class="w"> </span><span class="s2">";"</span><span class="w"> </span><span class="nt">-Encoding</span><span class="w"> </span><span class="nx">UTF8</span><span class="w">
</span></code></pre></div></div>
<p>Oto wytłumaczenie:</p>
<ul>
<li>Path – lokalizacja pliku wynikowego</li>
<li>NoTypeInformation – parametr skutkuje brakiem dodawania informacji w postaci “#TYPE Selected.Microsoft.ActiveDirectory.Management.ADUser” na początku pliku</li>
<li>Delimeter – wskazujemy jaki znak oddzielający poszczególne kolumny ma zostać zastosowany. Przydatne w szczególności wyników z AD, gdzie domyślnym przecinkiem oddzielane są m.in. informacje o ścieżce do obiektu</li>
<li>Encoding – wskazanie jakie kodowanie ma zostać użyte podczas eksportu</li>
</ul>
<h3 id="testy-wydajności-i-optymalizacja-polecenia">Testy wydajności i optymalizacja polecenia</h3>
<p>Teraz, gdy już wiemy jak uzyskać informacje z Active Directory oraz jak je wyeksportować do pliku wynikowego CSV, przyszedł czas na optymalizację zapytania.
Pomoże nam w tym kilka testów wydajności. Aby przeprowadzić takie testy mamy dwie możliwości. Pierwsza to wyposażyć się w stoper i mierzyć czas od naciśnięcia klawisza ENTER do pojawienia się wyniku na ekranie.
Drugim i w tym przypadku preferowanym sposobem mierzenia czasów wykonania zapytania jest wykorzystanie komendy <a href="https://docs.microsoft.com/en-gb/powershell/module/microsoft.powershell.utility/measure-command"><strong>Measure-Command</strong></a>.
Zatem do dzieła!
Na początek znane już polecenie wyświetlenia podstawowych informacji o użytkowniku emilwasilewski</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">Measure-Command</span><span class="w"> </span><span class="nt">-Expression</span><span class="w"> </span><span class="p">{</span><span class="nf">Get-ADUser</span><span class="w"> </span><span class="nt">-Identity</span><span class="w"> </span><span class="nx">emilwasilewski</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Wynik:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Jednostka</th>
<th style="text-align: left">Liczba</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">Minutes </td>
<td style="text-align: left">0</td>
</tr>
<tr>
<td style="text-align: left">Seconds </td>
<td style="text-align: left">0</td>
</tr>
<tr>
<td style="text-align: left"><strong>Milliseconds</strong> </td>
<td style="text-align: left"><strong>6</strong></td>
</tr>
<tr>
<td style="text-align: left">Ticks </td>
<td style="text-align: left">66181</td>
</tr>
</tbody>
</table>
<p>Sześć milisekund.</p>
<p>A teraz polecenie z parametrem –<em>*Properties **</em>:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">Measure-Command</span><span class="w"> </span><span class="nt">-Expression</span><span class="w"> </span><span class="p">{</span><span class="nf">Get-ADUser</span><span class="w"> </span><span class="nt">-Identity</span><span class="w"> </span><span class="nx">emilwasilewski</span><span class="w"> </span><span class="err">–</span><span class="nx">Properties</span><span class="w"> </span><span class="o">*</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Wynik:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Jednostka</th>
<th style="text-align: left">Liczba</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">Minutes </td>
<td style="text-align: left">0</td>
</tr>
<tr>
<td style="text-align: left">Seconds </td>
<td style="text-align: left">0</td>
</tr>
<tr>
<td style="text-align: left"><strong>Milliseconds</strong> </td>
<td style="text-align: left"><strong>9</strong></td>
</tr>
<tr>
<td style="text-align: left">Ticks </td>
<td style="text-align: left">94933</td>
</tr>
</tbody>
</table>
<p>Dziewięć milisekund. Niby niewielka różnica ale jednak.
Sprawdźmy zatem polecenie:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">Measure-Command</span><span class="w"> </span><span class="nt">-Expression</span><span class="w"> </span><span class="p">{</span><span class="nf">Get-ADUser</span><span class="w"> </span><span class="nt">-Filter</span><span class="w"> </span><span class="o">*</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Wynik na ponad 21 tysiącach użytkowników:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Jednostka</th>
<th style="text-align: left">Liczba</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">Minutes </td>
<td style="text-align: left">0</td>
</tr>
<tr>
<td style="text-align: left">Seconds </td>
<td style="text-align: left">0</td>
</tr>
<tr>
<td style="text-align: left"><strong>Seconds</strong> </td>
<td style="text-align: left"><strong>7</strong></td>
</tr>
<tr>
<td style="text-align: left"><strong>Milliseconds</strong> </td>
<td style="text-align: left"><strong>371</strong></td>
</tr>
<tr>
<td style="text-align: left">Ticks </td>
<td style="text-align: left">73719667</td>
</tr>
</tbody>
</table>
<p>Siedem sekund, całkiem nieźle. Zatem sprawdzamy efekt dodania parametru –<em>*Properties **</em>:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Jednostka</th>
<th style="text-align: left">Liczba</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><strong>Minutes</strong> </td>
<td style="text-align: left"><strong>1</strong></td>
</tr>
<tr>
<td style="text-align: left"><strong>Seconds</strong> </td>
<td style="text-align: left"><strong>12</strong></td>
</tr>
<tr>
<td style="text-align: left"><strong>Milliseconds</strong> </td>
<td style="text-align: left"><strong>4</strong></td>
</tr>
<tr>
<td style="text-align: left">Ticks </td>
<td style="text-align: left">720048243</td>
</tr>
</tbody>
</table>
<p>Hmm… ponad jedna minuta, to prawie dziewięciokrotnie dłużej niż poprzednia komenda.
Dobrze, dodajmy filtr ograniczający nam zakres poszukiwań do konkretnego OU. Jak pamiętamy, Klient konta pracowników umieścił w uporządkowanym drzewie OU.
Zatem lekko zoptymalizowane polecenie będzie wyglądać następująco:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">Measure-Command</span><span class="w"> </span><span class="nt">-Expression</span><span class="w"> </span><span class="p">{</span><span class="nf">Get-ADUser</span><span class="w"> </span><span class="nt">-Filter</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nt">-SearchBase</span><span class="w"> </span><span class="s2">"OU=People,DC=AD,DC=zapytajemila,DC=pl"</span><span class="p">;</span><span class="w"> </span><span class="nt">-Properties</span><span class="w"> </span><span class="o">*</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Wynik:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Jednostka</th>
<th style="text-align: left">Liczba</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left"><strong>Minutes</strong> </td>
<td style="text-align: left"><strong>1</strong></td>
</tr>
<tr>
<td style="text-align: left"><strong>Seconds</strong> </td>
<td style="text-align: left"><strong>11</strong></td>
</tr>
<tr>
<td style="text-align: left"><strong>Milliseconds</strong> </td>
<td style="text-align: left"><strong>376</strong></td>
</tr>
<tr>
<td style="text-align: left">Ticks </td>
<td style="text-align: left">713768204</td>
</tr>
</tbody>
</table>
<p>Jak widać wynik jest bardzo zbliżony do poprzedniego. W moim przypadku, gdzie różnica w ilości użytkowników globalnie a w tym konkretnym OU jest niewielka, ten zapis nie daje mi znacznej poprawy wydajności, ale warto go stosować.
Jak jeszcze bardziej można zoptymalizować powyższe zapytanie? A no można, czego przyznaję ja nie zrobiłem przygotowując polecenie Klientowi.
Mianowicie, mamy określony docelowy wynik naszego zapytania, wiemy jakich informacji potrzebujemy o użytkownikach.
Zatem zapis <strong>–Properties *</strong> powinniśmy zastąpić –<strong>Properties Name,mail,telephoneNumber,Description</strong>. Sprawdźmy:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">Measure-Command</span><span class="w"> </span><span class="nt">-Expression</span><span class="w"> </span><span class="p">{</span><span class="nf">Get-ADUser</span><span class="w"> </span><span class="nt">-Filter</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nt">-SearchBase</span><span class="w"> </span><span class="s2">"OU=People,DC=AD,DC=zapytajemila,DC=pl"</span><span class="w"> </span><span class="nt">-Properties</span><span class="w"> </span><span class="nx">name</span><span class="p">,</span><span class="nx">mail</span><span class="p">,</span><span class="nx">telephoneNumber</span><span class="p">,</span><span class="nx">Description</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Wynik:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Jednostka</th>
<th style="text-align: left">Liczba</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">Minutes</td>
<td style="text-align: left">0</td>
</tr>
<tr>
<td style="text-align: left"><strong>Seconds</strong> </td>
<td style="text-align: left"><strong>7</strong></td>
</tr>
<tr>
<td style="text-align: left"><strong>Milliseconds</strong> </td>
<td style="text-align: left"><strong>925</strong></td>
</tr>
<tr>
<td style="text-align: left">Ticks </td>
<td style="text-align: left">79252197</td>
</tr>
</tbody>
</table>
<p>WoooW, no i to jest optymalizacja!
No to jeszcze na koniec pomiar czasu wykonania całego polecenia bez i z optymalizacją:
Polecenie z początku tego wpisu osiągnęło wynik:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Jednostka</th>
<th style="text-align: left">Liczba</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">Minutes </td>
<td style="text-align: left">1</td>
</tr>
<tr>
<td style="text-align: left"><strong>Seconds</strong> </td>
<td style="text-align: left"><strong>23</strong></td>
</tr>
<tr>
<td style="text-align: left"><strong>Milliseconds</strong> </td>
<td style="text-align: left"><strong>480</strong></td>
</tr>
<tr>
<td style="text-align: left">Ticks </td>
<td style="text-align: left">834806914</td>
</tr>
</tbody>
</table>
<p>A zoptymalizowane zapytanie ze zdeklarowanymi właściwościami użytkownika do “wyciągnięcia” wykonało się w:</p>
<table>
<thead>
<tr>
<th style="text-align: left">Jednostka</th>
<th style="text-align: left">Liczba</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">Minutes </td>
<td style="text-align: left">0</td>
</tr>
<tr>
<td style="text-align: left"><strong>Seconds</strong> </td>
<td style="text-align: left"><strong>18</strong></td>
</tr>
<tr>
<td style="text-align: left"><strong>Milliseconds</strong></td>
<td style="text-align: left"><strong>251</strong></td>
</tr>
<tr>
<td style="text-align: left">Ticks </td>
<td style="text-align: left">182512315</td>
</tr>
</tbody>
</table>
<p>Czyli ponad <strong>4,5 razy szybciej</strong> niż zapytanie nie zoptymalizowane.
Plik wynikowy w moim środowisku testowym wyszedł o tak:</p>
<p><em>obrazek przepadł podczas migracji</em></p>
<h2 id="podsumowanie">Podsumowanie</h2>
<p>Jak widać nawet z pozoru niewielkie zmiany mogą w znaczącym stopniu poprawić działanie naszych skryptów.
Warto też pamiętać, że PowerShell podczas pracy wykorzystuje pamięć RAM do zapisu zbieranych informacji.
Aby uzyskać wynik zapytania niezoptymalizowanego proces powershell.exe potrzebował ponad 675 MB RAM.
Zapytanie zoptymalizowane wymagało już tylko 92,7 MB RAM, gdzie sama konsola PowerShell po starcie zabiera w moim przypadku 57,8 MB RAM!</p>Emil WasilewskiProblem Środowisko klienta składa się m.in. z kontrolerów domeny opartych o Windows Server 2008 R2, serwerów Exchange 2013, SharePoint 2013, Lync 2013. Struktura organizacyjna w AD nie jest mocno skomplikowana, niemniej jednak konta użytkowników zostały umieszczone w jednostkach organizacyjnych (Organizational Unit) odpowiadających fizycznej przynależności do odpowiednich wydziałów.