Przejdź do treści

Konfiguracja ApoAlly Insights#

Windows Server 2019#

Powershell Upload-Script
apoally-insights-upload.ps1
# upload_csv.ps1
#
# Ten skrypt automatycznie wyszukuje opcjonalny plik schematu (.json lub .csvs)
# o tej samej nazwie bazowej co plik CSV/TSV. JSON ma priorytet nad CSVS, jeśli oba istnieją.
# Jeśli nie znaleziono pliku schematu, przesyłany jest tylko plik CSV/TSV.
#
# Środowisko:
#   $apiUrl      - Domyślnie: "https://api.apoally.de/insights/upload"
#   $apiKey      - Domyślnie: "YOUR-API-KEY"
#   $csvFolder   - Domyślnie: "D:\ApoAlly-Insights"
#   $waitMinutes - Domyślnie: 5
#
# Skrypt sprawdza każdy plik CSV/TSV w $csvFolder. Jeśli plik jest starszy niż $waitMinutes,
# zostanie przesłany do API. W przypadku błędu tworzony jest plik error.log.

# Konfiguracja
$apiUrl = "https://api.apoally.de/insights/upload"
$apiKey = "YOUR-API-KEY"
$csvFolder = "D:\ApoAlly-Insights"
$waitMinutes = 5

function Upload-SingleFile {
    param (
        [string]$CsvFile
    )

    # Sprawdź, czy istnieje plik schematu JSON lub CSVS o tej samej nazwie bazowej (priorytet ma JSON)
    $schemaFileJson = Join-Path $CsvFile.DirectoryName ("$($CsvFile.BaseName).json")
    $schemaFileCsvs = Join-Path $CsvFile.DirectoryName ("$($CsvFile.BaseName).csvs")
    $schemaFileToUpload = $null

    if (Test-Path $schemaFileJson) {
        $schemaFileToUpload = $schemaFileJson
    }
    elseif (Test-Path $schemaFileCsvs) {
        $schemaFileToUpload = $schemaFileCsvs
    }

    Write-Host "Przesyłanie pliku: $($CsvFile.FullName)"
    if ($schemaFileToUpload) {
        Write-Host "Znaleziono opcjonalny plik schematu: $schemaFileToUpload"
    }

    # Określ MIME type na podstawie rozszerzenia (.csv lub .tsv)
    $extension = $CsvFile.Extension.ToLower()
    $contentType = "text/csv"
    if ($extension -eq ".tsv") {
        $contentType = "text/tab-separated-values"
    }

    # Zbuduj ciało multipart/form-data
    $boundary = "----MyBoundary$(Get-Random)"
    $LF = "`r`n"
    $bodyLines = @()

    # 1) Dodaj część CSV/TSV
    $csvContent = Get-Content $CsvFile.FullName -Raw
    $bodyLines += "--$boundary"
    $bodyLines += "Content-Disposition: form-data; name=`"files`"; filename=`"$($CsvFile.Name)`""
    $bodyLines += "Content-Type: $contentType$LF"
    $bodyLines += $csvContent

    # 2) Jeśli mamy plik schematu, dodaj go jako drugą część
    if ($schemaFileToUpload) {
        $schemaContent = Get-Content $schemaFileToUpload -Raw
        $bodyLines += "--$boundary"
        $bodyLines += "Content-Disposition: form-data; name=`"files`"; filename=`"$($schemaFileToUpload)`""

        if ($schemaFileToUpload.ToLower().EndsWith(".json")) {
            $bodyLines += "Content-Type: application/json$LF"
        }
        else {
            # Dla .csvs traktujemy jako tekst
            $bodyLines += "Content-Type: text/plain$LF"
        }

        $bodyLines += $schemaContent
    }

    # Zakończenie boundary
    $bodyLines += "--$boundary--"

    $body = $bodyLines -join $LF
    $headers = @{
        "X-API-Key" = $apiKey
        "Content-Type" = "multipart/form-data; boundary=$boundary"
    }

    try {
        $response = Invoke-RestMethod -Uri $apiUrl -Method Post -Headers $headers -Body $body
        return $response
    }
    catch {
        throw $_
    }
}

