nieaktywni użytkownicy EntraID

w AD sprawa była prosta… no może nie tak bardzo prosta, bo historia atrybutów lastLogon i lastLogonTimeStamp też ma swoje drugie dno, ale od wielu lat wiadomo jak aktywność użytkownika zbadać… i pojawiła się Chmura i hybryda, która całość skomplikowała…

przez wiele lat nie było prostego sposobu na zapytanie 'wyszukaj nieużywane konta’, ponieważ nie było w EntraID odpowiednika lastLogonTimeStamp i trzeba było każdy system badać na dziwne sposoby. wedle Microsoft, należało odpytać logu audytu, który miał standardowo 3o dni.. wielce przydatne. nie drążąc dalej historii, od kwietnia 2o2o GraphAPI produkcyjnie obsługuje ’signInActivity’ – w końcu atrybut/zasób, który jest automatycznie aktualizowany ostatnią datą uwierzytelnienia.

uwaga. atrybut może mieć do 6h opóźnienia w aktualizacji

jak odpytać

kilka przykładów jak przygotować sobie raport, korzystając z commandletów Microsoft.Graph

wyświetlenie wszystkich użytkowników, wraz z ich mailem oraz datą ostatniej aktywności:

Get-MgUser -Property displayname,mail,signInActivity -all|
    select displayname,mail,@{L='signin';E={$_.SignInActivity.LastSignInDateTime}}

korzystanie z commandletów graphowych nie jest przyjemne i wymaga cierpliwości. większość operacji, ze względu na optymalizację, nie wyświetla prawie żadnych atrybutów – dla tego trzeba wyraźnie zaznaczyć w 'property’ czego będzie się potrzebowało.

trochę bardziej złożony raport, wyrzucany na csv, zawierający dodatkowo informacje o licencjach:

Get-MgUser -Property id,displayname,givenname,surname,accountenabled,userprincipalname,mail,signInActivity,userType -all|
    select id,displayname,givenname,surname,accountenabled,userprincipalname,userType,mail,`
    @{L='signin';E={$_.SignInActivity.LastSignInDateTime}},`
    @{L='licenses';E={(Get-MgUserLicenseDetail -UserId $_.id).SkuPartNumber -join ','}}|
        export-csv -nti c:\temp\EntraUsers.csv -Encoding utf8

co mnie denerwuje w tych commandletach, to że nie są przyjmują w prosty sposób obiektów, np to nie zadziała:

get-mgUser -all|get-mgUserLicenseDetail

to było abecadło PS, ale wzięli się za to developerzy webowi i taki efekt… trzeba też zawsze pamiętać o dodaniu 'all’ bo standardowo jest paging na 1oo obiektów.

i jeszcze drobny przykład na użycie filtra. nie jest co prawda widoczne w helpie od get-mgUser ale to jest filtr OData – z którego ogólnie korzysta cały Graph. tutaj prosty filtr, żeby wyświetlić tylko konta typu guest. nie podjąłem się filtrowania po dacie w OData bo to by kosztowało mnie za dużo czasu na rozkminkę – operacje na datach nie są oczywiste, a PowerShell sobie świetnie z tym radzi:

Get-MgUser -Filter "userType eq 'guest'" -Property displayname,usertype,signinactivity|
    ?{$_.SignInActivity.LastSignInDateTime -lt (get-date).AddMonths(-2)}|
    select displayname,usertype,@{L='activity';E={($_|select -ExpandProperty SignInActivity).LastSignInDateTime}}

connect

oczywiście żeby korzystać z commandletów graph trzeba się połaczyć z odpowiednim zakresem (scope). jeśli to jest dla ciebie nadal problemem to koniecznie wrzuć do bookmarków ten link, który opisuje jak użyć Find-MgGraphCommand żeby sprawdzić niezbędne zakresy.

jak Microsoft potrafi strzelić klientom w kolano

ciekawostką jest, że żeby być w stanie odczytać ten atrybut, trzeba mieć minimum EntraID P1 – inaczej wyskoczy błąd:

