SFTP w PowerShell

Automatyzacja PowerShell i SFTP

O SFTP słów kilka

SFTP, rozwijany jako SSHSSH, Secure Shell, protokół zapewniający bezpieczną komunikację na niezabezpieczonej sieci. Zwykle sprowadza się to do zdalnej konsoli pozwalającej na wykonywanie poleceń. File Transfer Protocol, Secure File Transfer Protocol lub, popularnie, bezpieczny FTP. Tak jak FTP, tak i SFTP służy do zarządzania plikami. Z tą różnicą, że SFTP zapewnia bezpieczny kryptograficznie transfer.

Aplikacje klienckie

Do zarządzania zasobami poprzez SFTP w środowisku Windows można stosować wiele narzędzi. Jest FileZilla, graficzne narzędzie dostępne na wielu platformach (Windows, Linux). Jest PuTTY, szerzej znany jako klient SSH, ale dostępny także dla SFTP pod nazwą PSFTP (psftp.exe). Jest w końcu, moim zdaniem najpopularniejszy i najwygodniejszy w obsłudze, WinSCP. Najwygodniejszy, bo posiada graficzny interfejs użytkownika. Elastyczny, bo umożliwia wykonywanie zadań z linii poleceń. Co więcej, biblioteka, dostępna dla środowiska .NET, może być dołączana do własnych aplikacji i, co najbardziej teraz istotne, ładnie integrująca się z PowerShell.

Wymagania wstepne

Aby ustanowić połączenie SFTP musimy pobrać biliotekę WinSCPnet.dll. Jeżeli mamy już zainstalowaną plikację WinSCP, możemy ją znaleźć w katalogu instalacyjnym. W moim przypadku jest to:

C:\Program Files (x86)\WinSCP\WinSCPnet.dll

Jeżeli nie mamy WinSCP, można tę bibliotekę pobrać z Internetu, najlepiej bezpośrednio ze strony WinSCP. W momencie pisania tego akapitu była to podstrona Downloading and Installing WinSCP .NET Assembly.

Ostatni etap to pobranie parametrów połączenia:

  • Adresu serwera z plikami
  • Nazwy użytkownika
  • Hasła użytkownika
  • Skrótu klucza hosta

Adres, login i hasło nie wymagają wyjaśnień i powinniśmy je dostać od administratora. Ta ostatnia wartość może być zakakująca, ale i tę wartość powinien nam dać administrator. Więcej informacji można znaleźć na stronie WinSCP. Poniżej zamieszczam tylko krótki wycinak:

You should get an SSH host key fingerprint along with your credentials from a server administrator. Knowing the host key fingerprint and thus being able to verify it is an integral part of securing an SSH connection. It prevents man-in-the-middle attacks.

Wartość ta jest pochodną publicznego klucza serwera SFPT i jest taka sama dla wszystkich użytkowników. Jeżeli administrator tej wartości nie poda, można ją skopiować od innych użytkowników - będzie zawsze taka sama.

PowerShell

Po uzyskaniu wszystkich parametrów, samo połączenie jest już proste:

Add-Type -Path 'WinSCPnet.dll'
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Sftp
    HostName = "myserver.com"
    UserName = "MyLogin"
    Password = "MyP@ssłorD"
    SshHostKeyFingerprint = "ecdsa-sha2-nistp256 256 23:22:6f:dd:23:de:12:90:ff:ab:09:18:28:11:90:0e"
}

$session = New-Object WinSCP.Session
try
{
    $session.Open($sessionOptions)
    $session.ListDirectory("/subfolder").Files | ft
}
finally
{
    $session.Dispose()
}

W wyniku wykonania tego skryptu, oczywiście w zależności od zawartości systemu plików, możemy otrzymać mniej więcej taką odpowiedź:

Name      FullName             FileType Length Length32 LastWriteTime       FilePermissions Owner Group IsDirectory
----      --------             -------- ------ -------- -------------       --------------- ----- ----- -----------
Plik1.txt /subfolder/Plik1.txt        -   1315     1315 2018-06-21 09:22:21 rw-rw-r--       1017  100         False
FOLDER1   /subfolder/FOLDER1          d      0        0 2018-06-26 10:16:24 rwxr-xr-x       1017  100          True
FOLDER2   /subfolder/FOLDER2          d      0        0 2016-09-28 16:53:55 rwxr-xr-x       1017  100          True
(kolejne pozycje)

