Script PowerShell d’extraction AD pour audit sécurité

#----------------------------------------------------
# Extraction Active Directory pour audit sécurité
# PowerShell v4
#----------------------------------------------------

$ErrorActionPreference = 'SilentlyContinue' # Erreurs non affichées et exécution se poursuit sans interruption

#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\#
# Import des modules PowerShell
#//////////////////////////////////////////////////////////////////////#

Import-module -Name ActiveDirectory
Import-module -Name GroupPolicy

#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\#
# Initialisation des Variables
#//////////////////////////////////////////////////////////////////////#

$DicGroupGPO = @{}
$DicoToken = @{}
$ADDomain = get-addomain
$sDomainName = $ADDomain.DNSRoot

# Variables pour les fichiers à créer
$PathProjet = "C:\serveur_apps\scripts\Projet"
$GroupGPOAD = $PathProjet + "\GroupGPOAD_xyz.csv"
$sxyzFilePath1 = $PathProjet + "\UserListAD_xyz.csv"
$sxyzFilePath2 = $PathProjet + "\UserGroupAD_xyz.csv"
$sxyzFilePath3 = $PathProjet + "\temp.tmp"
$GPOFileOut = $PathProjet + "\GPO.txt"

# Variables pour les logs
$dDateCourante = Get-Date
$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss")+ " INFO - Début d'exécution "
$LogRep = "C:\serveur_apps\scripts\Projetlog\"
$sLogFile = $LogRep + "log.txt"
#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\#
# Initialisation des Fonctions
#//////////////////////////////////////////////////////////////////////#

# Fonction pour convertir un chemin LDAP en canonical / le nom du groupe n'est pas gardé dans la valeur de retour
[paycontent]
Function ConverTProjetnonicalName ($strToConvert,$sDomain){
$CanonicalName = $sDomain + "/"
$Liste = $strToConvert -split ","
For ($i = -1 ; $i -gt -$Liste.count; $i -- ){
	If (($Liste[$i]).substring(0,3) -eq "OU=") {
		$CanonicalName += ($Liste[$i]).substring(3,($Liste[$i]).length-3) + "/"
	}
		If (($Liste[$i]).substring(0,3) -eq "CN=") {
			$CanonicalName += ($Liste[$i]).substring(3,($Liste[$i]).length-3) + "/"
		}
	}

	return $CanonicalName
	$CanonicalName = $Null
}

# Fonction retournant les sous groupes d'un groupe
Function Get-GroupHierarchy ($SearchGroup, $sGPO){
	If ($SearchGroup -ne "")
	If ($DicGroupGPO.ContainsKey($SearchGroup)){
	$aGroupMember = $DicGroupGPO.Get_Item($SearchGroup)
	ForEach ($GroupMember in $aGroupMember){
		$strGroupMember = $GroupMember.name
		$strGroupMemberDNWithOutGroupName = $GroupMember.DistinguishedName
		$strGroupMemberCN = ConverTProjetnonicalName $strGroupMemberDNWithOutGroupName $sdomainName
		"$strGroupMember;$sGPO;$strGroupMemberCN" | Out-File -Append -FilePath $sxyzFilePath3 -Encoding Unicode
	}
}

Else{
$GroupMembers = get-ADGroupMember $SearchGroup | where {$_.ObjectClass -eq "group"} #| select-object name
If ($GroupMembers)
{
$DicGroupGPO.add($SearchGroup,$GroupMembers)
ForEach ($GroupMember in $GroupMembers){
	$strGroupMember = $GroupMember.name
	$strGroupMemberDNWithOutGroupName = $GroupMember.DistinguishedName
	$strGroupMemberCN = ConverTProjetnonicalName $strGroupMemberDNWithOutGroupName $sdomainName
	"$strGroupMember;$sGPO;$strGroupMemberCN" | Out-File -Append -FilePath $sxyzFilePath3 -Encoding Unicode
	Get-GroupHierarchy $strGroupMember $sGPO
} # ForEach $GroupMembers
} # If $GroupMembers
} # Else
} # If($DicGroupGPO.ContainsKey($SearchGroup))
} # End of Function

#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\#
# Vérification du répertoire
#//////////////////////////////////////////////////////////////////////#