Get-MgUser_List: Neither tenant is B2C or tenant doesn't have premium license

Status: 403 (Forbidden)
ErrorCode: Authentication_RequestFromNonPremiumTenantOrB2CTenant

…dlaczego? nie chodzi mi o techniczne wyjaśnienie, ale to krzyk w stronę MS – dla czego tak podstawowa funkcjonalność, jak wyszukiwanie nieaktywnych kont, wymaga dodatkowej licencji?

eN.

wyszukiwanie aktywności konta

ostatnimi czasy wróciłem do podstaw… i tak się stało, że duża część moich obowiązków związana jest z bezpieczeństwem. bezpieczeństwo zawsze było istotnym elementem mojej pracy zawodowej, ale zawsze jako dopełniający element, a nie przewodni – czy się zarządza, czy projektuje, zawsze trzeba mieć na uwadze czy środowisko/konfiguracja spełnia odpowiednie normy. wbrew niektórym poglądom środowiska on-premises prędko nie odejdą do lamusa, choć coraz bardziej się odchudzają. a ponieważ klienci, z którymi mam ostatnio do czynienia, nie mają wyszukanych rozwiązań, wszystko trzeba robić 'po staremu’.

podrzucam zatem przydatne komendy, które pomogą w manualnej inwestygacji. przyda się zarówno przy ogólnym audycie ale i w momencie jeśli próbujemy znaleźć gdzie jakieś konto 'żyje’, gdzie jest używane.

Event Log

można przeglądać live i offline. ponieważ jednym z pierwszych kroków jest zabezpieczenie logów i powinno się ograniczać pracę w zagrożonym środowisku, poniższy przykład pokazuje jak przeglądać wyeksportowane logi w poszukiwaniu aktywności użytkownika:

  • logi z DC nie są synchronizowane, każdy DC ma własne, w związku z tym trzeba wyeksportować z każdego oddzielnie. okazało się, że nie każdy to wie, więc tak na wszelki wypadek przypominam…
  • okazuje, nie jest również oczywiste, że logowanie nieudanych prób logowania jest co najmniej tak samo ważne, jak logowanie udanych. nieudane próby mogą świadczyć o próbie bruteforce na kontach albo po prostu próbach nieautoryzowanego dostępu
  • następnie można przeszukać korzystając z Get-WinEvent. problem z obróbka polega na tym, że zwrócony hashtable nie ma ustalonego formatu – zależnie od typu zdarzenia będzie inna ilość pól
  • poniższy przykład obrazuje wyszukiwanie udanych (4624) i nieudanych (4625) zdarzeń logowania dla kont 'account01′ oraz 'account02′
  • nazwy kont są bez domeny, match korzysta z regex więc dowolnie rozbudowywać i wyszukuję po atrybucie 'message’ ponieważ nazwa użytkownika przy tych zdarzeniach jest *zazwyczaj* na 6 pozycji w tablicy.. ale nie zawsze. dzięki przeszukaniu zawartości 'message’ wyłapuje się więcej
$events = Get-WinEvent -Path "C:\incident01\DC01_security.evtx" | Where-Object { ($_.ID -eq 4624 -or $_.ID -eq 4625) -and $_.message -match 'account01|account02'}
$events += Get-WinEvent -Path "C:\incident01\DC02_security.evtx" | Where-Object { ($_.ID -eq 4624 -or $_.ID -eq 4625) -and $_.message -match 'account01|account02'}
$events += Get-WinEvent -Path "C:\incident\DC03_security.evtx" | Where-Object { ($_.ID -eq 4624 -or $_.ID -eq 4625) -and $_.message -match 'account01|account02'}
$events|%{"{0},{1}" -f $($_.Properties.value -join ','),$_.TimeCreated}|Out-File C:\incident01\events_aggregated.csv

a jak ktoś korzysta z eNLib to jeszcze można sobie ułatwić życie i obejrzeć sformatowane w Excel:

&(convert-CSV2XLS c:\incident01\events_aggregated.csv)

