Skip to content

Commit 5bc02cc

Browse files
Update Launch-Script-AutomaticMenu.ps1
Signed-off-by: LUIZ HAMILTON ROBERTO DA SILVA <[email protected]>
1 parent 57ed609 commit 5bc02cc

1 file changed

Lines changed: 107 additions & 198 deletions

File tree

Lines changed: 107 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<#
1+
<#
22
.SYNOPSIS
33
PowerShell GUI for Executing Scripts Organized by Tabs with Real-Time Search.
44
@@ -11,284 +11,193 @@
1111
Luiz Hamilton Silva - @brazilianscriptguy
1212
1313
.VERSION
14-
Updated: July 17, 2025
15-
Version: 2.2 (Fixed GUI layout issues)
14+
Updated: August 6, 2025
15+
Version: 2.3 (Fixed GUI layout, inline search, logging compliance)
1616
#>
1717

1818
#region --- Initialization and Configuration
1919

2020
# Hide the PowerShell console window
21-
Add-Type @"
22-
using System;
23-
using System.Runtime.InteropServices;
24-
public class Window {
25-
[DllImport("kernel32.dll", SetLastError = true)]
26-
static extern IntPtr GetConsoleWindow();
27-
[DllImport("user32.dll", SetLastError = true)]
28-
[return: MarshalAs(UnmanagedType.Bool)]
29-
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
30-
public static void Hide() {
31-
var handle = GetConsoleWindow();
32-
ShowWindow(handle, 0); // 0 = SW_HIDE
33-
}
34-
public static void Show() {
35-
var handle = GetConsoleWindow();
36-
ShowWindow(handle, 5); // 5 = SW_SHOW
21+
if (-not ([System.Management.Automation.PSTypeName]'Window').Type) {
22+
Add-Type @"
23+
using System;
24+
using System.Runtime.InteropServices;
25+
public class Window {
26+
[DllImport("kernel32.dll", SetLastError = true)]
27+
static extern IntPtr GetConsoleWindow();
28+
[DllImport("user32.dll", SetLastError = true)]
29+
[return: MarshalAs(UnmanagedType.Bool)]
30+
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
31+
public static void Hide() {
32+
var handle = GetConsoleWindow();
33+
ShowWindow(handle, 0); // 0 = SW_HIDE
34+
}
35+
public static void Show() {
36+
var handle = GetConsoleWindow();
37+
ShowWindow(handle, 5); // 5 = SW_SHOW
38+
}
3739
}
38-
}
3940
"@
41+
}
4042
[Window]::Hide()
4143

42-
# Import necessary assemblies for Windows Forms and Drawing
4344
Add-Type -AssemblyName System.Windows.Forms
4445
Add-Type -AssemblyName System.Drawing
4546

46-
# Get the current script directory
4747
$scriptDirectory = Split-Path -Parent $MyInvocation.MyCommand.Path
48-
Write-Host "Current Script Directory: $scriptDirectory" -ForegroundColor Cyan
4948

50-
# Logging function
51-
function Log-Message {
49+
function Write-Log {
5250
param (
5351
[Parameter(Mandatory = $true)][string]$Message,
5452
[ValidateSet("INFO", "WARN", "ERROR")][string]$MessageType = "INFO"
5553
)
5654
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
57-
$logEntry = "[$timestamp] [$MessageType] $Message"
5855
$logPath = Join-Path $scriptDirectory "SysAdminToolSet.log"
56+
$entry = "[$timestamp] [$MessageType] $Message"
5957
try {
60-
if (-not (Test-Path (Split-Path $logPath))) {
61-
New-Item -Path (Split-Path $logPath) -ItemType Directory -Force | Out-Null
58+
if (-not (Test-Path $logPath)) {
59+
$null = New-Item -Path $logPath -ItemType File -Force
6260
}
63-
Add-Content -Path $logPath -Value $logEntry -ErrorAction Stop
61+
Add-Content -Path $logPath -Value $entry
6462
} catch {
65-
Write-Warning "Failed to write to log: $_"
63+
Write-Warning "Failed to log message: $_"
6664
}
6765
}
6866

69-
Log-Message "Starting Launch Script Automatic Menu execution."
70-
7167
#endregion
7268

7369
#region --- Core Functions
7470

75-
# Function to generate a dictionary of script filenames and paths from all subdirectories
7671
function Get-ScriptDictionaries {
7772
try {
7873
$directories = Get-ChildItem -Path $scriptDirectory -Directory -Recurse -ErrorAction Stop
7974
$scriptsByCategory = @{}
80-
8175
foreach ($dir in $directories) {
82-
$scriptFiles = Get-ChildItem -Path $dir.FullName -Filter "*.ps1" -File -ErrorAction Stop
83-
if ($scriptFiles.Count -gt 0) {
84-
$category = $dir.Name
85-
$scriptsByCategory[$category] = $scriptFiles | Sort-Object -Property Name
86-
Log-Message "Loaded $category category with $($scriptFiles.Count) scripts"
76+
$scripts = Get-ChildItem -Path $dir.FullName -Filter "*.ps1" -File -ErrorAction Stop
77+
if ($scripts.Count -gt 0) {
78+
$scriptsByCategory[$dir.Name] = $scripts | Sort-Object Name
79+
Write-Log "Loaded $($dir.Name) with $($scripts.Count) scripts"
8780
}
8881
}
89-
if ($scriptsByCategory.Count -eq 0) {
90-
Log-Message "No script categories found" -MessageType "WARN"
91-
}
9282
return $scriptsByCategory
9383
} catch {
94-
Log-Message "Failed to load script dictionaries: $_" -MessageType "ERROR"
84+
Write-Log "Script dictionary load failed: $_" "ERROR"
9585
return @{}
9686
}
9787
}
9888

99-
# Function to update listbox items based on the search text with debouncing
10089
function Update-ListBox {
10190
param (
102-
[System.Windows.Forms.TextBox]$searchBox,
103-
[System.Windows.Forms.CheckedListBox]$listBox,
104-
[System.Collections.ObjectModel.Collection[System.IO.FileInfo]]$originalList
91+
[System.Windows.Forms.TextBox]$SearchBox,
92+
[System.Windows.Forms.CheckedListBox]$ListBox,
93+
[System.IO.FileInfo[]]$ScriptFiles
10594
)
106-
107-
$searchText = $searchBox.Text.Trim().ToLower()
108-
$listBox.BeginUpdate()
109-
$listBox.Items.Clear()
110-
111-
if ([string]::IsNullOrEmpty($searchText)) {
112-
foreach ($file in $originalList) {
113-
$listBox.Items.Add($file.Name, $false)
114-
}
115-
} else {
116-
foreach ($file in $originalList) {
117-
if ($file.Name.ToLower().Contains($searchText)) {
118-
$listBox.Items.Add($file.Name, $false)
119-
}
95+
$searchText = $SearchBox.Text.Trim().ToLowerInvariant()
96+
$ListBox.BeginUpdate()
97+
$ListBox.Items.Clear()
98+
foreach ($script in $ScriptFiles) {
99+
if ($searchText -eq "" -or $script.Name.ToLowerInvariant().Contains($searchText)) {
100+
$ListBox.Items.Add($script.Name, $false)
120101
}
121102
}
122-
123-
if ($listBox.Items.Count -eq 0) {
124-
$listBox.Items.Add("<No matching scripts found>", $false)
103+
if ($ListBox.Items.Count -eq 0) {
104+
$ListBox.Items.Add("<No matching scripts found>", $false)
125105
}
126-
127-
$listBox.EndUpdate()
106+
$ListBox.EndUpdate()
128107
}
129108

130-
# Function to execute selected scripts
131109
function Execute-Scripts {
132-
param ([System.Windows.Forms.TabControl]$tabControl)
133-
$anyExecuted = $false
134-
135-
foreach ($tabPage in $tabControl.TabPages) {
136-
$listBox = $tabPage.Controls | Where-Object { $_ -is [System.Windows.Forms.CheckedListBox] }
137-
if ($listBox) {
138-
foreach ($script in $listBox.CheckedItems) {
139-
if ($script -eq "<No matching scripts found>") { continue }
140-
141-
$scriptPath = $scriptsByCategory[$tabPage.Text] | Where-Object { $_.Name -eq $script } | Select-Object -ExpandProperty FullName
142-
if (Test-Path $scriptPath) {
143-
try {
144-
$psi = New-Object System.Diagnostics.ProcessStartInfo
145-
$psi.FileName = "powershell.exe"
146-
$psi.Arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
147-
$psi.UseShellExecute = $false
148-
$psi.RedirectStandardOutput = $true
149-
$psi.RedirectStandardError = $true
150-
$process = [System.Diagnostics.Process]::Start($psi)
151-
$output = $process.StandardOutput.ReadToEnd()
152-
$errorOutput = $process.StandardError.ReadToEnd()
153-
$process.WaitForExit()
154-
if ($process.ExitCode -eq 0) {
155-
Log-Message "Successfully executed: $scriptPath"
156-
Write-Host "Executed: $scriptPath`nOutput: $output" -ForegroundColor Green
157-
} else {
158-
$errorMessage = "Execution failed for ${scriptPath}: ${errorOutput}"
159-
Log-Message $errorMessage -MessageType "ERROR"
160-
[System.Windows.Forms.MessageBox]::Show("Error executing ${script}: ${errorOutput}", "Execution Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
161-
}
162-
$anyExecuted = $true
163-
} catch {
164-
$errorMessage = "Failed to execute ${scriptPath}: $_"
165-
Log-Message $errorMessage -MessageType "ERROR"
166-
[System.Windows.Forms.MessageBox]::Show("Failed to execute ${script}: $_", "Execution Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
167-
}
110+
param ([System.Windows.Forms.TabControl]$TabControl)
111+
$executed = $false
112+
foreach ($tab in $TabControl.TabPages) {
113+
$listBox = $tab.Controls | Where-Object { $_ -is [System.Windows.Forms.CheckedListBox] }
114+
foreach ($item in $listBox.CheckedItems) {
115+
if ($item -eq "<No matching scripts found>") { continue }
116+
$scriptPath = ($scriptsByCategory[$tab.Text] | Where-Object { $_.Name -eq $item }).FullName
117+
if (-not (Test-Path $scriptPath)) {
118+
Write-Log "Script not found: $scriptPath" "ERROR"
119+
continue
120+
}
121+
try {
122+
$psi = New-Object System.Diagnostics.ProcessStartInfo -Property @{
123+
FileName = "powershell.exe"
124+
Arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
125+
UseShellExecute = $false
126+
RedirectStandardOutput = $true
127+
RedirectStandardError = $true
128+
}
129+
$process = [System.Diagnostics.Process]::Start($psi)
130+
$output = $process.StandardOutput.ReadToEnd()
131+
$errors = $process.StandardError.ReadToEnd()
132+
$process.WaitForExit()
133+
if ($process.ExitCode -eq 0) {
134+
Write-Log "Executed successfully: $scriptPath"
168135
} else {
169-
Log-Message "Script not found: $scriptPath" -MessageType "ERROR"
170-
[System.Windows.Forms.MessageBox]::Show("Script not found: $scriptPath", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
136+
Write-Log "Execution failed: $scriptPath - Error: $errors" "ERROR"
171137
}
138+
$executed = $true
139+
} catch {
140+
Write-Log "Exception while executing ${scriptPath}: $_" "ERROR"
172141
}
173142
}
174143
}
175-
176-
if (-not $anyExecuted) {
177-
[System.Windows.Forms.MessageBox]::Show("No scripts selected for execution.", "Info", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information)
144+
if (-not $executed) {
145+
[System.Windows.Forms.MessageBox]::Show("No scripts selected.", "Info")
178146
}
179147
}
180148

181149
#endregion
182150

183-
#region --- GUI Implementation
151+
#region --- GUI Builder
184152

185153
function Create-GUI {
186-
# Generate script dictionaries
187-
$scriptsByCategory = Get-ScriptDictionaries
154+
$global:scriptsByCategory = Get-ScriptDictionaries
188155
if ($scriptsByCategory.Count -eq 0) {
189-
[System.Windows.Forms.MessageBox]::Show("No scripts found in $scriptDirectory or its subdirectories.", "Error", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error)
156+
[System.Windows.Forms.MessageBox]::Show("No scripts found.", "Error")
190157
return
191158
}
192159

193-
# Initialize the Form
194-
$form = [System.Windows.Forms.Form]::new()
195-
$form.Text = 'Lauch Script Automatic Menu'
196-
$form.Size = [System.Drawing.Size]::new(1200, 900)
197-
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
198-
$form.BackColor = [System.Drawing.Color]::WhiteSmoke
199-
$form.Add_Resize({
200-
$tabControl.Size = [System.Drawing.Size]::new($form.ClientSize.Width - 40, $form.ClientSize.Height - 150)
201-
$executeButton.Location = [System.Drawing.Point]::new(($form.ClientSize.Width - 150) / 2, $form.ClientSize.Height - 80)
202-
})
160+
$form = New-Object Windows.Forms.Form -Property @{
161+
Text = "Launch Script Menu"
162+
Size = New-Object Drawing.Size(1100, 800)
163+
StartPosition = "CenterScreen"
164+
BackColor = "WhiteSmoke"
165+
}
203166

204-
# Add TabControl for organizing script categories
205-
$tabControl = [System.Windows.Forms.TabControl]::new()
206-
$tabControl.Size = [System.Drawing.Size]::new($form.ClientSize.Width - 40, $form.ClientSize.Height - 150)
207-
$tabControl.Location = [System.Drawing.Point]::new(10, 10)
208-
$tabControl.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Right -bor [System.Windows.Forms.AnchorStyles]::Bottom
167+
$tabControl = New-Object Windows.Forms.TabControl -Property @{
168+
Dock = "Fill"
169+
}
209170
$form.Controls.Add($tabControl)
210171

211-
# Store references to controls
212-
$tabControls = @{}
213-
214-
# Add Tabs for each category with debounced search
215172
foreach ($category in $scriptsByCategory.Keys) {
216-
$tabPage = [System.Windows.Forms.TabPage]::new()
217-
$tabPage.Text = $category
218-
$tabPage.AutoScroll = $true
219-
220-
# Add Search Box
221-
$searchBox = [System.Windows.Forms.TextBox]::new()
222-
$searchBox.Size = [System.Drawing.Size]::new($tabPage.ClientSize.Width - 20, 25)
223-
$searchBox.Location = [System.Drawing.Point]::new(10, 10)
224-
$searchBox.Font = [System.Drawing.Font]::new("Arial", 10)
225-
$searchBox.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Right
226-
$tabPage.Controls.Add($searchBox)
227-
228-
# Add ListBox
229-
$listBox = [System.Windows.Forms.CheckedListBox]::new()
230-
$listBox.Size = [System.Drawing.Size]::new($tabPage.ClientSize.Width - 20, $tabPage.ClientSize.Height - 60)
231-
$listBox.Location = [System.Drawing.Point]::new(10, 40)
232-
$listBox.Font = [System.Drawing.Font]::new("Arial", 9)
233-
$listBox.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Right -bor [System.Windows.Forms.AnchorStyles]::Bottom
234-
$listBox.ScrollAlwaysVisible = $true
235-
$tabPage.Controls.Add($listBox)
236-
237-
# Initial population
238-
Update-ListBox -searchBox $searchBox -listBox $listBox -originalList $scriptsByCategory[$category]
173+
$tab = New-Object Windows.Forms.TabPage -Property @{ Text = $category; AutoScroll = $true }
174+
$searchBox = New-Object Windows.Forms.TextBox -Property @{ Location = '10,10'; Size = '1050,25' }
175+
$listBox = New-Object Windows.Forms.CheckedListBox -Property @{ Location = '10,45'; Size = '1050,650' }
176+
$tab.Controls.AddRange(@($searchBox, $listBox))
177+
$tabControl.TabPages.Add($tab)
178+
179+
Update-ListBox -SearchBox $searchBox -ListBox $listBox -ScriptFiles $scriptsByCategory[$category]
239180

240-
# Debounced search handler
241-
$searchTimer = $null
242181
$searchBox.Add_TextChanged({
243-
if ($searchTimer) { $searchTimer.Dispose() }
244-
$searchTimer = New-Object System.Timers.Timer -ArgumentList 300
245-
$searchTimer.AutoReset = $false
246-
$searchTimer.add_Elapsed({
247-
Update-ListBox -searchBox $searchBox -listBox $listBox -originalList $scriptsByCategory[$category]
248-
})
249-
$searchTimer.Start()
250-
})
251-
252-
# Dynamic resize handler for tab page controls
253-
$tabPage.Add_Resize({
254-
$searchBox.Size = [System.Drawing.Size]::new($tabPage.ClientSize.Width - 20, 25)
255-
$listBox.Size = [System.Drawing.Size]::new($tabPage.ClientSize.Width - 20, $tabPage.ClientSize.Height - 60)
256-
})
257-
258-
$tabControls[$category] = @{ SearchBox = $searchBox; ListBox = $listBox }
259-
$tabControl.TabPages.Add($tabPage)
260-
}
261-
262-
# Handle tab switch
263-
$tabControl.Add_SelectedIndexChanged({
264-
$selectedTab = $tabControl.SelectedTab
265-
if ($selectedTab -ne $null) {
266-
$category = $selectedTab.Text
267-
if ($tabControls.ContainsKey($category)) {
268-
$controls = $tabControls[$category]
269-
Update-ListBox -searchBox $controls.SearchBox -listBox $controls.ListBox -originalList $scriptsByCategory[$category]
270-
}
271-
}
182+
Update-ListBox -SearchBox $searchBox -ListBox $listBox -ScriptFiles $scriptsByCategory[$category]
272183
})
184+
}
273185

274-
# Add Execute Button with padding
275-
$executeButton = [System.Windows.Forms.Button]::new()
276-
$executeButton.Text = 'Execute'
277-
$executeButton.Size = [System.Drawing.Size]::new(150, 40)
278-
$executeButton.Location = [System.Drawing.Point]::new(($form.ClientSize.Width - 150) / 2, $form.ClientSize.Height - 100) # Adjusted for padding
279-
$executeButton.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom
280-
$executeButton.BackColor = [System.Drawing.Color]::LightSkyBlue
281-
$executeButton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
282-
$executeButton.Add_Click({ Execute-Scripts -tabControl $tabControl })
283-
$form.Controls.Add($executeButton)
186+
$btnExecute = New-Object Windows.Forms.Button -Property @{
187+
Text = "Execute Selected"
188+
Size = '200,30'
189+
Location = New-Object Drawing.Point(440, 700)
190+
BackColor = 'LightSkyBlue'
191+
}
192+
$btnExecute.Add_Click({ Execute-Scripts -TabControl $tabControl })
193+
$form.Controls.Add($btnExecute)
284194

285-
# Show the Form
286-
[void] $form.ShowDialog()
195+
$form.ShowDialog() | Out-Null
287196
}
288197

289198
#endregion
290199

291-
# Call the function to create the GUI
200+
# Entry Point
292201
Create-GUI
293202

294203
# End of script

0 commit comments

Comments
 (0)