W pokazanym przykładzie użyta została metoda ListDirectory. Po otwarciu sesji i przed jej zamknięciem do naszej dyspozycji pozostaje znacznie więcej metod: GetFiles, PutFiles, RemoveFiles czy CreateDirectory. Dzięki mechanizmowi podpowiadania składni wystarczy wpisać $session, potem kropkę i uzyskać całą listę możliwości. Wszystko opisane jest w dokumentacji, ale w większości przypadków same nazwy dość jasno określają przeznaczenie metod.

Zobacz cały wpis: SFTP w PowerShell

Kategoria:PowerShell

Oracle 32-bit i 64-bit na jednym serwerze

Dwie wersje bibliotek - x86 i x64 - na jednym komputerze

Źródło problemu

Przejście procesorów z architektury 32-biowej na 64-botową niesie za sobą szereg konsekwencji. To co w głównej mierze decyduje o braku możliwości pogodzenia bibliotek 32-bitowych i 64-bitowych to rozmiar wskaźnika i możliwości adresowania poszczególnych obszarów pamięci. 32-bitowy wskaźnik nie jest w stanie zaadresować 64-bitowej przestrzeni adresowej, 64-bitowy wskaźnik może wskazywać adres niemożliwy do osiągnięcia przez wskaźnik 32-bitowy.

Tryby kompilacji .NET

Kompilator .NET pozwala wygenerować pliki wykonywalne (ang. PE, zob. format Portable Executable) oraz biblioteki w trzech podstawowych trybach:

  • x86 - pliki z kodem wykonywalnym przeznaczonym dla architektury 32-bitowej,
  • x64 - pliki z kodem wykonywalnym przeznaczonym dla architektury 64-bitowej,
  • AnyCPU - pliki z kodem zarządzanym, niezależnym od architektury, język pośredni (ang. CIL, Common Intermediate Language).

O ile dwa pierwsze tryby mają jasno określoną strukturę, o tyle ten ostatni tryb w przypadku wywołania funkcji natywnych (Win API, COM, itp.) musi samodzielnie obsłużyć różnice w adresacji.

Kombinacje bitowości i ich zgodność

Platforma .NET podczas wczytywania bibliotek zależnych sprawdza, czy istnieje zgodność wersji w następujący sposób:

System 32-bitowy

  • Any CPU uruchamiane jest jako proces 32-bitowy, może wczytywać zależności Any CPU oraz 32-bitowe. Generuje wyjątek BadImageFormatException podczas wczytywania zależności 64-bitowej.
  • x86 uruchamiane jest jako proces 32-bitowy, może wczytywać zależności Any CPU oraz 32-bitowe. Generuje wyjątek BadImageFormatException podczas wczytywania zależności 64-bitowej.
  • x64 Zawsze generuje wyjątek BadImageFormatException.

System 64-bitowy

  • Any CPU uruchamiane jest jako proces 64-bitowy, może wczytywać zależności Any CPU oraz 64-bitowe. Generuje wyjątek BadImageFormatException podczas wczytywania zależności 32-bitowej.
  • x86 uruchamiane jest jako proces 32-bitowy, może wczytywać zależności Any CPU oraz 32-bitowe. Generuje wyjątek BadImageFormatException podczas wczytywania zależności 64-bitowej.
  • x64 uruchamiane jest jako proces 64-bitowy, może wczytywać zależności Any CPU oraz 64-bitowe. Generuje wyjątek BadImageFormatException podczas wczytywania zależności 32-bitowej.

Zależność poza trybem zarządzanym z niezgodnośią bitów

O ile aplikacja w całości pisana w trybie zarządzanym (platforma .NET) działa bezproblemowo w trybie ANY CPU w obu architekturach sprzętowych, o tyle korzystanie z komponentów zewnętrznych wymaga ostrożności. Np. w przypadku sterownika Oracle (Oracle Client) niezgodność bitów może powodować komunikat podobny do poniższego:

Attempt to load Oracle client libraries threw BadImageFormatException. This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed.

Możliwość uruchamiania dwóch wersji na jednym fizycznym komputerze

