AFAS Profit – Power BI Historische data

Van niet alle data in AFAS Profit wordt de historie opgeslagen, in andere gevallen kan je deze minder gemakkelijk ophalen via connectoren. Een voorbeeld is bijvoorbeeld de forecast module, je kan de huidige status ophalen, maar het is niet te zien welke statussen deze nog meer gehad heeft in het verleden. We gaan dus kijken naar Historische AFAS Data in Power BI.

Mocht je dergelijke data nu wel in Power BI beschikbaar willen hebben zijn er een aantal mogelijke oplossingen. In dit bericht gaan we in op de quick and dirty oplossing. Mocht ik later nog tijd vinden voor een zal ik het bericht verder uitbreiden.

Wat gaan we doen?

We gaan een export ophalen uit AFAS Profit middels een getconnector, deze slaan we vervolgens op in Azure Storage. Dat doen we volgens de instructies uit dit artikel, met een kleine aanpassing. De files worden voorzien van een datumveld, in dit voorbeeld neem ik nog niet het opschonen van de historie mee en bouwen we de historie in principe eindeloos op.

Aanpassing Powershell script

Het enige echte verschil met het script uit het eerder genoemde artikel zit in de loop waar we data ophalen. In het eerste geval overschrijven we altijd de vorige export, maar in dit geval willen we graag meer versies van het bestand opslaan, hiervoor hebben we dus een extra variabele nodig:

foreach ($conn in $todo.getConnectors.id) {
    $naamDatum = Get-Date -Format "dd-MM-yyyy"
    $url = 'https://**URL_VAN_PROFIT_OMGEVING**/profitrestservices/connectors/' + $conn + '?skip=-1&take=-1'
    $file = '.\' + $conn + '.json'
    Invoke-WebRequest -Uri $url -OutFile $file -Headers $Headers -UseBasicParsing
    $filename = $conn + '_' + $naamDatum '.json'
    Set-azurestorageblobcontent -File $file -container $ContainerName -Blob $filename -Context $Context -Force
}

Iedere keer dat het script nu draait zal er een export gemaakt worden van de getconnector, deze wordt vervolgens op de blobstorage opgeslagen met de datum in de filename. Het gevolg hiervan is wel dat je maar 1 export per dag kan maken, iedere keer dat je het script opnieuw draait wordt de huidige dag overschreven.

Power BI

De handigheid zit hem in het consolideren van de diverse bestanden in Power BI. Hiervoor moet je eenmalig wat stappen doorlopen, maar vervolgens zal iedere keer dat je de rapportage ververst de nieuwe data opgehaald worden als die aanwezig is.

Stap 1: Toevoegen blob storage als datasource

In dit artikel staat (onder andere) uitgelegd hoe je blob storage kan toevoegen als datasource in PowerBI. In dit geval kan je de eerste stappen daarvan herhalen tot je dit scherm ziet:

Overzicht met files in de blobstorage
Blobstorage overzicht

Klik hier op OK, er zal een query ingeladen worden waarmee we verder kunnen werken.

Stap 2: Filter de bestanden die je nodig hebt (indien nodig)

Je kan in de tabelweergave die je vervolgens te zien krijgt op het “Name” veld filteren zodat alleen de velden (bestandsnamen) overblijven die je nodig hebt. Je kan hier allerlei filters, waaronder tekstfilters gebruiken.

Filterweergave power BI
Filter invoeren

Het resultaat is dan als het goed is de lijst met json files die je wil inlezen. Dit filter wordt iedere keer bij het verversen van de data toegepast, dus als er na een verversing meer bronbestanden zijn die aan het filter voldoen worden deze ook mee ingelezen.

Gefilterde weergave power bi
Het gefilterde resultaat

Stap 3: Het samenvoegen van de verschillende files

als het goed is hebben de files allemaal dezelfde structuur (LET OP: Dus niet de get-connector nog aanpassen nadat je dit gedaan hebt, dat levert problemen op met je historische data)! Je kan deze nu samenvoegen zodat we vanuit daar verder kunnen werken.

Klik voor het samenvoegen op de twee pijlen naar beneden naast “Content”

Samenvoegen files knop in power bi
Merge files

Je zal nu afhankelijk van de hoeveelheid data heel even moeten wachten, maar uiteindelijk zie je de volgende tabel (iets van die strekking)

Samengevoegde file-lijst power bi
Samengevoegde bestanden

Hier gaan we net als eerder weer een filter op toepassen, in de kolom “Name” filteren we zodat alleen de rows over blijven.

Stap 4: Bronbestanden “uitvouwen”

De volgende stap is het “uitvouwen” van het bronbestand. Door de aard van de JSON files moeten we de “lists” omzetten naar daadwerkelijke regels. Dat doen we als volgt:

Exploderen lijsten naar rijen
Expand to New Rows

Door op de “expand” knop te klikken krijgen we een keuze, kies hier voor “Expand to New Rows”. Je zal wederom even moeten wachten, maar daarna zie je dat er voor iedere regel uit iedere JSON file een regel gemaakt is in de tabel:

Toevoegen kolommen uit importbestanden
Uitgevouwen regels

De vervolgstap is om te bepalen welke kolommen uit de bronbestanden we zichtbaar willen maken in de eindtabel:

Filterweergave power bi
Kolomslectie

Vink de kolommen aan die je wil behouden en druk op OK.

