Category: Skrypty
40-tka wybiła, a jutro świętowanie ROCZNICY
| 2012-05-07 | Posted by Zygmunt B. under Polskie blogi IT, Relacje, Skrypty, WGUiSW |
|
To już miesiąc, jak stuknęła nam 40. !!!
A już jutro świętowanie. Oczywiście nie tej minionej 40, lecz 4 rocznicy powstania Grupy. Jeśli śledzicie informacje na stronie WGUiSW i Facebooku, to wiecie już, że z pewnością będzie ciekawie. Mnie niestety nie będzie
( Liczę więc, że znajdą się osoby z aparatem, by uwiecznić to ważne dla nas wydarzenie, a może nawet zechce napisać kilka słów relacji dla grupy?
Wróćmy jednak na razie do naszej czterdziestki. Spotkaniem kierował tym razem Łukasz Matuszewski. Program spotkania to… PowerShell, kontrola rodzicielska w wykonaniu Błażeja oraz…. NAGRODY, czyli podsumowanie cyklu Środy z certyfikatem. (agenda na stronie…)
PowerShell w dwóch podejściach. Najpierw Grzesiu Gałęzowski opowiadał o… gumowej kaczuszce
A poważniej pokazał nam, że PowerShell może służyć np. do komponowania muzyki
Co prawda osobiście wolę jednak muzykę z płyty CD (a przynajmniej porządnego – czyt. wysokiej jakości – mp3), ale wrażenie robi. Aż zaczynam się bać otwierać lodówkę, bo… jeszcze tam zobaczę PowerShella
)
Niestety nie wszystko się udało Grzesiowi pokazać, gdyż dopadł nas problem z Internetem
– tak bywa.
Po przerwie w konkury PowerShellowe stanął sam MVP w tym temacie – Bartosz Bielawski. Bartosz pokazał nam, że z kolejną wersją PowerShella możemy zrobić więcej, a przy tym łatwiej. Bardzo ciekawy wykład, w czasie którego namawiał między innymi do uczestnictwa w ScriptGames – coś w tym jest. Nie od dziś wiadomo, że najlepiej, najsprawniej się uczy wtedy, gdy mamy konkretne zadania do wykonania. Do tego zdrowa rywalizacja…. i w efekcie, jak twierdzi Bartosz, można zostać nawet MVP (podobno nie tak dawno nie przyszłoby mu do głowy, że jest to możliwe)
Tak zakończyła się przygoda z PowerShellem, ale oczywiście tylko w trakcie tego spotkania. Od dawna widać, że nie ma od niego ucieczki (tak jak od chmur)
Po kolejnej przerwie Błażej opowiedział jak być dobrym rodzicem. Bo dobry rodzic jednak kontroluje do czego jego dziecko ma dostęp np. w Internecie. Coraz więcej rodziców chce to robić – a nie wszyscy mają przecież przygotowanie informatyczne. Dlatego fajnie, że np. Windows 7, czy Windows 8 mają wbudowane mechanizmy znacznie ułatwiające taką kontrolę.
Okazuje się, że również producenci oprogramowania typu “antywirus” wprowadzają takie możliwości w swoich pakietach. Wprowadzają, bo badania wyraźnie wskazują, że klienci tego chcą. Błażej zapowiedział, że on na pewno będzie to robił
)
Na koniec… podsumowanie prowadzonego przez Pawła Pławiaka cyklu “Środy z certyfikatem”. Poza statystyką (ilość spotkań, uczestników….) był też czas na nagrody. I tu okazało się, że (wow!!!) nagród jest więcej niż uczestniczących w losowaniu. Otóż wymóg w pełni poprawnych odpowiedzi z przynajmniej 6 spotkań, sprawił, że nikt nie odszedł bez nagrody. Fajnie, nie?
Nagrody oczywiście losowała nasza Śnieżynka.
Było naprawdę fajnie, a przy tym zabawnie.
Na koniec pozostaje mi zaprosić (jeśli ktoś jeszcze ich nie widział) do obejrzenia galerii zdjęć z tego spotkania. I oczywiście na jutrzejsze ŚWIĘTOWANIE!
Tagged: PowerShell, relacje, WGUiSW
![]()
Problem z instalacją AdventureWorks2008R2 OLTP w SQL Server 2008R2 na WinXP SP3
| 2012-05-05 | Posted by Dariusz Brejnak under Polskie blogi IT, Skrypty |
|
Podczas instalacji skryptu dla bazy AdventureWorks2008R2 OLTP instalowanego na SQL Server 2008R2 w systemie Windows XP SP3 uzyskujemy błąd:
„Operating system error -2147024891: „0×80070005 filestream”
W internecie można znaleźć kilka różnych opisów tego problemu. Poniżej przedstawiam jedno z działających rozwiązań.
Generalnie chodzi o to, że MS SQL Server 2008 R2 uruchomiony jest z poświadczeniami konta wbudowanego:
NT AUTHORITY\NETWORK SERVICE i nie ma wtedy odpowiednich
uprawnień do założenia folderu z FILESTREAM podczas zakładania bazy.
Uzyskujemy wtedy taki komunikat:
"Below is the error using C:\Data STREAMFCB::Startup: Operating system error 0x80070005(Access is denied.) occurred while creating or opening file 'c:\data\filestreamP1'. Diagnose and correct the operating system error, and retry the operation."
Jedną z rad jest odinstalowanie „Aktualizacji zabezpieczeń systemu Windows KB956572„.
Ale co gdy nie mamy zainstalowanej łatki lub odinstalowanie nie pomaga ?
Ja na serwerze zatrzymałem usługę „SQL SERVER” oraz „SQL Full-Text Filter Daemon Launcher” a następnie
uruchomiłem ją z logując się kontem wbudowanym jako LocalSystem.
Instalacja przebiegła prawidłowo.
Podsumowując należy:
- Uruchomić SQL Server Configuration Manager
- W SQL Server Services wybrać:
- SQL Server. Kliknąć ppm wybrać properties. Po otwarciu okna w Built-in-account ustawić LocalSystem.
- Kliknąć na OK. Wtedy nastąpi restart.
- SQL Full-Text Filter Daemon Launcher. Po otwarciu okna w Built-in-account ustawić LocalSystem.
- Kliknąć na OK. Wtedy nastąpi restart.
PowerShell – formatowanie daty, a dodatkowe operacje
| 2012-03-08 | Posted by JeZZoo under Get-Date, Polskie blogi IT, Skrypty |
|
PowerShell ma tę niewdzięczną wadę, że jeśli sformatujemy sobie Get-Date za pomocą parametrów -format albo -uformat to na wyjściu nie otrzymamy już obiektu typu data ale string. Jeśli chodzi o operacje na takim obiekcie to tracimy w tym momencie jakiekolwiek związane … Czytaj dalej
Diagnostyka WMI
| 2012-02-06 | Posted by TechNet Polska under Grzegorz Tworek, IT Pro blogerzy, konfiguracja, Polskie blogi IT, Skrypty, Zarządzanie środowiskiem |
|
WMI (dla osób mających problem z zapamiętaniem skrótów – Windows Management Instrumentation) to potężny mechanizm, przy pomocy którego można niemal wszystko zrobić z lokalnym lub zdalnym systemem. Nie będę teraz opisywał jak wiele można zdziałać z samym WMI, zwrócę za to uwagę na fakt, że mechanizm ten często jest wykorzystywany przez aplikacje i inne rozwiązania, które chcą w jakiś sposób "mądrzej" porozmawiać z komputerem. Typowym przykładem może być program instalacyjny, który po uruchomieniu, właśnie dzięki WMI może sprawdzić, czy na serwerze działa IIS. Innym zastosowaniem jest zdalne sprawdzenie konfiguracji komputerów. Generalnie, WMI można użyć do wszystkiego. Problem pojawia się tylko wtedy, gdy mechanizmy WMI same w sobie działają niepoprawnie. Wszystko wtedy zależy od tego, na ile skutecznie aplikacja obsługuje nietypowe sytuacje i nie zdradzę chyba wielkiej tajemnicy pisząc, że zwykle robi to dość marnie…
Dlatego czasem, gdy wszystko idzie inaczej niż powinno, można sobie sprawdzić dla pewności czy nic się w mechanizmach WMI nie popsuło. Służy do tego narzędzie WMI Diagnosis Utility. Ma ono postać skryptu VBS, arkusza XLS oraz dokumentacji. Dokumentacja jest dość rzetelna (prawie 70 stron) i warto do niej zajrzeć. Do pobrania bezpłatnie z Microsoft.
Polecam do podręcznej skrzynki z narzędziami administratora. Pewnie nie przyda się dzisiaj ani jutro, za to, gdy nadejdzie jego chwila – zaoszczędzi wiele godzin walki z zupełnie nieracjonalnymi problemami.
Autor: Grzegorz Tworek [MVP]
Magia w Remote Apps
| 2011-12-22 | Posted by TechNet Polska under aplikacje, Grzegorz Tworek, IT Pro blogerzy, konfiguracja, Polskie blogi IT, Porady, serwery, Skrypty |
|
Dzisiaj będzie o konkretnym przypadku. Otóż była sobie aplikacja. Własnego wyrobu (w sensie, że firma miała dostęp do kodu, programistów itp.), absolutnie krytyczna dla biznesu i używająca CPU w sposób dość specyficzny. Otóż najważniejsze operacje bardzo mocno obciążały procesor na kilkanaście sekund, po których aplikacja była gotowa do użytku i procesora nie obciążała już tak wyraźnie przez kolejne kilka albo i kilkanaście minut. Trudno się dziwić, że pojawiła się koncepcja pilotażowego scentralizowania jej poprzez przeniesienie do usług terminalowych. Na silnym, wieloprocesorowym serwerze, mocne chwilowe obciążenia ładnie rozkładały się pomiędzy wielu użytkowników, a równocześnie czas oczekiwania na tę jedną operację znacząco się skrócił. Generalnie, wszystko działało jak trzeba, więc pojawił się pomysł, żeby pójść dalej. Zamiast udostępniać przez usługi terminalowe pełne pulpity, z Menu Start itp., lepiej przecież "wyterminalować" jedną aplikację. Poza elegancją takiego rozwiązania, Remote Apps mają ogromną zaletę, że przy porównaniu do aplikacji zainstalowanych lokalnie, nie zmienia się znacząco to, co użytkownik widzi na ekranie. W sytuacji, gdy z aplikacją pracują setki osób to ma naprawdę ogromne znaczenie, ponieważ łączny czas zaoszczędzony na szkoleniach i zmianie nawyków sumuje się do niemałej wartości.
Została przygotowana nowa platforma (całkiem spora szafa pełna serwerów) i wykonano testy. Wszystko było dobrze, choć odwlekane w nieskończoność aktualizacje ServicePacków na WindowsXP nabrały tempa, bo Remote Apps wymagało aktualizacji klienta RDP. ServicePack 3 pozwolił na normalną pracę. Po aktualizacji wyterminalowano kilka systemowych aplikacji, bo ludziom z IT łatwiej poruszać się po notepadzie, kalkulatorze czy menedżerze zadań niż po aplikacji biznesowej. Ta uruchamiała się poprawnie, więc uznano że w codziennych pracach również działa tak, jak trzeba. Było to o tyle uzasadnione, że w realiach udostępniania pełnego pulpitu pracowała już w kilku miejscach produkcyjnie i bez zastrzeżeń. Można było przejść do pilota. I tu zaczęły się schody.
Po uruchomieniu kilku instancji aplikacji przez jednego użytkownika, przy bardzo szczególnych operacjach okazywało się, że dane wpisywane w jednym oknie pojawiają się w zupełnie innym. Czysta magia. Problem był prosty do powtórzenia i dawał się dzięki temu dość prosto diagnozować. Szybko okazało się, że pojawia się tylko przy Remote Apps. Udostępnienie na tym samym serwerze całego pulpitu i uruchamianie aplikacji spod explorer.exe powodowało, że problem znikał. Po wielu godzinach dłubania w konfiguracji farmy (a tak naprawdę szukania natchnienia co by tu mogło być powodem problemów) po dyskusjach z programistami (kto programował, ten wie jak radosne może być szukanie przyczyny w takim scenariuszu) pojawiła się jeszcze jedna myśl: A co na to Windows 7? Okazało się, że w Windows 7 problem nie występuje. Dalej było już z górki, mimo że szybka zmiana systemu na stacjach klienckich nie wchodziła w grę. Wystarczyła instalacja klienta RDP 7.0 na XP (miło z jej strony, że nie wymaga restartu), testy i okazało się, że klawiatura działa tak, jak trzeba. Pozostało zautomatyzowanie instalacji (WSUS+skrypty tam, gdzie WSUS był zbyt powolny) i wykrywanie gdzie jeszcze problem istnieje. Gdyby ktoś kiedyś potrzebował się dowiedzieć o wersję klienta RDP na zdalnej stacji, to z wiersza poleceń można tak:
wmic /node:nazwakomputera datafile where "name=’c:\\windows\\system32\\mstsc.exe’" get version
Warto pamiętać o podwójnych backslashach wymaganych przez składnię WMIC.
Autor: Grzegorz Tworek [MVP]
Execution policy w Powershell x86 i x64
| 2011-11-10 | Posted by JeZZoo under ExecutionPolicy, Polskie blogi IT, Skrypty, x64, x86 |
|
Jedną z pierwszych czynności, które administrator zaprzyjaźniony już z PS wykonuje na swoim systemie to zmiana ExecutionPolicy na takie, które pozwolą wykonywać skrypty. Jakie zdziwienie było moje zdziwienie, kiedy zaraz po takiej zmianie przy próbie wykonania skryptu pojawił mi się … Czytaj dalej
PowerShell–efektywniej, część 6.
| 2011-11-06 | Posted by Bartek Bielawski under najlepsze praktyki, Początki, Polskie blogi IT, Skrypty, zaawansowane funkcje |
|
W poprzedniej części opisałem składnię, dzięki której funkcja zmienia się w funkcję zaawansowaną. Dziś skupię się na tym, co z tego wynika przy używaniu takiej funkcji.
Debug i Verbose
W wielu językach – zarówno programowania jak i skryptowych – pierwszą metodą sprawdzania co poszło nie tak jest wyświetlanie na ekran informacji, które mogą pomóc ustalić, gdzie popełniliśmy błąd. To generuje dwa problemy:
- nie usunięte komunikaty pojawiają się w najmniej odpowiednim momencie
- ponowne “włączenie” komunikatów po ich usunięciu jest niemożliwe
PowerShell ma bardzo przydatną właściwość: generuje nieco więcej strumieni niż domyślne wyjście standardowe i wyjście błędów: mamy dodatkowo ostrzeżenia, informacje rozszerzone (verbose) i komunikaty pomagające debugować (debug). Komunikaty verbose i debug można z powodzeniem pozostawić (jeśli są cenzuralne
) a w razie potrzeby – włączyć na żądanie. W funkcjach zwykłych wymagałoby to zmiany $DebugPreference i $VerbosePreference na poziomie sesji. Funkcje zaawansowane dają nam możliwość użycia po prostu jednego z parametrów: –Debug lub –Verbose. Dzięki temu automagicznie zmienia się wartość odpowiedniej zmiennej i wszystkie komunikaty pojawiają się w odpowiednich strumieniach. Dodajmy więc komunikaty dotyczące zawartości naszych parametrów:
Write-Verbose "Format: $Format" Write-Verbose "Liczba: $Liczba" Write-Verbose "Slowo: $Slowo" if ($Format) { Write-Debug "Wygląda na to, że używamy liczby." }
Begin, Process, End
Funkcja w PowerShellu może mieć trzy odseparowane części, co ułatwia zdecydowanie pracę w potokach i dzięki czemu każda funkcja może działać podobnie jak prawdziwy cmdlet (jeśli chodzi o funkcjonalność, nie o wydajność). Mamy więc:
- begin gdzie można zainicjować połączenia, zdefiniować funkcje pomocnicze, przetworzyć zmienne podawane “w linii”
- process stanowiący serce funkcji działającej w rurce: tu możemy sięgnąć do parametrów pobieranych z poprzedniej komendy i przekazać informację dalej
- end który sprząta na koniec: zabija połączenia, czyści pamięć ze zbędnych elementów
Jeśli zamierzamy korzystać tylko z parametrów podawanych w linii – nasza funkcja może mieć jedno, zbiorcze “ciało”. Jeśli jednak chcemy skorzystać z pipe’a – absolutnym minimum jest dodanie części process, pozostałe dwie pozostają wówczas opcjonalne. Begin ma sens wtedy, gdy potrzebujemy pewną operację przeprowadzić dokładnie raz na początku, a wykonywanie jej dla każdego elementu wpadającego w rurkę jest stratą czasu, czy wręcz może doprowadzić do nieoczekiwanych rezultatów. End działa podobnie – tylko operacja musi mieć miejsce dokładnie raz na końcu. Cała reszta – powinna trafić do bloku process. Zaawansowane funkcje tracą wiele jeśli pozbawimy ich tej troistości.
PSCmdlet
Zaawansowane funkcja ma jeszcze jedną wielką zaletę: w jej wnętrzu dostępna jest automatyczna zmienna ($PSCmdlet), która w zasadzie daje nam dostęp do tych samych metod i właściwości, jakie ma programista piszący cmdlet w C# lub VB.NET. Na blogu zespołu PowerShell jakiś czas temu opublikowana była prosta funkcja, która pozwala zajrzeć do wnętrza tej zmiennej, sprowadza się to właściwie do:
function Test-PSCmdlet { [CmdletBinding()] param() $p = $PSCmdlet function prompt { "Test-PSCmdlet> " } $host.EnterNestedPrompt() }
Dzięki temu możemy poeksperymentować ze zmienną $p (która jest kopią $PSCdmlet). W praktyce na ogół wykorzystuje się dwa jej elementy:
- właściwość ParameterSetName – pozwala ustalić, który zestaw parametrów jest wykorzystywany
- metody ShouldProcess i ShouldContinue – pozwalają zastosować parametry WhatIf oraz Confirm.
Ponieważ budowana przez nas zaawansowana funkcja wspiera ShouldProcess (a więc metody Shoud* będą w niej dostępne), oraz założyliśmy kilka różnych zestawów parametrów, więc wykorzystamy i jedno, i drugie:
process { if ($psCmdlet.ShouldProcess( "Cel: $Slowo $Liczba", "Operacja: Wyświetl" )) { switch ($psCmdlet.ParameterSetName) { Domyslny { "{0} to moje slowo" -f $Slowo } Liczby { "Moja liczba: {0:$Format}" -f $Liczba } } } }
Ponieważ część parametrów zamierzamy opcjonalnie pobierać z rurki – możemy do nich sięgać dopiero w bloku process. Jeśli mamy dwa zestawy parametrów na ogół wystarczy zwykły if – jeśli zestawów jest więcej, opcjonalnym rozwiązaniem może okazać się switch. Jak widać operacja przeprowadzana nie jest specjalnie niebezpieczna, ale czasem jednak funkcja napisana przez nas może nieść z sobą pewne ryzyko – warto wtedy wiedzieć jak zaimplementować parametry –WhatIf i –Confirm.
I tym optymistycznym akcentem kończę temat zaawansowanych funkcji. Jeszcze tylko nasza zaawansowana funkcja w pełnej krasie:
function Get-Foo { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High', DefaultParameterSetName = 'Domyslny' )] param ( [Parameter( Mandatory = $true, HelpMessage = 'Pomocy!', ValueFromPipeline = $true, Position = 0, ParameterSetName = 'Liczby' )] [double]$Liczba, [Parameter( Mandatory = $true, HelpMessage = 'Pomocy!', ValueFromPipelineByPropertyName = $true, Position = 0, ParameterSetName = 'Domyslny' )] [ValidatePattern('^\w+$')] [string]$Slowo, [Parameter( Position = 1, ParameterSetName = 'Liczby', Mandatory = $true, HelpMessage = 'Pomozcie mi!' )] [ValidateSet('P4','N4','C4')] [string]$Format ) begin { Write-Verbose "Format: $Format" Write-Verbose "Liczba: $Liczba" Write-Verbose "Slowo: $Slowo" if ($Format) { Write-Debug "Wygląda na to, że używamy liczby." } } process { if ($psCmdlet.ShouldProcess( "Cel: $Slowo $Liczba", "Operacja: Wyświetl" )) { switch ($psCmdlet.ParameterSetName) { Domyslny { "{0} to moje slowo" -f $Slowo } Liczby { "Moja liczba: {0:$Format}" -f $Liczba } } } } }
Następną część zamierzam poświęcić kolejnej funkcjonalności, przydatnej zarówno w funkcjach (również zaawansowanych) jak i w skryptach: pomocy generowanej w oparciu o komentarze.
PowerShell – efektywnie(j), część 5.
| 2011-10-25 | Posted by Bartek Bielawski under najlepsze praktyki, Polskie blogi IT, Skrypty, zaawansowane funkcje |
|
W wersji drugiej PowerShell został dość mocno rozbudowany o nowe możliwości: zdalne uruchamianie kodu, praca w tle, moduły… Sam język też zyskał bardzo wiele, przede wszystkim – zaawansowane funkcje. Czy może raczej: zaawansowane scriptblocki. Jest bowiem prawdą, że niezależnie od tego jak nasz blok skryptu jest zapisany: w postaci funkcji w pamięci, w postaci zmiennej typu [ScriptBlock] czy też w postaci pliku z rozszerzeniem ps1 – może on w każdej z tych postaci być zaawansowany. Tą część cyklu zamierzam poświęcić w całości temu, w czym objawia się to “zaawansowanie” i jak je wykorzystać.
Spytaj PowerShella.
Parafrazując mój ulubiony zespół punk-rockowy: “Spytaj PowerShella, on ci prawdę powie, spytaj PowerShella – on ci wskaże drogę”. W tym wypadku pytanie brzmieć powinno: get-help about_functions_advanced*, pytanie pomocnicze: get-help about_functions_CmdletBindingAttribute. Postaram się opisać najważniejsze cechy funkcji zaawansowanych w tym artykule w tym, oraz następnym artykule, ale na pewno coś mi umknie. PowerShell (przynajmniej z założenia) powinien dostarczyć nam komplet informacji. Zacznijmy więc od początku. Zbudujmy od zera zaawansowaną funkcję. Nie będzie ani troszkę funkcjonalna, ale za to bardzo, bardzo zaawansowana. ![]()
CmdletBinding
Od tego wszystko się zaczyna. PowerShell jest domyślny, więc w wielu sytuacjach ten element może się okazać zbędny. Jednak warto od niego zaczynać każdą funkcję. Nic to nie kosztuje, a daje kilka korzyści. Należy jednak pamiętać, że konstrukcja ta wymaga posiadania bloku param (może on być pusty) i może być rozbudowana o kilka opcji:
- SupportsShouldProcess – jeśli chcemy by nasza funkcja rozumiała –WhatIf i –Confirm, dopuszczalne wartości: $true, $false
- ConfirmImpact – jeśli zależy nam na tym, by pytanie o zgodę pojawiało się częściej, lub zawsze, dopuszczalne wartości: High, Medium, Low
- DefaultParameterSetName – jeśli definiujemy kilka zestawów parametrów i chcemy mieć pewność, że jeden z nich będzie używany domyślnie, dopuszczalne wartości: nazwy wszystkich użytych zestawów parametrów
W 9/10 przypadków [CmdletBinding()] w zupełności wystarczy, dobrze jednak wiedzieć, że to nie wszystko co ma do zaoferowania ta konstrukcja. Nasza funkcja oczywiście zalicza się do tych 10%, wszystko-w-sobie-mających:
function Get-Foo { [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High', DefaultParameterSetName = 'Domyslny' )] param (
Parameter
Wchodzimy do bloku definiowania parametrów i zaczynamy je zdobić. [Parameter()] to podstawa: pozwala nam zdefiniować parametry niezbędne (Mandatory), uzupełnić parametry o pomoc (HelpMessage), zdecydować czy będą “konsumować” rurkę i jak będą to robić (ValueFromPipeline, ValueFromPipelineByPropertyName), jaką pozycję mogą zajmować (Position), który zestaw parametrów opisujemy (ParameterSetName) i wreszcie – że parametr połknie całą resztą argumentów, do których nikt inny się nie przyznaje (ValueFromRemainingArguments). Należy pamiętać, że jeśli mamy kilka zestawów parametrów a opisywany parametr ma pojawiać się tylko w niektórych – to trzeba to wyraźnie zdefiniować (kilka bloków [Parameter()]). Jeśli parametr pojawia się wszędzie i wszędzie ma zachowywać się identycznie – wystarczy jedna deklaracja. My zdefiniujemy sobie dwa zestawy parametrów: liczba wraz z odpowiednim formatowaniem, lub po prostu słowo:
param ( [Parameter( Mandatory = $true, HelpMessage = 'Pomocy!', ValueFromPipeline = $true, Position = 0, ParameterSetName = 'Liczby' )] [double]$Liczba, [Parameter( Mandatory = $true, HelpMessage = 'Pomocy!', ValueFromPipelineByPropertyName = $true, Position = 0, ParameterSetName = 'Domyslny' )] [ValidatePattern('^\w+$')] [string]$Slowo, [Parameter( Position = 1, ParameterSetName = 'Liczby', Mandatory = $true, HelpMessage = 'Pomozcie mi!' )] [ValidateSet('P4','N4','C4')] [string]$Format )
Jak widać – można mieć dwa parametry o tej samej pozycji. O tym, który zostanie wykorzystany, decyduje zestaw parametrów: domyślnie nawet liczba zostanie potraktowana jako string. Jeśli jednak dodamy –Format (występujący tylko w zestawie z liczbami) PowerShell spróbuje pozycyjny parametr przerobić na [double]:
Jest wyjątek od tej reguły: jeśli typ będzie idealnie pasował do oczekiwanego (1.123123) to PowerShell wybierze ten zestaw, który pobiera zmienną danego typu.
Walidacja na wejściu
Kolejny efekt pisania funkcji jako zaawansowanej to możliwość walidacji tego, co użytkownik próbuje do funkcji wrzucić. Zgodnie z regułą GIGO (nie wiem czy polska wersja, choć bardziej dosadna, nie oddaje bardziej powagi sytuacji) – walidacja wejścia ma sens i należy jej używać zawsze wtedy, gdy zła informacja na wejściu może spowodować nieoczekiwane (na ogół bolesne) rezultaty. Sposobów walidacji mamy kilka:
- zestaw do wyboru: ValidateSet
- odpowiednia ilość elementów: ValidateCount
- odpowiednia matryca z wyrażeń regularnych: ValidatePattern
- odpowiednia długość: ValidateLength
- odpowiedni zakres wartośći: ValidateRange
- nie jest ‘zerowy’: ValidateNotNull
- nie jest ‘zerowy’ ani pusty: ValidateNotNullOrEmpty
- i najbardziej elastyczny: ValidateScript
Wszystkie te elementy ograniczają nasz element, jednak jeśli nasz argument jest wymagany (Mandatory) czasem konieczne może się okazać przymknięcie oka na pewne niedoskonałości (zwłaszcza jeśli element wpada nam z “rurki”):
- zezwól na wartości zerowe: AllowNull
- zezwól na pusty string: AllowEmptyString
- zezwól na puste kolekcje: AllowEmptyCollection
Jak widać jest w czym wybierać. Mój ulubiony to ValidateScript, który akceptuje parametr jeśli wynik skryptu będzie $true, odrzuci – jeśli wynik będzie $false, albo wyskoczy nam jakiś wyjątek. Dzięki temu i komendzie ‘throw’ możemy uczynić komunikat o błędzie bardziej zrozumiałym (zwłaszcza jeśli lokalizacja do języka narodowego nadal nie istnieje
).
Aliasy dla parametrów.
Aliasy mają dwa główne cele:
- umożliwienie wykorzystania w naszej funkcji różnych właściwości obiektów (ComputerName, Name, Nazwa)
- ułatwienie pracy z komendą “interaktywnie” (CN, NK)
Wydaje mi się, że druga ewentualność jest dość jasna. Co do pierwszej: jeśli zdarzy się, że jakaś komenda wyrzuca z siebie obiekty o właściwości Foo, która nam odpowiada a inna wyrzuca obiekty o właściwości Bar, która niczym się nie różni od Foo, to mamy idealnego kandydata na alias. Nazywając parametr Foo i nadając mu alias Bar zyskamy możliwość pobierania obiektów z obu komend. Wielokrotnie stosowałem tę metodę by móc “połykać” obiekty dotyczące komputerów i przypisywać wartość właściwości Name parametrowi ComputerName. Bez aliasów byłoby to trudne, lub wręcz niemożliwe…
I w ten oto sposób zamknęliśmy blok param () – przed nami wszystko to, co kryje się w automatycznie tworzonej w zaawansowanych funkcjach zmiennej $psCmdlet oraz kilka słów o Write-* w funkcji zaawansowanej. Zamierzam też wspomnieć, po co i gdzie używać konstrukcji begin, process i end. I choć wielka trójca była już dostępna w PowerShellu w wersji 1, to nie sposób pominąć tego tematu przy omawianiu zaawansowanych funkcji.
PowerShell – efektywnie(j), część 4.
| 2011-10-23 | Posted by Bartek Bielawski under najlepsze praktyki, Początki, Polskie blogi IT, Skrypty, zaawansowane funkcje |
|
Troszkę to trwało nim udało mi się przysiąść do tego artykułu. Przyczyna jest prozaiczna: temat jest dość obszerny i nie wiem jak go ugryźć. Pisanie skryptów w PowerShellu nie wymaga wielkiego wysiłku, ale jeśli chcemy by nasz skrypt był przydatny dla innych i dla nas za pół roku – trzeba się nieco przyłożyć w czasie jego tworzenia. Uznałem jednak, że rzecz sama się nie zrobi. W najgorszym wypadku po prostu rozpiszę się nieco bardziej niż zwykle (ha, ha, ha…
)
Od czego zacząć?
W zasadzie pierwsze pytanie jakie powinniśmy sobie zadać powinno brzmieć: czy chcemy napisać coś, co wykona serię operacji i da nam na koniec jakiś wynik (skrypt) czy bardziej interesuje nas biblioteka narzędzi (moduł). Dalej jest już prościej: dzielimy zadanie na proste czynności (funkcje), które następnie połączymy w całość. I o ile w przypadku modułów sprawa wydaje się “czysta” i dość naturalna, o tyle w wypadku skryptów musimy zwalczyć pokusę umieszczenia operacji w jednym, wielki worze.
Kod wielokrotnego użycia
Skrypty lubią rosnąć niby hydra: dodajemy do nich kolejne funkcjonalności, jednocześnie nie specjalnie dbając o to, by kod można było później wykorzystać. To moim zdaniem spory błąd: utrudnia ponowne wykorzystanie napisanego kodu w innym narzędziu, czyni narzędzie dość statycznym i dość silnie uwiązanym do wykorzystanej technologii. Może prosty przykład, by pokazać o co mi chodzi…
Naturalna kolej rzeczy: nasz skrypt może przyjąć jako parametr samą listę (przekazaną przez rurkę), OU w AD, plik txt/ csv z listą komputerów itd. Na wyjściu – podamy ścieżkę do pliku .csv w którym dane zostaną zapisane. To co się dzieje w środku zależy już od nas. Możemy więc albo zrobić to w formie funkcji, które następnie ustawimy w jednej “rurce” i uzyskamy pożądanych efekt. Albo wszystko zrobić za jednym zamachem, bez dziabania kodu na poszczególne fragmenty. Co tracimy?
- przejrzystość kodu (logika się “zlewa”)
- utrudnienia przy wymianie komponentu
- rozwiązując podobny problem musimy praktycznie kopiować cały skrypt, albo zacząć pisanie od początku
Problem, jaki może się pojawić, to konieczność zdefiniowania funkcji zanim ich użyjemy. Jak to w prosty sposób rozwiązać? Mój ulubiony trik to definiowanie na początku funkcji, która ma za zadanie tylko opisać zakładaną logikę – czy inaczej – szkic tego co chciałbym osiągnąć. Na ogół wygląda to tak:
#requires -version 2.0 <# Pomoc do skryptu #> function Invoke-Main { param ( $Parametr = $Script:Parametr, $DrugiParametr = $Script:DrugiParametr, $Path = $Script:Path ) Get-Foo -Parametr $Parametr | Test-Foo | ConvertTo-Bar -Drugi $DrugiParametr | Export-Csv -Path $Path } <# Tu definiujemy: * Get-Foo * Test-Foo * ConvertTo-Bar #> Invoke-Main
Jak widać – definicje funkcji następują przed jej wywołaniem (które ma miejsce na samym końcu skryptu) ale sposób ich wywołania znany jest od początku (zdefiniowany w pierwszej funkcji w skrypcie). Jeśli zechcę kiedyś zmienić finalny obiekt na ‘Boo’ zamiast funkcji ConvertTo-Bar zdefiniuję ConvertTo-Boo, zmienię nieco Invoke-Main i już – skrypt gotowy do użycia.
Funkcja w rurce – awansujemy.
Patrząc na składnię moich hipotetycznych funkcji od razu widać jedną rzecz: wszystkie “klocki” radzą sobie w rurce. To podstawa: pisząc funkcję niezdolną do pracy w środku pipe’a strzelamy sobie w stopę. By jednak współpraca przebiegała bezboleśnie – należy z całą pewnością przyzwyczaić się do pisania zaawansowanych funkcji. Wymagają one nieco dekoracji na wstępie, ale wartość dodaną trudno moim zdaniem przecenić. Druga rzecz, która być może w skryptach nie jest tak cenna, ale w modułach moim zdaniem absolutnie niezbędna: pomoc do funkcji. Wymaga to maciupeńkich nakładów pracy (odpowiednio skomponowany komentarz) a oszczędza konieczności czytania definicji funkcji za każdym razem. Myślę, że sam temat zaawansowanych funkcji jest zbyt obszerny, by go streścić tutaj, zostawię więc to na piątą część cyklu. Na rozbudzenie apetytu: malutka funkcja, która wykorzystuje część możliwości, które dają zaawansowane funkcje:
function Test-IsAlive { [CmdletBinding()] param ( [Parameter( ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = 'Nazwa komputera, ktory testujemy' )] [ValidatePattern('(?# Bez spacji w nazwach komputerow!)^\S+$')] [Alias('Name','CN','Nazwa')] [string]$ComputerName, [Parameter(ValueFromPipeline = $true)] [Alias('IO')] [PSObject]$InputObject ) process { Write-Verbose "Testuje komputer: $ComputerName" if (Test-Connection -ComputerName $ComputerName -Quiet -Count 1) { if (!$InputObject) { Write-Verbose 'Nic na wejsciu, tworzymy sami.' $InputObject = New-Object PSObject -Property @{ ComputerName = $ComputerName } } $InputObject | Add-Member NoteProperty IsAlive $true -PassThru } } }
Skutek? Mogę przez tą funkcję przepuścić dowolny obiekt, który posiada właściwość ComputerName, Name, Nazwa lub CN i jeśli właściwość ta nie zawiera spacji (ValidatePattern, z komentarzem, by nie straszyć ludzi niezrozumiałym regexpem) i da się ją “pingnąć” (preferowane więc będą obiekty pobrane z AD, lub innego zawierającego nazwę komputera) to na wyjściu dostanę ten sam obiekt “wzbogacony” o właściwość IsAlive. Jeśli spróbuję uruchomić funkcję bez parametru – poprosi mnie ona o wartość ComputerName. I rzecz nie bez znaczenia: dodanie wtrąceń typu Write-Verbose/ Debug działa bez potrzeby implementacji. [CmdletBinding()] daje mi te opcje za darmo. Mogę więc uruchomić funkcję z parametrem –Debug lub –Verbose i dowiedzieć się więcej o tym, co dzieje się w środku.
Wejście – wyjście.
Skrypty mają to do siebie, że czasem wolelibyśmy nie musieć pamiętać co do nich trzeba włożyć, oraz co byśmy chcieli z nich wyjąć. Z drugiej strony – czasem jednak chcemy mieć wpływ na to, co się stanie… PowerShell pozwala pogodzić te dwie sprzeczności. Rozwiązanie to wyciągnąć jak najwięcej elementów na zewnątrz skryptu (w postaci parametrów) i jednocześnie przypisać im wartość domyślną (by nie być zmuszonym podawać ich za każdym razem). Z wyjściem jest gorzej – optymalne rozwiązanie to parametr typu [switch], który na wyjściu da nam “żywe” obiekty. To co z nimi zrobimy dalej będzie zależeć już tylko od nas. I wilk syty, i owca cała.
Pomoc w funkcjach i skryptach PowerShell
| 2011-10-09 | Posted by JeZZoo under Get-Help, inline help, Polskie blogi IT, script library, Skrypty |
|
Tworzenie funkcji czy skryptów, szczególnie tych bardziej złożonych wymaga stworzenia dokumentacji, tak, aby późniejsze uruchomienie nie sprawiało problemów lub nie wymagało szukania w kodzie sposobu wywołania, np. parametrów wejściowych. Przydatne jest to szczególnie, jeśli tworzymy skrypty lub biblioteki funkcji, z … Czytaj dalej
PowerShellowy backup urządzeń sieciowych, czyli SSH w Powershell
| 2011-09-09 | Posted by JeZZoo under CSV, Narzędzia, Polskie blogi IT, remote execution, router, script library, Skrypty |
|
Konfigi z urządzeń sieciowych wymagają backupu jak wszystko inne. Wiadomo, jeden switch pada, to bierzemy następny, podmieniamy, ładujemy konfig i powinno działać. Tylko co, jeśli od ostatniego zrzutu minęło pół roku, a my zdążyliśmy zmienić połowę konfiguracji… Dlatego warto to … Czytaj dalej
PowerShell – przydatne narzędzia
| 2011-08-10 | Posted by JeZZoo under Narzędzia, plugin, Polskie blogi IT, PowerGUI, PowerShell ISE, PowerShell-jak zacząć?, PowerWF, produkty Microsoft, Quest Software, Skrypty |
|
Do pracy z PowerShell wystarczy konsola. Dodając do tego Notatnik możemy już pisać skrypty. Wykorzystując możliwość korzystania z bibliotek i odwoływania się do .NET możemy z PowerShellem zrobić już prawie wszystko. Jednak nakłąd pracy będzie spory. Dodatkowo sporo drzwi zostało … Czytaj dalej
Biblioteka własnych funkcji w PowerShell
| 2011-04-30 | Posted by JeZZoo under Polskie blogi IT, PowerShell-jak zacząć?, produkty Microsoft, script library, Skrypty |
|
Jeśli częściej posługujemy się PowerShellem to w pewnym momencie dochodzimy do etapu, gdzie mamy sporą ilość gotowców porozrzucanych po różnych plikach. Jeśli wykonujemy powtarzające się czynności, które wymagają większej ilości kodu również powstaje spore repozytorium, które za każdym razem trzeba … Czytaj dalej
Co tam w sieci piszczy – czyli Szybkość połączenia LAN
| 2010-08-29 | Posted by Przemek Kuczyński under Polskie blogi IT, Skrypty, Techniczne |
|
Skrypt logowania użytkownika pokaże nam :
nazwa komputera, zalogowanego użytkownika, nazwę karty sieciowej, opis karty sieciowej, adres ip, link speed
on error resume next strComputer = "." Set wshShell = Wscript.CreateObject( "Wscript.Shell" ) strServer=wshShell.ExpandEnvironmentStrings("%COMPUTERNAME%") strUser=wshShell.ExpandEnvironmentStrings("%USERNAME%") Function LinkSpeed(Desc) Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\WMI") Set colItems = objWMIService.ExecQuery("SELECT * FROM MSNdis_LinkSpeed Where InstanceName = '" & Desc & "'",,48) For Each objItem In colItems If objItem.NdisLinkSpeed < 10000 Then LinkSpeed = objItem.NdisLinkSpeed / 10 & " KBps" ElseIf objItem.NdisLinkSpeed > 10000 Then LinkSpeed = objItem.NdisLinkSpeed / 10000 & " MBps" end if Next End Function Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") Set colItems = objWMIService.ExecQuery("Select * From Win32_NetworkAdapterConfiguration " & "Where IPEnabled = True") For Each objItem in colItems Wscript.Echo strServer & ";" & strUser & ";" & objItem.Caption & ";" & objItem.Description & ";" & Join(objItem.IPAddress, ",") & ";" & LinkSpeed(objItem.Description) Next
Jeśli chcemy mieć zawsze aktualne informacje w logach skrypt wykonujemy nastepujaco:
cscript //nologo //u \\server\zasob\skrypt.vbs > \\server\logi\%computername%.csv
Następnie za pomocą poniższego skryptu mozna polaczyć wszystkie logi w 1
del /q \\server\logi\all.csv copy /y "\\server\logi\" C:\tmp\Nspeed\ FOR /R "C:\tmp\Nspeed" %%G IN (*.*) DO more %%G >> "\\server\logi\all.csv"