Nagios: Superviser les certificats dans Windows

L’objectif de ce plugin pour Nagios est de superviser l’état des certificats, et leur date d’expiration en particulier (oui, je ne fais pas que du SCOM malgré un ouvrage ENI dessus!)

J’utilise l’agent nsclient++ sur les serveurs afin de pouvoir exécuter des scripts PowerShell entre autre. On a donc:

Nagios => check_nrpe => script powershell => retour nagios

Cela fonctionne également sur les serveurs Core.

Windows contient des certificats déjà expiré depuis longtemps. Le script contient une blacklist afin de les ignorer.

Configuration testée

Linux:

  • Centos 6.4 x64
  • Nagios 3.4.4
  • check_nrpe 2.13
  • Centreon 2.4.2

Windows:

  • Windows Server 2003 / 2008 R2 / 2012
  • nsclient++ 0.4.1 x64 et x86
  • Serveurs Core et normaux

Arguments du script

  • checkMyStore (oui par défaut)
  • checkRootStore (oui par défaut)
  • checkCAStore (oui par défaut)
  • checkAuthRootStore (oui par défaut)
  • checkSharePointStore (oui par défaut)
  • expireInDays (60 jours par défaut)
  • maxWarn (avertissement si supérieur)
  • maxCrit (Critique si supérieur)

Pour chaque store, la réponse doit être un booléen ($true /$false ou 1/0)

expireInDays,maxWarn et maxCrit doivent être des entiers

Exemples d’utilisation

Exemple en exécution directe PowerShell:

PS C:Program FilesNSClient++scripts> . .lotp_check_certificates.ps1
CRITICAL: www.lotp.fr:2013/06/30
PS C:Program FilesNSClient++scripts>

Exécution NRPE:

[root~]# /usr/lib64/nagios/plugins/check_nrpe -H myserver -n -c check_certificate -a $true $true $true $true $true 60 0 0

CRITICAL: www.lotp.fr:2013/06/30

[root~]#

Installation:

Sur les Windows:

  • Activer l’exécution de scripts PowerShell non signés : Set-ExecutionPolicy RemoteSigned
  • copier le script dans C:Program FilesNSClient++scripts
  • Ajouter dans le fichier nsclient.ini:
    • [/settings/external scripts/wrapped scripts]
      check_certificate=lotp_check_certificate.ps1 $ARG1$ $ARG2$ $ARG3$ $ARG4$ $ARG5$ $ARG6$ $ARG7$ $ARG8$

Configuration:

Par exemple, sur Centreon, en ajoutant la commande:

$USER1$/check_nrpe -H $HOSTADDRESS$ -n -c check_certificate -a $ARG1$ $ARG2$ $ARG3$ $ARG4$ $ARG5$ $ARG6$ $ARG7$ $ARG8$

Téléchargement

(enlever le .txt à la fin)

lotp_check_certificates.ps1

Code source en direct si le téléchargement ne passe pas:

 

# ====================================================================
# Check certificates health state
# Author: Mathieu Chateau - LOTP
# mail: mathieu.chateau@lotp.fr
# version 0.1
# ====================================================================

#
# Require Set-ExecutionPolicy RemoteSigned.. or sign this script with your PKI 
#

# ============================================================
#
#  Do not change anything behind that line!
#
param 
(
	[bool]$checkMyStore=$true,
	[bool]$checkRootStore=$true,
	[bool]$checkCAStore=$true,
	[bool]$checkAuthRootStore=$true,
	[bool]$checkSharePointStore=$true,
	[int]$expireInDays=60,
	[int]$maxWarn = 1,
	[int]$maxError = 0

)

