Konfiguracja Certyfikatu RDP na serwerze Windows 2016

Na serwerze Windows 2016, tak samo jak w wersji poprzedniej, nie ma narzędzia konfiguracyjnego umożliwiającego ustawienie certyfikatów RDP.
Można dokonać konfiguracji certyfikatu przy użyciu WMI. Najłatwiej jest tego dokonać poprzez Powershella.
Poniżej skrypt konfigurujący:

1
2
3
4
$CN = "CN=localhost"
$RdpSetting = Get-WmiObject -class "Win32_TSGeneralSetting" -Namespace root\cimv2\terminalservices -Filter "TerminalName='RDP-tcp'"
$thumbprint = (Get-ChildItem -path cert:/LocalMachine/My | | ? Subject -eq $CN).Thumbprint
Set-WmiInstance -path $RdpSetting.__path -argument @{SSLCertificateSHA1Hash="$thumbprint"}

Jest to metoda uniwersalna, działająca zarówno na systemie klienckim, jak i serwerowym.

Błąd „Root element is missing” przy wywołaniu Runbooka SMA

Najczęściej taki błąd pojawia się, gdy z poziomu bloku inline lub z funkcji wywoływany jest inny Runbook. Zachowanie takie jest niedozwolone.
Ostatnio spotkałem się z innym powodem tego błędu.
Normalnie w Powershellu możliwe jest indeksowanie tablicowe obiektu zwracanego z wyrażenia objętego nawiasami:

1
$var = (get-service)[0]

W przypadku użycia takiego wyrażenia w SMA zwracany jest właśnie błąd „Root element is missing”

Zaawansowane filtrowanie w Windows Event Log

Jest mało znanym faktem, że Event Log Viewer umożliwia filtrowanie nie tylko graficzne, ale także zaawansowane query uwzględniające dowolne dane zawarte we wpisach określonego typu.
Drugim mało znanym faktem jest, że Event Log Viewer umożliwia wyświetlenie i filtrowanie po tak zwanym „Correlation ID”. Oczywiście, aplikacja wpisująca rekordy do dziennika zdarzeń także musi wspierać Correlation ID, gdyż część aplikacji nie zapisuje tego pola.
Niezwykle przydatną sprawą jeśli chodzi o Correlation ID jest to, że możemy odfiltrować zdarzenia związane z jakąś jedną konkretną czynnością, która generuje szereg zdarzeń, zakończony, na przykład, błędem.
Oto przykładowe query:

1
2
3
4
5
6
7
<QueryList>
  <Query Id="0" Path="file://C:\Logs\Logs.evtx">
    <Select Path="file://C:\Logs\Logs.evtx">
*[System[Correlation[@ActivityID='{8A348658-802A-4ACB-A855-1CC57EA25B18}'] and (Level=1  or Level=2 or Level=3 or Level = 4) and TimeCreated[@SystemTime&gt;='2016-11-27T15:11:00.000Z' and @SystemTime&lt;='2016-11-21T15:12:00.000Z']]]
    </Select>
  </Query>
</QueryList>

Każdy wpis w logu systemu windows od 2008 w górę jest prezentowany w formacie XML. Query się odnosi do pól we wpisie. Niestety nie jest to wyrażenie XPATH, ale jest równie intuicyjne i proste do odczytania.
Przedstawiam przykładowy wpis z dziennika zdarzeń:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Microsoft-Windows-GroupPolicy" Guid="{AEA1B4FA-97D1-45F2-A64C-4D69FFFD92C9}" />
    <EventID>1500</EventID>
    <Version>0</Version>
    <Level>4</Level>
    <Task>0</Task>
    <Opcode>1</Opcode>
    <Keywords>0x8000000000000000</Keywords>
    <TimeCreated SystemTime="2016-11-27T15:11:31.651603600Z" />
    <EventRecordID>31607</EventRecordID>
    <Correlation ActivityID="{8A348658-802A-4ACB-A855-1CC57EA25B18}" />
    <Execution ProcessID="1288" ThreadID="31724" />
    <Channel>System</Channel>
    <Computer>ComputerName</Computer>
    <Security UserID="S-1-5-18" />
  </System>
  <EventData>
    <Data Name="SupportInfo1">1</Data>
    <Data Name="SupportInfo2">4202</Data>
    <Data Name="ProcessingMode">0</Data>
    <Data Name="ProcessingTimeInMilliseconds">0</Data>
    <Data Name="DCName" />
  </EventData>
</Event>