Stap 5: Historisch datumveld prepareren

Je hebt nu de tabel met alle data, maar nog geen mogelijk om hier historisch op te filteren. Hiervoor moeten we het veld met de filename nog afmaken. we hebben de filename eerder in het Powershell script voorzien van de datum waarop de export gemaakt is. We zullen nu dus de overbodige tekst uit dat veld moeten weghalen en er een datumveld van moeten maken.

Onder het kopje “Transform” kan je voor “Replace” kiezen (selecteer eerst de kolom met de filenames):

Replace functie power bi
Replace Values

Je krijgt een dialoog te zien, afhankelijk van de opmaak kan je hier de tekst invullen die je niet meer nodig hebt. In mijn geval moet ik zowel voor als na de waarde die ik wil houden tekst verwijderen, dus ik moet deze handeling twee keer doen. Je voert de tekst in die je wil vervangen door “” oftewel niets, wat effectief betekend dat je de waarde verwijderd.

Replace functie power bi
Filterwaarde

Wanneer je dit zo veel gedaan hebt als je nodig hebt om alleen de datum nog in het veld over te houden kan je het veld transformeren naar een datumveld:

Transformeren kolom in Power BI
Transformeren naar datumveld

Tot slot kan je eventueel nog Kolommen verwijderen die je niet nodig hebt of andere transformaties doorvoeren. Wanneer je klaar bent kie je voor Close & Apply en daarna kan je met je data aan de slag!

Opslaan en verwerken in Power BI

Doordat we nu de exportdatum per regel beschikbaar hebben kan je deze datum als peildatum gebruiken voor bijvoorbeeld historische forecast statussen of debiteurenstanden vanuit AFAS Profit.

koppeling AFAS Profit & Microsoft Azure & Power BI

De eerdere posts waren gericht op het live (of near live) ontsluiten van data uit AFAS Profit naar een Power BI rapport. Alhoewel dit erg goed werkt voor rapporten waarbij de data zo live mogelijk moet zijn is het niet de beste optie als performance belangrijker is dan de meest actuele data. Zeker in de gevallen waarbij je de data maar eens per dag of nog minder hoeft te verversen.

Voor dit scenario maken we van de volgende diensten gebruikt:

  • AFAS Profit (on-prem of AFAS Online)
  • Azure Automation
  • Azure (Blob) Storage
  • Microsoft Power BI