# blacklist all third party known expired certificates in root & co, on Windows Server 2003, 2008 & 2012
$blacklist=@(
"109F1CAED645BB78B3EA2B94C0697C740733031C",
"12519AE9CD777A560184F1FBD54215222E95E71F",
"127633A94F39CBF6EDF7C7BF64C4B535E9706E9A",
"18F7C1FCC3090203FD5BAA2F861A754976C8DD25",
"23EF3384E21F70F034C467D4CBA6EB61429F174E",
"245C97DF7514E7CF2DF8BE72AE957B9E04741E85",
"24A40A1F573643A67F0A4B0749F6A22BF28ABB6B",
"24BA6D6C8A5B5837A48DB5FAE919EA675C94D217",
"2B84BFBB34EE2EF949FE1CBE30AA026416EB2216",
"3A850044D8A195CD401A680C012CB0A3B5F8DC08",
"4463C531D7CCC1006794612BB656D3BF8257846F",
"47AFB915CDA26D82467B97FA42914468726138DD",
"4BA7B9DDD68788E12FF852E1A024204BF286A8F6",
"4D8547B7F864132A7F62D9B75B068521F10B68E3",
"4DF13947493CFF69CDE554881C5F114E97C3D03B",
"4EF2E6670AC9B5091FE06BE0E5483EAAD6BA32D9",
"4F65566336DB6598581D584A596C87934D5F2AB4",
"51C3247D60F356C7CA3BAF4C3F429DAC93EE7B74",
"53DECDF3BC1BDE7C9D1CEDAE718468CA20CC43E7",
"587B59FB52D8A683CBE1CA00E6393D7BB923BC92",
"5E997CA5945AAB75FFD14804A974BF2AE1DFE7E1",
"637162CC59A3A1E25956FA5FA8F60D2E1C52EAC6",
"6690C02B922CBD3FF0D0A5994DBD336592887E3F",
"67EB337B684CEB0EC2B0760AB488278CDD9597DD",
"687EC17E0602E3CD3F7DFBD7E28D57A0199A3F44",
"688B6EB807E8EDA5C7B17C4393D0795F0FAE155F",
"68ED18B309CD5291C0D3357C1D1141BF883866B1",
"720FC15DDC27D456D098FABF3CDD78D31EF5A8DA",
"7613BF0BA261006CAC3ED2DDBEF343425357F18B",
"7A74410FB0CD5C972A364B71BF031D88A6510E9E",
"7AC5FFF8DCBC5583176877073BF751735E9BD358",
"7B02312BACC59EC388FEAE12FD277F6A9FB4FAC1",
"7CA04FD8064C1CAA32A37AA94375038E8DF8DDC0",
"7D7F4414CCEF168ADF6BF40753B5BECD78375931",
"7F88CD7223F3C813818C994614A89C99FA3B5247",
"838E30F77FDD14AA385ED145009C0E2236494FAA",
"8977E8569D2A633AF01D0394851681CE122683A6",
"8B24CD8D8B58C6DA72ACE097C7B1E3CEA4DC3DC6",
"9078C5A28F9A4325C2A7C73813CDFE13C20F934E",
"90DEDE9E4C4E9F6FD88617579DD391BC65A68964",
"96974CD6B663A7184526B1D648AD815CF51E801A",
"9845A431D51959CAF225322B4A4FE9F223CE6D15",
"9BACF3B664EAC5A17BED08437C72E4ACDA12F7E7",
"9FC796E8F8524F863AE1496D381242105F1B78F5",
"A1505D9843C826DD67ED4EA5209804BDBB0DF502",
"A399F76F0CBF4C9DA55E4AC24E8960984B2905B6",
"A3E31E20B2E46A328520472D0CDE9523E7260C6D",
"A5EC73D48C34FCBEF1005AEB85843524BBFAB727",
"B19DD096DCD4E3E0FD676885505A672C438D4E9C",
"B533345D06F64516403C00DA03187D3BFEF59156",
"B6AF5BE5F878A00114C3D7FEF8C775C34CCD17B6",
"B72FFF92D2CE43DE0A8D4C548C503726A81E2B93",
"CFDEFE102FDA05BBE4C78D2E4423589005B2571D",
"D29F6C98BEFC6D986521543EE8BE56CEBC288CF3",
"DBAC3C7AA4254DA1AA5CAAD68468CB88EEDDEEA8",
"E38A2B7663B86796436D8DF5898D9FAA6835B238",
"EC0C3716EA9EDFADD35DFBD55608E60A05D3CBF3",
"EF2DACCBEABB682D32CE4ABD6CB90025236C07BC",
"F5A874F3987EB0A9961A564B669A9050F770308A",
"F88015D3F98479E1DA553D24FD42BA3F43886AEF")

$output=""
$outputNames=""
$countMyStore=0
$countRootStore=0
$countCAStore=0
$countAuthRootStore=0
$countSharePointStore=0
$countTotal=0

$allCerts=Get-ChildItem -Path cert: -Recurse | ? {
($_.Notafter -lt (get-date).AddDays($expireInDays)) -and 
($_.PSPParentPath -notmatch "Disallowed") -and
($blacklist -notcontains $_.Thumbprint)} | select NotAfter,FriendlyName,PSParentPath

