Skip to content

Commit 1afdfd1

Browse files
Update Check-WSUS-AdminAssembly.ps1
Signed-off-by: LUIZ HAMILTON ROBERTO DA SILVA <[email protected]>
1 parent 594b7f6 commit 1afdfd1

File tree

1 file changed

+106
-44
lines changed

1 file changed

+106
-44
lines changed
Lines changed: 106 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
<#
22
.SYNOPSIS
3-
Validates the presence of Microsoft.UpdateServices.Administration.dll in the Global Assembly Cache (GAC).
3+
Validates and loads Microsoft.UpdateServices.Administration.dll (WSUS Admin API).
44
55
.DESCRIPTION
6-
This script checks whether the WSUS Administration Console assembly is loaded in the current PowerShell session.
7-
If not, it attempts to load it from the Global Assembly Cache (GAC). If that fails, it attempts to load it directly
8-
from a known file path. The script also displays GUI message boxes to assist the user with guidance and diagnostics.
6+
- Prefers Import-Module UpdateServices (works when WSUS Management Tools are installed).
7+
- If the module isn't available, attempts to load the WSUS Admin assembly from the GAC.
8+
- Searches common GAC roots on modern and legacy systems.
9+
- Falls back to a known explicit path if provided.
10+
- Uses small WinForms message boxes for guidance/diagnostics.
11+
- Hides the console window (comment out [Window]::Hide() while debugging).
912
1013
.AUTHOR
1114
Luiz Hamilton Silva - @brazilianscriptguy
1215
1316
.VERSION
14-
Last Updated: July 11, 2025
17+
Last Updated: Sep 15, 2025
1518
#>
1619

17-
# Hide Console Window
20+
# ---------------- Console (hidden) ----------------
1821
Add-Type @"
1922
using System;
2023
using System.Runtime.InteropServices;
@@ -24,76 +27,135 @@ public class Window {
2427
[DllImport("user32.dll", SetLastError = true)]
2528
[return: MarshalAs(UnmanagedType.Bool)]
2629
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
27-
public static void Hide() {
28-
var handle = GetConsoleWindow();
29-
ShowWindow(handle, 0);
30-
}
30+
public static void Hide() { var handle = GetConsoleWindow(); ShowWindow(handle, 0); }
3131
}
3232
"@
33-
[Window]::Hide()
33+
[Window]::Hide() # <-- comment this line while debugging to keep the console visible
3434

35-
# Load required assemblies
35+
# ---------------- UI + utils ----------------
3636
Add-Type -AssemblyName System.Windows.Forms
3737
[System.Windows.Forms.Application]::EnableVisualStyles()
3838

