Le blog technique

Toutes les astuces #tech des collaborateurs de PI Services.

#openblogPI

Retrouvez les articles à la une

Intune : Contrôle de la version des mises à jour de fonctionnalités (Feature updates)

Dans Intune, les stratégies de déploiement des mises à jour Windows sont découpés en deux principales catégories :

  • Update rings for Windows 10 and later
  • Feature updates for Windows 10 and later

Si vous créez une stratégies de déploiement Update rings for Windows 10 and later et la déployez sur un groupe d’ordinateurs, les appareils Windows 10/11 vont récupérer les dernières mises à jour de qualité mais aussi de fonctionnalités (Feature updates).

Exemple : un ordinateur sous Windows 10 20H2 passera à 21H2

Dans un scénario où on souhaite bloquer les mises à jour de fonctionnalités Windows 10/11 sur une version bien définie, il faut cibler les ordinateurs concernés par une stratégie Feature updates for Windows 10 and later.

Exemple : dans les paramètres de la stratégie, on définie la version 20H2 –> les ordinateurs seront bloqués sur cette version jusqu’à ce que l’administrateur choisisse de les mettre à jour vers une version ultérieure de Windows.

Tant que la version de fonctionnalités reste statique, les ordinateurs peuvent continuer à installer les mises à jour de qualité et de sécurité disponibles pour leur version de fonctionnalité.

Windows Server – Collecter des logs de crash applicatifs avec Windows Error Reporting

Windows Error reporting aussi abrégé WER a été introduit depuis Windows Vista et permet de générer un fichier de dump lorsqu’un processus crash. C’est particulièrement utile car tous les processus ne génèrent pas forcément leur propre logs.

 

Identifier le processus fautif

L’identification du processus qui crash se fait à l’aide du gestionnaire d’événement ou event viewer en anglais. Il permet d’accéder à plusieurs informations du crash tel que l’heure et le nom du processus en erreur.

Dans l’exemple suivant, on voit que c’est une défaillance du process lsass.exe qui fait planter la machine et le module responsable du crash de lsass.exe est ntdll.dll

 

Activer la génération de crash dump pour le processus en erreur

  1. Ouvrir l’éditeur de registre regedit sur le serveur qui est concerné par le crash
  2. Naviguer jusqu’à HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps
  3. Créer une nouvelle Key qui a comme valeur le nom du processus défaillant, dans notre exemple lsass.exe
  4. Dans la précédente clé, créer un premier DWORD (32-bit)
    1. Name : DumpCount
    2. Valeur : le nombre de crash dump a sauvegarder, par exemple 5
  5. Créer un deuxième DWORD (32-bit) value
    1. Name : DumpType
    2. Valeur : 2 cela permet de générer un full crash dump, celui-ci est le plus complet
  6. Créér une String value
    1. Name : DumpFolder
    2. Valeur : le chemin complet du dossier qu’il faudra créer et qui contiendra les dumps, par exemple c:\temp
  7. Créer un dossier temp dans le disque C:

 

Récupérer le fichier de log et l’analyser

Au prochain crash du processus, un fichier de log sera créé dans le dossier choisi dans la base de registre.

Pour pouvoir lire les fichiers de log, il est nécessaire d’installer un outil tel que WinDbg

 

Supprimer la génération de fichiers de dump

Pour supprimer la génération de log, il faut supprimer la clé précédemment créée dans la base de registre, dans notre exemple cela reviendrait à supprimer la clé lsass.exe

 

Pour aller plus loin

Documentation officielle Microsoft sur l’activation de Windows Error Reporting

Powershell : WSUS Report Servers States

Voici un script qui vous permettra de réaliser un état des lieu sur les mises à jour de sécurité nécessaires pour l’ensemble de vos serveurs rattachés à un WSUS.

Attention : Prenez soins de modifier les variables suivantes :

  1. Sur la ligne 12 vous pouvez remplacer le « -30 » par un valeur plus élevé si vous souhaitez un delta plus large (le -30 correspondant à M – 1, et ainsi connaitre le nombre de mise à jours manquante à J-30 jours)
  2. Sur la ligne 14 $Alias (doit correspondra à l’alias renseigné dans votre DNS).
  3. Ligne 44 vous pouvez ajouter un -Credential (si vous n’exécutez pas ce script dans un contexte avec les droits nécessaires).

 

