Add Windows/AcitveDirectory/usersignatures.md
This commit is contained in:
631
Windows/AcitveDirectory/usersignatures.md
Normal file
631
Windows/AcitveDirectory/usersignatures.md
Normal file
@@ -0,0 +1,631 @@
|
||||
# Requirements
|
||||
1. ".env" Datei im gleichen Verzeichnis, wie das, in dem das Powershell Script gesichert wird.
|
||||
2. "template.txt", "template.html", "template.rtf" ebenfalls in dem jeweiligen Verzeichnis ablegen.
|
||||
|
||||
## Aufbau: .env Datei
|
||||
|
||||
```
|
||||
AD_OUPath=OU=...,OU=...,OU=...,DC=contoso,DC=org
|
||||
SIGNATURE_PATH=C:\Scripts\Sinatures
|
||||
DEBUG=0
|
||||
```
|
||||
|
||||
Die Werte sind Beispielwerte und entsprechend anzupassen. Debug gibt Rückmeldungen in der Powershell.
|
||||
|
||||
## Aufbau: template Dateien
|
||||
|
||||
In den Templates werden Platzhalter genutzt um die Variablen zu ersetzen mit den Werten aus dem AD.
|
||||
|
||||
[VORNAME]
|
||||
[NACHNAME]
|
||||
[JOB]
|
||||
[DEPARTMENT]
|
||||
[PHONE]
|
||||
[PLAIN_PHONE]
|
||||
[EMAIL]
|
||||
|
||||
Ich selbst habe den Teil innerhalb der Templates so gestaltet, dass es "[JOB] | [DEPARTMENT]" gibt. Wenn ein User keine JOB Bezeichnung im AD hat, würde das automatisch ersetzt werden durch "[DEPARTMENT]".
|
||||
|
||||
Da ich auch Links beim Klicken auf Icons nutze, muss die Telefonnummer etwas angepasst werden in der html Template Datei. Dafür habe ich im "tel:" Bereich ein "[PLAIN_PHONE]" gesetzt.
|
||||
|
||||
## Powershell Script:
|
||||
|
||||
```powershell
|
||||
Canvas [Console]::OutputEncoding = [Text.Encoding]::UTF8
|
||||
|
||||
###############################################################################
|
||||
# 0) FUNKTION ZUR DEBUG-AUSGABE
|
||||
###############################################################################
|
||||
function Write-HostIfDebug {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Message,
|
||||
|
||||
# Der Typ hier ist entfernt, damit null oder eine valide Farbe möglich ist.
|
||||
$ForegroundColor
|
||||
)
|
||||
|
||||
if ($Env:DEBUG -eq "1") {
|
||||
if ($ForegroundColor) {
|
||||
Write-Host $Message -ForegroundColor $ForegroundColor
|
||||
} else {
|
||||
Write-Host $Message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 1) SIGNATUREN-LOGIK
|
||||
###############################################################################
|
||||
function ConvertPhoneForHtml($phone) {
|
||||
if (![string]::IsNullOrEmpty($phone)) {
|
||||
$phone = $phone -replace " ", " ​"
|
||||
$phone = $phone -replace "-", " ​- ​"
|
||||
}
|
||||
return $phone
|
||||
}
|
||||
|
||||
function ConvertEmailForHtml($mail) {
|
||||
if (![string]::IsNullOrEmpty($mail)) {
|
||||
$mail = $mail -replace "\\.", ".​"
|
||||
$mail = $mail -replace "@", "@​"
|
||||
$mail = $mail -replace "-", "-​"
|
||||
}
|
||||
return $mail
|
||||
}
|
||||
|
||||
# .env einlesen
|
||||
$envFile = Join-Path $PSScriptRoot '.env'
|
||||
if (Test-Path $envFile) {
|
||||
Get-Content -Path $envFile | ForEach-Object {
|
||||
if ($_ -match '^(?<key>[^=]+)=(?<value>.*)$') {
|
||||
$key = $Matches['key']
|
||||
$value = $Matches['value']
|
||||
Set-Item -Path "Env:$key" -Value $value
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-HostIfDebug ".env-Datei wurde nicht gefunden. Bitte stelle sicher, dass sie im gleichen Verzeichnis liegt."
|
||||
return
|
||||
}
|
||||
|
||||
# Pfade aus .env
|
||||
$ouPath = $Env:AD_OUPath
|
||||
$signaturePath = $Env:SIGNATURE_PATH
|
||||
|
||||
if (!$ouPath) {
|
||||
Write-HostIfDebug "Bitte überprüfe, ob in der .env-Datei die Variable 'AD_OUPath' eingetragen ist."
|
||||
return
|
||||
}
|
||||
|
||||
if (![string]::IsNullOrEmpty($signaturePath)) {
|
||||
if (!(Test-Path $signaturePath)) {
|
||||
Write-HostIfDebug "Der Pfad '$signaturePath' existiert nicht. Bitte überprüfen."
|
||||
return
|
||||
}
|
||||
} else {
|
||||
Write-HostIfDebug "Bitte überprüfe, ob in der .env-Datei die Variable 'SIGNATURE_PATH' eingetragen ist."
|
||||
return
|
||||
}
|
||||
|
||||
Write-HostIfDebug "Suche nach Benutzern in der OU: $ouPath..."
|
||||
|
||||
# Benutzer holen (und sortieren)
|
||||
$users = Get-ADUser -Filter * -SearchBase $ouPath -Properties cn, givenName, sn, telephoneNumber, mail, title, department
|
||||
Write-HostIfDebug "Gefundene Benutzer:`n"
|
||||
|
||||
$global:AllUsers = $users |
|
||||
Sort-Object -Property sn, givenName |
|
||||
ForEach-Object {
|
||||
[PSCustomObject]@{
|
||||
Selected = $false
|
||||
CN = $_.cn
|
||||
ADUser = $_
|
||||
DisplayText = if ($_.sn -and $_.givenName) {
|
||||
"$($_.sn), $($_.givenName) ($($_.cn))"
|
||||
} else {
|
||||
$_.cn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Generate-SignaturesForUsers($selectedUsers) {
|
||||
foreach ($item in $selectedUsers) {
|
||||
$user = $item.ADUser
|
||||
$cn = $user.cn
|
||||
$givenName = $user.givenName
|
||||
$sn = $user.sn
|
||||
$originalPhone = $user.telephoneNumber
|
||||
$originalEmail = $user.mail
|
||||
$plainPhone = if (![string]::IsNullOrEmpty($originalPhone)) {
|
||||
$originalPhone -replace '^0+', ''
|
||||
} else { "" }
|
||||
$convertedPhone = ConvertPhoneForHtml($originalPhone)
|
||||
$convertedEmail = ConvertEmailForHtml($originalEmail)
|
||||
$jobTitle = $user.title
|
||||
$department = $user.department
|
||||
|
||||
Write-HostIfDebug "-----------------------------------"
|
||||
Write-HostIfDebug "CN : $cn"
|
||||
Write-HostIfDebug "Vorname : $($givenName)"
|
||||
Write-HostIfDebug "Nachname : $($sn)"
|
||||
Write-HostIfDebug "Telefon (orig): $($originalPhone)"
|
||||
Write-HostIfDebug "Telefon (HTML): $($convertedPhone)"
|
||||
Write-HostIfDebug "plain_phone : $($plainPhone)"
|
||||
Write-HostIfDebug "E-Mail (orig) : $($originalEmail)"
|
||||
Write-HostIfDebug "E-Mail (HTML) : $($convertedEmail)"
|
||||
Write-HostIfDebug "Job (Title) : $($jobTitle)"
|
||||
Write-HostIfDebug "Abteilung : $($department)"
|
||||
|
||||
# 1) HTML
|
||||
$templateFilePath = Join-Path $PSScriptRoot 'template.html'
|
||||
if (!(Test-Path $templateFilePath)) {
|
||||
Write-HostIfDebug "Vorlage 'template.html' wurde nicht gefunden, bitte prüfe den Pfad." -ForegroundColor Red
|
||||
return
|
||||
}
|
||||
|
||||
$signatureHtml = Get-Content -Path $templateFilePath -Raw
|
||||
|
||||
if ([string]::IsNullOrEmpty($jobTitle)) {
|
||||
$searchString = '<div style="font-size: 14px; color: #ffffff;">[JOB] | [DEPARTMENT]</div>'
|
||||
$pattern = [Regex]::Escape($searchString)
|
||||
$replacement = '<div style="font-size: 14px; color: #ffffff;">[DEPARTMENT]</div>'
|
||||
$signatureHtml = $signatureHtml -replace $pattern, $replacement
|
||||
}
|
||||
|
||||
# E-Mail
|
||||
if ($originalEmail) {
|
||||
$pattern = 'href="mailto:\[EMAIL\]"'
|
||||
$replacement = 'href="mailto:' + $originalEmail + '"'
|
||||
$signatureHtml = $signatureHtml -replace $pattern, $replacement
|
||||
|
||||
$pattern = '\[EMAIL\]'
|
||||
$replacement = $convertedEmail
|
||||
$signatureHtml = $signatureHtml -replace $pattern, $replacement
|
||||
} else {
|
||||
$pattern = 'href="mailto:\[EMAIL\]"'
|
||||
$replacement = 'href="mailto:"'
|
||||
$signatureHtml = $signatureHtml -replace $pattern, $replacement
|
||||
|
||||
$pattern = '\[EMAIL\]'
|
||||
$replacement = ''
|
||||
$signatureHtml = $signatureHtml -replace $pattern, $replacement
|
||||
}
|
||||
|
||||
# Phone
|
||||
if ($plainPhone) {
|
||||
$pattern = 'href="tel:\+49\[PLAIN_PHONE\]"'
|
||||
$replacement = 'href="tel:+49' + $plainPhone + '"'
|
||||
$signatureHtml = $signatureHtml -replace $pattern, $replacement
|
||||
|
||||
$pattern = '\[PHONE\]'
|
||||
$replacement = $convertedPhone
|
||||
$signatureHtml = $signatureHtml -replace $pattern, $replacement
|
||||
} else {
|
||||
$pattern = 'href="tel:\+49\[PHONE\]"'
|
||||
$replacement = 'href="tel:"'
|
||||
$signatureHtml = $signatureHtml -replace $pattern, $replacement
|
||||
|
||||
$pattern = '\[PHONE\]'
|
||||
$replacement = ''
|
||||
$signatureHtml = $signatureHtml -replace $pattern, $replacement
|
||||
}
|
||||
|
||||
# Weitere Platzhalter
|
||||
$signatureHtml = $signatureHtml -replace '\[VORNAME\]', $givenName
|
||||
$signatureHtml = $signatureHtml -replace '\[NACHNAME\]', $sn
|
||||
$signatureHtml = $signatureHtml -replace '\[JOB\]', $jobTitle
|
||||
$signatureHtml = $signatureHtml -replace '\[DEPARTMENT\]', $department
|
||||
$signatureHtml = $signatureHtml -replace '\[PLAIN_PHONE\]', $plainPhone
|
||||
|
||||
$filename = "${cn}.htm"
|
||||
$outputPath = Join-Path $signaturePath $filename
|
||||
Set-Content -Path $outputPath -Value $signatureHtml -Encoding UTF8
|
||||
Write-HostIfDebug "Signatur (HTML) für '$($cn)' unter: $outputPath erstellt." -ForegroundColor Green
|
||||
|
||||
# 2) TXT (wenn vorhanden)
|
||||
$templateTxtFilePath = Join-Path $PSScriptRoot 'template.txt'
|
||||
if (Test-Path $templateTxtFilePath) {
|
||||
$signatureTxt = Get-Content -Path $templateTxtFilePath -Raw
|
||||
|
||||
if ([string]::IsNullOrEmpty($jobTitle)) {
|
||||
$searchString = '[JOB] | [DEPARTMENT]'
|
||||
$pattern = [Regex]::Escape($searchString)
|
||||
$replacement = '[DEPARTMENT]'
|
||||
$signatureTxt = $signatureTxt -replace $pattern, $replacement
|
||||
}
|
||||
|
||||
if ($originalEmail) {
|
||||
$signatureTxt = $signatureTxt -replace '\[EMAIL\]', $originalEmail
|
||||
} else {
|
||||
$signatureTxt = $signatureTxt -replace '\[EMAIL\]', ''
|
||||
}
|
||||
|
||||
if ($originalPhone) {
|
||||
$signatureTxt = $signatureTxt -replace '\[PHONE\]', $originalPhone
|
||||
} else {
|
||||
$signatureTxt = $signatureTxt -replace '\[PHONE\]', ''
|
||||
}
|
||||
|
||||
if ($plainPhone) {
|
||||
$signatureTxt = $signatureTxt -replace '\[PLAIN_PHONE\]', $plainPhone
|
||||
} else {
|
||||
$signatureTxt = $signatureTxt -replace '\[PLAIN_PHONE\]', ''
|
||||
}
|
||||
|
||||
$signatureTxt = $signatureTxt -replace '\[VORNAME\]', $givenName
|
||||
$signatureTxt = $signatureTxt -replace '\[NACHNAME\]', $sn
|
||||
$signatureTxt = $signatureTxt -replace '\[JOB\]', $jobTitle
|
||||
$signatureTxt = $signatureTxt -replace '\[DEPARTMENT\]', $department
|
||||
|
||||
$txtFilename = "${cn}.txt"
|
||||
$txtOutputPath = Join-Path $signaturePath $txtFilename
|
||||
Set-Content -Path $txtOutputPath -Value $signatureTxt -Encoding UTF8
|
||||
Write-HostIfDebug "Signatur (TXT) für '$($cn)' unter: $txtOutputPath erstellt." -ForegroundColor Green
|
||||
}
|
||||
|
||||
# 3) RTF (wenn vorhanden)
|
||||
$templateRtfFilePath = Join-Path $PSScriptRoot 'template.rtf'
|
||||
if (Test-Path $templateRtfFilePath) {
|
||||
$signatureRtf = Get-Content -Path $templateRtfFilePath -Raw
|
||||
|
||||
if ([string]::IsNullOrEmpty($jobTitle)) {
|
||||
$searchString = '[JOB] | [DEPARTMENT]'
|
||||
$pattern = [Regex]::Escape($searchString)
|
||||
$replacement = '[DEPARTMENT]'
|
||||
$signatureRtf = $signatureRtf -replace $pattern, $replacement
|
||||
}
|
||||
|
||||
if ($originalEmail) {
|
||||
$signatureRtf = $signatureRtf -replace '\[EMAIL\]', $originalEmail
|
||||
} else {
|
||||
$signatureRtf = $signatureRtf -replace '\[EMAIL\]', ''
|
||||
}
|
||||
|
||||
if ($originalPhone) {
|
||||
$signatureRtf = $signatureRtf -replace '\[PHONE\]', $originalPhone
|
||||
} else {
|
||||
$signatureRtf = $signatureRtf -replace '\[PHONE\]', ''
|
||||
}
|
||||
|
||||
if ($plainPhone) {
|
||||
$signatureRtf = $signatureRtf -replace '\[PLAIN_PHONE\]', $plainPhone
|
||||
} else {
|
||||
$signatureRtf = $signatureRtf -replace '\[PLAIN_PHONE\]', ''
|
||||
}
|
||||
|
||||
$signatureRtf = $signatureRtf -replace '\[VORNAME\]', $givenName
|
||||
$signatureRtf = $signatureRtf -replace '\[NACHNAME\]', $sn
|
||||
$signatureRtf = $signatureRtf -replace '\[JOB\]', $jobTitle
|
||||
$signatureRtf = $signatureRtf -replace '\[DEPARTMENT\]', $department
|
||||
|
||||
$rtfFilename = "${cn}.rtf"
|
||||
$rtfOutputPath = Join-Path $signaturePath $rtfFilename
|
||||
Set-Content -Path $rtfOutputPath -Value $signatureRtf -Encoding Default
|
||||
|
||||
Write-HostIfDebug "Signatur (RTF) für '$($cn)' unter: $rtfOutputPath erstellt." -ForegroundColor Green
|
||||
}
|
||||
Write-HostIfDebug "-----------------------------------"
|
||||
}
|
||||
Write-HostIfDebug "Fertig! Signaturen wurden erstellt."
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# 2) WPF-UI + DRAG MOVE
|
||||
###############################################################################
|
||||
Add-Type -AssemblyName PresentationCore,PresentationFramework
|
||||
|
||||
$XAML = @"
|
||||
<Window
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="E-Mail Signaturen"
|
||||
WindowStyle="None"
|
||||
ResizeMode="NoResize"
|
||||
Background="#262626">
|
||||
|
||||
<Window.Resources>
|
||||
|
||||
<!-- Keine Hover-Effekte, nur normal/pressed für den X-Button -->
|
||||
<Style x:Key="CloseButtonStyle" TargetType="Button">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="16"/>
|
||||
<Setter Property="Width" Value="30"/>
|
||||
<Setter Property="Height" Value="30"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<!-- Wir definieren ein Custom Template, ohne Hover-Trigger -->
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="border"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<!-- Nur Pressed-Trigger (optional) -->
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="border" Property="Background" Value="#444444"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Ab hier definieren wir ein eigenes ControlTemplate für OK/Abbrechen-Buttons -->
|
||||
<Style x:Key="FancyButtonStyle" TargetType="Button" BasedOn="{x:Null}">
|
||||
<!-- Wichtig: eigene Vorlage, damit wir Windows-Standard nicht haben -->
|
||||
<Setter Property="OverridesDefaultStyle" Value="True"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
|
||||
<!-- Normal-Attribute -->
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
<Setter Property="Background" Value="#3A3A3A"/>
|
||||
<Setter Property="BorderBrush" Value="#555555"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="5,0,5,0"/>
|
||||
<Setter Property="Padding" Value="6,3,6,3"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<!-- Rahmen in Form einer Border -->
|
||||
<Border x:Name="border"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<!-- Hier liegt der eigentliche Button-Inhalt -->
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<!-- Hover: Hintergrund #FDC100, Schrift #000000 -->
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Background" Value="#FDC100"/>
|
||||
<Setter Property="Foreground" Value="#000000"/>
|
||||
</Trigger>
|
||||
<!-- Pressed: Hintergrund #C77E00, Schrift #FFFFFF -->
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="border" Property="Background" Value="#C77E00"/>
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
</Trigger>
|
||||
<!-- Deaktiviert -->
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="border" Property="Background" Value="#707070"/>
|
||||
<Setter Property="Foreground" Value="#AAAAAA"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- RadioButton-Style -->
|
||||
<Style TargetType="RadioButton">
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="RadioButton">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,5">
|
||||
<Border Width="16" Height="16"
|
||||
BorderBrush="#3F3F3E"
|
||||
BorderThickness="2"
|
||||
CornerRadius="8" Margin="0,0,5,0">
|
||||
<Ellipse x:Name="EllipseFill" Fill="Transparent"/>
|
||||
</Border>
|
||||
<ContentPresenter/>
|
||||
</StackPanel>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="EllipseFill" Property="Fill" Value="#FDC100"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="EllipseFill" Property="Fill" Value="Gray"/>
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- ListView-Style: dunkel, bei deaktiviert -> Schrift grau -->
|
||||
<Style TargetType="ListView" x:Key="UserListStyle">
|
||||
<Setter Property="Background" Value="#2F2F2E"/>
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
<Setter Property="Background" Value="#2F2F2E"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- ListViewItem-Style -->
|
||||
<Style TargetType="ListViewItem" x:Key="ItemStyle">
|
||||
<Setter Property="Background" Value="#2F2F2E"/>
|
||||
<Setter Property="Foreground" Value="#FFFFFF"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#3A3A3A"/>
|
||||
</Trigger>
|
||||
<DataTrigger Binding="{Binding IsEnabled,
|
||||
RelativeSource={RelativeSource AncestorType=ListView}}" Value="False">
|
||||
<Setter Property="Foreground" Value="Gray"/>
|
||||
<Setter Property="Background" Value="#2F2F2E"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- ScrollViewer-Style: kein Weiß -->
|
||||
<Style TargetType="ScrollViewer">
|
||||
<Setter Property="Background" Value="#2F2F2E"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid x:Name="RootGrid">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/> <!-- Eigener Titelbalken -->
|
||||
<RowDefinition Height="Auto"/> <!-- Überschrift + Radiobuttons -->
|
||||
<RowDefinition Height="Auto"/> <!-- ListView -->
|
||||
<RowDefinition Height="Auto"/> <!-- Buttons -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Titelbalken (mit "X" rechts) -->
|
||||
<Grid Grid.Row="0" x:Name="TitleBar" Background="#444444">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Titel hier -->
|
||||
<TextBlock Text="E-Mail Signaturen"
|
||||
Foreground="#FFFFFF"
|
||||
VerticalAlignment="Center"
|
||||
Margin="10,0,0,0"/>
|
||||
<Button x:Name="btnClose" Grid.Column="1"
|
||||
Style="{StaticResource CloseButtonStyle}"
|
||||
Content="✕"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,10,0"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Überschrift + Radiobuttons -->
|
||||
<StackPanel Orientation="Vertical" Grid.Row="1" Margin="10">
|
||||
<TextBlock Text="Signaturen erstellen für ..."
|
||||
Foreground="#FFFFFF"
|
||||
FontWeight="Bold"
|
||||
FontSize="16"
|
||||
Margin="0,0,0,10"/>
|
||||
<RadioButton x:Name="rbAlle" Content="alle Mitarbeiter" />
|
||||
<RadioButton x:Name="rbAuswahl" Content="den ausgewählten Mitarbeiter" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Liste mit Nutzern (max 300px hoch, scrollt bei Bedarf) -->
|
||||
<ListView x:Name="lvUsers" Style="{StaticResource UserListStyle}"
|
||||
ItemContainerStyle="{StaticResource ItemStyle}"
|
||||
Grid.Row="2" Margin="10" MaxHeight="300">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox IsChecked="{Binding Selected}" Margin="5,0,5,0"/>
|
||||
<TextBlock Text="{Binding DisplayText}" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
|
||||
<!-- Buttons OK / Abbrechen -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="3" Margin="10">
|
||||
<Button x:Name="btnOK" Style="{StaticResource FancyButtonStyle}" Content="OK" Width="80" Margin="0,0,10,0"/>
|
||||
<Button x:Name="btnCancel" Style="{StaticResource FancyButtonStyle}" Content="Abbrechen" Width="80"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
"@
|
||||
|
||||
[xml]$xml = $XAML
|
||||
$reader = New-Object System.Xml.XmlNodeReader $xml
|
||||
$Window = [Windows.Markup.XamlReader]::Load($reader)
|
||||
|
||||
# Fenster-Einstellungen
|
||||
$Window.Width = 400
|
||||
$Window.SizeToContent = 'Height'
|
||||
$Window.WindowStartupLocation = 'CenterScreen'
|
||||
$Window.MaxHeight = [System.Windows.SystemParameters]::PrimaryScreenHeight * 0.8
|
||||
|
||||
# Elemente holen
|
||||
$TitleBar = $Window.FindName('TitleBar')
|
||||
$btnClose = $Window.FindName('btnClose')
|
||||
$rbAlle = $Window.FindName('rbAlle')
|
||||
$rbAuswahl = $Window.FindName('rbAuswahl')
|
||||
$lvUsers = $Window.FindName('lvUsers')
|
||||
$btnOK = $Window.FindName('btnOK')
|
||||
$btnCancel = $Window.FindName('btnCancel')
|
||||
|
||||
# Beim Start: "alle Mitarbeiter" -> Liste grau
|
||||
$rbAlle.IsChecked = $true
|
||||
$lvUsers.IsEnabled = $false
|
||||
|
||||
$rbAlle.Add_Checked({
|
||||
$lvUsers.IsEnabled = $false
|
||||
})
|
||||
$rbAuswahl.Add_Checked({
|
||||
$lvUsers.IsEnabled = $true
|
||||
})
|
||||
|
||||
# Datenquelle
|
||||
$lvUsers.ItemsSource = $global:AllUsers
|
||||
|
||||
# Funktion zur Aktualisierung der RadioButton-Beschriftung
|
||||
function UpdateRbAuswahlContent {
|
||||
$count = ($global:AllUsers | Where-Object { $_.Selected -eq $true }).Count
|
||||
if ($count -ge 2) {
|
||||
$rbAuswahl.Content = "die ausgewählten Mitarbeiter"
|
||||
}
|
||||
else {
|
||||
$rbAuswahl.Content = "den ausgewählten Mitarbeiter"
|
||||
}
|
||||
}
|
||||
|
||||
# Event-Handler für Check/Uncheck in der Liste
|
||||
$lvUsers.AddHandler(
|
||||
[System.Windows.Controls.Primitives.ButtonBase]::ClickEvent,
|
||||
[System.Windows.RoutedEventHandler]{
|
||||
UpdateRbAuswahlContent
|
||||
},
|
||||
$true
|
||||
)
|
||||
|
||||
# Titelbalken "Drag" (Fenster verschieben)
|
||||
$TitleBar.Add_MouseLeftButtonDown({
|
||||
if ($_.LeftButton -eq [System.Windows.Input.MouseButtonState]::Pressed) {
|
||||
try {
|
||||
$Window.DragMove()
|
||||
} catch {}
|
||||
}
|
||||
})
|
||||
|
||||
# "X"-Button oben rechts
|
||||
$btnClose.Add_Click({
|
||||
$Script:SelectedUsers = $null
|
||||
$Window.Close()
|
||||
})
|
||||
|
||||
# OK-/Abbrechen-Logik
|
||||
$Script:SelectedUsers = $null
|
||||
$btnOK.Add_Click({
|
||||
if ($rbAlle.IsChecked -eq $true) {
|
||||
$Script:SelectedUsers = $global:AllUsers
|
||||
} else {
|
||||
$Script:SelectedUsers = $global:AllUsers | Where-Object { $_.Selected -eq $true }
|
||||
}
|
||||
$Window.Close()
|
||||
})
|
||||
$btnCancel.Add_Click({
|
||||
$Script:SelectedUsers = $null
|
||||
$Window.Close()
|
||||
})
|
||||
|
||||
# UI anzeigen
|
||||
$null = $Window.ShowDialog()
|
||||
|
||||
# Falls abgebrochen oder geschlossen
|
||||
if (-not $Script:SelectedUsers) {
|
||||
Write-HostIfDebug "Abgebrochen. Keine Signaturen erzeugt."
|
||||
return
|
||||
}
|
||||
|
||||
# Signaturen erstellen
|
||||
Generate-SignaturesForUsers -selectedUsers $Script:SelectedUsers
|
||||
```
|
||||
Reference in New Issue
Block a user