De kosten van de Azure storage zijn afhankelijk van het gebruik, maar normaal gezien zouden we het over maximaal enkele euro’s per maand moeten hebben. De precieze kosten van Azure Blob Storage vind je eventueel hier (https://azure.microsoft.com/nl-nl/pricing/details/storage/blobs/)

Het stappenplan bevat de volgende onderdelen:

  • Aanmaken getconnectoren AFAS Profit
  • Aanmaken app-connector AFAS Profit en genereren token
  • Aanmaken Azure Automation instance
  • Aanmaken Azure Blob Storage
  • Invoeren Automation Runbook
  • Koppelen Power BI rapport

Aanmaken getconnectoren AFAS Profit

Binnen AFAS Profit kan je middels het aanmaken van een getconnector data buiten het pakket beschikbaar stellen. Deze connector is na het uitvoeren van de volgende stap vai de REST API beschikbaar.

De belangrijkste keuze die je in deze stap moet maken (naast de te ontsluiten velden natuurlijk) is waar je de filtering van de data uit wil voeren. Het is altijd een goed idee om niet meer data beschikbaar te stellen dan strikt noodzakelijk. Het heeft dan ook mijn persoonlijke voorkeur om filters waarvan je zeker weet dat die nooit veranderen aan de Profit kant in te regelen en alle overige filters af te handelen in de scripts die de data ophalen (of Power BI zelf).

Hoe je een getconnector in AFAS Profit aanmaakt vind je hier. (https://help.afas.nl/help/NL/SE/App_Cnr_XML_Get_Build.htm)

Aanmaken app-connector AFAS Profit en genereren token

De getconnectoren die we in de vorige stap aangemaakt hebben moeten nu nog naar buiten toe bescchikbaar gesteld worden. In de onderstaande twee stukken heb ik uitgewerkt hoe je de connectoren kan toevoegen aan een App connector en hoe je de autorisatie tokens klaar kan maken voor gebruik:

Normaal gezien gebruik ik een systeem gebruiker (Binnen AFAS Profit) en een specifieke groep van connectoren zodat ik de autorisatie van deze user middels groep autorisatie in kan regelen.

Alle get-connectoren die je mee neemt in de app connector zullen worden gedownload. Je kan de lijst later dus ook nog uitbreiden. Als je de lijst wil inkrimpen zal je handmatig de json’s van de verwijderde connectoren moeten verwijderen uit je blob-storage.

Aanmaken Azure Automation instance

Tot dusver hebben we nog niets gedaan dat we in eerdere stappen niet ook al gedaan hebben. Voor de volgende stappen moeten we in de Azure omgeving een aantal dingen voorbereiden. Je kan als je nog geen account hebt via https://portal.azure.com een nieuw account aanmaken. De kosten van de onderdelen die we inzetten zijn we erg afhankelijk van hoeveel data we opslaan, maar normaal gezien zou het maar een paar euro per maand moeten zijn.

In de Azure portal kan je zoeken naar “Azure Automation” je krijgt dan een optie om een Azure Automation Acocunt aan te maaken, als je dat onderdeel opent krijg je een beeld zoals hier onder:

Azure Automation menu

Klik hier op “Add” om een nieuwe Azure Automation Instance aan te maken. Je krijgt een venster zoals hier onder te zien:

Azure Automation Account aanmaken

Je moet de instance een naam geven en eventueel aan een bestaande resource group koppelen, als je die nog niet hebt kan je die ook meteen even aanmaken. Tot slot moet je een regio kiezen, qua functionaliteit maakt het niet uit, maar het is sterk aan te raden om de dichtstbijzijnde regio te kiezen. In ons geval dus West Europa.

Als alles goed gegaan is krijg je uiteindelijk een venster zoals dit te zien:

Azure Automation overview

Om er voor te zorgen dat je alle acties uit kan voeren is het noodzakelijk om te zorgen dat de juiste modules geactiveerd zijn (via de modules knop kan je de lijst aanpassen). In ons geval is dit de lijst die we gebruiken:

Azure Automation Modules

Dit zijn er iets meer dan strikt noodzakelijk voor dit artikel maar dat is verder geen probleem. Let er wel op dat je deze modules af en toe zal moeten updaten.

Het aanmaken van het Automation Account kan even duren, je kan onderstussen aan de slag met de volgende stap, we maken het Automation Account verderop af.

Vanuit hier kunnen we verder met de voorbereidingen en gaan we een Storage account aanmaken.

Aanmaken Azure Blob Storage

In tegenstelling tot de directe koppelingen waar ik eerder over schreef maken we nu een tussenstap door de data in Azure Blob Storage te zetten. Dat komt de performance ten goede en bied ook een aanzienlijk aantal extra mogelijkheden als we meer met de data zouden willen doen.

Op de Azure portal zoeken we naar “Storage Acocunts”. Als je daar op klikt krijg je een overzicht met de bestaande storage accounts. Indien nodig kan je nu zelf een nieuw acocunt aanmaken door op “Add” te klikken

Microsoft Azure Storage Accounts

Over de gevraagde velden in, normaal gezien staat alles goed, let wel op de regio waar je het storage account aanmaakt. Voor de beste performance houd je deze in dezelfde regio als je automation account.

Microsoft Azure Storage account aanmaken

Als het aanmaken gelukt is kan je de nieuw aangemaakte resource openen:

Micorosoft Azure Storage Account overview

Kies hier voor “Blob” om de container aan te maken waar we de JSON files die uit de AFAS Profit connector komen op gaan slaan.

Microsoft Storage Blob aanmaken

Tot slot hebben we nog twee zaken nodig uit ons Azure Storage account. Allereerst hebben we het access token nodig. Deze kan je vinden door op de Azure Storage Acocunt overview pagina in het menu op “Access Keys” te klikken en key 1 of 2 te kopiëren.

Azure Storage acces keys

Vervolgens hebben we de URL nodig waarop je Blob beschikbaar is. Open daarvoor vanuit  de Azure Storage Acocunt overview pagina het “Blobs” menu en open daar de Blob die we net aangemaakt hebben. Open daar vervolgens de properties en kopier de URL.

Microsoft Azure Storage Blob url

Invoeren Automation Runbook

De eerste stap die we moeten zetten in het Azure Automation account is het aanmaken van een runbook voor het draaien van het script. Ga hiervoor naar het runbook menu:

Azure Automation Runbook

Mogelijk staan hier een aantal voorbeeldscripts, die kan je verwijderen om het beeld wat overzichtelijker te maken. Vervolgens klik je op de “nieuw” knop, en vul je de velden in. De naam die je het script geeft is niet zo van belang, maar zorg er voor dat “type” op “Powershell” staat:

Azure Automation aanmaken runbook

Vervolgens kan je het runbook bewerken om het script toe te voegen. Het script heb ik onder aan deze post staan en nog even toegelicht.

Azure Automation Runbook bewerken

Wanneer je de code ingevoerd hebt kan je op “Publish” drukken, er is ook een save knop, maar het script draait altijd de laatste versie die gepubliceerd is, dus zeker voor de eerste keer opslaan is het van belang om “Publish” te gebruiken.

Je kan nu terug gaan naar het runbook overzicht zoals hier onder, als je op het script klikt ga je na de status pagina van dat script/runbook. Als je hier op “run” drukt zal het script in de wachtrij gezet worden, je gaat dan naar een status pagina waar je de “job” kan bekijken.

Azure Automation Runbook overzicht
Azure Automation Job status

Als alles goed gegaan is zal de job naar completed springen en zie je geen errors. (mogelijk moet je even op refresh drukken). Je kan ondertussen ook de blob storage opnieuw openen en controleren of de files daar verschenen zijn.

Tot slot willen we nog een schema toevoegen om het script/runbook periodiek te draaien. Je kan in de runbook op “Schedule” klikken:

Azure Automation Scheduling

Als je hier de stappen volgt kan je een script toevoegen dat bijvoorbeeld ieder uur of iedere dag draait:

Azure Automation Schedule aanmaken

Script

Je vind de code van het script hier (op Github, https://github.com/HermanRonk/ProfitExportToAzureBlob ), de nummers hier onder verwijzen naar de verschillende blokken in dat script.

  1. In het eerste blok worden de inloggegevens voor de Profit omgeving vastgelegd. En de header opgebouwd
  2. Hier worden de Variabelen voor het Azure Storage account vastgelegd.
  3. Hier maken we verbinding met de Azure Storage omgeving
  4. Hier halen we eerst de lijst met geautoriseerde connectoren op en vervolgens loopen we door deze connectoren heen. Voor iedere connector wordt een JSON file naar de storage geschreven.

Koppelen Power BI rapport

Het koppelen van de databron werkt niet helemaal intuitief, het is dus zaak om deze stappen goed te volgen.

Open de Power BI client en begin een nieuw rapport

  • Kies voor een nieuwe gegevensbron, gebruik eventueel het zoekveld en zoek naar Azure Blob
Power BI Gegevensbron toevoegen
  • Je krijgt vervolgens een veld waar je het adres van de Azure Blob in kan voeren. Je vind dit adres op de properties pagina van de Storage Blob in Azure.
Power BI gegevensbron URL
  • In het volgende veld moet je de “Key” van het storage account invoeren. Je vind deze “Key” op de “access keys” pagina van het storage account (dus 1 niveau hoger dan de Storage Blob).
Power BI Blob Accountsleutel
  • Je krijgt vervolgens een pagina te zien met alle beschikbare files op de Blob, je mag hier op laden klikken
Power BI Tabel
  • Als je vervolgens de Query Editor opent zie je een aantal regels, klik in de eerste regel op “Binary”
Power BI Tabel
  • In het volgende venster zie je weer een aantal regels, klik hier op “List”
Power BI List
  • In de nieuwe weergave mag je in het ribbon op de “Naar tabel” knop drukken
Power BI convert to table
  • Vervolgens kan je op de onderstaande knop drukken om de tabel om te zetten in alle kolommen.
Power BI Expand
  • Selecteer hier de kolommen die je wil gebruiken.
Power BI Kolommen selecteren

Je kan deze stappen herhalen voor iedere JSON / Connector die je in je rapportage wil gebruiken. Om de eerste stappen wat te versnellen kan je eventuele in de advanced editor de code die je heb na stap 4 kopieren en als nieuwe query plakken. Dat scheel eventueel wat handwerk.

Als je deze stappen doorlopen hebt is de data “live” beschikbaar in Power BI. Afhankelijk van de refresh die je in Azure Automation hebt ingesteld zal de data periodiek worden bijgewerkt. Als je de rapportage open hebt staan kan je op “Refresh” drukken om de nieuwe data op te halen.

Tot slot

Als je de bovenstaande stappen gevolgd heb zal alles normaal gezien naar behoren moeten werken. Er is dan wel nog ruimte voor verbetering, maar om het voorbeeld een beetje overzichtelijk te houden heb ik het hier bij gehouden. De eerste stap die eigenlijk nog gezet moet worden is het het gebruiken van de Azure Credential Store in je Azure Automation account, dat voorkomt dat de autorisatie tokens zichtbaar in het script staan en is dus uiteindelijk een veiligere implementatie.

Verder kan je het versiebeheer en de uitrol van het script nog mooi inregelen in Azure Devops of Github, maar dat is een post voor later :).

AFAS Profit bijlagen exporteren (Powershell)

AFAS Profit bijlagen exporteren is in bulk helaas niet zo eenvoudig. Als je een keer een enkele bijlage uit een AFAS Profit dossier nodig hebt ga je eenvoudig in de applicatie naar het desbetreffende dossieritem en download je de bijlage. Maar wat als je nou van alle abonnementen uit één groep of administratie alle bijlages wil exporteren om deze in een andere applicatie in te lezen?

Dit leek me wel een mooie Powershell oefening en na enig uitstel ben ik er maar eens voor gaan zitten. Ik sla de voorbereidende stappen in AFAS Profit even over in deze post, maar ik zal verwijzen naar de bestaande instructies voor die stappen.

Wat gaan we doen?

Doel: Alle bijlages uit de abonnementsdossiers opslaan buiten AFAS Profit. Per abonnement maken we een map aan en daar worden alle bijlages die bij dat abonnement gevonden worden opgeslagen.

Stappenplan:

  1. Connectoren aanmaken in AFAS Profit
  2. Connectoren autoriseren in AFAS Profit
  3. Powershell script maken met een aantal functies:
  4. Draaien export

Stap 1 en 2 ga ik nu niet al te veel tijd aan besteden, als je de instructies volgt die hier staan moet je hier wel uit komen, als je geen idee hebt hoe dat werkt kan je het beste mij of een consultant even een berichtje sturen 🙂

Wel heb ik de twee getconnectoren die ik in dit voorbeeld gebruik hier staan zodat je deze kan gebruiken en/of aanpassen. (zip)

Powershell

Zoals aangegeven gaan we het exporteren van de files doen middels Powershell en de AFAS Profit getconnectoren. In dit geval heb ik Powershell 6.2 gebruikt in verband met een Invoke-RestMethod functionaliteit.

Het script is opgebouwd uit een aantal functies die ik vervolgens aanroep in een runner die de daadwerkelijke uitvoering doet. Onderaan staat een linkje naar de hele file, maar ik loop hier even door de scriptblokken heen, ik heb overal de url en autorisatie tokens aangepast:

Functie: ProfitAuthorisatie

function ProfitAuthorisatie {
    # Bouw de autorisatie header voor AFAS Profit
    $token = '<token><version>1</version><data>****</data></token>'
    $encodedToken = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($token))
    $authValue = "AfasToken $encodedToken"
    $Headers = @{
        Authorization = $authValue
    }
    $Headers
    return
}

Deze functie bouwt de autorisatie header op die we nodig hebben voor het aanroepen van de REST API van AFAS Profit. Deze code wordt een aantal keer aangeroepen in de komende functies. Vergeet niet je eigen Autorisatie token in te voeren.

Functie: GetAbo

function GetAbo {
    param (
        [int32]$administratie
    )
    # Definieer de URL voor de Profit omgeving
    $url = 'https://****/profitrestservices/connectors/DossierBijlagen?filterfieldids=AdministratieAbo%3BAdministratieProject&filtervalues=' + $administratie + '%3B' + $administratie + '&operatortypes=1%3B1&skip=-1&take=200'
    # Connect and retrieve the table
    $auth = ProfitAuthorisatie
    ((Invoke-WebRequest -Uri $url -UseBasicParsing -Headers $auth).content | ConvertFrom-Json).Rows
}

Deze functie haalt een lijst op van alle abonnementen die dossieritems hebben. Ik haal direct ook de verschillende dossieritem ID’s op die ik later nodig heb om de bijlagen op te sporen. De functie heeft een parameter nodig om te kunnen werken, dit is de administratiecode waarvan je de abonnementen op wil halen. Je geeft deze code als parameter mee wanneer je het uiteindelijke script aanroept.

Functie: GetBijlagen

function GetBijlagen {
    param (
        [int32]$DossieritemID
    )
    # Definieer de URL voor de Profit omgeving
    $url_dossier = 'https://****/profitrestservices/connectors/AbonnementenExport?filterfieldids=DossieritemID&filtervalues=' + $DossieritemID + '&operatortypes=1&skip=-1&take=-1'
    # Connect and retrieve the table
    $auth = ProfitAuthorisatie
    ((Invoke-WebRequest -Uri $url_dossier -UseBasicParsing -Headers $auth).content | ConvertFrom-Json).Rows
}

Deze functie heeft het ID van het dossieritem als input parameter nodig. Dit is een van de velden die als resultaat uit de GetAbo functie is gekomen. De reden dat we los de bijlagen op moeten halen is dat de GUID en de filename niet direct in het dossieritem beschikbaar zijn. Daar komt bij dat een enkel dossieritem weer meerdere bijlagen kan hebben. De output hier is een object/array met alle bijlages die beschikbaar zijn bij dit dossieritem.

Functie: DownloadBijlagen

function DownloadBijlagen {
    param (
        [string]$filename,
        [string]$guid,
        [string]$map,
        [string]$abo
    )

    # Definieer de URL voor de Profit omgeving
    $url_download = 'https://****/profitrestservices/fileconnector/' + $guid + '/' + $filename 
    # Connect and retrieve the table
    $auth = ProfitAuthorisatie
    $fileout = $map + '\' + $abo + '-' + $filename 
    $download_error = 0

    # Voorkomen dat we lege files wegschrijven omdat de download niet uitgevoerd kan worden.
    try {
        $tempfile = Invoke-RestMethod -Uri $url_download -Method Get -Headers $auth 
    }
    catch {
        Write-Host $_ -fore Red
        $download_error = 1
    }
    
    if ($download_error -eq 0) {
        $bytes = [System.Convert]::FromBase64String($tempfile.filedata)
        [IO.File]::WriteAllBytes($fileout, $bytes)
        Write-Host $filename "- Succesvol weggeschreven in"  $fileout -ForegroundColor green
    } 
}

Op basis van de items in de lijst die uit GetBijlagen gekomen is kunnen we de files gaan downloaden. Je hebt sowieso de filename en de guid nodig om de fileconnector (subjectconnector) aan te kunnen roepen. Daarnaast geef ik de map mee waar we de file op gaan slaan en het abonnementsnummer (deze neem ik op in de filename, dit is wel een punt, het is niet uitgesloten dat dit dubbele bestanden op kan leveren, in ons geval komt dat niet voor, maar technisch zou je hier bestanden kunnen overschrijven).

In dit stukje code zit ook een error check, heel af en toe kan een file niet goed gedownload worden, dit leverde lege bestanden op. Om dat te voorkomen vang ik die error af (en meld dat in de output) en doe dan dus geen download.

Op dit moment levert dit wel nog lege mappen op als de enkele bijlage bij een abonnement niet goed gedownload kan worden, maar dat zou je simpel op kunnen lossen als dat een probleem is.

Functie: ScriptUitvoeren

function ScriptUitvoeren {
    param (
        [int32]$administratie
    )
    
    # Eerst Getabo
    $records = GetAbo $administratie

    # Per Abo dossieritems ophalen
    foreach ($record in $records) {
        
        # Map bepalen voor het eventueel opslaan van bijlagen
        $map = "C:\Exports\" + $record.Abonnement  

        # Bijlagenlijst per dossieritem maken
        $bijlagenlijst = GetBijlagen $record.DossieritemID

        # Als de map voor het abonnement nog niet bestaat deze aanmaken
        If (!(test-path $map) -And $bijlagenlijst.count -gt 0) {
            New-Item -ItemType Directory -Force -Path $map
        }

        # Per bijlage file downloaden
        foreach ($bijlage in $bijlagenlijst) {
            DownloadBijlagen $bijlage.Naam $bijlage.Bijlage $map $record.Abonnement
        }
    }
}

Dit is de functie die we aanroepen als we het script gaan draaien, je zou deze functie ook direct in de code aan kunnen roepen. Gezien ik het script per administratie wil kunnen draaien heb ik er voor gekozen om hem los aan te roepen. De functie heeft het administratienummer als parameter nodig.

In dit geval is de map waar we de bijlagen opslaan c:\exports\ maar daar kan je van maken wat je wil.

Je ziet in deze funtie dat alle eerdere functies stap voor stap opgeroepen worden en de output daarvan weer als input in een andere functie gestopt wordt. Er worden twee nested foreach loops gebruikt om door alle abonnementen en dossieritems heen te lopen.

Tot slot

Het script is zeker niet perfect, ik zou de lege mappen nog op kunnen ruimen en wat betere logging toe kunnen passen, maar voor ons doel was dit voldoende. Als je eventueel vragen hebt over het script kan je die in de comments stellen.

Het script is hier te downloaden en in te zien. Nadat je de ps1 file gedraaid hebt kan je met “ScriptUitvoeren #” het script starten (vervang # door het administratienummer).

Documenten

Plesk backup DNS (Slave-DNS-Manager)

Sinds kort heb ik de hosting van een aantal sites opnieuw ingeregeld. Hiervoor heb ik deze keer na jarenlang Directadmin gebruikt te hebben nu een keer voor Plesk gekozen. Tot op heden heb ik nog geen moment spijt gehad van mijn keuze en heb ik eigenlijk alles vrijwel direct werkend gekregen zoals ik dat wilde.

DNS was echter een van de dingen die op de Plesk server zelf goed werkte, maar het koppelen van de secundaire DNS server wilde niet helemaal werken zoals het hoort. Helaas bood het forum ook geen oplossing, maar na het nodige zoekwerk is het dan uiteindelijk toch gelukt :).