Ce dernier est une version pour un WSUS unique en mode autonome ou déconnecté, ne possédant pas de Downstram Server, je publierais une autre version pour ce cas de figure.

#################################
# Step 1 : Variables Definition #
#################################
#region - Variables
$RootFolder = "C:\Temp\WSUS"
$ResultFolder = "$RootFolder\Result"
$LogFolder = "$RootFolder\Logs"
$Archives = "$RootFolder\Archives"
$AllFolders = $RootFolder, $ResultFolder, $LogFolder, $Archives
$LogFile = "$LogFolder\GeneralLog.log"
$Date = Get-Date -Format M
$TargetDate = ((Get-Date).AddDays(-30)).ToString('MM/dd/yyyy')
$Array = @()
$Alias = "wsus"

# Folders creation
foreach ($Folder in $AllFolders) {
    If (!(Test-Path $Folder)) {
        New-Item $Folder -ItemType Directory
    }
}

# Old Files deletion
Get-ChildItem $LogFolder | Remove-Item -Force
Get-ChildItem $ResultFolder | Remove-Item -Force
#endregion - Variables

###############################
# Step 2 : Locate WSUS Server #
###############################
#region - Locate WSUS Server
Write-Output "Trying to locate WSUS server" | Add-Content $LogFile
Try {
    $WSUSServer = Resolve-DnsName $Alias -ErrorAction Stop | select -ExpandProperty Name -Last 1
    Write-Output "Successfully locate WSUS server" | Add-Content $LogFile
}
Catch {
    Write-Output "Failed to locate WSUS server" | Add-Content $LogFile
}

# Wsus Role Check
Write-Output "Verifying WSUS server role installation" | Add-Content $LogFile
Try {
    $WsusRoleInstalled = Invoke-Command -ComputerName $WSUSServer -ScriptBlock {Get-WindowsFeature | Where-Object {($_.InstallState -eq "Installed") -and ($_.Name -like "UpdateServices")}} -ErrorAction Stop | Select-Object -Property Installed
    Write-Output "Successfully Run the query" | Add-Content $LogFile
    If ($WsusRoleInstalled.Installed -ne $true) {
        # End of Script
        Write-Output "WSUS Server not found" | Add-Content $LogFile
        Exit
    }
}
Catch {
    Write-Output "Failed to verify WSUS server role installation" | Add-Content $LogFile
    Exit
}
#endregion - Locate WSUS Server

############################
# Step 3 : WSUS Connection #
############################
#region - WSUS Connection
# Try on default port 8530
Try {
    $WsusPort = "8530"
    [void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
    $Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$false,$WsusPort)
    $Connection = $Wsus.Name
}
Catch {
    # Try on port 80
    Try {
        $WsusPort = "80"
        [void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
        $Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$false,$WsusPort)
        $Connection = $Wsus.Name
    }
    Catch {
        # Try on port 8531
        Try {
            $WsusPort = "8531"
            [void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
            $Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$true,$WsusPort)
            $Connection = $Wsus.Name
        }
        Catch {
            # Try on port 443
            Try {
                $WsusPort = "443"
                [void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
                $Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$true,$WsusPort)
                $Connection = $Wsus.Name
            }
            Catch {
                # End of Script
                Write-Output "WSUS Server connection failed on all ports" | Add-Content $LogFile
                Exit
            }
        }
    }
}
#endregion - WSUS Connection

###########################
# Step 4 : WSUS Reporting #
###########################
#region - WSUS Reporting
# Variables Definition
$computerscope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope
$updatescope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
$updateClassifications = $Wsus.GetUpdateClassifications() | Where-Object {$_.Title -eq "Security Updates"}
$UpdateScope.Classifications.AddRange($updateClassifications)
$Servers = $wsus.GetComputerTargets($computerscope) | Where-Object {($_.ComputerRole -eq "Server")}
$NBServers = $Servers.Count

