mój zewnętrzny IP

Windows_PowerShell_icondość częste pytanie, jak się ma dynamiczny adres IP. najłatwiej oczywiście wejść na jakąś stronę, która ten adres pokazuje. ale lepiej napisać sobie skrypt (:

nie jest to skomplikowane, wystarczy użyć invoke-webRequest, który jest świetną przeglądarką textową. do testów wybrałem stronę 'http://whatismyipaddress.com’ ale można wybrać dowolny inny. po wejściu od razu widzę, że jestem przekierowany na 'http://whatismyipaddress.com/pl/moj-ip’. żeby oszczędzić sobie trochę grzebaniny robię inspekcję elementu, gdzie jest adres i widzę. że jest to DIV o ID=’section_left’. można to olać, ale przyda się żeby trochę zawęzić wyszukiwanie.

teraz z linii poleceń.

C:\...ive\_ScriptZ :))o- $page=invoke-WebRequest http://whatismyipaddress.com/pl/moj-ip

na początek trzeba się zaznajomić z obiektem więc warto sprawdzić:

C:\...ive\_ScriptZ :))o- $page

StatusCode        : 200
StatusDescription : OK
Content           : <!doctype html>
                    <html lang="pl">
                    <head>
                        <meta charset="utf-8">
                        <meta name="robots" content="noarchive">
                        <title>What Is My IP Address? NarzÄ?dzia do adresA3w IP i nie tylko</title>
                        <meta name="desc...
<CUT>

C:\...ive\_ScriptZ :))o- $page|gm
   TypeName: Microsoft.PowerShell.Commands.HtmlWebResponseObject

Name              MemberType Definition
----              ---------- ----------
Dispose           Method     void Dispose(), void IDisposable.Dispose()
Equals            Method     bool Equals(System.Object obj)
GetHashCode       Method     int GetHashCode()
GetType           Method     type GetType()
ToString          Method     string ToString()
AllElements       Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection AllElements {get;}
BaseResponse      Property   System.Net.WebResponse BaseResponse {get;set;}
Content           Property   string Content {get;}
Forms             Property   Microsoft.PowerShell.Commands.FormObjectCollection Forms {get;}
Headers           Property   System.Collections.Generic.Dictionary[string,string] Headers {get;}
Images            Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection Images {get;}
InputFields       Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection InputFields {get;}
Links             Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection Links {get;}
ParsedHtml        Property   mshtml.IHTMLDocument2 ParsedHtml {get;}
RawContent        Property   string RawContent {get;set;}
RawContentLength  Property   long RawContentLength {get;}
RawContentStream  Property   System.IO.MemoryStream RawContentStream {get;}
Scripts           Property   Microsoft.PowerShell.Commands.WebCmdletElementCollection Scripts {get;}
StatusCode        Property   int StatusCode {get;}
StatusDescription Property   string StatusDescription {get;}

polecam sprawdzić jeszcze $page.links oraz $page.images – może się kiedyś przydać. po wykonaniu

$page.AllElements|? id -eq 'section_left'

będzie już widać kawałek interesującego kodu. teraz trzeba wyłowić IP. do tego celu warto zrobić wyrażenie regularne, bo do tego są niezastąpione. np. takie super-proste, które po prostu szuka czterech liczb oddzielonych kropką, gdzie każda liczba ma od 1-3 cyfr:

[regex]$rxIP="\d{1,3}[.]\d{1,3}[.]\d{1,3}[.]\d{1,3}"

do celów skryptu można by się poważyć o napisanie porządnej walidacji, czyli dodatkowo, żeby te liczby miały wartości od 1-255. ale to nie ten wpis. po przepuszczeniu wyniku będzie wyświetlone IP:

C:\...ive\_ScriptZ :))o- $page.AllElements|? id -eq 'section_left'|%{ write-host -ForegroundColor Yellow $rxIP.Match($_.outerText)}

można teraz się dalej bawić, potestować na innych stronach, analizując elementy zwracanej strony. nie takie trudne (:

eN.

Jak szybko wygenerować certyfikaty dla Always On

Zadanie niby trywialne – skonfigurować TLS na SQL Server z grupami Always On. Chwila szukania i wiem co musi mieć template certyfikatu. https://technet.microsoft.com//en-us/library/ms189067(v=sql.105).aspx#Anchor_2 mówi, że jest potrzebne m.in.

The certificate must be meant for server authentication. This requires the Enhanced Key Usage property of the certificate to specify Server Authentication (1.3.6.1.5.5.7.3.1).

Pech chciał, że akurat miałem pasujący template, który poza tym pozwalał na client authentication i postanowiłem go użyć. Niestety takie podejście okazało się skuchą bo certyfikat musi mieć wyłącznie OID 1.3.6.1.5.5.7.3.1 . Jeśli pojawi się cokolwiek innego to koniec, kaplica, bez szans. SQL go nie uzna i nie pozwoli na użycie do szyfrowania połączeń. Z punktu widzenie bezpieczeństwa ma to sens ale mogło by się gdzieś w dokumentacji pojawić, że leniuchy będę musiały stracić czas na zastanawianie się czemu nie działa. Koniec końców, całkiem nieźle sprawdziłPKI się standardowy template Web Server :-)