Mijn secundaire DNS server draait bij DigitalOcean in Canada (een deel van de sites worden veel in de VS en Canada gebruikt) en is een droplet van het goedkoopste type (grofweg $5 per maand). De machine hoeft ook niet schokkend veel te doen dus dat moet prima uit komen.

Qua OS heb ik afgeweken van mijn normale voorkeur voor Ubuntu, maar om voor mij nog steeds onduidelijke redenen heb ik het daar nooit op werkend gekregen. In dit geval heb ik de collectie CentOS 7 servers maar uitgebreid van 2 naar 3..

In plesk:

In Plesk maak ik gebruik van de “Slave-DNS-Manager” extension die je via de extension manager kan installeren.

Slave DNS Manager extension page

De configuratie in Plesk is verder niet heel complex, je opent de extension via de extension manager en drukt op de knop om een nieuwe slave toe te voegen:

Add slave to config

Op deze pagina staat ook een stukje voorbeeld configuratie, kopieer deze in een losse file, we gaan niet de hele config gebruiken, maar nemen er een paar stukjes uit over. De invoervelden wijzen verder voor zich.

Slave DNS Manager config example

Op de secundaire DNS server:

  • yum update
  • yum install bind bind-utils
  • systemctl stop named
  • vi /etc/named.conf