Write-Output "WSUS Server has $NBServers to manage" | Add-Content $LogFile
$Servers | Foreach {
    $FullDomainName = $_.FullDomainName
    $WorkstationID = $_.Id
    $LastSyncClient = $_.LastSyncTime
    [STRING]$LastSyncResultClient = $_.LastSyncResult
    $LastReportedStatusTime = $_.LastReportedStatusTime
    $IPAddress = ($_.IPAddress).IPAddressToString
    $Id = $_.Id
    $Make = $_.Make
    $Model = $_.Model
    $OSLanguage = ($_.OSInfo).DefaultUILanguage
    $OSArchitecture = $_.OSArchitecture
    $OSFamily = $_.OSFamily
    $OSDescription = $_.OSDescription
    $ComputerTargetGroupIds = $_.ComputerTargetGroupIds
    $SyncsFromDownstreamServer = $_.SyncsFromDownstreamServer
    $UpdateServer = $_.UpdateServer.Name

    # Get AD Information
    Try {
        Write-Output "Trying to retrieve Active Directory Informations for $FullDomainName" | Add-Content $LogFile
        $CurrentServer = Get-ADComputer -Filter {DNSHostName -eq $FullDomainName} -Properties CanonicalName -ErrorAction Stop | Select-Object Enabled,CanonicalName,OperatingSystem,Name
        Write-Output "Successfully retrieve Active Directory Informations for $FullDomainName" | Add-Content $LogFile
    }
    Catch {
        Write-Output "Failed to retrieve Active Directory Informations for $FullDomainName" | Add-Content $LogFile
    }
    # Define state for Begining and End of year, plus a targeted date (here M-30)
    $updatescope.ToCreationDate=[DATETIME]"01/31/2022"
    $KBToInstallJanuary = $wsus.GetSummariesPerComputerTarget($updatescope,$computerscope) | where {($_.ComputerTargetId -eq $WorkstationID)} |Select-Object -ExpandProperty NotInstalledCount
    $updatescope.ToCreationDate=[DATETIME]"12/31/9999"
    $KBToInstallUpToDate = $wsus.GetSummariesPerComputerTarget($updatescope,$computerscope) | where {($_.ComputerTargetId -eq $WorkstationID)} |Select-Object -ExpandProperty NotInstalledCount
    $updatescope.ToCreationDate=[DATETIME]"$TargetDate"
    $KBToInstallJ30 = $wsus.GetSummariesPerComputerTarget($updatescope,$computerscope) | where {($_.ComputerTargetId -eq $WorkstationID)} |Select-Object -ExpandProperty NotInstalledCount
    $IPAddress = ($_."IPAddress").IPAddressToString
    
    $Array += New-Object psobject -Property @{
        FullDomainName = $FullDomainName
        WorkstationID = $Id
        LastSyncClient = $LastSyncClient
        LastSyncResultClient = $LastSyncResultClient
        LastReportedStatusTime = $LastReportedStatusTime
        IPAddress = $IPAddress
        Enabled = $CurrentServer.Enabled
        CanonicalName =$CurrentServer.CanonicalName
        Name = $CurrentServer.Name
        KBNeededInJanuary = $KBToInstallJanuary
        KBNeededLastMonth = $KBToInstallJ30
        KBNeededToBeUpToDate = $KBToInstallUpToDate
        Id = $Id
        Make = $Make
        Model = $Model
        OSLanguage = $OSLanguage
        OSArchitecture = $OSArchitecture
        OSFamily = $OSFamily
        OSDescription = $OSDescription
        ComputerTargetGroupIds = $ComputerTargetGroupIds
        SyncsFromDownstreamServer = $SyncsFromDownstreamServer
        UpdateServer = $UpdateServer
    }
    # Release
    $FullDomainName = $null
    $WorkstationID = $null
    $LastSyncClient = $null
    $LastSyncResultClient = $null
    $LastReportedStatusTime = $null
    $IPAddress = $null
    $Id = $null
    $Make = $null
    $Model = $null
    $OSLanguage = $null
    $OSArchitecture = $null
    $OSFamily = $null
    $OSDescription = $null
    $ComputerTargetGroupIds = $null
    $SyncsFromDownstreamServer = $null
    $CurrentServer = $null
    $UpdateServer = $null
    $KBToInstallJanuary = $null
    $KBToInstallUpToDate = $null
    $KBToInstallJ30 = $null
}
#endregion - WSUS Reporting

########################
# Step 4 : Export Data #
########################
#region - Export Data
$Array | select WorkstationID,Make,Model,OSFamily,OSDescription,OSArchitecture,OSLanguage,IPAddress,FullDomainName,Name,CanonicalName,Enabled,SyncsFromDownstreamServer,UpdateServer,LastReportedStatusTime,LastSyncClient,LastSyncResultClient,KBNeededInJanuary,KBNeededLastMonth,KBNeededToBeUpToDate | Export-Csv $ResultFolder\Report.csv -Delimiter ";" -Encoding UTF8 -NoTypeInformation

#endregion - Export Data