samedi 8 décembre 2018

Powershell : copie de fichiers considérés comme anciens

Suite à une demande d'un collègue, j'ai réalisé un script Powershell réalisant une copie récursive de fichiers et dossiers si ceux-ci ont été créés, modifiés ou utilisés (au choix de l'utilisateur) depuis un nombre de jours spécifiés.

En reprenant la logique du script d'archivage automatique de fichiers d'événements Windows, il peut être possible de réaliser une mécanique d'archivage automatique de certains fichiers comme des logs par exemple. Les deux scripts (combinés en un seul) pourraient alors réaliser la copie dans un répertoire temporaire où ils seraient compressés avant d'être acheminés sur un répertoire réseau dédié.

Une version commentée est disponible en téléchargement 😊

function process{
Write-Host "Folders will be displayed in Cyan." -ForegroundColor "Cyan"
Write-Host "Files will be displayed in Green.`r`n" -ForegroundColor "Green"
foreach($item in $items){
if ($item.Attributes -eq "Directory") { Write-Host $item.FullName -ForegroundColor "Cyan" }
else { Write-Host $item.FullName -ForegroundColor "Green" }
$destination = $item.FullName.Substring($origpath.Length,$item.FullName.Length-$origpath.Length)
Copy-Item $item.FullName -Destination "$destpath\$destination" -Force
}
}
Write-Host "Old files archiving script"
Write-Host "=========================="
$origpath = "C:\source\"
$destpath = "C:\dest\"
$today = Get-Date
if (Test-Path -Path $destpath) { Write-Host "Destination directory already exists. Be careful as the script will overwrite any existing files." -ForegroundColor "Red" } else { New-Item -Path $destpath -ItemType "directory" | out-null }
$olderthan = Read-Host "Archive files older than X days"
Write-Host "1: Creation Date"
Write-Host "2: Modification Date"
Write-Host "3: Last Access Date"
$datetype = Read-Host "Kind of timestamp the script should use ? (1, 2 or 3)"
switch($datetype){
"1" { $items = Get-ChildItem $origpath -Recurse | Where-Object { $_.CreationTime -lt $today.AddDays(-$olderthan) } ; process }
"2" { $items = Get-ChildItem $origpath -Recurse | Where-Object { $_.LastWriteTime -lt $today.AddDays(-$olderthan) } ; process }
"3" { $items = Get-ChildItem $origpath -Recurse | Where-Object { $_.LastAccessTime -lt $today.AddDays(-$olderthan) } ; process }
}
Write-Host "Bye."

mercredi 5 décembre 2018

J'ai testé l'Intel Compute Stick

Naturellement passionné par les nouvelles technologies en général et curieux de nature, j'ai possédé un Raspberry Pi et un Banana Pi pour divers usages, mais je n'ai jamais vraiment été satisfait de ces appareils. En cause, le processeur non-x86 interdisant l'installation d'un OS Windows et les possibilités limitées des premiers modèles. Bien qu'ils aient beaucoup évolué depuis le temps (plus de 6 ans !), je n'étais pas prêt à en racheter un lorsque je cherchais un petit appareil compact pour me servir de media-center portable et de petite console pour du rétro-gaming. Idéalement, un Raspberry Pi fonctionnant sous recalOS aurait pu faire l'affaire mais j'utilise Plex en media center et je voulais tout de même un peu plus de polyvalence.

Je me souvins alors qu'Intel avait sorti des nano-PC fonctionnant directement sur n'importe quel téléviseur ou écran grâce à l'interface HDMI (et évidemment, une alimentation USB). Après un petit temps d'hésitation, je décide donc d'acquérir un Intel Compute Stick de deuxième génération.

Image Wikimedia Commons

Il s'agit donc d'une grosse clef HDMI, un peu plus imposante que la première Chromecast avant qu'elle ne devienne un galet. Elle se branche tout simplement sur le port HDMI d'un téléviseur ou d'un moniteur et est alimentée par un chargeur USB fourni (avec de multiples prises internationales). Une rallonge est fournie avec le stick et elle est bienvenue, offrant plus de latitude quant au branchement, surtout derrière une TV. Bien que le form factor soit compact et simple, la plupart des composants d'un laptop moderne sont présents : double port USB (2.0 et 3.0), Bluetooth, WiFi, lecteur de carte microSD. Le processeur est un petit Atom à 4 cores et 4 threads, suffisamment performant pour réaliser des tâches simples (j'y reviendrai plus tard), il est épaulé par 2 Go de mémoire vive DDR3 et 32 Go de stockage flash interne. Le tout est refroidi par un tout petit ventilateur audible de près mais relativement silencieux.

Le produit se veut utilisable out of the box, mais ne l'est pas vraiment. Comme tout PC Windows 10 (ici installé en 32 bits !), la phase de configuration finale est à la charge de l'utilisateur. Il faut donc s'armer de clavier et souris Bluetooth, ou bien de brancher un hub USB et de passer par du filaire (ce qui n'est pas vraiment idéal). Une fois cette étape terminée, Windows finit sa configuration et affiche le bureau. Il reste alors environ 17 Go d'espace libre sur la mémoire interne, l'extension par microSD étant alors nécessaire pour être un peu plus serein.

Windows (livré en Home, quel dommage !) fonctionne plutôt bien avec cette configuration légère. Pas de ralentissements dans les applications ni en surf internet ou en usage multimédia. Les applications semblent plus performantes dans leurs versions "Store", peut-être à cause de librairies plus optimisées. Le système démarre en une vingtaine de secondes à peu près ; à noter que le BIOS est facilement accessible pour protéger l'appareil, désactiver des ports ou la communication Bluetooth par exemple... ou encore démarrer sur un périphérique USB et installer un autre OS par exemple.

J'ai procédé à la mise à niveau vers une version Pro de Windows, afin de bénéficier principalement de la prise en main à distance. J'ai également mis à jour Windows vers la version la plus récente proposée pour l'appareil, sans dysfonctionnement majeur, même si cela a pris son temps. Le Bluetooth est devenu quelque peu capricieux cependant depuis la mise à jour, et la mise à jour du driver sur le site d'Intel n'a pas résolu le problème ; j'ai donc installé le driver Realtek correspondant, ce qui a résolu le problème. Il est important de noter que c'est la même puce qui gère le Bluetooth et le Wi-Fi, et que donc en fonction du nombre d'appareils appairés avec la machine, il peut y avoir un débit Wi-Fi plus faible. Je n'ai rien constaté de dramatique ou d'handicapant cependant avec un clavier et une souris sans-fil, un test de synchronisation OneDrive téléchargeant les données à plus de 2 Mo/s.

L'Intel Compute Stick dans cette version de base trouvable à environ 150 euros sur Amazon est un parfait appareil pouvant donner une seconde jeunesse à une TV ou comme petit PC d'appoint. Un usage media center est tout désigné car l'OS Windows permet l'installation de nombreuses applications en rapport, et la puce graphique capable de décoder du 1080p. Pour mon usage, le Stick peut remplacer une Chromecast (moins polyvalente) et un Raspberry Pi (contraignant avec son architecture ARM) ; suffisant pour de la prise en main à distance, de la bureautique légère ou des présentations, ce nano-PC a beaux arguments à faire valoir, pour un prix malheureusement élevé par rapport aux appareils qu'il peut remplacer, mais pas tout à fait dans les clous si on le considère comme un véritable PC... ce qu'il n'est pas non plus à cause de son format et de ses composants.

vendredi 30 novembre 2018

VMware et Powershell : rapport des versions d'hôtes vSphere

Voici un script permettant de lister les versions des hôtes vSphere présents dans un vCenter. Le premier mode liste tous les hôtes tandis que le deuxième permet de lister une version spécifique, majeure ou mineure. Par exemple, en saisissant "6", alors le script cherchera les serveurs en 6.x.x tandis qu'en envoyant "5.5", il cherchera les serveurs en 5.5.x. Dans tous les cas, un export CSV exploitable est réalisé. Naturellement, il est nécessaire que les modules Powershell de VMware soient déployés sur la machine exécutant le script (si ils ne le sont pas, il suffit simplement de télécharger PowerCli).

Import-Module VMware.VimAutomation.Core

function allhosts{
    Write-Host "Retrieving all hosts on vCenter $vcenter"
    $spheres = Get-VMHost
    process
}

function spechosts{
    Write-Host "Retrieving specific hosts on vCenter $vcenter."
    $reqver = Read-Host "Please input the desired version in one of those formats : 6, 6.0 or 6.0.0"
    if($reqver.Length -lt 5) { $reqver = "$reqver*" }
    $spheres = Get-VMHost | Where-Object {$_.Version -like $reqver}
    process       
}

function process{
    $path = "$env:temp\vmware-hostver-$vcenter.csv"
    $header = "Hostname,PowerState,Version"
    Add-Content -Value $header -Path $path
    foreach($vsphere in $spheres) {
        $row = $vsphere.Name+","+$vsphere.PowerState+","+$vsphere.Version
        Add-Content -Value $row -Path $path
    }
    Write-Host "Processing is done. Results are located in $path."
    explorer $env:temp
}

Write-Host "vSphere host version listing script"
Write-Host "===================================`r`n"
$vcenter = Read-Host "vCenter to connect to ?"
Connect-VIServer $vcenter | Out-Null
Write-Host "1: List all hosts and versions on this vCenter`r`n2: List only hosts running under a specific version"
$mode = Read-Host "Choice"
switch ($mode){
    1 { allhosts }
    2 { spechosts }
}
Disconnect-VIServer $vcenter -confirm:$false | Out-Null
Write-Host "Bye."

Le script est téléchargeable dans une version commentée. 💾

lundi 26 novembre 2018

Powershell : listing d'enregistrements DNS

J'ai développé un (plutôt deux, à vrai dire) script(s) Powershell permettant de remplacer la fonction de filtre présente sur la console DNS. En effet, celle-ci est un peu pénible à utiliser car il faut attendre que toute la zone soit chargée dans la console si le filtre n'est pas encore actif, puis il faut rafraîchir... et il est persistant après fermeture, ce qui fait qu'il faut réinitialiser le filtre et actualiser lorsqu'on souhaite revenir à une vision d'ensemble.

A l'exécution, le script demande le nom ou l'IP du serveur DNS à interroger, ainsi que la chaîne de caractères à trouver dans le nom de l'enregistrement. Le joker * est utilisable, ce qui permet à la fois de rechercher une expression ou une chaîne stricte.

La version basique du script renvoie ses résultats dans la console avec uniquement le nom de l'enregistrement :



Write-Host "=========================================="
Write-Host "DNS records listing script - Basic Version"
Write-Host "=========================================="
$dnsnode = Read-Host "DNS Server to query"
$lfseq = Read-Host "Character sequence to look for ('*' tokens accepted)"
Write-Host "Connecting to DNS Server and retrieving DNS zones"
$dnszones = Get-DNSServerZone -ComputerName $dnsnode | Where-Object {$_.IsReverseLookupZone -eq $false}
foreach($dnszone in $dnszones){
    Write-Host "Zone currently parsed:" $dnszone.ZoneName
    $dnsrecords = Get-DnsServerResourceRecord -ComputerName $dnsnode -ZoneName $dnszone.ZoneName | Where-Object {$_.HostName -like "$lfseq"} | ft HostName
    if($dnsrecords.length -gt 0) { $dnsrecords }
    else { Write-Host "No matching records found." }
    Write-Host "`r"
}
Write-Host "Parsing over."
Write-Host "Bye."

La version améliorée renvoie les résultats dans la console, mais génère un fichier CSV offrant plus d'informations (type d'enregistrement et données de l'enregistrement) et effectue une suppression des doublons : nécessaire car la commande Powershell peut renvoyer plusieurs fois le même enregistrement si il est dans une sous-zone. Par exemple, en considérant la zone infra.local, si un enregistrement s'appelle sql dans la sous-zone prod, il apparaîtra alors deux fois : une fois en tant que sql.prod et une fois en tant que sql.prod.infra.local.


Write-Host "============================================="
Write-Host "DNS records listing script - Enhanced Version"
Write-Host "============================================="
$dnsnode = Read-Host "DNS Server to query"
$lfseq = Read-Host "Character sequence to look for ('*' tokens accepted)"
$today = Get-Date -f yyyyMMdd
$path = "dns-$today.csv"
$csvheader = "Hostname,Zone,RecordType,RecordData"
Add-Content -Value $csvheader -Path $path
Write-Host "Connecting to DNS Server and retrieving DNS zones"
$dnszones = Get-DNSServerZone -ComputerName $dnsnode | Where-Object {$_.IsReverseLookupZone -eq $false}
foreach($dnszone in $dnszones){
    Write-Host "Zone currently parsed:" $dnszone.ZoneName
    $dnsrecords = Get-DnsServerResourceRecord -ComputerName $dnsnode -ZoneName $dnszone.ZoneName | Where-Object {$_.HostName -like "$lfseq"}  
    if($dnsrecords.length -gt 0){
        foreach($dnsrecord in $dnsrecords){
            Write-Host "Record: "$dnsrecord.Hostname
            switch($dnsrecord.RecordType){
                "A" {$recorddata = $dnsrecord.RecordData.IPv4Address.IpAddressToString}
                "CNAME" {$recorddata = $dnsrecord.RecordData.HostNameAlias}
            }
            if($dnsrecord.HostName.SubString($dnsrecord.HostName.Length-$dnszone.ZoneName.Length,$dnszone.ZoneName.Length) -ne $dnszone.ZoneName) {
                $row = $dnsrecord.Hostname+","+$dnszone.ZoneName+","+$dnsrecord.RecordType+","+$recorddata
                Add-Content -Value $row -Path $path
            }
        }
        Write-Host "DNS records found:"$dnsrecords.length
    }
    else { Write-Host "No matching records found." }
    Write-Host "`r"
}
Write-Host "Parsing over, cleaned duplicates, hence the difference between the number of lines in the CSV file and the number displayed in console. Please find the output CSV file named $path in $pwd."
Write-Host "Bye."
explorer $pwd

Ces deux scripts sont téléchargeables dans des versions commentées depuis le serveur grâce aux liens suivants : simple - amélioré