function Upload-CSVFiles {
    param (
        [string]$Folder
    )

    # Pobierz wszystkie pliki CSV i TSV rekurencyjnie, ignorując te pasujące do '_img.csv' lub '_img.tsv'
    $csvFiles = Get-ChildItem -Path $Folder -Recurse -File -Include *.csv, *.tsv |
        Where-Object { $_.Name -notmatch '_img\.(csv|tsv)$' }

    foreach ($file in $csvFiles) {
        # Zdefiniuj nazwę pliku logu błędów dla pliku danych
        $errorLog = Join-Path $file.DirectoryName ("$($file.BaseName).error.log")

        # Pomiń, jeśli istnieje już plik logu błędów
        if (Test-Path $errorLog) {
            Write-Host "Pomijanie pliku z powodu istniejącego logu błędów: $($file.FullName)"
            continue
        }

        # Sprawdź, czy plik ma co najmniej $waitMinutes
        $fileAge = (Get-Date) - $file.LastWriteTime
        if ($fileAge.TotalMinutes -lt $waitMinutes) {
            Write-Host "Plik jest zbyt nowy (Wiek: $([math]::Round($fileAge.TotalMinutes, 2)) minut): $($file.FullName)"
            continue
        }

        Write-Host "Próba przesłania: $($file.FullName)"
        try {
            $response = Upload-SingleFile -CsvFile $file

            if ($response.status -eq "success") {
                Write-Host "Przesyłanie zakończone sukcesem: $($file.FullName)"
                Remove-Item $file.FullName -Force

                # Sprawdź i usuń powiązany plik _img.csv lub _img.tsv
                $imgCsv = Join-Path $file.DirectoryName ("$($file.BaseName)_img.csv")
                $imgTsv = Join-Path $file.DirectoryName ("$($file.BaseName)_img.tsv")
                if (Test-Path $imgCsv) {
                    Remove-Item $imgCsv -Force
                    Write-Host "Usunięto powiązany plik _img.csv: $imgCsv"
                }
                if (Test-Path $imgTsv) {
                    Remove-Item $imgTsv -Force
                    Write-Host "Usunięto powiązany plik _img.tsv: $imgTsv"
                }
            }
            else {
                Write-Host "Przesyłanie nie powiodło się dla pliku: $($file.FullName). Tworzenie logu błędów."
                $errorMessage = "Błąd przesyłania: " + ($response.error)
                $errorMessage | Out-File -FilePath $errorLog -Encoding utf8
            }
        }
        catch {
            Write-Host "Błąd przesyłania pliku $($file.FullName): $_. Tworzenie logu błędów."
            $_ | Out-File -FilePath $errorLog -Encoding utf8
        }
    }
}

function Start-Watch {
    param (
        [string]$Folder,
        [int]$WaitMinutes
    )

    # Początkowe przetwarzanie przy uruchomieniu
    Upload-CSVFiles -Folder $Folder

    # Powtarzaj w nieskończoność, czekając 1 minutę między sprawdzeniami
    while ($true) {
        Start-Sleep -Seconds 60
        Upload-CSVFiles -Folder $Folder
    }
}

# Rozpocznij obserwację folderu
Start-Watch -Folder $csvFolder -WaitMinutes $waitMinutes

Instrukcja instalacji i konfiguracji skryptu#

Poniższa instrukcja opisuje, jak zapisać, skonfigurować i uruchomić skrypt PowerShell apoally-insights-upload.ps1 na serwerze Windows Server 2019, aby działał automatycznie przy starcie systemu.


1. Zapisz skrypt#

  1. Otwórz edytor tekstu (np. Notatnik).
  2. Skopiuj zawartość skryptu PowerShell apoally-insights-upload.ps1 do edytora.
  3. Zapisz plik pod nazwą apoally-insights-upload.ps1 w wybranym katalogu, np. C:\Scripts.

2. Dostosuj politykę wykonywania PowerShell#

Aby uruchomić skrypt, należy dostosować politykę wykonywania PowerShell:

  1. Otwórz PowerShell jako administrator.
  2. Wpisz następujące polecenie, aby zmienić politykę wykonywania:
    Set-ExecutionPolicy RemoteSigned
    
  3. Potwierdź zmianę, wpisując Y (Tak).

3. Dostosuj API-Key i konfigurację#

  1. Otwórz plik apoally-insights-upload.ps1 w edytorze tekstu.
  2. Zamień YOUR-API-KEY na swój rzeczywisty klucz API.
  3. Dostosuj ścieżkę do folderu $csvFolder, jeśli Twoje pliki CSV znajdują się w innym katalogu.
  4. Zapisz zmiany.

4. Skonfiguruj zadanie automatycznego uruchamiania#

Aby skrypt uruchamiał się automatycznie przy starcie systemu, skonfiguruj zaplanowane zadanie:

  1. Otwórz Harmonogram zadań z menu Start.
  2. Kliknij Utwórz zadanie.
  3. W zakładce Ogólne nadaj nazwę zadaniu, np. ApoAlly Insights Upload.
  4. Zaznacz opcję Uruchom z najwyższymi uprawnieniami.
  5. Przejdź do zakładki Wyzwalacze i kliknij Nowy: - Wybierz Przy uruchomieniu. - Kliknij OK.
  6. Przejdź do zakładki Akcje i kliknij Nowy: - Wybierz Uruchom program. - W polu Program/skrypt wpisz:
    powershell.exe
    
    - W polu Dodaj argumenty (opcjonalne) wpisz:
    -File "C:\Scripts\apoally-insights-upload.ps1"
    
    - Kliknij OK.
  7. Przejdź do zakładki Warunki i odznacz opcję Uruchom zadanie tylko wtedy, gdy komputer jest zasilany z sieci, jeśli zadanie ma działać również na zasilaniu bateryjnym.
  8. Kliknij OK, aby utworzyć zadanie.

5. Testowanie#

  1. Uruchom skrypt ręcznie, aby upewnić się, że działa poprawnie:
    powershell.exe -File "C:\Scripts\apoally-insights-upload.ps1"
    
  2. Sprawdź wynik i utworzone pliki logów, aby upewnić się, że nie występują błędy.

6. Monitorowanie i rozwiązywanie problemów#

  • Regularnie sprawdzaj pliki logów zapisywane w tym samym katalogu, co pliki CSV.
  • Jeśli zaplanowane zadanie nie działa, sprawdź ustawienia w Harmonogramie zadań i upewnij się, że skrypt jest poprawnie skonfigurowany.

Po wykonaniu tych kroków skrypt zostanie pomyślnie skonfigurowany na Twoim serwerze Windows Server 2019 i będzie uruchamiał się automatycznie przy starcie systemu.