smutną informacją będzie, że klasyczne logi Windows pokazują gdzie nastąpiło uwierzytelnienie… ale nie pokazują skąd – co w przypadku logowania sieciowego jest dużym brakiem, bo znalezienie gdzie takie konto w zasadzie jest używane bywa trudne. przydatna będzie również wiedza dotycząca właśnie typu logowania, a najważniejsze to:

  • Type 2 – klasyczne logowanie lokalne
  • Type 3 – non-interactive, network logon
  • Type 5 – non-interactive, service logon (chyba najtrudniejszy w interpretacji)

żywe elementy systemu

jak na szybko sprawdzić czy coś nie działa w kontekście danego użytkownika?

task scheduler:

Get-ScheduledTask | select TaskName,@{L='context';E={$_.Principal.ID}}|sort context

usługi systemowe:

gcim win32_service|select name,startname|sort startname
oraz procesy:
Get-Process | ForEach-Object {
    $process = $_
    $cimProcess = Get-CimInstance -ClassName Win32_Process -Filter "ProcessId = $($process.Id)"
    $owner = Invoke-CimMethod -InputObject $cimProcess -MethodName GetOwner
    [PSCustomObject]@{
        Name = $process.Name
        Id = $process.Id
        Owner = $owner.User
    }
}
warto zwrócić uwagę na get-CimInstanstance zamiast get-WmiObject – i to trochę będzie zależało od wersji systemu. na bardzo starych Windowsach może być problem z CIM, a na nowych nie działa już gwmi.

Exit

chmury, SIEM, EDR, XDR, MFA, całe to AI i przełomy technologiczne… łatwo zapomnieć że to tylko fragment świata – tego lepiej dofinansowanego, rozwiniętego, technologicznego… ale jest też druga strona. środowiska on-premises, skonfigurowane… mówiąc delikatnie, odbiegając od jakichkolwiek norm i standardów, gdzie klienci nie rozumieją tego co jest potrzebne lub niepotrzebne w środowisku – widzą tylko czy działa aplikacja na ich komputerze i tylko tyle są w stanie ocenić. cała reszta to jakiś techniczny bełkot, którego nie chcą słyszeć… a zazwyczaj również nie bardzo za to płacić.

często zastanawiam się nad tym dysonansem – z jednej strony wydaje się, że technologiczna osobliwość jest tuż tuż i czytam artykuły straszące AI, które przejmie władzę nad światem i kolonizacji Marsa, a z drugiej ta część świata, w której pracują systemy z przed dekad czy te odległe miejsca, w których szczytem technologii jest żarówka i kuchenka gazowa…

eN.

App Registrations vs Enterprise Apps

różnica pomiędzy App Registrations a Enterprise Apps w EntraID niby jest oczywista.. ale po chwili zastanowienia robi się dość niejasna i sprawia problemy. zgodnie z zasadą Feynmana, która mówi, że naprawdę rozumie się tylko to, co potrafi się w przystępny sposób wytłumaczyć, długo miałem z tym problem. niby wiedziałem… ale nie byłem w stanie odpowiedzieć na to pytanie przekonywająco.

normalnie poleciłbym opis mojego ulubionego 'nauczyciela Azure’ – John Savill, ale o ile uważam, że bardzo warto obejrzeć ten wykład, nie do końca dobrze tłumaczy to, co najważniejsze. bardzo fajnie rozkłada na czynniki pierwsze model uwierzytelnienia i autoryzacji i pokazuje workflow podczas uzyskiwania dostępu – a więc arcyważny i ciekawy element… ale prezentacja urywa się tam, gdzie tak na prawdę powinna się zacząć. i kiedy dochodzi już do pokazania praktycznej różnicy pomiędzy App Registrations i Enterprise Apps – czegoś mi zabrakło – zbyt dogłębnie, za mało praktycznie.

to coś, czyli bardziej praktyczne wyjaśnienie tych elementów, znalazłem natomiast tu:

tłumaczy 'po mojemu’ – trochę teorii, trochę praktyki, jak to 'dotknąć’ PowerShell’em i po co to wszystko. to pierwsza z kilku części dotyczących tego tematu (SIC!), co pokazuje, że wcale nie jest taki trywialny i oczywisty – i tak patrząc na inne ich spotkania, jeszcze trochę czasu poświęcę na ich nagrania.

