767 lines
25 KiB
PowerShell
767 lines
25 KiB
PowerShell
############################################### SQL ################################################################
|
|
$Exporthtml = "C:\Exploitation\WSUS\default.htm"
|
|
$configPath = "C:\Scripts\config.json"
|
|
############################################### SQL ################################################################
|
|
|
|
|
|
$config = Get-Content $configPath | ConvertFrom-Json
|
|
$ServerSQL = $config.SQL.Server
|
|
$database = $config.SQL.Database
|
|
$user = $config.SQL.Username
|
|
$password = $config.SQL.Password
|
|
|
|
# Convertir le mot de passe en SecureString
|
|
$securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
|
|
$creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($user, $securePassword)
|
|
$PassSQL = $creds.GetNetworkCredential().Password
|
|
|
|
|
|
Import-Module -Name PSwriteHTML
|
|
#. ([scriptblock]::Create((Invoke-WebRequest -Uri "https://raw.githubusercontent.com/DavidWuibaille/Repository/main/Function/DashboardEPM.ps1" -UseBasicParsing).Content))
|
|
|
|
# ----------------------------------------------------------------------------------------------------------------------
|
|
function Get-SqlData($connection, $query) {
|
|
$command = $connection.CreateCommand()
|
|
$command.CommandText = $query
|
|
$result = $command.ExecuteReader()
|
|
$table = New-Object System.Data.DataTable
|
|
$table.Load($result)
|
|
return $table
|
|
}
|
|
|
|
function Connect-SQLDatabase {
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Server,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Database,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$User,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Password
|
|
)
|
|
|
|
try {
|
|
# Construction de la chaîne de connexion
|
|
$connectionString = "Server=$Server;uid=$User;pwd=$Password;Database=$Database;Integrated Security=False;"
|
|
|
|
# Création de l'objet connexion SQL
|
|
$connection = New-Object System.Data.SqlClient.SqlConnection
|
|
$connection.ConnectionString = $connectionString
|
|
|
|
# Ouverture de la connexion
|
|
$connection.Open()
|
|
Write-Host "------ Connected to Database: $Database on Server: $Server"
|
|
|
|
# Retourne l'objet connexion
|
|
return $connection
|
|
} catch {
|
|
# Gestion des erreurs
|
|
Write-Host "------ Error connecting to Database: $Database on Server: $Server"
|
|
Write-Host "------ Error details: $_"
|
|
return $null
|
|
}
|
|
}
|
|
|
|
function Get-ApplicationData {
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Data.SqlClient.SqlConnection]$Connection,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$AppFilter
|
|
)
|
|
|
|
# Initialiser la collection pour stocker les données
|
|
$ApplicationData = @()
|
|
|
|
# Définir la requête SQL avec le filtre dynamique
|
|
$query = @"
|
|
SELECT DISTINCT A0.DISPLAYNAME, A1.SUITENAME, A1.VERSION
|
|
FROM Computer A0 (nolock)
|
|
LEFT OUTER JOIN AppSoftwareSuites A1 (nolock) ON A0.Computer_Idn = A1.Computer_Idn
|
|
WHERE (A1.SUITENAME LIKE N'%$AppFilter%')
|
|
ORDER BY A0.DISPLAYNAME
|
|
"@
|
|
|
|
# Exécuter la requête et charger les résultats
|
|
$table = Get-SqlData -Connection $Connection -Query $query
|
|
|
|
# Parcourir les résultats et remplir la collection
|
|
foreach ($element in $table) {
|
|
$ApplicationData += [PSCustomObject]@{
|
|
'APPLICATION' = $element.SUITENAME
|
|
'VERSION' = $element.VERSION
|
|
'DEVICENAME' = $element.DISPLAYNAME
|
|
}
|
|
}
|
|
|
|
# Retourner la collection
|
|
return $ApplicationData
|
|
}
|
|
|
|
|
|
function Get-BitlockerDetails {
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Data.SqlClient.SqlConnection]$Connection
|
|
)
|
|
|
|
# Initialiser la collection pour stocker les données
|
|
$BitlockerDetails = @()
|
|
|
|
# Définir la requête SQL avec le filtre dynamique pour le système d'exploitation
|
|
$query = @"
|
|
SELECT DISTINCT A0.DISPLAYNAME, A2.SECUREBOOTENABLED, A2.UEFIENABLED, A3.CONVERSIONSTATUS,
|
|
A4.TPMENABLE, A4.TPMVERSION, A5.MODEL
|
|
FROM Computer A0 (nolock)
|
|
LEFT OUTER JOIN Operating_System A1 (nolock) ON A0.Computer_Idn = A1.Computer_Idn
|
|
LEFT OUTER JOIN BIOS A2 (nolock) ON A0.Computer_Idn = A2.Computer_Idn
|
|
LEFT OUTER JOIN BitLocker A3 (nolock) ON A0.Computer_Idn = A3.Computer_Idn
|
|
LEFT OUTER JOIN TPMSystem A4 (nolock) ON A0.Computer_Idn = A4.Computer_Idn
|
|
LEFT OUTER JOIN CompSystem A5 (nolock) ON A0.Computer_Idn = A5.Computer_Idn
|
|
WHERE
|
|
A0.Computer_Idn NOT IN (
|
|
SELECT Computer_Idn FROM Computer WHERE TYPE LIKE N'%Server%'
|
|
)
|
|
ORDER BY A0.DISPLAYNAME
|
|
"@
|
|
|
|
# Exécuter la requête et charger les résultats
|
|
$table = Get-SqlData -Connection $Connection -Query $query
|
|
|
|
# Parcourir les résultats et remplir la collection
|
|
foreach ($element in $table) {
|
|
$BitlockerDetails += [PSCustomObject]@{
|
|
'DEVICENAME' = $element.DISPLAYNAME
|
|
'BitLocker' = if ([string]::IsNullOrEmpty($element.CONVERSIONSTATUS)) { "NoData" } else { $element.CONVERSIONSTATUS }
|
|
'SECURE Boot' = $element.SECUREBOOTENABLED
|
|
'UEFI' = $element.UEFIENABLED
|
|
'TPM' = $element.TPMENABLE
|
|
'TPM Version' = $element.TPMVERSION
|
|
'Model' = $element.MODEL
|
|
}
|
|
}
|
|
|
|
# Retourner la collection d'objets
|
|
return $BitlockerDetails
|
|
}
|
|
|
|
|
|
function Get-WindowsDetails {
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Data.SqlClient.SqlConnection]$Connection
|
|
)
|
|
|
|
$WindowsDetails = @()
|
|
$SkippedDevices = @()
|
|
|
|
$query = @"
|
|
SELECT DISTINCT
|
|
A0.DISPLAYNAME,
|
|
A1.OSTYPE,
|
|
A2.CURRENTBUILD,
|
|
A2.UBR
|
|
FROM
|
|
Computer A0 (NOLOCK)
|
|
LEFT OUTER JOIN Operating_System A1 (NOLOCK) ON A0.Computer_Idn = A1.Computer_Idn
|
|
LEFT OUTER JOIN OSNT A2 (NOLOCK) ON A0.Computer_Idn = A2.Computer_Idn
|
|
WHERE
|
|
A0.Computer_Idn NOT IN (
|
|
SELECT Computer_Idn FROM Computer WHERE TYPE LIKE N'%Server%'
|
|
)
|
|
ORDER BY
|
|
A0.DISPLAYNAME
|
|
"@
|
|
|
|
# Exécute la requête SQL
|
|
$table = Get-SqlData -Connection $Connection -Query $query
|
|
|
|
foreach ($element in $table) {
|
|
$versionCode = Clean-WindowsVersion -OSType $element.OSTYPE -Build $element.CURRENTBUILD
|
|
|
|
$ubrValue = if ([string]::IsNullOrWhiteSpace($element.UBR)) {
|
|
$null
|
|
} else {
|
|
try {
|
|
[int]$element.UBR
|
|
} catch {
|
|
$null
|
|
}
|
|
}
|
|
|
|
if ($null -ne $ubrValue) {
|
|
$WindowsDetails += [PSCustomObject]@{
|
|
DEVICENAME = $element.DISPLAYNAME
|
|
VERSION = "$versionCode.$ubrValue"
|
|
}
|
|
} else {
|
|
$SkippedDevices += $element.DISPLAYNAME
|
|
}
|
|
}
|
|
|
|
if ($SkippedDevices.Count -gt 0) {
|
|
Write-Warning "Les machines suivantes n'ont pas de valeur UBR valide et ont été ignorées :"
|
|
$SkippedDevices | ForEach-Object { Write-Host " - $_" -ForegroundColor Yellow }
|
|
}
|
|
|
|
return $WindowsDetails | Sort-Object VERSION
|
|
}
|
|
|
|
|
|
|
|
function Close-SQLConnection {
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Data.SqlClient.SqlConnection]$Connection
|
|
)
|
|
|
|
try {
|
|
# Vérifier si la connexion est ouverte
|
|
if ($Connection.State -eq [System.Data.ConnectionState]::Open) {
|
|
$Connection.Close()
|
|
Write-Host "------ Connection closed successfully."
|
|
} else {
|
|
Write-Host "------ Connection is already closed or not initialized."
|
|
}
|
|
} catch {
|
|
# Gestion des erreurs
|
|
Write-Host "------ Error closing the connection."
|
|
Write-Host "------ Error details: $_"
|
|
}
|
|
}
|
|
|
|
function Clean-WindowsVersion {
|
|
param (
|
|
[string]$OSType,
|
|
[string]$Build
|
|
)
|
|
|
|
# Hashtable principale
|
|
$buildMap = @{
|
|
# Windows 11
|
|
'22621' = 'w11_22H2'
|
|
'22631' = 'w11_23H2'
|
|
|
|
# Windows 10 - Standard
|
|
'19041' = 'w10_2004'
|
|
'19042' = 'w10_20H2'
|
|
'19043' = 'w10_21H1'
|
|
'19044' = 'w10_22H2' # Peut être override via OSTYPE
|
|
'19045' = 'w10_22H2'
|
|
|
|
# Windows 10 - LTSC / LTSB
|
|
'17763' = 'w10_LTSC2019'
|
|
'14393' = 'w10_LTSB2016'
|
|
|
|
# Windows 8.x / 7
|
|
'9600' = 'w81'
|
|
'9200' = 'w8'
|
|
'7601' = 'w7_sp1'
|
|
|
|
# Windows Server
|
|
'17763_srv' = 'ws2019'
|
|
'20348' = 'ws2022'
|
|
'25398' = 'ws2025'
|
|
}
|
|
|
|
# Gestion spéciale de certains builds ambigus
|
|
if ($Build -eq '19044' -and $OSType -like '*LTSC 2021*') {
|
|
return 'w10_LTSC2021'
|
|
}
|
|
|
|
if ($Build -eq '17763' -and $OSType -like '*Server*') {
|
|
return $buildMap['17763_srv']
|
|
}
|
|
|
|
if ($Build -eq '14393' -and $OSType -like '*Server*') {
|
|
return 'ws2016'
|
|
}
|
|
|
|
if ($buildMap.ContainsKey($Build)) {
|
|
return $buildMap[$Build]
|
|
}
|
|
|
|
# Fallback dynamique
|
|
if ($OSType -like '*Server*') {
|
|
return "$Build"
|
|
} else {
|
|
return "$Build"
|
|
}
|
|
}
|
|
|
|
function Clean-OSType {
|
|
param (
|
|
[string]$OSType
|
|
)
|
|
|
|
if (-not $OSType) { return "Unknown OS" }
|
|
|
|
$os = $OSType
|
|
|
|
# Nettoyage de base
|
|
$os = $os -replace ',\s*64-bit', ''
|
|
$os = $os -replace 'Microsoft\s+', ''
|
|
$os = $os -replace '\s+Edition', ''
|
|
|
|
# Patterns à détecter
|
|
$patterns = @(
|
|
@{ Pattern = 'Windows\s+10\s+Enterprise\s+2016\s+LTSB'; Replacement = 'Windows 10 LTSB 2016' },
|
|
@{ Pattern = 'Windows\s+10\s+Enterprise\s+LTSC\s+2019'; Replacement = 'Windows 10 LTSC 2019' },
|
|
@{ Pattern = 'Windows\s+10\s+Enterprise\s+LTSC\s+2021'; Replacement = 'Windows 10 LTSC 2021' },
|
|
@{ Pattern = 'Windows\s+10\s+Enterprise'; Replacement = 'Windows 10 Enterprise' },
|
|
@{ Pattern = 'Windows\s+11\s+Enterprise'; Replacement = 'Windows 11 Enterprise' },
|
|
@{ Pattern = 'Windows\s+10\s+IoT\s+Enterprise'; Replacement = 'Windows 10 IoT Enterprise' },
|
|
@{ Pattern = 'Windows\s+Server\s+(\d+)\s+Datacenter'; Replacement = 'Windows Server $1 Datacenter' },
|
|
@{ Pattern = 'Windows\s+Server\s+(\d+)\s+Standard'; Replacement = 'Windows Server $1 Standard' }
|
|
)
|
|
|
|
foreach ($p in $patterns) {
|
|
if ($os -match $p.Pattern) {
|
|
return ($os -replace $p.Pattern, $p.Replacement)
|
|
}
|
|
}
|
|
|
|
# Fallback : retourne nom nettoyé
|
|
return $os
|
|
}
|
|
|
|
function Get-WorkstationModels {
|
|
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Data.SqlClient.SqlConnection]$Connection
|
|
)
|
|
|
|
$workstationModels = New-Object System.Collections.Generic.List[object]
|
|
|
|
$query = @"
|
|
SELECT DISTINCT
|
|
A0.DISPLAYNAME,
|
|
A1.MODEL,
|
|
A2.OSTYPE
|
|
FROM
|
|
Computer A0 WITH (NOLOCK)
|
|
LEFT JOIN CompSystem A1 WITH (NOLOCK) ON A0.Computer_Idn = A1.Computer_Idn
|
|
LEFT JOIN Operating_System A2 WITH (NOLOCK) ON A0.Computer_Idn = A2.Computer_Idn
|
|
ORDER BY
|
|
A0.DISPLAYNAME
|
|
"@
|
|
|
|
Write-Verbose "Executing SQL query to retrieve workstation models."
|
|
|
|
$table = Get-SqlData -Connection $Connection -Query $query
|
|
|
|
foreach ($row in $table) {
|
|
$modelValue = if ([string]::IsNullOrWhiteSpace($row.MODEL) -or $row.MODEL -eq 'Default string') {
|
|
'No Data'
|
|
} else {
|
|
$row.MODEL
|
|
}
|
|
|
|
$cleanOS = Clean-OSType -OSType $row.OSTYPE
|
|
|
|
$workstationModels.Add([PSCustomObject]@{
|
|
DEVICENAME = $row.DISPLAYNAME
|
|
MODEL = $modelValue
|
|
OS = $cleanOS
|
|
})
|
|
}
|
|
|
|
return $workstationModels
|
|
}
|
|
|
|
function Get-WorkstationManufacturers {
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Data.SqlClient.SqlConnection]$Connection
|
|
)
|
|
|
|
# Initialiser la collection pour stocker les données
|
|
$ManufacturerData = @()
|
|
|
|
# Définir la requête SQL
|
|
$query = @"
|
|
SELECT DISTINCT A0.DISPLAYNAME, A1.MANUFACTURER
|
|
FROM Computer A0 (nolock)
|
|
LEFT OUTER JOIN CompSystem A1 (nolock) ON A0.Computer_Idn = A1.Computer_Idn
|
|
WHERE (A0.Computer_Idn NOT IN (
|
|
SELECT Computer_Idn
|
|
FROM Computer
|
|
WHERE TYPE LIKE N'%Server%'
|
|
))
|
|
ORDER BY A0.DISPLAYNAME
|
|
"@
|
|
|
|
# Exécuter la requête et charger les résultats
|
|
$table = Get-SqlData -Connection $Connection -Query $query
|
|
|
|
# Parcourir les résultats et remplir la collection
|
|
foreach ($element in $table) {
|
|
$ManufacturerData += [PSCustomObject]@{
|
|
'DEVICENAME' = $element.DISPLAYNAME
|
|
'MANUFACTURER' = if ([string]::IsNullOrEmpty($element.MANUFACTURER)) { "NoData" } else { $element.MANUFACTURER }
|
|
}
|
|
}
|
|
|
|
# Retourner la collection d'objets
|
|
return $ManufacturerData
|
|
}
|
|
|
|
|
|
function Get-EnvironmentVariables {
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Data.SqlClient.SqlConnection]$Connection,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$VariableName
|
|
)
|
|
|
|
# Initialiser la collection pour stocker les données
|
|
$EnvironmentVariables = @()
|
|
|
|
# Définir la requête SQL avec le filtre pour le nom de la variable
|
|
$query = @"
|
|
SELECT DISTINCT A0.DISPLAYNAME, A1.VALUESTRING
|
|
FROM Computer A0 (nolock)
|
|
LEFT OUTER JOIN EnvironSettings A1 (nolock) ON A0.Computer_Idn = A1.Computer_Idn
|
|
WHERE (A0.Computer_Idn NOT IN (
|
|
SELECT Computer_Idn
|
|
FROM Computer
|
|
WHERE TYPE LIKE N'%Server%'
|
|
))
|
|
AND A1.NAME = N'$VariableName'
|
|
ORDER BY A0.DISPLAYNAME
|
|
"@
|
|
|
|
# Exécuter la requête et charger les résultats
|
|
$table = Get-SqlData -Connection $Connection -Query $query
|
|
|
|
# Parcourir les résultats et remplir la collection
|
|
foreach ($element in $table) {
|
|
$EnvironmentVariables += [PSCustomObject]@{
|
|
'DEVICENAME' = $element.DISPLAYNAME
|
|
'VALUE' = $element.VALUESTRING
|
|
}
|
|
}
|
|
|
|
# Retourner la collection d'objets
|
|
return $EnvironmentVariables
|
|
}
|
|
|
|
function Get-HardwareScanDay {
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Data.SqlClient.SqlConnection]$Connection
|
|
)
|
|
|
|
# Initialiser la collection pour stocker les données
|
|
$HardwareScanData = @()
|
|
|
|
# Définir la requête SQL
|
|
$query = @"
|
|
SELECT DISTINCT A0.DISPLAYNAME, A0.HWLASTSCANDATE
|
|
FROM Computer A0 (nolock)
|
|
WHERE (A0.Computer_Idn NOT IN (
|
|
SELECT Computer_Idn
|
|
FROM Computer
|
|
WHERE TYPE LIKE N'%Server%'
|
|
))
|
|
ORDER BY A0.DISPLAYNAME
|
|
"@
|
|
|
|
# Exécuter la requête et charger les résultats
|
|
$table = Get-SqlData -Connection $Connection -Query $query
|
|
|
|
# Parcourir les résultats et remplir la collection
|
|
foreach ($element in $table) {
|
|
$scanDate = $element.HWLASTSCANDATE
|
|
$daysDifference = (Get-Date) - [datetime]$scanDate
|
|
|
|
# Classifier la date selon les intervalles
|
|
$category = switch ($true) {
|
|
($daysDifference.TotalDays -le 7) { "<7 jours" }
|
|
($daysDifference.TotalDays -le 14) { "<14 jours" }
|
|
($daysDifference.TotalDays -le 30) { "<30 jours" }
|
|
($daysDifference.TotalDays -le 90) { "<90 jours" }
|
|
default { ">90 jours" }
|
|
}
|
|
|
|
$HardwareScanData += [PSCustomObject]@{
|
|
'DEVICENAME' = $element.DISPLAYNAME
|
|
'SCAN_CATEGORY' = $category
|
|
}
|
|
}
|
|
|
|
# Retourner la collection d'objets
|
|
return $HardwareScanData
|
|
}
|
|
|
|
|
|
#$Connection = Connect-SQLDatabase -Server $ServerSQL -Database $database -User $user -Password $PassSQL
|
|
#$Application1 = Get-ApplicationData -Connection $Connection -AppFilter $ApplicationFilter1
|
|
#$Application2 = Get-ApplicationData -Connection $Connection -AppFilter $ApplicationFilter2
|
|
#$BitlockerDetails = Get-BitlockerDetails -Connection $Connection
|
|
#$WindowsDetails = Get-WindowsDetails -Connection $Connection
|
|
#$WorkstationModels = Get-WorkstationModels -Connection $Connection
|
|
#$WorkstationMakes = Get-WorkstationManufacturers -Connection $Connection
|
|
#$Variable1 = Get-EnvironmentVariables -Connection $Connection -VariableName $VariableFilter1
|
|
#$HardwareScanDay = Get-HardwareScanDay -Connection $Connection
|
|
#$WindowsgroupesVersion = $WindowsDetails | Group-Object -Property VERSION
|
|
#$BitlockerStatus = $BitlockerDetails | Group-Object -Property Bitlocker
|
|
#$Modelscount = $WorkstationModels | Group-Object -Property MODEL
|
|
#$Makesount = $WorkstationMakes | Group-Object -Property MANUFACTURER
|
|
#$ScanDaycount = HardwareScanDay | Group-Object -Property SCAN_CATEGORY
|
|
#Close-SQLConnection -Connection $Connection
|
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------------------------------------------------
|
|
|
|
$Connection = Connect-SQLDatabase -Server $ServerSQL -Database $database -User $user -Password $PassSQL
|
|
#$Application1 = Get-ApplicationData -Connection $Connection -AppFilter $ApplicationFilter1
|
|
#$Application2 = Get-ApplicationData -Connection $Connection -AppFilter $ApplicationFilter2
|
|
#$BitlockerDetails = Get-BitlockerDetails -Connection $Connection
|
|
$WindowsDetails = Get-WindowsDetails -Connection $Connection
|
|
$WorkstationModels = Get-WorkstationModels -Connection $Connection
|
|
#$WorkstationMakes = Get-WorkstationManufacturers -Connection $Connection
|
|
#$Variable1 = Get-EnvironmentVariables -Connection $Connection -VariableName $VariableFilter1
|
|
#$HardwareScanDay = Get-HardwareScanDay -Connection $Connection
|
|
$WindowsgroupesVersion = $WindowsDetails | Group-Object -Property VERSION
|
|
#$BitlockerStatus = $BitlockerDetails | Group-Object -Property Bitlocker
|
|
$Modelscount = $WorkstationModels | Group-Object -Property MODEL
|
|
$Makesount = $WorkstationMakes | Group-Object -Property MANUFACTURER
|
|
#$ScanDaycount = HardwareScanDay | Group-Object -Property SCAN_CATEGORY
|
|
Close-SQLConnection -Connection $Connection
|
|
|
|
$WindowsMajorMap = $WindowsDetails | ForEach-Object {
|
|
$major = ($_.VERSION -split '\.')[0]
|
|
[PSCustomObject]@{
|
|
MAJORVERSION = $major
|
|
DEVICENAME = $_.DEVICENAME
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# Sauvegarde quotidienne des versions Windows
|
|
$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
|
$historyFile = Join-Path -Path $scriptPath -ChildPath "windows_versions_history.csv"
|
|
$today = (Get-Date -Format "yyyy-MM-dd")
|
|
|
|
$todayData = $WindowsgroupesVersion | ForEach-Object {
|
|
[PSCustomObject]@{
|
|
Date = $today
|
|
Version = $_.Name
|
|
Count = $_.Count
|
|
}
|
|
}
|
|
|
|
$yesterday = (Get-Date).AddDays(-1).ToString("yyyy-MM-dd")
|
|
|
|
|
|
|
|
$raw = Import-Csv -Path $historyFile
|
|
|
|
$cleaned = foreach ($entry in $raw) {
|
|
$date = $entry.Date
|
|
$version = $entry.Version
|
|
$count = [int]$entry.Count
|
|
|
|
$parts = $version -split '\.'
|
|
$build = $parts[0]
|
|
$ubr = $parts[1]
|
|
|
|
if ($ubr -match '^\d+$') {
|
|
$cleanCode = Clean-WindowsVersion -OSType '' -Build $build
|
|
[PSCustomObject]@{
|
|
Date = $date
|
|
Version = "$cleanCode.$ubr"
|
|
Count = $count
|
|
}
|
|
}
|
|
}
|
|
|
|
# Réécriture propre du CSV (overwrite)
|
|
$cleaned | Export-Csv -Path $historyFile -NoTypeInformation -Encoding UTF8
|
|
# Génération des courbes temporelles
|
|
$rawHistory = Import-Csv -Path $historyFile
|
|
|
|
# Nettoyage et enrichissement des lignes
|
|
$historyParsed = foreach ($entry in $rawHistory) {
|
|
$date = $entry.Date
|
|
$rawVer = $entry.Version
|
|
$count = [int]$entry.Count
|
|
|
|
# Découper Version brute : "17763.7009" => Build + UBR
|
|
$parts = $rawVer -split '\.'
|
|
$build = $parts[0]
|
|
$ubr = if ($parts[1] -match '^\d+$') { [int]$parts[1] } else { $null }
|
|
|
|
|
|
# Appeler Clean-WindowsVersion pour retrouver le VersionCode
|
|
$versionCode = Clean-WindowsVersion -OSType '' -Build $build
|
|
|
|
[PSCustomObject]@{
|
|
Date = $date
|
|
VersionCode = $versionCode
|
|
UBR = $ubr
|
|
Count = $count
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# Reconstruire version finale sans tag .old
|
|
$history = foreach ($row in $historyParsed) {
|
|
[PSCustomObject]@{
|
|
Date = $row.Date
|
|
Version = "$($row.VersionCode).$($row.UBR)"
|
|
Count = $row.Count
|
|
}
|
|
}
|
|
|
|
# Assurer que Count est bien un entier (au cas où CSV l'ait converti en string)
|
|
$history | ForEach-Object { $_.Count = [int]$_.Count }
|
|
|
|
$versions = $history.Version | Sort-Object -Unique
|
|
$dates = $history.Date | Sort-Object -Unique
|
|
|
|
# Courbe pour chaque version complète
|
|
$lines = foreach ($version in $versions) {
|
|
$valeurs = foreach ($date in $dates) {
|
|
$sum = ($history | Where-Object { $_.Date -eq $date -and $_.Version -eq $version } | Measure-Object -Property Count -Sum).Sum
|
|
if (-not $sum) { $sum = 0 }
|
|
$sum
|
|
}
|
|
[PSCustomObject]@{
|
|
Version = $version
|
|
Values = $valeurs
|
|
}
|
|
}
|
|
|
|
# Ajouter colonne MajorVersion à partir de Version
|
|
$historyGrouped = $history | ForEach-Object {
|
|
$_ | Add-Member -NotePropertyName "MajorVersion" -NotePropertyValue ($_.Version -split '\.')[0] -Force
|
|
$_
|
|
}
|
|
|
|
# Liste des versions majeures uniques
|
|
$majorVersions = $historyGrouped.MajorVersion | Sort-Object -Unique
|
|
|
|
# Courbes pour les versions majeures
|
|
$linesMajor = foreach ($version in $majorVersions) {
|
|
$valeurs = foreach ($date in $dates) {
|
|
$sum = ($historyGrouped | Where-Object {
|
|
$_.Date -eq $date -and $_.MajorVersion -eq $version
|
|
} | Measure-Object -Property Count -Sum).Sum
|
|
|
|
if (-not $sum) { $sum = 0 }
|
|
$sum
|
|
}
|
|
|
|
$displayName = $version
|
|
|
|
[PSCustomObject]@{
|
|
Version = $displayName
|
|
Values = $valeurs
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# Rapport HTML
|
|
New-HTML -TitleText 'Dashboard' {
|
|
|
|
# Onglet Windows - Donut chart actuel
|
|
New-HTMLTab -Name 'Windows' {
|
|
New-HTMLSection -HeaderText 'Windows Versions Over Time' {
|
|
New-HTMLPanel {
|
|
New-HTMLChart -Title "Windows Versions (Daily Evolution)" -TitleAlignment center {
|
|
New-ChartAxisX -Names $dates
|
|
foreach ($line in $lines) {
|
|
New-ChartLine -Name $line.Version -Value $line.Values
|
|
}
|
|
}
|
|
}
|
|
}
|
|
New-HTMLSection -HeaderText 'Windows Version' {
|
|
New-HTMLPanel {
|
|
New-HTMLChart -Title "Version" {
|
|
New-ChartToolbar -Download
|
|
New-ChartEvent -DataTableID 'WindowsOS' -ColumnID 1
|
|
foreach ($groupe in $WindowsgroupesVersion) {
|
|
New-ChartDonut -Name $($groupe.Name) -Value $($groupe.Count)
|
|
}
|
|
}
|
|
}
|
|
New-HTMLPanel {
|
|
New-HTMLTable -DataTable $WindowsDetails -DataTableID 'WindowsOS' -HideFooter
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
# Onglet Windows major
|
|
New-HTMLTab -Name 'Windows major' {
|
|
|
|
New-HTMLSection -HeaderText 'Windows Versions Over Time (Grouped by Major Version)' {
|
|
New-HTMLPanel {
|
|
New-HTMLChart -Title "Windows Major Versions (Daily Evolution)" -TitleAlignment center {
|
|
New-ChartAxisX -Names $dates
|
|
foreach ($line in $linesMajor) {
|
|
New-ChartLine -Name $line.Version -Value $line.Values
|
|
}
|
|
}
|
|
}
|
|
}
|
|
New-HTMLSection -HeaderText 'Windows Versions' {
|
|
New-HTMLPanel {
|
|
New-HTMLChart -Title "Windows Major" {
|
|
New-ChartToolbar -Download
|
|
New-ChartEvent -DataTableID 'WindowsV' -ColumnID 0
|
|
foreach ($line in $linesMajor) {
|
|
$total = ($line.Values | Measure-Object -Sum).Sum
|
|
New-ChartDonut -Name $($line.Version) -Value $total
|
|
}
|
|
}
|
|
}
|
|
New-HTMLPanel {
|
|
New-HTMLTable -DataTable $WindowsMajorMap -DataTableID 'WindowsV' -HideFooter
|
|
}
|
|
}
|
|
}
|
|
|
|
# Onglet Hardware
|
|
New-HTMLTab -Name 'Model' {
|
|
New-HTMLSection -HeaderText 'Hardware' {
|
|
New-HTMLPanel {
|
|
New-HTMLChart -Title "Version" {
|
|
New-ChartToolbar -Download
|
|
New-ChartEvent -DataTableID 'Modelcount' -ColumnID 1
|
|
foreach ($groupe in $Modelscount) {
|
|
New-ChartDonut -Name $($groupe.Name) -Value $($groupe.Count)
|
|
}
|
|
}
|
|
New-HTMLPanel {
|
|
New-HTMLTable -DataTable $WorkstationModels -DataTableID 'Modelcount' -HideFooter
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
# Pied de page
|
|
New-HTMLFooter {
|
|
New-HTMLText -Text "Date of this report (GMT time): $(Get-Date)" -Color Blue -Alignment Center
|
|
}
|
|
|
|
} -FilePath $Exporthtml -Online
|