Instalując sterownik 32-bitowy Oracle pozwalamy na działanie aplikacji tylko w trybie 32-bitowym. Instalując sterownik 64-bitowy pozwalamy na pracę tylko w trybie 64-bitowym. Co zrobić gdybyśmy zechcieli testować i uruchamiać aplikacje w dwóch różnych trybach? Można zastosować dokładnie ten sam mechanizm, który jest stosowany przez Windows.

Zobacz cały wpis: Oracle 32-bit i 64-bit na jednym serwerze

Kategoria:PowerShellWindows

Informacja o pliku wykonywalnym 32/64 bit - PowerShell

Zarządzanie bitowością aplikacji

Ikona mikroprocesora

Procesory 64-bitowe pojawiły się już dawno. Dawno też zaczęły się pojawiać aplikacje 64 bitowe. Na tyle dawno, że obsługa przez systemy operacyjne 64-bitowych procesorów oraz aplikacje kompilowane na 64-bitowe systemy wydaje się naturalna. Ale...

Świat informatyki nie jest jednak tak prosty jak to się architektom wydaje. Aby zapewnić wsparcie starszych aplikacji 32-bitowych 64-bitowe systemy operacyjne pozwalają uruchamiać aplikacje w trybie zgodności i jest to jedna strona. Druga strona to twórcy aplikacji, którzy celowo tworzą aplikacje 32-bitowe aby dało się je uruchamiać również na starszych systemach operacyjnych. W komputerach domowych problem może pozostać niezauważony, a nawet zauważony - zwykle jest ignorowany. W ostateczności pobiera się z Internetu inną wersję pliku. W dużych rozwiązaniach informatycznych tak łatwo nie jest. Jeden plik wykonywalny o nieprawidłowej "bitowości" może sprawić, że całe, nierzadko skomplikowane rozwiązanie, nie uruchomi się. Otrzymamy zwykle dziwne komunikaty postaci Bad image format lub wyjątki BadImageFormatException lub (Murphy był optymistą) jakieś numerki wyglądające jak wytworzone generatorem liczb pseudolosowych.

Nie jest to najczęściej wina systemu operacyjnego tylko konkretnej aplikacji. Plik wykonywalny może być 32-bitowy a jedna z bibliotek 64-bitowa, plik wykonywalny może być 64-bitowy, kilkadziesiąt bibliotek również 64-bitowych a jakis jeden, jedyny 32-bitowy. Nie ma to znaczenia. To nie demokracja, że decyduje większość. Tu liczy się jednomyślność.

Co możemy z tym zrobić? Musimy do tej jedności doprowadzić. Zanim jednak doprowadzimy, musimy takie pliki zlokalizować.

Pobieranie informacji z nagłówka pliku

Pliki *.exe i *.dll nie są tylko ciągiem instrukcji procesora połączonych z danymiTaką strukturę ma plik .com.. Pliki wykonywalne w Windows mają swoją określoną strukturę, która zdefiniowana jest przez format zwany PE (Portable Executable). I znów - wszystko nie jest takie łatwe jak się na początku wydaje. Aby zapewnić zgodnośc wstecz, format ten osadzony jest w innym formacie zwanym MZ (Mark Zbikowski, jeden z twórców DOS). W czasie pisania tego tekstu obecnie wspierane wersje Windows prawie całkowicie ignorują część zawartą w sekcji MZ rozpoczynając interpretację od sekcji PEW praktyce należy zweryfikować poprawność nagłówka (w szczególności dwa bajty zawierające znaki M i Z) oraz wartość wskazującą położenie nagłówka PE (zapisany na czterech bitach i rozpoczynający się na 60 bajcie nagłówka MZ)..

Nagłówek PE rozpoczyna się, a jakże, od dwóch liter P i E, po których występują dwa zerowe bajty. Kolejne dwa bajty określają architekturę procesora:

Bajty (szesnastkowo)Architektura
0x014cx86
0x0200Intel Itanium
0x8664x64

Mogą się tam pojawić jeszcze inne wartości (ARM, Hitachi - odsyłam do specyfikacji formatu PE), ale w środowisku Windows raczej się nie pojawią i nie będą uruchamiane.