in /etc/named.conf maken we een aantal aanpassingen, een deel van de info kan je overnemen uit de voorbeeldconfiguratie uit de Slave DNS Manager uit Plesk en een deel moet je even zelf invoeren.

acl “trusted” {
**IP Adres Primaire DNS**;
**IP Adres lokale server**;
127.0.0.1;
};

options {
listen-on port 53 { 127.0.0.1; **IP Lokale server**; };
listen-on-v6 port 53 { ::1; **IPv6 Lokale server**; };
directory “/var/named”;
dump-file “/var/named/data/cache_dump.db”;
statistics-file “/var/named/data/named_stats.txt”;
memstatistics-file “/var/named/data/named_mem_stats.txt”;
allow-new-zones yes;
allow-transfer {trusted;};
dnssec-enable yes;
dnssec-validation yes;
dnssec-lookaside auto;
auth-nxdomain no;

/* Path to ISC DLV key */
bindkeys-file “/etc/named.iscdlv.key”;

managed-keys-directory “/var/named/dynamic”;

pid-file “/run/named/named.pid”;
session-keyfile “/run/named/session.key”;
};

/*RNDC Key uit Primaire (Plesk) server*/
key “rndc-key-***” {
algorithm hmac-md5;
secret “****”;
};

controls {
inet * port 953 allow { ** IP Adressen primaire en lokale server, gescheiden door een ;**} keys { “rndc-key-***”; };
};