eN.

Classic Administrator – porządki i źle wyświetlane przypisanie

intro

kolejny brzegowy przypadek. tym razem mógł mnie kosztować usunięcie istniejących subskrypcji – a więc 'niuans, który może zabić’.

scenariusz to clean up subskrypcji. jest ich kilkaset, więc trzeba podejść do tematu systemowo. najpierw zajmę się omówieniem scenariusza i moim podejściem do sprzątania, a jak kogoś interesuje sam bug w Azure – to będzie na końcu.

clean up process

w pierwszej kolejności trzeba wyizolować osierocone i puste subskrypcje. o tym jak znaleźć te puste szybko, czyli KQLem – za niedługo, wraz z małym qrsem KQL. dziś o tych 'osieroconych’.

duża część subskrypcji zakładana jest na chwilę, głównie przez developerów, którzy przychodzą i odchodzą…. a subskrypcje zostają. warto więc znaleźć te, których właściciele już nie istnieją w AAD.

nie żeby i tu nie było problemów, bo okazuje się, że zadanie pod tytułem 'jaki to typ subskrypcji’ również okazało się zadaniem nietrywialnym. przez typ, mam na myśli offering. to, co widać w portalu jest trudno wyciągnąć z commandline – potrzeba do tego gimnastyki z REST API do API billingowego… ale to również na inny dzień. krótko mówiąc – tradycyjnie, PowerShellowo, nie da się tego wyłuskać. a jeśli ktoś chciałby mi przedstawić atrybut 'SubscriptionId’ to powiem, że nie tędy droga… ale to również leży w backlogu do opisania.

zadanie wygląda więc tak – zrobić listing wszystkich subskrypcji wraz z osobami które są Ownerami w ARM IAM oraz Classic Administrators – czyli role Service Administrator oraz Co-Administrator.  posłużą zarówno jako lista kontaktowa, oraz pozwolą na kolejne odpytania, żeby wyłuskać te konta, które już nie istnieją. subskrypcje bez właścicieli to najlepsze kandydatki do podróży do śmietnika. posłuży do tego taki prosty skrypcik, napisany na kolanie:

$csvOwnerFile = "c:\temp\subsAndOwners.csv"
Get-AzSubscription |
    ? {$_.state -ne 'disabled'} |
    %{
    $subname= $_.Name
    $subID = $_.SubscriptionId
    Set-AzContext -Subscription $_|Out-Null
    write-host "processing $subname..."
    Get-AzRoleAssignment -IncludeClassicAdministrators |
        ? {
            ($_.RoleDefinitionName -eq 'owner' -or $_.RoleDefinitionName -match 'administrator') -and ([string]::IsNullOrEmpty($_.RoleAssignmentId) -or $_.RoleAssignmentId -match 'subscriptions')
        } | select  @{L='SubscriptionName';E={$subname}},@{L='subscriptionID';E={$subID}},RoleDefinitionName,DisplayName,SignInName,roleassignmentid
} | export-csv -nti -Encoding utf8 -Path $csvOwnerFile

&(convert-CSV2XLS $csvOwnerFile)
większość commandletów jest z pakietu modułów Az, a ostatni – convert-CSV2XLS z mojego modułu eNlib [WOA! przekroczył 1k downloadów! jak miło q:]. zakładam, że całość jest prosta, ale to lepiej wyjaśnić:
([string]::IsNullOrEmpty($_.RoleAssignmentId) -or $_.RoleAssignmentId -match 'subscriptions')
ten fragment filtra wyrzuca uprawnienia dziedziczone z Management Groups, żeby było trochę przejrzyściej.
można się również zastanowić nad optymalniejszą metodą… ale to znów REST API a nie mam na to opanowanych bibliotek jeszcze /: kolejny z masy wpisów na backlogu…
dobra. jest CSV i excel dla czytelności, teraz trzeba sprawdzić czy konta istnieją. w excelu czyszczę, co niepotrzebne, co wiem, co mnie interesuje, export do CSVki z tymi wpisami, które uznałem za ważne, i jedziemy:
$users = load-CSV c:\temp\subsAndOwners.csv
connect-azuread
$users.SignInName | 
    select -unique | %{
      $u=Get-AzureADUser -SearchString $_;
      if([string]::IsNullOrEmpty($u)) {write-host "$_" -ForegroundColor Red}
    }