Najprostszą metodą do rozpoczęcia prac nad kwerendą jest wyjście od ustalenia elementarnych warunków Filtrowania poprzez wybranie opcji „Filter Current Log”.
Poniższy wycinek ekranu pokazuje przykładowe warunki filtru.
ScreenShot1
Następnie przechodzimy na zakładkę „XML” i zaznaczamy checkbox „Edit query manually”
ScreenShot2
Po zatwierdzeniu komunikatu o fakcie, iż nie będzie można tego query już więcej edytować graficznie, otrzymujemy edytor query.
ScreenShot3
Filozofia tworzenia query jest prosta. Każdy tag, na podstawie którego będzie wykonywane filtrowanie znajduje swoje odzwierciedlenie w postaci składni:

1
Tag[Warunek1 and/or Warunek2 (...)]

Oczywiście można zagnieżdżać w wyrażeniu kolejne tagi, jak również łączyć je operatorami. Każdy wpis w logu systemowym, który spełni wszystkie warunki zostanie pokazany w odfiltrowanym widoku.
Przedstawię jeszcze raz filtr, który pojawił się na początku. Zostanie on sformatowany w trochę inny sposób, należy jednak pamiętać, że query powinno być zapisane w jednej linii.

1
2
3
4
5
6
7
8
9
10
11
12
*[
    System[
        Correlation[
            @ActivityID='{8A348658-802A-4ACB-A855-1CC57EA25B18}'
        ]
        and (Level=1  or Level=2 or Level=3 or Level = 4)
        and TimeCreated[
            @SystemTime&gt;='2016-11-27T15:11:00.000Z'
            and @SystemTime&lt;='2016-11-21T15:12:00.000Z'
        ]
    ]
]
  1. Linia query mówi, że wyszukiwania należy wykonywać w dowolnych node’ach najwyższego rzędu. Tak naprawdę chodzi o node
  2. Linia nakazuje przeszukać Tag . W ten sam sposób można się odnieść do sekcji
  3. Linia nakazuje przeszukać Tag , który znajduje się wewnątrz tagu
  4. Linia definiuje warunek, w którym przyrównujemy wartość atrybutu o nazwie ActivityID do określonego ciągu znaków
  5. Linia zamyka listę warunków sprawdzanych w obrębie tagu
  6. Linia definiuje warunek sprawdzający zawartość tagu nie posiadającego żadnych subtagów, tylko wartość.
  7. Linia i kolejne definiują warunek w obrębie tagu i odnoszą się do dwóch atrybutów tego tagu.

Wprowadzenie do Failover Cluster Generic Script Resource

Dzisiaj chciałbym poświęcić trochę miejsca bardzo słabo udokumentowanej funkcjonalności Klastra.
Skrypty zasobów generycznych (Generic Script Resource) umożliwiają uruchomić w środowisku klastrowym nawet bardzo skomplikowane z punktu widzenia startu i potrzebnych zasobów usługi, które nie mają wbudowanych mechanizmów zapewniających wysoką dostępność.
W systemie Windows Failover Cluster umożliwia tworzenie skryptów zarządzających stanem zasobów JEDYNIE w języku Visual Basic (VBScript).
Ponieważ jest to technologia archaiczna, to powstały różne skrypty dostępne w sieci, służące do wywoływania innych narzędzi skryptowych. Ja posłużę się wersją uruchamiającą skrypty Powershell, gdyż jest to najlepszy obecnie dostępny język skryptowy dla systemu Windows.
Jednak, zanim dojdziemy do przedstawienia właściwych rozwiązań, chciałbym omówić filozofię tworzenia takich skryptów.
W środowisku klastrowym każdy zasób ma swojego właściciela (Owner Host). Jest host, na którym w danym momencie uruchamiany jest kod odpowiadający za obsługę zasobu. Celowo piszę „kod odpowiadający za obsługę”, gdyż może być to trojaki typ kodu:

  1. Manager Usług
  2. Biblioteka DLL zarządzająca zasobem (na przykład maszyny wirtualne)
  3. Skrypt zasobu generycznego

Po prawdzie, to implementacja zarówno managera usług jak i zasobu skryptu generycznego jest wewnętrznie realizowana przez odpowiednią DLL, ale rozróżnienie to jest przydatne dla administratorów i wdrożeniowców mających zdecydować, w jaki sposób należy zapewnić wysoką dostępność.

Cykl życia zasobu można opisać pewnymi etapami, które są charakterystyczne dla każdego właściciela. Należą do nich:

  1. Inicjalizacja managera zasobu (Open)
  2. Uruchomienie zasobu (Online)
  3. „Obejrzenie stanu zasobu” (LooksAlive)
  4. Sprawdzenie stanu zasobu (IsAlive)
  5. Wyłączenie zasobu (Offline)
  6. Zniszczenie zasobu (Terminate)
  7. Zamknięcie managera zasobu (Close)

