export angepasst

This commit is contained in:
2026-06-19 07:59:15 +01:00
parent d7d80f9d00
commit 1c97f2d498
+190 -176
View File
@@ -9,55 +9,61 @@ param (
[string]$LogPath = (Join-Path $PSScriptRoot ("export_log_" + (Get-Date -Format 'yyyyMMdd_HHmmss') + ".txt")) [string]$LogPath = (Join-Path $PSScriptRoot ("export_log_" + (Get-Date -Format 'yyyyMMdd_HHmmss') + ".txt"))
) )
# ---------------------------------------------------------------------------
# Ensure ActiveDirectory module is available
# ---------------------------------------------------------------------------
if (-not (Get-Module -Name ActiveDirectory -ListAvailable)) {
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Error "ActiveDirectory module not found. Please run this script as Administrator to install it automatically, or install RSAT manually."
exit 1
}
Write-Host "ActiveDirectory module not found. Attempting to install..." -ForegroundColor Yellow
$os = (Get-CimInstance Win32_OperatingSystem).Caption
if ($os -match "Server") {
try {
Import-Module ServerManager -ErrorAction Stop
Add-WindowsFeature RSAT-AD-PowerShell -ErrorAction Stop | Out-Null
Write-Host "ActiveDirectory module installed via Add-WindowsFeature." -ForegroundColor Green
} catch {
Write-Error "Failed to install ActiveDirectory module on Server: $_"
exit 1
}
} else {
try {
$feature = Get-WindowsCapability -Name "Rsat.ActiveDirectory*" -Online -ErrorAction Stop |
Where-Object State -ne Installed | Select-Object -First 1
if ($feature) {
Add-WindowsCapability -Name $feature.Name -Online -ErrorAction Stop | Out-Null
Write-Host "ActiveDirectory module installed via Add-WindowsCapability." -ForegroundColor Green
}
} catch {
Write-Error "Failed to install ActiveDirectory module on Windows client: $_"
exit 1
}
}
}
try {
Import-Module ActiveDirectory -ErrorAction Stop
} catch {
Write-Error "ActiveDirectory module could not be loaded: $_"
exit 1
}
Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles() [System.Windows.Forms.Application]::EnableVisualStyles()
# ---------------------------------------------------------------------------
# Ensure AD module is loaded — called lazily before first AD operation
# ---------------------------------------------------------------------------
function Initialize-ADModule {
if (Get-Module -Name ActiveDirectory) { return $true }
if (-not (Get-Module -Name ActiveDirectory -ListAvailable)) {
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
[System.Windows.Forms.MessageBox]::Show(
"Das ActiveDirectory-Modul wurde nicht gefunden.`nBitte das Skript als Administrator starten.",
"Modul fehlt", "OK", "Error") | Out-Null
return $false
}
try {
$os = (Get-CimInstance Win32_OperatingSystem).Caption
if ($os -match "Server") {
Import-Module ServerManager -ErrorAction Stop
Add-WindowsFeature RSAT-AD-PowerShell -ErrorAction Stop | Out-Null
} else {
$feature = Get-WindowsCapability -Name "Rsat.ActiveDirectory*" -Online -ErrorAction Stop |
Where-Object State -ne Installed | Select-Object -First 1
if ($feature) {
Add-WindowsCapability -Name $feature.Name -Online -ErrorAction Stop | Out-Null
}
}
} catch {
[System.Windows.Forms.MessageBox]::Show(
"RSAT konnte nicht installiert werden:`n$_", "Fehler", "OK", "Error") | Out-Null
return $false
}
}
try {
Import-Module ActiveDirectory -ErrorAction Stop -WarningAction SilentlyContinue
return $true
} catch {
[System.Windows.Forms.MessageBox]::Show(
"ActiveDirectory-Modul konnte nicht geladen werden:`n$_", "Fehler", "OK", "Error") | Out-Null
return $false
}
}
# ---------------------------------------------------------------------------
# Script-scope state for the recursive export
# ---------------------------------------------------------------------------
$script:visitedGroups = $null
$script:exportResults = $null
$script:exportAdParams = $null
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Helpers # Helpers
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -84,18 +90,85 @@ function Write-OutputLine {
[System.Windows.Forms.Application]::DoEvents() [System.Windows.Forms.Application]::DoEvents()
} }
function Get-NestedMembers {
param([string]$Group, [string]$SourceGroup)
if (-not $script:visitedGroups.Add($Group)) { return }
try {
$members = Get-ADGroupMember -Identity $Group -ErrorAction Stop @script:exportAdParams
} catch {
Write-Log "Gruppe '$Group' konnte nicht abgerufen werden: $_" -Level WARN
return
}
foreach ($member in $members) {
switch ($member.objectClass) {
'user' {
try {
$user = Get-ADUser -Identity $member.distinguishedName -Properties `
DisplayName, EmailAddress, Title, Department, Company,
Enabled, LastLogonDate, PasswordLastSet, PasswordNeverExpires,
Manager, telephoneNumber, DistinguishedName `
-ErrorAction Stop @script:exportAdParams
$managerName = ''
if ($user.Manager) {
try {
$mgr = Get-ADUser -Identity $user.Manager -Properties DisplayName `
-ErrorAction Stop @script:exportAdParams
$managerName = $mgr.DisplayName
} catch {}
}
$script:exportResults.Add([PSCustomObject]@{
SourceGroup = $SourceGroup
MemberOfGroup = $Group
SamAccountName = $user.SamAccountName
DisplayName = $user.DisplayName
GivenName = $user.GivenName
Surname = $user.Surname
EmailAddress = $user.EmailAddress
Title = $user.Title
Department = $user.Department
Company = $user.Company
TelephoneNumber = $user.telephoneNumber
Enabled = $user.Enabled
LastLogonDate = $user.LastLogonDate
PasswordLastSet = $user.PasswordLastSet
PasswordNeverExpires = $user.PasswordNeverExpires
Manager = $managerName
DistinguishedName = $user.DistinguishedName
})
Write-Log " Benutzer: $($user.SamAccountName) ($($user.DisplayName))"
} catch {
Write-Log "Benutzer '$($member.SamAccountName)' konnte nicht abgerufen werden: $_" -Level WARN
}
}
'group' {
Write-Log "Verschachtelte Gruppe: $($member.Name)"
Get-NestedMembers -Group $member.distinguishedName -SourceGroup $SourceGroup
}
}
}
}
function Start-Export { function Start-Export {
param([string]$GroupName, [string]$OutputPath, [string]$Server) param([string]$GroupName, [string]$OutputPath, [string]$Server)
$script:btnExport.Enabled = $false $script:btnExport.Enabled = $false
$script:rtbOutput.Clear() $script:rtbOutput.Clear()
$adParams = @{} if (-not (Initialize-ADModule)) {
if ($Server) { $adParams['Server'] = $Server } $script:btnExport.Enabled = $true
return
}
$script:exportAdParams = @{}
if ($Server) { $script:exportAdParams['Server'] = $Server }
# Validate group
try { try {
$null = Get-ADGroup -Identity $GroupName -ErrorAction Stop @adParams $null = Get-ADGroup -Identity $GroupName -ErrorAction Stop @script:exportAdParams
Write-Log "Gruppe gefunden: $GroupName" Write-Log "Gruppe gefunden: $GroupName"
} catch { } catch {
Write-Log "Gruppe '$GroupName' nicht gefunden: $_" -Level ERROR Write-Log "Gruppe '$GroupName' nicht gefunden: $_" -Level ERROR
@@ -103,88 +176,27 @@ function Start-Export {
return return
} }
$visitedGroups = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase) $script:visitedGroups = [System.Collections.Generic.HashSet[string]]::new(
$results = [System.Collections.Generic.List[PSCustomObject]]::new() [System.StringComparer]::OrdinalIgnoreCase)
$script:exportResults = [System.Collections.Generic.List[PSCustomObject]]::new()
function Get-NestedMembers { Write-Log "Starte Export für '$GroupName' (inkl. verschachtelter Gruppen)..."
param([string]$Group, [string]$SourceGroup)
if (-not $visitedGroups.Add($Group)) { return }
try {
$members = Get-ADGroupMember -Identity $Group -ErrorAction Stop @adParams
} catch {
Write-Log "Gruppe '$Group' konnte nicht abgerufen werden: $_" -Level WARN
return
}
foreach ($member in $members) {
switch ($member.objectClass) {
'user' {
try {
$user = Get-ADUser -Identity $member.distinguishedName -Properties `
DisplayName, EmailAddress, Title, Department, Company,
Enabled, LastLogonDate, PasswordLastSet, PasswordNeverExpires,
Manager, telephoneNumber, DistinguishedName `
-ErrorAction Stop @adParams
$managerName = ''
if ($user.Manager) {
try {
$mgr = Get-ADUser -Identity $user.Manager -Properties DisplayName -ErrorAction Stop @adParams
$managerName = $mgr.DisplayName
} catch {}
}
$results.Add([PSCustomObject]@{
SourceGroup = $SourceGroup
MemberOfGroup = $Group
SamAccountName = $user.SamAccountName
DisplayName = $user.DisplayName
GivenName = $user.GivenName
Surname = $user.Surname
EmailAddress = $user.EmailAddress
Title = $user.Title
Department = $user.Department
Company = $user.Company
TelephoneNumber = $user.telephoneNumber
Enabled = $user.Enabled
LastLogonDate = $user.LastLogonDate
PasswordLastSet = $user.PasswordLastSet
PasswordNeverExpires = $user.PasswordNeverExpires
Manager = $managerName
DistinguishedName = $user.DistinguishedName
})
Write-Log " Benutzer: $($user.SamAccountName) ($($user.DisplayName))"
} catch {
Write-Log "Benutzer '$($member.SamAccountName)' konnte nicht abgerufen werden: $_" -Level WARN
}
}
'group' {
Write-Log "Verschachtelte Gruppe: $($member.Name)" -Level INFO
Get-NestedMembers -Group $member.distinguishedName -SourceGroup $SourceGroup
}
}
}
}
Write-Log "Starte Export für Gruppe '$GroupName' (inkl. verschachtelter Gruppen)..."
Get-NestedMembers -Group $GroupName -SourceGroup $GroupName Get-NestedMembers -Group $GroupName -SourceGroup $GroupName
if ($results.Count -eq 0) { if ($script:exportResults.Count -eq 0) {
Write-Log "Keine Benutzer in Gruppe '$GroupName' gefunden." -Level WARN Write-Log "Keine Benutzer in Gruppe '$GroupName' gefunden." -Level WARN
$script:btnExport.Enabled = $true $script:btnExport.Enabled = $true
return return
} }
$unique = $results | Sort-Object SamAccountName -Unique $unique = $script:exportResults | Sort-Object SamAccountName -Unique
try { try {
$unique | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8 -Delimiter ';' -ErrorAction Stop $unique | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8 -Delimiter ';' -ErrorAction Stop
$summary = "Export abgeschlossen. Benutzer: {0} | Gruppen durchsucht: {1} | Datei: {2}" -f ` $msg = "Export abgeschlossen. Benutzer: {0} | Gruppen: {1} | Datei: {2}" -f `
$unique.Count, $visitedGroups.Count, $OutputPath $unique.Count, $script:visitedGroups.Count, $OutputPath
Write-Log $summary -Level INFO Write-Log $msg
Write-OutputLine $summary ([System.Drawing.Color]::LightGreen) Write-OutputLine $msg ([System.Drawing.Color]::LightGreen)
} catch { } catch {
Write-Log "Fehler beim Schreiben der CSV: $_" -Level ERROR Write-Log "Fehler beim Schreiben der CSV: $_" -Level ERROR
} }
@@ -224,23 +236,24 @@ $cmbGroup.AutoCompleteMode = "SuggestAppend"
$cmbGroup.AutoCompleteSource = "ListItems" $cmbGroup.AutoCompleteSource = "ListItems"
$form.Controls.Add($cmbGroup) $form.Controls.Add($cmbGroup)
$btnLoadGroups = New-Object System.Windows.Forms.Button $btnLoadGroups = New-Object System.Windows.Forms.Button
$btnLoadGroups.Text = "Gruppen laden" $btnLoadGroups.Text = "Gruppen laden"
$btnLoadGroups.Location = New-Object System.Drawing.Point(550, 16) $btnLoadGroups.Location = New-Object System.Drawing.Point(550, 16)
$btnLoadGroups.Size = New-Object System.Drawing.Size(96, 26) $btnLoadGroups.Size = New-Object System.Drawing.Size(96, 26)
$btnLoadGroups.BackColor = [System.Drawing.Color]::FromArgb(0, 122, 204) $btnLoadGroups.BackColor = [System.Drawing.Color]::FromArgb(0, 122, 204)
$btnLoadGroups.ForeColor = [System.Drawing.Color]::White $btnLoadGroups.ForeColor = [System.Drawing.Color]::White
$btnLoadGroups.FlatStyle = "Flat" $btnLoadGroups.FlatStyle = "Flat"
$btnLoadGroups.FlatAppearance.BorderSize = 0 $btnLoadGroups.FlatAppearance.BorderSize = 0
$form.Controls.Add($btnLoadGroups) $form.Controls.Add($btnLoadGroups)
$btnLoadGroups.Add_Click({ $btnLoadGroups.Add_Click({
if (-not (Initialize-ADModule)) { return }
$btnLoadGroups.Text = "Lädt..." $btnLoadGroups.Text = "Lädt..."
$btnLoadGroups.Enabled = $false $btnLoadGroups.Enabled = $false
[System.Windows.Forms.Application]::DoEvents() [System.Windows.Forms.Application]::DoEvents()
try { try {
$adP = @{} $adP = @{}
if ($txtServer.Text.Trim()) { $adP['Server'] = $txtServer.Text.Trim() } if ($txtServer.Tag) { $adP['Server'] = $txtServer.Tag }
$groups = Get-ADGroup -Filter * @adP | Select-Object -ExpandProperty Name | Sort-Object $groups = Get-ADGroup -Filter * @adP | Select-Object -ExpandProperty Name | Sort-Object
$cmbGroup.Items.Clear() $cmbGroup.Items.Clear()
$cmbGroup.Items.AddRange($groups) $cmbGroup.Items.AddRange($groups)
@@ -252,7 +265,7 @@ $btnLoadGroups.Add_Click({
$btnLoadGroups.Enabled = $true $btnLoadGroups.Enabled = $true
}) })
# --- Output file row --- # --- CSV output row ---
$lblOut = New-Object System.Windows.Forms.Label $lblOut = New-Object System.Windows.Forms.Label
$lblOut.Text = "CSV Datei:" $lblOut.Text = "CSV Datei:"
$lblOut.Location = New-Object System.Drawing.Point($pad, 58) $lblOut.Location = New-Object System.Drawing.Point($pad, 58)
@@ -265,27 +278,25 @@ $txtOut.Size = New-Object System.Drawing.Size(436, 22)
$txtOut.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 45) $txtOut.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 45)
$txtOut.ForeColor = [System.Drawing.Color]::White $txtOut.ForeColor = [System.Drawing.Color]::White
$txtOut.BorderStyle = "FixedSingle" $txtOut.BorderStyle = "FixedSingle"
$txtOut.Text = (Join-Path $PSScriptRoot "export.csv") $txtOut.Text = if ($PSScriptRoot) { Join-Path $PSScriptRoot "export.csv" } else { "export.csv" }
$form.Controls.Add($txtOut) $form.Controls.Add($txtOut)
$btnBrowse = New-Object System.Windows.Forms.Button $btnBrowse = New-Object System.Windows.Forms.Button
$btnBrowse.Text = "Speichern..." $btnBrowse.Text = "Speichern..."
$btnBrowse.Location = New-Object System.Drawing.Point(550, 54) $btnBrowse.Location = New-Object System.Drawing.Point(550, 54)
$btnBrowse.Size = New-Object System.Drawing.Size(96, 26) $btnBrowse.Size = New-Object System.Drawing.Size(96, 26)
$btnBrowse.BackColor = [System.Drawing.Color]::FromArgb(0, 122, 204) $btnBrowse.BackColor = [System.Drawing.Color]::FromArgb(0, 122, 204)
$btnBrowse.ForeColor = [System.Drawing.Color]::White $btnBrowse.ForeColor = [System.Drawing.Color]::White
$btnBrowse.FlatStyle = "Flat" $btnBrowse.FlatStyle = "Flat"
$btnBrowse.FlatAppearance.BorderSize = 0 $btnBrowse.FlatAppearance.BorderSize = 0
$form.Controls.Add($btnBrowse) $form.Controls.Add($btnBrowse)
$btnBrowse.Add_Click({ $btnBrowse.Add_Click({
$sfd = New-Object System.Windows.Forms.SaveFileDialog $sfd = New-Object System.Windows.Forms.SaveFileDialog
$sfd.Filter = "CSV files (*.csv)|*.csv|All files (*.*)|*.*" $sfd.Filter = "CSV files (*.csv)|*.csv|All files (*.*)|*.*"
$sfd.Title = "CSV-Datei speichern" $sfd.Title = "CSV-Datei speichern"
$sfd.FileName = "export.csv" $sfd.FileName = "export.csv"
if ($sfd.ShowDialog() -eq "OK") { if ($sfd.ShowDialog() -eq "OK") { $txtOut.Text = $sfd.FileName }
$txtOut.Text = $sfd.FileName
}
}) })
# --- Server row --- # --- Server row ---
@@ -299,55 +310,58 @@ $txtServer = New-Object System.Windows.Forms.TextBox
$txtServer.Location = New-Object System.Drawing.Point(104, 94) $txtServer.Location = New-Object System.Drawing.Point(104, 94)
$txtServer.Size = New-Object System.Drawing.Size(436, 22) $txtServer.Size = New-Object System.Drawing.Size(436, 22)
$txtServer.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 45) $txtServer.BackColor = [System.Drawing.Color]::FromArgb(45, 45, 45)
$txtServer.ForeColor = [System.Drawing.Color]::White
$txtServer.BorderStyle = "FixedSingle" $txtServer.BorderStyle = "FixedSingle"
$txtServer.Tag = ''
$txtServer.Text = 'Domänencontroller (leer = Standard)'
$txtServer.ForeColor = [System.Drawing.Color]::Gray $txtServer.ForeColor = [System.Drawing.Color]::Gray
$txtServer.Text = "Domänencontroller (leer = Standard)"
$form.Controls.Add($txtServer) $form.Controls.Add($txtServer)
$txtServer.Add_GotFocus({ $txtServer.Add_GotFocus({
if ($txtServer.ForeColor -eq [System.Drawing.Color]::Gray) { if ($txtServer.Tag -eq '') {
$txtServer.Text = '' $txtServer.Text = ''
$txtServer.ForeColor = [System.Drawing.Color]::White $txtServer.ForeColor = [System.Drawing.Color]::White
} }
}) })
$txtServer.Add_LostFocus({ $txtServer.Add_LostFocus({
if ([string]::IsNullOrWhiteSpace($txtServer.Text)) { $txtServer.Tag = $txtServer.Text.Trim()
$txtServer.Text = "Domänencontroller (leer = Standard)" if ($txtServer.Tag -eq '') {
$txtServer.Text = 'Domänencontroller (leer = Standard)'
$txtServer.ForeColor = [System.Drawing.Color]::Gray $txtServer.ForeColor = [System.Drawing.Color]::Gray
} }
}) })
# --- Separator --- # --- Separator ---
$sep = New-Object System.Windows.Forms.Panel $sep = New-Object System.Windows.Forms.Panel
$sep.Location = New-Object System.Drawing.Point($pad, 130) $sep.Location = New-Object System.Drawing.Point($pad, 130)
$sep.Size = New-Object System.Drawing.Size(632, 1) $sep.Size = New-Object System.Drawing.Size(632, 1)
$sep.BackColor = [System.Drawing.Color]::FromArgb(70, 70, 70) $sep.BackColor = [System.Drawing.Color]::FromArgb(70, 70, 70)
$form.Controls.Add($sep) $form.Controls.Add($sep)
# --- Export button --- # --- Export button ---
$script:btnExport = New-Object System.Windows.Forms.Button $script:btnExport = New-Object System.Windows.Forms.Button
$script:btnExport.Text = "Export starten" $script:btnExport.Text = "Export starten"
$script:btnExport.Location = New-Object System.Drawing.Point($pad, 140) $script:btnExport.Location = New-Object System.Drawing.Point($pad, 140)
$script:btnExport.Size = New-Object System.Drawing.Size(632, 34) $script:btnExport.Size = New-Object System.Drawing.Size(632, 34)
$script:btnExport.BackColor = [System.Drawing.Color]::FromArgb(16, 124, 16) $script:btnExport.BackColor = [System.Drawing.Color]::FromArgb(16, 124, 16)
$script:btnExport.ForeColor = [System.Drawing.Color]::White $script:btnExport.ForeColor = [System.Drawing.Color]::White
$script:btnExport.FlatStyle = "Flat" $script:btnExport.FlatStyle = "Flat"
$script:btnExport.FlatAppearance.BorderSize = 0 $script:btnExport.FlatAppearance.BorderSize = 0
$script:btnExport.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold) $script:btnExport.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold)
$form.Controls.Add($script:btnExport) $form.Controls.Add($script:btnExport)
$script:btnExport.Add_Click({ $script:btnExport.Add_Click({
$groupName = $cmbGroup.Text.Trim() $groupName = $cmbGroup.Text.Trim()
$outputPath = $txtOut.Text.Trim() $outputPath = $txtOut.Text.Trim()
$server = if ($txtServer.ForeColor -ne [System.Drawing.Color]::Gray) { $txtServer.Text.Trim() } else { '' } $server = $txtServer.Tag
if (-not $groupName) { if (-not $groupName) {
[System.Windows.Forms.MessageBox]::Show("Bitte eine AD-Gruppe eingeben oder auswählen.", "Validierung", "OK", "Warning") | Out-Null [System.Windows.Forms.MessageBox]::Show(
"Bitte eine AD-Gruppe eingeben oder auswählen.", "Validierung", "OK", "Warning") | Out-Null
return return
} }
if (-not $outputPath) { if (-not $outputPath) {
[System.Windows.Forms.MessageBox]::Show("Bitte einen Speicherpfad für die CSV angeben.", "Validierung", "OK", "Warning") | Out-Null [System.Windows.Forms.MessageBox]::Show(
"Bitte einen Speicherpfad für die CSV angeben.", "Validierung", "OK", "Warning") | Out-Null
return return
} }
@@ -361,24 +375,24 @@ $lblOutput.Location = New-Object System.Drawing.Point($pad, 186)
$lblOutput.Size = New-Object System.Drawing.Size(80, 18) $lblOutput.Size = New-Object System.Drawing.Size(80, 18)
$form.Controls.Add($lblOutput) $form.Controls.Add($lblOutput)
$script:rtbOutput = New-Object System.Windows.Forms.RichTextBox $script:rtbOutput = New-Object System.Windows.Forms.RichTextBox
$script:rtbOutput.Location = New-Object System.Drawing.Point($pad, 206) $script:rtbOutput.Location = New-Object System.Drawing.Point($pad, 206)
$script:rtbOutput.Size = New-Object System.Drawing.Size(632, 320) $script:rtbOutput.Size = New-Object System.Drawing.Size(632, 320)
$script:rtbOutput.BackColor = [System.Drawing.Color]::FromArgb(12, 12, 12) $script:rtbOutput.BackColor = [System.Drawing.Color]::FromArgb(12, 12, 12)
$script:rtbOutput.ForeColor = [System.Drawing.Color]::White $script:rtbOutput.ForeColor = [System.Drawing.Color]::White
$script:rtbOutput.Font = New-Object System.Drawing.Font('Consolas', 9) $script:rtbOutput.Font = New-Object System.Drawing.Font('Consolas', 9)
$script:rtbOutput.ReadOnly = $true $script:rtbOutput.ReadOnly = $true
$script:rtbOutput.BorderStyle = "None" $script:rtbOutput.BorderStyle = "None"
$script:rtbOutput.ScrollBars = "Vertical" $script:rtbOutput.ScrollBars = "Vertical"
$form.Controls.Add($script:rtbOutput) $form.Controls.Add($script:rtbOutput)
# --- Status bar --- # --- Status bar ---
$lblStatus = New-Object System.Windows.Forms.Label $lblStatus = New-Object System.Windows.Forms.Label
$lblStatus.Text = "Log: $LogPath" $lblStatus.Text = "Log: $LogPath"
$lblStatus.Location = New-Object System.Drawing.Point($pad, 536) $lblStatus.Location = New-Object System.Drawing.Point($pad, 536)
$lblStatus.Size = New-Object System.Drawing.Size(632, 18) $lblStatus.Size = New-Object System.Drawing.Size(632, 18)
$lblStatus.ForeColor = [System.Drawing.Color]::Gray $lblStatus.ForeColor = [System.Drawing.Color]::Gray
$lblStatus.Font = New-Object System.Drawing.Font('Segoe UI', 8) $lblStatus.Font = New-Object System.Drawing.Font('Segoe UI', 8)
$form.Controls.Add($lblStatus) $form.Controls.Add($lblStatus)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------