Cns.DataQuality.psm1

<#
 
  (c) 2020 CNS International
 
#>


If($Verbose) 
{
  $VerbosePreference = "Continue" 
}

$ErrorActionPreference = "Stop"
$WarningPreference = "Continue"
$ProgressPreference = "SilentlyContinue"

$DqConnectionSettings = $Null
$DqContext = $Null

Function Get-ConnectionSettings
{
  [OutputType([PsCustomObject])]
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$True, position=1)]
    [String] $PortalUrl
  )
  
  Write-Verbose "Requesting connection settings from '$($PortalUrl)'..." 
  Try 
  {
    $WebResponse = Invoke-WebRequest -UseBasicParsing -Uri $PortalUrl -Method Get
  }
  Catch [System.Net.WebException]
  {
    $ResponseBody = ""
    If ($_.Exception.Response)
    {
      $Stream = $_.Exception.Response.GetResponseStream()
      $StreamReader = New-Object System.IO.StreamReader($Stream)
      $StreamReader.BaseStream.Position = 0
      $ResponseBody = $StreamReader.ReadToEnd() | ConvertFrom-Json -ErrorAction SilentlyContinue
      $StreamReader.Close()
    }

    Write-Host "Connectie naar '$($PortalUrl)' niet gelukt: '$($_.Exception.Message)'." -ForegroundColor Red
    If ($WebResponse -and $ResponseBody.Message)
    {
      Write-Warning "Gedetaileerde informatie: $($ResponseBody.Message)"
    }

    Return $False
  }

  If (-not($WebResponse))
  {
    Write-Host "Connectie naar '$($PortalUrl)' niet gelukt. Controleer of de url juist is. Bij twijfel neem contact op met uw systeembeheerder of een consultant van CNS." -ForegroundColor Red
    Return;
  } 

  Write-Verbose "Searching for connection settings within webpage content..."
  $WebContent = $WebResponse.Content -replace '\n', '' -replace '\r', '' -replace '\s{2,}', ' '
  If ($WebContent -match "Application\.start\(\'(http.*)\',\s\'(http.*)\'\)")
  {
    $ApiUrl = $Matches.1
    $StsUrl = $Matches.2 

    If (-not($ApiUrl.EndsWith('/'))) { $ApiUrl = $ApiUrl + "/" }

    Write-Verbose "Connection settings found: ApiUrl: $($ApiUrl), StsUrl: $($StsUrl)."
    Return [PSCustomObject] @{
      ApiUrl = $ApiUrl
      StsUrl = $StsUrl
    }
  }
  Else 
  {
    Write-Host "Connectie naar '$($PortalUrl)' geslaagd maar geen connectiegegevens gevonden. Controleer of de url juist is. Bij twijfel neem contact op met uw systeembeheerder of een consultant van CNS." -ForegroundColor Red
    Return;
  }
}

Function New-Context
{
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$True)]
    [String] $StsUrl,

    [Parameter(Mandatory=$True)]
    [String] $ApiUrl,

    [Parameter(Mandatory=$True)]
    [String] $PortalUrl,

    [Parameter(Mandatory=$False)]
    [System.Management.Automation.PSCredential] $Credential = $Null
  )

  Try
  {
    Write-Verbose "Authenticeren met de Secure Token Service van DQ Monitor..."
    If ($Credential)
    {
      $StsResponse = Invoke-WebRequest -UseBasicParsing -Uri $StsUrl -Credential $Credential -Method Get -ErrorAction Ignore
    }
    Else 
    {
      $StsResponse = Invoke-WebRequest -UseBasicParsing -Uri $StsUrl -UseDefaultCredentials -Method Get -ErrorAction Ignore
    }

    $JsonObject = $StsResponse.Content | ConvertFrom-Json 
    $Token = $JsonObject.id_token
    $TokenType = $JsonObject.token_type
    
    $Authorization = [string]::Format("{0} {1}", $TokenType, $Token)
    $Headers = @{
      "Accept"        = "application/json"
      "Content-Type"  = "application/json;charset=UTF-8"
      "Authorization" = $Authorization
      "Referer"       = $PortalUrl
    }
    
    Return [PsCustomObject] @{
      Token = $Token;
      Headers = $Headers;
      ApiUrl = $ApiUrl;
      EntityControllerUrl = "$($ApiUrl)entities";
      CheckControllerUrl = "$($ApiUrl)checks";
    }
  }
  Catch 
  {
    $ErrorMessage = @"
Fout opgetreden bij het opvragen van een token bij Secure Token Service (STS) van DQ Monitor. Foutmelding:
$($_.Exception.Message)
"@

    Write-Error $ErrorMessage;
    Return;
  }
}

