1606 lines
59 KiB
PowerShell
1606 lines
59 KiB
PowerShell
# Powershell
|
||
|
||
# Nom: Info PC
|
||
# Description: Récupère les informations du PC
|
||
# Version: 0.5.0
|
||
# Categorie: Tools
|
||
# Changelog:
|
||
# - Ajout de la section Batterie complète
|
||
# - Amélioration de la gestion des erreurs
|
||
# - Configuration externalisée (SMTP)
|
||
# - Utilisation cohérente de Get-CimInstance
|
||
# - Ajout d'informations système supplémentaires
|
||
# - Meilleure détection du type de RAM
|
||
# - Ajout des informations TPM
|
||
# - Optimisation des performances
|
||
|
||
#Requires -Version 5.1
|
||
|
||
# ============================================================================
|
||
# CONFIGURATION
|
||
# ============================================================================
|
||
|
||
$Script:Config = @{
|
||
# Configuration SMTP - À externaliser dans un fichier config.json
|
||
SMTP = @{
|
||
Server = "ssl0.ovh.net"
|
||
Port = 587
|
||
From = "system@microinfoservice.fr"
|
||
To = "system@microinfoservice.fr"
|
||
Username = "system@microinfoservice.fr"
|
||
# ATTENTION: Ne pas laisser le mot de passe en clair en production!
|
||
# Utiliser: Get-Credential | Export-Clixml -Path "cred.xml"
|
||
# Puis: Import-Clixml -Path "cred.xml"
|
||
Password = $null # Sera demandé ou chargé depuis un fichier sécurisé
|
||
}
|
||
|
||
# Options du script
|
||
Options = @{
|
||
SendEmail = $true
|
||
OpenReportOnEnd = $true
|
||
IncludeWifiPasswords = $false # Attention: nécessite droits admin
|
||
}
|
||
}
|
||
|
||
# ============================================================================
|
||
# FONCTIONS UTILITAIRES
|
||
# ============================================================================
|
||
|
||
function Write-Log {
|
||
param(
|
||
[string]$Message,
|
||
[ValidateSet('Info', 'Warning', 'Error', 'Success')]
|
||
[string]$Level = 'Info'
|
||
)
|
||
|
||
$colors = @{
|
||
'Info' = 'White'
|
||
'Warning' = 'Yellow'
|
||
'Error' = 'Red'
|
||
'Success' = 'Green'
|
||
}
|
||
|
||
$timestamp = Get-Date -Format "HH:mm:ss"
|
||
Write-Host "[$timestamp] " -NoNewline -ForegroundColor Gray
|
||
Write-Host $Message -ForegroundColor $colors[$Level]
|
||
}
|
||
|
||
function Format-Size {
|
||
param([int64]$Size)
|
||
|
||
if ($Size -lt 0) { return "N/A" }
|
||
if ($Size -gt 1TB) { return "{0:N2} To" -f ($Size / 1TB) }
|
||
if ($Size -gt 1GB) { return "{0:N2} Go" -f ($Size / 1GB) }
|
||
if ($Size -gt 1MB) { return "{0:N2} Mo" -f ($Size / 1MB) }
|
||
if ($Size -gt 1KB) { return "{0:N2} Ko" -f ($Size / 1KB) }
|
||
return "$Size octets"
|
||
}
|
||
|
||
function Get-FormattedInstallDate {
|
||
param([string]$InstallDate)
|
||
|
||
if ([string]::IsNullOrEmpty($InstallDate)) { return 'N/A' }
|
||
|
||
try {
|
||
return [DateTime]::ParseExact($InstallDate, 'yyyyMMdd', $null).ToString("dd/MM/yyyy")
|
||
}
|
||
catch {
|
||
return 'N/A'
|
||
}
|
||
}
|
||
|
||
function Get-SafeValue {
|
||
param(
|
||
$Value,
|
||
[string]$Default = "N/A"
|
||
)
|
||
|
||
if ($null -eq $Value -or [string]::IsNullOrWhiteSpace($Value.ToString())) {
|
||
return $Default
|
||
}
|
||
return $Value
|
||
}
|
||
|
||
function Get-RAMTypeName {
|
||
param([int]$TypeCode)
|
||
|
||
$ramTypes = @{
|
||
0 = "Unknown"
|
||
1 = "Other"
|
||
2 = "DRAM"
|
||
3 = "Synchronous DRAM"
|
||
4 = "Cache DRAM"
|
||
5 = "EDO"
|
||
6 = "EDRAM"
|
||
7 = "VRAM"
|
||
8 = "SRAM"
|
||
9 = "RAM"
|
||
10 = "ROM"
|
||
11 = "Flash"
|
||
12 = "EEPROM"
|
||
13 = "FEPROM"
|
||
14 = "EPROM"
|
||
15 = "CDRAM"
|
||
16 = "3DRAM"
|
||
17 = "SDRAM"
|
||
18 = "SGRAM"
|
||
19 = "RDRAM"
|
||
20 = "DDR"
|
||
21 = "DDR2"
|
||
22 = "DDR2 FB-DIMM"
|
||
24 = "DDR3"
|
||
25 = "FBD2"
|
||
26 = "DDR4"
|
||
27 = "LPDDR"
|
||
28 = "LPDDR2"
|
||
29 = "LPDDR3"
|
||
30 = "LPDDR4"
|
||
34 = "DDR5"
|
||
35 = "LPDDR5"
|
||
}
|
||
|
||
if ($ramTypes.ContainsKey($TypeCode)) {
|
||
return $ramTypes[$TypeCode]
|
||
}
|
||
return "Unknown ($TypeCode)"
|
||
}
|
||
|
||
function Test-IsAdmin {
|
||
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
|
||
return $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||
}
|
||
|
||
# ============================================================================
|
||
# FONCTIONS DE COLLECTE D'INFORMATIONS
|
||
# ============================================================================
|
||
|
||
function Get-SystemInfo {
|
||
Write-Log "Collecte des informations système..." -Level Info
|
||
|
||
try {
|
||
$os = Get-CimInstance Win32_OperatingSystem
|
||
$cs = Get-CimInstance Win32_ComputerSystem
|
||
$bios = Get-CimInstance Win32_BIOS
|
||
$mb = Get-CimInstance Win32_BaseBoard
|
||
$cpu = Get-CimInstance Win32_Processor | Select-Object -First 1
|
||
|
||
# Correction pour Windows 11
|
||
$buildNumber = [int](Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion').CurrentBuildNumber
|
||
$windowsVersion = $os.Caption
|
||
if ($buildNumber -ge 22000) {
|
||
$windowsVersion = $windowsVersion -replace "Windows 10", "Windows 11"
|
||
}
|
||
|
||
# DisplayVersion (ex: 23H2)
|
||
$displayVersion = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction SilentlyContinue).DisplayVersion
|
||
if ($displayVersion) {
|
||
$windowsVersion += " ($displayVersion)"
|
||
}
|
||
|
||
# Secure Boot
|
||
try {
|
||
$secureBootStatus = Confirm-SecureBootUEFI -ErrorAction Stop
|
||
$secureBootText = if ($secureBootStatus) { "Activé" } else { "Désactivé" }
|
||
}
|
||
catch {
|
||
$secureBootText = "Non disponible (BIOS legacy)"
|
||
}
|
||
|
||
# TPM
|
||
try {
|
||
$tpm = Get-CimInstance -Namespace "root\cimv2\Security\MicrosoftTpm" -ClassName Win32_Tpm -ErrorAction Stop
|
||
$tpmInfo = @{
|
||
Present = $true
|
||
Version = $tpm.SpecVersion
|
||
Enabled = $tpm.IsEnabled_InitialValue
|
||
Activated = $tpm.IsActivated_InitialValue
|
||
}
|
||
}
|
||
catch {
|
||
$tpmInfo = @{
|
||
Present = $false
|
||
Version = "N/A"
|
||
Enabled = $false
|
||
Activated = $false
|
||
}
|
||
}
|
||
|
||
# Uptime
|
||
$uptime = (Get-Date) - $os.LastBootUpTime
|
||
$uptimeString = "{0}j {1}h {2}m" -f $uptime.Days, $uptime.Hours, $uptime.Minutes
|
||
|
||
return @{
|
||
ComputerName = $env:COMPUTERNAME
|
||
WindowsVersion = $windowsVersion
|
||
BuildNumber = $buildNumber
|
||
Architecture = $os.OSArchitecture
|
||
InstallDate = $os.InstallDate.ToString("dd/MM/yyyy HH:mm")
|
||
LastBoot = $os.LastBootUpTime.ToString("dd/MM/yyyy HH:mm")
|
||
Uptime = $uptimeString
|
||
SecureBoot = $secureBootText
|
||
TPM = $tpmInfo
|
||
Manufacturer = Get-SafeValue $cs.Manufacturer
|
||
Model = Get-SafeValue $cs.Model
|
||
Motherboard = Get-SafeValue $mb.Product
|
||
MotherboardMfr = Get-SafeValue $mb.Manufacturer
|
||
BiosVersion = Get-SafeValue $bios.SMBIOSBIOSVersion
|
||
BiosManufacturer = Get-SafeValue $bios.Manufacturer
|
||
BiosName = Get-SafeValue $bios.Name
|
||
BiosDate = if ($bios.ReleaseDate) { $bios.ReleaseDate.ToString("dd/MM/yyyy") } else { "N/A" }
|
||
CPU = Get-SafeValue $cpu.Name
|
||
CPUCores = $cpu.NumberOfCores
|
||
CPUThreads = $cpu.NumberOfLogicalProcessors
|
||
CPUSocket = Get-SafeValue $cpu.SocketDesignation
|
||
CPUMaxSpeed = "{0} MHz" -f $cpu.MaxClockSpeed
|
||
}
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des informations système: $_" -Level Error
|
||
return $null
|
||
}
|
||
}
|
||
|
||
function Get-MemoryInfo {
|
||
Write-Log "Collecte des informations mémoire..." -Level Info
|
||
|
||
try {
|
||
$memoryArray = Get-CimInstance Win32_PhysicalMemoryArray
|
||
$memoryModules = Get-CimInstance Win32_PhysicalMemory
|
||
|
||
$totalSlots = ($memoryArray | Measure-Object -Property MemoryDevices -Sum).Sum
|
||
$usedSlots = ($memoryModules | Measure-Object).Count
|
||
$totalCapacity = ($memoryModules | Measure-Object -Property Capacity -Sum).Sum
|
||
|
||
$modules = @()
|
||
foreach ($module in $memoryModules) {
|
||
$modules += @{
|
||
Manufacturer = Get-SafeValue $module.Manufacturer
|
||
PartNumber = Get-SafeValue ($module.PartNumber -replace '\s+', ' ').Trim()
|
||
Capacity = Format-Size $module.Capacity
|
||
Speed = "{0} MHz" -f $module.ConfiguredClockSpeed
|
||
Type = Get-RAMTypeName $module.SMBIOSMemoryType
|
||
DeviceLocator = Get-SafeValue $module.DeviceLocator
|
||
FormFactor = switch ($module.FormFactor) {
|
||
8 { "DIMM" }
|
||
12 { "SO-DIMM" }
|
||
default { "Autre" }
|
||
}
|
||
}
|
||
}
|
||
|
||
return @{
|
||
TotalCapacity = Format-Size $totalCapacity
|
||
TotalSlots = $totalSlots
|
||
UsedSlots = $usedSlots
|
||
Modules = $modules
|
||
}
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des informations mémoire: $_" -Level Error
|
||
return $null
|
||
}
|
||
}
|
||
|
||
function Get-GPUInfo {
|
||
Write-Log "Collecte des informations GPU..." -Level Info
|
||
|
||
try {
|
||
$gpus = Get-CimInstance Win32_VideoController
|
||
$gpuList = @()
|
||
|
||
foreach ($gpu in $gpus) {
|
||
$gpuList += @{
|
||
Name = Get-SafeValue $gpu.Name
|
||
Processor = Get-SafeValue $gpu.VideoProcessor
|
||
RAM = if ($gpu.AdapterRAM -gt 0) { Format-Size $gpu.AdapterRAM } else { "N/A" }
|
||
Driver = Get-SafeValue $gpu.DriverVersion
|
||
Resolution = "{0}x{1}" -f $gpu.CurrentHorizontalResolution, $gpu.CurrentVerticalResolution
|
||
RefreshRate = "{0} Hz" -f $gpu.CurrentRefreshRate
|
||
}
|
||
}
|
||
|
||
return $gpuList
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des informations GPU: $_" -Level Error
|
||
return @()
|
||
}
|
||
}
|
||
|
||
function Get-StorageInfo {
|
||
Write-Log "Collecte des informations stockage..." -Level Info
|
||
|
||
try {
|
||
$disks = Get-PhysicalDisk -ErrorAction SilentlyContinue
|
||
$volumes = Get-Volume -ErrorAction SilentlyContinue | Where-Object { $_.DriveLetter }
|
||
$bitlockerVolumes = @{}
|
||
|
||
try {
|
||
$blVolumes = Get-BitLockerVolume -ErrorAction SilentlyContinue
|
||
foreach ($bl in $blVolumes) {
|
||
$bitlockerVolumes[$bl.MountPoint.TrimEnd('\')] = $bl
|
||
}
|
||
}
|
||
catch {
|
||
Write-Log "BitLocker non disponible ou accès refusé" -Level Warning
|
||
}
|
||
|
||
$diskList = @()
|
||
foreach ($disk in $disks) {
|
||
$diskList += @{
|
||
Model = Get-SafeValue $disk.FriendlyName
|
||
Type = Get-SafeValue $disk.MediaType "Unknown"
|
||
Size = Format-Size $disk.Size
|
||
Health = Get-SafeValue $disk.HealthStatus
|
||
BusType = Get-SafeValue $disk.BusType
|
||
Serial = Get-SafeValue $disk.SerialNumber
|
||
}
|
||
}
|
||
|
||
$volumeList = @()
|
||
foreach ($vol in $volumes) {
|
||
$driveLetter = "$($vol.DriveLetter):"
|
||
$bl = $bitlockerVolumes[$driveLetter]
|
||
|
||
$usedPercent = 0
|
||
if ($vol.Size -gt 0) {
|
||
$usedPercent = [math]::Round((($vol.Size - $vol.SizeRemaining) / $vol.Size) * 100)
|
||
}
|
||
|
||
$volumeList += @{
|
||
Letter = $driveLetter
|
||
Label = Get-SafeValue $vol.FileSystemLabel "Sans nom"
|
||
FileSystem = Get-SafeValue $vol.FileSystem
|
||
Size = Format-Size $vol.Size
|
||
Free = Format-Size $vol.SizeRemaining
|
||
Used = Format-Size ($vol.Size - $vol.SizeRemaining)
|
||
UsedPercent = $usedPercent
|
||
BitLockerStatus = if ($bl) { $bl.ProtectionStatus.ToString() } else { "Non protégé" }
|
||
BitLockerMethod = if ($bl -and $bl.EncryptionMethod) { $bl.EncryptionMethod.ToString() } else { "N/A" }
|
||
}
|
||
}
|
||
|
||
return @{
|
||
Disks = $diskList
|
||
Volumes = $volumeList
|
||
}
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des informations stockage: $_" -Level Error
|
||
return @{ Disks = @(); Volumes = @() }
|
||
}
|
||
}
|
||
|
||
function Get-NetworkInfo {
|
||
Write-Log "Collecte des informations réseau..." -Level Info
|
||
|
||
try {
|
||
$cs = Get-CimInstance Win32_ComputerSystem
|
||
$adapters = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' -or $_.PhysicalMediaType }
|
||
$ipConfigs = Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -ne 'Loopback Pseudo-Interface 1' }
|
||
$dnsServers = (Get-DnsClientServerAddress -AddressFamily IPv4 | Select-Object -ExpandProperty ServerAddresses) -join ', '
|
||
$gateway = (Get-NetRoute -AddressFamily IPv4 | Where-Object { $_.DestinationPrefix -eq '0.0.0.0/0' } | Select-Object -First 1).NextHop
|
||
$networkDrives = Get-CimInstance Win32_NetworkConnection | Where-Object { $_.LocalName }
|
||
|
||
# Domaine/Workgroup
|
||
$domainInfo = if ($cs.PartOfDomain) {
|
||
"Domaine: $($cs.Domain)"
|
||
} else {
|
||
"Groupe de travail: $($cs.Workgroup)"
|
||
}
|
||
|
||
# Adaptateurs
|
||
$adapterList = @()
|
||
foreach ($adapter in $adapters) {
|
||
$ipConfig = $ipConfigs | Where-Object { $_.InterfaceAlias -eq $adapter.Name }
|
||
|
||
$adapterList += @{
|
||
Name = $adapter.Name
|
||
Description = $adapter.InterfaceDescription
|
||
Status = $adapter.Status
|
||
Speed = if ($adapter.LinkSpeed) { $adapter.LinkSpeed } else { "N/A" }
|
||
MAC = $adapter.MacAddress
|
||
IPAddress = if ($ipConfig) { $ipConfig.IPAddress -join ', ' } else { "N/A" }
|
||
Type = Get-SafeValue $adapter.MediaType
|
||
}
|
||
}
|
||
|
||
# Lecteurs réseau
|
||
$drivesList = @()
|
||
foreach ($drive in $networkDrives) {
|
||
$drivesList += @{
|
||
Letter = $drive.LocalName
|
||
Path = $drive.RemoteName
|
||
}
|
||
}
|
||
|
||
# Profils WiFi
|
||
$wifiProfiles = @()
|
||
try {
|
||
$profilesOutput = netsh wlan show profiles 2>$null
|
||
if ($profilesOutput) {
|
||
$profileNames = $profilesOutput | Select-String -Pattern ':\s*(.+)$' | ForEach-Object {
|
||
$_.ToString().Split(':')[-1].Trim()
|
||
} | Where-Object { $_ }
|
||
|
||
foreach ($profileName in $profileNames) {
|
||
if ([string]::IsNullOrWhiteSpace($profileName)) { continue }
|
||
|
||
$profileDetails = netsh wlan show profile name="$profileName" 2>$null | Out-String
|
||
|
||
$authType = "N/A"
|
||
if ($profileDetails -match "(Type d'authentification|Authentication)\s*:\s*(.*)") {
|
||
$authType = $matches[2].Trim()
|
||
}
|
||
|
||
$wifiProfiles += @{
|
||
SSID = $profileName
|
||
Authentication = $authType
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la récupération des profils WiFi: $_" -Level Warning
|
||
}
|
||
|
||
# Fichier hosts
|
||
$hostsContent = ""
|
||
try {
|
||
$hostsPath = "$env:SystemRoot\System32\drivers\etc\hosts"
|
||
$hostsContent = Get-Content -Path $hostsPath -Raw -ErrorAction Stop
|
||
}
|
||
catch {
|
||
$hostsContent = "Impossible de lire le fichier hosts"
|
||
}
|
||
|
||
return @{
|
||
DomainInfo = $domainInfo
|
||
Adapters = $adapterList
|
||
DNS = $dnsServers
|
||
Gateway = Get-SafeValue $gateway
|
||
NetworkDrives = $drivesList
|
||
WifiProfiles = $wifiProfiles
|
||
HostsFile = $hostsContent
|
||
}
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des informations réseau: $_" -Level Error
|
||
return $null
|
||
}
|
||
}
|
||
|
||
function Get-UserInfo {
|
||
Write-Log "Collecte des informations utilisateurs..." -Level Info
|
||
|
||
try {
|
||
$users = Get-CimInstance Win32_UserAccount | Where-Object { $_.LocalAccount -eq $true }
|
||
|
||
$userList = @()
|
||
foreach ($user in $users) {
|
||
$userList += @{
|
||
Name = $user.Name
|
||
FullName = Get-SafeValue $user.FullName
|
||
Description = Get-SafeValue $user.Description
|
||
Status = if ($user.Disabled) { "Désactivé" } else { "Actif" }
|
||
SID = $user.SID
|
||
}
|
||
}
|
||
|
||
return $userList
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des informations utilisateurs: $_" -Level Error
|
||
return @()
|
||
}
|
||
}
|
||
|
||
function Get-SoftwareInfo {
|
||
Write-Log "Collecte des logiciels installés..." -Level Info
|
||
|
||
try {
|
||
$software = @()
|
||
|
||
$regPaths = @(
|
||
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
||
"HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
|
||
)
|
||
|
||
foreach ($path in $regPaths) {
|
||
$items = Get-ItemProperty $path -ErrorAction SilentlyContinue |
|
||
Where-Object { $_.DisplayName } |
|
||
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
|
||
|
||
$software += $items
|
||
}
|
||
|
||
$software = $software | Sort-Object -Property DisplayName -Unique | ForEach-Object {
|
||
@{
|
||
Name = $_.DisplayName
|
||
Version = Get-SafeValue $_.DisplayVersion
|
||
Publisher = Get-SafeValue $_.Publisher
|
||
InstallDate = Get-FormattedInstallDate $_.InstallDate
|
||
}
|
||
}
|
||
|
||
return $software
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des logiciels: $_" -Level Error
|
||
return @()
|
||
}
|
||
}
|
||
|
||
function Get-StartupInfo {
|
||
Write-Log "Collecte des programmes de démarrage..." -Level Info
|
||
|
||
try {
|
||
$startupItems = @()
|
||
|
||
# WMI Startup Commands
|
||
$wmiItems = Get-CimInstance Win32_StartupCommand -ErrorAction SilentlyContinue
|
||
foreach ($item in $wmiItems) {
|
||
$startupItems += @{
|
||
Name = Get-SafeValue $item.Name
|
||
Command = Get-SafeValue $item.Command
|
||
Location = Get-SafeValue $item.Location
|
||
User = if ([string]::IsNullOrEmpty($item.User)) { "Tous" } else { $item.User }
|
||
Status = "Activé"
|
||
}
|
||
}
|
||
|
||
# Registry Run keys
|
||
$runKeys = @(
|
||
@{ Path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; User = "Tous" },
|
||
@{ Path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; User = $env:USERNAME }
|
||
)
|
||
|
||
foreach ($key in $runKeys) {
|
||
if (Test-Path $key.Path) {
|
||
$items = Get-ItemProperty -Path $key.Path -ErrorAction SilentlyContinue
|
||
foreach ($prop in $items.PSObject.Properties) {
|
||
if ($prop.Name -notin @("PSPath", "PSParentPath", "PSChildName", "PSDrive", "PSProvider")) {
|
||
$startupItems += @{
|
||
Name = $prop.Name
|
||
Command = $prop.Value
|
||
Location = $key.Path -replace 'HKLM:|HKCU:', ''
|
||
User = $key.User
|
||
Status = "Activé"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
# Remove duplicates based on Name
|
||
$uniqueItems = @{}
|
||
foreach ($item in $startupItems) {
|
||
if (-not $uniqueItems.ContainsKey($item.Name)) {
|
||
$uniqueItems[$item.Name] = $item
|
||
}
|
||
}
|
||
|
||
return $uniqueItems.Values
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des programmes de démarrage: $_" -Level Error
|
||
return @()
|
||
}
|
||
}
|
||
|
||
function Get-PrinterInfo {
|
||
Write-Log "Collecte des informations imprimantes..." -Level Info
|
||
|
||
try {
|
||
$printers = Get-CimInstance Win32_Printer
|
||
|
||
$printerList = @()
|
||
foreach ($printer in $printers) {
|
||
$driver = Get-PrinterDriver -Name $printer.DriverName -ErrorAction SilentlyContinue
|
||
|
||
$printerList += @{
|
||
Name = $printer.Name
|
||
Status = switch ($printer.PrinterStatus) {
|
||
1 { "Other" }
|
||
2 { "Unknown" }
|
||
3 { "Idle" }
|
||
4 { "Printing" }
|
||
5 { "Warmup" }
|
||
6 { "Stopped Printing" }
|
||
7 { "Offline" }
|
||
default { $printer.PrinterStatus }
|
||
}
|
||
Port = Get-SafeValue $printer.PortName
|
||
Driver = Get-SafeValue $printer.DriverName
|
||
Manufacturer = if ($driver) { Get-SafeValue $driver.Manufacturer } else { "N/A" }
|
||
Default = $printer.Default
|
||
Shared = $printer.Shared
|
||
}
|
||
}
|
||
|
||
return $printerList
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des informations imprimantes: $_" -Level Error
|
||
return @()
|
||
}
|
||
}
|
||
|
||
function Get-MailInfo {
|
||
Write-Log "Collecte des informations mail..." -Level Info
|
||
|
||
$result = @{
|
||
OutlookAccounts = @()
|
||
OutlookFiles = @()
|
||
ThunderbirdProfiles = @()
|
||
}
|
||
|
||
# Fichiers Outlook (PST/OST)
|
||
$searchPaths = @(
|
||
"$env:LOCALAPPDATA\Microsoft\Outlook",
|
||
[System.IO.Path]::Combine($env:USERPROFILE, 'Documents'),
|
||
[System.IO.Path]::Combine($env:USERPROFILE, 'Documents', 'Outlook Files')
|
||
)
|
||
|
||
foreach ($searchPath in $searchPaths) {
|
||
if (Test-Path $searchPath) {
|
||
try {
|
||
$files = Get-ChildItem -Path $searchPath -Include "*.pst", "*.ost" -Recurse -ErrorAction SilentlyContinue
|
||
foreach ($file in $files) {
|
||
$result.OutlookFiles += @{
|
||
Name = $file.Name
|
||
Path = $file.FullName
|
||
Size = Format-Size $file.Length
|
||
Type = $file.Extension.ToUpper().TrimStart('.')
|
||
}
|
||
}
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la recherche des fichiers Outlook dans $searchPath" -Level Warning
|
||
}
|
||
}
|
||
}
|
||
|
||
# Profils Thunderbird
|
||
$thunderbirdPath = "$env:APPDATA\Thunderbird\Profiles"
|
||
if (Test-Path $thunderbirdPath) {
|
||
try {
|
||
$profiles = Get-ChildItem -Path $thunderbirdPath -Directory -ErrorAction SilentlyContinue
|
||
foreach ($profile in $profiles) {
|
||
$size = (Get-ChildItem -Path $profile.FullName -Recurse -File -ErrorAction SilentlyContinue |
|
||
Measure-Object -Property Length -Sum).Sum
|
||
|
||
$result.ThunderbirdProfiles += @{
|
||
Name = $profile.Name
|
||
Path = $profile.FullName
|
||
Size = Format-Size $size
|
||
}
|
||
}
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la recherche des profils Thunderbird" -Level Warning
|
||
}
|
||
}
|
||
|
||
# Comptes Outlook (via COM)
|
||
try {
|
||
$outlook = New-Object -ComObject Outlook.Application -ErrorAction Stop
|
||
$namespace = $outlook.GetNamespace("MAPI")
|
||
|
||
foreach ($account in $outlook.Session.Accounts) {
|
||
$accountType = "Inconnu"
|
||
$deliveryStore = $account.DeliveryStore.FilePath
|
||
|
||
if ($deliveryStore -like "*.ost") {
|
||
$accountType = "Exchange/Office 365"
|
||
}
|
||
elseif ($deliveryStore -like "*.pst") {
|
||
$accountType = switch ($account.AccountType) {
|
||
1 { "IMAP" }
|
||
2 { "POP3" }
|
||
default { "POP3/IMAP" }
|
||
}
|
||
}
|
||
|
||
$result.OutlookAccounts += @{
|
||
Name = $account.DisplayName
|
||
Email = $account.SmtpAddress
|
||
Type = $accountType
|
||
Store = $deliveryStore
|
||
}
|
||
}
|
||
|
||
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($namespace) | Out-Null
|
||
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($outlook) | Out-Null
|
||
[System.GC]::Collect()
|
||
[System.GC]::WaitForPendingFinalizers()
|
||
}
|
||
catch {
|
||
Write-Log "Outlook non installé ou non accessible" -Level Warning
|
||
}
|
||
|
||
return $result
|
||
}
|
||
|
||
function Get-BatteryInfo {
|
||
param([bool]$IncludeBatteryTest)
|
||
|
||
if (-not $IncludeBatteryTest) {
|
||
return @{
|
||
Available = $false
|
||
Message = "Test de batterie ignoré (PC de bureau)"
|
||
}
|
||
}
|
||
|
||
Write-Log "Collecte des informations batterie..." -Level Info
|
||
|
||
try {
|
||
$battery = Get-CimInstance Win32_Battery -ErrorAction SilentlyContinue
|
||
|
||
if (-not $battery) {
|
||
return @{
|
||
Available = $false
|
||
Message = "Aucune batterie détectée"
|
||
}
|
||
}
|
||
|
||
# Générer le rapport batterie Windows
|
||
$reportPath = [System.IO.Path]::Combine($script:FolderPath, 'battery_report.html')
|
||
|
||
try {
|
||
$null = powercfg /batteryreport /output $reportPath 2>&1
|
||
$reportGenerated = Test-Path $reportPath
|
||
}
|
||
catch {
|
||
$reportGenerated = $false
|
||
}
|
||
|
||
# Status de la batterie
|
||
$batteryStatus = switch ($battery.BatteryStatus) {
|
||
1 { "Décharge" }
|
||
2 { "Secteur (non en charge)" }
|
||
3 { "Chargement" }
|
||
4 { "Charge faible" }
|
||
5 { "Charge critique" }
|
||
6 { "En charge" }
|
||
7 { "En charge et haute" }
|
||
8 { "En charge et faible" }
|
||
9 { "En charge et critique" }
|
||
10 { "Non défini" }
|
||
11 { "Partiellement chargée" }
|
||
default { "Inconnu" }
|
||
}
|
||
|
||
# Santé estimée
|
||
$designCapacity = $battery.DesignCapacity
|
||
$fullChargeCapacity = $battery.FullChargeCapacity
|
||
$healthPercent = 100
|
||
|
||
if ($designCapacity -gt 0 -and $fullChargeCapacity -gt 0) {
|
||
$healthPercent = [math]::Round(($fullChargeCapacity / $designCapacity) * 100)
|
||
}
|
||
|
||
$healthStatus = if ($healthPercent -ge 80) { "Bonne" }
|
||
elseif ($healthPercent -ge 50) { "Moyenne" }
|
||
else { "Faible" }
|
||
|
||
return @{
|
||
Available = $true
|
||
ChargeLevel = "$($battery.EstimatedChargeRemaining)%"
|
||
Status = $batteryStatus
|
||
DesignCapacity = if ($designCapacity) { "$designCapacity mWh" } else { "N/A" }
|
||
FullChargeCapacity = if ($fullChargeCapacity) { "$fullChargeCapacity mWh" } else { "N/A" }
|
||
HealthPercent = $healthPercent
|
||
HealthStatus = $healthStatus
|
||
DeviceID = Get-SafeValue $battery.DeviceID
|
||
ReportGenerated = $reportGenerated
|
||
ReportPath = if ($reportGenerated) { $reportPath } else { $null }
|
||
}
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de la collecte des informations batterie: $_" -Level Error
|
||
return @{
|
||
Available = $false
|
||
Message = "Erreur: $_"
|
||
}
|
||
}
|
||
}
|
||
|
||
# ============================================================================
|
||
# GÉNÉRATION HTML
|
||
# ============================================================================
|
||
|
||
function New-HTMLReport {
|
||
param(
|
||
[hashtable]$SystemInfo,
|
||
[hashtable]$MemoryInfo,
|
||
[array]$GPUInfo,
|
||
[hashtable]$StorageInfo,
|
||
[hashtable]$NetworkInfo,
|
||
[array]$UserInfo,
|
||
[array]$SoftwareInfo,
|
||
[array]$StartupInfo,
|
||
[array]$PrinterInfo,
|
||
[hashtable]$MailInfo,
|
||
[hashtable]$BatteryInfo
|
||
)
|
||
|
||
$htmlTemplate = @"
|
||
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Info PC - $($SystemInfo.ComputerName)</title>
|
||
<style>
|
||
* { box-sizing: border-box; }
|
||
|
||
body {
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
margin: 0;
|
||
padding: 0;
|
||
background-color: #f5f5f5;
|
||
color: #333;
|
||
}
|
||
|
||
.header {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 20px;
|
||
text-align: center;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 100;
|
||
}
|
||
|
||
.header h1 { margin: 0 0 5px 0; }
|
||
.header .subtitle { opacity: 0.9; font-size: 0.9em; }
|
||
|
||
.tab-container {
|
||
background: white;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||
position: sticky;
|
||
top: 70px;
|
||
z-index: 99;
|
||
overflow-x: auto;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.tab {
|
||
display: inline-flex;
|
||
padding: 0 10px;
|
||
}
|
||
|
||
.tab button {
|
||
background: transparent;
|
||
border: none;
|
||
padding: 15px 20px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
color: #666;
|
||
transition: all 0.3s;
|
||
border-bottom: 3px solid transparent;
|
||
}
|
||
|
||
.tab button:hover { color: #667eea; }
|
||
.tab button.active {
|
||
color: #667eea;
|
||
border-bottom-color: #667eea;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.tabcontent {
|
||
display: none;
|
||
padding: 20px;
|
||
max-width: 1400px;
|
||
margin: 0 auto;
|
||
animation: fadeIn 0.3s;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; transform: translateY(10px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
.info-block {
|
||
background: white;
|
||
border-radius: 10px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 1.1em;
|
||
font-weight: 600;
|
||
color: #444;
|
||
margin: 0 0 15px 0;
|
||
padding-bottom: 10px;
|
||
border-bottom: 2px solid #667eea;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.section-title::before {
|
||
content: '';
|
||
width: 4px;
|
||
height: 20px;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.info-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
}
|
||
|
||
.info-table th, .info-table td {
|
||
padding: 12px;
|
||
text-align: left;
|
||
border-bottom: 1px solid #eee;
|
||
}
|
||
|
||
.info-table th {
|
||
background: #f8f9fa;
|
||
font-weight: 600;
|
||
color: #555;
|
||
}
|
||
|
||
.info-table tr:hover { background: #f8f9fa; }
|
||
|
||
.health-ok { color: #28a745; font-weight: 600; }
|
||
.health-warning { color: #ffc107; font-weight: 600; }
|
||
.health-error { color: #dc3545; font-weight: 600; }
|
||
|
||
.progress-bar {
|
||
background: #e9ecef;
|
||
border-radius: 10px;
|
||
height: 24px;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
|
||
.progress-fill {
|
||
height: 100%;
|
||
border-radius: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
transition: width 0.5s ease;
|
||
}
|
||
|
||
.progress-green { background: linear-gradient(90deg, #28a745, #20c997); }
|
||
.progress-yellow { background: linear-gradient(90deg, #ffc107, #fd7e14); }
|
||
.progress-red { background: linear-gradient(90deg, #dc3545, #c82333); }
|
||
|
||
.badge {
|
||
display: inline-block;
|
||
padding: 4px 12px;
|
||
border-radius: 20px;
|
||
font-size: 0.85em;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.badge-success { background: #d4edda; color: #155724; }
|
||
.badge-warning { background: #fff3cd; color: #856404; }
|
||
.badge-danger { background: #f8d7da; color: #721c24; }
|
||
.badge-info { background: #d1ecf1; color: #0c5460; }
|
||
|
||
.grid-2 {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||
gap: 20px;
|
||
}
|
||
|
||
.warning-box {
|
||
background: #fff3cd;
|
||
border-left: 4px solid #ffc107;
|
||
padding: 15px;
|
||
border-radius: 5px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
pre {
|
||
background: #f8f9fa;
|
||
padding: 15px;
|
||
border-radius: 8px;
|
||
overflow-x: auto;
|
||
font-size: 13px;
|
||
max-height: 300px;
|
||
}
|
||
|
||
.truncate {
|
||
max-width: 300px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.tab button { padding: 12px 15px; font-size: 13px; }
|
||
.info-table th, .info-table td { padding: 8px; font-size: 13px; }
|
||
}
|
||
|
||
@media print {
|
||
.header, .tab-container { position: static; }
|
||
.tabcontent { display: block !important; page-break-inside: avoid; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="header">
|
||
<h1>🖥️ Info PC - $($SystemInfo.ComputerName)</h1>
|
||
<div class="subtitle">Rapport généré le $(Get-Date -Format "dd/MM/yyyy à HH:mm")</div>
|
||
</div>
|
||
|
||
<div class="tab-container">
|
||
<div class="tab">
|
||
<button class="active" onclick="openTab(event, 'InfoPC')">💻 Système</button>
|
||
<button onclick="openTab(event, 'Utilisateurs')">👥 Utilisateurs</button>
|
||
<button onclick="openTab(event, 'Logiciels')">📦 Logiciels</button>
|
||
<button onclick="openTab(event, 'Reseaux')">🌐 Réseaux</button>
|
||
<button onclick="openTab(event, 'Stockage')">💾 Stockage</button>
|
||
<button onclick="openTab(event, 'Mail')">📧 Mail</button>
|
||
<button onclick="openTab(event, 'Demarrage')">🚀 Démarrage</button>
|
||
<button onclick="openTab(event, 'Batterie')">🔋 Batterie</button>
|
||
<button onclick="openTab(event, 'Imprimante')">🖨️ Imprimantes</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ONGLET SYSTÈME -->
|
||
<div id="InfoPC" class="tabcontent" style="display: block;">
|
||
<div class="grid-2">
|
||
<div class="info-block">
|
||
<h3 class="section-title">Informations Système</h3>
|
||
<table class="info-table">
|
||
<tr><td><strong>Nom du PC</strong></td><td>$($SystemInfo.ComputerName)</td></tr>
|
||
<tr><td><strong>Windows</strong></td><td>$($SystemInfo.WindowsVersion)</td></tr>
|
||
<tr><td><strong>Architecture</strong></td><td>$($SystemInfo.Architecture)</td></tr>
|
||
<tr><td><strong>Date d'installation</strong></td><td>$($SystemInfo.InstallDate)</td></tr>
|
||
<tr><td><strong>Dernier démarrage</strong></td><td>$($SystemInfo.LastBoot)</td></tr>
|
||
<tr><td><strong>Uptime</strong></td><td>$($SystemInfo.Uptime)</td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">Sécurité</h3>
|
||
<table class="info-table">
|
||
<tr><td><strong>Secure Boot</strong></td><td>$(if($SystemInfo.SecureBoot -eq 'Activé'){'<span class="badge badge-success">Activé</span>'}else{'<span class="badge badge-warning">'+$SystemInfo.SecureBoot+'</span>'})</td></tr>
|
||
<tr><td><strong>TPM</strong></td><td>$(if($SystemInfo.TPM.Present){'<span class="badge badge-success">Présent</span>'}else{'<span class="badge badge-danger">Non détecté</span>'})</td></tr>
|
||
$(if($SystemInfo.TPM.Present){"<tr><td><strong>Version TPM</strong></td><td>$($SystemInfo.TPM.Version)</td></tr>"}else{""})
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid-2">
|
||
<div class="info-block">
|
||
<h3 class="section-title">Matériel</h3>
|
||
<table class="info-table">
|
||
<tr><td><strong>Fabricant</strong></td><td>$($SystemInfo.Manufacturer)</td></tr>
|
||
<tr><td><strong>Modèle</strong></td><td>$($SystemInfo.Model)</td></tr>
|
||
<tr><td><strong>Carte mère</strong></td><td>$($SystemInfo.MotherboardMfr) $($SystemInfo.Motherboard)</td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">BIOS</h3>
|
||
<table class="info-table">
|
||
<tr><td><strong>Version</strong></td><td>$($SystemInfo.BiosVersion)</td></tr>
|
||
<tr><td><strong>Fabricant</strong></td><td>$($SystemInfo.BiosManufacturer)</td></tr>
|
||
<tr><td><strong>Date</strong></td><td>$($SystemInfo.BiosDate)</td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">Processeur</h3>
|
||
<table class="info-table">
|
||
<tr><td><strong>CPU</strong></td><td>$($SystemInfo.CPU)</td></tr>
|
||
<tr><td><strong>Cœurs / Threads</strong></td><td>$($SystemInfo.CPUCores) cœurs / $($SystemInfo.CPUThreads) threads</td></tr>
|
||
<tr><td><strong>Socket</strong></td><td>$($SystemInfo.CPUSocket)</td></tr>
|
||
<tr><td><strong>Fréquence max</strong></td><td>$($SystemInfo.CPUMaxSpeed)</td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">Mémoire RAM</h3>
|
||
<table class="info-table">
|
||
<tr><td><strong>Capacité totale</strong></td><td>$($MemoryInfo.TotalCapacity)</td></tr>
|
||
<tr><td><strong>Slots utilisés</strong></td><td>$($MemoryInfo.UsedSlots) / $($MemoryInfo.TotalSlots)</td></tr>
|
||
</table>
|
||
|
||
<h4 style="margin-top: 20px;">Détails des modules</h4>
|
||
<table class="info-table">
|
||
<tr><th>Emplacement</th><th>Fabricant</th><th>Référence</th><th>Capacité</th><th>Type</th><th>Vitesse</th></tr>
|
||
$(foreach($module in $MemoryInfo.Modules) {
|
||
"<tr><td>$($module.DeviceLocator)</td><td>$($module.Manufacturer)</td><td>$($module.PartNumber)</td><td>$($module.Capacity)</td><td>$($module.Type)</td><td>$($module.Speed)</td></tr>"
|
||
})
|
||
</table>
|
||
</div>
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">Carte(s) Graphique(s)</h3>
|
||
<table class="info-table">
|
||
<tr><th>Nom</th><th>Processeur</th><th>VRAM</th><th>Driver</th><th>Résolution</th></tr>
|
||
$(foreach($gpu in $GPUInfo) {
|
||
"<tr><td>$($gpu.Name)</td><td>$($gpu.Processor)</td><td>$($gpu.RAM)</td><td>$($gpu.Driver)</td><td>$($gpu.Resolution) @ $($gpu.RefreshRate)</td></tr>"
|
||
})
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ONGLET UTILISATEURS -->
|
||
<div id="Utilisateurs" class="tabcontent">
|
||
<div class="info-block">
|
||
<h3 class="section-title">Comptes Utilisateurs Locaux</h3>
|
||
<table class="info-table">
|
||
<tr><th>Nom</th><th>Nom complet</th><th>Description</th><th>Statut</th></tr>
|
||
$(foreach($user in $UserInfo) {
|
||
$statusBadge = if($user.Status -eq 'Actif'){'<span class="badge badge-success">Actif</span>'}else{'<span class="badge badge-danger">Désactivé</span>'}
|
||
"<tr><td>$($user.Name)</td><td>$($user.FullName)</td><td>$($user.Description)</td><td>$statusBadge</td></tr>"
|
||
})
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ONGLET LOGICIELS -->
|
||
<div id="Logiciels" class="tabcontent">
|
||
<div class="info-block">
|
||
<h3 class="section-title">Logiciels Installés ($($SoftwareInfo.Count) programmes)</h3>
|
||
<table class="info-table">
|
||
<tr><th>Nom</th><th>Version</th><th>Éditeur</th><th>Date d'installation</th></tr>
|
||
$(foreach($soft in $SoftwareInfo) {
|
||
"<tr><td>$($soft.Name)</td><td>$($soft.Version)</td><td>$($soft.Publisher)</td><td>$($soft.InstallDate)</td></tr>"
|
||
})
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ONGLET RÉSEAUX -->
|
||
<div id="Reseaux" class="tabcontent">
|
||
<div class="info-block">
|
||
<h3 class="section-title">Configuration Réseau</h3>
|
||
<table class="info-table">
|
||
<tr><td><strong>Domaine / Groupe</strong></td><td>$($NetworkInfo.DomainInfo)</td></tr>
|
||
<tr><td><strong>DNS</strong></td><td>$($NetworkInfo.DNS)</td></tr>
|
||
<tr><td><strong>Passerelle</strong></td><td>$($NetworkInfo.Gateway)</td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">Adaptateurs Réseau</h3>
|
||
<table class="info-table">
|
||
<tr><th>Nom</th><th>Description</th><th>Statut</th><th>Vitesse</th><th>MAC</th><th>IP</th></tr>
|
||
$(foreach($adapter in $NetworkInfo.Adapters) {
|
||
$statusBadge = if($adapter.Status -eq 'Up'){'<span class="badge badge-success">Connecté</span>'}else{'<span class="badge badge-warning">'+$adapter.Status+'</span>'}
|
||
"<tr><td>$($adapter.Name)</td><td class='truncate' title='$($adapter.Description)'>$($adapter.Description)</td><td>$statusBadge</td><td>$($adapter.Speed)</td><td>$($adapter.MAC)</td><td>$($adapter.IPAddress)</td></tr>"
|
||
})
|
||
</table>
|
||
</div>
|
||
|
||
$(if($NetworkInfo.NetworkDrives.Count -gt 0) {
|
||
"<div class='info-block'>
|
||
<h3 class='section-title'>Lecteurs Réseau</h3>
|
||
<table class='info-table'>
|
||
<tr><th>Lettre</th><th>Chemin réseau</th></tr>
|
||
$(foreach($drive in $NetworkInfo.NetworkDrives) {
|
||
"<tr><td>$($drive.Letter)</td><td>$($drive.Path)</td></tr>"
|
||
})
|
||
</table>
|
||
</div>"
|
||
} else {
|
||
"<div class='info-block'><h3 class='section-title'>Lecteurs Réseau</h3><p>Aucun lecteur réseau connecté.</p></div>"
|
||
})
|
||
|
||
$(if($NetworkInfo.WifiProfiles.Count -gt 0) {
|
||
"<div class='info-block'>
|
||
<h3 class='section-title'>Profils WiFi Enregistrés ($($NetworkInfo.WifiProfiles.Count))</h3>
|
||
<table class='info-table'>
|
||
<tr><th>SSID</th><th>Authentification</th></tr>
|
||
$(foreach($wifi in $NetworkInfo.WifiProfiles) {
|
||
"<tr><td>$($wifi.SSID)</td><td>$($wifi.Authentication)</td></tr>"
|
||
})
|
||
</table>
|
||
</div>"
|
||
})
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">Fichier Hosts</h3>
|
||
<pre>$($NetworkInfo.HostsFile)</pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ONGLET STOCKAGE -->
|
||
<div id="Stockage" class="tabcontent">
|
||
<div class="info-block">
|
||
<h3 class="section-title">Disques Physiques</h3>
|
||
<table class="info-table">
|
||
<tr><th>Modèle</th><th>Type</th><th>Capacité</th><th>Interface</th><th>Santé</th><th>N° Série</th></tr>
|
||
$(foreach($disk in $StorageInfo.Disks) {
|
||
$healthBadge = switch($disk.Health) {
|
||
'Healthy' { '<span class="health-ok">Bon</span>' }
|
||
'Warning' { '<span class="health-warning">Attention</span>' }
|
||
'Unhealthy' { '<span class="health-error">Défectueux</span>' }
|
||
default { $disk.Health }
|
||
}
|
||
"<tr><td>$($disk.Model)</td><td>$($disk.Type)</td><td>$($disk.Size)</td><td>$($disk.BusType)</td><td>$healthBadge</td><td class='truncate' title='$($disk.Serial)'>$($disk.Serial)</td></tr>"
|
||
})
|
||
</table>
|
||
</div>
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">Volumes</h3>
|
||
<table class="info-table">
|
||
<tr><th>Lettre</th><th>Nom</th><th>Système de fichiers</th><th>Utilisation</th><th>BitLocker</th></tr>
|
||
$(foreach($vol in $StorageInfo.Volumes) {
|
||
$progressClass = if($vol.UsedPercent -gt 90){'progress-red'}elseif($vol.UsedPercent -gt 75){'progress-yellow'}else{'progress-green'}
|
||
$blBadge = switch($vol.BitLockerStatus) {
|
||
'On' { '<span class="badge badge-success">Protégé</span>' }
|
||
'Off' { '<span class="badge badge-warning">Désactivé</span>' }
|
||
default { '<span class="badge badge-info">Non protégé</span>' }
|
||
}
|
||
"<tr>
|
||
<td><strong>$($vol.Letter)</strong></td>
|
||
<td>$($vol.Label)</td>
|
||
<td>$($vol.FileSystem)</td>
|
||
<td style='min-width: 200px;'>
|
||
<div class='progress-bar'>
|
||
<div class='progress-fill $progressClass' style='width: $($vol.UsedPercent)%;'>$($vol.UsedPercent)%</div>
|
||
</div>
|
||
<small>$($vol.Used) / $($vol.Size) (libre: $($vol.Free))</small>
|
||
</td>
|
||
<td>$blBadge</td>
|
||
</tr>"
|
||
})
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ONGLET MAIL -->
|
||
<div id="Mail" class="tabcontent">
|
||
<div class="warning-box">
|
||
⚠️ <strong>Note:</strong> Le script scanne uniquement les dossiers AppData\Microsoft\Outlook, Thunderbird\Profiles, et le dossier Documents.
|
||
</div>
|
||
|
||
$(if($MailInfo.OutlookAccounts.Count -gt 0) {
|
||
"<div class='info-block'>
|
||
<h3 class='section-title'>Comptes Outlook Configurés</h3>
|
||
<table class='info-table'>
|
||
<tr><th>Nom</th><th>Email</th><th>Type</th><th>Fichier de données</th></tr>
|
||
$(foreach($account in $MailInfo.OutlookAccounts) {
|
||
"<tr><td>$($account.Name)</td><td>$($account.Email)</td><td>$($account.Type)</td><td class='truncate' title='$($account.Store)'>$($account.Store)</td></tr>"
|
||
})
|
||
</table>
|
||
</div>"
|
||
} else {
|
||
"<div class='info-block'><h3 class='section-title'>Comptes Outlook</h3><p>Aucun compte Outlook détecté ou Outlook n'est pas installé.</p></div>"
|
||
})
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">Fichiers Outlook (PST/OST)</h3>
|
||
$(if($MailInfo.OutlookFiles.Count -gt 0) {
|
||
"<table class='info-table'>
|
||
<tr><th>Fichier</th><th>Type</th><th>Taille</th><th>Chemin</th></tr>
|
||
$(foreach($file in $MailInfo.OutlookFiles) {
|
||
"<tr><td>$($file.Name)</td><td>$($file.Type)</td><td>$($file.Size)</td><td class='truncate' title='$($file.Path)'>$($file.Path)</td></tr>"
|
||
})
|
||
</table>"
|
||
} else {
|
||
"<p>Aucun fichier PST ou OST trouvé.</p>"
|
||
})
|
||
</div>
|
||
|
||
<div class="info-block">
|
||
<h3 class="section-title">Profils Thunderbird</h3>
|
||
$(if($MailInfo.ThunderbirdProfiles.Count -gt 0) {
|
||
"<table class='info-table'>
|
||
<tr><th>Profil</th><th>Taille</th><th>Chemin</th></tr>
|
||
$(foreach($profile in $MailInfo.ThunderbirdProfiles) {
|
||
"<tr><td>$($profile.Name)</td><td>$($profile.Size)</td><td class='truncate' title='$($profile.Path)'>$($profile.Path)</td></tr>"
|
||
})
|
||
</table>"
|
||
} else {
|
||
"<p>Aucun profil Thunderbird trouvé.</p>"
|
||
})
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ONGLET DÉMARRAGE -->
|
||
<div id="Demarrage" class="tabcontent">
|
||
<div class="info-block">
|
||
<h3 class="section-title">Programmes au Démarrage ($($StartupInfo.Count))</h3>
|
||
$(if($StartupInfo.Count -gt 0) {
|
||
"<table class='info-table'>
|
||
<tr><th>Nom</th><th>Statut</th><th>Commande</th><th>Emplacement</th><th>Utilisateur</th></tr>
|
||
$(foreach($item in $StartupInfo) {
|
||
$statusBadge = if($item.Status -eq 'Activé'){'<span class="badge badge-success">Activé</span>'}else{'<span class="badge badge-warning">Désactivé</span>'}
|
||
"<tr>
|
||
<td>$($item.Name)</td>
|
||
<td>$statusBadge</td>
|
||
<td class='truncate' title='$($item.Command)'>$($item.Command)</td>
|
||
<td>$($item.Location)</td>
|
||
<td>$($item.User)</td>
|
||
</tr>"
|
||
})
|
||
</table>
|
||
<p style='font-size: 0.85em; color: #666; margin-top: 10px;'>💡 Survolez les cellules tronquées pour voir le contenu complet.</p>"
|
||
} else {
|
||
"<p>Aucun programme de démarrage trouvé.</p>"
|
||
})
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ONGLET BATTERIE -->
|
||
<div id="Batterie" class="tabcontent">
|
||
$(if($BatteryInfo.Available) {
|
||
$healthClass = if ($BatteryInfo.HealthPercent -ge 80) { 'health-ok' } elseif ($BatteryInfo.HealthPercent -ge 50) { 'health-warning' } else { 'health-error' }
|
||
$batteryHtml = "<div class='info-block'>
|
||
<h3 class='section-title'>État de la Batterie</h3>
|
||
<div class='grid-2'>
|
||
<table class='info-table'>
|
||
<tr><td><strong>Niveau de charge</strong></td><td>$($BatteryInfo.ChargeLevel)</td></tr>
|
||
<tr><td><strong>Statut</strong></td><td>$($BatteryInfo.Status)</td></tr>
|
||
<tr><td><strong>Identifiant</strong></td><td>$($BatteryInfo.DeviceID)</td></tr>
|
||
</table>
|
||
<table class='info-table'>
|
||
<tr><td><strong>Capacité d'origine</strong></td><td>$($BatteryInfo.DesignCapacity)</td></tr>
|
||
<tr><td><strong>Capacité actuelle</strong></td><td>$($BatteryInfo.FullChargeCapacity)</td></tr>
|
||
<tr><td><strong>Santé estimée</strong></td><td><span class='$healthClass'>$($BatteryInfo.HealthPercent)% ($($BatteryInfo.HealthStatus))</span></td></tr>
|
||
</table>
|
||
</div>
|
||
</div>"
|
||
if($BatteryInfo.ReportGenerated) {
|
||
$batteryHtml += "<div class='info-block'>
|
||
<h3 class='section-title'>Rapport Windows Battery Report</h3>
|
||
<p>Le rapport détaillé de la batterie a été généré : <code>$($BatteryInfo.ReportPath)</code></p>
|
||
<p>Ce fichier contient l'historique complet de la batterie et est inclus dans le dossier du rapport.</p>
|
||
</div>"
|
||
}
|
||
$batteryHtml
|
||
} else {
|
||
"<div class='info-block'>
|
||
<h3 class='section-title'>Batterie</h3>
|
||
<p>$($BatteryInfo.Message)</p>
|
||
</div>"
|
||
})
|
||
</div>
|
||
|
||
<!-- ONGLET IMPRIMANTES -->
|
||
<div id="Imprimante" class="tabcontent">
|
||
<div class="info-block">
|
||
<h3 class="section-title">Imprimantes Installées</h3>
|
||
$(if($PrinterInfo.Count -gt 0) {
|
||
"<table class='info-table'>
|
||
<tr><th>Nom</th><th>Statut</th><th>Port</th><th>Pilote</th><th>Par défaut</th><th>Partagée</th></tr>
|
||
$(foreach($printer in $PrinterInfo) {
|
||
$defaultBadge = if($printer.Default){'<span class="badge badge-success">Oui</span>'}else{'Non'}
|
||
$sharedBadge = if($printer.Shared){'<span class="badge badge-info">Oui</span>'}else{'Non'}
|
||
"<tr>
|
||
<td>$($printer.Name)</td>
|
||
<td>$($printer.Status)</td>
|
||
<td>$($printer.Port)</td>
|
||
<td class='truncate' title='$($printer.Driver)'>$($printer.Driver)</td>
|
||
<td>$defaultBadge</td>
|
||
<td>$sharedBadge</td>
|
||
</tr>"
|
||
})
|
||
</table>"
|
||
} else {
|
||
"<p>Aucune imprimante installée sur ce système.</p>"
|
||
})
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function openTab(evt, tabName) {
|
||
var tabcontent = document.getElementsByClassName("tabcontent");
|
||
for (var i = 0; i < tabcontent.length; i++) {
|
||
tabcontent[i].style.display = "none";
|
||
}
|
||
|
||
var tablinks = document.getElementsByClassName("tab")[0].getElementsByTagName("button");
|
||
for (var i = 0; i < tablinks.length; i++) {
|
||
tablinks[i].classList.remove("active");
|
||
}
|
||
|
||
document.getElementById(tabName).style.display = "block";
|
||
evt.currentTarget.classList.add("active");
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|
||
"@
|
||
|
||
return $htmlTemplate
|
||
}
|
||
|
||
# ============================================================================
|
||
# ENVOI EMAIL
|
||
# ============================================================================
|
||
|
||
function Send-ReportEmail {
|
||
param(
|
||
[string]$ReportPath,
|
||
[string]$BatteryReportPath,
|
||
[string]$ComputerName
|
||
)
|
||
|
||
Write-Log "Préparation de l'envoi par email..." -Level Info
|
||
|
||
# Charger les credentials de manière sécurisée
|
||
$credPath = [System.IO.Path]::Combine($PSScriptRoot, "smtp_credentials.xml")
|
||
|
||
if (Test-Path $credPath) {
|
||
try {
|
||
$credential = Import-Clixml -Path $credPath
|
||
}
|
||
catch {
|
||
Write-Log "Impossible de charger les credentials SMTP" -Level Error
|
||
return $false
|
||
}
|
||
}
|
||
else {
|
||
# Demander les credentials
|
||
Write-Log "Fichier de credentials non trouvé. Veuillez entrer les informations SMTP." -Level Warning
|
||
|
||
$saveCredentials = Read-Host "Voulez-vous sauvegarder les credentials pour une utilisation future ? (O/N)"
|
||
|
||
$credential = Get-Credential -Message "Entrez les identifiants SMTP" -UserName $Script:Config.SMTP.Username
|
||
|
||
if ($saveCredentials -eq 'O') {
|
||
$credential | Export-Clixml -Path $credPath
|
||
Write-Log "Credentials sauvegardés dans $credPath" -Level Success
|
||
}
|
||
}
|
||
|
||
$attachments = @($ReportPath)
|
||
|
||
if ($BatteryReportPath -and (Test-Path $BatteryReportPath)) {
|
||
$attachments += $BatteryReportPath
|
||
}
|
||
|
||
try {
|
||
$mailParams = @{
|
||
SmtpServer = $Script:Config.SMTP.Server
|
||
Port = $Script:Config.SMTP.Port
|
||
UseSsl = $true
|
||
From = $Script:Config.SMTP.From
|
||
To = $Script:Config.SMTP.To
|
||
Subject = "Rapport PC - $ComputerName - $(Get-Date -Format 'dd/MM/yyyy HH:mm')"
|
||
Body = @"
|
||
Bonjour,
|
||
|
||
Veuillez trouver ci-joint le rapport PC généré pour la machine : $ComputerName
|
||
|
||
Rapport généré le : $(Get-Date -Format 'dd/MM/yyyy à HH:mm:ss')
|
||
|
||
Cordialement,
|
||
Script Info PC v0.5.0
|
||
"@
|
||
Credential = $credential
|
||
Attachments = $attachments
|
||
}
|
||
|
||
Send-MailMessage @mailParams -WarningAction SilentlyContinue
|
||
Write-Log "Email envoyé avec succès!" -Level Success
|
||
return $true
|
||
}
|
||
catch {
|
||
Write-Log "Erreur lors de l'envoi de l'email: $_" -Level Error
|
||
return $false
|
||
}
|
||
}
|
||
|
||
# ============================================================================
|
||
# SCRIPT PRINCIPAL
|
||
# ============================================================================
|
||
|
||
# Affichage du header
|
||
Clear-Host
|
||
Write-Host ""
|
||
Write-Host " ╔══════════════════════════════════════════╗" -ForegroundColor Cyan
|
||
Write-Host " ║ INFO PC - Version 0.5.0 ║" -ForegroundColor Cyan
|
||
Write-Host " ║ Diagnostic complet du système ║" -ForegroundColor Cyan
|
||
Write-Host " ╚══════════════════════════════════════════╝" -ForegroundColor Cyan
|
||
Write-Host ""
|
||
|
||
# Vérification des droits admin
|
||
if (-not (Test-IsAdmin)) {
|
||
Write-Log "Ce script nécessite des droits administrateur pour certaines fonctionnalités." -Level Warning
|
||
Write-Log "Certaines informations pourraient être incomplètes." -Level Warning
|
||
Write-Host ""
|
||
}
|
||
|
||
# Demande du nom du fichier
|
||
$htmlFileName = Read-Host "Entrez le nom du rapport (sans extension) [défaut: nom de la machine]"
|
||
if ([string]::IsNullOrWhiteSpace($htmlFileName)) {
|
||
$htmlFileName = $env:COMPUTERNAME
|
||
}
|
||
|
||
# Choix du type de PC
|
||
Write-Host ""
|
||
Write-Host "Type de PC :" -ForegroundColor White
|
||
Write-Host " 1 - PC de bureau (pas de test batterie)"
|
||
Write-Host " 2 - PC Portable (test batterie inclus)"
|
||
Write-Host ""
|
||
|
||
do {
|
||
$choice = Read-Host "Votre choix [1]"
|
||
if ([string]::IsNullOrWhiteSpace($choice)) { $choice = '1' }
|
||
} while ($choice -notin @('1', '2'))
|
||
|
||
$includeBatteryTest = ($choice -eq '2')
|
||
|
||
Write-Host ""
|
||
Write-Log "Démarrage de la collecte des informations..." -Level Info
|
||
Write-Host ""
|
||
|
||
# Création du dossier de sortie
|
||
$folderName = "$htmlFileName - Info PC"
|
||
$script:FolderPath = [System.IO.Path]::Combine($PSScriptRoot, $folderName)
|
||
$null = New-Item -ItemType Directory -Path $script:FolderPath -Force -ErrorAction SilentlyContinue
|
||
|
||
# Collecte des informations
|
||
$systemInfo = Get-SystemInfo
|
||
$memoryInfo = Get-MemoryInfo
|
||
$gpuInfo = Get-GPUInfo
|
||
$storageInfo = Get-StorageInfo
|
||
$networkInfo = Get-NetworkInfo
|
||
$userInfo = Get-UserInfo
|
||
$softwareInfo = Get-SoftwareInfo
|
||
$startupInfo = Get-StartupInfo
|
||
$printerInfo = Get-PrinterInfo
|
||
$mailInfo = Get-MailInfo
|
||
$batteryInfo = Get-BatteryInfo -IncludeBatteryTest $includeBatteryTest
|
||
|
||
# Génération du rapport HTML
|
||
Write-Log "Génération du rapport HTML..." -Level Info
|
||
|
||
$htmlContent = New-HTMLReport `
|
||
-SystemInfo $systemInfo `
|
||
-MemoryInfo $memoryInfo `
|
||
-GPUInfo $gpuInfo `
|
||
-StorageInfo $storageInfo `
|
||
-NetworkInfo $networkInfo `
|
||
-UserInfo $userInfo `
|
||
-SoftwareInfo $softwareInfo `
|
||
-StartupInfo $startupInfo `
|
||
-PrinterInfo $printerInfo `
|
||
-MailInfo $mailInfo `
|
||
-BatteryInfo $batteryInfo
|
||
|
||
$htmlFilePath = [System.IO.Path]::Combine($script:FolderPath, "$htmlFileName.html")
|
||
$htmlContent | Out-File -FilePath $htmlFilePath -Encoding UTF8
|
||
|
||
Write-Log "Rapport généré: $htmlFilePath" -Level Success
|
||
|
||
# Envoi par email
|
||
if ($Script:Config.Options.SendEmail) {
|
||
Write-Host ""
|
||
$sendEmail = Read-Host "Voulez-vous envoyer le rapport par email ? (O/N) [O]"
|
||
if ([string]::IsNullOrWhiteSpace($sendEmail) -or $sendEmail -eq 'O') {
|
||
$batteryReportPath = if ($batteryInfo.ReportPath) { $batteryInfo.ReportPath } else { $null }
|
||
Send-ReportEmail -ReportPath $htmlFilePath -BatteryReportPath $batteryReportPath -ComputerName $systemInfo.ComputerName
|
||
}
|
||
}
|
||
|
||
# Ouverture du rapport
|
||
if ($Script:Config.Options.OpenReportOnEnd) {
|
||
Write-Host ""
|
||
Write-Log "Ouverture du rapport..." -Level Info
|
||
Invoke-Item -Path $htmlFilePath
|
||
}
|
||
|
||
Write-Host ""
|
||
Write-Host " ╔══════════════════════════════════════════╗" -ForegroundColor Green
|
||
Write-Host " ║ Script terminé ! ║" -ForegroundColor Green
|
||
Write-Host " ╚══════════════════════════════════════════╝" -ForegroundColor Green
|
||
Write-Host ""
|
||
Write-Host " Dossier: $script:FolderPath" -ForegroundColor Gray
|
||
Write-Host "" |