PSPrimusQuery.psm1

#PSPrimusquery powershell wrapper for Visma primusquery
#Copyright (C) 2019,2020 Petri Asikainen
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; either version 2
#of the License, or (at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

function ImportConfiguration {
    param (
  [Parameter(Mandatory=$false)]
  [string]$server=$null
  )
    
    #Test for primusquery
    if((Test-Path "$PSScriptRoot\primusquery\primusquery.exe") -eq $false) {
       Throw "Kopioi primusquery sijaintiin $PSScriptRoot\primusquery"
    }
    
    $Configuration = Import-Configuration
    
    
    #migrate to support multiple named servers
    if ($null -eq $Configuration.Servers) {
       $Configuration.Servers = @{}
 
       $curserv = @{'server' = $Configuration.server;
                    'port' = $Configuration.port;
                    'Credential'= $Configuration.Credential }
       $Configuration.Servers.Add($Configuration.server,$curserv)
       $Configuration.DefaultServer = $Configuration.server
       $Configuration | Export-Configuration
    } 
    
    #Witch server to use
    if ( $server -ne "") {
        #test for requested server
        if ($server -ne "" -and $false -eq $Configuration.Servers.ContainsKey($server) ){
        throw "Pyydetty� palvelinta `"$($server)`" ei ole m��ritetty. Aja Set-PQueryConfig"
    
        }
        $serveralias = $server
    } else {
      $serveralias = $Configuration.DefaultServer
    }
    
    
    #Save used server information on root level of configuration
    #or use default server if none is given
    
    $Configuration.server = $Configuration.Servers[$serveralias].server
    $Configuration.port = $Configuration.Servers[$serveralias].port
    $Configuration.Credential = $Configuration.Servers[$serveralias].Credential


    if(!$Configuration.Credential.Password.Length) {
        $Configuration
        Write-Warning "Aseta Primuquerylle tunnus ja salasana Set-PSQuery komennolla."
        throw "Moduulia ei ole konfiguroitu. Aja Set-PQueryConfig"
    }
    
    $Configuration
}
<#
 .Synopsis
  M��ritt�� PSPrimusqueryn k�ytt�m�t palvelimet
 
 .Description
  T�ll� voi m��ritell� yhden tai usempia palvelimia tai palvelin aliaksia k�ytett�v�ksi primusqueryn kanssa.
 
 .Parameter server
  Palvelimen osoite tai verkkonimi.
 
 .Parameter serveralias
  Palvelimen alias. Jos tyhj� niin k�ytet��n server parametrin arvoa.
 
 .Parameter port
  Palvelimen portti.
 
 .Parameter Credential
  P��sytiedot primuserverille, m��rit� t�h�n muutuja joka sis�lt�� get-credential komennolla
  saadir tiedot, tai "(get-credential)" jolloin tunnus ja salasana kysyt��n m��rityksen yhteydess�.
 
 .Parameter RemoveServer
  Poistaa vastaavan palvelinaliaksen tiedot
 
 .Example
   Set-PQueryConfig -server 127.0.0.1 -port 1222 -Credential (get-credential)
   Lis�� palvelin
    
 .Example
   Set-PQueryConfig -server 127.0.0.1 -port 1224 -serveralias testi -Credential (get-ceredential)
    
   Lis�� testi-palvelin ja m��rit� sille alias
    
 .Example
    
   Set-PQueryConfig -server 127.0.0.1 -port 1224 -serveralias testi -SetAsDefault $true -Credential (get-ceredential)
   Lis�� testi-palvelin ja m��rit� se oletukseksi
 
 .Example
   Set-Primusquery -serveralias testi -RemoveServer $true
  
 .Example
   Set-Primusquery -serveralias testi -NewAlias vanhatesti
     
#>

function Set-PrimusQueryConfig { 
  [CmdletBinding()]
  param (
  [Parameter(Mandatory=$false)]
  [string]$server=$null,
  [Parameter(Mandatory=$false)]
  [string]$serveralias=$null,
  [Parameter(Mandatory=$false)]
  [string]$port =$null,
  [Parameter(Mandatory=$false)]
  [PSCredential]$Credential=$null,
  [Parameter(Mandatory=$false)]
  [bool]$SetAsDefaultServer=$false,
  [Parameter(Mandatory=$false)]
  [bool]$RemoveServer=$false,
  [Parameter(Mandatory=$false)]
  [string]$NewAlias=$null
  )
  
  
  $currentconfig = Import-Configuration
  
  #K�ytet��n aliaksena servernime� jos muuta ei oo annettu
  if ( $serveralias -eq "") {
      $serveralias = $server
  }

  if ($serveralias -eq "") {
    Write-Warning "M��rit� komennolle -server ja/tai -serveralias."
    throw "M��rit� komennolle -server ja/tai -serveralias"
  }

  
  if ($null -eq $currentconfig.Servers) {
     $currentconfig.Servers = @{};
  }
  
  #Add or update server to servers
  if ( $server -ne $null -or $port -ne $null -or $Credential -ne $null) {
      if ($false -eq $currentconfig.Servers.ContainsKey($serveralias)) {
        $curserv = @{};
      } else {
        $curserv =$currentconfig.Servers[$serveralias]
      }

      if ( $server -ne "") {
         $curserv.server = $server
      }
      if ( $port -ne "") {
         $curserv.port = $port
      }
      if ( $Credential -ne "") {
         $curserv.Credential = $Credential
      }

      if ($false -eq $currentconfig.Servers.ContainsKey($serveralias) ){
         $currentconfig.Servers.Add($serveralias,$curserv)
         } else {
            $currentconfig.Servers[$serveralias]= $curserv
      }
  }

  #set as default if asked or if no default
  if ($SetAsDefaultServer -eq $true -or $currentconfig.DefaultServer -eq $null) {
     $currentconfig.DefaultServer = $serveralias;
  }

  #RemoveServer
  if ($true -eq $currentconfig.Servers.ContainsKey($serveralias) -and $RemoveServer -eq $true ){
       $currentconfig.Servers.Remove($serveralias)
  }      

  #NewAlias
  if ($true -eq $currentconfig.Servers.ContainsKey($serveralias) -and $NewAlias -ne "" -and $NewAlias -ne $serveralias -and $currentconfig.Servers.ContainsKey($NewAlias) -eq $false ){
       $currentconfig.Servers.Add($NewAlias,$currentconfig.Servers.Remove($serveralias))
       $currentconfig.Servers.Remove($serveralias)
  }      

  if ( $currentconfig.DefaultServer -eq $serveralias -and $NewAlias -ne "") {
       $currentconfig.DefaultServer = $NewAlias
  }

  #save config
  $currentconfig | Export-Configuration
  
}
<#
 .Synopsis
  Palauttaa moduulin asetukset raakamuodossa
 
 .Description
  Voit tarkistella moduulin tallenettujaasetuksia
 
 .Example
   Get-PrimusQueryConfig -server 127.0.0.1 -port 1224 -serveralias testi -Credential (get-ceredential)
    
     
#>

function Get-PrimusQueryConfig {
   $script:Config = Import-Configuration
   $config
}
<#
 .Synopsis
  Palauttaa primusquery vastauksen XML-objektina
 
 .Description
  Kun primusquery m��ritys palautaa XML muotoista dataa palauttaa t�m� sen valmiiksi XML-objektina
  jatkok�siteely� varten.
 
 .Parameter server
  Palvelimen alias, jos et m��ritt�nyt aliasta erikseen Set-PrimusQueryConfig komennolla on alias palvelimen nimi tai osoite.
  Jos et m��rit� palvelinta k�ytet��n Set-PrimusQueryConfig komennolla m��ritetty� oletuspalvelinta
 
 .Parameter kysely
  Primusquery kyselyn nimi.
 
 .Parameter parameters
  Muut primusquery kyselylle v�litett�v�t kysely parametrit.
 
 .Example
   Get-PrimusQueryXML -kysely poissaolot
    
   Suorita kysely oletuspalvelimella
 
 
 .Example
   Get-PrimusQueryXML -server testi -kysely poissaolot
    
   Suorita kysely testi palvelimella
    
#>

function Get-PrimusQueryXML  {
  param (
  [Parameter(Mandatory=$true, Position = 0)]
  [string]$kysely,
  [Parameter(Mandatory=$false)]
  [string]$server=$null,
  [Parameter(Mandatory=$false)]
  [string]$parameters=$null
  )
  $config = ImportConfiguration -server $server
  #Primusdata t�nne
  $tmpfile =  [System.IO.Path]::GetTempFileName()
  
  #Salasana tiedostoon kyselyn ajaksi
  $pwdfile = [System.IO.Path]::GetTempFileName()
  $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($config.Credential.password)
  $UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
  [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
  $UnsecurePassword |Out-File -encoding utf8 $pwdfile
  
  $pq = "$PSScriptRoot\primusquery\primusquery.exe" 

  &$pq -f -q $(if($parameters -ne ""){"-p"}) $(if($parameters -ne ""){"$parameters"}) -o $tmpfile $($config.server) $($config.port) $($config.Credential.UserName)  "`"file:$pwdfile`""  $kysely
  
  SafeRemoveTmpFile -tmpfile $pwdfile

  #Write-host "Parsing xml..."
  $primusdata = new-object Xml
  $ft = get-item $tmpfile
  if ($ft.Length -ne 0 ) {
    try  {$primusdata.load($tmpfile)
    }
    catch {
      $ErrorMessage = $_.Exception.Message
      Write-host "XML-dokumentin $tmpfile j�sent�misess� virhe:`r$ErrorMessage"
    
    }
  }
  #poista primusdata
  SafeRemoveTmpFile -tmpfile $tmpfile
  #Write-host "Removed tmpfile"
  return $primusdata  
}

<#
 .Synopsis
  Palauttaa m��ritetyt palvelimet ja niiden tiedot
 
 .Description
  Palauttaa m��ritetyt palvelimet ja niiden tiedot
 
  
 .Example
   Get-PrimusQueryServers
    
#>

function Get-PrimusQueryServers {
 
 $script:Config = Import-Configuration
 ForEach ($server in $config.Servers.Keys) {
    $sd = $config.Servers[$server]
    $sd.alias = $server
    $sd | select -Property @{N='alias';E={$_.alias}},@{N='server';E={$_.server}},@{N='port';E={$_.port}},@{N='default';E={$_.alias -eq $config.DefaultServer}}
    }
}
<#
 .Synopsis
  Suorittaa annetun primusqueryn
 
 .Description
  Suorittaa primusqueryn ja tallentaa tiedot m��ritettyyn tiedostoon
 
 .Parameter server
  Palvelimen alias, jos et m��ritt�nyt aliasta erikseen Set-PrimusQueryConfig komennolla on alias palvelimen nimi tai osoite.
  Jos et m��rit� palvelinta k�ytet��n Set-PrimusQueryConfig komennolla m��ritetty� oletuspalvelinta
 
 .Parameter kysely
  Primusquery kyselyn nimi.
 
 .Parameter parameters
  Muut primusquery kyselylle v�litett�v�t kysely parametrit.
 
 .Parameter outputfile
  Voit m��rit�� tiedoston johon kyselyn tulos tallennetaa. JOs t�� on m��ritt�m�tt� tallennus tapahtuu joko kyselyss� m��riteltyy tiedostoon tai
  kyselyn tulos tulsotuu vain ruudulle.
 
 .Example
   Invoke-PrimusQuery -kysely poissaolot
    
   Suorita kyselyn oletuspalvelimella kyselyn tulos n�kyy n�yt�ll� jos kyselyss� ei ole m��riteltyn� tallenustiedostoa
 
 
 .Example
   Invoke-PrimusQueryXML -server testi -kysely ryhm�t -outputfile ryhm�t.csv
    
   Suorita kysely testi palvelimella ja tallenna tiedot ryhm�t.csv tiedostoon
    
#>


function Invoke-PrimusQuery  {
  param (
  [Parameter(Mandatory=$true, Position = 0)]
  [string]$kysely,
  [Parameter(Mandatory=$false)]
  [string]$server=$null,
  [Parameter(Mandatory=$false)]
  [string]$parameters=$null,
  [Parameter(Mandatory=$false)]
  [string]$outputfile=$null
  )
  $config = ImportConfiguration -server $server
  
  #Salasana tiedostoon kyselyn ajaksi
  $pwdfile = [System.IO.Path]::GetTempFileName()
  $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($config.Credential.password)
  $UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
  [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
  $UnsecurePassword |Out-File -encoding utf8 $pwdfile
  
  $pq = "$PSScriptRoot\primusquery\primusquery.exe" 
  
  &$pq -f -q $(if($parameters -ne ""){"-p"}) $(if($parameters -ne ""){"$parameters"}) $(if($outputfile -ne ""){"-o"}) $(if($outputfile -ne ""){"$outputfile"})  $($config.server) $($config.port) $($config.Credential.UserName)  "`"file:$pwdfile`""  $kysely
 
  SafeRemoveTmpFile -tmpfile $pwdfile
 
   
}
<#
 .Synopsis
  Vie dataa primukseen
 
 .Description
  Suorittaa primusqueryn ja vie PRIMUSQUERY_IMPORT m��rityksen muotoista dataa primukseen
 
 .Parameter server
  Palvelimen alias, jos et m��ritt�nyt aliasta erikseen Set-PrimusQueryConfig komennolla on alias palvelimen nimi tai osoite.
  Jos et m��rit� palvelinta k�ytet��n Set-PrimusQueryConfig komennolla m��ritetty� oletuspalvelinta
 
 .Parameter kysely
  Primusquery kyselyn nimi.
 
 .Parameter parameters
  Muut primusquery kyselylle v�litett�v�t kysely parametrit.
 
 .Parameter import
  Vietovien tietojen xml-muotoinen tiedosto.
 
 .Example
   Invoke-PrimusQueryImport -kysely p�ivit�ryhm�t -import uudetryhm�t.xml
    
  Vie oletuspalvelimelle uudetryhm�t.xml tiedon sis�lt�m�t tiedot.
    
#>


function Invoke-PrimusQueryImport  {
  param (
  [Parameter(Mandatory=$true,Position = 0)]
  [string]$kysely,
  [Parameter(Mandatory=$false)]
  [string]$server=$null,
  [Parameter(Mandatory=$false)]
  [string]$parameters=$null,
  [Parameter(Mandatory=$true)]
  [string]$import=$null
  )
  $config = ImportConfiguration -server $server
  if ((Test-Path $import) -eq $false) {
   Write-host "Tiedotoa $import ei l�ydy"
   exit
  }
  
  #Salasana tiedostoon kyselyn ajaksi
  $pwdfile = [System.IO.Path]::GetTempFileName()
  $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($config.Credential.password)
  $UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
  [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
  $UnsecurePassword |Out-File -encoding utf8 $pwdfile
  
  $pq = "$PSScriptRoot\primusquery\primusquery.exe" 
  
  &$pq -f -q $(if($parameters -ne ""){"-p"}) $(if($parameters -ne ""){"$parameters"}) $($config.server) $($config.port) $($config.Credential.UserName)  "`"file:$pwdfile`""  $kysely -i $($import)
  
  SafeRemoveTmpFile -tmpfile $pwdfile
 
   
}

function Invoke-PrimusQueryArgTest  {
  param (
  [Parameter(Mandatory=$false)]
  [string]$server=$null,
  [Parameter(Mandatory=$true)]
  [string]$kysely,
  [Parameter(Mandatory=$false)]
  [string]$parameters=$null,
  [Parameter(Mandatory=$false)]
  [string]$outputfile=$null
  )
  $config = ImportConfiguration -server $server
  
  #Salasana tiedostoon kyselyn ajaksi
  $pwdfile = [System.IO.Path]::GetTempFileName()
  $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($config.Credential.password)
  $UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
  [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
  $UnsecurePassword |Out-File -encoding utf8 $pwdfile
  
  $pq = "$PSScriptRoot\primusquery\echoargs.exe" 
  
  &$pq -f -q $(if($parameters -ne ""){"-p"}) $(if($parameters -ne ""){"$parameters"}) $(if($outputfile -ne ""){"-o"}) $(if($outputfile -ne ""){"$outputfile"})  $($config.server) $($config.port) $($config.Credential.UserName)  "`"file:$pwdfile`""  $kysely
  
  SafeRemoveTmpFile -tmpfile $pwdfile
   
}

function SafeRemoveTmpFile {
  param (
  [Parameter(Mandatory=$true)]
  [string]$tmpfile=$null
  )
  if((get-item $tmpfile).Length -le 52 -and (get-item $tmpfile).Length -gt 0 ) {
  $rs = -join ((65..90) + (97..122) | Get-Random -Count (get-item $tmpfile).Length | % {[char]$_})
  Set-Content -Path $tmpfile $rs
  } else {
  Clear-Content -Path $tmpfile 
  }

  Remove-Item $tmpfile
}