logging {
channel default_debug {
file “data/named.run”;
severity dynamic;
};
};
zone “.” IN {
type hint;
file “named.ca”;
};

 

include “/etc/named.rfc1912.zones”;
include “/etc/named.root.key”;

  • mkdir /var/named/
  • chown named:named /var/named/ -R
  • chmod 0770 /var/named -R
  • systemctl start name
  • reboot

Dit zou normaal voldoende moeten zijn, maar ik bleef authenticatie fouten krijgen vanuit de primaire DNS server (Plesk), deze server heb ik daarna nog een keer herstart en dat heeft uiteindelijk de problemen verholpen.

Ik heb me hier dan enkel gericht op het werkend maken van de slave DNS server, de vervolgstappen omvatten uiteraard het beveiligen van de server maar dat is buiten de scope van deze post.

Microsoft Power BI Gateway (Deel 2)

In de vorige post hebben we gekeken naar hoe we data uit Profit via de webconnectoren naar JSON files kunnen halen. Om deze files ook beschikbaar te maken in de cloud voor Power Bi kunnen we het beste gebruik maken van de Power Bi gateway. Hier onder vind je een instructie van hoe deze te installeren en configureren. De instructie is op basis van de documentatie van Microsoft die je hier vind.

Stap 1: Download Enterprise Gateway