To absolutne minimum jakie trzeba wiedzieć, aby dobrać się do informacji o tym, czy plik skompilowany został jako 64-bitowy czy 32-bitowy. Informacja oczywiście dotyczy plików wykonywalnych w środowisku Windows.

Przykładowa implementacja w PowerShell

Uznałem, że takie badania "bitowości" bardziej kwalifikują się do prac administracyjnych. Stąd wybór narzędzia. Przepisanie tego na C++, C# i inne języki powinno być łatwe. Pełny listing zaprezentowano poniżej:

Zobacz cały wpis: Informacja o pliku wykonywalnym 32/64 bit - PowerShell

Kategoria:PowerShellWindows

Pobieranie tabeli z Excela w PowerShell

Najczęściej używane skrypty PowerShell w pracy programisty - ikona konsoli

Tabele w Excelu

Powershell posiada mnóstwo komponentów do importu i eksportu z różnych źródeł danych. To przecież nie tylko zwykłe tekstowe pliki, ale także pliki html (ConvertTo-Html), pliki JSON (ConvertTo-Json, ConvertFrom-Json), pliki CSV (ConvertFrom-Csv, ConvertTo-Csv, Export-Csv, Import-Csv). Wymagania biznesowe często prowadzą jednak w innym kierunku - w kierunku plików bardziej skomplikowanych w strukturze i mniej nadających się do wymiany danych. Analiza frekwencji potrzeb doprowadziła mnie do wniosku, że bardzio potrzebny okazuje się komponent do importu z pliku Excela - *.xlsx. Problem jednak w tym, że w pliku xlsx może być wiele różnych arkuszy, na każdym z arkuszy kilka bloków z danymi. Trudno wymyślić komponent, który pozbiera wszystkie te dane i wyświetli w jakiś łatwy do dalszej analizy i przetwarzania sposób.

Dane biznesowe prezentowane są zwykle w postaci tabelarycznej, a naturalną ich reprezentacją w Excelu są - a jakże - tabele.

Komponent do importu pliku xlsx

Komponent będzie się nazywał, podobnie jak ma to miejsce w przypadku pliku CSV, Import-ExcelTable (poprzez analogię do wymienionego juz Import-Csv). O ile plik CSV zawiera tylko jedną tabelę (tj. jedną porcję danych), o tyle plik *.xlsx może tych niezależnych porcji mieć więcej. Jak już wspomniałem, mogą to być dane na dowolnym arkuszu i w dowolnej tabeli na tym arkuszu. W najprostszej wersji komponentu wszystkie te parametry będą wymagane. W wersji uproszczonej można założyć, że o ile nie podamy konkretnego arkusza, wybrany zostanie pierwszy z brzegu. Podobnie tabele - jeżeli jakieś są, wybrana zostanie pierwsza w kolejności.

Implementacja komponentu

Komponent będzie korzystał z obiektów COM instalowanych razem z pakietem Office - Excel.Application. Komponent musi być zainstalowany, a jego wersja zostanie odpowiednio wybrana - w zależności od wskazań w rejestrze systemowym.

Popatrzmy na przykładową implementację funkcji, która jest w stanie odczytać dane z tabeli Excela:

function Import-ExcelTable
{
    Param
    (
        [Parameter(Mandatory=$true)]
        [string]$Path,
        [Parameter(Mandatory=$true)]
        [string]$Sheet,
        [Parameter(Mandatory=$true)]
        [string]$Table
    )
    try {
        $excel = New-Object -ComObject Excel.Application
        $file = (ls $Path).FullName
        Write-Verbose "Opening file $file..."
        $workbook = $excel.Workbooks.Open($file)
        $xlSheet = $excel.Sheets.Item($Sheet)
        $xlTable = $xlSheet.ListObjects.Item($Table)
        $captions = $xlTable.HeaderRowRange.Value2

        $data = $xlTable.DataBodyRange.Value2
        for ($i=1; $i -le $data.GetLength(0); $i++) {
            $obj = @{}
            1..$captions.Count | % { $obj[[string]$captions[1,$_]] = [string]$data[$i,$_] }
            [PSCustomObject]$obj
        }
    } finally {
        $workbook.Close()
        $excel.Quit()
        [Runtime.InteropServices.Marshal]::ReleaseComObject($excel) | Out-Null
    }
}

To wszystko, aby w prosty sposób wyświetlić dowolną tabelę.