load-CSV to kolejna funkcja z eNlib – jedna z najczęściej przeze mnie używanych. ładuje CSV z automatyczną detekcją znaq oddzielającego, co jest mega istotne jak się pracuje w różnych regionalsach. ma też kilka innych bajerów… ale nie o tym tu. dalej już z górki – wyłusqję SignInNames unikalne i odpytuję AAD o użytkownika. ponieważ brak użytkownika nie jest błędem, a nullem, więc nie można użyć try/catch a trzeba wykorzystać IFa.

i wydawałoby się że mam już to, co potrzeba – wrzucam wynik do excela, robię XLOOKUP i pięknie widać które subskrypcje należą do kont, których już wśród nas nie ma… zabrzmiało złowieszczo khekhe…

Błąd w Azure

…chyba, żeby nie. całe szczęście natchnęło mnie, żeby jednak kilka posprawdzać ręcznie. i nagle okazało się, że konta których nie ma… czasem jednak są. a wszystko rozbija się o 'Classic Administrators’, który musi wewnętrznie źle komunikować się z ARMem. wiele staje się jaśniejsze, jeśli przyjrzeć się jak takie obiekty są listowane przy 'get-AzRoleAssigment -includeClassic’:

RoleAssignmentName :
RoleAssignmentId :
Scope : /subscriptions/732d1eea-xxxx-xxxx-xxxx-6154fb40f73f
DisplayName : uname@w-files.pl
SignInName : uname@w-files.pl
RoleDefinitionName : ServiceAdministrator
RoleDefinitionId :
ObjectId :
ObjectType : Microsoft.Authorization/classicAdministrators
CanDelegate : False
Description :
ConditionVersion :
Condition :

na pierwszy rzut okiem może wydawać się, że jest ok… ale gdzie jest 'ObjectId’? to jednak tylko pierwsza część problemu. porządki mają to do siebie, że robi się je rzadko. a to oznacza bagaż historii. a w tym bagażu np. projekt standaryzacji nazw użytkowników i zmiana UPNów z gsurname@domain.name na givenname.surname@domain.name. okazuje się, że ten staruszek nie ma mechanizmu odświeżania i pomimo zmiany UPN, czyli de facto SignInName, tutaj pokazuje starą nazwę. a więc przy odpytaniu AAD – nie znajduje usera, pomimo, że ten istnieje.

co ciekawe, jeśli wejdzie się do uprawnień IAM w portalu Azure, każdy user jest aktywnym linkiem, pozwalającym na kliknięcie i przeniesienie do AAD, na szczegóły konta. tak z ciekawości spróbujcie to zrobić dla Classic Administrators…

całe szczęście projekt był zrobiony z głową i stare UPNy zostały jako aliasy mailowe, a więc doprecyzowałem zapytanie:

$users.SignInName |
    select -unique |%{ 
        $u=Get-AzureADUser -Filter "UserPrincipalName eq '$_' or proxyAddresses/any(p:startswith(p,'smtp:$_'))";
        if([string]::IsNullOrEmpty($u)) {write-host "$_" -ForegroundColor Red}
    }

ale co mnie to czasu i nerwów kosztowało…

możliwości filtra AzureADUser też podnoszą ciśnienie… już nie wspominając o tym, że commandlety AzureAD nie wspierają PowerShell 7, a commandlety Az nie wspierają nie działają dobrze w PowerShell 5. mam od razu w głowie 'niezły burdel tam macie, w tym swoim Archosofcie!’

eN.

 

KB5020276 – mała-wielka zmiana