Nazwy funkcji Callback implementowane w skrypcie zasobu Podane zostały w nawiasach.
Istotne jest wyjaśnienie różnicy między LooksAlive a IsAlive, gdyż na pierwszy rzut oka wydaje się to być dość nietypowe rozwiązanie. Callback LooksAlive jest wywoływany często, żeby zmniejszyć możliwie najbardziej czas reakcji na ewentualną awarię. Czas wykonania tego callback’a jest ograniczony do 300ms.
Dopiero, gdy ta funkcja zwróci błąd wywoływana jest funkcja IsAlive.
Ponadto raz na około minutę wywoływana jest funkcja IsAlive niezależnie od opisanego powyżej mechanizmu. Wynika to z pryncypium szybkiego wykonania LooksAlive, a w konsekwencji pobieżnego sprawdzenia, które może coś (celowo, lub nie) przeoczyć.
Dlatego manager klastra i tak sprawdza pełną diagnostykę zasobu raz na minutę. Jest to na tyle nieduży czas, że jeszcze akceptowalny dla większości usług, a z drugiej strony jest on na tyle duży, że nie wprowadza znacznego obciążenia do systemu „władającego” usługą.
Pozostałe funkcje callback ze skryptu nie wymagają dłuższego omówienia.

Bardzo ważną sprawą do omówienia, gdyż z tym się mogą wiązać błędu i w konsekwencji problemy z uruchomieniem, jest kwestia zmiennych zasobu. Każdy zasób może (i powinien) przechowywać swój stan konfiguracji w przestrzeni klastra – dzięki temu unikniemy sytuacji, w której usługa będzie zachowywać się niespójnie na różnych hostach-właścicielach zasobu.
Istotnym jest, aby definiować zmienne zasobu na samym zasobie skryptu, a nie na grupie zasobów, czy też na zasobie adresu ip albo jakimkolwiek innym zasobie w grupie. Tylko zmienne zasobu skryptu (czyli zdefiniowane dla instancji typu Generic Script Resource) będą dostępne przez Api Klastra.

API klastra reprezentowane jest przez obiekt VBScript o nazwie

1
Resource

Przykład użycia tego obiektu prezentuje poniższa funkcja:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Function CheckProperties(ActionName, ErrorBaseCode)
    If Resource.PropertyExists("DebugVBA") = False Or Resource.PropertyExists("DebugPS") = False Then
        WshShell.LogEvent 1, "No Debugging Settings! Exiting."
        CheckProperties = ErrorBaseCode+1
        Exit Function
    End If
    LogEvent 4, "Enter " & ActionName & "()"
    If Resource.PropertyExists("PSScriptsPath") = False Then
        LogEvent 1, "Error " & ActionName & "(). No PSScriptsPath private property. Exiting."
        CheckProperties = ErrorBaseCode+2
        Exit Function
    End If
    If Resource.PropertyExists("QueueIndex") = False Then
        WshShell.LogEvent 1, ActionName & "(): No Cluster Queue Definition! Define QueueIndex private property. Exiting."
        CheckProperties = ErrorBaseCode+3
        Exit Function
    End If
    CheckProperties = 0
End Function

Windows Terminal Services Logon „Access Denied”

Dzisiaj przedstawię rozwiązanie problemu z Usługą Terminalową w środowisku z odrębnym serwerem Licencji Terminalowych.

Symptomy:

  • W trakcie logowania użytkownik otrzymuje komunikat „Access denied.”. Wyświetlany jest on zamiast ekranu logowania po uprzednim komunikacie „Welcome”.
  • W logu aplikacyjnym i systemowym nie występują żadne informacje o błędach, lub są one ewidentnie niezwiązane z podstawowym objawem.
  • W logu TerminalServices-LocalSessionManager występuje następujący wpis skorelowany z próbą logowania użytkownika: „Session X has been disconnected, reason code 12”, gdzie X oznacza numer sesji przydzielony konkretnej próbie logowania.
  • Problem ten dotyka zarówno systemy windows 2008 R2 jak i 2012 (R2).
  • Często towarzyszy tej sytuacji brak możliwości wymuszenia GPO

Tymczasowym rozwiązaniem problemu może być wykonanie dodatkowego wpisu w rejestrze:

1
2
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\
IgnoreRegUserConfigErrors (DWORD) = 1

