Powershell : obtention de la taille d’un share

Voici un petit script Powershell permettant de récupérer la taille d’un ou plusieurs share.

Ce script peut être appelé de deux manières :

  • sans arguments : le script va chercher un fichier texte dans le répertoire d’exécution pour passer sur TOUS les répertoires indiqués dans le fichier (un partage par ligne) ; le but est donc de renseigner tous les partages pour lesquels on souhaite connaître la volumétrie dans le fichier. Le script retourne ensuite un fichier CSV :
 
 
 
 
  •  avec des arguments : en donnant en argument d’exécution du script le serveur et le partage, on récupère la taille dans la console directement :
param([string]$shareHost, [string]$shareName)

function folderSize()
{
param($path)
try {
$byteSize = (Get-ChildItem -path "$path" -Recurse -ErrorAction SilentlyContinue | Measure-Object Length -sum).Sum
if ($byteSize.ToString().Length -lt 4) { return "$byteSize B." }
if ($byteSize.ToString().Length -ge 4 -and $byteSize.ToString().Length -lt 7) { $kbSize = [math]::Round($byteSize/1024,1) ; return "$kbSize KB." }
if ($byteSize.ToString().Length -ge 7 -and $byteSize.ToString().Length -lt 10) { $mbSize = [math]::Round($byteSize/1048576,1) ; return "$mbSize MB." }
if ($byteSize.ToString().Length -ge 10 -and $byteSize.ToString().Length -lt 13) { $gbSize = [math]::Round($byteSize/1073741824,1) ; return "$gbSize GB." }
if ($byteSize.ToString().Length -ge 13) { $tbSize = [math]::Round($byteSize/1099511627776,2) ; return "$tbSize TB." }
}
catch { return "Share doesn't exist or is unreachable or you don't have the required privileges." }
}

Write-Host "Share size retriever Powershell script"
Write-Host "======================================"
Write-Host "Usage: .\win_foldersize.ps1 <SERVER> <SHARE>"
Write-Host "If any parameter is missing, the script will look for a sharelist.txt file in the execution folder and will detect the size of all the folders inside the file."

if ($shareHost -eq "" -or $shareName -eq "")
{
Write-Host "You didn't provide both parameters while running the script. I will now try to read directly the shares from sharelist.txt in the script folder."
$today = Get-Date -f "yyMMdd"
$CsvOutputFile = "share-size-$today.csv"
$InputFile = "sharelist.txt"
$CsvHeader = "Share,Size"
Add-Content $CsvOutputFile $CsvHeader
try { $ShareList = Get-Content $InputFile -ErrorAction Stop }
catch { Write-Host "Unable to read sharelist.txt. Aborting." ; break }
foreach ($Share in $ShareList)
{
$sizeDump = folderSize($Share)
$Dump = "$Share,$sizeDump"
Add-Content $CsvOutputFile $Dump
}
Write-Host "Done, output file : $CsvOutputFile"
}
else {
Write-Host "Both parameters detected."
Write-Host "Server specified: $shareHost"
Write-Host "Share: $shareName"
$shareString = "\\"+"$shareHost"+"\"+"$shareName"
$displaySize = folderSize($shareString)
Write-host $displaySize
}

Powershell : audit des serveurs SQL Server

J’ai développé en prenant comme base ce script sur le TechNet un script Powershell récupérant diverses informations propres aux serveurs SQL Server dont le nom est renseigné dans un fichier CSV.

Le script parcourt dans le fichier CSV spécifié la colonne ayant pour entête ServerName (si jamais votre extract d’origine comprend plusieurs colonnes, comme le nom de l’instance par exemple) et va tenter de récupérer plusieurs informations pour chacun des hostname lus. Une fois un serveur traité, les détails recueillis sont ajoutés à un fichier CSV exploitable par la suite dans Excel par exemple.

Un exemple de fichier d’entrée avec les hostname des serveurs SQL à auditer.

Je n’ai pas réalisé de contrôles particuliers sur l’écriture ou l’accès aux serveurs SQL dans le script, il faudra donc en cas de dysfonctionnement quelconque s’assurer que les fichiers CSV d’entrée et sortie puissent être lus et écrits sur le disque et que l’utilisateur exécutant le script ait un minimum de privilèges sur SQL Server.