Function Validate-Context 
{
  [CmdletBinding()]
  Param()

  If ($DqContext -eq $Null)
  {
    Write-Error "Geen actieve context gevonden voor DQ Monitor. Gebruik het commando 'Set-DqContext' om een nieuwe context aan te maken."
    Return;
  }
}

Function Remove-Check
{
  [OutputType([Bool])]
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$True)]
    [ValidateNotNull()]
    [Int] $CheckId
  )

  Validate-Context

  Write-Verbose "Verwijderen van controle met Id '$($CheckId)'..."
  Try
  {
    $Response = Invoke-WebRequest -UseBasicParsing -Uri "$($DqContext.CheckControllerUrl)/$($CheckId)" -Method Delete -Header $DqContext.Headers
    Return $True 
  }
  Catch [System.Net.WebException]
  {
    $Stream = $_.Exception.Response.GetResponseStream()
    $StreamReader = New-Object System.IO.StreamReader($Stream)
    $StreamReader.BaseStream.Position = 0
    $ResponseBody = $StreamReader.ReadToEnd() | ConvertFrom-Json | ConvertFrom-Json -ErrorAction SilentlyContinue
    $StreamReader.Close()

    Write-Error "Fout bij verwijderen van controle met id '$($CheckId)': '$($_.Exception.Message)'."
    If ($ResponseBody -and $ResponseBody.Message)
    {
      Write-Warning "Gedetaileerde informatie: $($ResponseBody.Message)"
    }

    Return $False
  }
}

Function Validate-CheckJsonFile
{
  [OutputType([Boolean])]
  [CmdletBinding()]
  Param(
    [String] $CheckJsonFile
  )
  
  If (-not(Test-Path -Path $CheckJsonFile -PathType Leaf))
  {
    Write-Host "Het bestand '$($CheckJsonFile)' kon niet worden gevonden."
    Return $False;
  }

  $CheckJsonRaw = Get-Content $CheckJsonFile -Raw -ErrorAction Ignore
  if (!$CheckJsonRaw)
  {
    Write-Error "Fout ontstaan bij inlezen van bestand '$($CheckJsonFile)'."
    Return;
  }

  Write-Verbose "Validatie voor geldige JSON..."
  Try
  {
    $CheckJsonObject = $CheckJsonRaw | ConvertFrom-Json 
  }
  Catch 
  {
    Write-Host "Opgegeven bestand '$($CheckJsonFile)' bevat geen geldige JSON. Gebruik bij twijfel een JSON validator (bijv. https://jsonlint.com/) om je JSON bestand te controleren." -ForegroundColor Red
    Return $False;
  }

  If (-not($CheckJsonObject.PSobject.Properties.name -match "checks") -or $CheckJsonObject.checks.Count -eq 0)
  {  
    Write-Host "Opgegeven bestand '$($CheckJsonFile)' bevat geen controles of deze is leeg." -ForegroundColor Red
    Return $False;
  }

  Write-Verbose "JSON validatie voltooid."
  Return $True 
}

<#
 
  Prepare DQ Monitor Api check objects to upload.
 
#>

