mitnick
Goto Top

Automatisierte Abwesenheitsliste

Hallo zusammen, ich würde gerne automatisiert eine Abwesenheitsliste erstellen (Excel?), die ihre Informationen aus Outlook-Kalendern verschiedener Mitarbeiter bezieht. Es sollen aber nur Termine mit bestimmten Titeln wie z.B. Urlaub oder Tagung ausgelesen bzw. übertragen werden. Dass man Kalender händisch exportieren kann, auch in Excel, weiß ich, aber wie könnte ich dies automatisiert umsetzen? Wäre da Powershell eine Option?, gefunden habe ich aber noch nichts

Danke für eure Hilfe und ein schönes Wochenende

Content-Key: 2403349841

Url: https://administrator.de/contentid/2403349841

Printed on: April 29, 2024 at 00:04 o'clock

Member: Celiko
Celiko Sep 15, 2023 updated at 21:53:14 (UTC)
Goto Top
Moin, on prem exchange oder online?

https://learn.microsoft.com/en-us/graph/api/resources/outofofficesetting ...

Ist noch in der beta über die Rest api.

Vg
Member: ElmerAcmeee
ElmerAcmeee Sep 18, 2023 at 10:00:37 (UTC)
Goto Top
Moin,
ist das bei euch die einzige Stelle, wo ein Urlaub, Tagung, Dienstreise etc. eingetragen ist?
Bei uns läuft diese Auswertung / Anzeige über die Zeitwirtschaft.
Gruß
Member: colinardo
Solution colinardo Sep 19, 2023 updated at 09:32:36 (UTC)
Goto Top
Servus.
Für Exchange Online (M365) hier die Variante. Ist etwas länger da die App-Impersonation gleich auch einmalig im AzureAD mit angelegt wird, so muss man sie nicht von Hand erstellen.

(Man beachte die benötigten Powershell-Module in der ersten Zeile und die anzupassenden Variablen)
#Requires -Modules Microsoft.Graph.Applications,Microsoft.Graph.Identity.DirectoryManagement,Microsoft.Graph.Users,Microsoft.Graph.Users.Actions

<#
    Export OUT-OF-OFFICE Information of all users for today as CSV. (M365)
#>

# VARIABLES #################################################
# TENANT FQDN
$TENANT = 'yourdomain.onmicrosoft.com'  
# only respect appointments with the following subject regular expression match
$SUBJECTREGEX = 'Tagung|Urlaub|Dienstreise'  
# Filepath for CSV-Export
$EXPORTLIST = ".\out-of-office.csv"  
# created application impersonation credentials will be saved to and read from this filepath
# (by default it will be saved in the path of the script)
$AUTHCONFIG = "$PSSCRIPTROOT\auth.data"  
# #################################################

# SCRIPT INTERNAL VARIABLES (DO NOT CHANGE!) ==
$SCRIPT:CLIENT_ID = ''  
$SCRIPT:CLIENT_KEY = ''  
# =============================================
$ErrorActionPreference = 'Stop'  

# Function to create new M365 azure application credentials for app impersonation
function Create-M365AppImpersonation {
    param (
        [Parameter(mandatory=$false)]$appname = 'MyGraphUsersCalendarAccess'  
    )
    write-host "Enter your AzureAD Admin-Credentials in the displayed dialogue and approve access to continue ..." -F Yellow  
    
    # connect to Microsoft Graph
    $connection = Connect-MgGraph -Scopes Application.ReadWrite.All,Directory.ReadWrite.All,RoleManagement.ReadWrite.Directory,AppRoleAssignment.ReadWrite.All

    # check if app with name exists
    $app = Get-MgApplication -Filter "DisplayName eq '$appname'"  
    if (!$app){
        # add allowed permissions
        $resource = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphRequiredResourceAccess -Property @{
            ResourceAppId = '00000003-0000-0000-c000-000000000000'  
            ResourceAccess = (@{Id='df021288-bdef-4463-88db-98f22de89214';Type = 'Role'},@{Id='8ba4a692-bc31-4128-9094-475872af8a53';Type = 'Role'})  
        }
        # add new company application
        $newapp = New-MgApplication -DisplayName $appname -RequiredResourceAccess $resource
        # assign new password
        $pass = Add-MgApplicationPassword -ApplicationId $newapp.Id
        # create service principal for app
        $sPrincipal = New-MgServicePrincipal -AppId $newApp.AppId -Tags @("WindowsAzureActiveDirectoryIntegratedApp")  
        # get objectid of service principle
        $resApp = Get-MgServicePrincipal -All | ? appId -eq $newApp.RequiredResourceAccess[0].ResourceAppId
        # set admin consent approval for access roles
        $newApp.RequiredResourceAccess[0].ResourceAccess.id | %{
            New-MgServicePrincipalAppRoleAssignment -PrincipalId $sPrincipal.Id -ServicePrincipalId $sPrincipal.Id -ResourceId $resApp.Id -AppRoleId $_ | out-null
        }
        
        $data = [pscustomobject]@{
            APPNAME = $appname
            CLIENT_ID = $newapp.AppId
            CLIENT_KEY = $pass.SecretText
            VALID_UNTIL=$pass.EndDateTime.toString('o')  
        }
        # export auth data to file
        $data | export-csv -Path $AUTHCONFIG -Delimiter ";" -NoTypeInformation -Encoding UTF8  
        $data
    }else{
        Write-Error -Message "AppImpersonation with name '$appname' already exists."  
        return
    }
    Disconnect-MGGraph | out-null
}


