Skip to content

Commit eb1cc95

Browse files
Update Deploy-GLPI-Agent-viaGPO.ps1
Signed-off-by: LUIZ HAMILTON ROBERTO DA SILVA <[email protected]>
1 parent af07cf0 commit eb1cc95

1 file changed

Lines changed: 150 additions & 141 deletions

File tree

SysAdmin-Tools/SystemConfiguration-and-Deployment/Deploy-GLPI-Agent-viaGPO.ps1

Lines changed: 150 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,179 +1,188 @@
1-
<#
1+
<#
22
.SYNOPSIS
3-
PowerShell Script for Deploying GLPI Agent via GPO.
3+
Deploy/upgrade GLPI Agent via GPO without blocking startup.
44
55
.DESCRIPTION
6-
This script installs and configures the GLPI Agent on workstations using Group Policy (GPO).
7-
It ensures seamless inventory management and reporting within an enterprise environment.
8-
The script also retrieves the %USERDOMAIN% environment variable and sends it as a TAG to the GLPI server.
6+
- Detects installed GLPI Agent version from registry (and falls back to the EXE file version).
7+
- If the same major/minor version is already installed, it skips installation (idempotent).
8+
- If different/not found, runs MSI with silent parameters and logs to C:\Scripts-LOGS.
9+
- Avoids uninstalling older versions; relies on MSI’s built-in upgrade/replace logic.
10+
- Detects GPO Startup context and does NOT wait on msiexec in that path (prevents boot hang).
911
1012
.AUTHOR
11-
Luiz Hamilton Silva - @brazilianscriptguy
13+
Luiz Hamilton Silva (@brazilianscriptguy) – adapted for GPO-safe, idempotent flow.
1214
1315
.VERSION
14-
Last Updated: February 14, 2025
16+
Last Updated: 2025-09-10
1517
#>
1618