Function Get-ApiChecksToUpload
{
  [OutputType([Array])]
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$True)]
    [ValidateNotNullOrEmpty()]
    [String] $CheckJsonRaw,

    [Parameter(Mandatory=$True)]
    [ValidateNotNullOrEmpty()]
    [String] $CheckStatementRootPath
  )

  Write-Verbose "Voorbereiden requests naar de server..."
  $CheckJsonObject = $CheckJsonRaw | ConvertFrom-Json
  $ChecksToUpload = @()

  If ($CheckJsonObject.checks.Count -eq 0)
  {
    Return $ChecksToUpload;
  }

  # First get information about available entities.
  [Array]$Entities = Get-DqEntities

  ForEach($CustomCheck in $CheckJsonObject.checks)
  {
    $StatementFile = $CustomCheck.statementFile
    If (-not([System.IO.Path]::IsPathRooted($StatementFile)))
    {
      $StatementFile = Join-Path -Path $CheckStatementRootPath -ChildPath $StatementFile
    }
    
    If (-not(Test-Path -Path $StatementFile -PathType Leaf))
    { 
      Write-Warning "T-SQL statement bestand '$($StatementFile)' kon niet worden gevonden."
      Write-Warning "Controle $($CustomCheck.name)' zal worden overgeslagen."
      Continue;
    }

    $Statement = [String](Get-Content -Path $StatementFile -Raw -ErrorAction Stop)
   
    $EntityId = -1;
    If ([Int]::TryParse($CustomCheck.entity, [ref]$EntityId))
    {
      $EntityId = [Int]$CustomCheck.entity
    }
    Else
    {
      Write-Verbose "Opzoeken id voor entiteit '$($CustomCheck.entity)'..."
      
      $Entity = $Entities | Where-Object { $_.Name -eq $CustomCheck.entity } 
      If (-not($Entity))
      {
        Write-Warning "Opgegeven entiteit '$($CustomCheck.entity)' kon niet gevonden worden op de server. Neem contact op met een CNS consultant om deze entiteit op te voeren."
        Write-Warning "Controle '$($CustomCheck.name)' zal worden overgeslagen."
        Continue;
      }
      
      $EntityId = $Entity.Id
    }
   
    Try 
    {
      $ChecksToUpload += [PSCustomObject]@{
        check = @{
          name = $CustomCheck.name;
          entityId = $EntityId;
          tags = $(If ($CustomCheck.PSObject.Properties.name -match "tags") { $CustomCheck.tags } Else { @() });
      
          documentation = [PSCustomObject]@{
            caption = $CustomCheck.caption;
            description = $CustomCheck.description;
            technicalDescription = $CustomCheck.technicalDescription;
          };
      
          source = $CustomCheck.source;
          statement = $Statement;
        }
      }
    }
    Catch
    {
      Write-Warning "Er is een fout opgetreden bij het voorbereiden van controle '$($CustomCheck.name)'. Controleer de syntax van het bestand."
      Write-Warning "Deze controle wordt genegeerd."
      Continue; 
    }
  }

  Return $ChecksToUpload;
}

Function Upload-ChecksToApi
{
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$True)]
    [ValidateNotNull()]
    [Object[]] $ChecksToUpload,

    [Parameter(Mandatory=$True)]
    [ValidateNotNullOrEmpty()]
    [String] $CheckStatementRootPath,

    [Parameter(Mandatory=$False)]
    [Switch] $Force
  )

  [Array]$ExistingCustomChecks = Get-DqChecks -CustomOnly

  $Imported = 0;
  Write-Verbose "Uploaden van controles naar DQ Monitor API..."

  ForEach($Check in $ChecksToUpload)
  {
    $ExistingCheck = $ExistingCustomChecks | Where-Object { $_.Name -eq $Check.check.name }
    If ($ExistingCheck)
    {
      If (-not $Force.IsPresent)
      {
        Write-Warning "Controle '$($Check.check.name)' bestaat al. Als u de controle wilt overschrijven, gebruik dan parameter 'Force' zodat deze eerst wordt verwijderd."
        Write-Warning "LET OP: Alle resultaten en historie gaan verloren als deze controle wordt verwijderd. Deze controle wordt voor nu genegeerd."
        Continue;
      }

      # Verwijderen van custom controle zodat deze hieronder kan worden toegevoegd.
      Write-Verbose "Verwijderen van controle '$($Check.check.name)' met id '$($ExistingCheck.Id)'..."
      $Result = Remove-Check -CheckId $ExistingCheck.Id -ErrorAction SilentlyContinue
      If (-not($Result))
      {
        Write-Warning "Verwijderen van controle '$($Check.check.name)' is mislukt. Deze wordt voor nu genegeerd."
        Continue;
      }
    }

    Try
    {
      Write-Verbose "Controle '$($Check.check.name)' uploaden..."
      $Response = Invoke-WebRequest -UseBasicParsing -Uri $DqContext.CheckControllerUrl -Method Post -Header $DqContext.Headers -Body ($Check | ConvertTo-Json)
      
      If ($ExistingCheck)
      {
        Write-Host "Controle '$($Check.Check.Name)' is verwijderd en opnieuw opgevoerd."
      }
      Else 
      {
        Write-Host "Controle '$($Check.Check.Name)' is opgevoerd."
      }

      $Imported += 1;
    }
    Catch [System.Net.WebException]
    {
      $Stream = $_.Exception.Response.GetResponseStream()
      $StreamReader = New-Object System.IO.StreamReader($Stream)
      $StreamReader.BaseStream.Position = 0
      $ResponseBody = $StreamReader.ReadToEnd() | ConvertFrom-Json | ConvertFrom-Json -ErrorAction SilentlyContinue
      $StreamReader.Close()
   
      Write-Warning "Fout bij opvoeren/uploaden controle '$($Check.check.name)': '$($_.Exception.Message)'."
      If ($ResponseBody -and $ResponseBody.Message)
      {
        Write-Warning "Gedetaileerde informatie: $($ResponseBody.Message)"
      }
    }
  }

  Write-Host "$($Imported) controle(s) opgevoerd."
}