# check if app credentials are available
if (Test-Path $AUTHCONFIG){
    # import config from file
    $config = Import-CSV $AUTHCONFIG -Delimiter ";"  
    # check credential expiration
    if ((get-date) -gt (get-date $config.VALID_UNTIL).AddDays(-14)){
        # warn if app credentials expire in 14 days
        Write-Warning -Message "You app credentials will expire in '$(((get-date $config.VALID_UNTIL)-(get-date)).TotalDays)' days! Please generate a new password for your app in Azure!"  
    }elseif((get-date) -gt (get-date $config.VALID_UNTIL)){
        # app credential expired
        Write-Error -Message "Your App-Impersonation-Password has expired on '$(get-date $config.VALID_UNTIL)'. Please create a new credential in Azure first, and update the credentials in the config file '$($AUTHCONFIG)'."  
        exit 1
    }
    # set credential variables
    $SCRIPT:CLIENT_ID = $config.CLIENT_ID
    $SCRIPT:CLIENT_KEY = $config.CLIENT_KEY
}else{
    write-host "Creating app impersonation in Azure AD ..." -F Green  
    # create app impersonation in Azure (needs to be created once)
    $app = Create-M365AppImpersonation
    # set credential variables
    $SCRIPT:CLIENT_ID = $app.CLIENT_ID
    $SCRIPT:CLIENT_KEY = $app.CLIENT_KEY
}

# try to connect to Graph with App-Credentials
$maxtries = 60;$cnt = 0; $success = $false
do{
    try{
        # connect to MS Graph
        Connect-MgGraph -TenantId $TENANT -ClientSecretCredential (new-Object PSCredential($SCRIPT:CLIENT_ID,(ConvertTo-SecureString $SCRIPT:CLIENT_KEY -AsPlainText -Force))) -NoWelcome
        $success = $true
        sleep 3
    }catch{
        write-host "Waiting until the App becomes available within in M365 ..." -F Cyan  
        sleep 2
        $cnt++
        if ($nct -ge $maxtries){
            write-error -Message "Failed to connect to MS Graph! $($_.Exception.Message)"  
            exit 1
        }
    }
}until($success)

# get all users from directory
$users = Get-MGUser -All
# process all users
$result = foreach($user in $users){
    $params = @{
	    Schedules = @($user.mail)
	    StartTime = @{
		    DateTime = (get-date).Date.tostring("s")  
		    TimeZone = [System.TimeZoneInfo]::Local.Id
	    }
	    EndTime = @{
		    DateTime = (get-date).Date.AddDays(1).tostring("s")  
		    TimeZone = [System.TimeZoneInfo]::Local.Id
	    }
	    AvailabilityViewInterval = 1440
    }
    $data = Get-MgUserDefaultCalendarSchedule -UserId $user.Id -BodyParameter $params
    # filter out out of office schedules
    [array]$oofschedule = $data.ScheduleItems | ?{$_.Status -eq 'oof' -and $_.Subject -match $SUBJECTREGEX}  
    # output custom object with information about out of office and times on the current day
    $user | select DisplayName,Mail,@{n='OutOfOffice';e={($oofschedule.Count -gt 0)}},@{n='OOFTimes';e={($oofschedule | %{"$((get-date $_.start.dateTime).ToLocalTime().toString('t'))-$((get-date $_.end.dateTime).ToLocalTime().toString('t'))"}) -join ','}}  
}

# finally export data to csv
$result | export-csv -LiteralPath $EXPORTLIST -Delimiter ";" -NoType -Encoding UTF8 -verbose  

Ergebnis ist dann eine CSV-Datei die so aussieht und die Out Of Office Zeiten für den aktuellen Tag auflistet.
Es werden nur Termine beachtet deren Status auf "Abwesend" gesetzt sind und das angegebenen Regular-Expression Pattern im Kopf des Skripts auf das Subject zutrifft.
"DisplayName";"Mail";"OutOfOffice";"OOFTimes"  
"Max Muster";"maxmuster@domain.onmicrosoft.com";"False";""  
"Diana Musterfrau";"dianamusterfrau@domain.onmicrosoft.com";"True";"10:00-14:30,16:00-17:00"  
Grüße Uwe
Member: mitnick
mitnick Sep 21, 2023 at 11:30:28 (UTC)
Goto Top
Super vielen Dank, ich werde das mal testen.

Lg