Skip to content

Commit 6b313f2

Browse files
Create Iventory-ADWorkstation-Collector.ps1
Signed-off-by: LUIZ HAMILTON ROBERTO DA SILVA <[email protected]>
1 parent 2064637 commit 6b313f2

1 file changed

Lines changed: 201 additions & 0 deletions

File tree

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
<#
2+
.SYNOPSIS
3+
Interactive PowerShell GUI to Collect System, Network, and User Information from Remote Workstations.
4+
5+
.DESCRIPTION
6+
This script uses CIM (or fallback to WMI) to collect OS, BIOS, user, and network details
7+
from a list of workstations input by the user. It features GUI interaction, console hiding,
8+
structured logging, CSV export, and a responsive progress bar for user feedback.
9+
10+
.AUTHOR
11+
Luiz Hamilton Silva - @brazilianscriptguy
12+
13+
.VERSION
14+
Last Updated: September 30, 2025
15+
#>
16+
17+
# Hide PowerShell console
18+
if (-not ("Window" -as [type])) {
19+
Add-Type @"
20+
using System;
21+
using System.Runtime.InteropServices;
22+
public class Window {
23+
[DllImport("kernel32.dll", SetLastError = true)]
24+
static extern IntPtr GetConsoleWindow();
25+
[DllImport("user32.dll", SetLastError = true)]
26+
[return: MarshalAs(UnmanagedType.Bool)]
27+
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
28+
public static void Hide() {
29+
var handle = GetConsoleWindow();
30+
ShowWindow(handle, 0); // SW_HIDE
31+
}
32+
}
33+
"@
34+
}
35+
[Window]::Hide()
36+
37+
# Required GUI assembly
38+
Add-Type -AssemblyName System.Windows.Forms
39+
40+
# Define paths
41+
$scriptName = "WorkstationInventory"
42+
$logDir = "C:\Logs-TEMP"
43+
$logFile = Join-Path $logDir "$scriptName.log"
44+
$outputCsv = "C:\AD_Workstation_Inventory.csv"
45+
46+
if (-not (Test-Path $logDir)) {
47+
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
48+
}
49+
50+
function Log-Message {
51+
param(
52+
[string]$Message,
53+
[ValidateSet("INFO", "WARNING", "ERROR")] [string]$Type = "INFO"
54+
)
55+
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
56+
$entry = "[$timestamp] [$Type] $Message"
57+
Add-Content -Path $logFile -Value $entry
58+
}
59+
60+
function Show-InfoMessage {
61+
param([string]$Message)
62+
[System.Windows.Forms.MessageBox]::Show($Message, "Information", 'OK', 'Information') | Out-Null
63+
Log-Message -Message $Message -Type "INFO"
64+
}
65+
66+
function Show-ErrorMessage {
67+
param([string]$Message)
68+
[System.Windows.Forms.MessageBox]::Show($Message, "Error", 'OK', 'Error') | Out-Null
69+
Log-Message -Message $Message -Type "ERROR"
70+
}
71+
72+
function Get-ComputerListFromText ($inputText) {
73+
return $inputText -split "[\r\n]+" | Where-Object { $_ -and $_.Trim() -ne "" }
74+
}
75+
76+
function Collect-Inventory {
77+
param (
78+
[string[]]$Computers,
79+
[System.Windows.Forms.ProgressBar]$ProgressBar
80+
)
81+
$Results = @()
82+
$count = 0
83+
$total = $Computers.Count
84+
85+
foreach ($Computer in $Computers) {
86+
$count++
87+
$percent = [math]::Round(($count / $total) * 100)
88+
$ProgressBar.Value = [math]::Min($percent, 100)
89+
90+
try {
91+
Log-Message -Message "Querying $Computer..."
92+
if (Test-Connection -ComputerName $Computer -Count 2 -Quiet) {
93+
try {
94+
$OS = Get-CimInstance -Class Win32_OperatingSystem -ComputerName $Computer -ErrorAction Stop
95+
$BIOS = Get-CimInstance -Class Win32_BIOS -ComputerName $Computer -ErrorAction Stop
96+
$Net = Get-CimInstance -Class Win32_NetworkAdapterConfiguration -ComputerName $Computer -ErrorAction Stop | Where-Object { $_.IPEnabled -eq $true }
97+
$User = Get-CimInstance -Class Win32_ComputerSystem -ComputerName $Computer -ErrorAction Stop
98+
} catch {
99+
Log-Message -Message "Falling back to WMI for $Computer..." -Type "WARNING"
100+
$OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $Computer
101+
$BIOS = Get-WmiObject -Class Win32_BIOS -ComputerName $Computer
102+
$Net = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $Computer | Where-Object { $_.IPEnabled -eq $true }
103+
$User = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $Computer
104+
}
105+
106+
$Results += [PSCustomObject]@{
107+
Hostname = $Computer
108+
LoggedUser = $User.UserName
109+
OperatingSystem = $OS.Caption
110+
OSVersion = $OS.Version
111+
LastBootTime = ([Management.ManagementDateTimeConverter]::ToDateTime($OS.LastBootUpTime))
112+
IPAddress = $Net.IPAddress -join ', '
113+
MACAddress = $Net.MACAddress
114+
DefaultGateway = $Net.DefaultIPGateway -join ', '
115+
AdapterName = $Net.Description
116+
Domain = $User.Domain
117+
BIOSManufacturer = $BIOS.Manufacturer
118+
SerialNumber = $BIOS.SerialNumber
119+
}
120+
} else {
121+
Log-Message -Message "$Computer is unreachable." -Type "WARNING"
122+
$Results += [PSCustomObject]@{
123+
Hostname = $Computer
124+
LoggedUser = "Unavailable"
125+
OperatingSystem = "Unreachable"
126+
OSVersion = "N/A"
127+
LastBootTime = "N/A"
128+
IPAddress = "N/A"
129+
MACAddress = "N/A"
130+
DefaultGateway = "N/A"
131+
AdapterName = "N/A"
132+
Domain = "N/A"
133+
BIOSManufacturer = "N/A"
134+
SerialNumber = "N/A"
135+
}
136+
}
137+
} catch {
138+
Log-Message -Message ("Error querying ${Computer}: $($_.Exception.Message)") -Type "ERROR"
139+
}
140+
}
141+
142+
try {
143+
$Results | Export-Csv -Path $outputCsv -NoTypeInformation -Encoding UTF8
144+
Show-InfoMessage -Message "Report generated successfully.\nSaved to: $outputCsv"
145+
} catch {
146+
Show-ErrorMessage -Message "Error exporting to CSV: $($_.Exception.Message)"
147+
}
148+
149+
$ProgressBar.Value = 100
150+
}
151+
152+
# GUI - Input for hostnames
153+
$form = New-Object System.Windows.Forms.Form
154+
$form.Text = "Workstation Inventory Collector"
155+
$form.Size = New-Object System.Drawing.Size(500, 420)
156+
$form.StartPosition = "CenterScreen"
157+
158+
$label = New-Object System.Windows.Forms.Label
159+
$label.Text = "Enter hostnames or IPs (one per line):"
160+
$label.Location = '10,10'
161+
$label.AutoSize = $true
162+
$form.Controls.Add($label)
163+
164+
$textBox = New-Object System.Windows.Forms.TextBox
165+
$textBox.Multiline = $true
166+
$textBox.ScrollBars = 'Vertical'
167+
$textBox.Location = '10,40'
168+
$textBox.Size = '460,220'
169+
$form.Controls.Add($textBox)
170+
171+
$progressBar = New-Object System.Windows.Forms.ProgressBar
172+
$progressBar.Location = '10,270'
173+
$progressBar.Size = '460,20'
174+
$progressBar.Style = 'Continuous'
175+
$form.Controls.Add($progressBar)
176+
177+
$buttonRun = New-Object System.Windows.Forms.Button
178+
$buttonRun.Text = "Run Inventory"
179+
$buttonRun.Location = '10,310'
180+
$buttonRun.Size = '220,40'
181+
$buttonRun.Add_Click({
182+
$computers = Get-ComputerListFromText -inputText $textBox.Text
183+
if ($computers.Count -gt 0) {
184+
$progressBar.Value = 0
185+
Collect-Inventory -Computers $computers -ProgressBar $progressBar
186+
} else {
187+
Show-ErrorMessage -Message "Please provide at least one valid hostname or IP."
188+
}
189+
})
190+
$form.Controls.Add($buttonRun)
191+
192+
$buttonClose = New-Object System.Windows.Forms.Button
193+
$buttonClose.Text = "Close"
194+
$buttonClose.Location = '250,310'
195+
$buttonClose.Size = '220,40'
196+
$buttonClose.Add_Click({ $form.Close() })
197+
$form.Controls.Add($buttonClose)
198+
199+
$form.Topmost = $true
200+
$form.Add_Shown({ $form.Activate() })
201+
[void]$form.ShowDialog()

0 commit comments

Comments
 (0)