personio/sync_full.ps1
2024-07-26 19:37:06 +02:00

405 lines
25 KiB
PowerShell

<#
.SYNOPSIS
Personio Sync Script (Personio -> MEHRKANAL AD)
.DESCRIPTION
Dieses Script übernimmt Personenbezogene Daten aus Personio in die Active Directory
.EXAMPLE
PS C:\POSTV>.\mk.ps1
<Startet den Sync für alle User>
.NOTES
Author: Sebastian Mendyka <mendyka@mehrkanal.com>
Date: Sep 13, 2017
.Link
URL: https://developer.personio.de/v1.0/reference
#>
######################################################################################
######################################################################################
# Variablen setzen
######################################################################################
######################################################################################
$application = "https://api.personio.de";
$company = "5989";
# Define the user credentials
$username = "#TOREPLACE#";
$password = "#TOREPLACE#";
# Force TLS1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$LOGDATE = Get-Date -Format "yyyy-MM-dd_"
$OWNPID = $([System.Diagnostics.Process]::GetCurrentProcess()).ID
$ScriptDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)
$ini = .\functions\functions.ps1 "$ScriptDir\config.ini"
$IMPERSONATEADMIN = $ini.exchange.impersonateuser
######################################################################################
######################################################################################
# Functions
######################################################################################
######################################################################################
# Active Directory Modul laden
. .\functions\json_function.ps1
# Active Directory Modul laden
. .\functions\activedirectory_function.ps1
# Füge Log Klasse hinzu, Inspiriert von https://gist.github.com/9to5IT/9620565
. .\functions\log_function.ps1
# Füge Exchange Klassen hinzu
. .\functions\exchange_function.ps1
# Füge Personio Klassen hinzu
. .\functions\personio.ps1
# Füge SQLITE Klassen hinzu
. .\functions\sqlite.ps1
# Starte Logging
Write-Log -Message "Starte FULL Import" -Level Info
# http://www.spech.de/2016/06/sqlite-mit-der-powershell-nutzen/
if (! $(Get-Command Invoke-SqliteQuery -ErrorAction SilentlyContinue)) {
Write-Log -Message "Aktiviere SQLITE Modul" -Level Warn
#Import-Module "$($ScriptDir)\modules\sqlite\PSSQLite.psm1"
Import-Module PSSQLite
}
if (! $(Get-Command Invoke-SqliteQuery -ErrorAction SilentlyContinue)) {
Send-ErrorMail -Mail "Error: Sqlite Module not found / working" -VACSTART "-" -VACENDE "-" -VACID "-"
Write-Log -Message "Aktiviere SQLITE Modul" -Level Error
exit
}
$force = 0
$CHANGEDUSERDATA = $true
$CHANGEDAPPOINTMENT = $true
######################################################################################
######################################################################################
# Prüfe auf "User" Daten
######################################################################################
######################################################################################
try {
$getallapiuserdata = $(Get-UserInfo).content | ConvertFrom-Json | Select-Object -expand "data"
$tmpgetallapiuserdata = ($getallapiuserdata).attributes | convertto-json -depth 5
$tmpgetallapiuserdata | out-file "$ScriptDir\$($ini.general.tmp_path)\userdata_tmp.csv"
if (Test-Path "$ScriptDir\$($ini.general.tmp_path)\userdata.csv") {
$fileA = Get-Content "$ScriptDir\$($ini.general.tmp_path)\userdata.csv"
$fileB = Get-Content "$ScriptDir\$($ini.general.tmp_path)\userdata_tmp.csv"
if ( Compare-Object "$fileA" "$fileB") {
Write-Log -Message "User-Daten haben sich geändert..." -Level Info
$CHANGEDUSERDATA = $true
}
else {
if ($force -eq "0") {
Write-Log -Message "User-Daten haben sich NICHT geändert... Breche ab" -Level Warn
$CHANGEDUSERDATA = $false
}
else {
Write-Log -Message "Daten haben sich NICHT geändert... force aktiv" -Level Info
$CHANGEDUSERDATA = $true
}
}
}
}
catch {
Write-Log -Message "Error: $_.Exception.Message - check_user_change - Line Number: $($_.InvocationInfo.ScriptLineNumber)" -Level Error
Send-ErrorMail -Mail "Error: get User-Data from API: $($_.Exception.Message)" -VACSTART "-" -VACENDE "-" -VACID "-"
exit
}
######################################################################################
######################################################################################
# Prüfe auf "neue" Kalender Daten
######################################################################################
######################################################################################
try {
Write-Log -Message "Get tmp Data (convert to json)" -Level Warn
$(Get-UserVacation) | fl | out-file "$ScriptDir\$($ini.general.tmp_path)\data_tmp_test.csv"
$getallapidata = $(Get-UserVacation).content | ConvertFrom-Json | select -expand "data"
Write-Log -Message "Create tmp Data (convert to json)" -Level Warn
$tmpgetallapidata = ($getallapidata).attributes | convertto-json -depth 8
Write-Log -Message "Write tmp Data" -Level Warn
$tmpgetallapidata | fl | out-file "$ScriptDir\$($ini.general.tmp_path)\data_tmp.csv"
if (Test-Path "$ScriptDir\$($ini.general.tmp_path)\data.csv") {
Write-Log -Message "Compare tmp Data" -Level Warn
$fileA = Get-Content "$ScriptDir\$($ini.general.tmp_path)\data.csv"
$fileB = Get-Content "$ScriptDir\$($ini.general.tmp_path)\data_tmp.csv"
if ( Compare-Object "$fileA" "$fileB") {
Write-Log -Message "Daten haben sich geändert..." -Level Info
$CHANGEDAPPOINTMENT = $true
}
else {
if ($force -eq "0") {
Write-Log -Message "Daten haben sich NICHT geändert... Breche ab" -Level Warn
$CHANGEDAPPOINTMENT = $false
}
else {
Write-Log -Message "Daten haben sich NICHT geändert... force aktiv" -Level Info
$CHANGEDAPPOINTMENT = $true
}
}
}
}
catch {
Write-Log -Message "Error: $($_.Exception.Message) - check_change - Line Number: $($_.InvocationInfo.ScriptLineNumber)" -Level Error
Send-ErrorMail -Mail "Error: get Cal-Data from API: $($_.Exception.Message)" -VACSTART "-" -VACENDE "-" -VACID "-"
exit
}
############################## DEBUG
#$CHANGEDUSERDATA = $true
#$CHANGEDAPPOINTMENT = $false
############################## DEBUG
if ( $CHANGEDUSERDATA -eq $false -and $CHANGEDAPPOINTMENT -eq $false) {
Write-Log -Message "Keine Datenänderungen vorhanden.. Beende Import" -Level Info
exit
}
Create-ExMsalToken
$getallapiuserdata | foreach {
[PSCustomObject]@{
FirstName = $_.attributes.first_name.value | Select-Object -First 1
LastName = $_.attributes.last_name.value | Select-Object -First 1
Email = $_.attributes.email.value | Select-Object -First 1
Position = $_.attributes.position.value | Select-Object -First 1
Abteilung = $_.attributes.department.value.attributes.name | Select-Object -First 1
Tel = $_.attributes.dynamic_99874.value | Select-Object -First 1
Status = $_.attributes.status.value | Select-Object -First 1
Kostenstelle = $_.attributes.cost_centers.value.attributes.name | Select-Object -First 1
Vorgesetzter = $_.attributes.supervisor.value.attributes.email.value | Select-Object -First 1
Fax = $_.attributes.dynamic_137780.value | Select-Object -First 1
ID = $_.attributes.dynamic_99886.value | Select-Object -First 1
PersonioID = $_.attributes.id.value | Select-Object -First 1
Mobile = $_.attributes.dynamic_99877.value | Select-Object -First 1
HomeMobile = $_.attributes.dynamic_130998.value | Select-Object -First 1
} | Where-Object { $_.Status -notLike "inactive" } | ForEach-Object {
######################################################################################
######################################################################################
# Prüfe ob die ID aus Personio in der AD enthalten ist
######################################################################################
######################################################################################
if ( ! $_.ID -eq "$null" ) {
Write-Log -Message "Gefunden: $($_.FirstName) $($_.LastName) = $($_.ID) $($_.Kostenstelle)" -Level Info
if ( (Get-ADUser $_.ID -ErrorAction SilentlyContinue) -eq "$false") {
Write-Log -Message "Mitarbeiter ID nicht korrekt: $($_.ID)" -Level Error
}
else {
Write-Log -Message "Mitarbeiter gefunden $($_.ID)" -Level Info
######################################################################################
######################################################################################
# Aktualisiere AD Daten des Users -> $_.ID
######################################################################################
######################################################################################
if ($CHANGEDUSERDATA -eq $true) {
SYNC-ADUser -USERNAME $_.ID -Position $_.Position -Abteilung $_.Abteilung -Tel $_.Tel -Fax $_.Fax -Manager $_.Vorgesetzter -Mobile $_.Mobile -HomeMobile $_.HomeMobile
}
######################################################################################
######################################################################################
# Aktualisiere Kalenderdaten des Users -> $_.ID
######################################################################################
if ( $CHANGEDAPPOINTMENT -eq $true) {
$USERMAIL = $_.Email
$USERID = $_.ID
if (! (Test-path -Path "$($ScriptDir)\sqlite\$($_.ID).db" )) {
CREATE-SQLITE $USERID
}
else {
If ((Get-Item "$($ScriptDir)\sqlite\$($_.ID).db").length -le 0kb) {
Remove-Item "$($ScriptDir)\sqlite\$($_.ID).db"
CREATE-SQLITE $USERID
}
}
######################################################################################
######################################################################################
# DELETE old and dup Appointments
######################################################################################
######################################################################################
$USERAPPOINTMENTSSQLITE = GET-SQLITEUSERAPPOINTMENTS -USERID $USERID
$USERAPPOINTMENTSSQLITE | foreach {
if ( $getallapidata.attributes.id -notcontains "$($_.Id)" ) {
Write-Log -Message "Kalendereintrag: $($($_.Id)) für $($USERID) nicht mehr in Personio enthalten... delete" -Level WARN
$GETOLDEXCHANGEID = Get-SQLITE -USERID $USERID -VACPERSONIOID $_.Id
$EXCHANGEMEETINGID = ($GETOLDEXCHANGEID).Vacexchangeid
if ( $EXCHANGEMEETINGID -notlike "False" ) {
if ( Remove-CalendarItem -CALID "$($EXCHANGEMEETINGID)" -Impersonate ($GETOLDEXCHANGEID).Mail ) {
DELETE-SQLITE -USERID $USERID -VACPERSONIOID $_.Id
Write-Log -Message "Kalendereintrag und SQLITE Daten: $($($_.Id)) für $($USERID) gelöscht" -Level WARN
}
else {
Write-Log -Message "Kalendereintrag : $($($_.Id)) für $($USERID) konnte nicht gelöscht werden" -Level WARN
}
}
else {
Write-Log -Message "Kalendereintrag: $($($_.Id)) für $($USERID) fehlerhafte SQLITE Daten... delete wird anhand Datum durchgeführt" -Level WARN
$EXCHANGEMEETINGSTART = ($GETOLDEXCHANGEID).Vacstart
$EXCHANGEMEETINGEND = ($GETOLDEXCHANGEID).Vacend
if ( Remove-CalendarItemByDate -Start $EXCHANGEMEETINGSTART -End $EXCHANGEMEETINGEND -Impersonate ($GETOLDEXCHANGEID).Mail ) {
DELETE-SQLITE -USERID $USERID -VACPERSONIOID $_.Id
}
}
}
else {
$GETOLDEXCHANGEID = Get-SQLITE -USERID $USERID -VACPERSONIOID $_.Id
$EXCHANGEMEETINGSTART = ($GETOLDEXCHANGEID).Vacstart
$EXCHANGEMEETINGEND = ($GETOLDEXCHANGEID).Vacend
Remove-DupCalendarItem -Start "$($EXCHANGEMEETINGSTART)" -End "$($EXCHANGEMEETINGEND)" -Impersonate ($GETOLDEXCHANGEID).Mail -USERID "$($USERID)"
}
}
Write-Log -Message "Lösche nicht zuordbare Kalendereinträge für $($USERID) in SQLITE" -Level Info
DELETE-WRONGSQLITEDATA -USERID $USERID
######################################################################################
######################################################################################
# Add new Appointments
######################################################################################
######################################################################################
#2022-09-21T00:00:00+02:00
#$DatePattern = "yyyy-MM-ddTHH:mm:ssK"
$DatePattern = "MM/dd/yyyy HH:mm:ss"
$getallapidata | where { $_.attributes.employee.attributes.email.value -Like $USERMAIL -and $_.attributes.status -match "approved" -and [datetime]::ParseExact($_.attributes.start_date, $DatePattern, $null) -gt $STARTDATEOLDEST -and ([DateTime]::ParseExact($_.attributes.start_date, $DatePattern, $null).Year) -ge "2018" } | ForEach-Object {
[PSCustomObject]@{
"VACID" = $_.attributes.id | select -First 1
"VACStatus" = $_.attributes.status | select -First 1
"VACStart" = $_.attributes.start_date | select -First 1
"VACEnde" = $_.attributes.end_date | select -First 1
"VACTage" = $_.attributes.days_count | select -First 1
"VACHalbTagAnfang" = $_.attributes.half_day_start | select -First 1
"VACHalbTagEnde" = $_.attributes.half_day_end | select -First 1
"VACTyp" = $_.attributes.time_off_type.attributes.name | select -First 1
"VACTypID" = $_.attributes.time_off_type.attributes.id | select -First 1
"VACEMail" = $_.attributes.employee.attributes.email.value | select -First 1
"VACFirstName" = $_.attributes.employee.attributes.first_name.value | select -First 1
"VACLastName" = $_.attributes.employee.attributes.last_name.value | select -First 1
}
} | ForEach-Object {
######################################################################################
######################################################################################
# Prüfe auf gelöschte Termine
######################################################################################
######################################################################################
$STARTDATE = Get-Date -date $_.VACStart
$STARTDATEOLDEST = (get-date).adddays(-60)
$ENDDATE = Get-Date -date $_.VACEnde
$ENDDATEOLDEST = (get-date).adddays(+360)
[datetime]$VACStart = $_.VACStart
[datetime]$VACEnde = $_.VACEnde
$VACHalbTagAnfang = $_.VACHalbTagAnfang
$VACHalbTagEnde = $_.VACHalbTagEnde
$VACTage = $_.VACTage
# Berechnung Urlaubsanfang und Urlaubsende
if ($VACTAGE -lt 1) {
if ($VACHalbTagAnfang -eq "1") {
$VACStart = $VACStart
}
if ($VACHalbTagEnde -eq "1") {
$VACStart = $VACStart.AddHours(13)
$VACEnde = $VACEnde.AddHours(23).AddMinutes(59)
}
else {
$VACEnde = $VACEnde.AddHours(13)
}
}
else {
if ($VACHalbTagAnfang -eq "1") {
$VACStart = $VACStart.AddHours(13)
}
if ($VACHalbTagEnde -eq "1") {
$VACEnde = $VACEnde.AddHours(13)
}
else {
$VACEnde = $VACEnde.AddHours(23).AddMinutes(59)
}
}
######################################################################################
######################################################################################
# Prüfe auf vorhandensein des Kalendereintrags in SQLITE Objekt
######################################################################################
######################################################################################
$GETRESPONSE = Get-SQLITE -USERID $USERID -VACPERSONIOID $_.VACID
if ($GETRESPONSE -eq $null) {
Write-Log -Message "Kalendereintrag: $($_.VACID) für $($USERID) nicht gefunden" -Level Warn
$RESPONSE = GET-ExchangeSubject -VacationType $($_.VACTypID)
######################################################################################
######################################################################################
# Termin ist nicht im SQLITE vorhanden..
######################################################################################
######################################################################################
$CREATEEWSOK = New-CalendarItem -Subject "$($RESPONSE.Name)" -Body "Dieser Eintrag wurde automatisch erzeugt. Bindend sind nur die Angaben in Personio (https://mehrkanal.personio.de/login/index )" -Start $VACStart -End $VACEnde -AdminUser "$IMPERSONATEADMIN" -Impersonate $_.VACEMail -FreeBusyStatus "$($RESPONSE.Status)"
if ( $CREATEEWSOK -ne $null -or $CREATEEWSOK -ne $false) {
INSERT-SQLITE -USERID $USERID -MAIL $_.VACEMail -FIRSTNAME $_.VACFirstName -LASTNAME $_.VACLastName -VACPERSONIOID $_.VACID -VACTYPE $_.VACTYP -VACSTART $VACStart -VACEND $VACEnde -VAEXCHANGEID $CREATEEWSOK
Remove-DupCalendarItem -Start "$($VACStart)" -End "$($VACEnde)" -Impersonate $_.VACEMail -USERID "$($USERID)"
Write-Log -Message "Kalendereintrag: $($_.VACID) für $($USERID) angelegt und wenn vorhanden dupplikate gelöscht" -Level Info
}
else {
Write-Log -Message "Urlaubsfreigabe EWS Sync war fehlerhaft..." -Level Error
Send-ErrorMail -Mail $($_.VACEMail) -VACSTART $($VACStart) -VACENDE $($VACEnde) -VACID $($_.VACID)
}
}
else {
######################################################################################
######################################################################################
# Vergleiche API-Response mit vorhandenen SQLITE Daten...
######################################################################################
######################################################################################
$RESPONSE = GET-ExchangeSubject -VacationType $($_.VACTypID)
$APIRESP = New-Object psobject -Property @{USERID = $USERID; MAIL = $_.VACEMail; VACID = $_.VACID; VACTYP = $_.VACTYP; VACSTART = $VACStart; VACENDE = $VACEnde }
$SQLITERESP = New-Object psobject -Property @{USERID = ($GETRESPONSE).Userid; MAIL = ($GETRESPONSE).Mail; VACID = ($GETRESPONSE).id; VACTYP = ($GETRESPONSE).Vactype; VACSTART = [datetime]($GETRESPONSE).Vacstart; VACENDE = [datetime]($GETRESPONSE).Vacend }
if (Compare-Object $APIRESP $SQLITERESP -Property VACID, MAIL, VACSTART, VACENDE, VACTYPE ) {
Write-Log -Message "Kalendereintrag: $($_.VACID) für $($USERID) haben sich geändert" -Level Warn
Write-Log -Message "Kalendereintrag: $($APIRESP)" -Level Warn
Write-Log -Message "Kalendereintrag: $($SQLITERESP)" -Level Warn
######################################################################################
######################################################################################
# Termin muss in Exchange geändert werden
######################################################################################
######################################################################################
$EXCHANGEMEETINGID = ($GETRESPONSE).Vacexchangeid
Remove-CalendarItem -CALID "$(($GETRESPONSE).Vacexchangeid)" -Impersonate ($GETRESPONSE).Mail
DELETE-SQLITE -USERID $USERID -VACPERSONIOID $_.VACID
$CREATEEWSOK = New-CalendarItem -Subject "$($RESPONSE.Name)" -Body "Dieser Eintrag wurde automatisch erzeugt. Bindend sind nur die Angaben in Personio (https://mehrkanal.personio.de/login/index )" -Start $VACStart -End $VACEnde -AdminUser "$IMPERSONATEADMIN" -Impersonate $_.VACEMail -FreeBusyStatus "$($RESPONSE.Status)"
if ( $CREATEEWSOK -ne $null -or $CREATEEWSOK -ne $false) {
#$Name=$($_.VACEMail).Split("@")[0]
echo $CREATEEWSOK
#exit
INSERT-SQLITE -USERID $USERID -MAIL $_.VACEMail -FIRSTNAME $_.VACFirstName -LASTNAME $_.VACLastName -VACPERSONIOID $_.VACID -VACTYPE $_.VACTYP -VACSTART $VACStart -VACEND $VACEnde -VAEXCHANGEID $CREATEEWSOK.Replace("Microsoft.Exchange.WebServices.Data.Appointment ",'')
}
else {
Write-Log -Message "Urlaubsfreigabe EWS Sync war fehlerhaft..." -Level Error
Send-ErrorMail -Mail $($_.VACEMail) -VACSTART $($VACStart) -VACENDE $($VACEnde) -VACID $($_.VACID)
}
}
}
}
}
}
}
}
}
# Erhalte Kalender-Daten und bereite diese auf...
$tmpgetallapidata | fl | out-file "$ScriptDir\$($ini.general.tmp_path)\data.csv"
$tmpgetallapiuserdata | out-file "$ScriptDir\$($ini.general.tmp_path)\userdata.csv"
# Starte Logging
Write-Log -Message "Beende Import" -Level Info