<#
 
 
  PUBLIC METHODS
 
 
#>



Function Get-DqContext
{
  [OutputType([PsCustomObject])]
  [CmdletBinding()]
  Param()

  Validate-Context -ErrorAction Stop

  Return $DqConnectionSettings

  <#
    .SYNOPSIS
      Deze functie vraagt de huidige verbindinggegevens op naar een DQ Monitor Webservice.
   
    .DESCRIPTION
      De Get-DqContext haalt verbindinggegevens op, die eerder is opgeslagen via Set-DqContext, over een DQ Monitor Webservice.
         
    .INPUTS
      Geen.
   
    .OUTPUTS
      Geen.
   
    .EXAMPLE
      PS> Get-DqContext
       
      ApiUrl StsUrl
      ------ ------
      https://woongeluk-api.dq-monitor.nl/api/ https://woongeluk-sts.dq-monitor.nl/oauth/ro
   
    .LINK
      Set-DqContent
  #>

}

Function Set-DqContext
{
  [OutputType([PsCustomObject])]
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$True, position=1)]
    [ValidateNotNullOrEmpty()]
    [String] $PortalUrl,

    [Parameter(Mandatory=$False, position=2)]
    [ValidateNotNull()]
    [System.Management.Automation.PSCredential] $Credential = $Null
  )

  $Result = Get-ConnectionSettings -PortalUrl $PortalUrl
  If (-not($Result))
  {
    Write-Host "Handeling afgebroken." -ForegroundColor Red 
    Return;
  }

  Set-Variable -Name "DqConnectionSettings" -Value $Result -Scope Script | Out-Null
  $Context = New-Context -StsUrl $DqConnectionSettings.StsUrl -ApiUrl $DqConnectionSettings.ApiUrl -PortalUrl $PortalUrl -Credential $Credential
  If (-not($Context))
  {
    Write-Host "Handeling afgebroken." -ForegroundColor Red
    Return;
  }

  Set-Variable -Name "DqContext" -Value $Context -Scope Script | Out-Null
  $DqConnectionSettings

  <#
    .SYNOPSIS
      Deze functie creëert en bewaard verbindinggegevens naar een DQ Monitor Webservice zodat deze gebruikt kan worden door andere functies in de huidige sessie.
    
    .DESCRIPTION
      De Set-DqContext plaatst authenticatie informatie, over DQ Monitor, voor andere functies die gedraaid worden in de huidige sessie. Deze informatie bevat de URL's om verbinding te maken.
         
    .PARAMETER PortalUrl
      De volledige url naar de DQ Monitor Portal. Deze wordt gebruikt om te achterhalen hoe verbinding gelegd moet worden met de onderdelen van de DQ Monitor Webservice.
     
    .PARAMETER Credential
      Optioneel: Een credential object verkregen via Get-Credential, om authenticatie met de DQ Monitor Webservice te overrulen. Standaard wordt Windows Authenticatie gebruikt met de huidige gebruiker.
    
    .INPUTS
      Geen.
    
    .OUTPUTS
      Geen.
    
    .EXAMPLE
      PS> Set-DqContext -PortalUrl "http://dq-portal"
       
      ApiUrl StsUrl
      ------ ------
      http://dq-api/api/ http://dq-sts/oauth/ro
    
    .EXAMPLE
      PS> Set-DqContext -PortalUrl "https://woongeluk.dq-monitor.nl" -Credential $Credential
       
      ApiUrl StsUrl
      ------ ------
      https://woongeluk-api.dq-monitor.nl/api/ https://woongeluk-sts.dq-monitor.nl/oauth/ro
  #>

}