function outputCert ($temp)
{
	$outputTemp=""
	foreach ($t in $temp)
	{
		$outputTemp+=$t.FriendlyName+":"+(get-date -Date $t.NotAfter -format "yyyy/MM/dd")+" "
	}
	return $outputTemp
}
# check params if provided

if($checkMyStore)
{
	$temp=@($allCerts | ? {$_.PSParentPath -match "\My$"})
	$countMyStore=$temp.Count
	if($temp.Count -gt 0)
	{
		$outputNames+=outputCert $temp
	}
}
if($checkRootStore)
{
	$temp=@($allCerts | ? {$_.PSParentPath -match "\Root$"})
	$countRootStore=$temp.Count
	if($temp.Count -gt 0)
	{
		$outputNames+=outputCert $temp
	}
}
if($checkCAStore)
{
	$temp=@($allCerts | ? {$_.PSParentPath -match "\CA$"})
	$countCAStore=$temp.Count
	if($temp.Count -gt 0)
	{
		$outputNames+=outputCert $temp
	}
}
if($checkAuthRootStore)
{
	$temp=@($allCerts | ? {$_.PSParentPath -match "\AuthRoot$"})
	$countAuthRootStore=$temp.Count
	if($temp.Count -gt 0)
	{
		$outputNames+=outputCert $temp
	}
}
if($checkSharePointStore)
{
	$temp=@($allCerts | ? {$_.PSParentPath -match "\SharePoint$"})
	$countSharePointStore=$temp.Count
	if($temp.Count -gt 0)
	{
		$outputNames+=outputCert $temp
	}
}

foreach ($var in (Get-Variable -Name "count*Store"))
{
	$countTotal+=$($var).Value
}

if($countTotal -gt $maxError)
{
	$state="CRITICAL"
	$exitcode=2
}
elseif($countTotal -gt $maxWarn)
{
	$state="WARNING"
	$exitcode=1
}
else
{
	$state="OK"
	$exitcode=0
}
$output=$state+": "+$outputNames

Write-Host $output
exit $exitcode

Convertisseur USB vers port série sous 2008R2 / 64 bit nickel chrome!

Suite à des problèmes d’accès sur un switch PowerConnect 6224, j’ai eu besoin d’accéder en port série..Vous avez, le truc qu’on utilise plus, la preuve tous les nouveaux portables en ont plus ! Pour savoir si un modèle de portable est vieux, il suffit de savoir s’il a encore un port série !

Il y a quelques années j’avais acheté un convertisseur USB/port série Belkin, mais pas de driver signé, et encore moins 64 bit. Par hasard, j’en ai trouvé un super bien !

  • Fonctionne sur 2008 R2, et donc 64 bit
  • Fonctionne sur MacOS X 10.6.2 (donc 64 bit encore)
  • Il possède une rallonge ce qui ne gâche rien

Convertisseur usb port série

Le constructeur est MCL Samar, je l’ai trouvé chez Surcouf (24.99€). Sur la boite, il y avait bien écrit « Windows 7 » mais je m’attendais à un pilote non signé, et donc pas 64 bit.
Que nenni, ils sous valorisent la qualité de leur travail:

  • Il fonctionne même sur 2008 R2 (pas de fichier ini avec une section qui ne s’applique qu’à Windows 7)
  • Il fonctionne même sur Mac, avec le package d’installation et tout alors que ce n’est même pas écrit sur la boite!

Afin d’être complet, le seul problème concerne le CD fourni, qui est tout petit en taille, et donc le lecteur DVD du macBook Air ne l’absorbe pas.

Je recommande vivement ce produit à tous ceux qui ont un portable et qui trimballe un câble cisco « au cas où » dans la sacoche !

WDS/MDT: enlever F12

Par défaut, pour démarrer depuis le réseau via WDS, il faut:

  • Indiquer pendant le bios de démarrer sur le réseau (F12 en général)
  • Une fois le bail DHCP obtenu, il faut de nouveau et rapidement presser F12 pour vraiment démarrer sur le réseau

Cette deuxième confirmation est une sécurité. Si l’ordre de boot positionne le réseau avant le disque dur, les machines essaieront tout le temps de démarrer via le réseau avant le disque dur. En général, on démarre sur le réseau uniquement pour installer le système d’exploitation, et ensuite tout le temps depuis le disque dur.

Moyennant d’avoir les bios correctement configurés, le deuxième F12 est en trop. Depuis WDS (2003 et 2008), il suffit de remplacer pxeboot.com par pxeboot.n12 pour supprimer le deuxième F12:

Pour rattraper un historique sur un parc existant, Dell et HP offre des outils centralisés pour paramétrer le bios des machines à distance (génération d’un exécutable à télé-distribuer en général):

Est-ce que vos serveurs/stations sont sous garantie ?

Il y a certains contextes où l’on ne dispose pas de cette information. Le parc en question est composé de serveurs Dell et HP. Ces deux fabricants proposent de vérifier cette information sans problème, mais seulement de façon unitaire (par 10 pour HP, mais pour un même numéro de produit). Un appel au support Gold donne le même résultat pour les deux, ils ne proposent pas d’autres moyens, et le support eux mêmes utilisent ces pages.

Pour Dell: http://support.euro.dell.com/support/topics/topic.aspx/emea/shared/support/my_systems_info/fr/details?c=fr&l=fr&s=gen
Pour HP: http://www13.itrc.hp.com/service/ewarranty/warrantyResults.do

Quand on a quelques serveurs ou stations, cela ne pose pas de problème. Mais quand il s’agit de vérifier 230 machines, cela se complique!

1/Récupérer les numéros de série des serveurs/stations

La première étape consiste à avoir la liste des machines où récupérer le numéro de série, par exemple depuis l’active directory avec Adfind.
J’ai crée le vbscript suivant, qui prend en argument un nom de serveur, et renvoi une ligne formatée pour un CSV, avec plusieurs informations dont l’asset tag HP ou Dell. Par exemple:

ServeurA;Dell Computer Corporation;PowerEdge 1850;SerialIci;;2;x86 Family 15 Model 4 Stepping 1;3220455424;
ServeurB;HP;ProLiant DL360 G5;SerialIci;;4;x86 Family 6 Model 23 Stepping 10;3487408128;

Le code VBScript:

-------------------------------------------------------------------------------------
Dim hostname,manufacturer,model,serial,assettag
Set objArgs = WScript.Arguments
strComputer = objArgs(0) 
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") 
Set colSettings = objWMIService.ExecQuery("SELECT * FROM Win32_ComputerSystem")
For Each objComputer in colSettings
 hostname= objComputer.Name
 manufacturer=objComputer.Manufacturer
 model=objComputer.Model
 memory= objComputer.TotalPhysicalMemory
 cpucount= objComputer.NumberOfProcessors
Next
Set colSettings = objWMIService.ExecQuery _
 ("SELECT * FROM Win32_Processor")
For Each objProcessor in colSettings
 cputype=objProcessor.Description
Next
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_BIOS",,48) 
For Each objItem in colItems 
serial=objItem.SerialNumber
Next
wscript.echo hostname & ";" & manufacturer & ";" & model & ";" & serial & ";" & assettag & ";" & cpucount & ";" & cputype & ";" & memory & ";"
-------------------------------------------------------------------------------------

Il reste ensuite a appeler ce script par machine:

for /f %s in (serveurs.txt) do cscript //NOLOGO serial.vbs %s >> serveurs.csv

2/Vérifier les garanties

On a donc maintenant un fichier CSV avec notamment le fameux serial par machine. Le reste va devenir un peu plus « artisanal », car on va:

  • Construire l’URL a appelé pour chacun des fabricants (avec le numéro de série en paramètre)
  • Récupérer la page Web (résultat de la recherche) en html avec wget. (Une page html par machine, le fichier ayant comme nom le numéro de série)
  • Parser les pages pour récupérer uniquement la date d’achat et fin de garantie.

Les étapes unitaires ne sont pas techniquement compliquée, mais nécessite un peu de temps. Plus on a de machines à vérifier, plus cela devient intéressant en terme de temps. D’autre part, on progresse toujours plus en prenant ce chemin qu’en faisant la même tâche 230 fois…

A/Construire les adresses

Une fois le fichier excel importé, on va utiliser les fonctions Excel (en anglais) pour créer l’url des pages. Cela suppose que les numéros de séries sont dans la colonne E.

Pour Dell:

=CONCATENATE("wget -F -O ";E3;" ""http://support.euro.dell.com/support/topics/topic.aspx/emea/shared/support/my_systems_info/fr/details?c=fr&l=fr&s=gen&~ck=anavml&servicetag=";E3;"""")

Le résultat est de la forme:

wget -F -O YYYYY "http://support.euro.dell.com/support/topics/topic.aspx/emea/shared/support/my_systems_info/fr/details?c=fr&l=fr&s=gen&~ck=anavml&servicetag=YYYYYY"

Pour HP:

=CONCATENATE("wget -F -O ";E3;" --post-data=""BODServiceID=NA&RegisteredPurchaseDate=&country=FR&productNumber=AAAAAA-AA&serialNumber2=&serialNumber3=&serialNumber4=&serialNumber5=&serialNumber6=&serialNumber7=&serialNumber8=&serialNumber9=&serialNumber10=&x=31&y=12&serialNumber1=";E3;"""";" http://www13.itrc.hp.com/service/ewarranty/warrantyResults.do")

Il faut remplacer AAAAAA-AA par le product part.

Le résultat est de la forme:

wget -F -O YYYYYY --post-data="BODServiceID=NA&RegisteredPurchaseDate=&country=FR&productNumber=AAAAAA-AA&serialNumber2=&serialNumber3=&serialNumber4=&serialNumber5=&serialNumber6=&serialNumber7=&serialNumber8=&serialNumber9=&serialNumber10=&x=31&y=12&serialNumber1=YYYYYYYY"http://www13.itrc.hp.com/service/ewarranty/warrantyResults.do

B/Récupérer les pages Web

Il suffit de copier/coller le résultat des concaténations dans un .bat. Wget pour Windows est téléchargeable ici par exemple.

Le répertoire courant du .bat se rempli de fichiers portant comme nom chaque numéro de série.

Vous devez d’abord faire tous les Dell puis tous les HP afin de séparer les fichiers.

C/Parser les pages Web

J’ai commencé l’informatique sur Unix/Linux. Pour se qui est de parser des fichiers textes, j’ai gardé mes habitudes sed/awk/grep. Pour faire cela, j’utilise Cygwin sur Windows, qui est gratuit.

Parser les pages HTML pour Dell:

for serial in $(ls -1);do
achat=`cat $serial | awk '{FS="</table>";print $2}' | awk '{FS="<td";print $7}' | grep class | cut -d'>' -f2 | cut -d'<' -f1`
garantie=`cat $serial | awk '{FS="contract_oddrow\">";print $5}' | cut -d'<' -f1 | grep "/"`
echo "$serial ; $achat ; $garantie" >>dell_output.csv
done

Parser les pages HTML pour HP:

for serial in $(ls -1);do
achat=`cat $serial | sed "s/[\t]//g" | grep '^[0-9]\{2\}' | head -1`
garantie=`cat $serial | sed "s/[\t]//g" | grep '^[0-9]\{2\}' | head -2 | tail -1`
echo "$serial ; $achat ; $garantie" >> hp_output.txt
done

Il ne reste plus qu’à faire le rapprochement via les numéros de séries dans Excel 🙂

Tips and tricks du moment

Voici quelques commandes que j’ai utilisé cette semaine…Puisque cela m’a aidé, peut être que cela vous aidera aussi !

Besoin: connaître les utilisateurs qui n’utilisent pas le mode mise en cache de outlook.
Solution: Exchange 2007 possède un cmdlet PowerShell qui correspond tout à fait:

Get-LogonStatistics -server MonServeurExchange | where {$_.ClientMode -eq "Classic"} |FL ClientName

Besoin: Collecter les adresses IP assignées aux serveurs.
Solution:

  • Créer un fichier texte contenant un nom de serveur par ligne, par exemple en récupérant tous les objets AD ayant pour OS « Windows Servers » via adfind
  • Utiliser PowerShell + psexec pour récupérer le résultat de ipconfig /all sur chaque serveur

Le « script » powershell est le suivant:

———————————————————————————————-

get-content servers.txt | foreach-object {
$server=$_
$ip=.\psexec \\$server ipconfig /all| where { $_ -match "IP Address"} | %{$_  -replace "IP Address. . . . . . . . . . . . : ","$server;"}
Write-Output $ip >> servers_ipconfig.txt
}
———————————————————————————————-
Cette méthode, bien que très basique a certains avantages:
  • On récupère les informations en « live » sans reposer sur des relevés pouvant être obsolètes
  • Tout es ramassé, IP via NLB, carte réseau privée (heartbeat…), ip d’un tunnel VPN…
  • psexec permet de spécifier un login/pass quand on est hors domaine
  • Elle ne nécessite aucun agent sur les serveurs (SCCM, Altiris…)
Elle a au moins un inconvénient, il faut adapter la chaîne  de caractère « IP Address » à la langue de vos systèmes d’exploitation.
Si vous êtes allergiques à PowerShell, où qu’il n’est pas disponible depuis votre environnement, une variante en MSDOS:
for /f %s in (servers.txt) do echo %s >>ipall.txt && psexec \\%s ipconfig /all | findstr "Address" | findstr "IP" >> ipall.txt

BGI info: l’erreur avec succès sans succès…

Je n’avais pas utilisé bginfo de sysinternals depuis quelques temps. Comme d’hab, je mets un fond avec notamment le logo de l’entreprise, et là surprise au moment de l’enregistrement:
bginfo
(Error saving settings to registry: The operation completed sucessfully)

Pour les non anglophones, il y a donc une erreur à l’enregistrement dans la base de registre, mais l’opération à réussi…Surprenant hein ?
Evidemment, grosse déception, point de fichier bgi…

Contexte:

  • Windows Vista SP1 32 bit
  • dernier bginfo (4.15)
  • Avec et sans élévation de privilège (comment ça tout de suite on accuse UAC?)

Que faire quand un outil sysinternal échoue ? Utiliser un autre outil Sysinternal pour diagnostiquer !
Process monitor
montre notamment une erreur pour « ressource insuffisante« :

bginfo_processmonitor

Process explorer montre que le système est utilisé et manque un peu de ressource (quoi que, encore 742Mo de ram disponible tout de suite)
procexp

J’essaye sur ma station avec 8Go de ram, idem…Windows XP: idem!

Finalement, j’ai réduit et importé de nouveau l’image, fonctionne nickel.

Je me suis permis un petit mail à Mark Russinovich…Retour une heure plus tard:

« Thanks for the bug report, Mathieu. It looks like Bginfo was trying to write 7MB to the registry.« 

Cygwin1.dll et le mystérieux problème de version

Ayant commencé l’informatique sur Linux/FreeBSD, j’ai mes petites habitudes pour analyser des logs (awk/sed/cat/sort/uniq…).
Récemment cygwin, un port de shell Unix (bash) et outils diverses s’est mis à ne plus fonctionner:
cygwin

Il s’agit donc d’un problème sur cygwin1.dll. Effectivement, j’utilise aussi en ce moment un autre outil, John the ripper, qui a été porté sur Windows via cygwin.
La DLL pour JTR est beaucoup plus ancienne que mon installation de cygwin. Démarrer dans l’ordre inverse donne le même résultat, c’est JTR qui plante.

Procmon de Sysinternals indique bien que chaque programme charge la dll cygwin1.dll de son répertoire, mais JTR lis la DLL et fini par « Load image » alors que cygwin fait uniquement un « Load image »:

procmon

Process Explorer m’a permis de mettre en évidence d’où vient le problème. Cygwin1.dll utilise un handle de type section qui porte le même nom quelque soit la version de la DLL.

Voici les handles pour JTR:
cygwin1_processexplorer_jtr

Voici les handles pour cygwin lui même (bash.exe)cygwin1_processexplorer_cygwin

J’ai pu confirmer le diagnostique en utilisant une fonctionnalité de Process Explorer: fermer arbitrairement un handle:

cygwin1_processexplorer_jtr_close

Le shell Cygwin (bash.exe) se lance maintenant, alors que JTR tourne toujours. Je ne sais pas cependant si cela peut avoir des conséquences dans JTR:

cygwin

Notepad++: pourquoi faire compliquer quand on peut faire simple

Mon besoin était simple: j’avais un fichier avec 90 lignes de noms d’extensions de fichiers à mettre sur une seule ligne de texte. Après avoir chercher à le faire avec des expressions régulières, je me suis rendu compte que Notepad++ prévoit déjà ce cas de figure: ctrl + J

Il suffit donc de sélectionner les lignes à joindre ensemble, et de faire le raccourci clavier!

gestion des attributs mp3: Fixtunes c’est génial

Je cherchais depuis longtemps un outil à la fois efficace et ne demandant pas d’effort. J’ai trouvé mon bonheur: FixTunes. Ils proposent à la fois une version intégrées à Itunes d’Apple et une version standalone. Leur base de données est un aggrégat de plusieurs sources. Un taux de réussite est estimé, permettant de ne changer automatiquement que ceux ayant une forte probabilité. Le lui ai soumis une petite centaine de mp3 crados, là ou TheGodFather & co échouent. Il a pratiquement tout trouvé tout seul :). Il corrige l’auteur, l’album, le titre, la catégorie et ajoute la jaquette! Il supprime aussi les doublons!

Le poids des mots, le choc des captures d’écran:

24$ pour ce genre de service, je trouve ça bon marché !

C’est par ici :