17-
param (
18-
# Path to the GLPI Agent MSI installer (desired version)
19-
[string]$GLPIAgentMSI = "\\headq.scriptguy\netlogon\glpi-agent112-install.msi",
20-
# Directory where logs will be recorded
21-
[string]$GLPILogDir = "C:\Logs-TEMP",
22-
# Expected version after installation
23-
[string]$ExpectedVersion = "1.12"
19+
param(
20+
# Path to the GLPI Agent MSI installer (desired version)
21+
[string]$GLPIAgentMSI = "\\headq.scriptguy\netlogon\glpi-agent115-install.msi",
22+
# Directory where logs will be recorded
23+
[string]$GLPILogDir = "C:\Logs-TEMP",
24+
# Target version string to compare (prefix match, e.g. '1.15')
25+
[string]$ExpectedVersion = "1.15",
26+
# GLPI server URL and TAG to write during MSI install
27+
[string]$ServerUrl = "http://cmdb.headq.scriptguy/front/inventory.php",
28+
[string]$TagOverride = $null
2429
)
2530

26-
# Immediately stop execution in case of an error
27-
$ErrorActionPreference = "Stop"
31+
$ErrorActionPreference = 'Stop'
2832

29-
# Define log file name and path
30-
$scriptName = [System.IO.Path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name)
31-
$logFileName = "${scriptName}.log"
32-
$logPath = Join-Path $GLPILogDir $logFileName
33+
# ------------------------ Logging ------------------------
34+
$scriptName = [IO.Path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name)
35+
$logFileName = "$scriptName.log"
36+
$logPath = Join-Path $GLPILogDir $logFileName
3337

34-
# Get the user’s domain from the environment variable; if not set, use a default value.
35-
$userDomain = $env:USERDOMAIN
36-
if (-not $userDomain) {
37-
$userDomain = "UNKNOWN_DOMAIN"
38-
}
39-
40-
###############################################################################
41-
# FUNCTION: Log-Message
42-
# Logs messages to the log file. In case of an error, also logs to the EventLog.
43-
###############################################################################
4438
function Log-Message {
45-
param (
46-
[Parameter(Mandatory = $true)]
47-
[string]$Message,
48-
[string]$Severity = "INFO"
49-
)
50-
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
51-
$logEntry = "[$Severity] [$timestamp] $Message"
52-
try {
53-
Add-Content -Path $logPath -Value $logEntry -ErrorAction Stop
54-
}
55-
catch {
56-
Write-EventLog -LogName Application -Source "GLPI-Agent-Install" -EntryType Error -EventId 1 -Message "Failed to write to log at $logPath. Error: $_"
57-
}
39+
param(
40+
[Parameter(Mandatory=$true)][string]$Message,
41+
[ValidateSet('INFO','WARNING','ERROR')][string]$Level='INFO'
42+
)
43+
$ts = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
44+
$line = "[$ts] [$Level] $Message"
45+
try { Add-Content -Path $logPath -Value $line -ErrorAction Stop } catch { Write-Host $line }
5846
}
5947

60-
# Ensure the log directory exists
61-
if (-not (Test-Path $GLPILogDir)) {
62-
New-Item -Path $GLPILogDir -ItemType Directory -Force | Out-Null
63-
Log-Message "Log directory $GLPILogDir created."
48+
# Ensure log directory
49+
if (-not (Test-Path -Path $GLPILogDir)) {
50+
try { New-Item -Path $GLPILogDir -ItemType Directory -Force | Out-Null } catch {}
6451
}
6552

66-
###############################################################################
67-
# FUNCTION: Uninstall-GLPIAgent
68-
# Uninstalls the current installation of GLPI Agent using the Registry value.
69-
###############################################################################
70-
function Uninstall-GLPIAgent {
71-
param (
72-
[string]$RegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\GLPI-Agent"
73-
)
74-
Log-Message "Checking for GLPI Agent in the registry..."
75-
try {
76-
$key = Get-ItemProperty -Path $RegistryKey -ErrorAction SilentlyContinue
77-
if ($key) {
78-
$uninstallString = $key.UninstallString
79-
if ($uninstallString) {
80-
Log-Message "Removing installed version of GLPI Agent..."
81-
# Execute the uninstallation command silently
82-
Start-Process -FilePath "cmdbexe" -ArgumentList "/c $uninstallString /quiet /norestart" -Wait -NoNewWindow
83-
Log-Message "GLPI Agent successfully removed."
84-
} else {
85-
Log-Message "Key found, but UninstallString is empty." -Severity "WARNING"
86-
}
87-
} else {
88-
Log-Message "GLPI Agent not found in the registry."
89-
}
90-
}
91-
catch {
92-
Log-Message "Error while uninstalling GLPI Agent: $_" -Severity "WARNING"
93-
}
53+
# -------------------- Context detection --------------------
54+
function Get-IsGpoStartup {
55+
try {
56+
$isSystem = ([Security.Principal.WindowsIdentity]::GetCurrent().User.Value -eq 'S-1-5-18')
57+
$session0 = ([Diagnostics.Process]::GetCurrentProcess().SessionId -eq 0)
58+
$pp = Get-CimInstance Win32_Process -Filter "ProcessId=$pid"
59+
$parent = if ($pp.ParentProcessId) { Get-Process -Id $pp.ParentProcessId -ErrorAction SilentlyContinue }
60+
$pname = ($parent.Name -replace '\.exe$','').ToLower()
61+
$gpParents = @('gpscript','gpupdate','winlogon','services')
62+
return ($isSystem -and $session0 -and $gpParents -contains $pname)
63+
} catch { return $false }
9464
}
9565

96-
###############################################################################
97-
# FUNCTION: Install-GLPIAgent
98-
# Installs the GLPI Agent via MSI.
99-
###############################################################################
100-
function Install-GLPIAgent {
101-
param (
102-
[string]$InstallerPath
103-
)
104-
Log-Message "Starting installation of GLPI Agent version $ExpectedVersion..."
105-
# Define installation parameters: /quiet, RUNNOW=1, SERVER, and TAG
106-
$installArgs = "/quiet RUNNOW=1 SERVER='http://cmdb.headq.scriptguy/front/inventory.php' TAG='$userDomain'"
107-
try {
108-
Start-Process -FilePath "msiexec.exe" -ArgumentList "/i `"$InstallerPath`" $installArgs" -Wait -NoNewWindow -ErrorAction Stop
109-
Log-Message "GLPI Agent version $ExpectedVersion installed successfully."
110-
}
111-
catch {
112-
Log-Message "Error while installing GLPI Agent: $_" -Severity "WARNING"
113-
exit 1
114-
}
115-
}
66+
$IsGpoStartup = Get-IsGpoStartup
67+
Log-Message "GPO Startup context: $IsGpoStartup"
11668

117-
###############################################################################
118-
# FUNCTION: Get-GLPIAgentPath
119-
# Returns the path of the GLPI Agent executable, checking known locations.
120-
###############################################################################
69+
# -------------------- Utilities --------------------
12170
function Get-GLPIAgentPath {
122-
$possiblePaths = @(
123-
"C:\Program Files\GLPI-Agent\glpi-agent.exe",
124-
"C:\Program Files (x86)\GLPI-Agent\glpi-agent.exe",
125-
"C:\Program Files\GLPI-Agent\perl\bin\glpi-agent.exe"
126-
)
127-
128-
foreach ($path in $possiblePaths) {
129-
if (Test-Path $path) {
130-
return $path
71+
$candidates = @(
72+
"C:\Program Files\GLPI-Agent\glpi-agent.exe",
73+
"C:\Program Files (x86)\GLPI-Agent\glpi-agent.exe",
74+
"C:\Program Files\GLPI-Agent\perl\bin\glpi-agent.exe"
75+
)
76+
foreach ($p in $candidates) { if (Test-Path $p) { return $p } }
77+
return $null
78+
}
79+
80+
function Get-InstalledGLPIInfo {
81+
$roots = @(
82+
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall",
83+
"HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
84+
)
85+
foreach ($r in $roots) {
86+
Get-ChildItem $r -ErrorAction SilentlyContinue | ForEach-Object {
87+
$it = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
88+
if ($it -and $it.DisplayName -and ($it.DisplayName -like "*GLPI Agent*")) {
89+
[PSCustomObject]@{
90+
DisplayName = $it.DisplayName
91+
DisplayVersion = $it.DisplayVersion
92+
UninstallString = $it.UninstallString
93+
InstallLocation = $it.InstallLocation
94+
RegistryKey = $_.PSChildName
13195
}
96+
}
13297
}
133-
return $null
98+
}
13499
}
135100

136-
###############################################################################
137-
# FUNCTION: Configure-GLPIAgent
138-
# Applies configuration to the GLPI Agent by calling the executable with parameters.
139-
###############################################################################
140-
function Configure-GLPIAgent {
141-
param (
142-
[string]$AgentPath
143-
)
144-
Log-Message "Configuring GLPI Agent for domain: $userDomain..."
145-
$configArgs = "--server=http://cmdb.headq.scriptguy/front/inventory.php --tag='$userDomain' --debug"
146-
try {
147-
Start-Process -FilePath $AgentPath -ArgumentList $configArgs -Wait -NoNewWindow -ErrorAction Stop
148-
Log-Message "GLPI Agent configuration successfully applied."
149-
}
150-
catch {
151-
Log-Message "Error while configuring GLPI Agent: $_" -Severity "WARNING"
152-
exit 1
153-
}
101+
# Resolve domain/TAG
102+
$domainTag = if ($TagOverride) { $TagOverride } elseif ($env:USERDOMAIN) { $env:USERDOMAIN } else {
103+
try { (Get-CimInstance Win32_ComputerSystem).Domain } catch { 'UNKNOWN' }
154104
}
155105

156-
###############################################################################
157-
# MAIN SCRIPT FLOW
158-
###############################################################################
106+
# -------------------- Pre-checks --------------------
107+
if (-not (Test-Path $GLPIAgentMSI)) { Log-Message "MSI not found: $GLPIAgentMSI" 'ERROR'; exit 1 }
159108

160-
# Always perform a clean installation: uninstall any existing version
161-
Uninstall-GLPIAgent
109+
# Installed version?
110+
$installed = Get-InstalledGLPIInfo | Select-Object -First 1
111+
if ($installed) {
112+
Log-Message "Detected installed GLPI Agent: '$($installed.DisplayName)' version '$($installed.DisplayVersion)'."
113+
} else {
114+
# Try fallback by file version
115+
$exe = Get-GLPIAgentPath
116+
if ($exe) {
117+
try {
118+
$fv = (Get-Item $exe).VersionInfo.ProductVersion
119+
if ($fv) {
120+
$installed = [PSCustomObject]@{ DisplayName='GLPI Agent (file)'; DisplayVersion=$fv; UninstallString=$null; InstallLocation=(Split-Path $exe -Parent); RegistryKey='(file)' }
121+
Log-Message "Detected GLPI Agent by executable: '$exe' (file version: $fv)."
122+
}
123+
} catch {}
124+
}
125+
}
162126

163-
# Install the GLPI Agent (even if no previous version exists)
164-
Install-GLPIAgent -InstallerPath $GLPIAgentMSI
127+
# -------------------- Idempotent decision --------------------
128+
$needInstall = $true
129+
if ($installed -and $installed.DisplayVersion) {
130+
if ($installed.DisplayVersion -like "$ExpectedVersion*") {
131+
$needInstall = $false
132+
Log-Message "Same version '$ExpectedVersion' already installed; skipping installation (idempotent)."
133+
} else {
134+
Log-Message "Installed version '$($installed.DisplayVersion)' differs from target '$ExpectedVersion'; will run MSI."
135+
}
136+
} else {
137+
Log-Message "GLPI Agent not found; will run MSI."
138+
}
165139

166-
# Try to locate the installed executable
167-
$glpiAgentPath = Get-GLPIAgentPath
168-
if (-not $glpiAgentPath) {
169-
Log-Message "Error: Could not locate the GLPI Agent executable after installation." -Severity "WARNING"
140+
# -------------------- Install (no uninstall) --------------------
141+
if ($needInstall) {
142+
# Build MSI arguments. We log MSI to a separate file for troubleshooting.
143+
$msiLog = Join-Path $GLPILogDir 'glpi-install.log'
144+
$installArgs = @(
145+
'/i', "`"$GLPIAgentMSI`"",
146+
'/qn', '/norestart', 'REBOOT=ReallySuppress',
147+
'/l*v', "`"$msiLog`"",
148+
"RUNNOW=1",
149+
"SERVER=`"$ServerUrl`"",
150+
"TAG=`"$domainTag`""
151+
) -join ' '
152+
153+
Log-Message "Executing: msiexec.exe $installArgs"
154+
155+
try {
156+
# IMPORTANT: Do not block in GPO Startup. We omit -NoNewWindow to avoid conflicts with -WindowStyle.
157+
$proc = Start-Process -FilePath 'msiexec.exe' -ArgumentList $installArgs `
158+
-WindowStyle Hidden -PassThru -Wait:(!$IsGpoStartup) -ErrorAction Stop
159+
160+
# If we did not wait (GPO Startup), $proc may be $null; log accordingly.
161+
if ($proc) {
162+
Log-Message "msiexec exited with code: $($proc.ExitCode)"
163+
if ($proc.ExitCode -ne 0) { Log-Message "MSI returned non-zero exit code. See $msiLog" 'WARNING' }
164+
} else {
165+
Log-Message "Started msiexec in background (GPO Startup); see $msiLog for progress."
166+
}
167+
}
168+
catch {
169+
Log-Message "Failed to launch msiexec. Error: $_" 'ERROR'
170170
exit 1
171+
}
171172
} else {
172-
Log-Message "GLPI Agent found at: $glpiAgentPath"
173-
# Apply the agent configuration
174-
Configure-GLPIAgent -AgentPath $glpiAgentPath
173+
# Optionally ensure service is running, but do not block.
174+
try {
175+
$svc = Get-Service -ErrorAction SilentlyContinue | Where-Object {
176+
$_.Name -like '*glpi*agent*' -or $_.DisplayName -like '*GLPI*Agent*'
177+
} | Select-Object -First 1
178+
if ($svc -and $svc.Status -ne 'Running') {
179+
Start-Service -Name $svc.Name -ErrorAction SilentlyContinue
180+
Log-Message "Started service '$($svc.Name)'."
181+
}
182+
} catch {}
175183
}
176184

185+
# -------------------- End --------------------
177186
Log-Message "End of script."
178187
exit 0
179188

0 commit comments

Comments
 (0)