Function Get-DqEntities
{
  [OutputType([Array])]
  [CmdletBinding()]
  Param()

  Validate-Context

  Write-Verbose "Ophalen van alle entiteiten uit de DQ Monitor API..."
  $Response = Invoke-WebRequest -UseBasicParsing -Uri $DqContext.EntityControllerUrl -Method Get -Header $DqContext.Headers -ErrorAction Stop
  $Entities = $Response.Content | ConvertFrom-Json | Select -ExpandProperty Entities
  Write-Verbose "$($Entities.Count) entiteiten gevonden."
  Return [Array]$Entities

  <#
    .SYNOPSIS
      Deze functie haalt alle entiteiten op uit een DQ Monitor Webservice.
   
    .DESCRIPTION
      De Get-DqEntities functie haalt een lijst op van entiteiten die bekend zijn bij de DQ Monitor Webservice.
      Voordat deze functie gebruikt wordt, zorg ervoor dat de Context is gezet via functie Set-DqContext.
     
    .INPUTS
      Geen.
   
    .OUTPUTS
      Array met JSON objecten die entiteiten representeren.
  
    .EXAMPLE
      PS> Get-DqEntities
      {}
   
    .LINK
      Set-DqContext
  #>

}

Function Get-DqChecks
{
  [OutputType([Array])]
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$False)]
    [Switch] $CustomOnly
  )

  Validate-Context

  If ($CustomOnly.IsPresent -and $CustomOnly)
  {
    Write-Verbose "Ophalen aanwezige klantencontroles van DQ Monitor API..."
  }
  Else 
  {
    Write-Verbose "Ophalen alle controles van DQ Monitor API..."
  }

  $Response = Invoke-WebRequest -UseBasicParsing -Uri $DqContext.CheckControllerUrl -Method Get -Header $DqContext.Headers -ErrorAction Stop
  $Checks = $Response.Content | ConvertFrom-Json | Select -ExpandProperty Checks

  If ($CustomOnly.IsPresent -and $CustomOnly)
  {
    $CustomChecks = @($Checks | Where-Object { $_.IsCustom -eq $True })
    Write-Verbose "Totaal $($Checks.Count) controle(s) gevonden waarvan $($CustomChecks.Count) klantencontrole(s)."
    $Checks = $CustomChecks
  }
  Else 
  {
    Write-Verbose "$($Checks.Count) controles gevonden."
  }

  Return [Array] ($Checks | Sort-Object { $_.Name })

  <#
    .SYNOPSIS
      Deze functie haalt alle controles op uit een DQ Monitor Webservice.
   
    .DESCRIPTION
      De Get-DqChecks functie haalt een lijst op van controles die bekend zijn bij de DQ Monitor Webservice.
      Voordat deze functie gebruikt wordt, zorg ervoor dat de Context is gezet via functie Set-DqContext.
   
    .PARAMETER CustomOnly
      Optioneel: Indicatie dat alleen een lijst met eigen gemaakte controles van de klant opgehaald moeten worden.
       
    .INPUTS
      Geen.
   
    .OUTPUTS
      Array met JSON objecten die controles representeren.
     
    .EXAMPLE
      PS> Get-DqChecks
      {}
   
    .EXAMPLE
      PS> Get-DqChecks -CustomOnly
      {}
 
    .LINK
      Set-DqContext
  #>

}