Zobacz cały wpis: Pobieranie tabeli z Excela w PowerShell

Kategoria:PowerShell

Pobieranie obciążenia procesora w PowerShell

Najczęściej używane skrypty PowerShell w pracy programisty - ikona konsoli

Liczniki wydajności Windows

System Windows posiada liczne mechanizmy pozwalające na monitorowanie zachowań samego systemu, aplikacji i usług. Najbardziej znanym narządziem jest chyba Menedżer zadań. Pozwala on pobrać obciążenie procesora, pamięć zajętą przez poszczególne procesy czy obciążenie karty sieciowej. Jest to z pewnoscią doskonałe narzędzie dla użytkowników, którzy chcą szybko zobaczyć stan systemu. Istnieją jednak inne narzędzia, które znacznie łatwiej automatyzować. Są to liczniki wydajności. Liczniki wykorzystywane są, tak jak Menedżer zadań, w celu udostępnienia informacji o systemie, aplikacjach, usługach i wskazują, jak te komponenty sobie radzą. Pozwala to wskazać słabe elementy, a na dalszym etapie ulepszyć ich działanie. Dane te mogą być pobierane i przetwarzane przez praktycznie każdą aplikację. Nie inaczej jest z PowerShellem.

Pobieranie informacji o zajętości procesora

Aby pobrać dane licznika związane z obciążeniem procesora, a w zasadzie wszystkich procesorów, wystarczy wywołać polecenie Get-Counter z odpowiednią nazwą, np.:

Get-Counter "\Procesor(*)\Czas procesora (%)"

Tu mała uwaga: jeżeli system operacyjny jest w innym języku, nazwy będą inne. Jeżeli wszystko się uda, otrzymamy rezultat podobny do poniższego (przykład obejmuje maszyną z czterema procesorami):

Timestamp                 CounterSamples
---------                 --------------
2017-04-14 18:57:52       \\komputer\procesor(0)\czas procesora (%) :
                          10,5217729945603

                          \\komputer\procesor(1)\czas procesora (%) :
                          13,6072290981962

                          \\komputer\procesor(2)\czas procesora (%) :
                          5,89358883910656

                          \\komputer\procesor(3)\czas procesora (%) :
                          19,7781413054679

                          \\komputer\procesor(_total)\czas procesora (%) :
                          12,450190476247

Przyznam, że nie jest to najwygodniejszy sposób prezentacji informacji. Nie jest też łatwy w późniejszym przetwarzaniu i analizowaniu - zwłaszcza, gdy mamy wiele takich pomiarów. Znacznie wygodniejsza, przynajmniej dla mnie jest forma tabelaryczna, gdzie każdy z procesorów ma swoją kolumnę. Popatrzmy na nieco bardziej złożony skrypt:

Get-Counter "\Procesor(*)\Czas procesora (%)" -MaxSamples 5 | % {
    $obj = [PSCustomObject]@{Time = $_.Timestamp}
    $_.CounterSamples | % {
        $obj | Add-Member -MemberType NoteProperty -Name "Processor($($_.InstanceName))" -Value $_.CookedValue
    }
    $obj
} | ft

Tym razem wyniki będą się prezentowały następująco:

Time                    Processor(0)     Processor(1)     Processor(2)     Processor(3) Processor(_total)
----                    ------------     ------------     ------------     ------------ -----------------
2017-04-14 19:07:23 15,1414729941447 8,96994375735522 10,5128260665526 4,34129682976312  9,74138985705781
2017-04-14 19:07:24  9,2392634503808  12,315898587656  12,315898587656 6,16262831310558  10,0084173042262
2017-04-14 19:07:25  12,315898587656 7,70094588174318 6,16262831310558 7,70094588174318  8,47010959653541
2017-04-14 19:07:26 16,9308512935689 7,70094588174318  12,315898587656 15,3925337249313  13,0850524415014
2017-04-14 19:07:27 21,5458039994817  9,2392634503808 15,3925337249313 20,0074864308441  16,5462743666462

Analiza takiej tabelki wydaje się łatwiejsza.

Zobacz cały wpis: Pobieranie obciążenia procesora w PowerShell

Kategoria:PowerShell

PowerShell i wykonywanie poleceń SQL Server

