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

param(
    [int]$int
)

switch($int) {
    1 { write-host 'normalka'}
    {2 -or 3} {write-host 'ten sam dla dwóch wartości'}
    {$_ -ge 4} { write-host 'wieksze niz 3'}
    {$_ -ge 5} { write-host 'wieksze niz 4'
        break;
    }
    {$_ -lt 8} {write-host 'mniejsze niz 8 [ale nie wieksze niz 4]'} 
    default { write-host 'wszystkie inne'}
}

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.

Powershell on Linux

devopskilka dni temu został oficjalnie zaprezentowany PowerShell dla Linux. co prawda na razie w wersji Alpha, niemniej jest to wielka sprawa. .Net był zapowiadany jako wielo-platformowa alternatywa dla Javy podczas, kiedy wychodziła wersja 1. trzeba było czekać dekadę – od 2o14 MS wspiera rozwój projektu Mono, dzięki czemu w końcu powstała wersja .NET, pozwalająca na przeniesienie PSh na Antarktydę (;

Linux w kilq miejscach utknął w latach 9o’ i tak jest m.in. z konsolą i 'string-thinking’ czyli operowaniem na ciągach. kto popracował z obiektami i poznał realną przyjemność pracy z ich obróbką [filtry, export/import, badanie parametrów itd], ten wie o czym mowa. to oczywiście jeden z ważniejszych aspektów, ale najważniejszy, który wpisuje się w promowany trend DevOps i Cloud, to ujednolicenie środowisk. 1/3 wszystkich maszyn działających w Azure to Linuxy, co pokazuje zarówno do czego tak na prawdę jest 'Chmura’ oraz jak światy MS/Lin zaczynają się przenikać. a to oznacza, że developerzy, tudzież DevOpsi, potrzebują jednolitych środowisk, bez względu na platformę. to warstwa, która przez lata dzieliła światy i w końcu staje się tylko kolejną warstwą abstrakcji – czy pracuje się na Windows czy na Linux, można to robić w coraz bardziej zunifikowany sposób.

ci, którzy nie wierzą, i jeszcze się z tym nie spotkali, niech obejrzą prezentację: https://channel9.msdn.com/Blogs/hybrid-it-management/PowerShell-on-Linux-and-Open-Source

podczas oglądania warto zwrócić uwagę na to, jak coraz trudniej odróżnić na którym systemie ktoś pracuje – np. Visual Studio Code działające na Linux i na Mac, PSh na Mac, Linux czy VMWare, jednolity sposób zarządzania środowiskami …

pamiętam czasy, kiedy wystarczyło rzucić nieopatrzne hasło nie na tym forum i z wpisów tryskała krew nienawiści i słowne krucjaty w wojnie o to, który system jest najlepszy i jak bardzo moja mojszość jest mojsiejsza. przyjemnie patrzeć jak z tego średniowiecza przechodzimy do prawdziwego renesansu, wymiany myśli i współpracy między platformami, z korzyścią dla całego rynq. hasło 'DevOps’ wprowadza nas do nowej epoki na rynq IT będąc taką samą rewolucją w myśleniu, jak jakiś czas temu wirtualizacja.

eN.

 

logowanie na szybko – commandlet defaults

Windows_PowerShell_icondobrze jest dodawać jakieś logi do skryptu. można sobie ułatwić to zadanie na wiele sposobów, ale chciałem dorzucić jeszcze jeden, który może przydać się przy innych scenariuszach, jeśli tylko często wykonuje się jakieś polecenie z takimi samymi wartościami parametrów.

jeśli logowanie robimy przekierowując przy pomocy out-file to co chwila będziemy wpisywać:

"message"|out-file -append -path $logPath

niby nie dużo, ale czemu nie skrócić tego zapisu? można ustawić standardowe wartości parametrów dla wszystkich commandletów. robi się przy pomocy zmiennej $PSDefaultParameterValues, a w praktyce wygląda to np. tak:

$logFile="logifilename$(Get-Date -Format yyMMddHHmm).log"
    $PSDefaultParameterValues = @{
        "Out-File:FilePath"=$logFile
        "Out-File:append"=$true
    }
    $startTime = Get-Date
    "starting operation at $startTime"|Out-File
    "second line to test append"|out-file

eN.

hack the hash – master level

Windows_PowerShell_iconpoprzedni konqrs okazał się zbyt łatwy. no to kto będzie prawdziwym cwaniakiem i rozkmini na tym poziomie? tym razem trochę wiedzy o:

  • rekurencji
  • zakresach zmiennych
  • praktyka
  • i kolejna zagadka (;

poprzedni wpis zainspirowany został podczas poprawiania skryptu.. czy też pisania go od nowa, który gdzieś tam wewnątrz miał funkcję budującą listę użytkowników grupy distribution:

function Get-GroupMember
{
    param($name)
    $members = @()
    foreach($member in (Get-DistributionGroupMember $name))
    {
        if($member.RecipientType -eq "UserMailbox")
        {
            $member
        }
        elseif($member.RecipientType -eq "MailUniversalSecurityGroup")
        {
            Get-GroupMember $member.Name
        }
    }

}

jak widać jest to rekursywne zapytanie, w wersji 'czyste zło’. zło, które zostało wskazane w odpowiedzi przez bula – tak na prawdę funkcja nie zwraca jednej zmiennej, tylko całą serię zagnieżdżonych zmiennych. zwróćcie uwagę, że wewnątrz funkcji jest deklaracja '$members=@()’ – czyli przy każdym kolejnym zagnieżdżeniu tworzy się nowy '$members’. w efekcie, nie dość, że technicznie nie ma jednego wyniq a seria wyniqw, to jeśli osoba należy do wielu grup, pojawi się wiele razy. jeśli okaże się, że grupy są gdzieś zapętlone, co przy skomplikowanej strukturze może się wydarzyć, to skrypt będzie leciał w nieskończoność [grupa A należy do grupy B, B do C, C do A – pętelka. AD pozwala nawet na A do B i B do A – nie ma tutaj weryfikacji].

rekursja jest również zła ze względu na obsługę pamięci i możliwość przepełnienia stosu. to trochę zabawne [i frustrujące] ale na pierwszym roq, na programowaniu uczono mnie rekurencji. potrzebowałem duuużo czasu i dobrego przykładu aż w końcu zrozumiałem. bo jak mówi stare przysłowie – ’rekurencję zrozumiał ten, kto zrozumiał rekurencję’. a jak już zrozumiałem, to ten sam wykładowca [Ś.P. prof. Bielecki] poświęcił następny semestr na wyjaśnianiu czemu rekurencja jest zła, czemu należy jej unikać i jak z niej wychodzić… w skrócie – nad wywołaniem rekurencyjnym na prawdę trudno zapanować, chyba że ktoś umie myśleć jak implementacja zagnieżdżonego stosu.

anyway… najprostszą metodą, jest po prostu wyrzucenie zmiennej do wspólnego zakresu [scope]. zmienne mają swoje 'skołpy’, co najlepiej widać właśnie przy rekursji. ale w prostym przykładzie:

function test {
  $a=2
  $a
}
$a=1
test
$a

output to: 2,1 . wewnątrz funkcji 'test’ są dwie zmienne $a – ta wewnątrz funkcji i ta zadeklarowana na poziomie skryptu. słowa 'globalnie’ unikam świadomie, ponieważ są trzy podstawowe poziomy: global, script, local. więcej tutaj.

fajnym testem rekursji+zakresu jest taki przykład:

function recursion {
    param($r)
    $var+=[string]$r
    if($r -lt 10) {
        recursion ($r+1)
    }
}

$var= recursion 1
$var

co wyświetli się na ekranie? spróbuj wymyślić, odpal kod, sprawdź… jeśli nie jesteś zaskoczony – to jesteś unikatem, który na prawdę zajebiście rozumie działanie stosu. ale to nie była końcowa zagadka. do tego jeszcze dojdę.

…. a nie będę pisał na razie dalszej części. zostawię w tym miejscu bo tłumacząc zepsuję zabawę, a dzięki temu ilość zagadek się zwiększy q:

czyli kolejna zagadka i kontynuacja przeróbki skryptu – jakoś na dniach ^^

hef fan

eN.

 

hack the hash

taki mały konqrs. jest sobie hash-tablica:

$a=@{}

cechą hashtable aka tablicy słownikowej jest to, że klucze w niej są unikalne – stąd nazwa 'słownikowa’. przykład:

C:\...ive\_scriptz :))o- $a.Add('key','val')
C:\...ive\_scriptz :))o- $a.Add('key','co innego')
Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: 'key'  Key being added: 'key'"
At line:1 char:1
+ $a.Add('key','co innego')
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException

przy próbie dodania drugiego klucza o tej samej nazwie, dostajemy błąd. jasne.

no to teraz taki hack the hash:

function addHash {
param($hashValue,$i)
    
    $ht=@{}
    $ht.add('key',$hashValue)
    if(-not $i) {addHash 'test' -i $true}
    $ht

}
addHash 'bla'

Name                           Value                                                                                                                                                 
----                           -----                                                                                                                                                 
key                            test                                                                                                                                                  
key                            bla

i okazuje się, że są dwa klucze o tej samej nazwie!

pytanie konqrsowe – jak to możliwe? (:

odpowiedź… jak mi się przypomni q:

eN.

get-MACAddressVendor

Windows_PowerShell_iconadresy MAC to tzw. OUIs – Organizationally Unique Identifier przyznawane przez IEEE. wszystkie można ściągnąć w postaci pliq textowego (1oMB). w związq z tym skrypt, który odpytuje się o MACa może albo wykorzystać jakieś query dostępne w necie, albo ściągną bazę lokalnie i operować na lokalnym pliq.

plik można ściągnąć na kilka sposób. w tym przypadq invoke-webRequest się wywala ze względu na timeout [duża wielkość pliq]. można zmienić timeout, można oprogramować metodę [System.Net.WebClient] … a można wykorzystać BITS.

poniżej prosty skrypcik, do weryfikacji MAC vendor, po uprzednim zassaniu oui.txt lokalnie. to na co warto zwrócić uwagę – to alternatywny sposób na pobieranie pliqw z netu, oraz parametr 'context’ dla select-string.

get-MACAddressVendor.ps1

################################################################################################
#.SYNOPSIS
#   simple script getting NIC vendor by checking MAC address OUI table. 
#   use -webAPI to use remote query. otherwise out.txt file will be download locally.
#.LINKS
#   oui file: http://standards-oui.ieee.org/oui.txt
#   remote query API: http://www.macvendorlookup.com/api
#.NOTES
#   nExoR 2o16
################################################################################################
param([string]$macAddress,[switch]$webAPI) 

$macAddressToVerify=$macAddress.Replace(':','').Replace('-','').ToLower()
$macAddressToVerify=$macAddressToVerify.Substring(0,6)
if($macAddressToVerify -notmatch [regex]'[0-9a-f]{6}') {
    throw 'NOT VALID MAC ADDRESS'   
}

if($webAPI) {
    $result=Invoke-WebRequest "http://www.macvendorlookup.com/api/v2/$macAddressToVerify"
    $result=ConvertFrom-Json $result.Content   
} else {
    if(-not (Test-Path .\oui.txt)) {
        Start-BitsTransfer -Source 'http://standards-oui.ieee.org/oui.txt' -Destination 'oui.txt' -TransferType Download
    }

    $result=Select-String -path .\oui.txt -Pattern $macAddressToVerify -Context 0,4
}

if($result) {
    $result
} else {
    throw "Vendor not found for $macAddress"
}


eN.

 

 

what-is-my-ip – kontunuacja

Windows_PowerShell_iconpo  komentarzach na FB, zamieszczam prosty skrypt, który pozwala odpytać dwóch różnych stron – whatsmyipaddress, API, które zwraca czysty adres, ale ponieważ:

You may programmatically query that server but limit queries to no more than once per five minutes and include an appropriate user agent that will allow us to contact you if needed

dodałem starą metodę przegrzebującą się przez HTML.

get-ExternalIP.ps1

param( [switch]$alternateServer )

if($alternateServer) {
    $page=Invoke-WebRequest http://whatismyipaddress.com/pl/moj-ip
    [regex]$rxIP='((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
    $page.AllElements|? id -eq 'section_left'|%{ $IP=$rxIP.Match($_.outerText)}
} else {

    $result=Invoke-WebRequest ipv4bot.whatismyipaddress.com
    $IP=$result.content
}

Write-Host -BackgroundColor DarkYellow -ForegroundColor Black "EXTERNAL IP ADDRESS OF THE CONNECTION: $IP"

eN.