w listopadzie wyszła poprawka, która wpływa na dodawanie komputerów do domeny – KB5020276. dowiedziałem się o niej od klienta z takim komunikatem:

„An account with the same name exists in Active Directory. Re-using the account was blocked by security policy”

pierwszy raz spotkałem się z takim problemem… mały-wielki problem bo zależnie od workflowu, w jaki pojawiają się obiekty w AD, logika może wylecieć. poprawka mianowicie zabrania dodawania komputera jako inna osoba, niż owner obiektu. nie działa nawet delegacja – czyli tworzę obiekt komputera i definiuję, że może go dodać taka-a-taka osoba. a więc jeśli jest automat, który zakłada obiekty i daje komuś uprawnienia do dodania – jest problem.

z jednej strony eliminuje to dość częste problemy z nadpisywaniem sobie wzajemnie obiektów – co zdarza się w większych środowiskach z generycznymi nazwami – np. ktoś zakłada kolejny serwer SQL w lokalizacji ABC i generuje sobie wedle konwencji nazwę ABCWINSQL03 – bo taki wynikał z czegoś kolejny numer… ale niedawno inny dział użył tej samej nazwy w innym projekcie… i serwer poszedł z dymem. może nie takim fizycznym, ale dym na pewno w takiej sytuacji by był (;

z drugiej strony wyłączenie możliwości delegowania dodania komputera bywa kłopotliwe, a w przypadq automatyzacji – trzeba pozmieniać workflowy, co może być dość kosztowne.

eN.

konsola PS7 nie przyjmuje wpisywania

na wczorajszym WGUiSW miałem przyjemność poopowiadać trochę o różnicach pomiędzy PS 5 a 7. krótki 'Snack’ więc nie chciałem targać całego lapka, przygotowałem wszystko na AVD i połączyłem się przez przeglądarkę.

… i tu zaskoczenie. z jakiegoś niewyjaśnionego powodu konsola PS7 nie akceptuje klawiszy przy takim połączeniu. konsola PS5 działa normalnie. co ciekawe – nawet uruchomienie pwsh wewnątrz konsoli PS5 nie pomoga. szczęśliwie dostałem szybkie wsparcie z sali (to chyba Zbyszek? dzięki!) i pomogła sztuczka, którą wykorzystuje się przy podobnym problemie przy konsoli Hyper-V:

uruchomić pwsh z parameterm 'noninteractive'

parametr ten wyłącza wszelkie funkcje interaktywne typu 'read-host’. co zmienia w takim scenariuszu? – drugi w-files. nie potrafię wyjaśnić mechanizmu, ani który blokuje, ani czemu non-interactive pomogło. ale warto pamiętać.

eN.

AzureAD priv preview

funkcje preview można niby włączyć… ale nie wszystkie. niektóre są dostępne – jeśli doda się specjalną flagę.

znalazłem poszukując narzędzia do weryfikacji uprawnień Enterprise Apps. obecnie jest spory śmietnik – apki pojawiają się i po pewnych czasie są trudności z określeniem co do czego ma uprawnienia (globalnie/centralnie).

po włączeniu tej funkcji dostępne  są dodatkowe opcje pozwalające na przejrzenie uprawnień wszystkich aplikacji – niestety brak opcji 'download’. ciekawą funkcją jest również application risk:

próbowałem znaleźć inne opcje, które dzięki tej fladze są dostępne, ale na razie nie trafiłem – zachęcam do poszukania i podzielenia się odkryciami.

eN.

search nie działa

hmmm… nie wiedziałem, że to problem globalny – forbes z pewnymi przymyśleniami – ale piszę bo rozwiązanie jest trywialne, zajmuje 3 min i zadziałało na razie na każdym kompie:

w kluczu HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Search trzeba założyć wartość 'BingSearchEnable’ = 0

i przelogować się.

za to z searchem ogólnie coś się ostatnio dziwnego dzieje i od razu wpływa to na pracę – zarówno zmieinone wyszukiwanie w Outlook działa fatalnie, nie jestem w stanie wyszukać tego, co potrzebuję, jak i OneNote – nie podświetla wyniqw, wyszukuje niepełne frazy… czy to ma związek? czy Bing search jest wykorzystywany pod spodem, w lokalnym wyszukiwaniu? wszystkie arty i krzyki mówią o systemowym, a ja mam takie wrażenie, że z każdym jedynym nie jest dobrze…

eN.

do którego AP podłączyliśmy się w roamingu?

podczas debugowania problemów z siecią warto wiedzieć do którego AP się jest podłączonym. jak jest wiele AP ustawionych w roaming, ciężko stwierdzić. a można to sprawdzić starym, dobrym netsh:

PS C:\_scriptZ> netsh wlan show interfaces

There is 1 interface on the system:

Name : Wi-Fi
Description : Intel(R) Dual Band Wireless-AC 8260
GUID : a061220a-2bc8-492a-a3ff-495223935c04
Physical address : aa:bb:cc:dd:ee:ff
State : connected
SSID : wfiles
BSSID : 11:22:33:44:55:66
Network type : Infrastructure
Radio type : 802.11g
Authentication : WPA2-Personal
Cipher : CCMP
Connection mode : Auto Connect
Channel : 11
Receive rate (Mbps) : 54
Transmit rate (Mbps) : 54
Signal : 99%
Profile : wfiles

Hosted network status : Not available

i tak przy okazji jeszcze jedna przydatna komenda z tego zakresu, która wyświetli wszystkie dostępne AP w okolicy wraz z siłą sygnału i tym, co oferują:

netsh wlan show network mode=bssid

eN.

SkypeOnlinePowershell wywala się błędem o braku VC++ redistributable

exploruję tamat BOTów (super sprawa pod kontem obniżenia kosztów HelpDesk!) i aby zarejestrować BOTa w SfB dla tenanta trzeba zainstalować bohatera tytułowego – Skype for Business Online Connector. pomimo spełnienia wszystkich warunków (prerequisites), instalator wywala się z informacją, że brakuje VS C++ Redistributable. trochę się z tym pomęczyłem, nic nie udało mi się znaleźć na forach, więc trzeba grzebnąć samemu.

główny log nic powiedział, ale w logu *_TenantPowerShell.msi.txt jest coś takiego:

MSI (s) (08:10) [23:39:07:026]: Note: 1: 2262 2: Signature 3: -2147287038 
MSI (s) (08:10) [23:39:07:026]: Note: 1: 1402 2: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64 3: 2 
MSI (s) (08:10) [23:39:07:026]: Note: 1: 2262 2: Signature 3: -2147287038 
MSI (s) (08:10) [23:39:07:026]: PROPERTY CHANGE: Adding PROPERTY_POWERSHELL_V51_INSTALLED property. Its value is '1.0, 2.0, 3.0, 4.0, 5.0, 5.1'.
MSI (s) (08:10) [23:39:07:027]: Skipping action: SetReinstallMode (condition is false)
MSI (s) (08:10) [23:39:07:027]: Doing action: FindRelatedProducts
Action ended 23:39:07: AppSearch. Return value 1.
Action start 23:39:07: FindRelatedProducts.
MSI (s) (08:10) [23:39:07:028]: Doing action: LaunchConditions
Action ended 23:39:07: FindRelatedProducts. Return value 1.
Action start 23:39:07: LaunchConditions.
MSI (s) (08:10) [23:39:09:307]: Product: Skype for Business Online, Windows PowerShell Module -- Skype for Business Online, Windows PowerShell Module installation or uninstallation requires that Microsoft Visual C++ 2017 x64 Minimum Runtime - 14.10.25008 Package is already installed.

no to już blisko rozwiązania… bo wskazana ścieżka nie istnieje. znalazłem wpisy od innych paczek VS redist i na tej podstawie zrobiłem nowy plik reg do obecnej wersji:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64]
"Version"="v14.16.27012.01"
"Installed"=dword:00000001
"Major"=dword:0000000e
"Minor"=dword:00000010
"Bld"=dword:00006984
"Rbld"=dword:00000001

instalator łyknął. gra i buczy (:

eN.