Po dodaniu tego wpisu konieczne jest ponowne uruchomienie komputera.

Po zażegnaniu kryzysu związanego z brakiem możliwości pracy użytkowników na spokojnie można przystąpić do diagnostyki, co się zepsuło tak naprawdę.
W tym konkretnym przypadku przyczyną był błędnie skonfigurowany Firewall na kontrolerach domeny przy użyciu GPO, gdzie był zabroniony ruch „SMB over TCP”.
Przyczyn należy w każdym razie szukać w otoczeniu kontrolerów domeny.

Failover Cluster Generic Script Resource Failed 0x80070009

Witajcie,

Dzisiaj chciałbym się podzielić spostrzeżeniem mocno nieintuicyjnego zachowania funkcjonalności Failover Clustering w Windows 2012 R2.
Mianowicie, może się zdarzyć, że po przygotowaniu skryptu kontrolującego zachowanie aplikacji (Generic Script), której chcemy zapewnić wysoką dostępność i po konfiguracji zgodnie z tym blogiem Zespołu produktowego Microsoft zasób klastra nie zostanie uruchomiony, a status zasobu będzie zawierał informację

1
The storage control block is invalid.

Przedstawia to poniższy zrzut ekranowy:
Status zasobu klastrowego
Kiedy zgodnie z sugestią z komunikatu o błędzie wyświetlimy rozszerzoną informację o błędzie uzyskamy informację o kodzie błędu

1
0x80070009

Rozszerzona informacja o błędzie
Podobny wpis zostanie odłożony w logu systemowym klastra:
Log systemowy klastra

W takiej sytuacji należy przede wszystkim się upewnić, że przygotowany przez nas skrypt nie zwraca z żadnego wywołania API wartości 0x9.
Gdy posiadamy taką pewność, to błąd ten oznacza, że skrypt Visual Basic ma niepoprawną składnię i menedżer zasobów klastra nie był w stanie prawidłowo go skompilować.
Dlatego dobrą praktyką jest przed utworzeniem zasobu klastrowego weryfikacja poprawności kompilacji skryptu. W tym celu należy wydać polecenie z linii poleceń:

1
cscript.exe C:\pełna\ścieżka\do\pliku.vbs

Ponieważ skrypt zawierać powinien same definicje funkcji, a nie ma żadnych ich wywołań (cecha charakterystyczna wywołań zwrotnych – „CallBack”), to prawidłowo napisany skrypt nie powinien nic wykonać ani wyświetlić.
W przypadku nieprawidłowej walidacji wynik będzie podobny do poniższego zrzutu ekranu:
Błąd walidacji skryptu

Pozdrawiam serdecznie i życzę samych poprawnych skryptów!

Migracja zasobów między subskrypcjami w MS Azure

W chmurze Microsoft Azure użytkownik może posiadać dowolną liczbę subskrypcji. Subskrypcja jest najmniejszą jednostką konfigurującą sposób płatności i zakres własności zasobów.
Każda subskrypcja generuje swój osobny Billing. Nie ma żadnego znaczenia w tym przypadku fakt, że jeden użytkownik, czy organizacja jest właścicielem subskrypcji. Jedna subskrypcja, jeden rachunek. Istnieje wyjątek w postaci umów typu Enterprise, gdzie ten model jest bardziej skomplikowany, ale ten temat zostawiamy na boku.
Istotne jest to, że będąc indywidualnym właścicielem kilku subskrypcji, można dostać na przykład 3 rachunki opiewające na 2 euro. To potrafi być irytujące.
Dlatego zaistniała potrzeba połączenia subskrypcji ze sobą.
Jedną metodą, jaka jest dostępna w Azure, na wykonanie takiej akcji jest migracja zasobów do jednej z subskrypcji i odwołanie pozostałych. W sieci można znaleźć dużo pytań na ten temat, jednak mało która odpowiedź jest konkretna. Okazuje się jednak, że rozwiązanie jest bardzo proste i wspierane. Opisane dokładnie w szczegółach jest w tym artykule.
Tutaj tylko przytoczę informację o tym, że możliwość migracji jest uzależniona od konkretnego typu zasobu i niektóre zasoby posiadają pewne ograniczenia w przenoszeniu.
Pełna lista zasobów wspierających przenoszenie dostępna jest tutaj.

Instalacja Service Pack 1 dla Windows 2008 R2 poprzez MDT 2010 U1

Dzisiaj będzie rzecz o tym, jak czasem korzystanie z manuala potrafi byc zwodnicze.
Normalnym jest, że jak się dostaje aplikację, którą potrzebujemy wywołać w sposób bardziej fikuśny, niż prosty „dwuklik” to wywołujemy