39-
# Logging function
4039
function Write-Log {
41-
param (
42-
[string]$Message,
43-
[ValidateSet("INFO", "WARNING", "ERROR")][string]$Level
40+
param(
41+
[Parameter(Mandatory)][string]$Message,
42+
[ValidateSet("INFO","WARNING","ERROR")] [string]$Level = "INFO"
4443
)
45-
46-
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
47-
$formatted = "[$timestamp] [$Level] $Message"
48-
Write-Output $formatted
44+
$stamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
45+
Write-Output "[$stamp] [$Level] $Message"
4946
}
5047

5148
function Show-MessageBox {
52-
param (
53-
[string]$Message,
49+
param(
50+
[Parameter(Mandatory)][string]$Message,
5451
[string]$Title = "WSUS Administration Assembly Check",
5552
[System.Windows.Forms.MessageBoxButtons]$Buttons = [System.Windows.Forms.MessageBoxButtons]::OK,
5653
[System.Windows.Forms.MessageBoxIcon]$Icon = [System.Windows.Forms.MessageBoxIcon]::Information
5754
)
5855
[System.Windows.Forms.MessageBox]::Show($Message, $Title, $Buttons, $Icon) | Out-Null
5956
}
6057

61-
# Define the expected path to the WSUS Administration assembly in the GAC
62-
$wsusAssemblyPath = "C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.UpdateServices.Administration\v4.0_4.0.0.0__31bf3856ad364e35\Microsoft.UpdateServices.Administration.dll"
58+
# If you want to pin a known path (kept from your original script).
59+
$ExplicitAssemblyPath = "C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.UpdateServices.Administration\v4.0_4.0.0.0__31bf3856ad364e35\Microsoft.UpdateServices.Administration.dll"
60+
61+
# Common GAC roots on modern/legacy systems
62+
# Common GAC roots on modern/legacy systems
63+
$GacRoots = @(
64+
(Join-Path $env:WINDIR 'Microsoft.NET\assembly\GAC_MSIL') # .NET 4+ (Win10/2016+)
65+
(Join-Path $env:WINDIR 'assembly\GAC_MSIL') # legacy view
66+
)
67+
68+
# ---------------- Helper: Is Assembly Loaded? ----------------
69+
function Test-AssemblyLoaded {
70+
[OutputType([bool])]
71+
param([string]$PartialName = "Microsoft.UpdateServices.Administration")
72+
return [AppDomain]::CurrentDomain.GetAssemblies().FullName -match [regex]::Escape($PartialName)
73+
}
74+
75+
# ---------------- Try 1: Import-Module UpdateServices ----------------
76+
try {
77+
if ($PSVersionTable.PSEdition -eq 'Core') {
78+
# PowerShell 7+: use Windows PowerShell compatibility shim if available
79+
Import-Module -Name UpdateServices -UseWindowsPowerShell -ErrorAction Stop
80+
} else {
81+
Import-Module -Name UpdateServices -ErrorAction Stop
82+
}
83+
84+
if (Test-AssemblyLoaded) {
85+
Write-Log "WSUS Administration assembly available via UpdateServices module." -Level INFO
86+
Show-MessageBox -Message "WSUS Administration assembly is available (loaded with UpdateServices module)."
87+
return
88+
}
89+
} catch {
90+
Write-Log "UpdateServices module not available or failed to load: $($_.Exception.Message)" -Level WARNING
91+
}
6392

64-
# Attempt to load the assembly by partial name (GAC)
93+
# ---------------- Try 2: Load from GAC (by partial name) ----------------
6594
try {
66-
$assembly = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
67-
if ($assembly) {
68-
Write-Log "WSUS Administration assembly loaded successfully from GAC." -Level INFO
69-
Show-MessageBox -Message "WSUS Administration assembly loaded successfully from the Global Assembly Cache (GAC)."
95+
$asm = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
96+
if ($asm -and (Test-AssemblyLoaded)) {
97+
Write-Log "WSUS Administration assembly loaded from GAC via partial name." -Level INFO
98+
Show-MessageBox -Message "WSUS Administration assembly loaded from the Global Assembly Cache (GAC)."
7099
return
71100
} else {
72-
throw "Assembly not loaded from GAC."
101+
throw "LoadWithPartialName returned null."
73102
}
74103
} catch {
75-
Write-Log "Failed to load WSUS assembly from GAC: $_" -Level WARNING
104+
Write-Log "Could not load WSUS assembly by partial name: $($_.Exception.Message)" -Level WARNING
76105
}
77106

78-
# Attempt to load the assembly directly from known GAC path
79-
if (Test-Path $wsusAssemblyPath) {
107+
# ---------------- Try 3: Probe known GAC folders and Add-Type ----------------
108+
$foundPath = $null
109+
foreach ($root in $GacRoots) {
110+
if (-not (Test-Path $root)) { continue }
80111
try {
81-
Add-Type -Path $wsusAssemblyPath -ErrorAction Stop
82-
Write-Log "WSUS Administration assembly loaded successfully from $wsusAssemblyPath." -Level INFO
83-
Show-MessageBox -Message "WSUS Administration assembly loaded successfully from path:`n$wsusAssemblyPath"
112+
$candidate = Get-ChildItem -Path $root -Recurse -Filter "Microsoft.UpdateServices.Administration.dll" -ErrorAction SilentlyContinue | Select-Object -First 1
113+
if ($candidate) { $foundPath = $candidate.FullName; break }
114+
} catch { }
115+
}
116+
117+
if (-not $foundPath -and (Test-Path $ExplicitAssemblyPath)) {
118+
$foundPath = $ExplicitAssemblyPath
119+
}
120+
121+
if ($foundPath) {
122+
try {
123+
Add-Type -Path $foundPath -ErrorAction Stop
124+
if (Test-AssemblyLoaded) {
125+
Write-Log "WSUS Administration assembly loaded from: $foundPath" -Level INFO
126+
Show-MessageBox -Message "WSUS Administration assembly loaded from:`n$foundPath"
127+
return
128+
} else {
129+
throw "Add-Type succeeded but assembly not visible in current AppDomain."
130+
}
84131
} catch {
85-
$msg = "Error: Failed to load WSUS assembly from:`n$wsusAssemblyPath`n`nDetails: $_"
132+
$msg = "Failed to load WSUS assembly from:`n$foundPath`n`nDetails: $($_.Exception.Message)"
86133
Write-Log $msg -Level ERROR
87134
Show-MessageBox -Message $msg -Icon 'Error'
88135
exit 1
89136
}
90-
} else {
91-
$msg = "WSUS assembly not found at:`n$wsusAssemblyPath`n`nEnsure the WSUS Administration Console is installed using one of the following methods:`n"
92-
$msg += "`n1. Server Manager:`n - Add Roles and Features > Features > Windows Server Update Services > WSUS Tools"
93-
$msg += "`n2. PowerShell:`n - Install-WindowsFeature -Name UpdateServices-UI"
94-
Write-Log "Error: WSUS assembly not found at $wsusAssemblyPath." -Level ERROR
95-
Show-MessageBox -Message $msg -Icon 'Error'
96-
exit 1
97137
}
98138

139+
# ---------------- Final guidance (not found) ----------------
140+
$help = @"
141+
WSUS Administration assembly was not found.
142+
143+
Install WSUS Management Tools (Administration Console) using one of the following:
144+
145+
1) Server Manager
146+
- Add Roles and Features ➜ Features ➜ Windows Server Update Services ➜ WSUS Tools
147+
148+
2) PowerShell (Windows Server)
149+
Install-WindowsFeature -Name UpdateServices-UI
150+
151+
3) Windows Client (RSAT on Windows 10/11)
152+
DISM /Online /Enable-Feature /FeatureName:Rsat.WSUS.Tools~~~~0.0.1.0 /All
153+
154+
After installing, re-run this script.
155+
"@
156+
157+
Write-Log "WSUS Administration assembly not found in GAC paths or explicit path." -Level ERROR
158+
Show-MessageBox -Message $help -Icon 'Error'
159+
exit 1
160+
99161
# End of script

0 commit comments

Comments
 (0)