Powershell : vérification de l’installation d’un KB

Etant donné que je participe à la préparation d’une campagne de patchs suite aux failles Meltdown et Spectre, je me suis développé rapidement un script qui me permettra de vérifier si le(s) KB que nous allons installer l’auront bien été sur les systèmes en question.

Param
([string]$m,[string]$id)
$id = "KB"+$id
$KBlist = Get-Hotfix -ComputerName $m | Select HotfixID
foreach ($KB in $KBlist)
{
if ([string]$KB.HotfixID -ne $id){continue}
echo $id" effectif sur "$m
}

On exécutera simplement le script avec deux arguments :

.\win_kbcheck.ps1 -m <NomMachine> -id <NoDeKB>

Si le script ne retourne rien, c’est que le numéro de patch paramétré n’est pas installé sur la machine.

Powershell : listing des disques locaux d’une machine distante et export CSV

Pour un besoin ponctuel, j’ai eu à faire un recensement des disques locaux et de leur état sur de multiples machines distantes. J’ai donc réalisé un script Powershell permettant de les lister et d’obtenir d’autres informations et d’en faire un export CSV qui devient finalement exploitable sous Excel grâce à la conversion (onglet Données > Convertir).

Ce script utilise WMI, il est donc important que le service soit en fonctionnement sur les machines cibles et que le pare-feu autorise la communication. Si il s’agit du pare-feu Windows, cela est très facile dans les réglages de ce dernier :

Pour autoriser WMI, on coche les cases « Domaine » ou « Domestique/entreprise » en fonction de sa situation.

A noter que le script commenté est également téléchargeable sur mon miroir de téléchargement.

Le script nécessite de placer simplement en paramètre le nom de la machine en question. On l’appellera par l’instruction suivante :

PS> .\win_listdisks.ps1 server.local
Param
    ([string]$Comp)
    
$output = @()
$DiskList = Get-WmiObject Win32_LogicalDisk -ComputerName $Comp
foreach ($Disk in $DiskList){
    if ($Disk.DriveType -ne 3){continue}
    $DiskLetter = $Disk.DeviceID
    $DiskName = $Disk.VolumeName
    $DiskSize = $Disk.Size
    $DiskFS = $Disk.FreeSpace
    $DiskSize = [long]$DiskSize/1073741824
    $DiskFS = [long]$DiskFS/1073741824
    $DiskPerc = ($DiskFS/$DiskSize)*100
    
    echo "Disk $DiskLetter"
    echo "Name: $DiskName"
    echo "Size: $DiskSize"
    echo "Free: $DiskFS"
    echo "Percentage Free: $DiskPerc"
    
	$DiskObj = New-Object PSCustomObject
	$DiskObj | Add-Member -Type NoteProperty -Name 'DiskLetter' -Value $DiskLetter
	$DiskObj | Add-Member -Type NoteProperty -Name 'DiskName' -Value $DiskName
	$DiskObj | Add-Member -Type NoteProperty -Name 'DiskSize' -Value $DiskSize
	$DiskObj | Add-Member -Type NoteProperty -Name 'DiskFS' -Value $DiskFS
	$DiskObj | Add-Member -Type NoteProperty -Name 'DiskPerc' -Value $DiskPerc
	$output+=$DiskObj
}
$output | Export-CSV disks-$comp.csv

Ensuite, dans Excel, en convertissant le CSV en tableau en choisissant la virgule comme élément délimitant les données, on obtient quelque chose de lisible :

Harmonisation de la synchronisation du temps sur Debian et Windows

Aujourd’hui j’ai pris un peu le temps de mettre à plat ma configuration concernant les horloges et la synchronisation de celles-ci sur les différents serveurs que je fais fonctionner sur mon environnement personnel. Les horloges étant disparates sur les systèmes, j’ai donc défini la configuration suivante :

  • L’hyperviseur ESXi se synchronisant sur des serveurs NTP publics : http://www.pool.ntp.org/ ;
  • Mes deux contrôleurs de domaine Windows se synchronisant sur ces mêmes serveurs NTP ;
  • Toutes mes autres machines se synchronisant sur mes contrôleurs de domaine.

Sur Windows, j’ai développé un script Powershell – qu’il m’aurait été possible d’appliquer via GPO – qui s’occupe de modifier la configuration dans la base de registre afin que le serveur utilise comme source les contrôleurs de domaine. Ce script (disponible sur mon miroir de téléchargement) nécessite évidemment des droits d’administration sur le serveur pour être exécuté – on s’assurera de remplacer time-srvX par le nom du serveur de temps, en conservant bien ,0x1 et en séparant les noms de serveurs par un espace :

Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Services\w32time\Config -name « AnnounceFlags » -value « 5 »
Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Services\w32time\Parameters -name « Type » -value « NTP »
Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Services\w32time\TimeProviders\NtpServer -name « Enabled » -value « 1 »
Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Services\w32time\Parameters -name « NtpServer » -value « time-srv1,0x1 time-srv2,0x1 »