# Répertoire pour les fichiers de log
If(!(Test-Path $sLogFile )){
	$sResult = New-Item $LogRep -Type directory
	$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " INFO - SUCCES Le répertoire " + $PathProjet + " a été créé"
	$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
}

# Réroire pour les fichiers d'extraction
If(!(Test-Path $PathProjet)){
	Try{
		$sResult = New-Item $PathProjet -Type directory
		$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " INFO - SUCCES Le répertoire " + $PathProjet + " a été créé"
		$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
	}	

Catch{
	$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ERREUR - Création du répertoire " + $PathProjet + " impossible"
	$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode

	ForEach($ErreurMessage in $Error){
		$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ERREUR - " + ($ErreurMessage.ToString()).Replace("`n","")
		$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
	}
	$Error.clear()
	}
}

# Suppression des anciens fichiers
Remove-Item C:\Serveur_apps\Scripts\Projet\*.zip
Remove-Item C:\Serveur_apps\Scripts\Projet\*.csv
Remove-Item C:\Serveur_apps\Scripts\Projet\*.tmp
Remove-Item C:\Serveur_apps\Scripts\Projet\*.txt

#\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\#
# Extraction des données #
#//////////////////////////////////////////////////////////////////////#

# Vérification de la présence des fichiers, suppressions si "true"
If(Test-Path $sxyzFilePath1){remove-item -path $sxyzFilePath1 -Force}
If(Test-Path $sxyzFilePath2){remove-item -path $sxyzFilePath2 -Force}
If(Test-Path $sxyzFilePath3){remove-item -path $sxyzFilePath3 -Force}
If(Test-Path $GroupGPOAD){remove-item -path $GroupGPOAD -Force}
If(Test-Path $GPOFileOut){remove-item -path $GPOFileOut -Force}

######### Création du fichier groupe GPO #########

# Extraction des GPO dans un fichier puis une variable
$oListGPOS = Get-gpo -all | Format-table DisplayName -HideTableHeaders | Out-File $GPOFileOut
$oListGPOS = Get-Content $GPOFileOut
$sResult = New-Item $sxyzFilePath3 -Type File -force

# Préparation du fichier GPO, entêtes
$sOutPutMess = "Nom du groupe;Nom de la GPO;OU Group"
$sOutPutMess | Out-File -Append -FilePath $GroupGPOAD -Encoding Unicode
$Error.clear()
ForEach ($oListGPO in $oListGPOS) # Début de traitement du tableau utilisateur et GPO{
$Error.clear()

Try{
	$oListGPO = ($oListGPO).trim()
	$oListPERMISSIONS = Get-GPPermissions -Name $oListGPO -All -DomainName $sDomainName

	# Check des permissions sur chaque GPO
	ForEach ($sListPermission in $oListPERMISSIONS ){
	If(($sListPermission.Permission -eq "GpoApply") -and ($sListPermission.Trustee.Name -ne "Utilisateurs authentIfiés")){
		# S'il y a un utilisateur ou ordinateur directement dans le filtre GPO

		If (($sListPermission.Trustee.SIDType -eq "User") -or ($sListPermission.Trustee.SIDType -eq "Computer")){
			$sGPOMessage = "ATTENTION " + $sListPermission.Trustee.SIDType + " " + $sListPermission.Trustee.Name + ";" + $oListGPO
			$sGPOMessage | Out-File -Append -FilePath $sxyzFilePath3 -Encoding Unicode
			$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ATTENTION - Des utilisateurs ou ordinateurs sont directement rattachés à la GPO :'$oListGPO'. Fichier : " + $sxyzFilePath3

			$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
}		

ElseIf ($sListPermission.Trustee.SIDType -eq "Unknown"){
	$sGPOMessage = "ATTENTION Groupe ou utilisateur inexistant;" + $oListGPO
	$sGPOMessage | Out-File -Append -FilePath $sxyzFilePath3 -Encoding Unicode
	$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ATTENTION - Groupe ou utilisateur inexistant pour la GPO : '$oListGPO' Fichier : $sxyzFilePath3"
	$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
}

Else{
	$strDSPathGroupe = $sListPermission.Trustee.DSPath
	$strCNGroupe = ConverTProjetnonicalName $strDSPathGroupe $sdomainName
	$sGPOMessage = $sListPermission.Trustee.Name + ";" + $oListGPO + ";" + $strCNGroupe
	$sGPOMessage | Out-File -Append -FilePath $sxyzFilePath3 -Encoding Unicode
	Get-GroupHierarchy $sListPermission.Trustee.Name $oListGPO
	}
}

} # ForEach ($sListPermission in $oListPERMISSIONS )
} # Try

Catch{
	$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ERREUR - Problème de traitement du fichier, GPO : '$oListGPO' dans " + $sxyzFilePath3 + " pour " + $GroupGPOAD

	$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode

	ForEach($ErreurMessage in $Error){
		$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ERREUR - " + ($ErreurMessage.ToString()).Replace("`n","")
		$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
	}

	$Error.clear()
	}
} # ForEach ($oListGPO in $oListGPOS)

