praktyka
zmienne mają swoje zakresy (scopes). zakresy są niby bardzo proste… ale czy na pewno? to jak pobrać zmienną z zakresu nadrzędnego (parent scope)?
bardzo proste:
get-variable -name <varName> -scope 1
teoria
ale, że '1′? zawsze i niezmiennie '1′? jak to tak? a jak pobrać wartość zakresu w którym obecnie się znajduję?
zmienne układane są na stosie, zwanym czasem kolejką LIFO (Last-In, First-Out). [najstarsza zarejestrowana implementacja LIFO to ’pierwsi będą ostatnimi, a ostatni pierwszymi’ więc łatwo zapamiętać (; ]. element na szczycie stosu, to element 'obecny’, i zawsze ma wartość '0′. proste, ale konsekwencje są nieoczywiste. do tego dochodzi specyfika samego PS i tego, jaki próbuje być 'przyjazny’, co dodatkowo może mieć niespodziewane konsekwencje. oprócz zakresów 'numerowanych’ są zakresy 'nazwane’ i to one powodują sporo zamieszania. nie będę kopiował definicji, które można znaleźć łatwo i szybko, ale z nazwy, podstawowe zakresy to 'Global’ i 'Script’. tak więc uruchamiając dowolny skrypt, zakresy wyglądają tak:
prosty kod testowy:
function level1 {
$x = 1
$x
}
$x = 0
level1
$x
wyświetli oczywiście '1′ a następnie '0′ – ponieważ przy każdym wyświetleniu $x wskazuje na zmienną z obecnego zakresu. obecnego, czyli '0′, co obrazuje:
mamy więc odpowiedź 'jak pobrać obecny zakres’ – jest to po prostu zakres zero. skompliqjmy ten skrypt tak, aby przetestować czy faktycznie 'parent scope’ to '1′:
function level1 {
$x = 1
"here: $x"
"parent from l1: {0}" -f (Get-Variable -Name x -Scope 1).Value
level2
}
function level2 {
$x = 2
"here: $x"
"parent to l2: {0}" -f (get-variable -name x -Scope 1).value
"script from l2: {0}" -f ($script:x)
}
$x=0
Write-Host -ForegroundColor Magenta "level1:"
level1
Write-Host -ForegroundColor Red "level2:"
level2
write-host -ForegroundColor Green "script:"
$script:x
write-host -ForegroundColor Yellow 'global:'
$Global:x
stos zmiennych dla tego wywołania ma teraz taką strukturę:
oczywiste? ruchome wartości dla zakresów nazwanych mogą sprawić problem i wydawać się nieintuicyjne. ale to nie koniec pułapek. ostatnia wartość [$global:x] może przyjąć albo $null albo… zero. zależnie od środowiska uruchomieniowego [możesz odpalić kod w VSC]. dodatkowo problemy może sprawić zmiana wartości zmiennej nadrzędnej… o ile odczytana zostanie zmienna z dowolnego, pierwszego zakresu, w którym istnieje, o tyle zmiana wartości będzie wykonana w tym samym zakresie. żeby to zobrazować, zmodyfiqjmy odrobinę pierwszy kod:
function level1 {
$x
$x = 1
}
$x = 0
level1
$x
tym razem na ekranie pojawią się dwa zera. w funkcji 'level1′ żądamy wyświetlenia $x, które w tym zakresie jeszcze nie istnienie. w związq z tym wyświetlony został $x z zakresu wyżej. ale w momencie wykonania „$x = 1”, zgodnie z definicją, iż przypisanie następuje zawsze w tym samym zakresie, zmienna została zainicjowana lokalnie – a nie nadpisana pierwsza istniejąca – i to jej przypisana została wartość '1′. a więc $x wyświtlony na końcu nie uległ zmianie i wyświelone zostało '0 0′
jeśli chcemy zmienić wartość zmiennej w zakresie nadrzędnym (parent scope) kod wygląda tak:
function level1 {
$x
set-variable -name x -scope 1 -Value 1
}
$x = 0
level1
$x
…no i warto zwrócić uwagę, że podając nazwy zmiennych dla commandletów *-variable nie dodaje się '$’.
…i może jeszcze to, że nie ma standardowo metody aby odpytać się o to, jak głęboki jest obecnie stos. jeśli masz taki scenariusz, to przyda ci się jeden z poprzednich wpisów. no dobra, podpowiem… to będzie „((get-PSCallStack).count-1)”.
eN.
katalog stricte sieciowy
w jaki sposób 'dostarczyć’ jakiś katalog na kilka serwerów/VDI? łatwym i popularnym sposobem jest wykorzystanie Azure Files i po prostu podmapować dysk sieciowy.
takie rozwiązanie ma (potencjalnie) kilka wad. potencjalnie – ponieważ wszystko zależy od założeń po co i dla kogo to robimy:
chodziło o dostarczenie wspólnego repozytorium, dostępnego na wszystkich VDI. można taki efekt osiągnąć mapując udział sieciowy jako katalog.
potrzebny do tego jest Storage Account wspierający Azure Files, dodany do domeny. jest to konieczne ze względu na możliwość uwierzytelnienia. a kiedy mamy już założony Azure Files, wystarczy utworzyć w systemie katalog, który będzie na niego wskazywał:
as simple as that. i mamy katalog, który zachowuje się i wygląda (niemal) jak normalny katalog. nie trzeba już polis GPO ponieważ Windows już nie traktuje tego jako dysq sieciowego a zwykły katalog lokalny.
dodam do tego kilka uwag i ciekawostek:
\\wfilesrepo.file.core.windows.net\repo\wlasciwykatalog – i wyłączyć dziedziczenie na poziomie 'wlasiciwykatalog’
albo
c:\root\[repo] – gdzie [repo] to symlink – i wyłączyć dziedziczenie na poziomie 'root’…
to problemu nie będzie. tylko jest wtedy bzdurny dodatkowy katalog /:
mimo pewnych dziwnych zachowań sprawdza się fajnie a dla użytkowników wygląda i zachowuje się jak folder lokalny.
eN.