Function Get-DqChecksFormatted
{
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$False)]
    [Switch] $CustomOnly
  )

  If ($CustomOnly.IsPresent -and $CustomOnly)
  { 
    [Array]$CustomChecks = Get-DqChecks -CustomOnly
  }
  Else 
  {
    [Array]$CustomChecks = Get-DqChecks
  }

  If ($CustomChecks.Count -eq 0)
  {
    Write-Warning "Geen controles gevonden."
    Return;
  }
  
  Write-Host " "
  Write-Host "Naam".PadRight(25) "Entiteit".PadRight(15) "Omschrijving"
  Write-Host "-".PadRight(25, "-") "-".PadRight(15, "-") "-".PadRight(40, "-")
  For($x=1;$x -le $CustomChecks.Count; $x++)
  {
    Write-Host ([String]::Format("{0} {1} {2}", $CustomChecks[$x-1].Name.PadRight(25), $CustomChecks[$x-1].Entity.PadRight(15), $CustomChecks[$x-1].Documentation.Description.Replace([Char]10, ' ').Replace([Char]13, ' ')));
  }

  <#
    .SYNOPSIS
      Deze functie haalt alle controles op uit een DQ Monitor Webservice en presenteert deze op een leesbare manier.
   
    .DESCRIPTION
      De Get-DqChecksFormatted functie haalt een lijst op van controles die bekend zijn bij de DQ Monitor Webservice.
      Het resultaat wordt in een geformatteerde tabel gepresenteerd.
      Voordat deze functie gebruikt wordt, zorg ervoor dat de Context is gezet via functie Set-DqContext.
   
    .PARAMETER CustomOnly
      Optioneel: Indicatie dat alleen een lijst met eigen gemaakte controles van de klant opgehaald moeten worden.
       
    .INPUTS
      Geen.
   
    .OUTPUTS
      Geen.
   
    .EXAMPLE
      PS> Get-DqChecksFormatted
   
      Naam Entiteit Omschrijving
      ------------------------- --------------- ----------------------------------------
      ... ... ...
      MY_CUSTOM_CHECK006 Eenheid Controleert of er aanwezigheid en geldigheid controles aanwezig zijn.
      WOONGELUK_REL_GEG_GELDIG Relatie Controleert per voorbeeldrelatie of de adresgegevens correct zijn ingevuld. Controle gaat alleen over relaties die nog staan ingeschreven.
      WOONGELUK_REL_GEG_GELDIG2 Relatie Controleert per voorbeeldrelatie of de adresgegevens correct zijn ingevuld. Controle gaat alleen over relaties die nog staan ingeschreven.
   
   
    .EXAMPLE
      PS> Get-DqChecksFormatted -CustomOnly
   
      Naam Entiteit Omschrijving
      ------------------------- --------------- ----------------------------------------
      MY_CUSTOM_CHECK006 Eenheid Controleert of er aanwezigheid en geldigheid controles aanwezig zijn.
      WOONGELUK_REL_GEG_GELDIG Relatie Controleert per voorbeeldrelatie of de adresgegevens correct zijn ingevuld. Controle gaat alleen over relaties die nog staan ingeschreven.
      WOONGELUK_REL_GEG_GELDIG2 Relatie Controleert per voorbeeldrelatie of de adresgegevens correct zijn ingevuld. Controle gaat alleen over relaties die nog staan ingeschreven.
   
    .LINK
      Set-DqContext
  #>

}

Function Import-DqChecks
{
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$True)]
    [ValidateNotNull()]
    [String] $CheckJsonFile,

    [Parameter(Mandatory=$False)]
    [Switch] $Force
  )

  Validate-Context

  Write-Verbose "Checks bestand '$($CheckJsonFile)' wordt gebruikt."

  $ValidationResult = Validate-CheckJsonFile -CheckJsonFile $CheckJsonFile -ErrorAction Stop
  If ($ValidationResult -ne $True)
  {
    Return;
  }

  $CheckJsonRaw = Get-Content $CheckJsonFile -Raw -ErrorAction Ignore
  $CheckStatementRootPath = Split-Path -Path $CheckJsonFile -Parent
  
  $ChecksToUpload = Get-ApiChecksToUpload -CheckJsonRaw $CheckJsonRaw -CheckStatementRootPath $CheckStatementRootPath
  If ($ChecksToUpload.Count -eq 0)
  {
    Write-Warning "Geen controles gevonden om te uploaden."
    Return;
  }

  If ($Force.IsPresent -and $Force)
  {
    Upload-ChecksToApi -ChecksToUpload $ChecksToUpload -CheckStatementRootPath $CheckStatementRootPath -Force
  }
  Else 
  {
    Upload-ChecksToApi -ChecksToUpload $ChecksToUpload -CheckStatementRootPath $CheckStatementRootPath
  }

  <#
    .SYNOPSIS
      Deze functie importeert een of meerdere controles naar de DQ Monitor Webservice.
   
    .DESCRIPTION
      De Import-DqChecks functie leest een checks definitiebestand uit en zal de controles die daarin gedefinieerd staan importeren naar de DQ Monitor Webservice.
      Voordat deze functie gebruikt wordt, zorg ervoor dat de Context is gezet via functie Set-DqContext.
   
    .PARAMETER CheckJsonFile
      Het volledige pad naar een .JSON bestand dat voorzien is van een verzameling controles die geupload moeten worden naar de DQ Monitor Webservice.
      Houdt er rekening mee dat SQL script bestanden die benoemd worden in het JSON bestand (eigenschap 'statement') in dezelfde map worden geplaatst als het JSON bestand.
   
    .PARAMETER Force
      Indien opgegeven zullen controles die eerder zijn opgevoerd in de DQ Monitor service worden verwijderd en daarna weer aangemaakt. Eventuele historie gaat hiermee verloren.
   
    .INPUTS
      Geen.
   
    .OUTPUTS
      Geen.
   
    .EXAMPLE
      PS> Import-DqChecks -CheckJsonFile "C:\DQ\controles.json"
      Controle 'WOONGELUK_REL_GEG_AANW1' is opgevoerd.
      Controle 'WOONGELUK_REL_GEG_AANW2' is opgevoerd.
      Controle 'WOONGELUK_REL_GEG_AANW3' is opgevoerd.
      3 controle(s) opgevoerd.
       
    .EXAMPLE
      PS> Import-DqChecks -CheckJsonFile "C:\DQ\controles2.json"
      WARNING: Controle 'WOONGELUK_REL_GEG_GELDIG' bestaat al. Als u de controle wilt overschrijven, gebruik dan parameter 'Force' zodat deze eerst wordt verwijderd.
      WARNING: LET OP: Alle resultaten en historie gaan verloren als deze controle wordt verwijderd. Deze controle wordt voor nu genegeerd.
      0 controles opgevoerd.
 
    .EXAMPLE
      PS> Import-DqChecks -CheckJsonFile "C:\DQ\controles2.json" -Force
      Controle 'WOONGELUK_REL_GEG_GELDIG' is verwijderd en opnieuw opgevoerd.
      1 controle(s) opgevoerd.
 
    .LINK
      Set-DqContext
  #>

}