# Tri pour avoir unicite des resultats

# Le passage par un fichier temporaire et un tri est preferable à l utilisation d'un tableau pour de nombreuses donnees
Get-Content $sxyzFilePath3 | Sort | Get-Unique | Out-File -Append -FilePath $GroupGPOAD -Encoding Unicode

######### Requètes des utilisateurs #########

$oLDAPUsers = Get-ADUser -Filter * –Properties SamAccountName,Surname,GivenName,DistinguishedName,whencreated,Enabled,LockedOut,LastLogonDate,PasswordNeverExpires,PasswordLastSet,CannotChangePassword,PasswordNotRequired,AccountLockOutTime,LockedOut

Get-GroupHierarchy $sListPermission.Trustee.Name $oListGPO

######### Requètes des groupes #########

$oListGroups = Get-ADGroup -Filter * -Properties SamAccountName

# Construction des fichiers utilisateurs et groupes : new File ; création des entetes, logs,

If($oLDAPUsers -And $oListGroups){
	# Création des fichiers, des entetes et écritures dans le log
	$sResult = New-Item $sxyzFilePath1 -Type File # Création du nouveau fichier 'xyz_UserListAD.csv'

	$sOutPutMess = "Id;Nom;Prenom;DN;creation;modIfication;Statut Actif;verrouillé;connexion;password expiré;Derniere modification du password;password permanent;password optionnel;expiration;Duree depuis le verrouillage;Nombre de mauvais password;password verrouillé;Changement de password au prochain demarrage"

	$sOutPutMess | Out-File -Append -FilePath $sxyzFilePath1 -Encoding Unicode
	$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " INFO - Début de traitement du fichier " + $sxyzFilePath1
	$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
	$sResult = New-Item $sxyzFilePath2 -Type File # Création du nouveau fichier 2
	$sOutPutMess = "IdentIfiant;Domaine;Ressources"
	$sOutPutMess | Out-File -Append -FilePath $sxyzFilePath2 -Encoding Unicode
	$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " INFO - Début de traitement du fichier " + $sxyzFilePath2
	$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
	$iValue = 0x02
	$oCultureInfo = New-Object System.Globalization.CultureInfo("fr-FR")

ForEach ($oLDAPUser in $oLDAPUsers) # Début de traitement du tableau utilisateur{
	$Error.clear()
	Try{
		$sSAMAcName = $oLDAPUser.samaccountname
		$sLastName = $oLDAPUser.sn
		$sFirstName = $oLDAPUser.givenname
		$sdistinguishedName = $oLDAPUser.distinguishedname

		# DN du compte sans le nom de l'utilisateur, valeur 'DN du compte' dans le fichier $sxyzFilePath1
		$sDistinguishedNameWithOutUserName = ($sdistinguishedName -split(",",2))[1]

		# En remplacement du 'Get-ACL' et 'récup compte verrouillé'
		$sUserProperties = Get-ADUser -SearchScope Base -SearchBase $sdistinguishedName -Filter * -Properties CannotChangePassword,LockedOut,PasswordExpired -Server $sDomainName
		$sPwdProtected = $sUserProperties.CannotChangePassword

		If($oLDAPUser.whencreated) #Format date{
			$sWhenCreated = [datetime]::Parse($oLDAPUser.whencreated.ToString())
			$dWhenCreated = ($sWhenCreated.ToLProjetlTime()).ToString("G", $oCultureInfo)
		}

		Else {$dWhenCreated = $Null}
		If($oLDAPUser.whenchanged) #Format date{
			$sWhenChanged = [datetime]::Parse($oLDAPUser.whenchanged.ToString())
			$dWhenChanged = ($sWhenChanged.ToLProjetlTime()).ToString("G", $oCultureInfo)
		}	

		Else {$dWhenChanged = $Null}

		If($oLDAPUser.lastlogontimestamp) #Format int{

			$dLastLogOn = [datetime]::FromFileTime([Int64]::Parse($oLDAPUser.lastlogontimestamp))
			$sLastLogOn = $dLastLogOn.ToString("G", $oCultureInfo)
		}

		Else {$sLastLogOn = $Null}

		$sUserAccountLocked = $sUserProperties.LockedOut

	If($oLDAPUser.lockOuttime -gt 0) #Format int{
		$sLastlockOutTime = [datetime]::FromFileTime([Int64]::Parse($oLDAPUser.lockOuttime))
		$dLastlockOutTime = $sLastlockOutTime.ToString("G", $oCultureInfo)
	}	

	Else {$dLastlockOutTime = ""}
	$sPasswordExpired = $sUserProperties.PasswordExpired
	If(($oLDAPUser.pwdlastset -ne 0) -and ($oLDAPUser.pwdlastset -ne $NULL)) #Format int{
		$spwdLastSet = [datetime]::FromFileTime([Int64]::Parse($oLDAPUser.pwdlastset))
		$dpwdLastSet = $spwdLastSet.ToString("G", $oCultureInfo)
		$spwdToInitialize = "False"
	}

	Else{
		$spwdToInitialize = "True"
		$dpwdLastSet = ""
	}

	$DONT_EXPIRE_PASSWORD = 65536
	If($oLDAPUser.useraccountcontrol){
		If($oLDAPUser.useraccountcontrol.Value -band $DONT_EXPIRE_PASSWORD) {$sPwdPermanent = "True"}
		Else {$sPwdPermanent = "False"}
	}

	Else {$sPwdPermanent = "False"}
	$PASSWORD_NOT_REQUIRED = 32
	If($oLDAPUser.useraccountcontrol){
		If($oLDAPUser.useraccountcontrol.Value -band $PASSWORD_NOT_REQUIRED) {$sPwdNotRequired = "True"}
		Else {$sPwdNotRequired = "False"}
	}
	
	Else {$sPwdNotRequired = "False"}
	If (($oLDAPUser.accountexpires -ne 0) -and ($oLDAPUser.accountexpires -ne $NULL) -and ($oLDAPUser.accountexpires -le [DateTime]::MaxValue.Ticks)){
		$saccountExpires = [datetime]::FromFileTime([Int64]::Parse($oLDAPUser.accountexpires))
		$daccountExpires = $saccountExpires.ToString("G", $oCultureInfo)
	}

	Else {$daccountExpires = ""}
	$sbadPwdCount = $oLDAPUser.badpwdcount
	$ACCOUNT_DISABLE = 2
	If($oLDAPUser.useraccountcontrol){
		If($oLDAPUser.useraccountcontrol -band $ACCOUNT_DISABLE) {$sUserAcControl = "Disabled"}
		Else {$sUserAcControl = "Enabled"}
	}