A noter qu’en fonction de la politique d’exécution des scripts sur la machine, il est possible que le script ne s’exécute pas, on va donc l’autoriser si cette politique n’est pas gérée au niveau du domaine.

Set-ExecutionPolicy Unrestricted

Une fois ces instructions interprétées par Powershell, on redémarre le service de temps :

net stop w32time
net start w32time

Puis, on peut s’assurer que la source est correcte et faire une synchronisation grâce aux commandes suivantes – l’interrogation de la source devrait renvoyer l’un des serveurs spécifiés plus haut :

w32tm /query /source
w32tm /resync

Ensuite, sur mes machines Debian, grâce au paquet ntpdate, il est possible de spécifier au système l’adresse d’un serveur sur lequel synchroniser l’horloge.

apt-get install ntpdate

On modifie le fichier de configuration :

nano /etc/default/ntpdate

Afin de forcer ntpdate a bien utiliser ce fichier de configuration, on passe le paramètre NTPDATE_USE_NTP_CONF à no, puis on modifie NTPSERVERS pour y intégrer les serveurs de temps, ce qui donne ceci :

NTPDATE_USE_NTP_CONF=no
NTPSERVERS= »time-srv1 time-srv2″

Et enfin, pour synchroniser la machine avec les serveurs tout juste renseignés :

ntpdate-debian

Powershell : Détection des comptes ayant un mot de passe expirant prochainement et envoi d’un rapport par mail

Aujourd’hui, je souhaitais me connecter à mes serveurs Windows dans mon nuage. Cela faisait quelques semaines que je ne m’étais pas connecté aux machines Windows, mais uniquement à ma machine de rebond qui me permet ensuite de prendre la main sur le réseau interne aux autres machines. Possédant deux comptes différents, j’ai été quelque peu pris au piège en m’apercevant que tous mes comptes, y compris celui d’administration, avaient leurs mots de passe expirés : impossible donc d’ouvrir une console AD ou une session sur l’AD directement avec mon compte pour y modifier mes mots de passe. Il a donc fallu que je me connecte sur l’ESX pour prendre la main directement en console sur l’AD et pouvoir accéder au prompt de login classique afin que Windows me propose naturellement de modifier mon mot de passe.

Changeant irrégulièrement mes mots de passe de mes trois comptes, le fait de changer le mot de passe d’un compte ne m’indique pas que les deux autres sont proches de l’expiration, et ne me connectant pas toujours sur les machines Windows de ma plateforme ni même l’AD, je n’ai pas les rappels habituels m’indiquant que j’arrive à la fin de la durée de vie pour mon mot de passe. Il est vrai que je pourrais tout simplement procéder au changement des trois password une fois pour toutes afin de partir sur un seul délai mais ce n’est pas ce qu’il y a de plus pratique.

Afin d’éviter d’avoir à refaire face à cette situation, j’ai écrit un script plutôt simple qui contrôle les comptes de l’AD et qui vérifie la date d’expiration des comptes dont le mot de passe n’est pas permanent, en envoyant un courriel avec un fichier contenant les noms des comptes dont il va falloir penser à s’occuper.

Import-Module ActiveDirectory

$From = « admin-win@localhost »
$To = « supervision@localhost »
$Smtp = « smtp.localdomain »
$SoonToExpireList = @()
$ReportFilePath = ‘c:\temp\exp.log’
$ReportFile = New-Item -ItemType File -path c:\temp\exp.log
$Proc = $false

$AccountArray = Get-AdUser -Filter {PasswordNeverExpires -eq « false »} -Properties msDS-UserPasswordExpiryTimeComputed | select samAccountName,msDS-UserPasswordExpiryTimeComputed

foreach ($Account in $AccountArray)
    {
    $ExpDate = [datetime]::FromFileTime($Account.’msDS-UserPasswordExpiryTimeComputed’)
    $NowDate = Get-Date
    $DiffDate = $ExpDate – $NowDate
    if ($DiffDate.Days -lt 15 -and $DiffDate.Days -gt 0)
        {
        $Proc = $true
        Add-Content -path $ReportFilePath -value ($Account.samAccountName)
        }
    }

if ($Proc -eq $true)
    {
    $MailString = « Bonjour, les mots de passe des comptes indiques dans le fichier en PJ expirent dans moins de 15 jours. »
    Send-MailMessage -From $From -To $To -Subject « Comptes aux mots de passe expirant prochainement » -SmtpServer $Smtp -Body $MailString -Attachments $ReportFilePath
    }   

Remove-Item $ReportFilePath

Bien entendu, il est possible d’améliorer ce script, en programmant l’envoi de mail lorsqu’il reste 7 jours, puis 3 jours, par exemple. Dans mon cas, le script est en exécution hebdomadaire, ce qui me laisse deux courriels pour prendre quelques minutes et m’occuper de changer mes password avant que mes comptes soient inaptes à ouvrir une session TS.

Le script est téléchargeable avec ses commentaires et prêt à l’emploi sur mon miroir de téléchargement.