Om de Gateway te kunnen downloaden moet je inloggen op Office.com en dan doorklikken naar de PowerBI omgeving.

Office 365 Power BIRechts bovenaan heb je een “download” knop, kies daar voor “Data Gateway”

Power BI Gateway

Je wordt vervolgens doorverwezen naar de download pagina, klik daar op de “Download Gateway” optie.

Download Power BI gateway

Stap 2: Installeer Enterprise Gateway

Na de download kan je de installer starten, als er al andere applicaties draaien op de server is het zeer waarschijnlijk dat aan alle requirements voldaan wordt voor de installatie.

Power BI Gateway installatie

Je krijgt de keuze voor twee types gateway, kies hier voor de aanbevolen optie en dus NIET voor de personal mode!

Power BI Gateway Installtie modusDruk op volgende tot de installatie daadwerkelijk start.

Stap 3: Koppel Gateway

Na de installatie moet deze gekoppeld worden. Het maakt in principe niet al te veel uit welke user hier gekoppeld wordt, maar:

Alleen deze user kan:

  • aanpassingen doen aan de configuratie van de gateway zelf
  • Logging exporteren

Verder:

  • Er wordt een recovery code aangemaakt waarmee we deze user kunnen omzeilen, bewaar deze goed
  • Je moet met deze user in kunnen loggen op Office.com en je hebt dus een volledige O365 licentie nodig!

Power BI Gateway user

Je zal vervolgens een pop-up krijgen voor je credentials.

Vervolgens moet je een keuze maken of je een oude gateway wil recoveren of dat je een nieuwe gaat installeren, in ons geval installeren we dus een nieuwe:

Power BI Gateway Nieuw of Recover

Geef de gateway een naam en voer de herstelsleutel in, bewaar deze goed, we hebben deze nodig als we de gateway ooit zouden willen migreren naar een nieuwe server.

Power BI Gateway Recovery Key en naam

Je krijgt vervolgens de instellingen te zien, deze staan goed, dus die kan je zo laten:

Power BI Gateway regio

Zet tot slot het vinkje voor het verzenden van de gebruikersgegevens nog even uit. Vervolgens is de installatie klaar.

Power BI Gateway installatie voltooid

Stap 4: Autoriseer Gateway

Tot slot moet de gateway nog geautoriseerd worden. Deze is op dit moment alleen beschikbaar voor de user die je bij de installatie hebt opgegeven.

Log als deze user in op Offic.com, ga naar de PowerBI pagina en kies deze keer voor de “Settings” knop en kies voor manage gateways

Power BI Gateway autorisatie

Klik vervolgens op administrators:

Power BI Gateway administrators

 

 

De rest van de configuratie vind plaats vanuit Power Bi zelf.

Mattermost (Slack alternatief)

Samenwerking en onderlinge communicatie binnen een organisatie kunnen een flinke uitdaging zijn, zeker als jij en je collega’s elkaar niet regelmatig zien kan dat ten koste gaan van de samenwerking en kennisdeling.

Nou zijn er meerdere mogelijkheden om deze afstand tussen mensen te verkleinen, zo heb je Skype for Business voor het chat, bel en video element, je kan Sharepoint inzetten als een collaboration platform en natuurlijk hebben we ook nog e-mail, sms, Whatsapp en al dat soort oplossingen. Maar als je iets zoekt dat op alle platformen out of the box werkt, laagdrempelig is en ook nog eens brede ondersteuning bied voor allerlei koppelingen kom je toch snel uit op een oplossing als bijvoorbeeld Slack.

Het grote nadeel van Slack is echter dat het een relatief prijzige oplossing is, zeker wanneer je met grotere groepen gebruikers te maken hebt. Daarnaast is het een cloud dienst en je kan je afvragen of je je interne bedrijfscommunicatie volledig via een cloudoplossing wil laten lopen.

Wat is Mattermost?

Mattermost is een webbased platform waarop gebruikers in “chat” style met elkaar kunnen praten, maar ook direct documenten kunnen delen. Daarnaast heeft het ondersteuning voor het aanmaken van zowel public als private kanalen waar je met groepen samen over bepaalde onderwerpen of projecten kan praten.

Het sterkste punt van dit soort tools is de mate waarin je het kan integreren met andere systemen, Mattermost kent een krachtig webhook systeem dat over het algemeen compatible is met het Slack systeem. Hierdoor zijn er ook direct al een groot aantal koppelingen beschikbaar met allerlei ontwikkel systemen. Je kan hier zo ver gaan dat je complete bots inricht die taken voor de gebruikers kunnen uitvoeren, of het simpel laten zien van updates via een RSS feed.

mattermost screen

Net zoals de alternatieven werkt Mattermost eigenlijk op alle soorten clients, het maakt dus niet uit of een gebruiker nou Windows, Linux of eventueel een Mac gebruikt om het systeem te gebruiken, het ziet er zo goed als altijd hetzelfde uit.