Else {$sUserAcControl = $Null}
$aGroupMembers = Get-ADUser -SearchScope Base -SearchBase $oLDAPUser.distinguishedname -LDAPFilter '(objectClass=user)' -Properties TokenGroups -Server $sDomainName| Select-Object -ExpandProperty TokenGroups | Select-Object -ExpandProperty Value

ForEach($TokenGroup In $aGroupMembers){
	Try{
		If($sSAMAcName){
			If ($DicoToken.ContainsKey($TokenGroup)){
				$sGroupPath_strNameTokenGroup = $DicoToken.Get_Item($TokenGroup)
				$sOutPutMess = "$sSAMAcName;$sGroupPath_strNameTokenGroup"
				$sOutPutMess | Out-File -Append -FilePath $sxyzFilePath2 -Encoding Unicode
			}

		Else{
			$strTokenGroupIndentity = Get-ADGroup -Identity $TokenGroup -Server $sDomainName
			$strNameTokenGroup = $strTokenGroupIndentity.Name
			$strDistNameTokenGroup = $strTokenGroupIndentity.DistinguishedName
			$sGroupPath = ConverTProjetnonicalName $strDistNameTokenGroup $sdomainName
			$sOutPutMess = "$sSAMAcName;$sGroupPath;$strNameTokenGroup"
			$sOutPutMess | Out-File -Append -FilePath $sxyzFilePath2 -Encoding Unicode
			$strGroupForDico = "$sGroupPath;$strNameTokenGroup"

			$DicoToken.Add($TokenGroup,$strGroupForDico)

		}		
	}# If($sSAMAcName)
} # Try

Catch{
	ForEach($ErreurMessage in $Error){
		If (!(($ErreurMessage.CategoryInfo.Category -eq "ObjectNotFound") -and ($ErreurMessage.CategoryInfo.Reason -eq "ADIdentityNotFoundException"))){
			$sOutPutMess = "ATTENTION PROBLEME sur utilisateur $sSAMAcName et le groupe $TokenGroup (Partie Début de traitement du tableau utilisateur du script)"
			$sOutPutMess | Out-File -Append -FilePath $sxyzFilePath2 -Encoding Unicode
			$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ATTENTION PROBLEME - sur utilisateur $sSAMAcName dans fichier $sxyzFilePath2" + " Partie Début de traitement du tableau utilisateur du script"
			$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
			$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ERREUR NON BLOQUANTE - " + ($ErreurMessage.ToString()).Replace("`n","") + "Partie Début de traitement du tableau utilisateur du script"
			$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
			}
	
			Else{
				objSID = New-Object System.Security.Principal.SecurityIdentIfier ($TokenGroup)
				objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
				sOutPutMess = "$sSAMAcName;$objUser;$TokenGroup"
				$sOutPutMess | Out-File -Append -FilePath $sxyzFilePath2 -Encoding Unicode
			}
		} # ForEach

	$Error.clear()
	} # Catch

	If($sSAMAcName) # AjOut des données de l'utilisateur en cours de traitement dans le fichier 1 xyz{
		$sOutPutMess = "$sSAMAcName;$sLastName;$sFirstName;$sdistinguishedNameWithOutUserName;$dWhenCreated;$dWhenChanged;$sUserAcControl;$sUserAccountLocked;$sLastLogOn;$sPasswordExpired;$dpwdLastSet;$sPwdPermanent;$sPwdNotRequired;$daccountExpires;$dLastlockOutTime;$sbadPwdCount;$sPwdProtected;$spwdToInitialize"

		$sOutPutMess | Out-File -Append -FilePath $sxyzFilePath1 -Encoding Unicode
		}
	} # ForEach($TokenGroup In $aGroupMembers)
}# Try de ForEach ($oLDAPUser in $oLDAPUsers)

Catch{
	$sOutPutMess = "ATTENTION PROBLEME sur utilisateur $sSAMAcName;$sLastName;$sFirstName;$sdistinguishedNameWithOutUserName;$dWhenCreated;$dWhenChanged;$sUserAcControl;$sUserAccountLocked;$sLastLogOn;$sPasswordExpired;$dpwdLastSet;$sPwdPermanent;$sPwdNotRequired;$daccountExpires;$dLastlockOutTime;$sbadPwdCount;$sPwdProtected;$spwdToInitialize"

	$sOutPutMess | Out-File -Append -FilePath $sxyzFilePath1 -Encoding Unicode
	$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ATTENTION PROBLEME - sur utilisateur $sSAMAcName dans fichier $sxyzFilePath1"
	$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode

ForEach($ErreurMessage in $Error){
	$sLogMessage = (Get-Date).ToString("dd/MM/yyyy HH:mm:ss") + " ERREUR NON BLOQUANTE - " + ($ErreurMessage.ToString()).Replace("`n","")
	$sLogMessage | Out-File -Append -FilePath $sLogFile -Encoding Unicode
	}

		$Error.clear()
		} # Catch
	} # ForEach ($oLDAPUser in $oLDAPUsers) # tableau utilisateur
} # If($oLDAPUsers -And $oListGroup)
[/paycontent]

# Suppression des fichiers temporaires
If(!(Test-Path $sxyzFilePath3)){Remove-Item $sxyzFilePath3}
If(!(Test-path $GPOFileOut)){Remove-Item $GPOFileOut}


Laisser un commentaire