Drugim problemem dla leniwego admina pojawia się wygenerowanie requestów z wszystkim nazwami listenerów (purystów przepraszam za moją hiperniepoprawną polszczyznę) na wszystkich serwerach. https://msdn.microsoft.com/en-us/library/hh213417.aspx#SSLcertificates bardzo ładnie podaje, że temat certyfikatu to hostname bądź fqdn serwera a SAN musi zawierać wszystkie nazwy DNSowe listenerów (zarówno skrócone jak i fqdn). I tu pojawiają się dwa problemy (korporacyjnie: wyzwania) bo po pierwsze serwerów jest dużo a po drugie każdy z nich ma po kilkanaście listenerów. Jako, że nie chce mi się tyle klikać w GUI a tym bardziej nie chcę zrobić nigdzie literówki, piszę coś takiego i paroma linijkami kodu ratuję sobie resztę dnia ;)

#import SQL PS module
ipmo sqlps

#get all availability groups
#
#  Replace HOSTNAME and INSTANCE with correct names
#

$allag = Get-ChildItem SQLSERVER:\SQL\HOSTNAME\INSTANCE\AvailabilityGroups

#Get list of all Subject Alternative Names
# (FQDNs and short names of all listeners)

[String[]] $listeners = @()
$allag | Select-Object Name | %{$listeners += ($_.Name + "." + $env:userdnsdomain); $listeners += $_.Name }
$fqdn = ([System.Net.Dns]::GetHostByName(($env:computerName)).HostName) 


#Add server's hostname and FQDN to SANs
$listeners += $env:computerName
$listeners += $fqdn.ToString()

#Set subject as server's FQDN 
[String]$subject = ("CN=" + $fqdn)

#Request certificate
Get-Certificate -Template WebServer -SubjectName $subject -DnsName $listeners -CertStoreLocation cert:\LocalMachine\My

 

słowo o prywatności

privacytaka anegdotka na chwilę refleksji…

oddałem ostatnio stare kasety VHS i Hi8 do dygitalizacji. przed przekazaniem zapytałem, czy dostanę jakiś certyfikat, zapewniający, że materiał nie zostanie skopiowany ani wykorzystany bez mojej wiedzy. pan się uśmiechną, pokiwał głową i powiedział

'wie Pan, przez tyle lat przychodziło tu tyle osób, nawet jacyś ambasadorzy, osoby publiczne…. i nikt nigdy nie prosił o takie zaświadczenie…’

eN.

 

nieautoryzowany email do zmiany hasła office365

ciekawy przypadek

firma X qpiła klientowi licencje i założyła tenant office365. projektu nie zrealizowała i przeszedł na nas. pozmienialiśmy wszystkie dane, przepięliśmy konto Global Admina, łącznie z 'aternative mail address’. można to zrobić z interfejsu, a z PS wygląda to tak:

PS C:\_ScriptZ> Connect-MsolService -cred $creds
PS C:\_ScriptZ> Get-MsolUser -UserPrincipalName admin@domain.onmicrosoft.com|select *mail*

AlternateEmailAddresses
-----------------------
{admin.email@server.com}

i niby wszystko załatwione….

ale zupełnie przypadkiem postanowiłem sprawdzić zmianę hasła i moim oczom ukazało się:

Microsoft Online Password Resetprzy czym ten drugi adres, należał do osoby z firmy X.

przeczesałem wszystkie znane miejsca i nigdzie tego adresu nie ma. w panelu o365 również widać tylko podstawowy.

o365 support

bardzo rozczarowało mnie wsparcie o365. wysłałem ticket jako partner obsługujący klienta, z oznaczeniem 'critical – security breach’. przy każdej wymianie korespondencji były mi proponowane te same kroki, te same pytania, wysłałem screenshoty, wysłałem PSR (problem steps recoder) i nadal dostawałem instrukcję jak zmienić email przez portal o365. po kilq mailach ticket został zamknięty z informacją mniej-więcej 'ten problem to nie problem’.  nie było eskalacji, po prostu nie potrafił rozwiązać to zamknął. łoś.

rozwiązanie

trochę mi zajęło, ale znalazłem miejsce, gdzie zapisany został drugi adres. trzeba założyć AzureAD [tak na prawdę pod spodem i tak się zakłada, ale cały portal manageazure jest nieaktywny], wyedytować właściwości domeny, włączyć usługę 'Reset Password’ i przejść do skonfigurowania maila. okazuje się, że jest to oddzielna baza, do której nie ma innego dostępu [?]. poniżej kroki w obrazkach:

  • założenie portalu AAD

EnterAzureAD

  • Przejście do konfiguracji domenyResetPassword00
  • włączenie Reset Password. następnie trzeba przejść na stronę gdzie można skonfigurować dane [zaznaczone]ResetPassword01
  • i już widok samej strony gdzie są skonfigurowane daneResetPassword02

eN.