[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO')

function Get_ProperOS{
param($OS)
if ($OS -like '5.0*') { return "Windows Server 2000" }
elseif ($OS -like '5.2*') { return "Windows Server 2003" }
elseif ($OS -like '6.0*') { return "Windows Server 2008" }
elseif ($OS -like '6.1*') { return "Windows Server 2008 R2" }
elseif ($OS -like '6.2*') { return "Windows Server 2012" }
elseif ($OS -like '6.3*') { return "Windows Server 2012 R2" }
elseif ($OS -like '10.0*') { return "Windows Server 2016" }
else { return "Unknown NT version" }
}

function Get_ProperSQL{
param($SQL)
if ($SQL -like '8.0*') { return "SQL Server 2000" }
elseif ($SQL -like '9.0*') { return "SQL Server 2005" }
elseif ($SQL -like '10.0*') { return "SQL Server 2008" }
elseif ($SQL -like '10.5*') { return "SQL Server 2008 R2" }
elseif ($SQL -like '11.0*') { return "SQL Server 2012" }
elseif ($SQL -like '12.0*') { return "SQL Server 2014" }
elseif ($SQL -like '13.0*') { return "SQL Server 2016" }
elseif ($SQL -like '14.0*') { return "SQL Server 2017" }
else { return "Unknown SQL version" }
}

function Get_ServerName{
param($SqlHostProperties)
$SrvHostname = $SqlHostProperties | where {$_.name -eq "ComputerNamePhysicalNetBios"} | select value
return $SrvHostname.Value
}

function Get_ServerMemory{
param($SqlHostProperties)
$SrvMemory = $SqlHostProperties | where {$_.name -eq "PhysicalMemory"} | select value
return $SrvMemory.Value
}

function Get_ServerProcessors{
param($SqlHostProperties)
$SrvCPUs = $SqlHostProperties | where {$_.name -eq "Processors"} | select value
return $SrvCPUs.Value
}

Write-Host "SQL Server Inventory Powershell Script"
Write-Host "======================================"
$today = Get-Date -f "yyMMdd"
$CsvFile = "C:\temp\SqlServer_Inventory_$today.csv"
Clear-Content -path $CsvFile -Force
$CsvHeader = "ServerName,OS,SqlServerVersion,SqlServerEdition,SqlServicePack,Cores,RAM"
Add-Content $CsvFile $CsvHeader
$SqlSrvListFile = "sqlsrv_list.csv"
$SqlSrvList = [object]$SqlSrvList = Import-CSV $SqlSrvListFile
foreach ($SqlServer in $SqlSrvList.ServerName) {
Write-Host "Working on $SqlServer"
$SqlHost = New-Object -type Microsoft.SqlServer.Management.Smo.Server -ArgumentList $SqlServer
if ($SqlHost.ComputerNamePhysicalNetBIOS -ne $null) {
$SqlHostProperties = $SqlHost.Information.Properties | select Name,Value
$ServerName = Get_ServerName($SqlHostProperties)
$OSVersString = Get_ProperOS($SqlHost.OSVersion)
$SqlVersString = Get_ProperSQL($SqlHost.VersionString)
$SqlEdit = $SqlHost.Edition
$SqlSpack = $SqlHost.ProductLevel
$Cpu = Get_ServerProcessors($SqlHostProperties)
$Mem = Get_ServerMemory($SqlHostProperties)
$Dump =  "$ServerName"+","+"$OSVersString"+","+"$SqlVersString"+","+"$SqlEdit"+","+"$SqlSpack"+","+"$Cpu"+","+"$Mem"
Add-Content $CsvFile $Dump
}
else { Write-Host "Couldn't query $SqlServer." }
}
Write-Host "Done."

Voici une copie d’écran d’exemple du fichier CSV généré par le script :

Powershell : liste des homedirs orphelins V2

J’avais présenté dans un précédent article un script Powershell permettant de lister les homedirs orphelins, c’est à dire les homedirs dont le compte AD lié n’existe plus. Celui-ci se basait sur une vérification du nom du répertoire et testait la corrélation avec un utilisateur existant dans l’AD. Rapide mais peu robuste car un utilisateur changeant d’identifiant déjoue le script.

J’ai donc réalisé une v2 de ce script, en utilisant cette fois-ci l’instruction Get-Acl pour récupérer le propriétaire des répertoires. Chaque homedir possède en propriétaire un SID qui renvoie vers un utilisateur local ou du domaine. Si l’utilisateur du domaine est supprimé, alors le SID disparaît de l’annuaire… mais reste référencé en tant que propriétaire du homedir, comme on peut le voir sur cette capture d’écran du répertoire avec la colonne Owner affichée :

comptetest sur DOMAIN existe toujours par contre les comptes propriétaires des autres répertoires ont été supprimés de l’AD car Windows ne fait pas le lien entre le SID enregistré et un SID existant dans l’annuaire.      

Le script commenté est disponible en fin d’article et est prêt à être adapté à n’importe quel environnement.

function noexist{
Write-Host "Homedir $folderfullpath doesn't have any owner."
Add-Content -path "orphan-homedir.log" -Force -Value $folderfullpath
}

Write-Host "Orphan homedir listing script V2"
Write-Host "================================"
Write-Host ""
Clear-Content -path "orphan-homedir.log" -Force
for ($Line = 15; $Line -gt 0; $Line--) {
$RemoteServer = (Get-Content C:\homedir-srv-list.txt -TotalCount 15)[-$Line]
Write-Host "Building user homedir list on $RemoteServer"
$HomedirPath = "\\"+$RemoteServer+"\c$\homedir"
Add-Content -path "orphan-homedir.log" -Force -Value "`r`n$RemoteServer`r`n========"
$folderlist = Get-ChildItem $HomedirPath | select name
Write-Host "Checking directories ACLs"
foreach ($folder in $folderlist) {
$folderFullPath = $homedirpath+$folder.Name
$prop = Get-Acl $folderFullPath
if ($prop.Owner.Contains("S-1-5-21")) { noexist }
}
}
Write-Host "Please find in orphan-homedir.log the list of homedirs that don't have any linked AD account."
Write-Host "Bye"

Powershell : liste des homedirs orphelins

Afin de libérer un peu d’espace disques sur les serveurs de fichiers portant les homedirs, j’ai développé un script lisant dans un fichier les serveurs de fichiers hébergeant des homedirs, récupérant les noms des répertoires, puis faisant une comparaison entre chaque nom de répertoire et un utilisateur AD. Si l’utilisateur AD est introuvable, cela signifie selon toute vraisemblance que l’utilisateur n’existe plus, et que le homedir peut donc être détruit. Le script exporte enfin vers un fichier texte la liste des homedir orphelins détectés sur chaque serveur.

function noexist{
    Write-Host "Homedir $username doesn't have any owner."
    Add-Content -path "orphan-homedir.log" -Force -Value $username
}


Write-Host "Orphan homedir listing script"
Write-Host "============================="
Write-Host ""
Clear-Content -path "orphan-homedir.log" -Force
for ($Line = 15; $Line -gt 0; $Line--) {
    $RemoteServer = (Get-Content C:\homedir-srv-list.txt -TotalCount 15)[-$Line]
    Write-Host "Building user homedir list on $RemoteServer"
    $HomedirPath = "\\"+$RemoteServer+"\c$\homedir"
    Add-Content -path "orphan-homedir.log" -Force -Value "`r`n$RemoteServer`r`n========"
    $folderlist = Get-ChildItem $HomedirPath | select name
    Write-Host "Compairing homedir list to AD user list"
    foreach ($name in $folderlist) {
        $username = $name.Name   
        Try { $aduser = Get-ADUser $username }
        Catch { noexist }
    }
}
Write-Host "Please find in orphan-homedir.log the list of homedirs that don't have any linked AD account."
Write-Host "Bye"

Il ne reste donc plus qu’à adapter les variables en fonction de l’environnement sur lequel le script est exécuté. Le script doit être exécuté sur un contrôleur de domaine ou une station ayant les outils Powershell ActiveDirectory, ainsi qu’avec un compte utilisateur pouvant parcourir les répertoires administratifs des serveurs.