<# .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 .NOTES Author: Sebastian Mendyka 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