Waarom Mattermost?

Als we puur naar de functionaliteit kijken zou er niet direct een aanleiding zijn om Mattermost boven Slack te verkiezen. Sterker nog, Slack is eigenlijk beter ondersteund en is voor mensen die gelijktijdig op meerdere platformen of voor meerdere klanten in dergelijke omgevingen moeten werken een beter alternatief. Daarnaast is het een net even bekender platform waardoor er meer mensen bekend mee zijn.

Echter, de kosten van Slack kunnen flink oplopen als je met grotere groepen gebruikers werkt. Mattermost heeft daarentegen een versie die je zelf kan hosten die qua functionaliteit voor verreweg de grootste groepen gebruikers prima voldoet. Het voordeel wat je daarmee hebt is dat je zelf volledig controle krijgt over waar je het platform draait en wie er eventueel bij de data kan. Het zelf hosten van de omgeving kost natuurlijk ook geld, maar zelfs een VPS van een euro of 10 per maand kan al voldoende zijn voor het draaien van een omgeving voor 500+ gebruikers. (1 core, 1GB RAM).

Een ander voordeel van het zelf hosten van het platform is dat je de server ook direct kan gebruiken voor eventuele andere services die je nodig hebt om bijvoorbeeld je RSS feeds te posten in de diverse channels. Nou zijn hier genoeg andere aanbieders voor, maar je kan er eenvoudig voor kiezen om ook dit deel van het systeem volledig in eigen beheer te houden.

Tot slot is er nog het “voordeel” dat het open source software betreft. Je kan betwisten of dit uiteindelijk nou echt een voordeel is, maar voor nu betekend het in ieder geval wel dat er een grote groep mensen meewerkt aan het verder ontwikkelen en het beveiligen van het product.

Concrete toepassingen

We hebben met Duh-Events inmiddels een half jaar ervaring opgedaan met Mattermost, in eerste instantie alleen voor communicatie tussen onze vrijwilligers, maar sinds kort ook voor de communicatie rondom onze competities met de deelnemers van de evenementen. We hadden verwacht dat het toelaten van de bezoekers tot een enorme wildgroei in vervuiling en channels op zou leveren maar dat is ons uiteindelijk alles meegevallen.

Het platform leent zich het beste voor de korte vragen die je eventueel even aan elkaar of aan een groep wil stellen en de eventuele discussie die daar op volgt. Vooral omdat alle berichten ook historisch doorzoekbaar zijn is het platform ook prima geschikt als archief voor dit soort discussies.

Gezien het zowel op telefoons als ieder denkbaar ander platform met een browser werkt kunnen de meeste gebruikers eenvoudig aanhaken. Het goed instellen van je highlites is wel een must als je niet de hele tijd zelf wil monitoren of er voor jou belangrijke info voorbij komt. Deze mentions kan je ook weer koppelen aan bijvoorbeeld een mailtrigger (of webhook) om er voor te zorgen dat je een berichtje krijgt op het moment dat iemand iets tegen je zegt of over een onderwerp begint wat jouw interesse heeft.

Aandachtspunten

Er zijn wel nog een aantal aandachtspunten om rekening mee te houden als je gebruik wil gaan maken van Mattermost. Het meest beperkende is dat je op dit moment eigenlijk maar twee rechtenniveau’s hebt, administrator en user. Je kan bijvoorbeeld het aanmaken van webhooks verder niet autoriseren, de administrators kunnen dit, maar verder niemand. Dat heeft dus als gevolg dat je iemand volledige admin rechten moet geven op het moment dat hij/zij webhooks aan moet kunnen maken of beheren. Alternatief is dat je alle gebruikers webhooks aan laat maken, maar dat kan ook weer ongewenste gevolgen hebben.

Het beheren van de gebruikers is sowieso redelijk omslachtig, je kan gebruikers die eenmaal een account hebben inactief maken, maar bijvoorbeeld niet selectief weren van (publieke) groepen. Binnen een zakelijke omgeving is dit misschien niet heel belangrijk, maar voor het geval waarbij we onze bezoekers ook op het systeem laten zou het handig zijn om een lastige gebruiker al dan niet tijdelijk uit een channel te kunnen weren. Overigens kan je iemand wel uit een channel gooien, maar tenzij het een private channel betreft kan hij/zij direct weer toegang krijgen tot het channel.

Conclusie

Als je op zoek bent naar een tool waarmee een groep gebruikers gemakkelijk chat-based met elkaar kunnen communiceren is dit zeker het overwegen waard. Het gemak waarmee het systeem werkt (en te beheren is) en de eenvoud bij het uitwisselen van bestanden binnen de groep gebruikers maken het een erg toegankelijk systeem.

Gezien de gebruikers zelf eenvoudig groepen aan kunnen maken heb je weinig onderhoud aan de omgeving, het updaten van de software is tot op heden altijd relatief eenvoudig in een paar minuten te doen dus ook op dat vlak valt het onderhoud mee.

De performance van het systeem is ook prima. De native Android en iOS apps hebben wel een probleem dat het laden van de app lang duurt, maar ik neem aan dat dat probleem op termijn vanzelf een keer verholpen wordt.

Links

  • Mattermost (Site van de makers)
  • Franz (Client voor onder andere Mattermost)