Function Remove-DqCheck 
{
  [CmdletBinding(DefaultParameterSetName="ByCheckName")]
  Param(
    [Parameter(Mandatory=$True, ParameterSetName="ByCheckName", position=2)]
    [ValidateNotNullOrEmpty()]
    [String] $CheckName,

    [Parameter(Mandatory=$False, ParameterSetName="ByCheckName", position=3)]
    [Switch] $Force,

    [Parameter(Mandatory=$True, ParameterSetName="ByCheckObject", position=2)]
    [ValidateNotNull()]
    [PsCustomObject] $CheckObject
  )
  
  If ($PSCmdlet.ParameterSetName.Equals("ByCheckName"))
  {
    $CheckObjects = Get-DqChecks -CustomOnly | Where-Object { $_.Name.ToLowerInvariant().Equals($CheckName.ToLowerInvariant()) }
    If (-not($CheckObjects))
    {
      Write-Host "Controle '$($CheckName)' kon niet worden gevonden." -ForegroundColor Red
      Return $False;
    }

    $CheckObject = $CheckObjects | Select -First 1
  }
  
  If (-not($CheckObject.IsCustom))
  {
    Write-Host "Controle '$($CheckName)' is geen eigen gemaakte controle. Verwijderen wordt niet ondersteund." -ForegroundColor Red 
    Return;
  }

  If (-Not($Force.IsPresent) -or -not($Force))
  {
    Write-Host "Weet u zeker dat controle " -NoNewline
    Write-Host "'$($CheckObject.Name)'" -NoNewline -ForegroundColor White -BackgroundColor DarkRed 
    Write-Host " met Id " -NoNewline
    Write-Host "$($CheckObject.Id)" -NoNewline -ForegroundColor White -BackgroundColor DarkRed 
    Write-Host " verwijderd moet worden uit DQ Monitor? Dit kan niet ongedaan gemaakt worden:" 
  
    $Keuze = ""
    Do
    {
      $Keuze = Read-Host "Keuze (jn)"
    } While ($Keuze.Trim() -notmatch '^[jJnN]$')

    If ($Keuze.ToLowerInvariant().Equals("n"))
    {
      Write-Host "Handeling afgebroken."
      Return $False;
    }
  }

  Write-Verbose "Verwijderen van controle '$($CheckObject.Name)' met Id $($CheckObject.Id)..."
  $Result = Remove-Check -CheckId $CheckObject.Id -ErrorAction Stop 
  Write-Host "Controle is verwijderd."

  <#
    .SYNOPSIS
      Deze functie verwijdert een enkele controle uit een DQ Monitor Webservice.
   
    .DESCRIPTION
      De Remove-DqCheck functie geeft de mogelijkheid om een enkele controle te verwijderen uit een DQ Monitor Webservice.
      Voordat deze functie gebruikt wordt, zorg ervoor dat de Context is gezet via functie Set-DqContext.
   
    .PARAMETER CheckName
      De unieke naam van de controle zoals deze bekend is bij de DQ Monitor Webservice.
     
    .PARAMETER Force
      Optioneel: Indien opgegeven zal de controle worden verwijderd zonder eerst een bevestiging te vragen.
       
    .INPUTS
      Geen.
   
    .OUTPUTS
      Geen.
   
    .EXAMPLE
      PS> Remove-DqCheck -CheckName "WOONGELUK_REL_GEG_GELDIG"
      Weet u zeker dat controle 'WOONGELUK_REL_GEG_GELDIG' met Id 1 verwijderd moet worden uit DQ Monitor? Dit kan niet ongedaan gemaakt worden:
      Keuze (jn):
   
    .EXAMPLE
      PS> Remove-DqCheck -CheckName "WOONGELUK_REL_GEG_GELDIG" -Force
      Controle is verwijderd.
 
    .LINK
      Set-DqContext
  #>

}

