Compare commits

...
29 Commits
Author SHA1 Message Date
nlang 2bd1502710 Modification emplacement script 2023-12-17 20:20:48 +01:00
nlang a37052fb15 Création script 2023-12-17 20:17:25 +01:00
nlang ffaf6ac330 Création script 2023-12-17 20:09:45 +01:00
nlang 0700844125 Création script 2023-12-17 20:01:55 +01:00
nlang 368911a19d Création script 2023-12-17 19:57:13 +01:00
nlang 781541c8ea Création script 2023-12-17 19:52:00 +01:00
nlang 0cc57e62b1 Création scripts 2023-12-17 19:42:32 +01:00
nlang 2d3209318e Modification url 2023-12-17 19:37:55 +01:00
nlang 93feddd42f Création script 2023-12-17 19:35:28 +01:00
nlang 97ba946da0 Création script 2023-12-17 19:29:57 +01:00
nlang 56afc579c0 Création script 2023-12-17 01:18:44 +01:00
nlang e7b06258bf Création script 2023-12-17 01:11:55 +01:00
nlang c86c8e5f24 Création script 2023-12-17 00:58:26 +01:00
nlang 897acf751e Creation scripts 2023-12-16 19:35:57 +01:00
nlang 90b005c54e Création script 2023-12-16 17:26:24 +01:00
nlang 1b82503322 Création script 2023-12-16 17:20:09 +01:00
nlang 100de993bc Création script 2023-12-16 17:17:13 +01:00
nlang f06354514d Création script 2023-12-16 17:12:01 +01:00
nlang f0d6701cd2 Création script 2023-12-16 17:06:25 +01:00
nlang 91426c80d2 Création script 2023-12-16 17:03:05 +01:00
nlang c63e8744ab Création script 2023-12-16 16:58:45 +01:00
nlang 4449bb1221 Modification erreur affichage 2023-12-16 16:56:04 +01:00
nlang c36060d589 Création script 2023-12-16 16:53:59 +01:00
nlang fa4e1d68fc Création script 2023-12-16 16:50:52 +01:00
nlang abe380f22a Création script 2023-12-16 16:47:18 +01:00
nlang 296ca71051 Création script 2023-12-16 16:44:01 +01:00
nlang 434b6c4b17 ajout script 2023-12-16 16:41:26 +01:00
nlang 2d25000938 précision licence 2023-12-16 16:37:57 +01:00
nlang 7097618f89 ajout script 2023-12-16 16:33:33 +01:00
30 changed files with 4576 additions and 0 deletions
+200
View File
@@ -0,0 +1,200 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
ipmo activedirectory
Set-Location $( [environment]::GetFolderPath("MyDocuments") )
$now = Get-Date -Format dd/MM/yyyy
$from = "moi@domaine.com"
$to = "lui@domaine.com"
$smtpserver = "serveurmail.domaine.fr"
if (!(Get-Module -name ActiveDirectory)) {throw("Impossible de trouver le module Active Directory")}
function addthis([string]$groupname=$(throw("Nom de groupe obligatoire")),[string]$name=$null,$added=$null,$removed=$null)
{
if ($added -eq $null -and $removed -eq $null)
{
throw("Aucun indice d`'ajout / retrait pour $groupname")
}
$objet = New-Object psobject
$objet | Add-Member -MemberType NoteProperty -name "Date" -value $now
$objet | Add-Member -MemberType NoteProperty -Name "Group_name" -Value $groupname
$objet | Add-Member -MemberType NoteProperty -Name "Name" -Value $name
$objet | Add-Member -MemberType NoteProperty -Name "Added" -Value $added
$objet | Add-Member -MemberType NoteProperty -Name "Removed" -Value $removed
return $objet
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
########################## CREATION DE LA BASE DES GROUPES ##################################
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
$listegroupes = Get-ADGroup -Filter * -Properties members | Select-Object -Property name,members | Sort-Object -Property name
$array = New-Object System.Collections.ArrayList
foreach ($groupe in $listegroupes)
{
$objet = New-Object psobject
$groupe.members = $($groupe.members | foreach {$_.split(",")[0] -replace("^CN=","")})
$objet | add-member -MemberType NoteProperty -Name "name" -Value $groupe.name
$objet | Add-Member -MemberType NoteProperty -Name "members" -Value $groupe.members
$array.Add($objet) | Out-Null
}
if (!(Test-Path referenceadgroupes.xml))
{
$listegroupes | Export-Clixml referenceadgroupes.xml -Force
}
else
{
$referenceadgroupes = Import-Clixml referenceadgroupes.xml
$array | Export-Clixml newgroups.xml -Force
$newgroups = Import-Clixml newgroups.xml
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
########################### VERIFICATION DE CHAQUE GROUPE ###################################
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
$arraygroups = New-Object System.Collections.ArrayList
#|~~~~~~~~~~~~~~~~~~~~~~~~~~~|#
#| Reference VS. nouveau |#
#|~~~~~~~~~~~~~~~~~~~~~~~~~~~|#
$i = 1
foreach ($groupe in $referenceadgroupes)
{
Write-Progress -Status "Analyse" -Activity $($groupe.name) -PercentComplete ($i / $($referenceadgroupes.count) * 100)
$i ++
$obj = New-Object PSobject
$compareit = $null
$compareit = $newgroups | Where-Object {$_.name -eq $($groupe.name)}
#_____________________________
#1) Le groupe n'est pas trouvé
#_____________________________
if (!$compareit)
{
#Si le groupe n'est pas présent dans la nouvelle liste il a été retiré
$arraygroups.Add($(addthis -groupname $groupe.name -removed "X")) | Out-Null
}
#_____________________________
#2) La propriété membres de reference et différence sont nuls
#_____________________________
elseif($groupe.members.Count -eq 0 -and $compareit.members.Count -eq 0)
{
#on ne fait rien
}
#_____________________________
#3) L'une ou l'autre des propriétés membres est égale à zero, mais leur count diffère
#_____________________________
#Une erreur est causée lorsque l'on compare une valeur et un $null. Il faut donc filtrer.
#Si le nombre de membres de la reference = zéro ou celle du nouveau = 0 et que groupe.members.count et compare.membre.count sont différents alors [...]
elseif(($groupe.members.count -eq 0 -or $compareit.members.count -eq 0) -and ($groupe.members.count -ne $compareit.members.count))
{
if ($groupe.members.count -gt $compareit.members.Count)
{
$toadd = $groupe.members
$groupname = $groupe.name
$removed = "X"
$added = $null
}
else
{
$toadd = $compareit.members
$groupname = $compareit.name
$removed = $null
$added = "X"
}
foreach ($membre in $toadd)
{
$arraygroups.add($(addthis -groupname $groupname -name $($membre) -added $added -removed $removed))
}
}
#_____________________________
#4) aucun des cas précedents n'est valide
#_____________________________
else
{
$changes = $null
$changes = Compare-Object -ReferenceObject $groupe.members -DifferenceObject $compareit.members
foreach ($change in $changes)
{
switch ($($change.sideindicator))
{
"=>" {$arraygroups.add($(addthis -groupname $($groupe.name) -name $($change.inputobject) -added "X"));break}
"<=" {$arraygroups.add($(addthis -groupname $($groupe.name) -name $($change.inputobject) -removed "X"));break}
default {throw("Erreur pas d'indice!")}
}#foreach ($change in $changes)
}
}
}#foreach ($groupe in $referenceadgroupes)
#|~~~~~~~~~~~~~~~~~~~~~~~~~~~|#
#| Nouveau VS. reference |#
#|~~~~~~~~~~~~~~~~~~~~~~~~~~~|#
$i = 1
foreach ($groupe in $newgroups)
{
Write-Progress -Status "Recherche de nouveaux groupes" -PercentComplete ($i / $($referenceadgroupes.Count) * 100) -Activity $groupe.name
$i++
$compareit = $null
$compareit = $referenceadgroupes | Where-Object {$_.name -eq $($groupe.name)}
if (!$compareit)
{
#Le groupe n'existe pas dans l'ancienne liste. Il est donc crée
$arraygroups.Add($(addthis -groupname $groupe.name -added "X"))
foreach ($member in $groupe.members)
{
$arraygroups.Add($(addthis -groupname $groupe.name -name $member -added "X"))
}
}
}
Move-Item .\newgroups.xml -Destination .\referenceadgroupes.xml -Force
$arraygroups | Export-Csv -Path .\changements_groupes.csv -Delimiter ";" -Encoding UTF8 -NoTypeInformation -Append
if ($arraygroups)
{
$body = $null
foreach ($line in $arraygroups)
{
[string]$body += $line -replace("@{","") -replace(";","`t") -replace ("}","`n")
}
Send-MailMessage -from $from -to $to -SmtpServer $smtpserver -Subject "Ajouts dans les groupes AD le $now" -Body "Voici les groupes modifiés : `n$body" -Attachments .\changements_groupes.csv -Encoding UTF8
}
}
+118
View File
@@ -0,0 +1,118 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
#Requires -version 3
#Ce script requiert Powershell V3 ou supérieur pour fonctionner correctement, car l'export vers un fichier HTML ne fonctionnera pas correctement si c'est une version 2.
#Pensez à faire correspondre le chemin du fichier a ce que vous avez dans les .bat mis en GPO
$filename = "\\storage\logs$\loginout.TXT"
$logs = Get-Content $filename
# Cette partie est utilisée pour éviter d'avoir un trop gros fichier. Au dessus de 20000 entrées, il sauvegardera le contenu dans un autre fichier, puis réecrira le fichier avec les 10000 dernières. Vous pouvez changer ces valeurs à volonté.
if ($logs.count -gt 20000)
{
Copy-Item $filename $($filename + "_archive_" + $(Get-Date -Format dd_MM_yy) + ".txt")
$logs[-10000..-1] | Out-File $filename -Force utf8
}
$tableau = new-object System.Collections.ArrayList
$tableau2 = new-object System.Collections.ArrayList
#L'outil RSAT avec le module Active Directory n'est nécessaire que si vous lancer le script depuis un poste client. Si vous vous en servez depuis le serveur, ce doit être, celui ci doit être au moins un 2008 R2.
ipmo activedirectory
# Obtient la liste des utilisateurs depuis le controlleur de domaine. Necessaire pour retrouver le nom complet à partir du Sam Account Name.
$userlist = get-aduser -filter * | Select-Object -Property samaccountname,name
# Lisons le fichier ligne par ligne!
foreach ($log in $logs)
{
# J'utilise une REGEX pour retrouver les diverses informations de chaque ligne du fichier
if ($log -match "(?<date>\d+/\d+/\d+);(?<heure>.+:\d+:\d+[,.]\d+);(?<compte>\S+);(?<pc>\S+);(?<serveur>\W{2}\w+);(?<action>.*$)")
{
# Dans certains cas, le format de date diffère et affiche l'année en premier. Je vérifie juste si le format correspond à un format étranger, et le cas écheant, je réorganise le tout.
$date = $Matches.date -split("/")
if ($date[0].length -le 2)
{
$matches.date = [string]$($date[1]+"/"+$date[0]+"/"+$date[2])
}
$object = [pscustomobject]@{
"Date" = $([datetime]$Matches.date)
"Time" = $($($Matches.heure) -replace(",\d+",""))
"Account" = $Matches.compte
"Pc" = $matches.pc
"Action" = $Matches.action
"Server" = $Matches.serveur
}
$tableau.add($object) | Out-Null
}
}
# Je trie le tableau récapitulatif, par date en descendant, puis je regroupe tout par nom d'ordinateur
$tableaugroupe = $tableau | sort-object -property @{Expression="Date";descending=$true} | Group-Object -Property "PC"
# Comme certains ordinateurs n'ont pas d'information de login / logout en fonction de leur utilisation (travail par VPN par exemple), je crée un objet avec des valeurs pré-définies pour ces cas
$itemsansvaleur = [pscustomobject]@{
"Date" = $([datetime]"01/01/1901")
"Time" = "00:00:00"
}
# Pour chaque entrée dans le tableau trié, je prends le premier login et logout (qui sont les valeurs les plus récentes), puis je retrouve les informations dessus.
foreach ($entree in $tableaugroupe)
{
$lastlogin = $lastlogout = [PSCustomObject]
try
{
$lastlogin = $($entree.group | Where-Object {$_.action -like "*login*"})[0]
}
catch
{
Write-Host "Erreur login sur $($entree.Name)"
$lastlogin = $itemsansvaleur
}
try
{
$lastlogout = $($entree.group | Where-Object {$_.action -like "*logout*"})[0]
}
catch
{
Write-Host "Erreur logout sur $($entree.Name)"
$lastlogout = $itemsansvaleur
}
# Je retrouve le nom complet
$nom = $userlist | where-object {$_.samaccountname -eq $($lastlogin.account)} | Select-Object -ExpandProperty "Name"
# Puis je crée l'objet.
$object = [pscustomobject]@{
"Compte" = $lastlogin.account
"Name" = $nom
"PC" = $entree.group[0].pc
"Dernier Login" = get-date $(($lastlogin.Date).ToShortDateString()+" "+$lastlogin.heure) -Format "dd/MM/yy HH:mm:ss"
"Serveur Login" = $lastlogin.server
"Dernier Logout" = get-date $(($lastlogout.Date).ToShortDateString()+" "+$lastlogout.heure) -Format "dd/MM/yy HH:mm:ss"
"Serveur Logout" = $lastlogout.server
}
$tableau2.Add($object) | out-null
}
$date = Get-Date
# Je trie le tableau par ordinateur, puis je le convertit au format HTML. J'ai rajouté un fichier CSS pour rendre le tout plus joli. Si vous voulez donner un look plus sympa à votre fichier, créez juste un fichier nommé "tableaux.css" dans le même répertoire que le fichier HTML et laissez votre créativité travailler :D
$tableau2 | sort-object -Property "PC" | ConvertTo-Html -title "$($date.ToShortDateString()) $($date.ToShortTimeString())" -CssUri "tableaux.css" | Out-File "\\storage\logs$\logintohtml.html" -Encoding utf8 -Force
#Après cela, j'uploade le fichier sur un serveur web en me servant de .NET et en passant via le FTP. Ce n'est pas utile si vous stockez la page localement.
# Le login / password est en clair ici. Je ne le recommande pas, mais c'est uniquement à but d'exemple. Vous pouvez le rendre plus sur, mais ce n'est pas le but de ce script.
$credentials = new-object System.Net.NetworkCredential("username","password")
$webclient = new-object System.Net.WebClient
$webclient.Credentials = $credentials
$uri = New-Object System.Uri("ftp://webserver/www/logintohtml.html")
$webclient.uploadFile($uri,'\\storage\log$\logintohtml.html')
+57
View File
@@ -0,0 +1,57 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
#Ajout du module AD pour les rebelles de la V1/ V2 ;)
ipmo activedirectory
#Obtention de la liste des serveurs
$serveurs = Get-ADComputer -SearchBase "OU=Servers,DC=domaine,DC=local" -filter * | Select-Object -ExpandProperty name
#Creation du tableau qui stockera les données
$tableau = New-Object System.Collections.ArrayList
#Fonction utilisée pour stocker les données ET les erreurs
function addarray([string]$serveur,[string]$description=$null,[string]$serveur1=$null,[string]$serveur2=$null)
{
#définition de l'objet envoyé dans le tableau
$object = [PSCUSTOMOBJECT]@{
"Ordinateur" = $serveur
"Carte réseau" = $description
"Serveur 1" = $serveur1
"Serveur 2" = $serveur2
}
return $object
}
foreach ($serveur in $serveurs)
{
Write-Host "Analyse de $serveur"
#On teste si ne réponds pas au ping. Si c'est le cas, on stocke l'erreur dans le tableau
if (!(Test-Connection $serveur -Count 1))
{
$tableau.Add($(addarray -serveur $serveur -serveur1 $($Error[0].Exception.Message) -serveur2 "Erreur Ping"))
}
else
{
#Cette commande obtient la configuration de différentes cartes réseau. Pour filtrer les cartes actives, il suffit de savoir si l'adresse IP n'est pas vide.
$configuration = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $serveur | where-object {$_.ipaddress -ne $null}
#Si la derniere commande renvoie une erreur, on enregistre cette erreur
if (!$?)
{
$tableau.Add($(addarray -serveur $serveur -serveur1 $($Error[0].Exception.Message )-serveur2 "Erreur"))
}
else
{
foreach ($entry in $configuration)
{
#Si aucun DNS n'est renseigné sur la carte, alors on le précise dans le tableau
if (!($($entry.DNSServerSearchOrder)))
{
$tableau.Add($(addarray -serveur $serveur -description $($entry.caption) -serveur1 "Aucun DNS" -serveur2 "Aucun DNS"))
}
else
{
$tableau.Add($(addarray -serveur $serveur -description $($entry.caption) -serveur1 $($entry.dnsserversearchorder[0]) -serveur2 $($entry.dnsserversearchorder[1])))
}
}
}
}
}
#Et on exporte le tout sur le bureau :)
$tableau | Export-Csv -Path $([environment]::GetFolderPath("Desktop")+"\DNS_SERVEURS_"+$(get-date -Format mm_dd_yyyy)+".csv") -NoTypeInformation -Encoding UTF8 -Delimiter ";"
+564
View File
@@ -0,0 +1,564 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
###############################################
#region VARIABLES
#Emplacement où seront sauvegardés les fichiers
$workspace = "\\serveur\GPO_check"
#nom du fichier HTML qui sera envoyé par mail
$htmlfilename = "results.html"
#informations du serveur de messagerie et d'envoi de mail
$mailserver = "serveurmail.societe.fr"
$usessl = $false
$smtpport = 25
$from = "moi@societe.fr"
$to = "toi@societe.fr"
#Si besoin est : credentials utilisés pour la sauvegarde des fichiers HTML issus des GPO. N'oubliez pas de les sécuriser en mettant le tout dans un
#fichier haché
$username = "user"
$password = "password"
#emplacement de sauvegarde des fichiers HTML
$backuplocation = "\\serveur\GPOS_HTML\"
#Encodage du texte. UTF8 est toujours un bon choix. Ou presque.
$encoding = "UTF8"
#Nom de fichier de réference pour les anciennes GPO. Inutile de le changer.
$gpolistfilename = "oldgpo.clixml"
#nombre de lignes récupérées avant et après chaque modification trouvée dans les GPO
$maxgathering = 5
#endregion
try
{
#Ajout de la DLL diffmatchpatch qui comparera les fichiers XML des gpo
Add-type -path '\\serveur\chemin\vers\DiffMatchPatch.dll' -ErrorAction Stop
}
catch
{
throw "Impossible d'ajouter la DLL diffmatchpatch"
exit 10
}
#On récupère toutes les GPO. Si ça ne fonctionne pas, on bloque le script. (module manquant?)
try
{
$gpos = get-gpo -All -ErrorAction Stop
}
catch
{
throw "Impossible de récuperer les GPOS. Module AD manquant?!"
exit 1
}
Set-Variable DebugPreference -Value continue
try
{
Write-Debug "Déplacement du répertoire vers $workspace"
Set-Location $workspace -ErrorAction Stop
}
catch
{
Write-Output "Une erreur s'est produite lors de l'accès à $workspace. $($Error[0].exception.message)"
Start-Sleep -Seconds 5
exit 3
}
$date = get-date -Format "yyyyMMddHHmmss"
$errors = New-Object System.Collections.ArrayList
$infos = New-Object System.Collections.ArrayList
#Cette fonction est utilisée pour parser et mettre en forme les différences de l'outil fc.exe
function Highlight-Differences {
param ($originalfile,$differences)
Begin
{
$highlightarray = New-Object System.Collections.ArrayList
try
{
Write-Debug "Récupération du contenu du fichier original"
$old = Get-Content $originalfile -ErrorAction Stop
Write-Debug "Récupération du contenu du fichier de différences"
$new = Get-Content $differences -ErrorAction Stop
}
catch
{
Write-Debug "Erreur de lecture du fichier, fin du script"
throw("Erreur lors de la lecture du fichier source")
exit
}
}
Process {
# Creation d'un objet diffmatchpatch via la dll (générée depuis le fichier .cs)
$diff = new-object DiffMatchPatch.diff_match_patch
#création de l'objet de différences
$differences = $diff.diff_main($old,$new,$true)
#nettoyage sémantique pour lecture plus aisée
$diff.diff_cleanupSemantic($differences)
#Création du fichier HTML qui sera parsé ensuite
$textdiffs = $diff.diff_prettyHtml($differences).replace("> <",">`n<").split("`n")
#parsing de l'ensemble du fichier et récupération des lignes comportant un élément ajouté par diff_match_patch
$indexarray = New-Object System.Collections.ArrayList
$temparray = New-Object System.Collections.ArrayList
$gatheringtrigger = $false
#décompte du numéro de ligne
$index = 0
$textdiffs | % {
if ($_ -like "*<del style=*" -or $_ -like "*<ins style=*" -or $_ -like "*</del>*" -or $_ -like "*</ins>*")
{
if ($index -notin $indexarray)
{
if (($index - $maxgathering) -lt 0)
{
$start = 0
}
else
{
$start = $index - $maxgathering
}
$end = $index + 1
$count = 0
do
{
$count++
$end++
if ($textdiffs[$end] -like "*<del style=*" -or $textdiffs[$end] -like "*<ins style=*" -or $textdiffs[$end] -like "*</del>*" -or $textdiffs[$end] -like "*</ins>*")
{
$count = 0
}
}
until ($count -gt $maxgathering -or $end -eq $textdiffs.Length)
for($start=$start;$start -le $end;$start++)
{
$null = $indexarray.Add($start)
$null = $temparray.Add("$($start+$maxgathering) : $($textdiffs[$start])<br>")
}
$null = $temparray.Add("******************************************************<br>")
}
}
$index++
}
return $temparray
}
}
#On récupère tous les fichiers de GPO marqués _new.xml (faits lors de la dernière exécution du script) pour les renommer en date du jour
foreach ($item in (Get-ChildItem $workspace -Filter "*_new.xml"))
{
try
{
Write-Debug "Renommage du fichier de $($item.name) vers $($item.name.replace("_new.xml","_$date.xml"))"
Move-Item $item.Name ($item.Name.Replace("_new.xml","_$date.xml")) -ErrorAction Stop -Force
}
catch [System.Management.Automation.ItemNotFoundException]
{
$errors.Add([pscustomobject]@{
"Fichier" = $item.Name
"Type" = [System.Management.Automation.ItemNotFoundException].name
"Action" = "Déplacement"
"Erreur" = "Impossible de le renommer en date du jour, $($Error[0].exception.message)"
})
}
catch
{
$errors.Add([pscustomobject]@{
"Fichier" = $item.Name
"Type" = [System.Management.Automation.ItemNotFoundException].name
"Action" = "Déplacement"
"Erreur" = "Impossible de le renommer en date du jour, $($Error[0].exception.message)"
})
}
}
$sendmail = $false
$checkoldgpos = $true
try
{
Write-Debug "Import du fichier CLIXML de la liste des noms de gpo"
$oldgpolist = Import-Clixml $gpolistfilename -ErrorAction Stop
}
catch
{
$checkoldgpos = $false
}
if ($checkoldgpos -eq $true)
{
#On vérifie les gpo crées ou disparues
$gpochangelist = Compare-Object -ReferenceObject $oldgpolist.displayname -DifferenceObject $gpos.displayname
foreach ($entry in $gpochangelist)
{
Write-Debug "Recherche de création ou suppression de $($entry.inputobject)"
if ($entry.sideindicator -eq "=>")
{
Write-Debug "GPO $($entry.inputobject) crée"
$infos.Add([pscustomobject]@{
"GPO" = $entry.inputobject
"Information" = "La GPO a été créée"
}) | Out-Null
}
else
{
Write-Debug "GPO $($entry.inputobject) supprimée"
$infos.Add([pscustomobject]@{
"GPO" = $entry.inputobject
"Information" = "La GPO a été supprimée"
}) | Out-Null
}
}
}
Write-Debug "Export de la liste des GPO"
$gpos | Export-Clixml $gpolistfilename
Write-Debug "Filtrage de la liste des GPO qui ne se terminent pas par _new.xml et suppression de la date en fin de nom de fichier"
$gpolist = (Get-ChildItem -Filter "*.xml" | Where-Object {$_.name -notlike "*_new.xml"}).Name -Replace("_\d{$($date.Length)}.xml$","") | Sort-Object -Unique
foreach ($gpo in $gpos)
{
Write-Debug "Création d'un rapport HTML pour $($gpo.displayname)"
$gpo.GenerateReportToFile([Microsoft.GroupPolicy.ReportType]::Html, $(Join-Path $workspace "$($gpo.DisplayName).html"))
if ($gpo.DisplayName+"_new.xml" -notin $errors.fichier)
{
try
{
Write-Debug "Création d'un rapport XML pour $($gpo.displayname) nommé $($gpo.displayname)_new.xml"
$gpo.GenerateReportToFile([Microsoft.GroupPolicy.ReportType]::Xml, $(Join-Path $workspace "$($gpo.DisplayName)_new.xml"))
}
catch
{
Write-Debug "Erreur lors de l'export de la GPO"
$errors.Add([pscustomobject]@{
"Fichier" = $gpo.displayName
"Type" = $Error[0].CategoryInfo.Reason
"Action" = "Export de la GPO"
"Erreur" = "Une erreur s'est produite lors de l'export de la GPO. $($error[0].Exception.Message)"
})
}
}
else
{
Write-Debug "Le déplacement du fichier source $($gpo.displayname) est en erreur. Pas d'export fait"
$errors.Add([pscustomobject]@{
"Fichier" = $gpo.displayName
"Type" = "Manuel"
"Action" = "Export de la GPO"
"Erreur" = "Un déplacement du fichier source est en erreur. Cette GPO ne sera pas exportée pour préserver l'historique."
})
}
#On vérifie si le répertoire de backup existe ou non
if (!(Test-Path $(Join-Path $workspace $gpo.DisplayName)))
{
Try
{
New-Item -ItemType Directory -Name $gpo.DisplayName -ErrorAction Stop -Verbose -Force
Backup-GPO -Guid $gpo.id -Path $(Join-Path $workspace $gpo.DisplayName) -Comment "Backup du $date" -ErrorAction Stop -Verbose
}
catch
{
$errors.Add([PSCUSTOMOBJECT]@{
"Fichier" = $gpo.DisplayName
"Type" = $Error[0].CategoryInfo.Reason
"Action" = "Création de backup"
"Erreur" = "Une erreur s'est produite lors de la création du répertoire de backup ou du backup pour la GPO. $($Error[0].Exception.Message)"
})
}
}
}
#Une feuille CSS qui sera intégrée au fichier HTML afin de pouvoir avoir un affichage un peu plus sympa
$css = @"
<style media="screen" type="text/css">
table {
width: 100%;
border: 2px solid;
border-collapse: collapse;
}
th, td, tr {
border: 1px solid;
}
th {
color: black;
text-align: center;
vertical-align: middle;
height: 50px;
font-size: 30px;
background-color: lightblue;
}
td[div=gpo]{
font-size: 18px;
vertical-align: top;
text-align: center;
text-transform: uppercase;
font-weight: bold;
}
td[div=time]{
vertical-align: top;
text-align: center;
}
p {
font-family: verdana;
font-size: 20px;
}
div {
font-family: Arial;
}
div.delete {
background-color: lightcoral;
color: darkred;
text-decoration:line-through;
display: block;
font-weight: bold;
font-family: verdana;
}
div.create{
background-color: lightgreen;
color: darkgreen;
font-style: italic;
font-family: verdana;
}
div.warning{
background-color: yellow;
font-weight: bold;
font-size: 150%;
}
</style>
"@
try
{
$htmlfile = new-object System.Collections.Generic.List[string]
}
catch
{
try
{
$htmlfile = [System.Collections.Generic.List[string]]::new()
}
catch
{
exit 50
}
}
$htmlfile.Add("<html>")
$htmlfile.Add("<head>")
$htmlfile.Add('<meta charset="utf-8" />')
$htmlfile.Add($css)
$htmlfile.Add("</head>")
$htmlfile.Add("<body>")
$htmlfile.Add("<table>")
$htmlfile.Add("<tr>")
$htmlfile.Add("<th>GPO</th>")
$htmlfile.Add("<th>Date de modification</th>")
$htmlfile.Add("<th>Différences</th>")
$htmlfile.Add("</tr>")
Write-Debug "Parcours des nouveaux fichiers extraits de GPOS"
foreach ($newitem in (Get-ChildItem $workspace -Filter "*_new.xml"))
{
$isnewgpo = $false
try
{
Write-Debug "Récupération de $($newitem.name.replace(`"_new.xml`","_$date.xml`"))"
$olditem = Get-Item $newitem.name.replace("_new.xml","_$date.xml") -ErrorAction Stop
}
catch
{
Write-Debug "Pas de fichier en date du jour. Recherche d'un plus ancien"
$foundfiles = Get-ChildItem | Where-Object {$_.name -match "^$($newitem.Name.replace("_new.xml","_\d{$($date.length)}.xml$"))"}
#if ((get-childitem $newitem.Name.Replace("_new.xml","_*.xml") -Exclude $newitem.Name).count -ne 0)
if ($foundfiles.count -ne 0)
{
try
{
Write-Debug "Récupération du fichier le plus récent qui n'est pas $($newitem.name)"
$lastknownitem = (get-childitem -Exclude $newitem.Name -ErrorAction Stop | Where-object {$_.name -match "^$($newitem.Name.replace("_new.xml","_\d{$($date.length)}.xml$"))"}) | Sort-Object -Property name -Descending | Select-Object -First 1
Write-Debug "Fichier trouvé : $($lastknownitem.name)"
$olditem = $lastknownitem
}
catch
{
Write-Debug "Aucun fichier plus récent. La GPO est nouvelle."
$isnewgpo = $true
}
if ($isnewgpo -eq $true -or $olditem -eq $null)
{
$errors.Add([pscustomobject]@{
"Fichier" = $olditem.Name
"Type" = $Error[0].CategoryInfo.Reason
"Action" = "Récupération de l'ancien fichier $($newitem.name.replace("_new.xml","_$date.xml"))"
"Erreur" = "La récupération de l'ancien fichier n'a pas pu être effectuée. $($Error[0].Exception.Message). La gpo est nouvelle"
})
$isnewgpo = $true
}
}
else
{
Write-Debug "Aucun fichier plus ancien trouvé."
$isnewgpo = $true
}
}
#récupération des fichiers
Write-Debug "Lecture du contenu de $($newitem.name) pour création d'un objet XML"
[xml]$xmlnew = Get-Content $newitem
if ($isnewgpo -eq $true)
{
Write-Debug "La gpo $($newitem.name) est nouvelle, on passe ce fichier"
$errors.Add([pscustomobject]@{
"Fichier" = $newitem.Name
"Type" = "Nouvelle GPO"
"Action" = "La GPO $($newitem.name.replace("_new.xml","_$date.xml")) a été créée en date du $($xmlnew.GPO.CreatedTime)"
"Erreur" = "GPO Non traitée car nouvelle. $($Error[0].Exception.Message)."
})
continue
}
Write-Debug "Lecture du contenu de $($olditem.name) pour création d'un object XML de comparaison"
[xml]$xmlold = Get-Content $olditem
if ($xmlold.GPO.ModifiedTime -ne $xmlnew.GPO.ModifiedTime)
{
Write-Debug "Les fichiers comportent des dates de modifications différentes."
$sendmail = $true
Write-Host -ForegroundColor Green "Modifications détectées entre $($newitem.name) et $($olditem.name)!"
$htmlfile.Add("<tr>")
$htmlfile.Add("<td div='gpo'>$($xmlold.GPO.Name)</td>")
$htmlfile.Add("<td div='time'>$($xmlold.GPO.ModifiedTime)</td>")
Write-Debug "Selection de la GPO pour sauvegarde"
$thisgpo = $gpos | Where-Object {$_.DisplayName -eq $xmlnew.GPO.Name}
try
{
Backup-GPO -Guid $thisgpo.id -Path $(Join-Path $workspace $thisgpo.DisplayName) -Comment "Backup du $date" -ErrorAction Stop
}
catch
{
$errors.Add([pscustomobject]@{
"Fichier" = $thisgpo.DisplayName
"Type" = "BackupGPO"
"Action" = "La GPO $($thisgpo.DisplayName) n'a pas pu être sauvegardée"
"Erreur" = "GPO Non sauvegardée. $($Error[0].Exception.Message)."
})
}
#$enc sera utilisé pour lire et convertir le fichier xml
$enc = [System.Text.Encoding]::$encoding
$xmlold.InnerXml.replace("><",">`n<")| Out-File $(join-path $workspace "__xmlold.xml") -Encoding $encoding -Force
$xmlnew.InnerXml.replace("><",">`n<")| Out-File $(join-path $workspace "__xmlnew.xml") -Encoding $encoding -Force
Write-Debug "Analyse des fichiers XML et comparaison via l'outil diff_match_patch"
$differences = Highlight-Differences -originalfile (Get-Item .\__xmlold.xml) -differences (Get-Item .\__xmlnew.xml)
if ($differences)
{
$htmlfile.Add("<td>")
foreach ($difference in $differences)
{
$htmlfile.add("$($difference.replace('<span>','<div>').replace('</span>','</div>'))")
}
}
else
{
#Encore valide?
Write-Debug "une erreur s'est produite lors de la comparaison des fichiers."
$htmlfile.Add("<td>")
$htmlfile.Add("ERREUR LORS DE LA COMPARAISON DES FICHIERS")
}
$htmlfile.Add("</td>")
$htmlfile.Add("</tr>")
}
else
{
#Supprimer le fichier XML fraichement crée, inutile car aucune modification par rapport à l'ancien
Remove-Item $newitem -Verbose -Force
}
}
$htmlfile.Add("</table>")
$htmlfile.Add("<br>")
$htmlfile.Add("<br>")
$htmlfile.Add("<br>")
if ($infos.Count -gt 0)
{
$sendmail = $true
$htmlfile.Add("<table>")
$htmlfile.Add("<tr>")
$htmlfile.Add("<th>GPO</th>")
$htmlfile.Add("<th>Action</th>")
$htmlfile.Add("</tr>")
foreach ($entry in $infos)
{
$htmlfile.Add("<tr>")
$htmlfile.Add("<td>$($entry.gpo)</td>")
if ($entry.Information -eq "La GPO a été créée")
{
$htmlfile.Add("<td div='create'>Creation d'une GPO</td>")
}
else
{
$htmlfile.Add("<td div='delete'>Suppression d'une GPO</td>")
}
$htmlfile.Add("</tr>")
}
}
$htmlfile.Add("</table>")
$htmlfile.Add("</body>")
$htmlfile.Add("</html>")
Write-Debug "Export du fichier HTML $(Join-Path $workspace "$htmlfilename")"
$htmlfile | Out-File $(Join-Path $workspace "$htmlfilename")
$htmlcontent = ""
foreach ($ligne in $htmlfile) { $htmlcontent += $ligne}
$accesserror = $false
if ($sendmail)
{
Send-MailMessage -From "$from" -To $to -Subject "Modifications sur GPO" -Body $htmlcontent -BodyAsHtml -Attachments $(Join-Path $workspace "$htmlfilename") -SmtpServer "$mailserver" -Port $smtpport -UseSsl:$usessl -Encoding $encoding
}
$creds = new-object System.Management.Automation.PSCredential -ArgumentList "$username",$("$password" | ConvertTo-SecureString -AsPlainText -Force)
try
{
$drive = New-PSDrive -PSProvider FileSystem -Name "strategies" -Root "$backuplocation" -Credential $creds -ErrorAction Stop
}
catch
{
$accesserror = $true
Write-Host -ForegroundColor Red "Impossible de se connecter au lecteur réseau. $($error[0].exception.message)"
}
if (!$accesserror)
{
foreach ($file in (Get-ChildItem $workspace "*.html" |Where-Object {$_.name -ne "$htmlfilename"}))
{
try
{
Move-Item $file "strategies:\" -Force -ErrorAction Stop -Verbose
#Remove-Item $file -Force -ErrorAction Stop -Verbose
}
catch
{
Write-Host "Erreur sur $($file.name) : $($error[0].exception.Message)"
}
}
}
remove-psdrive -Name "strategies" -PSProvider FileSystem
+18
View File
@@ -0,0 +1,18 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
import-module activedirectory
$utilisateurs = Get-ADUser -Filter * -Properties *
$actifs = $utilisateurs | Where-Object {$_.enabled -eq $true}
$date = Get-Date
$connectes = $actifs | Where-Object {($_.lastlogondate -lt $date.AddMonths(-6)) -and ($_.lastlogondate -ne $null)}
$tableau = @()
foreach ($user in $connectes)
{
$ajout = New-Object Psobject
$ajout | Add-Member -Name "Nom" -MemberType Noteproperty -value $user.name
$ajout | Add-Member -Name "Logon" -MemberType Noteproperty -value $user.Lastlogondate
$ajout | Add-Member -Name "S.I.D" -MemberType Noteproperty -value $user.sid.value
$tableau += $ajout
}
$tableau
+131
View File
@@ -0,0 +1,131 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
$nomanagerstring = "Sans Manager"
$windowname = "Vue hierarchique de l'A.D."
$all = get-aduser -filter 'enabled -eq $true' -Properties manager,department,directreports
$arraylist = New-Object System.Collections.ArrayList
$managegroups = ($all | select-object -Property samaccountname,name,manager | Group-Object -Property manager)
$loop = $null
#J'ajoute les données du treeview à l'aide d'une fonction. C'est pour cela qu'elle est déclarée avant le restant du script
function Add-Treeview {
$treeView1.Nodes.Add($nomanagerstring,$nomanagerstring) | Out-Null
$userslevel = New-Object System.Collections.ArrayList
foreach ($utilisateur in $all)
{
$loop = $utilisateur.manager
#"Manager de début pour $($utilisateur.samaccountname) : $loop"
#$loop -eq $null
$level = 0
$array =@()
While($loop -ne $null)
{
$level++
$array += $loop
$loop = ($all | Where-Object {$_.distinguishedname -eq $loop}).manager #récupère le manager de l'utilisateur / S / S+1 / S+x afin de déterminer l'endroit dans l'arborescence
if ($array -contains $loop)
{
"$($utilisateur.samaccountname) boucle sur $loop"
$array.Clear()
break
}
}
if (($level -eq 0) -and ($managegroups.name.contains($utilisateur.distinguishedname)) -ne $false)
{
$userslevel.Add([PSCUSTOMOBJECT]@{"name" = $utilisateur.name;"samaccountname" = $utilisateur.samaccountname;"Manager" = "Direction";"level" = $level;"Department" = $utilisateur.department}) |Out-Null
}
elseif ($level -eq 0)
{
$userslevel.Add([PSCUSTOMOBJECT]@{"name" = $utilisateur.name;"samaccountname" = $utilisateur.samaccountname;"Manager" = $nomanagerstring;"level" = $level;"Department" = $utilisateur.department}) | Out-Null
}
else
{
$userslevel.Add([PSCUSTOMOBJECT]@{"name" = $utilisateur.name;"samaccountname" = $utilisateur.samaccountname;"Manager" = $utilisateur.Manager;"level" = $level;"Department" = $utilisateur.department}) | Out-Null
}
}
$userslevel = $userslevel | Sort-Object -Property level
$groupedlevel = $userslevel | Group-Object -Property level
foreach ($level in $groupedlevel){
foreach ($utilisateur in $level.Group)
{
$ispresent = $null
if ($utilisateur.Manager -eq $nomanagerstring)
{
$treeView1.nodes[$nomanagerstring].nodes.add($utilisateur.samaccountname, $utilisateur.name) | Out-Null
}
else
{
$managername = $all | Where-Object {$_.distinguishedname -eq $utilisateur.Manager}
$ispresent = $treeView1.Nodes.Find($managername.samaccountname,$true)
#@($utilisateur.name,$ispresent.count) | ft
if ($($ispresent.count) -eq 0 -or ($ispresent -eq $null))
{
$treeView1.Nodes.Add($utilisateur.samaccountname,"$($utilisateur.name) - $($utilisateur.department)") | Out-Null
}
else
{
$ispresent[0].nodes.add($utilisateur.samaccountname,"$($utilisateur.name) - $($utilisateur.department)") | Out-Null
}
}
}
}
#Trier le treeview c'est mieux :)
$treeView1.Sorted = $true
}
#################################################################
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion
#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$treeView1 = New-Object System.Windows.Forms.TreeView
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 407
$System_Drawing_Size.Width = 558
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.Name = "form1"
$form1.Text = $windowname
$treeView1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 24
$System_Drawing_Point.Y = 127
$treeView1.Location = $System_Drawing_Point
$treeView1.Name = "treeView1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 268
$System_Drawing_Size.Width = 522
$treeView1.Size = $System_Drawing_Size
$treeView1.TabIndex = 0
Add-Treeview
$form1.Controls.Add($treeView1)
$InitialFormWindowState = $form1.WindowState
$form1.add_Load($OnLoadForm_StateCorrection)
$form1.ShowDialog()| Out-Null
+349
View File
@@ -0,0 +1,349 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
Function Reactivate-ADUSER
{
<#
.SYNOPSIS
Script de réactivation de compte d'utilisateur.
.DESCRIPTION
Ce script permet de réactiver des comptes utilisateurs désactivés, de modifier leur mot de passe, leur date de désactivation en une seule ligne de commande.
.EXAMPLE
C:\PS> Reactivate-Aduser -SamAccountName NicolasLang -Unlock
Réactive l'utilisateur NicolasLang
.EXAMPLE
C:\PS> Reactivate-ADUSER -SamAccountName NicolasLang -NewExpirationDate 10d
Met une date d'expiration du compte dans 10 jours
.EXAMPLE
C:\PS> Get-Aduser -filter 'samaccountname -like "Interimaire_*"' | Reactivate-ADUSER -NewExpirationDate 1m -NewPassword "TempPASS" -ChangePasswordAtLogon
Ajoute un mois à la date d'expiration, créé un nouveau mot de passe et force son changement à la prochaine ouverture de session pour tous les comptes commençant par "Interimaire_"
.INPUTS
Des objets du type [Microsoft.ActiveDirectory.Management.ADUser], généralement issus d'une commande Get-Aduser
.OUTPUTS
Un objet Arraylist qu'il est possible de renvoyer vers Export-CSV pour une lecture et un stockage aisé
.PARAMETER SamAccountName
Le nom du compte Windows à réactiver. Peut provenir du pipe.
.PARAMETER Unlock
Réactive le compte (décoche la case "vérrouillé" dans l'AD)
.PARAMETER NewExpirationDate
Permet de définir une date d'expiration par rapport à aujourd'hui. Le format est le suivant : (durée)(valeur)
La valeur est soit : d (pour Days : Jours), m (pour Months : Mois), y (pour Year : Année)
Ainsi, une valeur de 2d correspond à 2 jours. Le compte sera desactivé après demain à 23h59:59.
.PARAMETER NewPassword
Le nouveau mot de passe choisi pour le / les utilisateur(s) à réactiver
.PARAMETER ChangePasswordAtLogon
Précise si le mot de passe est à changer à la prochaine ouverture de session.
.LINK
https://nicolaslang.fr/articles/gerer-aisement-les-deverrouillages-de-comptes
.NOTES
Crée par Nicolas Lang
#>
[CmdletBinding(DefaultParametersetName="unlock",
ConfirmImpact="Medium",
SupportsShouldProcess=$true,
helpURI="http://nicolaslang.blogspot.com/",
SupportsPaging=$false,
PositionalBinding=$false
)]
param (
[Parameter (Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[Alias("Username","Compte")]
[ValidateNotNullOrEmpty()]
[string]$SamAccountName,
[Parameter (Mandatory=$false)]
[switch]$Unlock,
[Parameter (Mandatory=$false)]
[ValidatePattern('^(?\d+)(?[d,m,y])$')]
[string]$NewExpirationDate,
[Parameter (Mandatory=$false)]
[string]$NewPassword,
[Parameter (Mandatory=$false)]
[switch]$ChangePasswordAtLogon
)
Begin
{
[switch]$whatif = $false
$whatif = $PSCmdlet.MyInvocation.BoundParameters["whatif"]
$verbose = $PSCmdlet.MyInvocation.BoundParameters["Verbose"]
$verbosestatus = $VerbosePreference
if ($verbose)
{
$VerbosePreference = "Continue"
}
$array = New-Object System.Collections.ArrayList
}
Process
{
#On vérifie l'entrée du pipe, et on s'assure que le format de l'objet est correct
if ($_)
{
Write-Verbose "Vérification des informations venant du pipe"
if ($_ -isnot [Microsoft.ActiveDirectory.Management.ADUser])
{
return $(throw("Le type de données est incorrect"))
}
if ($verbose)
{
Write-Verbose "Informations du pipe valides"
}
$compte = $_
}
else
{
Write-Verbose "Recherche du compte $SamAccountName dans l'AD"
try
{
$compte = get-aduser $SamAccountName -Properties passwordlastset,AccountExpirationDate,Lockedout -ErrorAction Stop
}
#Si pas de commande, alors peut etre pas de module?
catch [System.Management.Automation.CommandNotFoundException]
{
Write-Verbose "Erreur sur la commande, recherche du module AD dans la liste des modules disponibles"
#On vérifie s'il est disponible, et on tente de le charger
if ((Get-Module -listavailable ActiveDirectory) -eq $null)
{
Return "Module ActiveDirectory manquant. Installez les outils RSAT pour utiliser cette fonction"
}
else
{
try
{
Write-Verbose "Module trouvé, intégration dans PowerShell"
Import-Module ActiveDirectory -ErrorAction Stop
}
catch
{
return $(throw("Impossible de charger le module ActiveDirectory! Have you tried turn it off and on again, Moss?"))
}
try
{
Write-Verbose "Intégration OK : Nouvelle recherche du compte."
$compte = Get-ADUser $SamAccountName -ErrorAction Stop
}
catch
{
Return $(throw("Une nouvelle erreur s'est produite : $($error[0].Exception)"))
}
}
}
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
{
return $(throw("Le compte $Samaccountname est introuvable"))
}
catch
{
return "Une erreur inconnue s'est produite : $($error[0])"
}
}
$user = $compte
$object = [PSCUSTOMOBJECT]@{
"Compte" = $user.samaccountname
"Nom" = $user.name
}
#region EXPIRATION
if ($NewExpirationDate)
{
switch ($user.accountexpirationdate)
{
$null { $accountexpirationdate = "?"}
default { $accountexpirationdate = $user.accountexpirationdate}
}
$object | Add-Member -MemberType NoteProperty -Name "Accountexpirationdate" -Value $accountexpirationdate
Write-Verbose "Calcul de la nouvelle date d'expiration."
$NewExpirationDate -match '^(?\d+)(?[d,m,y])$' | Out-Null
switch ($Matches.duree)
{
"d" {$expirationdate = (Get-Date).date.AddDays(1).AddDays($Matches.valeur)}
"m" {$expirationdate = (Get-Date).date.AddDays(1).AddMonths($Matches.valeur)}
"y" {$expirationdate = (Get-Date).date.AddDays(1).AddYears($Matches.valeur)}
}
Write-Verbose "Nouvelle date : $expirationdate"
Write-Verbose "Application de la nouvelle date au compte $($user.samaccountname)"
try
{
Set-ADUser $user -AccountExpirationDate $expirationdate -ErrorAction Stop -WhatIf:([bool]$whatif)
}
catch
{
return $(throw("Une erreur s'est produite durant la modification de la date d'expiration sur $($user.samaccountname)"))
}
try
{
$accountexpirationdate = (Get-aduser $user -Properties Accountexpirationdate -ErrorAction Stop).AccountexpirationDate
}
catch
{
throw("Impossible de récuperer les informations d'expiration du compte $user")
}
finally
{
$object | Add-Member -Name "AccountExpirationDate_apres" -MemberType NoteProperty -Value $accountexpirationdate
}
}
#endregion EXPIRATION
#region CHANGEPASSWORDATLOGON
if ($ChangePasswordAtLogon.IsPresent)
{
switch ($user.passwordexpired)
{
$true { $passwordchangevalue = "Oui"}
$false { $passwordchangevalue = "Non"}
default { $passwordchangevalue = "?"}
}
$object | Add-Member "ChangePasswordAtLogon" -MemberType NoteProperty -Value $passwordchangevalue
Write-Verbose "Application du changement de mot de passe forcé"
try
{
set-aduser $user -ChangePasswordAtLogon $true -WhatIf:([bool]$whatif)
}
catch
{
return $(throw("Erreur lors de l'application du changement de mdp à la prochaine ouverture de session. $($error[0])"))
}
finally
{
Write-Verbose "Récupération du nouveau status de changement de mot de passe"
$passwordchangevalue = $null
switch ((get-aduser $user -Properties passwordexpired).passwordexpired)
{
$true { $passwordchangevalue = "Oui"}
$false { $passwordchangevalue = "Non"}
default { $passwordchangevalue = "?"}
}
$object | Add-Member "ChangePasswordAtLogon_Apres" -MemberType NoteProperty -Value $passwordchangevalue
}
}
#endregion CHANGEPASSWORDATLOGON
#region PASSWORD
if ($NewPassword)
{
$invalidpassword = $true
Write-Verbose "Modification du mot de passe pour $($user.samaccountname)"
While ($invalidpassword)
{
try
{
Set-ADAccountPassword $user -Reset -NewPassword (ConvertTo-SecureString $NewPassword -AsPlainText -Force) -ErrorAction Stop -WhatIf:([bool]$whatif)
$invalidpassword = $false
}
catch [Microsoft.ActiveDirectory.Management.ADPasswordComplexityException]
{
$invalidpassword = $true
$NewPassword = Read-Host "Le mot de passe ne respecte pas le niveau de complexité, de longueur, ou d'historique.`nEntrez un nouveau mot de passe : "
}
catch
{
return $(throw("Erreur lors de la mise à jour du mot de passe sur $($user.samaccountname).`n$($error[0])"))
}
finally
{
$object | Add-Member -MemberType NoteProperty -Name "Password_apres" -Value $NewPassword -Force
}
}
}
#endregion PASSWORD
#region UNLOCK
if ($Unlock.IsPresent)
{
switch ($user.lockedout)
{
$true { $islockedout = "Oui" }
$false { $islockedout = "Non" }
default { $islockedout = "???" }
}
$object | Add-Member -Name "Verrouillage" -MemberType NoteProperty -Value $islockedout
Write-Verbose "Déverouillage du compte utilisateur $($user.samaccountname)"
try
{
Unlock-ADAccount -Identity $user -WhatIf:([bool]$whatif)
}
catch
{
return $(throw("Une erreur est survenue lors du déverouillage du compte $($user.samaccountname)`n$($error[0])"))
}
switch ((get-aduser $user -Properties lockedout).lockedout)
{
$true {$islockedout = "Oui"}
$false {$islockedout = "Non"}
default {$islockedout = "???"}
}
$object | Add-Member -Name "Verrouillage_apres" -MemberType NoteProperty -Value $islockedout
}
#endregion UNLOCK
$array.Add($object) | Out-Null
}
End
{
$VerbosePreference = $verbosestatus
return $array
}
}
@@ -0,0 +1,614 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
#La variable $path représente le repertoire dans lequel les données seront sauvegardées. Changez le également dans le script de planification pour qu'il corresponde à celui renseigné ici
$path = "\\nas\ScriptPS\Workspaces\TemporaryUserToGroup"
#Le nom des colonnes. Changez le à votre guise, mais ne le changez plus une fois que le script est mis en production
$columnsnames = @("Util.","Groupe","De","Jusque")
#Labels que vous pouvez changer à votre guise
$labelusername = "Util."
$labelgroupname = "Groupe"
$labelfromname = "De"
$labeluntilincluded = "Jusque (inclus)"
$labelform = "Ajout de groupe temporaire by Nicolas LANG. lang.nicolas54 arobase gmail .com"
$popupmessage = "Choisissez un utilisateur et un ou plusieurs groupes"
#Différents messages d'erreur que vous pouvez modifier si besoin est
$aderror = "Impossible d'obtenir des informations de groupe ou d'utilisateur. Vérifiez que le module AD pour Powershell est activé ou que le controleur de domaine est joignable"
$nopathcreated = "Impossible de créer $path"
try
{
$users = Get-ADUser -filter 'enabled -eq $true'
$groups = Get-ADGroup -filter *
}
catch
{
Write-Output $aderror
Start-Sleep -Seconds 5
throw("AD Error")
}
$datestart = Get-Date -Format yyyy-MM-dd
$array = New-Object System.Collections.ArrayList
If (!(Test-Path $path))
{
Try
{
New-Item $path -ItemType Folder -Force
}
Catch
{
throw($nopathcreated)
}
}
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
#endregion
#region Generated Form Objects
$bds = New-Object System.Windows.Forms.BindingSource
$form1 = New-Object System.Windows.Forms.Form
$groupBox_permatemp = New-Object System.Windows.Forms.GroupBox
$radioButton_temporary = New-Object System.Windows.Forms.RadioButton
$radioButton_permanent = New-Object System.Windows.Forms.RadioButton
$label4 = New-Object System.Windows.Forms.Label
$button_OK = New-Object System.Windows.Forms.Button
$button3 = New-Object System.Windows.Forms.Button
$button_remove = New-Object System.Windows.Forms.Button
$button_add = New-Object System.Windows.Forms.Button
$listBox_results = New-Object System.Windows.Forms.ListBox
$label_from = New-Object System.Windows.Forms.Label
$dateTimePicker2 = New-Object System.Windows.Forms.DateTimePicker
$dateTimePicker1 = New-Object System.Windows.Forms.DateTimePicker
$label_group = New-Object System.Windows.Forms.Label
$label_utilisateur = New-Object System.Windows.Forms.Label
$comboBox1 = New-Object System.Windows.Forms.ComboBox
$datagridview1 = New-Object System.Windows.Forms.datagridview
$checkedListBox1 = New-Object System.Windows.Forms.CheckedListBox
$button_uncheck = New-Object System.Windows.Forms.Button
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects
#region fonctions
function Check-Date{
if ([datetime]$dateTimePicker1.value -gt [datetime]$dateTimePicker2.Value)
{
$dateTimePicker2.value = $dateTimePicker1.Value
}
}
Function Show-popup([string]$message){
$popup = New-Object -ComObject Wscript.Shell
$popup.Popup($message,0,"Erreur",0x0)
}
Function Check-Array($row, $comparearray){
$return = $false
foreach ($line in $comparearray)
{
if (!(Compare-Object $row.psobject.properties $line.psobject.properties))
{
$return = $true
return $return
}
}
return $return
}
#endregion
#show_sidebar: false
visible: false
----------------------------------------------
#Generated Event Script Blocks
#show_sidebar: false
visible: false
----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$handler_button_add_MouseClick=
{
}
$handler_dateTimePicker2_ValueChanged=
{
Check-Date
}
$button_OK_OnClick=
{
if ($array.Count -gt 0)
{
$dateTime = "$(Get-Date -Format yyyyMMdd_HHmmss).xml"
$array | Export-Clixml (Join-Path $path $dateTime)
$form1.Close()
}
}
$handler_button3_MouseClick=
{
}
$handler_dateTimePicker1_ValueChanged=
{
Check-Date
}
$handler_button_uncheck_Click=
{
foreach ($checked in $checkedListBox1.CheckedIndices)
{
$checkedListBox1.SetItemChecked($checked,$False)
}
}
$handler_radioButton_permanent_CheckedChanged=
{
if ($radioButton_permanent.Checked)
{
$dateTimePicker1.Enabled = $False
$dateTimePicker2.Enabled = $False
}
else
{
$dateTimePicker1.Enabled = $True
$dateTimePicker2.Enabled = $True
}
}
$button_remove_OnClick=
{
foreach ($selectedrow in $datagridview1.SelectedRows)
{
$index= $array.IndexOf(($array | Where-Object {$_ -eq $selectedrow.DataBoundItem}))
$array.RemoveAt($index)
}
$datagridview1.DataSource = $null
$bds.DataSource = $null
$bds.DataSource = $array
$datagridview1.DataSource = $bds
}
$handler_button_OK_MouseClick=
{
$array | Export-Clixml
}
$button3_OnClick=
{
$array.Clear()
$datagridview1.DataSource = $null
$bds.DataSource = $null
$bds.DataSource = $array
$datagridview1.DataSource = $bds
#TODO: Place custom script here
}
$handler_button_remove_MouseClick=
{
#TODO: Place custom script here
}
$button_add_OnClick=
{
if ($checkedListBox1.SelectedItems.Count -gt 0 -and $comboBox1.SelectedItem -ne $null)
{
Foreach ($item in $($checkedListBox1.CheckedItems))
{
$newline = [pscustomobject]@{$columnsnames[0]=$comboBox1.SelectedItem;$columnsnames[1]=$item;$columnsnames[2]=([datetime]$dateTimePicker1.Value).ToShortDateString();$columnsnames[3]=([datetime]$dateTimePicker2.Value).ToShortDateString()}
$result = (Check-Array -row $newline -comparearray $array)
if (!($result))
{
$array.add($newline)
}
}
$datagridview1.DataSource = $null
$bds.DataSource = $null
$bds.DataSource = $array
$datagridview1.DataSource = $bds
}
else
{
Show-Popup $popupmessage
}
#TODO: Place custom script here
}
$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
$form1.WindowState = $InitialFormWindowState
$comboBox1.items.AddRange($($users | select-object -ExpandProperty samaccountname | sort-object))
$checkedListBox1.items.AddRange($($groups | select-object -ExpandProperty name | sort-object))
}
#show_sidebar: false
visible: false
----------------------------------------------
#region Generated Form Code
$form1.AcceptButton = $button_OK
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 261
$System_Drawing_Size.Width = 1033
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.MaximizeBox = $False
$form1.Name = "form1"
$form1.ShowIcon = $False
$form1.Text = $labelform
$button_uncheck.BackColor = [System.Drawing.Color]::FromArgb(255,255,255,255)
$button_uncheck.DataBindings.DefaultDataSourceUpdateMode = 0
$button_uncheck.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",6,0,3,0)
$button_uncheck.ForeColor = [System.Drawing.Color]::FromArgb(255,255,0,0)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 444
$System_Drawing_Point.Y = 42
$button_uncheck.Location = $System_Drawing_Point
$button_uncheck.Name = "button_uncheck"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 17
$System_Drawing_Size.Width = 23
$button_uncheck.Size = $System_Drawing_Size
$button_uncheck.TabIndex = 13
$button_uncheck.Text = "X"
$button_uncheck.UseVisualStyleBackColor = $False
$button_uncheck.add_Click($handler_button_uncheck_Click)
$form1.Controls.Add($button_uncheck)
$dataGridView1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 520
$System_Drawing_Point.Y = 8
$dataGridView1.Location = $System_Drawing_Point
$dataGridView1.Name = "dataGridView1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 241
$System_Drawing_Size.Width = 449
$dataGridView1.Size = $System_Drawing_Size
$dataGridView1.TabIndex = 12
$dataGridView1.SelectionMode = 1
$dataGridView1.AllowUserToAddRows = $False
$dataGridView1.AllowUserToDeleteRows = $False
$bds.DataSource = $array
$datagridview1.DataSource = $bds
$form1.Controls.Add($dataGridView1)
$groupBox_permatemp.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 14
$System_Drawing_Point.Y = 68
$groupBox_permatemp.Location = $System_Drawing_Point
$groupBox_permatemp.Name = "groupBox_permatemp"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 74
$System_Drawing_Size.Width = 200
$groupBox_permatemp.Size = $System_Drawing_Size
$groupBox_permatemp.TabIndex = 2
$groupBox_permatemp.TabStop = $False
$form1.Controls.Add($groupBox_permatemp)
$radioButton_temporary.Checked = $True
$radioButton_temporary.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 7
$System_Drawing_Point.Y = 38
$radioButton_temporary.Location = $System_Drawing_Point
$radioButton_temporary.Name = "radioButton_temporary"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 24
$System_Drawing_Size.Width = 104
$radioButton_temporary.Size = $System_Drawing_Size
$radioButton_temporary.TabIndex = 3
$radioButton_temporary.TabStop = $True
$radioButton_temporary.Text = "Temporaire"
$radioButton_temporary.UseVisualStyleBackColor = $True
$groupBox_permatemp.Controls.Add($radioButton_temporary)
$radioButton_permanent.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 7
$System_Drawing_Point.Y = 10
$radioButton_permanent.Location = $System_Drawing_Point
$radioButton_permanent.Name = "radioButton_permanent"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 24
$System_Drawing_Size.Width = 104
$radioButton_permanent.Size = $System_Drawing_Size
$radioButton_permanent.TabIndex = 2
$radioButton_permanent.TabStop = $True
$radioButton_permanent.Text = "Permanent"
$radioButton_permanent.UseVisualStyleBackColor = $True
$radioButton_permanent.add_CheckedChanged($handler_radioButton_permanent_CheckedChanged)
$groupBox_permatemp.Controls.Add($radioButton_permanent)
$groupBox_permatemp.Visible = $False
$label4.BorderStyle = 1
$label4.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 14
$System_Drawing_Point.Y = 198
$label4.Location = $System_Drawing_Point
$label4.Name = "label4"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 200
$label4.Size = $System_Drawing_Size
$label4.TabIndex = 9
$label4.Text = $labeluntilincluded
$label4.TextAlign = 32
$form1.Controls.Add($label4)
$button_OK.DataBindings.DefaultDataSourceUpdateMode = 0
$button_OK.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",8,0,3,0)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 975
$System_Drawing_Point.Y = 8
$button_OK.Location = $System_Drawing_Point
$button_OK.Name = "button_OK"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 31
$System_Drawing_Size.Width = 55
$button_OK.Size = $System_Drawing_Size
$button_OK.TabIndex = 11
$button_OK.Text = "OK"
$button_OK.UseVisualStyleBackColor = $True
$button_OK.add_Click($button_OK_OnClick)
#$button_OK.add_MouseClick($handler_button_OK_MouseClick)
$form1.Controls.Add($button_OK)
$button3.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 472
$System_Drawing_Point.Y = 182
$button3.Location = $System_Drawing_Point
$button3.Name = "button3"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 39
$System_Drawing_Size.Width = 42
$button3.Size = $System_Drawing_Size
$button3.TabIndex = 9
$button3.Text = "<<"
$button3.UseVisualStyleBackColor = $True
$button3.add_Click($button3_OnClick)
$button3.add_MouseClick($handler_button3_MouseClick)
$form1.Controls.Add($button3)
$button_remove.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 472
$System_Drawing_Point.Y = 138
$button_remove.Location = $System_Drawing_Point
$button_remove.Name = "button_remove"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 38
$System_Drawing_Size.Width = 42
$button_remove.Size = $System_Drawing_Size
$button_remove.TabIndex = 8
$button_remove.Text = "<"
$button_remove.UseVisualStyleBackColor = $True
$button_remove.add_Click($button_remove_OnClick)
$button_remove.add_MouseClick($handler_button_remove_MouseClick)
$form1.Controls.Add($button_remove)
$button_add.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 472
$System_Drawing_Point.Y = 42
$button_add.Location = $System_Drawing_Point
$button_add.Name = "button_add"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 34
$System_Drawing_Size.Width = 42
$button_add.Size = $System_Drawing_Size
$button_add.TabIndex = 7
$button_add.Text = ">"
$button_add.UseVisualStyleBackColor = $True
$button_add.add_Click($button_add_OnClick)
$button_add.add_MouseClick($handler_button_add_MouseClick)
$form1.Controls.Add($button_add)
$listBox_results.DataBindings.DefaultDataSourceUpdateMode = 0
$listBox_results.FormattingEnabled = $True
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 543
$System_Drawing_Point.Y = 9
$listBox_results.Location = $System_Drawing_Point
$listBox_results.Name = "listBox_results"
$listBox_results.SelectionMode = 3
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 238
$System_Drawing_Size.Width = 238
$listBox_results.Size = $System_Drawing_Size
$listBox_results.TabIndex = 10
$form1.Controls.Add($listBox_results)
$label_from.BorderStyle = 1
$label_from.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 14
$System_Drawing_Point.Y = 149
$label_from.Location = $System_Drawing_Point
$label_from.Name = "label_from"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 200
$label_from.Size = $System_Drawing_Size
$label_from.TabIndex = 6
$label_from.Text = $labelfromname
$label_from.TextAlign = 32
$form1.Controls.Add($label_from)
$dateTimePicker2.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 14
$System_Drawing_Point.Y = 224
$dateTimePicker2.Location = $System_Drawing_Point
$dateTimePicker2.Name = "dateTimePicker2"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 200
$dateTimePicker2.Size = $System_Drawing_Size
$dateTimePicker2.TabIndex = 5
$dateTimePicker2.add_ValueChanged($handler_dateTimePicker2_ValueChanged)
$form1.Controls.Add($dateTimePicker2)
$dateTimePicker1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 14
$System_Drawing_Point.Y = 175
$dateTimePicker1.Location = $System_Drawing_Point
$dateTimePicker1.MinDate = "2015-09-03"
$dateTimePicker1.Name = "dateTimePicker1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 200
$dateTimePicker1.Size = $System_Drawing_Size
$dateTimePicker1.TabIndex = 4
$dateTimePicker1.add_ValueChanged($handler_dateTimePicker1_ValueChanged)
$form1.Controls.Add($dateTimePicker1)
$label_group.BorderStyle = 1
$label_group.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 237
$System_Drawing_Point.Y = 9
$label_group.Location = $System_Drawing_Point
$label_group.Name = "label_group"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 228
$label_group.Size = $System_Drawing_Size
$label_group.TabIndex = 3
$label_group.Text = $labelgroupname
$label_group.TextAlign = 32
$form1.Controls.Add($label_group)
$label_utilisateur.BorderStyle = 1
$label_utilisateur.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 14
$System_Drawing_Point.Y = 9
$label_utilisateur.Location = $System_Drawing_Point
$label_utilisateur.Name = "label_utilisateur"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 200
$label_utilisateur.Size = $System_Drawing_Size
$label_utilisateur.TabIndex = 2
$label_utilisateur.Text = $labelusername
$label_utilisateur.TextAlign = 32
$form1.Controls.Add($label_utilisateur)
$comboBox1.DropDownStyle = 2
$comboBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$comboBox1.FormattingEnabled = $True
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 13
$System_Drawing_Point.Y = 45
$comboBox1.Location = $System_Drawing_Point
$comboBox1.Name = "comboBox1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 21
$System_Drawing_Size.Width = 201
$comboBox1.Size = $System_Drawing_Size
$comboBox1.TabIndex = 1
$form1.Controls.Add($comboBox1)
$checkedListBox1.CheckOnClick = $True
$checkedListBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$checkedListBox1.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",8,0,3,0)
$checkedListBox1.FormattingEnabled = $True
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 237
$System_Drawing_Point.Y = 59
$checkedListBox1.Location = $System_Drawing_Point
$checkedListBox1.Name = "checkedListBox1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 184
$System_Drawing_Size.Width = 228
$checkedListBox1.Size = $System_Drawing_Size
$checkedListBox1.TabIndex = 6
$form1.Controls.Add($checkedListBox1)
#endregion Generated Form Code
#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
$form1.ShowDialog()| Out-Null
@@ -0,0 +1,221 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
$ErrorActionPreference = "Stop"
#Faites correspondre $path avec la même valeur que dans le script d'interface utilisateur
$path = "\\nas\ScriptPS\Workspaces\TemporaryUserToGroup"
$filelist = Get-ChildItem $path
#Les fichiers XML sont générés avec un identifiant numérique. La regex va filtrer selon ce critère
$totreat = $filelist | Where-Object {$_.Name -match "^\p{Nd}.+.xml$"}
#Les fichiers à moitié traités commencent par un A puis un identifiant numérique. La encore, la regex va filtrer.
$resultarrayimports = $filelist | Where-Object {$_.Name -match "^A\p{Nd}.+.xml$"}
$resultarray = New-Object System.Collections.ArrayList
$global:headers = $null
function Update-File
{
param($from = $null,$until = $null)
$result = $null
if ($from -ne $null)
{
$result = $resultarray.IndexOf($from)
if ($result -eq -1)
{
"$(get-date -format yyyyMMdd_HHmmss) : Update from FROM - $($line.$($global:headers[1])) / $($line.$($global:headers[2])) => $($Error[0].Exception.Message)" >> "$path\warning.txt"
throw("No result for FROM in the result array")
}
else
{
$resultarray[$result].$($global:headers[2]+"_checked") = "X"
}
}
elseif ($until -ne $null)
{
$result = $resultarray.IndexOf($until)
if ($result -eq -1)
{
"$(get-date -format yyyyMMdd_HHmmss) : Update from UNTIL - $($line.$($global:headers[1])) / $($line.$($global:headers[2])) => $($Error[0].Exception.Message)" >> "$path\warning.txt"
throw("No result for UNTIL in the result array")
}
else
{
$resultarray[$result].$($global:headers[3]+"_checked") = "X"
}
}
else
{
"$(get-date -format yyyyMMdd_HHmmss) : A Null value came to the function => $($Error[0].Exception.Message)" >> "$path\warning.txt"
throw("Null Value from function")
}
}
#Récupération des fichiers et ajout des colonnes de check date
foreach ($file in $totreat)
{
try
{
$array = Import-Clixml $file.FullName
}
catch
{
"$(get-date -format yyyyMMdd_HHmmss) : $($file.FullName) => $($Error[0].Exception.Message)" >> "$path\error.txt"
throw("Error while importing")
}
$global:headers = $array[0].psobject.Properties.name
$array | Add-Member -MemberType NoteProperty -Name $($global:headers[2]+"_checked") -Value $null
$array | Add-Member -MemberType NoteProperty -Name $($global:headers[3]+"_checked") -Value $null
$array | Add-Member -MemberType NoteProperty -Name "Original_file" -Value $file.Name
foreach ($entry in $array)
{
$resultarray.Add($entry) | Out-Null
}
}
#Récupère les headers si aucun fichier créé depuis la GUI n'existe.
if ($global:headers -eq $null)
{
#Tente depuis des fichiers déja importés
try
{
$array = Import-Clixml ($filelist | Where-Object {$_.Name -like "IMPORTED_*"} | Select-Object -First 1).fullname
$Global:headers = $array[0].psobject.Properties.name
}
catch
{
#Si rien, tente depuis un fichier Axxxxx.xml issu d'un $resultarray précedent
try
{
$array = Import-Clixml $($resultarrayimports | Select-Object -First 1).FullName
$global:headers = $array[0].psobject.Properties.name
}
catch
{
"$(get-date -format yyyyMMdd_HHmmss) : No file to import" >> "$path\warning.txt"
throw("Nothing to import!")
}
}
}
#Rajoute chaque enregistrement déja exporté auparavant
if ($resultarrayimports -ne $null)
{
$import = Import-Clixml $resultarrayimports.FullName
foreach ($result in $import)
{
$resultarray.Add($result)
}
foreach ($result in $resultarrayimports)
{
Move-Item $result.FullName (join-path $path $("IMPORTED_"+ $($result.Name)))
}
}
#Renomme chaque fichier totreat, considéré comme intégré, pour ne plus être pris en compte au prochain passage du script
foreach ($file in $totreat)
{
$newname = "IMPORTED_" + $file.Name
try
{
Move-Item $file.FullName (Join-Path $path $newname) -Force
}
catch
{
"$(get-date -format yyyyMMdd_HHmmss) : $($file.FullName) / $newname => $($Error[0].Exception.Message)" >> "$path\error.txt"
throw("Error while moving item")
}
}
#Checke de chaque entrée dans resultarray
$date = get-date
foreach ($line in $resultarray)
{
$line
if ((Get-Date $($line.$($global:headers[2]))).date -le $date.Date -and $line.$($global:headers[2]+"_checked") -eq $null)
{
try
{
Add-ADGroupMember $line.$($global:headers[1]) $line.$($global:headers[0])
Write-output "Adding $($line.$($global:headers[0])) to $($line.$($global:headers[1])) / $($line.$($global:headers[2])) to $($line.$($global:headers[3]))"
}
catch [Microsoft.ActiveDirectory.Management.ADException]
{
"$(get-date -format yyyyMMdd_HHmmss) : $($line.$($global:headers[1])) / $($line.$($global:headers[0])) => $($Error[0].Exception.Message)" >> "$path\warning.txt"
}
catch
{
"$(get-date -format yyyyMMdd_HHmmss) : $($line.$($global:headers[1])) / $($line.$($global:headers[0])) => $($Error[0].Exception.Message)" >> "$path\error.txt"
throw("Erreur!")
}
Update-File -from $line
}
if ((Get-Date $($line.$($global:headers[3]))).date -lt $date.Date -and $line.$($global:headers[3]+"_checked") -eq $null)
{
try
{
Write-output "Removing $($line.$($global:headers[0])) from $($line.$($global:headers[1])) / $($line.$($global:headers[2])) to $($line.$($global:headers[3]))"
Remove-ADGroupMember $line.$($global:headers[1]) $line.$($global:headers[0]) -Confirm:$false
}
catch [Microsoft.ActiveDirectory.Management.ADException]
{
"Account not member of the group "
"$(get-date -format yyyyMMdd_HHmmss) : $($line.$($global:headers[1])) / $($line.$($global:headers[0])) => $($Error[0].Exception.Message)" >> "$path\warning.txt"
}
catch
{
"$(get-date -format yyyyMMdd_HHmmss) : $($line.$($global:headers[1])) / $($line.$($global:headers[0])) => $($Error[0].Exception.Message)" >> "$path\error.txt"
throw("Erreur!")
}
Update-File -until $line
}
}
#Clean des entrées
$indexarray = @()
$index = 0
foreach ($line in $resultarray)
{
if ($line.$($global:headers[2]+"_checked") -eq "X" -and $line.$($global:headers[3]+"_checked") -eq "X")
{
$indexarray += $index
}
$index++
}
$indexarray = $indexarray | Sort-Object -Descending
foreach ($entry in $indexarray)
{
$resultarray.RemoveAt($entry)
}
$rafile = "A"+(Get-Date).Ticks+".xml"
if ($resultarray.Count -gt 0)
{
$resultarray | Export-Clixml (Join-Path $path $rafile)
}
+52
View File
@@ -0,0 +1,52 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
#Liste des serveurs à analyser
$serveurs = @("DC1","DC2","DC3","hyperv1","hyperv2","hyperv3","hyperv4","lotus1","lotus2")
#création de la variable qui stockera les résultats
$table = New-Object System.Collections.ArrayList
#L'heure de réference. C'est l'instant T qui définira l'heure exacte sur les serveurs en retirant le temps de fonctionnement du script
$heurereference = get-date
#Pour chaque serveur dans la liste...
foreach ($serveur in $serveurs)
{
write-host "Récupération de $serveur"
$resultat = $null
#Nous obtenons l'heure du serveur
$temps = Get-WmiObject win32_localtime -ComputerName $serveur
#Nous reprenons l'heure actuelle
$heurecompare = Get-Date
#Enregistrement d'un message d'erreur s'il en est
if (!$temps)
{
$resultat = "Erreur $($error[0].exception.message)"
}
else
{
#Nous formatons la valeur pour lui donner le format JJ/MM/AAAA hh:mm:ss
$resultat = $(("{0:D2}" -f $temps.day) + "/" + ("{0:D2}" -f $temps.month) + "/" + [string]$temps.year + " " + ("{0:D2}" -f $temps.hour) +":"+ ("{0:D2}" -f $temps.minute)+":" + ("{0:D2}" -f $temps.second))
#Nous la définissons en format date, et nous retirons le nombre de ticks passés. La méthode Addticks() est utilisée, mais en précisant une valeur négative elle retirera des ticks, comme c'est le cas ici
$resultat = (get-date $resultat).addticks(($heurereference - $heurecompare).Ticks))
}
#Nous ajoutons dans la table un objet qui correspond au nom du serveur et à l'heure recalculée
$table.Add([PSCUSTOMOBJECT]@{
"Serveur" = $serveur
"Heure" = $resultat
})
}
#Une fois tout ceci fini, nous avons un joli fichier CSV sur le bureau avec les informations récoltées
$table | Export-Csv -Path $(([environment]::GetFolderPath("Desktop") + "\"+$(get-date -Format yyyyMMdd_HHmm)+"_date_heure_serveurs.csv")) -NoTypeInformation -Delimiter ";" -Force
if ($?)
{
"fichier exporté sur le bureau"
}
else
{
"Erreur lors de la création du fichier"
$table
}
$table
+73
View File
@@ -0,0 +1,73 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
function Give-time {
$retour = (Get-date).ToLongTimeString()
return $retour
}
$fullpathtofile = "$([environment]::getfolderpath("Desktop"))\export_ad_"+$((get-date).toshortdatestring().replace("/","-"))+".csv"
Write-Host "$(Give-time) : Ajout du module Active Directory"
try
{
ipmo activedirectory
}
catch
{
Write-Host "$(Give-time) : Attention! Impossible de récupérer le module A.D. pour Powershell. Assurez vous que les RSAT sont bien activés (si vous êtes sur un poste client) ou que le contrôleur de domaine sur lequel vous lancez ce script est correctement configuré"
Write-host "show_sidebar: false
visible: false
------------Fin du script dans 10 secondes---------------"
$x = 0
do
{
Write-Host -NoNewline "*"
Start-Sleep -Seconds 1
$x++
}until ($x -ge 10)
Exit
}
Write-Host "$(Give-time) : Obtention des données de l'A.D."
$users = Get-ADUser -filter * -Properties name,memberof | Sort-Object -Property memberof | Select-Object name,samaccountname,memberof
$max=0
Write-host "$(Give-time) : Calcul du maximum de groupes"
foreach ($user in $users)
{
if ($max -lt $($user.memberof).count)
{
$max = $(($user.memberof).count)
}
}
$array = new-object System.collections.arraylist
Write-Host "$(Give-time) : Analyse des données"
foreach ($user in $users)
{
$object = New-Object psobject
$object | Add-Member -MemberType NoteProperty -Name "Name" -Value $($user.name)
$object | Add-Member -MemberType NoteProperty -Name "SamAccountName" -Value $($user.samaccountname)
$groups = $($user.memberof) | % {$_.split(",")[0] -replace ("^CN=","")}
$grpnumber = 0
for ($start = 0; $start -lt $max;$start++)
{
if (!$groups -or !$groups[$start])
{
$object |Add-member -membertype Noteproperty -name "Group Number $($start+1)" -value ""
}
else
{
$object | Add-Member -MemberType NoteProperty -Name "Group Number $($start+1)" -value @($groups)[$start]
}
}
$array.Add($object) | Out-Null
}
Write-host "$(Give-time) : Fin de l'analyse des données. Export du fichier csv sur le bureau"
$array | sort-object -Property name | Export-Csv -Path $fullpathtofile -Encoding UTF8 -Force -NoTypeInformation -Delimiter ";"
+279
View File
@@ -0,0 +1,279 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
param(
[int]$joursprochains = 0
)
#Ce paramètre vous permettra de choisir sur combien de jours vous souhaitez analyser les sauvegardes
#Le serveur SMTP pour l'envoi du mail
$mailserver = "smtpserver.domain.local"
#L'expéditeur
$from = "moi@domain.local"
#Le / Les destinateurs
$to = @("moi@domain.local","lui@domain.local","eux@autredomaine.fr")
#On démarre un fichier de log, utile en cas de problème
Start-Transcript C:\Temp\BECheck.txt -Force
#On essaie d'importer le module BEMCLI. S'il n'existe pas, alors on arrête le script
try
{
Import-Module BEMCLI
}
catch
{
Write-Output "Impossible d'importer le module BEMCLI"
throw("No BEMCLI")
exit
}
#Un peu de texte pour alimenter le fichier de log
if ($joursprochains -ne 0)
{
Write-Output "$((get-date).tolongtimestring()) : Vérification pour les $joursprochains prochains jours."
}
Write-Output "$((get-date).tolongtimestring()) : Récupération de l'objet de librairie"
#On essaie d'obtenir l'objet de libraire. Si c'est impossible, on coupe.
try
{
$librairie = Get-BERoboticLibraryDevice
}
catch
{
Write-Output "$((get-date).tolongtimestring()) : Impossible de récupérer la libraire : $($Error[0])"
throw("Library error")
exit
}
# On essaie ensuite de récuperer la liste des backups. Si une erreur se présente, on coupe.
try
{
$listofjobs = Get-BEJob -JobType "Backup"
}
catch
{
Write-Output "$((get-date).tolongtimestring()) : Impossible de récuperer les jobs : $($error[0])"
throw("Backup error")
exit
}
#region inventaire
#Lancement d'un inventaire. Si pas d'inventaire... et bien... la aussi, on coupe.
try
{
$inventory = Submit-BEInventoryJob -RoboticLibraryDevice $librairie
}
catch
{
Write-Output "$((get-date).tolongtimestring()) : Une erreur s'est produite durant le lancement de l'inventaire : $($Error[0])"
throw("Inventory error")
exit
}
#Attente du lancement du job d'inventaire
#L'outil BEMCLI est assez mal concu sur certains points. Il y a un décallage entre le lancement de l'inventaire et sa détection dans les jobs actifs.
#Nous devons donc attendre que l'inventaire déclenché précedemment soit détecté et actif.
Write-Output "Attente du lancement du job`n"
do
{
try
{
$jobcheck = Get-BEActiveJobDetail
}
catch
{
Write-host -NoNewline "-"
}
$jobfinished = Get-BEJobHistory -FromStartTime (get-date).Date | Where-Object {$_.name -eq $($inventory.name)}
Start-Sleep -Seconds 10
Write-Host -NoNewline "-"
}
until($jobcheck.Name -eq $inventory.Name -or $jobfinished -ne $null)
Write-host " "
#Couleurs jolies pour patienter. Oui. Comme ça.
$i = 1
$z = 15
Write-Host $(" " * $((get-host).ui.rawui.buffersize.width)) -BackgroundColor 15
Write-Host "Attente de la fin du job d'inventaire"
Write-Host $(" " * $((get-host).ui.rawui.buffersize.width)) -BackgroundColor 15
do {
if ($i % $((get-host).UI.RawUI.BufferSize.Width) -eq 0)
{
if ($z -eq 0){$z = 16}
$z--
Write-host " " -BackgroundColor $z
}
else
{
Write-Host -NoNewline " " -BackgroundColor $z
}
$i++
Start-Sleep -Seconds 1
$endofjob = Get-BEJobHistory -FromStartTime (get-date).Date | Where-Object {$_.name -eq $($inventory.name)}
}while ($endofjob -eq $null)
#Si le job n'est pas en succès, on coupe la et on avertit. Sinon, on continue.
if ($endofjob.JobStatus -ne "Succeeded")
{
Write-Output "$((get-date).tolongtimestring()) : Fin de l'inventaire."
Send-MailMessage -From $from -To $to -SmtpServer $mailserver -Subject "Erreur durant l'inventaire" -Body [string]($endofjob | ConvertTo-Html) -BodyAsHtml
Stop-Transcript
throw("ERREUR DURANT L'INVENTAIRE")
Exit
}
Write-Output "$((get-date).tolongtimestring()) : Fin de l'inventaire."
#endregion
#Récupération du pool de media géré par BE. Nous recalculons à l'aide d'une propriété dynamique la date car elle est au format texte.
#Nous en aurons besoin au format DateTime pour pouvoir faire le tri.
Write-output "$((get-date).tolongtimestring()) : Récupération des médias gérés par BE."
try
{
$mediapool = (get-bemedia) | Select-Object Name,AllocatedDate,@{Name = "Date ajoutable";Expression = {Get-date $_.AppendableUntilDate}} | Sort-Object "date ajoutable" -Descending
}
catch
{
Write-output "$((get-date).tolongtimestring()) : Erreur lors de la récupération du pool de médias : $($error[0])"
}
#Récupération du contenu de l'autoloader.
Write-output "$((get-date).tolongtimestring()) : Récupération du contenu de l'autoloader."
try
{
$slots = Get-BERoboticLibrarySlot -RoboticLibraryDevice $librairie -IsCleaningSlot $false
}
catch
{
Write-output "$((get-date).tolongtimestring()) : Erreur lors de la récupération des slots de la librairie : $($Error[0])"
}
#Récupération des jobs dont le prochain démarrage est entre aujourd'hui et le nombre de jours précisé.
$jobrunningtoday = $listofjobs | Where-Object {($_.nextstartdate.date -ge (get-date).Date -and $_.nextstartdate.date -le (get-date).AddDays($joursprochains).Date)} | Select-Object Name,Storage,nextStartDate
if ($jobrunningtoday -eq $null)
{
Write-output "$((get-date).tolongtimestring()) : Aucune sauvegarde detectée. Fin du script"
throw("No backup")
exit
}
$tapedefinitions = New-Object System.Collections.ArrayList
$validtapes = New-Object System.Collections.ArrayList
$analysed = @()
# Dans la liste des jobs qui seront lancés, nous récupérons l'emplacement utilisé dans la librairie et vérifions le nombre de cassettes sur lequel nous pouvons écrire.
foreach ($job in $jobrunningtoday)
{
if ($job.storage -notin $analysed)
{
$analysed += $job.storage
$slots = Get-BERoboticLibrarySlot -RoboticLibraryPartition $job.storage
foreach ($tape in $slots)
{
try {
$writedate = $($($mediapool | Where-Object {$_.name -eq $tape.media})."date ajoutable" | Sort-Object -Property "date ajoutable" -Descending) | Select-Object -First 1 -ErrorAction Stop
}
catch
{
Write-Host "Pas de date d'écriture sur une cassette"
$writedate = get-date "01/01/2001"
}
$tapedefinitions.Add([PSCUSTOMOBJECT]@{
"Media" = $tape.Media
"Slot" = $tape.SlotNumber
"Storage" = $job.storage
"Ecrasable" = $writedate
}) | Out-Null
}
try
{
$toadd = $($tapedefinitions | Where-Object {$_.storage -eq $job.storage -and $_.ecrasable -lt $job.nextstartdate -and $_.media -and $_.media -ne $null})
foreach ($addit in $toadd)
{
$validtapes.add($addit) | Out-Null
}
}
catch
{
Write-output "$((get-date).tolongtimestring()) : Détection d'une erreur sur l'ajout de $($toadd.media) dans la liste des cassettes valides"
}
}
}
$groupedjobs = $jobrunningtoday | Group-Object Storage
$groupedtapes = $validtapes | Group-Object Storage
$errorarray = New-Object System.Collections.ArrayList
# En fonction de si l'on a le nombre précis de cassettes necessaires pour les sauvegardes (Ex : 2 backups a faire et 2 cassettes à disposition),
# nous affichons un message d'alerte.
# Si c'est un nombre inférieur, nous affichons une erreur
foreach ($line in $groupedjobs)
{
$oktapes = $($groupedtapes | Where-Object {$_.name -eq $line.name})
if ($line.count -gt $oktapes.count)
{
$errorarray.Add([PSCUSTOMOBJECT]@{
"Niveau" = "DANGER"
"Erreur" = "$($line.count) sauvegardes ($($line.Group.name)) dans les logements $($line.name), mais seulement $($oktapes.Count) disponible(s) $($oktapes.group.media)"
})
}
elseif ($line.count -eq $oktapes.count)
{
$errorarray.Add([PSCUSTOMOBJECT]@{
"Niveau" = "Avertissement"
"Erreur" = "Juste assez de cassettes disponibles en écriture dans les logements $($line.name) pour faire la/les sauvegarde(s) $($line.Group.name). Si une sauvegarde demande plus d'une cassette, une sera bloquée en attente de média!"
})
}
}
#Et nous envoyons le mail avec toutes les informations nécessaires
$body = ""
$subject = "Liste des cassettes"
$priority = "Normal"
if ($errorarray.Count -gt 0)
{
$subject = "!!DANGER SUR LES PROCHAINES SAUVEGARDES!!"
$priority = "High"
$body += $errorarray | ConvertTo-Html
$body += "
"*5
}
$choosein = $mediapool | Where-object {$_.name -notin $tapedefinitions.media} | Sort-Object "Date ajoutable"
$body += "Liste des cartouches triées par date d'écrasement
"
$body += $choosein | Select-Object Name,"Date ajoutable" | ConvertTo-Html
Send-MailMessage -SmtpServer $mailserver -From $from -To $to -Body $body -BodyAsHtml -Subject $subject -Encoding UTF8 -Priority $priority
Stop-Transcript
+19
View File
@@ -0,0 +1,19 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
$today = Get-Date
$cible = [datetime]"12/16/2016"
$feries = @([datetime]"01/01",[datetime]"05/01",[datetime]"05/08",[datetime]"07/14",[datetime]"08/15",[datetime]"11/1",[datetime]"11/11",[datetime]"12/25")
$feries += @([datetime]"04/21/2014",[datetime]"05/29/2014",[datetime]"06/09/2014",[datetime]"04/06/2015",[datetime]"05/14/2015",[datetime]"05/25/2015")
#ajoutez les jours qui sont fériés en conservant cette syntaxe
$joursouvres = 1
while ($today.ToLongDateString() -ne $cible.ToLongDateString())
{
if (($today.DayOfWeek -ne "Sunday") -and ($today.DayOfWeek -ne "Saturday") -and ($feries.tolongdatestring() -notcontains $today.tolongdatestring()))
{
$joursouvres++
}#fin if
$today = $today.AddDays(1)
}#fin while
Write-Host $joursouvres "jour(s) ouvré(s), aujourd'hui inclus"
+278
View File
@@ -0,0 +1,278 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
if ([System.IntPtr]::Size -ne 4)
{
Write-Error "Ce script doit être lancé depuis un Powershell 32 bits (disponible dans %windir%\syswow64\WindowsPowershell)"
Exit 3
}
function Clean-Filename ($Filename=$(throw "Can't be empty"))
{
$invalidcharsforpath = [System.IO.Path]::GetInvalidFileNameChars()
foreach ($char in $invalidcharsforpath)
{
$Filename = $Filename.replace("$char","")
return $Filename
}
}
$aclarray = New-Object System.Collections.ArrayList
$errorarray = New-Object System.Collections.ArrayList
#Le mot de passe à utiliser par l'identité proposée par Notes lorsque vous le lancez. Vous ne pouvez pas changer d'identité depuis ce script
$passwordforactualaccount = "PASSW0RD"
#Creating the Lotus object
$lotus = New-Object -ComObject Lotus.Notessession
try
{
#Ouverture de Notes avec l'identité par défaut et le mot de passe fourni
$lotus.Initialize("$passwordforactualaccount")
}
catch
{
Write-Output "Impossible d'ouvrir Notes, mot de passe incorrect?."
exit 2
}
Write-Output "Logged as $($lotus.usernamelist.canonical)"
<#
Ce script enregistrera les données sur le Bureau. Vous pouvez changer la valeur pour un chemin régulier ou utiliser une valeur de cette list :
Desktop
Programs
MyDocuments
Personal
(et bien d'autres...)
#>
$exportfolder = [Environment]::GetFolderPath("Desktop")
Set-Location $exportfolder
#Vous pouvez ajouter autant d'objets que vous le désirez dans la section $databasepath. Respectez juste la syntaxe et tout sera ok :
#"server" : Le chemin vers le serveur Domino. Exemple : "\\DOMINO01"
#"datapath" : Le chemin amenant versle repertoire des données de Domino, là ou sont stockés les fichiers NSF. Si vous utilisez un partage caché, ajoutez un ` avant le $. Cela échappera le caractère. Exemple : "d`$\domino\data\"
#"splitpart" : Utilisé pour séparaer le repertoire racine du restant. Il s'agit souvent de "data", et cette section est utilisée pour Lotus, permettant à l'object COM de trouver la base dans son arborescence.
# NE TERMINEZ PAS PAR Un \ . Si vous spécifiez une valeur avec un \ dedans, remplacez le par un double backslash \\.
#"lotusdomainname" : Le nom que la methode getdatabase() va utiliser pour selectionner le serveur.
$databasepath = @(
[PSOBJECT]@{
"server"="\\DOMINO01"
"datapath"="c`$\lotus\domino\data\"
"splitpart"="data"
"lotusdomainname"="domino01/Company France"
}
[PSOBJECT]@{
"server"="\\DOMINO03"
"datapath"="d`$\lotus\domino\data\"
"splitpart"="data"
"lotusdomainname"="domino02/Company UK"
}
)
$resultsarray = @()
#<#
$id =0
$databasepath | foreach {
#Pour chaque valeur dans databasepath, je joins "server" et "datapah' pour créer un chemin UNC pour l'analyse avec Robocopy
$analysed = Join-Path $_.server $_.datapath
#Le nom du fichier de log. $ID est incrementé, permettant de reconnaitre chaque entrée dans la variable $databasepath
$logname = "robocopylog_$id.log"
#Ajout de l'ID correspondante à l'entrée actuelle dans $databasepath
$_ | Add-Member -MemberType NoteProperty -Name "logid" -Value $id
$id++
$logname = Clean-Filename -Filename $logname
try
{
New-Item -ItemType file -Name "$logname" -Force -ErrorAction Stop
}
catch
{
Write-Host "Impossible de créer le fichier de log : $logname"
continue
}
#Lancement d'un nouveau processus Robocopy, qui scannera les dossiers à la recherche de nos précieux fichiers NSF, et enregistrant tout dans le fichier de log précedemment crée
$results = Start-process "robocopy" -argumentlist "$analysed NULL *.nsf /NDL /NS /L /S /XJ /TS /NJS /NJH /UNILOG:$logname" -PassThru -Wait -WindowStyle Hidden
#Les codes de sortie de Robocopy sont ok si en dessous de 7. Au dessus, une erreur s'est produite
if ($results.ExitCode -gt 7)
{
Write-Warning "Erreur avec robocopy!"
Exit 5
}
}
#>
#On récupère les fichiers de log robocopy
$loglist = Get-item "robocopylog_*.log"
foreach ($log in $loglist)
{
#On se lance à la recherche du bon serveur et on collecte les valeurs demandées
$thisserver = $null
foreach ($server in $databasepath)
{
if ($log.name -eq "robocopylog_$($server.logid).log")
{
$thisserver = $server
break
}
}
if ($thisserver -eq $null)
{
Write-host "Impossible de trouver le serveur qui a créé $($log.name)"
continue
}
else
{
#On récupère le contenu de chaque fichier...
Get-Content $log | % {
#Une petite regex pour retrouver le nom
if ($_.trim() -match "(?[\\].*$)")
{
#Et on retrouve le chemin du fichier NSF sous un format que l'objet Lotus pourra comprendre
$object = $null
$cutindex = $Matches.file.IndexOf("$($thisserver.splitpart)\")
$length = $Matches.file.Length
try
{
$object = [PSOBJECT]@{
"server" = $thisserver.lotusdomainname
"nsffile" = $Matches.file.Substring($cutindex,$length-$cutindex)
}
}
catch
{
Write-Warning "Erreur lors de l'obtention des infos de $($matches.file)"
}
$resultsarray += $object
}
}
}
}
#Maintenant que nous avons la liste des fichiers NSF, leur chemin, et le serveur domino qui est rattaché, nous pouvons collecter nos ACLs
$progress = 0
foreach ($entry in $resultsarray)
{
Write-Progress -Activity "Analyse des ACL" -Status $entry.nsffile -PercentComplete $($progress/$($resultsarray.count)*100)
$progress++
$index = 1
$aclobjectlist = @()
#Vidage de $db à chaque passage, pour pouvoir vérifier si la propriété .ISOpen est $false (DB manquante) ou si $db n'existe pas (problem avec le chemin)
$db = $null
#Connexion à la DB
$db = $lotus.GetDatabase($entry.server,$entry.nsffile)
#On verifie que l'ouverture se fait correctement
if ($db.IsOpen -eq $false -or $db -eq $null)
{
$message = $null
switch ($db.isopen)
{
$null {$message = $($error[0].Exception.Message)}
$false {$message = "Pas de base de données $($entry.nsffile) sur $($entry.server)"}
}
$errorarray.Add([PSCUSTOMOBJECT]@{
"Fichier" = $entry.nsffile -as [String]
"Serveur" = $entry.server -as [String]
"Erreur" = $message
})
Write-Host "Impossible d'ouvrir $($entry.nsffile) sur $($entry.server)"
continue
}
#On obtient la première ACL
$acl = $db.ACL.GetFirstEntry()
#On boucle tant qu'on trouve une autre ACL
while ($acl -ne $null)
{
#On récupère si ca n'est pas un serveur et si c'est un groupe ou une personne
if ($acl.IsServer -ne $true -and ($acl.isGroup -eq $true -or $acl.isperson -eq $true))
{
#Je vérifie seulement les propriétés de création et suppression de documents. D'autres droits existent, que vous pouvez ajouter à la suite en utilisant la même syntaxe.
$aclinfo = [PSCUSTOMOBJECT]@{
"Name" = $acl.Name
"CanCreateDocuments" = $acl.CanCreateDocuments
"CanDeleteDocuments" = $acl.CanDeleteDocuments
}
#Ajout de l'objet à la liste d'ACL
$aclobjectlist += [pscustomobject]@{"Nom" =$acl.name;"Droits"=$aclinfo}
$index++
}
#On obtient la prochaine ACL ... et ainsi de suite
$acl = $db.ACL.GetNextEntry($acl)
}
#Lorsque nous avons fini avec les ACL sur cette DB, on ajoute les résultats au tableau récaputilatif
$aclarray.Add([PSCUSTOMOBJECT]@{
"Serveur" = $entry.server -as [String]
"Fichier" = $entry.nsffile -as [String]
"ACL" = $aclobjectlist | Sort-Object -Property "Nom"}) | Out-Null
#Et on passe à la suivante
}
#On compte le maximum d'ACLs trouvées sur un DB. Cette valeur maximum sera utilisée pour ajouter des membres aux autres objets, d'avoir le même nombre partout afin d'avoir un fichier CSV à la fin.
$max = 0
$aclarray | % {
$count = $_.acl.count
if ($count -gt $max)
{
$max = $count
}
}
#Nouvel objet qui conservera toutes les données après formatage
$exportableaclarray = New-Object System.Collections.ArrayList
#On parcourt les résultats
foreach ($entry in $aclarray)
{
#On crée une nouvelle ligne qui démarrera avec le nom du serveur, puis le nom de la base NSF
$object = [PSCUSTOMOBJECT]@{
"Serveur" = $entry.serveur
"Fichier" = $entry.Fichier
}
$index=1
#On ajoute des colonnes. D'abord le nom, puis les droits de création, ensuite de suppression pour chaque ACL trouvée
foreach ($acl in $entry.acl)
{
$object | Add-Member -Name "Membre_$index" -MemberType NoteProperty -Value $acl.Nom
$object | Add-Member -Name "Droits_Creation_membre_$index" -MemberType NoteProperty -Value $acl.Droits.CanCreateDocuments
$object | Add-Member -Name "Droits_Suppression_membre_$index" -MemberType NoteProperty -Value $acl.Droits.CanDeleteDocuments
$index++
}
#Et on remplit le reste avec des valeurs vides jusqu'a ce que nous ayons le même nombre de colonnes que le fichier NSF avec le plus grand nombre d'ACL
for ($i = $index;$i -le $max;$i++)
{
$object | Add-Member -Name "Membre_$i" -MemberType NoteProperty -Value $null
$object | Add-Member -Name "Droits_Creation_membre_$i" -MemberType NoteProperty -Value $null
$object | Add-Member -Name "Droits_Suppression_membre_$i" -MemberType NoteProperty -Value $null
}
$exportableaclarray.Add($object) | Out-Null
}
#Puis nous exportons les résultats
$exportableaclarray | Export-Csv "$exportfolder\liste_acl_Notes.csv" -NoTypeInformation -Delimiter ";" -Encoding UTF8
#Et enfin les erreurs rencontrées
$errorarray | Export-Csv "$exportfolder\erreuracl.csv" -NoTypeInformation -Delimiter ";" -Encoding UTF8
+122
View File
@@ -0,0 +1,122 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
$debugging = $false #a mettre sur true pour avoir des infos sur la zone de code qui crée l'enregistrement
$date = Get-Date -Format "dd/MM/yyyy HH:mm:ss"
set-location $([Environment]::GetFolderPath("Mydocuments")) #se place dans le repertoire "mes documents" de l'utilisateur actuel
try
{
$base = Import-Clixml referencegroupes.xml
}
catch
{
Write-Host "Le fichier de réference n'existe pas, ou n'est pas disponible , il sera regénéré à la fin de ce script. Aucun fichier de modification ne se créera."
}
#ce bloc crée un message pour signifier qu'il n'a pas pu accéder au fichier de base. Si c'est le premier lancement, ou si le fichier n'est plus accessible, il le recréera avec ce que le script aura récuperé
$base = $base | Sort-Object -Property groupe -Unique
$Connection = New-Object -Com "ADODB.Connection" #création d'un objet de connexion
$Connection.Provider = "ADsDSOObject" #On spécifie que c'est une connexion LDAP
$Connection.Properties.Item("User ID")="CN=Nicolas LANG,O=Ma Société" #authentifiant à préciser
$Connection.Properties.Item("Password")="P@ssw0rd!" #Votre mot de passe
$Connection.Open("Active Directory Provider") #Nous mettons en place la connexion avec les identifiants précisés
$Command = New-Object -Com "ADODB.Command" #on initialise la commande qui sera fournie à la connexion $Connection
$Command.ActiveConnection = $Connection #On lie la commande à la connexion
$Query = "SELECT displayname, mail, member FROM 'LDAP://lotusserveur.mondomaine.com' WHERE objectclass='dominogroup'" #nous enregistrons un texte qui précise que nous selectionnons les propriétés displayname mail et member sur le serveur LDAP précisé de ce qui est un dominogroup
$Command.Commandtext = $Query
$Command.Commandtimeout = 60 #Ce timeout est le temps de validité de la commande avant qu'elle soit précisée comme perdue. Si votre base est imposante ou que votre connexion vers le serveur est lente, augmentez la valeur.
$execute = $Command.execute() #On execute la commande et on l'enregistre dans $execute
$tab = @() #on crée un tableau qui recueillera les données
$execute.MoveFirst() #nous nous déplaçons au premier enregistrement
function ajoutligne ($groupe=$null,$ajout=$null,$retrait=$null,$creation=$null,$suppression=$null,$reference="???") #Cette fonction permettra d'ajouter dans chaque colonne l'attribut et la valeur désirée
{
$obj = New-Object PSOBJECT
$obj | add-member -MemberType NoteProperty -Name "Date" -Value $date
$obj | add-member -MemberType NoteProperty -Name "Groupe" -Value $groupe
$obj | add-member -MemberType NoteProperty -Name "Ajout de" -Value $ajout
$obj | add-member -MemberType NoteProperty -Name "Retrait de" -Value $retrait
$obj | add-member -MemberType NoteProperty -Name "Création" -Value $creation
$obj | add-member -MemberType NoteProperty -Name "Suppression" -Value $suppression
if ($debugging -eq $true) {$obj | add-member -MemberType NoteProperty -Name "Debbuging only" -Value $reference}
return $obj
}
while ($execute.eof -eq $false) #cette boucle s'execute tant que nous ne sommes pas arrivés sur le EOF (End Of File) qui indique la fin des enregistrements. Une valeur BOF (Begin Of File) existe pour préciser le premier enregistrement.
{
$member = $execute.Fields | Where-Object {$_.name -eq "member"} #nous selectionnons dans l'element de la boucle la valeur "member"
$displayname = $execute.Fields | Where-Object {$_.name -eq "displayname"} #idem pour displayname
$addresse = $execute.Fields | Where-Object {$_.name -eq "mail"} #idem pour mail
if ($member.Value -isnot [System.DBNull]) #Pour un enregistrement de base de donnée vide, $null n'est pas valide. Le type pour une entrée vide est [System.DBNull]
{
$objet = New-Object PSOBJECT
$objet |add-member -Name "Groupe" -MemberType NoteProperty -Value $($displayname.value)
$objet |Add-Member -Name "Adresse" -MemberType NoteProperty -Value $($addresse.value)
$objet |add-member -Name "Membres" -MemberType NoteProperty -Value $($member.value)
$tab += $objet
}
$execute.MoveNext()
}
if ($base -eq $null) #crée la première reference si elle n'existe pas
{
$tab | Export-Clixml referencegroupes.xml
#(get-date).toshortdatestring()+";"+(get-date).toshorttimestring()+";Ecriture du fichier de reference" >> debug.txt
}
else #execute le script s'il trouve la première reference
{ $tab = $tab |Sort-Object -Property Groupe -Unique
$tab | Export-Clixml newbase.xml
#(get-date).toshortdatestring()+";"+(get-date).toshorttimestring()+";Ecriture du fichier de comparaison" >> debug.txt
$newbase = Import-Clixml newbase.xml
$recap =@()
foreach ($entree in $base)
{
if ($newbase.groupe -notcontains $entree.groupe) #si la nouvelle base ne comporte pas le groupe, alors c'est qu'il est supprimé
{
$recap += ajoutligne -groupe $entree.groupe -suppression $true -reference '$newbase.groupe -contains $entree.groupe'
}
else #si le groupe existe, on en vérifie les utilisateurs en appelant l'autre base
{
$comparaison = $newbase | Where-Object {$_.groupe -eq $entree.groupe}
$changements = $null
$changements = Compare-Object $entree.membres $comparaison.membres
foreach ($changement in $changements)
{
if ($changement.sideindicator -eq "=>")
{
$recap += ajoutligne -groupe $entree.groupe -ajout $changement.inputobject -reference '$changement.sideindicator -eq "=>"'
}
else
{
$recap += ajoutligne -groupe $entree.groupe -retrait $changement.inputobject -reference 'else ($changement.sideindicator -eq "<=")'
}
} # fin foreach ($changement in $changements)
} #fin else
} #foreach ($groupe in $entree.groupe)
foreach ($entree in $newbase)
{
if ($base.groupe -notcontains $entree.groupe) #si l'ancienne base ne comporte pas le groupe, alors c'est qu'il est crée
{
$recap += ajoutligne -groupe $entree.groupe -creation $true -reference '$base.groupe -notcontains $entree.groupe'
}
} # foreach ($entree in $newbase)
$recap | Export-Csv "Changements comptes.csv" -Encoding UTF8 -notypeinformation -Append -Delimiter ";" #export du fichier de suivi des modifications sur le compte
Move-Item -Path newbase.xml -destination referencegroupes.xml -Force #remplacement du fichier
} #fin else
+3
View File
@@ -1,3 +1,6 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
$versionexchange = Get-WmiObject Win32_Product | Where-object {$_.name -like "Microsoft Exchange Server"} $versionexchange = Get-WmiObject Win32_Product | Where-object {$_.name -like "Microsoft Exchange Server"}
$serveur = "[Nom de votre serveur exchange]" $serveur = "[Nom de votre serveur exchange]"
#Versions Exchange renvoyées sur le get-wmiobject Win32_Product #Versions Exchange renvoyées sur le get-wmiobject Win32_Product
+2
View File
@@ -1,3 +1,5 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
Add-PSSnapin Microsoft.Exchange.Management.Powershell.E2010 Add-PSSnapin Microsoft.Exchange.Management.Powershell.E2010
$domaines = get-accepteddomain $domaines = get-accepteddomain
$nomduserveur = "Entrez le nom de votre serveur" $nomduserveur = "Entrez le nom de votre serveur"
+83
View File
@@ -0,0 +1,83 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
#déplacement dans le repertoires "mes documents" de l'utilisateur actuel
Set-Location $([Environment]::GetFolderPath("Mydocuments"))
#import du module activedirectory
ipmo activedirectory
#nous récupérons la liste des ordinateurs du domaine, en prenant également la dernière ouverture de session
$ordinateurs = Get-ADComputer -Filter * -Properties lastlogondate | Select-Object -Property name,lastlogondate
#nous filtrons à 4 mois en arrière
$ordinateurs = $ordinateurs | Where-Object {$_.lastlogondate -gt $((Get-Date).addmonths(-4))}
#creation d'un tableau
$tableau = New-Object System.Collections.ArrayList
$progress = 0
foreach ($ordinateur in $ordinateurs)
{
$progress++
Write-Progress -Activity "Recherche d'écrans sur $($ordinateur.name) " -PercentComplete $($progress/$($ordinateurs.Count)*100) -Status "$progress / $($ordinateurs.count)"
$objet = New-Object Psobject
$objet |Add-Member -MemberType NoteProperty -Name "Ordinateur" -Value $ordinateur.name
$ping = $null
#nous pingons le poste.
$ping = Test-Connection -ComputerName $ordinateur.name -Count 1
#Si le TTL du poste est entre 65 et 128, c'est un poste windows. Nous continuons donc le script
if ($ping -and $ping.responsetimetolive -gt 64 -and $ping.responsetimetolive -le 128)
{
$objet |Add-Member -MemberType NoteProperty -Name "Répond au ping" -Value "Oui"
$moniteurs = $null
$moniteurs = $null
#on lance la requete WMI
$moniteurs = Get-WmiObject -Namespace root\wmi -Class wmiMonitorID -ComputerName $($ordinateur.name)
#Si le resultat de la commande precedente est une erreur, alors...
if (!$?)
{
Write-Host "Erreur!"
$objet | Add-Member -MemberType NoteProperty -Name "WMI" -Value "ERREUR!!"
}
#Sinon...
else
{
Write-Host "Aucune erreur"
$objet | Add-Member -MemberType NoteProperty -Name "WMI" -Value ""
}
$i=0
foreach ($moniteur in $moniteurs)
{
$i++
#Le modele est la deuxième valeur de la propriété instancename.
$modele = $moniteur.instancename.split("\")[1]
$sn = $null
#Récupération du SN puis ajout dans l'objet
$moniteur.serialnumberid | % {$sn += [char]$_}
$objet | Add-Member -MemberType NoteProperty -Name "Modèle ecran $i" -Value $modele
$objet | Add-Member -MemberType NoteProperty -Name "SN ecran $i" -Value $sn
}
$i++
for($i; $i -le 3;$i++)
{
$objet | Add-Member -MemberType NoteProperty -Name "Modèle ecran $i" -Value ""
$objet | Add-Member -MemberType NoteProperty -Name "SN ecran $i" -Value ""
}
}
#si le ttl est inférieur ou égal à 64, c'est un non windows
elseif ($ping.responsetimetolive -ne $null -and $ping.responsetimetolive -le 64)
{
$objet |Add-Member -MemberType NoteProperty -Name "Répond au ping" -Value "Non Windows"
}
else
{
$objet | Add-Member -MemberType NoteProperty -Name "Répond au ping" -Value "Non"
}
$null = $tableau.add($objet)
}
$tableau | Export-Clixml -Path "ecrans.xml"
$tableau | Export-Csv -Path "ecrans.csv" -NoTypeInformation -Encoding UTF8 -Force -Delimiter ";"
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
KEYPATH="/root/.ssh/reverseproxy2"
REMOTEHOST="reverseproxy-2.domaine"
# La synchro se fait par une récupération depuis le backup de master.
# Si keepalived est master, on ne fait pas de synchro
STATE=`/bin/snmpget -v2c -c public 127.0.0.1 KEEPALIVED-MIB::vrrpInstanceState.1 | /bin/sed -Er 's/(.*)INTEGER: (.*)\(([0-9])\)/\2/g'`
echo "State : ${STATE}"
if [[ "$STATE" == "master" ]]; then
echo "Master : No sync"
exit 2
fi
# Si keepalived est down, on ne fait pas de synchro (maintenance)
systemctl is-active --quiet keepalived
if [ $? -ne 0 ]; then
echo "Keepalived down : no sync"
exit 0
fi
echo "Run sync nginx"
RSYNCNGINX=$(/bin/rsync -e "ssh -i $KEYPATH" -aiuh root@$REMOTEHOST:/etc/nginx/ /etc/nginx)
if [ $? -eq 0 ]; then
echo "Run sync Let's Encrypt'"
RSYNCLE=$(/bin/rsync -e "ssh -i $KEYPATH" -aiuh root@$REMOTEHOST:/etc/letsencrypt/ /etc/letsencrypt)
else
exit 3
fi
if [ $? -eq 0 ]; then
echo "Run sync www"
RSYNCWWW=$(/bin/rsync -e "ssh -i $KEYPATH" -aiuh root@$REMOTEHOST:/var/www/ /var/www)
else
exit 2
fi
if [ $? -eq 0 ]; then
if [ -n "${RSYNCNGINX}" ] || [ -n "${RSYNCWWW}" ]; then
/usr/sbin/nginx -s reload
echo "reloaded."
fi
else
exit 1
fi
+127
View File
@@ -0,0 +1,127 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
function Get-LinuxGroups
{
[CmdletBinding(
SupportsShouldProcess=$false,
HelpUri="http://nicolaslang.blogspot.com"
)]
param(
[Parameter (Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$Name,
[Parameter (Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('(?&ltpropertyname&gt(Name|ID_Group|Member))\s+(?&ltoperator&gt(-like|-eq|-ceq|-clike))\s+"(?&ltvalue&gt.*)"')]
[string]$filter
)
begin
{
$groups = Get-Content /etc/group
$grouparray = New-Object System.Collections.ArrayList
$maxgroup = 0
#Calcul de la valeur maxgroup
foreach ($group in $groups)
{
$splitted = $group.split(":")
$count = $splitted[-1].split(",")
if ($count.count -gt $maxgroup)
{
$maxgroup = $count.count
}
}
foreach ($group in $groups)
{
$splitted = $group.split(":")
$count = $splitted[-1].split(",")
$object = [PSCustomObject]@{
"Name" = $splitted[0]
"ID_Group" = $splitted[2]
}
$loop = 0
foreach ($member in $count)
{
$object | Add-Member -Name "Member $($loop + 1)" -MemberType NoteProperty -Value $member
$loop++
}
while ($loop -lt $maxgroup)
{
$object | Add-Member -Name "Member $($loop + 1)" -MemberType NoteProperty -Value ""
$loop++
}
$object | Add-Member -name "TotalList" -MemberType NoteProperty -Value $count
$grouparray.Add($object) | Out-Null
}
#Définition des paramètres affichés par défaut
$defaultProperties = ($grouparray | Get-Member | Where-Object {$_.membertype -eq "NoteProperty" -and $_.name -like "Member*"}).Name
$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(DefaultDisplayPropertySet,[string[]]$defaultProperties)
$defaultdisplaypropertyset.ReferencedPropertyNames.insert(0,"ID_Group")
$defaultdisplaypropertyset.ReferencedPropertyNames.insert(0,"Name")
$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
$grouparray | Add-Member MemberSet PSStandardMembers $PSStandardMembers
}
Process
{
if ($filter)
{
$filter -match '(?&ltpropertyname&gt(Name|ID_Group|Member))\s+(?&ltoperator&gt(-like|-eq|-ceq|-clike))\s+"(?&ltvalue&gt.*)"' | Out-Null
if ($matches.propertyname -eq "Member")
{
Switch ($matches.operator)
{
"-like" {
$return = $grouparray | Where-object {$_.totallist.split(",") -like "$($matches.value)"}
}
"-clike"{
$return = $grouparray | Where-object {$_.totallist.split(",") -clike "$($matches.value)"}
}
"-eq" {
$return = $grouparray | Where-object {$_.totallist.split(",") -eq "$($matches.value)"}
}
"-ceq" {
$return = $grouparray | Where-object {$_.totallist.split(",") -ceq "$($matches.value)"}
}
}
return $return
}
else
{
Switch ($matches.operator)
{
"-like" {$return = $grouparray | Where-Object {$_.$($matches.propertyname) -like "$($matches.value)"}}
"-clike"{$return = $grouparray | Where-Object {$_.$($matches.propertyname) -clike "$($matches.value)"}}
"-eq" {$return = $grouparray | Where-Object {$_.$($matches.propertyname) -eq "$($matches.value)"}}
"-ceq" {$return = $grouparray | Where-Object {$_.$($matches.propertyname) -ceq "$($matches.value)"}}
}
return $return
}
}
elseif ($name)
{
return $($grouparray | Where-Object {$_.name -eq $name})
}
else
{
return $grouparray
}
}
}
+69
View File
@@ -0,0 +1,69 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
function Get-LinuxUsers
{
[CmdletBinding(
SupportsShouldProcess=$false,
HelpUri="http://nicolaslang.blogspot.com"
)]
param(
[Parameter (Position=0, ValueFromPipeline=$true)]
[ValidateNotNullOrEmpty()]
[string]$name,
[Parameter (Mandatory=$false)]
[ValidateNotNullOrEmpty()]
[ValidatePattern('(?&ltpropertyname&gt(Name|Pass|ID_User|ID_Group|Comment|Home|Shell))\s+(?&ltoperator&gt(-like|-eq|-ceq|-clike))\s+"(?&ltvalue&gt.*)"')]
[string]$filter,
[Parameter (DontShow,ValueFromPipelineByPropertyName=$true)]
[AllowNull()]
$totallist
)
$users = Get-content /etc/passwd
$userarray = New-Object System.Collections.ArrayList
foreach ($user in $users)
{
$splitted = $user.split(":")
$object = [PSCustomObject]@{
"Name" = $splitted[0]
"Pass" = $splitted[1]
"ID_User" = $splitted[2]
"ID_Group" = $splitted[3]
"Comment" = $splitted[4]
"Home" = $splitted[5]
"Shell" = $splitted[6]
}
$userarray.Add($object) | Out-Null
}
if($totallist)
{
$return = $userarray | Where-Object {$_.name -in $totallist.split(",")}
return $return
}
if ($filter)
{
$filter -match '(?&ltpropertyname&gt(Name|Pass|ID_User|ID_Group|Comment|Home|Shell))\s+(?&ltoperator&gt(-like|-eq|-ceq|-clike))\s+"(?&ltvalue&gt.*)"' | Out-Null
Switch ($matches.operator)
{
"-like" {$return = $userarray | Where-Object {$_.$($matches.propertyname) -like "$($matches.value)"}}
"-clike"{$return = $userarray | Where-Object {$_.$($matches.propertyname) -clike "$($matches.value)"}}
"-eq" {$return = $userarray | Where-Object {$_.$($matches.propertyname) -eq "$($matches.value)"}}
"-ceq" {$return = $userarray | Where-Object {$_.$($matches.propertyname) -ceq "$($matches.value)"}}
}
return ($return)
}
elseif ($name) {
$return = $userarray | Where-Object {$_.name -eq $name}
return ($return)
}
else {
return $userarray
}
}
+100
View File
@@ -0,0 +1,100 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
function get-netstat
{
#definition des paramètres servant aux requetes
param($port_local="*",$adresse_locale="*",$adresse_distante="*",$port_distant="*",[string]$Connection_Status="*")
#vérification de la validité des entrées
if ($port_local -ne '*')
{
if ($port_local -as [int] -is [int])
{[int]$port_local = $port_local}
else { throw("Port local non valide")}
}
if ($port_distant -ne '*')
{
if ($port_distant -as [int] -is [int])
{[int]$port_distant = $port_distant}
else { throw("Port distant non valide")}
}
if ($adresse_distante -ne '*')
{
if ($adresse_distante -as [Net.IPAddress] -is [Net.IPAddress])
{[Net.IPAddress]$adresse_distante =$adresse_distante}
else { throw("Adresse distante non valide")}
}
if ($adresse_locale -ne '*')
{
if ($adresse_locale -as [Net.IPAddress] -is [Net.IPAddress])
{[Net.IPAddress]$adresse_locale =$adresse_locale}
else { throw("Adresse locale non valide")}
}
$netstat = netstat -n
#on saute les 4 premières lignes pour éviter le texte de présentation des résultats de la commande netstat -n
$netstat = $netstat | Select-Object -Skip 4
#on modifie chaque ligne pour faire disparaitre les espaces surnuméraires
$resultat = @()
foreach ($entry in $netstat)
{
$entry = $entry.replace(" "," ")
$entry = $entry.replace(" "," ")
$entry = $entry.replace(" "," ")
$entry = $entry.replace(" "," ")
#cette entrée compte aussi les espaces insécables (alt+255)
$entry = $entry.replace(" "," ")
#création d'un objet qui va recueillir les proprietés de la ligne en cours
$ajout = New-Object Psobject
#on coupe à l'espace, et l'on ne prend pas en compte la première entrée qui correspond à l'espace avant le protocole
$entry = $entry.Split(" ") | Select-Object -Skip 1
#on sépare l'ip du port en prenant du début jusqu'à la dernière occurence du caractère ":" (séparer juste à ":" sans prendre la dernière occurence pose problème sur de l'ipv6
[string]$adresselocale = $entry[1].substring(0,$entry[1].lastindexof(":"))
[string]$adressedistante = $entry[2].substring(0,$entry[2].lastindexof(":"))
#de même pour le port, on prend la chaine allant du dernier ":" jusqu'a la fin. L'ajustement +1 / -1 est fait car la valeur "length" commence à 1, alors que l'indexation des caractères commence à 0
$portlocal = $entry[1].substring($entry[1].lastindexof(":")+1,$entry[1].length - $entry[1].lastindexof(":")-1)
$portdistant = $entry[2].substring($entry[2].lastindexof(":")+1,$entry[2].length - $entry[2].lastindexof(":")-1)
#si c'est une IPV6, l'adresse est entre [], il faut les retirer pour pouvoir avoir une info utilisable
if ($adresselocale.Chars(0) -eq "[")
{
$adresselocale = $adresselocale.Remove(0,1)
$adresselocale = $adresselocale.Remove($adresselocale.Length - 1,1)
#Une fois que l'on a ôté les caractères superflus, la variable peut être enregistrée sous le format [Net.IPAdress]
[Net.IPAddress]$adresselocale = $adresselocale
$adressedistante = $adressedistante.Remove(0,1)
$adressedistante = $adressedistante.Remove($adressedistante.Length - 1,1)
[Net.IPAddress]$adressedistante = $adressedistante
}
#on ajoute chacune des valeurs à l'objet...
$ajout | add-member -MemberType NoteProperty -Name "Protocole" -Value $entry[0]
$ajout | add-member -MemberType NoteProperty -Name "Adresse_locale" -Value $adresselocale
$ajout | add-member -MemberType NoteProperty -Name "Port_local" -Value $portlocal
$ajout | add-member -MemberType NoteProperty -Name "Adresse_distante" -Value $adressedistante
$ajout | add-member -MemberType NoteProperty -Name "Port_distant" -Value $portdistant
$ajout | add-member -MemberType NoteProperty -Name "status" -Value $entry[3]
# ... que l'on ajoute ensuite au tableau...
$resultat += $ajout
}
# ... dans lequel on filtre ensuite en fonction de ce qui a été demandé. Si les propriétés ne sont pas renseignées, elles sont de valeur "*", ce qui permet de renvoyer tout ce qui n'est pas précisé
$retour = $resultat | Where-Object {($_.port_local -like $port_local) -and ($_.adresse_locale -like $adresse_locale) -and ($_.adresse_distante -like $adresse_distante) -and ($_.port_distant -like $port_distant) -and ($_.status -like $connection_status)}
return $retour
}
+55
View File
@@ -0,0 +1,55 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
#ajout du snappin
Add-PSSnapin NutanixCMDletsPSSnapin
#l'ip du cluster que nous allons interroger
$clusterip = "10.0.0.100"
#un identifiant ayant possibilité de se connecter
$username = 'user@domain.fr'
#le mot de passe lié à cet utilisateur
$password = (Get-Content C:\users\moi\motdepassechiffré.txt | ConvertTo-SecureString)
#création d'une connexion
$connection = Connect-NTNXCluster -Server $ip -UserName $username -Password $password -ForcedConnection -AcceptInvalidSSLCerts
if ($connection.isconnected -eq $false)
{
exit 20
}
#id du container recherché
$id = "00042dc6-1b11-a279-6b43-246e960c61c2::44330611"
#on essaie d'obtenir les informations de compression, on exit avec un code d'erreur 30 si une erreur se produit. Vous pouvez ajouter dans la partie catch{} toute action supplémentaire qui vous permettrait d'avoir du debug.
try
{
$stats = Get-NTNXContainerStat -Id $id -Metrics data_reduction.overall.saving_ratio_ppm,data_reduction.compression.saving_ratio_ppm -ErrorAction Stop
}
catch
{
exit 30
}
#on prend la date et heure actuelle
$now = Get-Date
#on exporte nos informations en ajout d'un fichier CSV qui sera dans C:\Temp et qui aura pour nom la date du jour.
try{
[pscustomobject]@{
"date" = $now.ToShortDateString()
"heure" = $now.ToShortTimeString()
"métrique 1" = $stats[0].metric
"valeur 1" = $stats[0].values[0] / 1000000
"métrique 2" = $stats[1].metric
"valeur 2" = $stats[1].values[0] / 1000000
} | Export-Csv -Delimiter ";" -NoTypeInformation -Append -Encoding UTF8 -Path "C:\Temp\compression_$($now.ToShortDateString().Replace("/","_")).csv" -ErrorAction Stop
}
catch
{
exit 40
}
+3
View File
@@ -1,3 +1,6 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
#Au lancement du script, nous vérifions si le fichier de log de l'exécution du script n'est pas encore présent. #Au lancement du script, nous vérifions si le fichier de log de l'exécution du script n'est pas encore présent.
if (-not (Test-Path "\\serveur\publicshare\office_version\office_version_$($env:computername).txt")) if (-not (Test-Path "\\serveur\publicshare\office_version\office_version_$($env:computername).txt"))
{ {
+53
View File
@@ -0,0 +1,53 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
#On commence par importer le module Veeam pour Powershell. Ce module est disponible sur le serveur ayant Veeam Backup & Restore d'installé
Import-Module Veeam.Backup.PowerShell
# Nous enregistrons l'ensemble des jobs que nous voulons modifier. Ici, nous filtrons sur les jobs ayant "Premium" dans leur nom
$tochangejobs = Get-VBRJob -Name "premium"
# Cet index est juste là pour afficher la progression, rien de plus
$i = 1
#Pour chaque job dans les jobs sélectionnés
foreach ($changeme in $tochangejobs)
{
#On affiche la progression via Write-Progress
Write-Progress -Activity "Modification des jobs" -Status $($changeme).name -PercentComplete $($i / $($tochangejobs.count) \* 100)
#Pour les jobs de Synthetic Full, on peut utiliser Set-VBRJobAdvancedBackupOptions, qui permet de modifier certains paramètres que l'on trouve dans les arguments de la commande.
#Ici, TransformToSyntethicDays accepte une liste séparée par des virgules d'une énumération de jours.
Set-VBRJobAdvancedBackupOptions -Job $changeme -TransformToSyntethicDays Friday,Monday
#Par contre, Set-VBRJobAdvancedBackupOptions n'est pas en mesure de changer la durée de rétention.
#Pour ça, nous allons directement changer une propriété d'un objet représentant les options du job.
try
{
#Nous enregistrons les options du job sélectionné dans un objet
$joboptions = Get-VBRJobOptions -Job $changeme -ErrorAction Stop
#Puis nous modifions les propriétés de cet objet à notre guise. Ici, le nombre de points du job.
$joboptions.BackupStorageOptions.RetainCycles = 14
#Et enfin, nous appliquons à nouveau l'objet d'options de job à notre job, ce qui aura pour effet de le modifier.
Set-VBRJobOptions -Job $changeme -Options $joboptions -ErrorAction Stop
}
catch
{
#Un peu de Try / Catch au cas ou un problème arrive
Write-Error "Erreur sur $($premium.name)"
}
#On incrémente notre index pour l'affichage de Write-Progress
$i++
}
+72
View File
@@ -0,0 +1,72 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
Function Get-VMBackupsizes
{
#ajout du Snappin veeam
try {
Add-PSSnapin VeeamPSSnapin -ErrorAction Stop
}
catch {
exit 10
}
#récupération des backups
$backups = Get-VBRBackup
#récupération des jobs
$jobs = Get-VBRJob
#création d'un tableau
$array = New-Object System.collections.arraylist
#pour chaque backup dans la liste des backups
foreach ($backup in $backups)
{
#si le job avec le même ID possède une planification...
if ($($jobs | Where-Object {$_.id -eq $backup.JobId}).isScheduleEnabled -eq $true)
{
#définition d'une variable à "oui"
$isScheduled = "Oui"
}
else
{
#sinon à $false
$isScheduled = "Non"
}
#Recherche du job dont l'id est le même que l'id de job dans le backup en cours
$thisjob = $jobs | Where-Object {$_.id -eq $backup.info.jobid}
if ($thisjob -ne $null)
{
#Recherche des objets dans le job en question
$jobobject = Get-VBRJobObject $thisjob
}
else
{
$jobobject = $null
}
#Recherche des Objects In Backup et selection de vmname, calcul de la taille et des infos
$thisbackup = $backup.getlastoibs() | Select-Object -Property vmname,@{Name = "Size_calc"; Expression = {[math]::Round($($_.approxsize / 1024 / 1024 / 1024),2)}},info | sort -Property vmname
#pour chaque Object in Backup
foreach ($entry in $thisbackup)
{
#Recherche des objets dans le job en cours dont l'objectid est le même que l'id de l'Object in Backup actuel
$thisjobobject = $jobobject | Where-Object {$_.info.objectid -eq $entry.info.objectid}
#si ce jobobject n'est pas exclus
if(!$thisjobobject.isexcluded)
{
$null = $array.add([pscustomobject]@{
"VM" = $entry.vmName
"Active" = $isScheduled
"Job" = $backup.Name
"JobPath" = $backup.DirPath.ToString()
"JobRepository" = $backup.GetRepositoryName()
"Size" = $entry.size_calc
"LastPointCreation" = $backup.LastPointCreationTime
})
}
}
}
$array = $array | Sort-Object -Property Job,vm
return $array
}
+689
View File
@@ -0,0 +1,689 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
$scriptPath = $null
$answer = "z"
if ((Get-Host).Version.Major -le 2)
{
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
}
else
{
$scriptPath = $PSScriptRoot
}
$configfile = Join-Path $scriptPath "config.ini"
try
{
$configuration = Get-Content $configfile -ErrorAction Stop
}
catch
{
#region CONFIGFILECREATION
While($answer.tolower()[0] -ne "y" -and $answer.tolower()[0] -ne "n")
{
$answer = Read-host "Impossible d'accéder au fichier $configfile `nVoulez vous le créer? (Y/N)"
}
if ($answer.ToLower()[0] -eq "n")
{
throw("Fin du script")
}
else
{
#region DHCPPOOLS
$answer = "z"
while($answer.tolower()[0] -ne "y")
{
$ippoolarray = @()
$answer = "z"
Write-Host "Saisissez les plages DHCP, une par ligne. Entrez une ligne vide pour terminer."
do
{
$ippool = "Add_pools"
while($ippool -as [System.Net.IPAddress] -isnot [System.Net.IPAddress] -and $ippool -ne "")
{
$ippool = Read-Host "=>"
}
if ($ippool -ne "")
{
Write-host "$(([System.Net.IPAddress]$ippool).Ipaddresstostring) ajouté!"
$ippoolarray += $ippool
}
}while ($ippool -ne "")
$ippoolarray = $ippoolarray | Sort-Object -Unique
Write-Host "Vous avez choisi les pools suivants :`n"
$ippoolarray
while ($answer.tolower()[0] -ne "y" -and $answer.tolower()[0] -ne "n")
{
$answer = Read-Host "Est-ce correct? (Y/N)"
}
}
#endregion
#region DHCPSERVERS
$answer = "z"
while($answer.tolower()[0] -ne "y")
{
$dhcpserversarray = @()
$answer = "z"
Write-Host "Saisissez les noms ou ips des serveurs DHCP, un par ligne. Entrez une ligne vide pour terminer."
do
{
$dhcpserver = "Add_server"
while($dhcpserver -ne "")
{
$dhcpserver = Read-Host "=>"
if ($dhcpserver -ne "")
{
Write-host "$dhcpserver ajouté!"
$dhcpserversarray += $dhcpserver
}
}
}while ($dhcpserver -ne "")
$dhcpserversarray = $dhcpserversarray | Sort-Object -Unique
Write-Host "Vous avez choisi les serveurs suivants :`n"
$dhcpserversarray
while ($answer.tolower()[0] -ne "y" -and $answer.tolower()[0] -ne "n")
{
$answer = Read-Host "Est-ce correct? (Y/N)"
}
$answertotest = "z"
while ($answertotest.tolower()[0] -ne "y" -and $answertotest.tolower()[0] -ne "n" -and $answer -ne "n")
{
$answertotest = Read-Host "voulez vous tester la connexion aux serveurs? (Y/N)"
}
if ($answertotest.ToLower()[0] -eq "y")
{
$iserror = $false
foreach ($server in $dhcpserversarray)
{
$message = "Succès!"
$color = "Green"
if (!(Test-Connection $server -Count 1 -Quiet -ErrorAction Stop))
{
$iserror = $true
$message = "Echec! :c"
$color = "Red"
}
Write-host $server " => " $message -ForegroundColor $color
}
if ($iserror -eq $false)
{
Write-host "Tous les tests sont passés :)"
}
else
{
Write-Host "Une ou plusieurs erreurs sont arrivées."
do
{
$answer = Read-host "Voulez vous continuer malgré tout? (Y/N)"
}while ($answer.tolower()[0] -ne "y" -and $answer.tolower()[0] -ne "n")
if ($answer.tolower()[0] -eq "n")
{
throw("Vous avez arrêté le script")
}
}
}
}
#endregion
#region MAIL
$answertomail = "z"
while($answertomail.ToLower()[0] -ne "y")
{
do
{
Write-Host "Renseignez le nom du SMTP de messagerie"
$mailserver = Read-Host "=>"
Write-Host "Renseignez l'adresse de l'EXPEDITEUR"
$from = Read-Host "=>"
Write-Host "Renseignez l'adresse du DESTINATAIRE"
$to = Read-Host "=>"
$mailconfiguration = [pscustomobject]@{
"Mailserver"=$mailserver
"From" = $from
"To" = $to
}
$mailconfiguration | ft
$answertomail = Read-Host "Est-ce correct? (Y/N)"
}while($answertomail.ToLower()[0] -ne "y" -and $answertomail.ToLower()[0] -ne "n")
$answertosendmail = "z"
$mailreceived = "z"
if ($answertomail.ToLower()[0] -eq "y")
{
while($answertosendmail -ne "n")
{
do
{
$answertosendmail = Read-Host "Voulez vous envoyer un mail de test? (Y/N)"
} while($answertosendmail.ToLower()[0] -ne "y" -and $answertosendmail.ToLower()[0] -ne "n")
if ($answertosendmail.ToLower()[0] -eq "y")
{
$sendmailerror = $false
try
{
Send-MailMessage -From $from -To $to -Subject "Test mail du script Powershell" -SmtpServer $mailserver
}
catch
{
$sendmailerror = $true
Write-host "Une erreur s'est produite durant l'envoi du mail!"
}
if ($sendmailerror -eq $false)
{
do
{
$mailreceived = read-host "Le mail a été envoyé. L'avez vous recu? (Y/N)."
}while ($mailreceived.ToLower()[0] -ne "y" -and $mailreceived.ToLower()[0] -ne "n")
if ($mailreceived.ToLower()[0] -eq "n")
{
do
{
$answertomail = Read-Host "Voulez vous continuer et reconfigurer? (Y/N)"
}while ($answertomail.ToLower()[0] -ne "y" -and $answertomail.ToLower()[0] -ne "n")
switch ($answertomail.tolower()[0])
{
"y" { $answertomail = "n";$answertosendmail = "n" }
"n" { throw("Impossible d'envoyer le mail. Arrêt du script") }
}
}
else
{
$answertosendmail = "n"
}
}
}
}
}
}
#endregion
#region CHEMIN
$answer = "z"
$path = $null
do
{
do
{
$path = Read-Host "Entrez un chemin (local ou UNC) pour l'enregistrement des données du script`n=>"
$answerpathtest = Read-Host "Voulez vous tester le chemin :`n$path`n(Y/N) =>"
} until ($answerpathtest.ToLower()[0] -eq "y" -or $answerpathtest.ToLower()[0] -eq "n")
if ($answerpathtest -eq "y")
{
$answerpathretry = "z"
if (Test-Path $path)
{
Write-host -ForegroundColor Green "Le chemin est valide.`nTest d'écriture."
$testfilename = [string](get-date).Ticks+".test"
$answer = "y"
try
{
New-Item -ItemType File (Join-Path $path $testfilename) -Force
}
catch
{
Write-Host "Impossible d'écrire dans $path `nVeuillez selectionner un autre dossier."
$answer = "z"
}
Remove-Item (Join-Path $path $testfilename) -Force -ErrorAction SilentlyContinue
}
else
{
do
{
Write-Host "La destination n'existe pas. Voulez-vous la créer? (Y/N)"
$answerpathretry = Read-Host "=>"
} until ($answerpathretry.ToLower()[0] -eq "y" -or $answerpathretry.ToLower()[0] -eq "n")
if ($answerpathretry.ToLower()[0] -eq "n")
{
throw("Arrêt du script")
}
$answer = "z"
}
}
} until ($answer.ToLower()[0] -eq "y" -or $answer.ToLower()[0] -eq "n")
$answer = "z"
do
{
$answer = Read-Host "Voulez vous surveiller les réservations DHCP également? (Y/N)"
} until($answer.ToLower()[0] -eq "y" -or $answer.ToLower()[0] -eq "n")
#endregion
$dhcprescheck = $true
if ($answer.ToLower()[0] -eq "n")
{
$dhcprescheck = $false
}
}
try
{
$configurationarray = New-Object PSCUSTOMOBJECT
$configurationarray | Add-Member -Name pools -MemberType NoteProperty -Value $ippoolarray
$configurationarray | Add-Member -name servername -MemberType NoteProperty -Value $dhcpserversarray
$configurationarray | Add-Member -Name mailconfiguration -MemberType NoteProperty -Value $mailconfiguration
$configurationarray | Add-Member -Name path -MemberType NoteProperty -Value $path
$configurationarray | Add-Member -Name rescheck -MemberType NoteProperty -Value $dhcprescheck
}
catch
{
Write-Host -ForegroundColor Red "Une erreur s'est produite durant l'assemblage des infos de configuration. Voici l'état actuel de l'objet représentant la configuration :`n$configurationarray"
}
try
{
$configurationarray | Export-Clixml $configfile -ErrorAction Stop
}
catch
{
Write-Host -ForegroundColor Red "Impossible d'enregistrer le fichier de configuration. Le script va s'arrêter"
}
#endregion
} #end catch
$configurationarray = Import-Clixml $configfile -ErrorAction Stop
#region fichiers
#Précisez le chemin du fichier ou seront sauvegardées les données des PC détectés
$path = $configurationarray.path
$filename = "outsidedomain.xml" #Nom a donner au fichier.
$staticfile = "staticaddress.xml" #Nom a donner au fichier.
$exceptionfile = "exceptions.txt" #Nom du fichier d'exceptions
$exceptionpath = Join-Path $path $exceptionfile
$fullpath = Join-Path $path $filename
$staticpath = Join-Path $path $staticfile
$dateforcsv = Get-Date -Format "yyyy_MM"
#endregion
#region DHCP
$plages = $configurationarray.pools #Plage(s) à surveiller
$servername = $configurationarray.servername #nom de serveur(s) DHCP
#endregion
#region MAIL
$from = $configurationarray.mailconfiguration.From #Adresse mail de l'expéditeur
$to = $configurationarray.mailconfiguration.To #Adresse mail du destinataire
$smtpserver = $configurationarray.mailconfiguration.Mailserver #Serveur SMTP
$encoding = [System.Text.UTF8Encoding]::UTF8 #Encodage en UTF8 pour éviter les problèmes d'accents, entre autre
#endregion
#region jobs
$maximaljobperserver = 4
#endregion
#region variables
try
{
Import-module ActiveDirectory
}
catch
{
Write-host "Impossible de charger le module Active Directory pour Powershell. Ce module est-il bien installé et activé?"
Start-Sleep -Seconds 5
throw("No AD Module")
}
$computerlist = Get-ADComputer -filter *
$arraylist = New-Object System.Collections.ArrayList
$notindomainarraylist = New-Object System.Collections.ArrayList
$resultingarray = New-Object System.Collections.ArrayList
$staticresults = New-Object System.Collections.ArrayList
$staticmodified = New-Object System.Collections.ArrayList
$monitorstatic = $true
#endregion
function Report-StaticChange {
param(
[string]$Raison = "non spécifiée",
[string]$NewIP = $null,
[string]$OldIP = $null,
[string]$NewMAC = $null,
[string]$OldMAC = $null)
$staticmodified.Add([pscustomobject]@{
"Raison" = $Raison
"Nouvelle_IP" = $NewIP
"Ancienne_IP" = $OldIP
"Nouvelle_MAC" = $NewMAC
"Ancienne_MAC" = $OldMAC}) | Out-Null
}
try {
$staticresultsprevious = Import-Clixml $staticpath
}
catch
{
"Aucun fichier précedent d'IP reservées"
}
try{
$exceptions = Get-content $exceptionpath -erroraction stop
}
catch
{
Try
{
New-Item -ItemType File $exceptionpath -Force
}
catch
{
"Impossible de créer le fichier d'exception. Arrêt du script"
Start-Sleep -Seconds 5
throw("STOP FICHIER EXCEPT.")
}
}
try
{
$fichiernondomaine = Import-Clixml $fullpath
}
catch
{
Write-Output "Aucun fichier de précedence à $fullpath, vérification du chemin."
if (!(Test-Path $fullpath))
{
Write-Output "Chemin inexistant, création du fichier"
try
{
New-Item -ItemType File $fullpath -Force -ErrorAction Stop
}
catch
{
Write-Output "Impossible de créer le fichier, arret du script."
Start-Sleep -Seconds 5
throw($error[0].Exception)
}
}
}
foreach($plage in $plages)
{
foreach ($server in $servername)
{
if ($monitorstatic -eq $true)
{
if ((get-job -Name "$server*" | Where-Object {$_.state -eq "Running"}).count -ge $maximaljobperserver)
{
Write-Output "Plus de $maximaljobperserver jobs actifs sur $server. En attente de la libération de jobs."
do
{
Start-Sleep -Seconds 1
} while ((get-job -Name "$server*" | Where-Object {$_.state -eq "Running"}).count -ge $maximaljobperserver)
}
Start-Job -Name $($server+"_"+$plage+"_static") -ScriptBlock {
param($plage,$server)
$jobstaticresults = New-Object System.Collections.ArrayList
$staticstats = Invoke-Command -computername $server -scriptblock {powershell.exe "chcp 1252;Netsh dhcp server scope $($args[0]) show reservedip"} -ArgumentList $plage
foreach ($entry in $staticstats)
{
if ($entry.trim() -match "(?<ip>\d+.\d+.\d+.\d+)\W+-\W+(?<mac>\w+-\w+-\w+-\w+-\w+-\w+)")
{
$jobstaticresults.Add([PSCUSTOMOBJECT]@{
"IP" = $Matches.IP
"MAC" = $Matches.MAC
}) | Out-Null
}
}
return $jobstaticresults
} -ArgumentList $plage,$server #end start-job
} #end if ($monitostatic -eq $true)
if ((get-job -Name "$server*" | Where-Object {$_.state -eq "Running"}).count -ge $maximaljobperserver)
{
Write-Output "Plus de $maximaljobperserver jobs actifs sur $server. En attente de la libération de jobs. (leases)"
do
{
Start-Sleep -Seconds 1
} while ((get-job -Name "$server*" | Where-Object {$_.state -eq "Running"}).count -ge $maximaljobperserver)
}
Start-Job -Name $($server+"_"+$plage+"_leases") -ScriptBlock {
param($plage,$server)
$jobarraylist = New-Object System.Collections.ArrayList
$stats = Invoke-Command -computername $server -scriptblock {powershell.exe "chcp 1252;Netsh dhcp server scope $($args[0]) show clients 1"} -ArgumentList $plage
foreach ($entry in $stats)
{
if ($entry.trim() -match "(?<ip>\d+.\d+.\d+.\d+.)\W+-\W+(?<masque>\d+.\d+.\d+.\d+.).*?[^\w+](?<mac>\w+-\w+-\w+-\w+-\w+-\w+).*?[^\d+](?<bail>\d+/\d+/\d+\s+\d+:\d+:\d+).*?[^\w+](?<type>\w+).*?[^\w+](?<pc>\w+.*)$")
{
$jobarraylist.Add([pscustomobject]@{
"IP" = $Matches.ip
"Masque" = $Matches.MASQUE
"MAC" = $Matches.MAC
"PC" = $Matches.PC
"Type" = $Matches.TYPE
"Date" = (get-date $Matches.Bail )
}) | Out-Null
}
}
return $jobarraylist
} -ArgumentList $plage,$server #end start-job
}
}
Get-job | Wait-Job
$joblist = Get-Job | Where-Object {$_.State -eq "Completed"}
Write-Output "Obtention des résultats d'IP statiques"
foreach ($job in ($joblist |Where-Object {$_.name -like "*static"}))
{
$value = Receive-Job $job
if ($value -ne $null)
{
try
{
$staticresults.AddRange($value) | Out-Null
}
catch
{
try
{
$staticresults.Add($value) | Out-Null
}
catch
{
Write-Output "Erreur lors de l'ajout des données du job $($job.name) avec comme valeur $($value)"
}
}
}
Remove-Job $job
}
$joblist = Get-Job
foreach ($job in $joblist)
{
$value = Receive-Job $job
if ($value -ne $null)
{
try{
$arraylist.AddRange($value) | Out-Null
}
catch
{
try
{
$arraylist.Add($value) | Out-Null
}
catch
{
Write-Output "Erreur sur l'ajout de données du job $($job.name) avec comme valeur $($value)"
}
}
}
Remove-Job $job -ErrorAction stop
}
foreach ($job in Get-Job)
{
Write-Output "Erreur sur $job. $Job.state"
Receive-Job $job
}
foreach ($computer in $arraylist)
{
$results = $arraylist | Where-Object {$_.pc -eq $computer.PC}
foreach ($result in $results)
{
if ($computerlist.dnshostname -notcontains $result.pc)
{
"$($result.pc) N'EST PAS CONNU DANS L'AD."
$notindomainarraylist.Add($result) | Out-Null
}
}
}
#Filtrage en fonction des exceptions. Ne garder que ce qui n'a pas d'adresse mac et de nom correspondant à la liste.
$notindomainwithexceptions = $notindomainarraylist | Where-Object {$_.MAC -notin $exceptions -and $_.PC -notin $exceptions}
if ($fichiernondomaine -ne $null)
{
foreach ($computer in $notindomainwithexceptions)
{
if ($fichiernondomaine.pc.contains($computer.pc))
{
#Recherche du pc X avec l'adresse mac Y
$results = $fichiernondomaine | Where-Object {$_.pc -eq $computer.pc -and $_.MAC -eq $computer.MAC} | Sort-Object -property ip,date -Unique
if ($results -eq $null)
{
"results eq null"
#L'ordinateur est trouvé, mais sous une autre carte réseau
$index = $notindomainwithexceptions.pc.IndexOf($computer.pc) #changé $_.pc en $computer.pc
$item = $notindomainwithexceptions[$index]
$item | Add-Member -MemberType NoteProperty -Name "Raison" -Value "Nouvelle carte réseau" -force
$resultingarray.Add($item) | Out-Null
}
elseif ($results.ip -contains $computer.ip)
{
#L'ordinateur est trouvé dans le DHCP, on vérifie si le bail expire à la même date.
#On filtre uniquement sur l'objet ayant la même adresse que l'ordinateur
$item = $results | Where-Object {$_.ip -eq $computer.ip}
if ($computer.Date -gt $item.Date)
{
#La valeur date est plus grande, il a donc eu un renouvellement de bail
$item | Add-Member -MemberType NoteProperty -Name "Raison" -Value "Renouvellement du bail DHCP" -Force
$resultingarray.Add($item) | Out-Null
}
#Sinon, on enregistre pas, on avertit pas.
}
}
else
{
#Si le fichier xml importé ne comporte pas l'ordinateur, c'est donc une nouvelle connexion
$item = $computer
$item | Add-Member -MemberType NoteProperty -Name "Raison" -Value "Nouvelle connexion" -Force
$resultingarray.Add($item) | Out-Null
}
}
$notindomainarraylist | Export-Clixml $fullpath
if ($resultingarray -ne $null)
{
$resultingarray = $resultingarray | Select-object -property IP,Masque,Mac,PC,Type,Date,Raison
Send-MailMessage -From $from -To $to -Subject "Nouvelles connexions détectées" -Bodyashtml $([string]($resultingarray | ConvertTo-Html -PreContent "Type : N - AUCUN, D - DHCP B - BOOTP, U - NON SPÉCIFIÉ, R - RÉSERVATION IP" -Head "")) -Encoding $encoding -SmtpServer $smtpserver
$resultingarray | Export-Csv (join-path $configurationarray.path $("out_domain_"+ $dateforcsv +".csv")) -NoTypeInformation -Append -Delimiter ";" -Encoding UTF8
}
}
else
{
Write-Output "Aucun fichier de précedence du DHCP trouvé. Enregistrement des données actuelles en tant que reference"
$notindomainarraylist | Export-Clixml $fullpath
Send-MailMessage -From $from -To $to -Subject "Première analyse faite. Surveillance de ces entrées." -Bodyashtml $([string]($notindomainwithexceptions | ConvertTo-Html -PreContent "Type : N - AUCUN, D - DHCP B - BOOTP, U - NON SPÉCIFIÉ, R - RÉSERVATION IP" -Head "")) -Encoding $encoding -SmtpServer $smtpserver
}
#Gestion des IP Statiques
if ($monitorstatic -eq $true)
{
$staticresults = $staticresults | Select-object -property IP,MAC | Sort-Object -Property "ip","mac" -Unique
if ($staticresultsprevious -eq $null)
{
Write-Output "Aucun fichier de précedence des réservations trouvé. Enregistrement des données actuelles en tant que reference"
$staticresults | Export-Clixml $staticpath
}
else
{
foreach ($entry in $staticresults)
{
#Si l'ip est bien dans la liste des résultats précedents...
if ($entry.ip -in $staticresultsprevious.ip)
{
#On reprends l'objet de la fois précedente...
$check = $staticresultsprevious | Where-Object {$_.ip -eq $entry.ip}
#Si leurs macs différent, l'adresse mac a été changée
if ($entry.MAC -ne $check.MAC)
{
"Mac."
Report-StaticChange -Raison "Mac Changée" -OldIP $check.ip -NewIP $entry.ip -OldMAC $check.mac -NewMAC $entry.MAC
}
}
#Si l'ip n'est pas dans la liste des résultats précédents
#MAIS que la MAC y est... L'IP a donc changé
elseif ($entry.mac -in $staticresultsprevious.mac)
{
"ip"
$check = $staticresultsprevious | Where-Object {$_.mac -eq $entry.mac}
Report-StaticChange -Raison "IP Changée" -OldIP $check.ip -NewIP $entry.ip -OldMAC $check.mac -NewMAC $entry.MAC
}
#Si ni MAC ni IP, alors c'est une nouvelle entrée
else
{
"new"
Report-StaticChange -Raison "Nouvelle entrée" -OldIP $null -NewIP $entry.ip -NewMAC $entry.MAC
}
}
#On loop et vérifie que chaque ancien résultat est toujours présent pour s'assurer que rien n'est supprimé
foreach ($staticresultprevious in $staticresultsprevious)
{
#Si l'IP n'est pas dans la liste actuelle, et que la MAC n'est pas dans la liste actuelle
if ($staticresultprevious.ip -notin $staticresults.ip -and $staticresultprevious.mac -notin $staticresults.mac)
{
#On regarde si l'adresse et la mac ne sont pas dans les dernières détections de changement MAC / IP
#afin de ne pas marquer une entrée comme retirée alors qu'elle est simplement modifiée
if ($staticresultprevious.ip -notin $staticmodified.ip -or $staticresultprevious.mac -notin $staticmodified.mac)
{
Report-StaticChange -Raison "Entrée retirée" -OldIP $null -NewIP $staticresultprevious.ip -NewMAC $staticresultprevious.MAC
}
}
}
$staticresults | Export-Clixml $staticpath
if ($staticmodified.Count -gt 0)
{
Send-MailMessage -From $from -To $to -Subject "Modifications des reservations DHCP" -Bodyashtml $([string]($staticmodified | ConvertTo-Html -PreContent "Liste des modifications détectées sur les réservations du DHCP" -Head "")) -Encoding $encoding -SmtpServer $smtpserver
$staticmodified | Export-Csv (join-path $configurationarray.path $("reserved_changed_"+ $dateforcsv +".csv")) -NoTypeInformation -Append -Delimiter ";" -Encoding UTF8
}
}
}
+70
View File
@@ -0,0 +1,70 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
$ou = @("OU=Servers,OU=SITE 1,DC=domaine,DC=local","OU=Domain Controllers,DC=domaine,DC=local")
#définition des UO
$tableauerreurs = New-object System.Collections.ArrayList
#création d'un tableau contenant les erreurs
$listesrv = New-Object System.Collections.ArrayList
#création d'un tableau contenant la liste des serveurs
$tableauodbc =New-object System.Collections.ArrayList
#création d'un tableau contenant la liste des connecteurs trouvés
$ou | % {
$serveurs = Get-ADComputer -SearchBase $_ -Filter * -Properties "OperatingSystem"
$listesrv.AddRange($serveurs)
#nous ajoutons la liste contenue dans $serveurs au tableau
}
$listesrv = $listesrv | Where-Object {$_.operatingsystem -like "Windows*"} |Sort-Object -Property name
#Nous filtrons ce qui comporte "windows" et trions par le nom
$listesrv | Select-Object -Property name
foreach ($serveur in $listesrv)
{
$key = "SOFTWARE\ODBC\ODBC.INI"
$types = @([Microsoft.Win32.RegistryHive]::CurrentUser,[Microsoft.Win32.RegistryHive]::LocalMachine)
foreach ($type in $types)
{
$regkey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $($serveur.name)) #nous ouvrons la ruche distante sur l'ordinateur scanné
if (!$?)
{
$tableauerreurs.add([PSCUSTOMOBJECT]@{
"Serveur" = $($serveur.name)
"Region" = "ODBC $type clé $type\$key"
"Erreur" = $error[0].Exception.Message
})
}
else
{
$regkey = $regkey.opensubkey($key) #ouverture de la clé contenant les infos d'ODBC
if ($regkey -ne $null)
{
#on récupère l'intégralité des clés enfants, et pour chaque on va voir s'il y'a des informations d'UID
foreach ($value in $regkey.GetSubKeyNames() )
{
$subkey = $regkey.OpenSubKey($value)
if ($subkey.GetValueNames() -contains "UID")
{
$user = $subkey.getValue("UID") #on récupère le nom d'utilisateur
$pass = $subkey.getValue("PWD") #et également le mot de passe
$tableauodbc.Add([PSCUSTOMOBJECT]@{
"Serveur" = $($serveur.name)
"Type ODBC" = "$type"
"Chemin ODBC" = "$type\$key\$subkey"
"Utilisateur" = $user
}) #et on ajoute le tout dans le tableau
}
} #fin foreach valeur dans sous clés registre
}
}
}
} #fin foreach
$tableauodbc
+97
View File
@@ -0,0 +1,97 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
#Création de l'objet de selection de la boite de dialogue
$filepick = New-Object System.Windows.Forms.OpenFileDialog
#On précise qu'on peut choisir plusieurs fichiers
$filepick.Multiselect = $true
#On filtre uniquement sur les images
$filepick.Filter = "Images (*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF"
#On définit un repertoire par défaut
$filepick.InitialDirectory = "C:\"
$filepick.Title = "Selectionnez une ou plusieurs photos"
#On affiche le Forms en enregistrant le bouton cliqué dans une variable
$filepickreturn = $filepick.ShowDialog()
#Un tableau récapitulatif
$array = New-Object System.Collections.ArrayList
#Utilisé à la fin pour calculer le temps pris
$start = Get-Date
if ($filepickreturn -eq "OK")
{
#Cette ligne renvoie la longueur de la string du nombre de fichier. Utilisé ensuite pour l'incrément. Ex : 3 fichiers, longueur du chiffre 3 : 1 caractère => incrémentera jusque 9 au maximum. 15 fichiers, longueur de 15 : 2 caractères => incrémentera jusque 99 au maximum, etc.
$filesize = $filepick.FileNames.Count.ToString().length
#récupère le repertoire en allant du début jusqu'au dernier "\"
$repertoire = $filepick.FileName.substring(0,$($filepick.FileName.lastindexof("\")))
#On crée l'objet Shell
$objShell = New-Object -ComObject Shell.Application
#On selectionne le répertoire
$objfolder = $objShell.NameSpace($repertoire)
#On filtre les objets pour ne prendre que ceux selectionnés par le Forms
$objectlist = $objfolder.Items() | Where-Object {$_.path -in $filepick.FileNames}
#Utilisé pour l'affichage de la progression
$a = 0
foreach ($file in $objectlist)
{
#On tente d'obtenir les détails de l'image. En cas d'erreur, on passe à la suivante
try
{
$picturedate = $objfolder.GetDetailsOf($file,12)
}
catch
{
Write-Error "Impossible de récuperer la date sur $($file.Path)"
continue
}
#On récupère l'objet afin de pouvoir avoir l'extension. En cas d'erreur, on passe à l'image suivante.
try
{
$item = Get-Item $($file.Path)
}
catch
{
Write-Error "Erreur sur $($file.Path)"
continue
}
$i = 0
$extension = $item.Extension
#L'incrément se fait sur ce format : (001) . Le nombre de 0 change selon le nombre de photos selectionnées
$increment = $("({0:D$filesize})" -f $i)
#On retire les caractères inadéquat pour la création d'un nom de fichier
$newfilename = (get-date -UFormat $picturedate).Replace("/","-").Replace(" ","-").Replace(":","-") + $extension
$a++
do
{
#On reconstitue le nom complet du fichier : Repertoire + nouveau nom
$fullfilename = Join-Path $repertoire $newfilename
#On regarde si le fichier existe déja...
$testpathreturn = (Test-Path $fullfilename)
#Et si oui, on ajoute 1 à l'incrément et que l'on ajoute au nom du fichier. On incrémente le nom du fichier jusqu'a ce que l'on tombe sur aucun fichier ne portant ce nom.
if ($testpathreturn -eq $true)
{
$i++
$increment = $("({0:D$filesize})" -f $i)
#Format : jj-mm-yyyy-HH-MM (increment).extension
$newfilename = (get-date -UFormat $picturedate).Replace("/","-").Replace(" ","-").Replace(":","-") + " " + $increment + $extension
}
#Une barre de progression, toujours utile pour savoir ou on en est
Write-Progress -Activity "Renommage des fichiers en cours" -CurrentOperation "$($file.Name) => $newfilename" -PercentComplete ($a / $objectlist.Count * 100)
}while($testpathreturn -eq $true)
#Les objets fichier obtenus par Shell.Application ont une méthode permettant de leur définir aisément un nouveau nom.
$file.Name = $newfilename
$array.Add([PSCUSTOMOBJECT]@{
"Nom_initial"= $file.Name
"Nouveau_nom" = $newfilename}) | Out-Null
}
}
#Fin du chrono
$end = Get-Date
#On calcule le temps passé
$temps = $end - $start
#On affiche un récap de toutes les modifications faites
$array | ft
#Ainsi que le temps passé et le nombre de fichiers!
write-host "$($objectlist.Count) photos en $([math]::round($temps.TotalSeconds,0)) secondes"
+13
View File
@@ -0,0 +1,13 @@
#Script créé par Nicolas Lang - Sous licence CC-BY-SA
#https://nicolaslang.fr
[xml]$taches = schtasks /query /s "Nom_serveur" /xml one
$tableau = New-object System.Collections.ArrayList
$i = 0
$taches.tasks.'#comment' | % {$add = [pscustomobject]@{
"Serveur" = "Nom_du_serveur"
"Name" = $_
"Utilisateur" = $taches.tasks.task[$i].Principals.principal.userid}
$i++
$tableau.add($add) | Out-Null}
$tableau | Where-object {$_.utilisateur -like "*administrateur*"}