Najczęściej używane skrypty PowerShell w pracy programisty - ikona konsoli

Wywoływanie w wersji uproszczonej

W jednym z artykułów na temat PowerShell opisywałem już sposób łączenia się z SQL Server. Wpis można zobaczyć pod tym linkiem: Wykonywanie zapytań w SQL Server z poziomu PowerShell. W tamtym przypadku połączenie wykonywane było przy pomocy dostarczanego wraz z SQL Server modułu SQLPS. Moduł daje nam dostęp do wielu oszarów SQL Server, których sterowanie z poiomu PowerShell wydaje się bardzo kuszące. Wykonywanie zapytań też wydaje się na tyle łatwe, że pisanie kolejnego artykułu na ten temat mija się z celem. W tamtym artykule pokazałem proste instrukcje SELECT. Istrukcje były stałym ciągiem znaków, nie przyjmowały żadnych parametrów. Nie pokazywałem też w jaki sposób można wywoływać instrukcje INSERT oraz UPDATE. Nie dlatego, że nie da się ich wykonać. Powód jest nieco inny.

Niebezpieczeństwo SQL Injection

Sposób przekazywania parametrów do metody Invoke-SqlCmd nie jest do końca przemyślany. Może i łatwo jest to wszystko zintegrować z resztą infrastruktury PowerShell, ale kosztem bezpieczeństwa. A bezpieczeństwo powinno w takich przypadkach, mimo wszystko, stać na pierwszym miejscu.

Polecenie Invoke-SqlCmd nie pozwala wręcz przekazać parametrów w sposób bezpieczny (przykład wstrzyknięcia SQL można znaleźć między innymi tutaj: Invoke-SqlCmd considered harmful. Odradzałbym stosowanie tego polecenia dla zapytań mających jakiekolwiek parametry, niekoniecznie tylko tych tekstowych. To dlatego pokusiłem się o przygotowanie oddzielnej funkcji do wywoływani poleceń SQL.

Stare dobre ADO.NET

PowerShell jest doskonale zintegrowany z całym środowiskim .NET. W zasadzie wszystko to, co może być wykonane w programie .NET, może być z powodzeniem wykanane w PowerShellu. Pozostaje oczywiście kwestia czytelności kodu, jego jakości i wydajności, ale zrobić można wszystko. Aby zasygnalizować technikę działania tym, którzy nigdy w czystym ADO.NET nie pisali i przypomnieć tym, którzy kiedyś pisali (tak, tak, przez te wszystkie narzędzia typu NHibernate, LINQ to SQL, Entity Framework już mało kto to pamięta), przedstawię ogólny schemat działania:

  • Stwórz obiekt połączenia SqlConnection,
  • Stwórz obiekt polecenia SQL w ramach tego połączenia, SqlCommand
  • Otwórz połączenie, wykonaj polecenie i pobierz reprezentujący operację odczytu obiekt SqlDataReader,
  • Wykonaj iterację po kolejnych rekordach zwróconych przez zapyatanie

Wiemy, że możemy wywoływać dowolne zapytania SQL. Nie wiemy ile kolumn mają zwracane rekordy i jakie są nazwy tych kolumn. Teoretycznie moglibyśmy zwrócić typ object, ale nie jest to dobre z wielu względów. ADO.NET rozwiązuje to w prosty sposób: zwraca wszystkie dane potrzebne do rozpoznania wyniku w obiekcie SqlDataReader. Mamy właściwość FieldCount, która zwraca liczbę kolumn, a także motodę GetName, która pobiera nazwę kolumny pod wskazanym indeksem. To wszystko pozwala nam przetworzyć pobierane z bazy rekordy na ich wygodniejsze w obsłudze odpowiedniki w PowerShell. Popatrzmy na poniższy listing:

Zobacz cały wpis: PowerShell i wykonywanie poleceń SQL Server

Kategoria:SQL ServerPowerShell

Ostatnie komentarze
Dzieki za te informacje. były kluczowe
Dobrze wyjaśnione, dzięki !
a z innej strony - co gdybym ciąg znaków chciał mieć rozbity nie na wiersze a na kolumny? Czyli ciąg ABCD: 1. kolumna: A, 2. kolumna: B, 3. kolumna: C, 4 kolumna: D?