Dotyczy wersji: 2022 R1 i powyżej; autor: Konrad Keppert
Dokumentacja powiązana
Szczegółowy opis funkcjonalności wymienionych w niniejszym artykule oraz ich konfiguracji można znaleźć na następujących stronach:
Wstęp
Użytkownicy WEBCON BPS niejednokrotnie mierzą się z potrzebą eksportowania załączników przechowywanych w obiegach do archiwów ZIP. Przykładowymi scenariuszami mogą być:
- zmniejszenie rozmiarów baz załączników przez eksport plików do udziału sieciowego i późniejsze usunięcie ich z obiegu,
- startowanie nowych instancji (z użyciem HotFolderu) na podstawie plików ZIP.
Najczęściej w tego typu scenariuszach wykorzystuje się dodatki SDK, ponieważ generowanie plików ZIP nie jest dostępne za pomocą standardowych akcji BPS. Możliwe jest to natomiast przy użyciu rozwiązania PowerShell, w którym napisane skrypty można wywoływać w WEBCON BPS.
Niniejszy artykuł przedstawia przykład wykorzystania akcji „Uruchom skrypt PowerShell” (zwaną dalej „akcją PowerShell”) do skompresowania wszystkich załączników z bieżącego elementu obiegu do archiwum ZIP i zapisania wynikowego archiwum na dysku.
Uwaga: aby akcja działała prawidłowo, konieczne może być przygotowanie serwera, na którym skrypty PowerShell będą wykonywane. Informacje na ten temat można znaleźć w dokumentacji: Uruchom skrypt PowerShell | WEBCON BPS.
Na końcu artykułu zawarto kilka uwag i praktycznych wskazówek, które pomogą dostosować to rozwiązanie do swoich potrzeb lub rozbudować je o dodatkowe funkcjonalności.
Konfiguracja akcji
Konfiguracja akcji PowerShell jest bardzo prosta i wymaga jedynie napisania skryptu oraz opcjonalnie nadpisania poświadczeń użytkownika, w kontekście którego uruchomiony zostanie skrypt (domyślnie jest to konto, na którym działa Workflow Service). To drugie będzie miało duże znaczenie w przypadku uprawnień, zarówno do udziału sieciowego, jak i baz danych (jeśli w parametrach połączenia SQL użyto logowania zintegrowanego).
Akcję PowerShell można wykonać jedynie w kontekście elementu obiegu, to znaczy nie ma możliwości dodania takiej akcji w automatyzacji cyklicznej. Upraszcza to konfigurację, ponieważ w ten sposób zawsze zapewniony jest dostęp do zmiennej {WFD_ID}, dzięki czemu z łatwością można pobrać z bazy informacje o załącznikach z bieżącego elementu obiegu. Aby wykonywać taką akcję cyklicznie, można zastosować podejście, które opisano na końcu tego artykułu.
Przykładową akcję umieszczono w automatyzacji na Przycisk w menu w jednym z kroków obiegu:
Rysunek 1. Kontekst wykonania akcji (przycisk w menu)
W konfiguracji akcji nie wprowadzono poświadczeń, przez co skrypt zostanie uruchomiony w kontekście konta, na którym działa usługa Workflow Service. Jest to możliwe, jeśli to konto ma dostęp do udziału sieciowego, na którym plik ma zostać zapisany. Jeśli konto serwisu posiada uprawnienia do odczytu baz danych środowiska, możliwe jest również wykorzystanie logowania zintegrowanego w parametrach połączenia do SQL Server:
Rysunek 2. Konfiguracja akcji
Cały skrypt zastosowany w przykładzie wraz z opisem zmiennych znajduje się w kolejnej sekcji tego artykułu.
Do przetestowania akcji utworzono element obiegu i dodano do niego dwa załączniki. Akcja dostępna jest na przycisk w menu, zgodnie z konfiguracją:
Rysunek 3. Przykład wywołania akcji
Po pomyślnym wykonaniu akcji, we wskazanej w skrypcie lokalizacji utworzone zostanie archiwum ZIP:
Rysunek 4. Wynik działania akcji
Przykładowy skrypt
Poniżej znajduje się skrypt PowerShell, który został wykorzystany w przedstawionym wyżej przykładzie.
Najważniejszymi parametrami, które wymagają zmiany przed implementacją, będą:
$serverName – nazwa SQL Servera, do którego nastąpi połączenie
$contentDbName – nazwa bazy zawartości, z której pobierane będą dane załączników
$attachmentDbName – nazwa bazy, w której przechowywane są pliki załączników (baza załączników lub zawartości)
$tempFolderPath – lokalizacja technicznego folderu dla plików tymczasowych (zostanie usunięta po zakończeniu wykonywania skryptu)
$zipFilePath – pełna ścieżka, wraz z nazwą archiwum ZIP, pod którą wynikowy plik zostanie zapisany
$query – zapytanie SQL, które wybierze kolumny z nazwą plików ($nameColumnName) oraz zawartością binarną załącznika ($valueColumnName).
Szczególną uwagę należy zwrócić również zmiennej $connectionString, reprezentującej parametry połączenia do SQL Servera, które powinny pozwolić na odczyt danych z bazy zawartości. W zastosowanym przykładzie ustawiono parametr „Integrated Security=True”, ponieważ konto serwisu, w kontekście którego uruchamiany jest skrypt PowerShell, posiada uprawnienia odczytu do bazy zawartości. W innych przypadkach konieczne może być podanie dedykowanych poświadczeń loginu SQL.
Treść skryptu:
## Database connection parameters $serverName = "SQL01" $contentDbName = "BPS_Content" $attachmentDbName = "BPS_Content_Att" $valueColumnName = "ATF_Value" ## name of a column that stores att. binary data $nameColumnName = "ATT_Name" ## name of a column that stores attachment name ## Temporary folder and result ZIP file saving location $tempFolderPath = "C:\zip_export\sql_files" $zipFilePath = "C:\zip_export\{WFD_ID}.zip" ## Temporary folder creation, if not exists if (-Not (Test-Path -Path $tempFolderPath)) { New-Item -ItemType Directory -Path $tempFolderPath } ## Connect to a database and fetch files $connectionString = "Server=$serverName;Database=$contentDbName;Integrated Security=True;" $query = "SELECT $nameColumnName, $valueColumnName FROM [$attachmentDbName].[dbo].[WFAttachmentFiles] JOIN [$contentDbName].[dbo].[WFDataAttachmets] ON ATF_ATTID = ATT_ID AND ATF_Version = ATT_FileVersion AND ATT_IsDeleted = 0 AND ATT_WFDID = {WFD_ID}" try { $connection = New-Object System.Data.SqlClient.SqlConnection $connection.ConnectionString = $connectionString $connection.Open() $command = $connection.CreateCommand() $command.CommandText = $query $reader = $command.ExecuteReader() while ($reader.Read()) { $fileName = $reader[$nameColumnName] $fileData = $reader[$valueColumnName] $filePath = Join-Path -Path $tempFolderPath -ChildPath "$fileName" [System.IO.File]::WriteAllBytes($filePath, $fileData) } $connection.Close() } catch { Write-Error "Error occurred while fetching files from a database: $_" exit 1 } ## ZIP file creation try { Add-Type -AssemblyName "System.IO.Compression.FileSystem" [System.IO.Compression.ZipFile]::CreateFromDirectory($tempFolderPath, $zipFilePath) } catch { Write-Error "Error occurred while creating a ZIP file: $_" exit 1 } ## Delete temporary files Remove-Item -Path $tempFolderPath -Recurse Write-Output "Files were fetched from a database, compressed to a ZIP file and saved on disk: $zipFilePath"
Praktyczne wskazówki
Kontekst użytkownika
Akcja PowerShell domyślnie wykonywana jest w kontekście użytkownika, na którym uruchomiona jest usługa Workflow Service, nawet jeśli wywoływana jest z poziomu formularza (BPS Portalu). Aby zmienić kontekst, należy w konfiguracji akcji wskazać login i hasło dedykowanego użytkownika. Ma to duże znaczenie w odniesieniu do uprawnień do udziałów sieciowych oraz baz danych (jeśli w parametrach połączenia wybrano logowanie zintegrowane).
Cykliczne wykonanie akcji
Jak wspomniano wcześniej, akcji PowerShell nie można zdefiniować w automatyzacji cyklicznej (globalnej), gdzie brakuje kontekstu elementu obiegu. Aby umożliwić jej cykliczne wykonanie, stosuje się następujące podejście:
- tworzony jest obieg techniczny służący wyłącznie eksportowaniu danych,
- w automatyzacji cyklicznej wykonywana jest akcja „Uruchom podobieg”,
- w konfiguracji tej akcji wskazywana jest ścieżka, którą element obiegu zostanie przesunięty po uruchomieniu,
- na wskazanej ścieżce przejścia uruchamiana jest akcja PowerShell,
- po pomyślnym zapisie, element obiegu zostaje zarchiwizowany (usunięty).
Takie podejście zalecane jest wszędzie tam, gdzie zachodzi potrzeba cyklicznego wykonania akcji, której nie da się w sposób standardowy uruchomić globalnie.
Archiwizację instancji obiegu technicznego można opóźnić w czasie, aby w razie niepowodzenia akcji mieć dostęp do historii elementu (logów).
Możliwość rozbudowania (+ przykład wysyłki do Azure Blob Storage)
Zastosowań PowerShell w WEBCON BPS jest wiele, m.in. cykliczny eksport plików XLSX/CSV z danymi pobranymi z bazy zawartości.
Scenariuszem bardzo zbliżonym do przedstawionego w artykule jest wysyłka plików do Azure Blob Storage. Można go zrealizować, edytując przykładowy skrypt poprzez:
- zamianę $zipFilePath na parametry połączenia do Blob Storage:
#Blob connection params $storageAccountName = "123store321" $storageAccountKey = "asdf+r/asdfasdS/asdfasasdfasdqVMC2aasdIasdfasdJ6glPAgerqQ+ASt/Pfafwe==" $containerName = "somefiles" $blobName = "file.pdf"
- dodanie na końcu skryptu poleceń realizujących wysyłkę:
##Send file do desired Blob storage $context = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey Set-AzStorageBlobContent -File $filePath -Container $containerName -Blob $blobName -Context $context
Tak zmodyfikowany skrypt do poprawnego działania wymaga, aby na serwerze aplikacyjnym zainstalowany był PowerShell Azure.