1
aplikacja.exe /?

albo

1
aplikacja.exe /help

W odpowiedzi dostajemy w dowolnej formie informacje dotyczące przełączników dostępnych w linii poleceń. W szczególności w takiej formie otrzymujemy informacje dotyczace uruchamiania różnych komponentów aktualizujących system Windows.
Instalator Dodatku Service Pack 1 dla Windows 2008 R2 odpowiada w ten sposób:
Okno Dialogowe z pomocą dla linii komend instalatora SP1 dla Windows 2008 R2
Akcją konieczną do wykonania żeby komponent Microsoft Deployment Toolkit był w stanie zaimportować dodatek jako pakiet systemowy jest rozpakowanie pliku .exe do postaci pliku Standalone Update (.msu lub .cab). Jak widzimy na przytoczonym zrzucie ekranowym producent nie przewidział takiej akcji.
Jednakże po kilku nieudanych próbach stwierdziłem że wywołanie:

1
 windows6.1-KB976932-X64.exe /extract

Nie spowodowało zwrócenia błędu niepoprawnej komendy, natomiast pod oknem interpretera linii poleceń pojawiło się okno dialogowe z wyborem lokalizacji dla wyodrębnionych plików. Znajduje się wśród nich plik .cab, który jest konieczny przy użyciu MDT 2010 U1

Ciekawi mnie tylko, dlaczego Microsoft nie dodał tego przełącznika do manuala.

Układ współrzędnych w Mailach, czyli jak odpisywać LOGICZNIE

Przed chwilą odbyłem z moim przyjacielem TeMPOraLem Dyskusję na temat konwencji odpisywania na wiadomości email, a także o kierunku sortowania danych opatrzonych czasem.

Moim stanowiskiem jest odpowiadanie na górze, a także umieszczanie najświeższych informacji u góry strony/zasobu. Nie przemawia do mnie argument, że książki czytamy z góry na dół, gdyż książki nie są zawartością dynamiczną. Uważam, że sieć jest bardzo elastyczną strukturą, potrzebujemy najważniejsze i najświeższe informacje, a co za tym idzie dostęp do nich powinien być maksymalnie uproszczony.
Historia jest także bardzo ważnym elementem życia onLine, gdyż pozwala jednoznacznie określić ewentualne drobiazgi i przebieg jakiejś aktywności. Jednak jest to tylko w celach dokumentacyjnych. Życie toczy się tak szybko, iż ogarniamy najpilniejsze sprawy. Pamiętamy co było w liście/smsie/rssie godzinę czy dwie temu. Interesuje nas aktualny stan rzeczy dostępny w taki sposób, aby nie musieć się zastanawiać GDZIE on jest. Powinien być, jak mówi jedna Bardzo Ważna dla mnie Osoba „Na Oczach”. Takie ułożenie daje sortowanie malejące względem czasu. Najaktualniejsze dane są na wierzchu.

Argument że wiadomości powinny być posortowane rosnąco względem czasu można jeszcze przyjąć pod dyskusję, gdy ktoś uważa, że zawsze potrzebuje całą informację aby być wstanie przyswoić i zrozumieć aktualną wiadomość. Jednakże poglądu, że powinno się odpowiadać w treści czyjegoś komunikatu „cytując” jedynie, w żaden sposób nie potrafię uzasadnić jako rozsądne. Wyrywa się ułamki wypowiedzi z kontekstu, często bardzo podobnego gdy się dyskutuje niuanse zagadnienia, stąd łatwo o pomyłki w interpretacji. A kiedy konwersację prowadzi więcej osób, to bez zaawansowanego systemu śledzenia cytatów (zagadnienie: kto na co odpowiedział) cała energia czytającego/śledzącego zostaje zmarnowana na dojście do tego, kto jaki pogląd prezentuje.

Na koniec drobne pytanko do wszystkich którzy preferują ułożenie „najnowsze na dole”. Czy swój telefon komórkowy, tudzież klienta poczty elektronicznej przestawili na to, aby sam spis wiadomości był także samo posortowany? Z tego co wiem, wszystkie serwisy webowe obsługujące pocztę pokazują najnowsze wiadmości na górze. Telefony komórkowe tak samo. Readery rss podobnie. Klienty poczty elektronicznej także potwierdzają moją tezę.

To dlaczego na siłę zmieniać od dawna ubite szlaki kosztem szybkości dostępu w imię dziwnej filozofii ?