Function Remove-DqChecks 
{
  [CmdletBinding()]
  Param()

  Write-Verbose "Verkrijgen van lijst van controles die verwijderd kunnen worden..."
  
  $Deleted = 0
  While ($True) 
  {
    # We only support custom checks at this point.
    [Array]$CustomChecks = Get-DqChecks -CustomOnly
   
    If ($CustomChecks.Count -eq 0)
    {
      If ($Deleted -gt 0)
      {
        Write-Warning "Geen controles meer gevonden die verwijderd kunnen worden."
      }
      Else 
      {
        Write-Warning "Geen controles gevonden die verwijderd kunnen worden."
      }
      
      Return;
    }
    
    Write-Host ""
    Write-Host "Maak een keuze uit een van onderstaande controles (kies 'Q' om af te breken):" 
    Write-Host " "
    Write-Host " #" "Naam".PadRight(25) "Entiteit".PadRight(15) "Omschrijving"
    Write-Host "-----" "-".PadRight(25, "-") "-".PadRight(15, "-") "-".PadRight(40, "-")
    For($x=1;$x -le $CustomChecks.Count; $x++)
    {
      Write-Host ([String]::Format("[{0}] {1} {2} {3}", $x.ToString().PadLeft(3, " "), $CustomChecks[$x-1].Name.PadRight(25), $CustomChecks[$x-1].Entity.PadRight(15), $CustomChecks[$x-1].Documentation.Description.Replace([Char]10, ' ').Replace([Char]13, ' ')));
    }
   
    Write-Host " "
    $Keuze = ""
    Do 
    {
      Do
      {
        $Keuze = Read-Host "Keuze (1-$($CustomChecks.Count) of q)"
      } While ($Keuze.Trim() -notmatch '^([0-9]{1,2})$|^[qQ]$')
   
      If($Keuze -match "^\d+$")
      {
        # Make sure we do not get out of bounds.
        If ([Int]$Keuze - 1 -gt ($CustomChecks.Count - 1) -or [Int]$Keuze -eq 0)
        {
          $Keuze = ""
        }
      }
    } While ([String]::IsNullOrEmpty($Keuze))
  
    Write-Host ""
    If ($Keuze.ToLowerInvariant().Equals("q"))
    {
      Write-Host "Handeling afgebroken."
      Return;
    }
   
    $Check = $CustomChecks[$Keuze-1];
    $Result = Remove-DqCheck -CheckObject $Check
    
    If ($Result)
    {
      $Deleted += 1;  
    }
  }

  <#
    .SYNOPSIS
      Deze functie geeft de gebruiker, aan de hand van een lijst van controles, de mogelijkheid deze te verwijderen uit een DQ Monitor Webservice.
   
    .DESCRIPTION
      De Remove-DqChecks functie haalt een lijst op met controles uit een DQ Monitor Webservice die kunnen worden verwijderd en presenteert deze.
      Via een keuzemenu kan de gebruiker een of meerdere controles verwijderen.
      Voordat deze functie gebruikt wordt, zorg ervoor dat de Context is gezet via functie Set-DqContext.
   
    .INPUTS
      Geen.
   
    .OUTPUTS
      Geen.
     
    .EXAMPLE
      PS> Remove-DqChecks
       
      Maak een keuze uit een van onderstaande controles (kies 'Q' om af te breken):
          # Naam Entiteit Omschrijving
      ----- ------------------------- --------------- ----------------------------------------
      [ 1] MY_CUSTOM_CHECK006 Eenheid Controleert of er aanwezigheid en geldigheid controles aanwezig zijn.
      [ 2] WOONGELUK_REL_GEG_GELDIG Relatie Controleert per voorbeeldrelatie of de adresgegevens correct zijn ingevuld. Controle gaat alleen over relaties die nog staan ingeschreven.
      [ 3] WOONGELUK_REL_GEG_GELDIG2 Relatie Controleert per voorbeeldrelatie of de adresgegevens correct zijn ingevuld. Controle gaat alleen over relaties die nog staan ingeschreven.
   
      Keuze (1-3 of q):
 
    .LINK
      Set-DqContext
  #>

}