IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Scripts/Batch Discussion :

'System.OutOfMemoryException' mémoire saturée [PowerShell]


Sujet :

Scripts/Batch

  1. #1
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut 'System.OutOfMemoryException' mémoire saturée
    Bonjour,

    J'ai un script qui recherche les membres de groupes AD. Dans certains groupes, j'ai plus de 3000 utilisateurs.
    J'ai au total plus de 250 groupes à analysés.

    Lorsque je test mon script, a un moment donnée, j'arrive à des erreurs de mémoire du shell ('System.OutOfMemoryException' was thrown)

    J'ai essayé en augmentant le quota de mémoire du shell, mais j'arrive rapidement à sa limite. J'ai essayé d'enregistrer dans un fichier temporaire, les informations retournées par la commande Get-ADGroupMember afin de ne pas saturé la mémoire. C'est mieux, mais arrivé à un moment, j'arrive à saturation.

    Aussi, j'ai remarqué, que plus je fais de test, plus la saturation de mémoire arrive rapidement. J'ai lu sur internet que la fermeture du shell permettait de vider cette mémoire ou en utilisant la commande "[System.GC]::Collect()". J'ai placé cette commande en début de script. Il y a du mieux mais malgré tout, j'arrive à la limitation.

    Y a -il une autres méthode ?

    Pour analyser mes groupes, j'utilise un fichier de réponse CSV que je parcours via une boucle. Je pourrai placer la commande "[System.GC]::Collect()" en début de boucle pour vider la mémoire ?

    Merci pour votre aide

  2. #2
    Membre habitué
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Juillet 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Juillet 2015
    Messages : 66
    Points : 126
    Points
    126
    Par défaut
    Hello Arnaud,

    il faudrait que tu postes ton script pour qu'on puisse voir ce qui ne va pas.

    Le GC n'aidera pas beaucoup car tant qu'une variable existe il n'y a pas de raison de libérer sa mémoire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $a = "abc"
    [System.GC]::Collect()
    $a
    abc
    Je pense plutôt que tu as peut-être une variable qui n'est pas initialisée et qui est augmentée (+= ou autre).

  3. #3
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    Je peux poster le script, mais il est énorme et pas forcement bien écrit car c'est du jetable (utilisation unique)

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
     
     
    CLS
     
    ######################################
    #             VARIABLES              #
    ######################################
     
    $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition       																# Path du script
    $PathLDAP = "OU=GroupShare,OU=FileSharing,OU=ouSecurityGroups,OU=ouFRANCE,DC=DOMAIN,DC=com"											# Path LDAP																								# Access Right
    $GroupsAdmin = @("BUILTIN\Administrators","Administrator","NT AUTHORITY\SYSTEM","DOMAIN\PREFIXE_GROUPE_SharedAdmin","DOMAIN\PREFIXE_GROUPE_SharedAdminService")	# Groups Admin
    $PathLog = "D:\PowerShell\Script\Développement\GenGroups\LogGenGroups.log"																		# Path log
     
    ######################################
    #           DLL & Modules            #
    ######################################
     
    Add-type -Path "$scriptPath\AlphaFS\lib\net451\AlphaFS.dll"
    Import-Module ActiveDirectory 
     
    ######################################
    #             FONCTIONS              #
    ######################################
     
    #Check if the OU exists
    Function CheckOU{
    	Param(
    			[parameter(Mandatory=$true)][string]$PathLDAP
    	)	
     
    	If ([ADSI]::Exists("LDAP://$PathLDAP") -eq $true)
    	{
    		Return $true
    	}Else{
    		Write-Host "Target OU can't be found! Group creation skipped!" -ForegroundColor Red
    		Return $false
    	}
    }
    # Conversion SID vers SamAccountName
    Function ConvertFrom-SID{  
    	[CmdletBinding()] 
    	param( 
    		[Parameter(Mandatory=$true,ValueFromPipeline=$true)]$sid,
    		[Parameter(Mandatory=$true,ValueFromPipeline=$true)][string[]]$ComputerName
    	) 
     
    	$objSID = New-Object System.Security.Principal.SecurityIdentifier($sid) 
    	try
    	{
    		# Conversion sur le domaine
    		$objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
    		$name = $objUser.Value
     
    		$GetQADObject = Get-QADObject $sid | SELECT Type,DN
    		$ObjectType = $GetQADObject.Type+" domain"
    		$DN = $GetQADObject.DN
    	}
    	catch
    	{
    		# Conversion sur la machine local
    		$adsi = [adsi]"WinNT://$ComputerName"
    		$users = $adsi.Children | where {($_.SchemaClassName -eq 'user') -OR ($_.SchemaClassName -eq 'group')}
    		$users | ForEach-Object{
    			$localSID = New-Object System.Security.Principal.SecurityIdentifier($_.objectSid.Value,0)
    			if ($localSID.Value -eq $sid)
    			{
    				$Split = $_.Path -Split '/'
    				$name = $Split[$Split.count-1]
    				$ObjectType = $_.SchemaClassName+" local"
    				$DN = "Compte local" # Pas de DN car en local
    			}
    		}
    	}
     
    	# Affichage des résultats
    	New-Object -TypeName PSObject -Property @{ 	SID = $sid 
    												Name = $name
    												ObjectType = $ObjectType
    												DN = $DN
    											} | Select SID,Name,ObjectType,DN
    }
    # Retourne les droits NTFS d'une arborésence donnée
    Function Get-AlphaleonisACL{
    	Param(
    		[parameter(Mandatory=$true)][string]$Path,
    		[parameter(Mandatory=$true)][string]$Server,
    		[parameter(Mandatory=$true)][int]$IsInherited
    	)
     
    	# Conversion du Path via AlphaFS
    	$LongDirectory = [Alphaleonis.Win32.Filesystem.Path]::GetLongPath($Path)
    	# Obtention des ACL depuis conversion du Path via AlphaFS
    	# Test présence répertoire
    	if(TestAccessFolder -Path $LongDirectory){
    		$ItemACL = [Alphaleonis.Win32.Filesystem.Directory]::GetAccessControl($LongDirectory)
    		# Obtention des ACL étendus avec les héritages
    		$ItemACL.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier]) | ForEach-Object{
    			# Conversion SID vers SamAccountName
    			$User = ConvertFrom-SID -ComputerName $Server -sid $_.IdentityReference.value
    			# Filtrage : ne prend pas en compte les dossiers hérités
    			if($IsInherited -eq $false){
    				if($_.IsInherited -eq $False){
    					# Affichage des résultats des Contrôles si héritage activé
    					New-Object -TypeName PSObject -Property @{	Date = Get-Date -format "dd-MMM-yyyy HH:mm"
    																Server = $Server
    																Path = $Path
    																Sid = $_.IdentityReference.value
    																DN = $User.DN
    																Identity = $User.Name
    																Rights = $_.FileSystemRights
    																ObjectType = $User.ObjectType
    																AccessControlType = $_.AccessControlType
    																Propagation = $_.InheritanceFlags
    																IsInherited = $_.IsInherited
    																Error = ""
    															} | Select Date,Server,Path,Sid,DN,Identity,Rights,ObjectType,AccessControlType,Propagation,IsInherited,Error						
    				}
    			}else{
    				# Affichage des résultats des Contrôles sans héritage activé
    				New-Object -TypeName PSObject -Property @{	Date = Get-Date -format "dd-MMM-yyyy HH:mm"
    															Server = $Server
    															Path = $Path
    															Sid = $_.IdentityReference.value
    															DN = $User.DN
    															Identity = $User.Name
    															Rights = $_.FileSystemRights
    															ObjectType = $User.ObjectType
    															AccessControlType = $_.AccessControlType
    															Propagation = $_.InheritanceFlags
    															IsInherited = $_.IsInherited
    															Error = ""
    														} | Select Date,Server,Path,Sid,DN,Identity,Rights,ObjectType,AccessControlType,Propagation,IsInherited,Error
    			}
    		}
    	}else{
    		# Affichage des résultats des Contrôles en cas d'erreur
    		New-Object -TypeName PSObject -Property @{	Date = Get-Date -format "dd-MMM-yyyy HH:mm"
    													Server = $Server
    													Path = $Path
    													Sid = ""
    													DN = ""
    													Identity = ""
    													Rights = ""
    													ObjectType = ""
    													AccessControlType = ""
    													Propagation = ""
    													IsInherited = ""
    													Error = "Accès impossible"
    												} | Select Date,Server,Path,Sid,DN,Identity,Rights,ObjectType,AccessControlType,Propagation,IsInherited,Error
    	}
    }
    # Test si l'accès à un dossier est autorisé
    Function TestAccessFolder{
    	Param(
    		[parameter(Mandatory=$true)][string]$Path
    	)
     
    	Try {
    		# Obtention des propriétés du dossier
    		[Alphaleonis.Win32.Filesystem.Directory]::GetProperties($Path) | Out-Null
    	}
    	Catch{
    		If($_.Exception.Message | Select-String -Pattern "Access is denied" -Quiet){
    			Return $false
    		}elseif($_.Exception.Message | Select-String -Pattern "The system cannot find the path specified" -Quiet){
    			Return $false
    		}
    	}
    	Return $true
    }
    # Retourne les membres des groupes locaux sur une machine distante
    Function GetLocalGroupMembers{
    	param(
    		[Parameter(ValuefromPipeline=$true)][string]$server = $env:computername,
    		[Parameter(ValuefromPipeline=$true)][string]$GroupName = $null
    	)
     
    	PROCESS {
     
    		$finalresult = @()
    		$computer = [ADSI]"WinNT://$server,computer"
     
    		if (!($groupName))
    		{
    			Try{
    				$Groups = $computer.psbase.Children | Where {$_.psbase.schemaClassName -eq "group"} | select -expand name
    			}Catch{	
    				# Affichage des résultats des Contrôles
    				New-Object -TypeName PSObject -Property @{	Server = $server
    															LocalGroup = "Erreur"
    															MemberGroup = "Erreur"
    															Type = "Erreur"
    														} | Select Server,LocalGroup,MemberGroup,Type
    			}
    		}
    		else
    		{
    			$groups = $groupName
    		}
     
    		foreach ($group in $groups)
    		{
    			$gmembers = $null
    			$GMembers = ([ADSI]("WinNT://$server/$group,group")).psbase.invoke("Members")
    			if(!([string]::IsNullOrEmpty($gmembers))){
    				foreach ($gmember in $gmembers)
    				{
    					$name = $gmember.GetType().InvokeMember("Name",'GetProperty', $null, $gmember, $null)
    					$sid = $gmember.GetType().InvokeMember("objectsid",'GetProperty', $null, $gmember, $null)
    					$UserSid = New-Object System.Security.Principal.SecurityIdentifier($sid, 0)
    					$class = $gmember.GetType().InvokeMember("Class",'GetProperty', $null, $gmember, $null)
    					$ads = $gmember.GetType().InvokeMember("adspath",'GetProperty', $null, $gmember, $null)
    					$ConvertFromSID = ConvertFrom-SID -sid $UserSid  -ComputerName $server
    					$members = $ConvertFromSID.Name
     
    					# Affichage des résultats des Contrôles
    					New-Object -TypeName PSObject -Property @{	Server = $server
    																LocalGroup = $group.ToUpper()
    																MemberGroup = $members.ToUpper()
    																Type = (Get-Culture).textinfo.totitlecase($ConvertFromSID.ObjectType)
    															} | Select Server,LocalGroup,MemberGroup,Type
    				}
    			}else{
    					# Affichage des résultats des Contrôles
    					New-Object -TypeName PSObject -Property @{	Server = $server
    																LocalGroup = $group
    																MemberGroup = $null
    																Type = $null
    															} | Select Server,LocalGroup,MemberGroup,Type		
    			}
    		}
        }
    }
    Function GetGroupsMembers{
    	Param(
    			[parameter(Mandatory=$true)][string]$GroupName,
    			[parameter(Mandatory=$true)][string]$ObjectType,
    			[parameter(Mandatory=$true)][string]$Serveur
    	)	
     
    	If($ObjectType -eq "group domain"){
    		# Recherche les utilisateurs (recurssivement) d'un groupe de domaine
    		Return Get-QADGroupMember -Identity $GroupName -Type 'user' -Indirect -SizeLimit 0 | Select Sid,@{N='MemberGroup';e={$_.Name}},Type,DN
    	}
    	ElseIf($ObjectType -eq "group local"){
    		# Recherche les utilisateurs (recurssivement) d'un groupe local
    		GetLocalGroupMembers -Server $Serveur -GroupName $GroupName | Select MemberGroup,Type | ForEach-Object{
    			If($_.Type -like "group*"){
    				GetGroupsMembers -GroupName $_.MemberGroup -ObjectType $_.Type -Serveur $Serveur
    			}else{
    				Return $_ 
    			}
    		}
    	}Else{
    		Return "error"
    	}
    }
    Function AccessRightByDirectories{
    	Param(
    			[parameter(Mandatory=$true)][string]$NetworkPath,
    			[parameter(Mandatory=$true)][array]$GroupsAdmin,
    			[parameter(Mandatory=$true)][string]$Serveur
    	)
    	$regex = [regex]"(^DOMAIN\\Gd-FRA)([0-9]+)-SHARE-(.+?)-(R[OW])$"
    	# Recherche Les membres et ACL du répertoire
    	Get-AlphaleonisACL -Path $NetworkPath -Server $Serveur -IsInherited $false | WHERE {($_.Identity -notmatch $regex) -and ($_.Identity -notcontains $null ) -and ($GroupsAdmin –notcontains $_.Identity) -and ($_.Identity -notcontains $null )} | Select Path,Identity,DN,Sid,Rights,ObjectType,Propagation,AccessControlType | ForEach-Object{
    		# Si le membre est un groupe, on détermine ses utilisateurs
    		If($_.ObjectType -like "group*")
    		{
    			# Recherche les membres du groupe
    			$GetGroupsMembers = GetGroupsMembers -GroupName $_.Identity -ObjectType $_.ObjectType -Serveur $Serveur
    			ForEach($GetGroupsMember in $GetGroupsMembers)
    			{
    				# Affichage des résultats
    				New-Object -TypeName PSObject -Property @{	Path = $item.NetworkPath 
    															Sid = $GetGroupsMember.Sid
    															DN = $GetGroupsMember.DN
    															Users = $GetGroupsMember.MemberGroup
    															Type = $GetGroupsMember.Type
    															AccessRight = $_.Rights
    															AccessControlType = $_.AccessControlType
    															Propagation = $_.Propagation
    														} | Select Path,Sid,DN,Users,Type,AccessRight,AccessControlType,Propagation
    			}
    		}
    		# Sinon on affiche l'utilisateur
    		Else
    		{
    			# Affichage des résultats
    			New-Object -TypeName PSObject -Property @{	Path = $item.NetworkPath 
    														Sid = $_.Sid
    														DN = $_.DN
    														Users = $_.Identity
    														Type = "User Direct"
    														AccessRight = $_.Rights
    														AccessControlType = $_.AccessControlType
    														Propagation = $_.Propagation
    													} | Select Path,Sid,DN,Users,Type,AccessRight,AccessControlType,Propagation
    		}
    	}
    }
    # Ajout des ACL sur un répertoire
    Function AddNTFSPermissions{
    	Param(
    		[parameter(Mandatory=$true)][string]$Path,
    		[parameter(Mandatory=$true)][string]$User,
    		[parameter(Mandatory=$true)][string]$Permission,
    		[parameter(Mandatory=$true)][string]$AccessControlType
    	)
     
        $FileSystemRights = [System.Security.AccessControl.FileSystemRights]$Permission
        $InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
        $PropagationFlag = [System.Security.AccessControl.PropagationFlags]"None"
        $AccessControlType = [System.Security.AccessControl.AccessControlType]$AccessControlType
        $Account = [System.Security.Principal.NTAccount]$User
        $FileSystemAccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($Account, $FileSystemRights, $InheritanceFlag, $PropagationFlag, $AccessControlType)
        $DirectorySecurity = Get-ACL $Path
    	$DirectorySecurity.SetAccessRuleProtection($false,$false) # Active l'héritage
    	#$DirectorySecurity.Access | %{$DirectorySecurity.RemoveAccessRule($_)} | Out-Null # Supprime tous les ACL existantes
    	$DirectorySecurity.AddAccessRule($FileSystemAccessRule) # Ajoute les droits utilisateur
        $DirectorySecurity	| Set-ACL $Path
    }
    # Création des groupes à la volées et ajout des utilisateurs suivant leurs droits d'accès
    Function AddGroupsAndUsers{
    	Param(
    			[parameter(Mandatory=$true)][string]$Serveur,
    			[parameter(Mandatory=$true)][string]$NetworkPath,
    			[parameter(Mandatory=$true)][string]$AccessRightFamilly,
    			[parameter(Mandatory=$true)][string]$Groupe,
    			[parameter(Mandatory=$true)][string]$DescriptionGroupe,
    			[parameter(Mandatory=$true)][string]$PathLDAP,
    			[parameter(Mandatory=$true)][string]$DN,
    			[parameter(Mandatory=$true)][string]$User,
    			[parameter(Mandatory=$true)][string]$SidUser,
    			[parameter(Mandatory=$true)][string]$CountGroup
    	)
     
    	# Réinitialise les variables
    	$CTRL_Add_Group = $null
    	$CTRL_Add_Access_Right_On_Folder = $null
    	$CTRL_Add_Group_Com = $null
    	$CTRL_Add_User_On_Group = $null
     
    	# Personnalise les droits
    	If($AccessRightFamilly -eq 3){
    		$Groupe = $Groupe.Replace("-XX","-RW")
    		$DescriptionGroupe = $DescriptionGroupe.Replace("- XX","- Read/Write")
    		$Permission = "Modify"
    	}ElseIf($AccessRightFamilly -eq 2){
    		$Groupe = $Groupe.Replace("-XX","-RO")
    		$DescriptionGroupe = $DescriptionGroupe.Replace("- XX","- Read")
    		$Permission = "Read"
    	}ElseIf($AccessRightFamilly -eq 1){
    		$Groupe = $Groupe.Replace("-XX","-BW")
    		$DescriptionGroupe = $DescriptionGroupe.Replace("- XX","- Browse")
    		$Permission = ""
    	}ElseIf($AccessRightFamilly -eq 0){
    		$Groupe = $Groupe.Replace("-XX","-SP") 
    		$DescriptionGroupe = $DescriptionGroupe.Replace("- XX","- Special")
    		$Permission = ""
    	}
     
    	Write-Host $Serveur";"$NetworkPath";"$AccessRightFamilly";"$Groupe";"$DescriptionGroupe";"$PathLDAP";"$DN";"$User";"$SidUser";"$CountGroup
    	Write-Host
     
     
     
    #	####
    #	# Création du groupe
    #	####
    #	
    #	# Test si le groupe existe ($True) sinon on le créer ($False)
    #	[ADSI]::Exists("LDAP://CN=$Groupe,$PathLDAP")
    #	If([ADSI]::Exists("LDAP://CN=$Groupe,$PathLDAP")){ # $True
    #		$CTRL_Add_Group = "OK"
    #		If($CountGroup -lt 1 ){
    #			$CTRL_Add_Group_Com = "Groupe déjà présent dans l'AD"
    #		}	
    #		####
    #		# Ajout du groupe dans les sécurité NTFS du répertoire
    #		####
    #		
    #		AddNTFSPermissions -Path $NetworkPath -User $Groupe -Permission $Permission -AccessControlType "Allow"
    #		# Test ajout membre et ACL au répertoire
    #		If((Get-AlphaleonisACL -Path $NetworkPath -Server $Serveur -IsInherited $false | Select Path,Identity | WHERE {$_.Identity -like "*$Groupe*"} | measure | % { $_.Count }) -eq 1){ # $True
    #			$CTRL_Add_Access_Right_On_Folder = "OK"
    #		}Else{
    #			$CTRL_Add_Access_Right_On_Folder = "KO"
    #		}
    #	}Else{ # $False
    #		$NewGroup = New-qadGroup -name $Groupe -samAccountName $Groupe -Description $DescriptionGroupe -ParentContainer $PathLDAP -grouptype 'Security' -groupscope 'Global'
    #		# Test si le groupe a bien été créé
    #		If([ADSI]::Exists("LDAP://CN=$Groupe,$PathLDAP")){ # $True
    #			$CTRL_Add_Group = "OK"
    #			$CountGroup = $CountGroup + 1
    #			
    #			####
    #			# Ajout du groupe dans les sécurité NTFS du répertoire
    #			####
    #			
    #			AddNTFSPermissions -Path $NetworkPath -User $Groupe -Permission $Permission -AccessControlType "Allow"
    #			# Test ajout membre et ACL au répertoire
    #			If((Get-AlphaleonisACL -Path $NetworkPath -Server $Serveur -IsInherited $false | Select Path,Identity | WHERE {$_.Identity -like "*$Groupe*"} | measure | % { $_.Count }) -eq 1){ # $True
    #				$CTRL_Add_Access_Right_On_Folder = "OK"
    #			}Else{ # $False
    #				$CTRL_Add_Access_Right_On_Folder = "KO"
    #			}
    #		}Else{ # $False
    #			$CTRL_Add_Group = "KO"
    #		}
    #	}
    #	
    #	####
    #	# Ajout utilisateur dans groupe
    #	####
    #	
    #	# Chemin LDAP du groupe et de l'utilisateur
    #	$LDAPGroup =[ADSI]"LDAP://CN=$Groupe,$PathLDAP"
    #	$LDAPUser = [ADSI]"LDAP://$DN"
    #	
    #	# Ajout du membre dans le groupe s'il n'est pas présent
    #	If($LDAPGroup.IsMember($LDAPUser.ADsPath)){ # $True
    #		$CTRL_Add_User_On_Group_Com = "Utilisateur déjà présent dans le groupe"
    #	}Else{ # $False
    #		$LDAPGroup.Add($LDAPUser.ADsPath)
    #		$CTRL_Add_User_On_Group_Com = $null
    #	}
    #	# Test si l'utilisateur est bien ajouté dans le groupe ; utilise ADSI car plus rapide que Get-QADGroupMember
    #	If ($LDAPGroup.IsMember($LDAPUser.ADsPath)){ # $True
    #		$CTRL_Add_User_On_Group = "OK"
    #	}Else{ # $False
    #		$CTRL_Add_User_On_Group = "KO"
    #	}
    #	
    #	####
    #	# Affichage des retours
    #	####
    #	New-Object -TypeName PSObject -Property @{	Date = Get-Date -format "dd-MMM-yyyy HH:mm"
    #												Path = $NetworkPath
    #												Groupe = $Groupe
    #												Utilisateur = $User
    #												SidUtilisateur = $SidUser
    #												CTRL_Add_Group = $CTRL_Add_Group
    #												CTRL_Add_Access_Right_On_Folder = $CTRL_Add_Access_Right_On_Folder
    #												CTRL_Add_Group_Com = $CTRL_Add_Group_Com
    #												CTRL_Add_User_On_Group = $CTRL_Add_User_On_Group
    #												CTRL_Add_User_On_Group_Com = $CTRL_Add_User_On_Group_Com
    #											} | Select Date,Path,Groupe,Utilisateur,SidUtilisateur,CTRL_Add_Group,CTRL_Add_Access_Right_On_Folder,CTRL_Add_Group_Com,CTRL_Add_User_On_Group,CTRL_Add_User_On_Group_Com
    }
     
    ######################################
    #                MAIN                #
    ######################################
     
    #Import CSV 
    $path     = Split-Path -parent $MyInvocation.MyCommand.Definition
    $newpath  = $path + "\GénérationGroupesAD.csv"
    $csv      = @()
    (Get-Content $newpath) | Set-Content $newpath -Encoding UTF8
    $csv      = Import-Csv -Path $newpath -Delimiter ";"
    $pathlog = $path + "\LogGenGroupsAD.csv"
     
    # Limite de recherche : ilimité
    Set-QADPSSnapinSettings -DefaultSizeLimit 0
     
    # Connexion au DC
    #$QADService = connect-QADService -Service $DC":"$PortDC
     
    # Augmentation de la mémoire du shell
    #$maxmemorypershellmb = Set-item wsman:localhost\shell\maxmemorypershellmb 4096
     
    # Suppression des LOG
    If(Test-Path "CTRL.log")
    {
    	Remove-Item  "CTRL.log" -Force
    }
     
    If(Test-Path "LogGenGroupsAD.csv")
    {
    	Remove-Item  "LogGenGroupsAD.csv" -Force
    }
     
    # Famille de droits NTFS
    $AccessRightReadAndWrite = @("AppendData,","CreateDirectories,","CreateFiles,","Delete,","DeleteSubdirectoriesAndFiles,","FullControl","Modify,","Write,","WriteData,")
    $AccessRighRead = @("ExecuteFile,","Read,","ReadAndExecute,","ReadData,")
    $AccessRighBrowseFolder = @("Traverse,","ListDirectory,","ReadAndExecute,")
    $AccessRighSpecial = @("ChangePermissions,","ReadAttributes,","ReadExtendedAttributes,","ReadPermissions,","Synchronize,","TakeOwnership,","WriteAttributes,","WriteExtendedAttributes,")
     
     
    #Check if the OU exists
    If ((CheckOU -PathLDAP $PathLDAP) -eq $True) 
    {
     
    	####
    	# Barre chargement
    	####
    	$i = 0	# Variable compteur pour le Write-Progress
    	Write-Progress -activity "Génération des groupes, ajout des utilisateurs et attribution des accès : " -status "Avancement : calcul en cours..."
     
    	# Parcours le fichier CSV
    	ForEach ($item In $csv)
    	{
    		# Vider la mémoire
    		[System.GC]::Collect()
    		# Progression barre chargement
    		$i++
    		Write-Progress -activity "Génération des groupes, ajout des utilisateurs et attribution des accès : " -status "Avancement : $i sur $(($csv | measure).Count)" -percentComplete $($i* 100/($csv | measure).Count)
     
    		##########
    		# Recherche les utilisateurs/droits ayant des accès aux répertoires
    		##########
    		If(TestAccessFolder -Path $item.NetworkPath)
    		{
    			$CountGroup = 0
    			$AccessRightByDirectories = AccessRightByDirectories -NetworkPath $item.NetworkPath -GroupsAdmin $GroupsAdmin -Serveur $item.Serveur
    			ForEach($AccessRightByDirectorie in $AccessRightByDirectories){
    				# Contenaires d'utilisateurs par type de droits
    				$UsersWithAccessRight = @()
    				# Catégorisation par famille de droits des utilisateurs suivant leurs accès
    				# Création d'un nouvel objet
    				$obj = New-Object Psobject
    				If($AccessRightReadAndWrite | Where-Object {$AccessRightByDirectorie.accessRight -match $_}){
    					$obj | add-member -name "Path" -membertype Noteproperty -value $AccessRightByDirectorie.Path
    					$obj | add-member -name "Sid" -membertype Noteproperty -value $AccessRightByDirectorie.Sid
    					$obj | add-member -name "Users" -membertype Noteproperty -value $AccessRightByDirectorie.Users
    					$obj | add-member -name "DN" -membertype Noteproperty -value $AccessRightByDirectorie.DN
    					$obj | add-member -name "AccessRightFamilly" -membertype Noteproperty -value "3" # Read/Write
    					$UsersWithAccessRight += $obj
    				}
    				ElseIf(($AccessRighBrowseFolder | Where-Object {$AccessRightByDirectorie.accessRight -match $_}) -and ($AccessRightByDirectorie.Propagation -like "None")){
    					$obj | add-member -name "Path" -membertype Noteproperty -value $AccessRightByDirectorie.Path
    					$obj | add-member -name "Sid" -membertype Noteproperty -value $AccessRightByDirectorie.Sid
    					$obj | add-member -name "Users" -membertype Noteproperty -value $AccessRightByDirectorie.Users
    					$obj | add-member -name "DN" -membertype Noteproperty -value $AccessRightByDirectorie.DN
    					$obj | add-member -name "AccessRightFamilly" -membertype Noteproperty -value "1" # Browse
    					$UsersWithAccessRight += $obj
    				}
    				ElseIf($AccessRighRead | Where-Object {$AccessRightByDirectorie.accessRight -match $_}){
    					$obj | add-member -name "Path" -membertype Noteproperty -value $AccessRightByDirectorie.Path
    					$obj | add-member -name "Sid" -membertype Noteproperty -value $AccessRightByDirectorie.Sid
    					$obj | add-member -name "Users" -membertype Noteproperty -value $AccessRightByDirectorie.Users
    					$obj | add-member -name "DN" -membertype Noteproperty -value $AccessRightByDirectorie.DN
    					$obj | add-member -name "AccessRightFamilly" -membertype Noteproperty -value "2" # Read
    					$UsersWithAccessRight += $obj
    				}
    				Else{
    					$obj | add-member -name "Path" -membertype Noteproperty -value $AccessRightByDirectorie.Path
    					$obj | add-member -name "Sid" -membertype Noteproperty -value $AccessRightByDirectorie.Sid
    					$obj | add-member -name "Users" -membertype Noteproperty -value $AccessRightByDirectorie.Users
    					$obj | add-member -name "DN" -membertype Noteproperty -value $AccessRightByDirectorie.DN
    					$obj | add-member -name "AccessRightFamilly" -membertype Noteproperty -value "0" # Special
    					$UsersWithAccessRight += $obj
    				}
     
    				# Dédoublonnement en gardant le droits d'accès le plus élévé
    				$G = $UsersWithAccessRight | group users
    				$UsersWithAccessRightUnduplicated = $G | % {
    					$current=$_.group    
    					if ($current.Count -gt 1)
    					{ 
    						$Current|Sort AccessRightFamilly -Descending|select -first 1 
    					}
    					else
    					{  
    						$Current
    					}
    				}
    				$UsersWithAccessRightUnduplicated | export-csv -path "D:\PowerShell\Script\Développement\GenGroups\CTRL.log"  -Encoding UTF8 -Delimiter ";" -NoTypeInformation -Append -Force
     
    				# Création des groupes à la volées et ajout des utilisateurs suivant leurs droits d'accès puis ajout des groupes dans les sécuritées NTFS du répertoire
    				$UsersWithAccessRightUnduplicated | Foreach-object {
    					If(-not ($_.DN -like "Compte local")){
    						AddGroupsAndUsers -Serveur $item.Serveur -NetworkPath $item.NetworkPath -AccessRightFamilly $_.AccessRightFamilly -Groupe $item.Groupe -DescriptionGroupe $item.DescriptionGroupe -PathLDAP $PathLDAP -DN $_.DN -User $_.Users -SidUser $_.Sid -CountGroup $CountGroup #| export-csv -path $PathLog -Encoding UTF8 -Delimiter ";" -NoTypeInformation -Append -Force
    					}		
    				}	
    				$CountGroup = $CountGroup + 1
    			}# End ForEach AccessRightByDirectories
    		}# End If TestAccessFolder
    	}# End Foreach csv	
     
    	####
    	# Fin barre chargement
    	####
    	Write-Progress -activity "Génération des groupes, ajout des utilisateurs et attribution des accès : " -status "FINI !"
    	sleep 5
    	Write-Progress -activity "Génération des groupes, ajout des utilisateurs et attribution des accès : " -completed
    }# End If Check OU

  4. #4
    Membre habitué
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Juillet 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Juillet 2015
    Messages : 66
    Points : 126
    Points
    126
    Par défaut
    Effectivement pas simple de voir ce qui ne va pas.

    Ton script effectue pas mal d'opérations.

    Il faudrait séparer chaque gros bloc d'opération (recherche d'ACL, recherche de groupes, etc), les tester à part afin d'identifier le code qui ne va pas.
    Tu avais mentionné que c'était la recherche des membres d'un groupe qui posait problème. Je créerais une cmdlet qui ne fait que ça, même en simulant les inputs (liste de groupes par exemples).

  5. #5
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    Tu initialises comment tes variables ?

    $var = $null ?

  6. #6
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Points : 15 060
    Points
    15 060
    Billets dans le blog
    1
    Par défaut
    Salut,
    Citation Envoyé par Micky Balladelli Voir le message
    Effectivement pas simple de voir ce qui ne va pas.
    Le script utilise la librairie Alphaleonis vérifie sur le site du projet.
    J'y lis aussi des appels à des interfaces [ADSI] (COM), à regarder donc, mais sans outil dédié cela va être laborieux.
    Enfin ne pas exclure qu'un cmdlet peut avoir des fuites mémoire.
    Le contexte d'exécution est en remote ?



    Ceci est déconseillé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        $UsersWithAccessRight = @()
    ...
        $UsersWithAccessRight += $obj
    Utilise un arraylist, attention à la méthode Add() : [void]$List.Add($Objet)

    Autre piste : tester sans le Write-Progress

  7. #7
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    J'ai refais des tests pas à pas. Effectivement le Alphaeonis mange pas mal de mémoire ! J'ai fais un test en basculant la sortie vers un fichier et ca mange de la mémoire malgré tout. Cependant, je n'ai pas eu d'erreur de mémoire.

    J'aimerai optimisé cette partie de code par rapport à tes conseils mais je ne sais comment faire pour ne pas passer par un tableau. Je le ferai bien directement dans la fonction, ca serai le top :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    =powershell$AccessRightByDirectories = AccessRightByDirectories -NetworkPath $item.NetworkPath -GroupsAdmin $GroupsAdmin -Serveur $item.Serveur			
    			ForEach($AccessRightByDirectorie in $AccessRightByDirectories){
    				# Contenaires d'utilisateurs par type de droits
    				$UsersWithAccessRight = @()
    				# Catégorisation par famille de droits des utilisateurs suivant leurs accès
    				# Création d'un nouvel objet
    				$obj = New-Object Psobject
    				If($AccessRightReadAndWrite | Where-Object {$AccessRightByDirectorie.accessRight -match $_}){
    					$obj | add-member -name "Path" -membertype Noteproperty -value $AccessRightByDirectorie.Path
    					$obj | add-member -name "Sid" -membertype Noteproperty -value $AccessRightByDirectorie.Sid
    					$obj | add-member -name "Users" -membertype Noteproperty -value $AccessRightByDirectorie.Users
    					$obj | add-member -name "DN" -membertype Noteproperty -value $AccessRightByDirectorie.DN
    					$obj | add-member -name "AccessRightFamilly" -membertype Noteproperty -value "3" # Read/Write
    					$UsersWithAccessRight += $obj
    				}
    				ElseIf(($AccessRighBrowseFolder | Where-Object {$AccessRightByDirectorie.accessRight -match $_}) -and ($AccessRightByDirectorie.Propagation -like "None")){
    					$obj | add-member -name "Path" -membertype Noteproperty -value $AccessRightByDirectorie.Path
    					$obj | add-member -name "Sid" -membertype Noteproperty -value $AccessRightByDirectorie.Sid
    					$obj | add-member -name "Users" -membertype Noteproperty -value $AccessRightByDirectorie.Users
    					$obj | add-member -name "DN" -membertype Noteproperty -value $AccessRightByDirectorie.DN
    					$obj | add-member -name "AccessRightFamilly" -membertype Noteproperty -value "1" # Browse
    					$UsersWithAccessRight += $obj
    				}
    				ElseIf($AccessRighRead | Where-Object {$AccessRightByDirectorie.accessRight -match $_}){
    					$obj | add-member -name "Path" -membertype Noteproperty -value $AccessRightByDirectorie.Path
    					$obj | add-member -name "Sid" -membertype Noteproperty -value $AccessRightByDirectorie.Sid
    					$obj | add-member -name "Users" -membertype Noteproperty -value $AccessRightByDirectorie.Users
    					$obj | add-member -name "DN" -membertype Noteproperty -value $AccessRightByDirectorie.DN
    					$obj | add-member -name "AccessRightFamilly" -membertype Noteproperty -value "2" # Read
    					$UsersWithAccessRight += $obj
    				}
    				Else{
    					$obj | add-member -name "Path" -membertype Noteproperty -value $AccessRightByDirectorie.Path
    					$obj | add-member -name "Sid" -membertype Noteproperty -value $AccessRightByDirectorie.Sid
    					$obj | add-member -name "Users" -membertype Noteproperty -value $AccessRightByDirectorie.Users
    					$obj | add-member -name "DN" -membertype Noteproperty -value $AccessRightByDirectorie.DN
    					$obj | add-member -name "AccessRightFamilly" -membertype Noteproperty -value "0" # Special
    					$UsersWithAccessRight += $obj
    				}
    				
    				# Dédoublonnement en gardant le droits d'accès le plus élévé
    				$G = $UsersWithAccessRight | group users
    				$UsersWithAccessRightUnduplicated = $G | % {
    					$current=$_.group    
    					if ($current.Count -gt 1)
    					{ 
    						$Current|Sort AccessRightFamilly -Descending|select -first 1 
    					}
    					else
    					{  
    						$Current
    					}
    				}

  8. #8
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    J'ai supprimé le tableau d'objet et inclure ma condition dans la fonction.

    Je ne sais pas s'il y a moyen de mettre le doublonnage dans la fonction directement

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    Function AccessRightByDirectories{
    	Param(
    			[parameter(Mandatory=$true)][string]$NetworkPath,
    			[parameter(Mandatory=$true)][array]$GroupsAdmin,
    			[parameter(Mandatory=$true)][string]$Serveur,
    			[parameter(Mandatory=$true)][array]$AccessRightReadAndWrite,
    			[parameter(Mandatory=$true)][array]$AccessRighBrowseFolder,
    			[parameter(Mandatory=$true)][array]$AccessRighRead
    	)
    	# Recherche Les membres et ACL du répertoire
    	Get-AlphaleonisACL -Path $item.NetworkPath -Server $item.Serveur -IsInherited $false | WHERE {($_.Identity -notmatch ([regex]"(^FERRERONET\\Gd-FRA)([0-9]+)-SHARE-(.+?)-(R[OW])$")) -and ($_.Identity -notcontains $null ) -and ($GroupsAdmin –notcontains $_.Identity) -and ($_.Identity -notcontains $null )} | Select Path,Identity,DN,Sid,Rights,ObjectType,Propagation,AccessControlType | ForEach-Object{
    		# Conversion par famille de droits des utilisateurs suivant leurs accès				
    		If($AccessRightReadAndWrite | Where-Object {$_.Rights -match $_.Rights}){
    			$AccessRightFamilly = "3" # Read/Write
    		}
    		ElseIf(($AccessRighBrowseFolder | Where-Object {$_.Rights -match $_}) -and ($_.Propagation -like "None")){
    			$AccessRightFamilly = "1" # Browse
    		}
    		ElseIf($AccessRighRead | Where-Object {$_.Rights -match $_}){
    			$AccessRightFamilly = "2" # Read
    		}
    		Else{
    			$AccessRightFamilly= "0" # Special
    		}
    		# Si le membre est un groupe, on détermine ses utilisateurs
    		If($_.ObjectType -like "group*")
    		{
    			# Recherche les membres du groupe
    			$GetGroupsMembers = GetGroupsMembers -GroupName $_.Identity -ObjectType $_.ObjectType -Serveur $Serveur
    			ForEach($GetGroupsMember in $GetGroupsMembers)
    			{
    				# Affichage des résultats
    				New-Object -TypeName PSObject -Property @{	Path = $item.NetworkPath 
    															Sid = $GetGroupsMember.Sid
    															DN = $GetGroupsMember.DN
    															Users = $GetGroupsMember.MemberGroup
    															AccessRightFamilly = $AccessRightFamilly
    														} | Select Path,Sid,DN,Users,AccessRightFamilly
    			}
    		}
    		# Sinon on affiche l'utilisateur
    		Else
    		{
    			# Affichage des résultats
    			New-Object -TypeName PSObject -Property @{	Path = $item.NetworkPath 
    														Sid = $_.Sid
    														DN = $_.DN
    														Users = $_.Identity
    														AccessRightFamilly = $AccessRightFamilly
    													} | Select Path,Sid,DN,Users,AccessRightFamilly
    		}
    	}
    }

  9. #9
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    Pour le dédoublonnage, j'ai essayé un truc comme ca, mais je ne sais pas si cela fonctionne. Je n'ai pas d'erreurs :

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
     
    Function AccessRightByDirectories{
    	Param(
    			[parameter(Mandatory=$true)][string]$NetworkPath,
    			[parameter(Mandatory=$true)][array]$GroupsAdmin,
    			[parameter(Mandatory=$true)][string]$Serveur,
    			[parameter(Mandatory=$true)][array]$AccessRightReadAndWrite,
    			[parameter(Mandatory=$true)][array]$AccessRighBrowseFolder,
    			[parameter(Mandatory=$true)][array]$AccessRighRead
    	)
    	# Recherche Les membres et ACL du répertoire
    	Get-AlphaleonisACL -Path $item.NetworkPath -Server $item.Serveur -IsInherited $false | WHERE {($_.Identity -notmatch ([regex]"(^FERRERONET\\Gd-FRA)([0-9]+)-SHARE-(.+?)-(R[OW])$")) -and ($_.Identity -notcontains $null ) -and ($GroupsAdmin –notcontains $_.Identity) -and ($_.Identity -notcontains $null )} | Select Path,Identity,DN,Sid,Rights,ObjectType,Propagation,AccessControlType | ForEach-Object{
    		# Conversion par famille de droits des utilisateurs suivant leurs accès				
    		If($AccessRightReadAndWrite | Where-Object {$_.Rights -match $_.Rights}){
    			$AccessRightFamilly = "3" # Read/Write
    		}
    		ElseIf(($AccessRighBrowseFolder | Where-Object {$_.Rights -match $_}) -and ($_.Propagation -like "None")){
    			$AccessRightFamilly = "1" # Browse
    		}
    		ElseIf($AccessRighRead | Where-Object {$_.Rights -match $_}){
    			$AccessRightFamilly = "2" # Read
    		}
    		Else{
    			$AccessRightFamilly= "0" # Special
    		}
    		# Si le membre est un groupe, on détermine ses utilisateurs
    		If($_.ObjectType -like "group*")
    		{
    			# Recherche les membres du groupe
    			$GetGroupsMembers = GetGroupsMembers -GroupName $_.Identity -ObjectType $_.ObjectType -Serveur $Serveur
    			ForEach($GetGroupsMember in $GetGroupsMembers)
    			{
    				# Affichage des résultats
    				New-Object -TypeName PSObject -Property @{	Path = $item.NetworkPath 
    															Sid = $GetGroupsMember.Sid
    															DN = $GetGroupsMember.DN
    															Users = $GetGroupsMember.MemberGroup
    															AccessRightFamilly = $AccessRightFamilly
    														} | Select Path,Sid,DN,Users,AccessRightFamilly
    			}
    		}
    		# Sinon on affiche l'utilisateur
    		Else
    		{
    			# Affichage des résultats
    			New-Object -TypeName PSObject -Property @{	Path = $item.NetworkPath 
    														Sid = $_.Sid
    														DN = $_.DN
    														Users = $_.Identity
    														AccessRightFamilly = $AccessRightFamilly
    													} | Select Path,Sid,DN,Users,AccessRightFamilly
    		}
    	} | group $_.users | % { # Dédoublonnement en gardant le droits d'accès le plus élévé
    		$current=$_.group    
    		if ($current.Count -gt 1)
    		{ 
    			$Current|Sort AccessRightFamilly -Descending|select -first 1 
    		}
    		else
    		{  
    			$Current
    		}
    	}
    }

  10. #10
    Membre habitué
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Juillet 2015
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Juillet 2015
    Messages : 66
    Points : 126
    Points
    126
    Par défaut
    J'utilise AlphaFS moi-même, c'est vraiment top.

    Un conseil, au lieu de piper et faire du one-line (meme si c'est beau ) casse ton code, crée des variables avec le résultat des différents blocs ainsi tu verras de suite si le résultat est correct.

  11. #11
    Rédacteur


    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    7 171
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 7 171
    Points : 15 060
    Points
    15 060
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par arnaudperfect Voir le message
    J'aimerai optimisé cette partie de code par rapport à tes conseils mais je ne sais comment faire pour ne pas passer par un tableau.
    Comme ceci :
    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
                    # --> change : $UsersWithAccessRight = @()
                    $UsersWithAccessRight = New-Object System.Collections.ArrayList() # ou System.Collections.ArrayList(20)
                    # Catégorisation par famille de droits des utilisateurs suivant leurs accès
                    # Création d'un nouvel objet
                    $obj = New-Object Psobject
                    If($AccessRightReadAndWrite | Where-Object {$AccessRightByDirectorie.accessRight -match $_}){
                        $obj | add-member -name "Path" -membertype Noteproperty -value $AccessRightByDirectorie.Path
                        $obj | add-member -name "Sid" -membertype Noteproperty -value $AccessRightByDirectorie.Sid
                        $obj | add-member -name "Users" -membertype Noteproperty -value $AccessRightByDirectorie.Users
                        $obj | add-member -name "DN" -membertype Noteproperty -value $AccessRightByDirectorie.DN
                        $obj | add-member -name "AccessRightFamilly" -membertype Noteproperty -value "3" # Read/Write
                        #  --> change : $UsersWithAccessRight += $obj
                        [void]$UsersWithAccessRight.Add($obj)
    La syntaxe '$UsersWithAccessRight += $obj' fonctionne avec un arraylist, et bien que ce soit plus verbeux je lui préfère l'appel à Add()

    Citation Envoyé par arnaudperfect Voir le message
    Je le ferai bien directement dans la fonction, ca serai le top
    De créer une fonction d'ajout de membre est préférable.
    Tu peux utiliser une globale ( 'c'est mal'), le scope (risqué) ou une fonction de ce type (code avancè).
    Mais si demain tu veux réutiliser la fonction ce sera délicat, pour du code rapido de faire simple et lisible c'est pour moi un bon compris.

    Citation Envoyé par arnaudperfect Voir le message
    Pour le dédoublonnage, j'ai essayé un truc comme ca, mais je ne sais pas si cela fonctionne
    Freine
    On peut tout placer dans une seule fonction, mais le debug/la maintenance nécessitera plus de temps.
    Un conseil créer une fonction dédiée pour ce traitement.

  12. #12
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    Alors, j'ai du mieux.

    J'ai réorganisé mon code et fait moins de grosses fonctions. Je l'ai pas découper en petites fonctions plus simple à comprendre. Aussi, j'utilisais un shell en 32 bits (je n'avais pas fait attention). Maintenant, j'utilise le shell en 64 bits. Je consomme toujours de la mémoire (jusqu'à 3 Go) mais je n'ai pas d'erreur Powershell sur la mémoire.

    Voici le code :

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    CLS
     
    ######################################
    #             VARIABLES              #
    ######################################
     
    $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition       																# Path du script
    $PathLDAP = "OU=GroupShare,OU=FileSharing,OU=ouSecurityGroups,OU=ouSITE,DC=DOMAIN,DC=com"											# Path LDAP																								# Access Right
    $GroupsAdmin = @("BUILTIN\Administrators","Administrator","NT AUTHORITY\SYSTEM","DOMAIN\prefixe_Groupe_SharedAdmin","DOMAIN\prefixe_Groupe_SharedAdminService")	# Groups Admin
    $PathLog  = $scriptPath + "\LogGenGroupsAD.csv" # Path Log
    $CSVPath  = $scriptPath + "\GénérationGroupesAD.csv" # Path CSV
    # Famille de droits NTFS
    $AccessRightReadAndWrite = @("AppendData,","CreateDirectories,","CreateFiles,","Delete,","DeleteSubdirectoriesAndFiles,","FullControl","Modify,","Write,","WriteData,")
    $AccessRighRead = @("ExecuteFile,","Read,","ReadAndExecute,","ReadData,")
    $AccessRighBrowseFolder = @("Traverse,","ListDirectory,","ReadAndExecute,")
    $AccessRighSpecial = @("ChangePermissions,","ReadAttributes,","ReadExtendedAttributes,","ReadPermissions,","Synchronize,","TakeOwnership,","WriteAttributes,","WriteExtendedAttributes,")
     
    ######################################
    #           DLL & Modules            #
    ######################################
     
    Add-type -Path "$scriptPath\AlphaFS\lib\net451\AlphaFS.dll"
    Import-Module ActiveDirectory 
     
    ######################################
    #             FONCTIONS              #
    ######################################
     
    # Check if the OU exists
    Function CheckOU{
    	Param(
    			[parameter(Mandatory=$true)][string]$PathLDAP
    	)	
     
    	If ([ADSI]::Exists("LDAP://$PathLDAP") -eq $true)
    	{
    		Return $true
    	}Else{
    		Write-Host "Target OU can't be found! Group creation skipped!" -ForegroundColor Red
    		Return $false
    	}
    }
    # Test si l'accès à un dossier est autorisé
    Function TestAccessFolder{
    	Param(
    		[parameter(Mandatory=$true)][string]$Path
    	)
     
    	Try {
    		# Obtention des propriétés du dossier
    		[Alphaleonis.Win32.Filesystem.Directory]::GetProperties($Path) | Out-Null
    	}
    	Catch{
    		If($_.Exception.Message | Select-String -Pattern "Access is denied" -Quiet){
    			Return $false
    		}elseif($_.Exception.Message | Select-String -Pattern "The system cannot find the path specified" -Quiet){
    			Return $false
    		}
    	}
    	Return $true
    }
    # Sous fonction de Get-AlphaleonisACL. Conversion SID vers SamAccountName
    Function ConvertFrom-SID{  
    	[CmdletBinding()] 
    	param( 
    		[Parameter(Mandatory=$true,ValueFromPipeline=$true)]$sid,
    		[Parameter(Mandatory=$true,ValueFromPipeline=$true)][string[]]$ComputerName
    	) 
     
    	$objSID = New-Object System.Security.Principal.SecurityIdentifier($sid) 
    	try
    	{
    		# Conversion sur le domaine
    		$objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
    		$name = $objUser.Value
     
    		$GetQADObject = Get-QADObject $sid | SELECT Type,DN
    		$ObjectType = $GetQADObject.Type+" domain"
    		$DN = $GetQADObject.DN
    	}
    	catch
    	{
    		# Conversion sur la machine local
    		$adsi = [adsi]"WinNT://$ComputerName"
    		$users = $adsi.Children | where {($_.SchemaClassName -eq 'user') -OR ($_.SchemaClassName -eq 'group')}
    		$users | ForEach-Object{
    			$localSID = New-Object System.Security.Principal.SecurityIdentifier($_.objectSid.Value,0)
    			if ($localSID.Value -eq $sid)
    			{
    				$Split = $_.Path -Split '/'
    				$name = $Split[$Split.count-1]
    				$ObjectType = $_.SchemaClassName+" local"
    				$DN = "Compte local" # Pas de DN car en local
    			}
    		}
    	}
     
    	# Affichage des résultats
    	New-Object -TypeName PSObject -Property @{ 	SID = $sid 
    												Name = $name
    												ObjectType = $ObjectType
    												DN = $DN
    											} | Select SID,Name,ObjectType,DN
    }
    # Retourne les droits NTFS d'une arborésence donnée
    Function Get-AlphaleonisACL{
    	Param(
    		[parameter(Mandatory=$true)][string]$Path,
    		[parameter(Mandatory=$true)][string]$Server,
    		[parameter(Mandatory=$true)][int]$IsInherited
    	)
     
    	# Conversion du Path via AlphaFS
    	$LongDirectory = [Alphaleonis.Win32.Filesystem.Path]::GetLongPath($Path)
    	# Obtention des ACL depuis conversion du Path via AlphaFS
    	# Test présence répertoire
    	if(TestAccessFolder -Path $LongDirectory){
    		$ItemACL = [Alphaleonis.Win32.Filesystem.Directory]::GetAccessControl($LongDirectory)
    		# Obtention des ACL étendus avec les héritages
    		$ItemACL.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier]) | ForEach-Object{
    			# Conversion SID vers SamAccountName
    			$User = ConvertFrom-SID -ComputerName $Server -sid $_.IdentityReference.value
    			# Filtrage : ne prend pas en compte les dossiers hérités
    			if($IsInherited -eq $false){
    				if($_.IsInherited -eq $False){
    					# Affichage des résultats des Contrôles si héritage activé
    					New-Object -TypeName PSObject -Property @{	Server = $Server
    																Path = $Path
    																Sid = $_.IdentityReference.value
    																DN = $User.DN
    																Identity = $User.Name
    																Rights = $_.FileSystemRights
    																ObjectType = $User.ObjectType
    																AccessControlType = $_.AccessControlType
    																Propagation = $_.InheritanceFlags
    																IsInherited = $_.IsInherited
    																Error = ""
    															} | Select Server,Path,Sid,DN,Identity,Rights,ObjectType,AccessControlType,Propagation,IsInherited,Error						
    				}
    			}else{
    				# Affichage des résultats des Contrôles sans héritage activé
    				New-Object -TypeName PSObject -Property @{	Server = $Server
    															Path = $Path
    															Sid = $_.IdentityReference.value
    															DN = $User.DN
    															Identity = $User.Name
    															Rights = $_.FileSystemRights
    															ObjectType = $User.ObjectType
    															AccessControlType = $_.AccessControlType
    															Propagation = $_.InheritanceFlags
    															IsInherited = $_.IsInherited
    															Error = ""
    														} | Select Server,Path,Sid,DN,Identity,Rights,ObjectType,AccessControlType,Propagation,IsInherited,Error
    			}
    		}
    	}else{
    		# Affichage des résultats des Contrôles en cas d'erreur
    		New-Object -TypeName PSObject -Property @{	Server = $Server
    													Path = $Path
    													Sid = ""
    													DN = ""
    													Identity = ""
    													Rights = ""
    													ObjectType = ""
    													AccessControlType = ""
    													Propagation = ""
    													IsInherited = ""
    													Error = "Accès impossible"
    												} | Select Server,Path,Sid,DN,Identity,Rights,ObjectType,AccessControlType,Propagation,IsInherited,Error
    	}
    }
    # Sous fonction de GetLocalGroupMembers. Retourne les membres locaux d'un groupe local sur une machine distante
    Function GetLocalGroupMembers{
    	param(
    		[Parameter(ValuefromPipeline=$true)][string]$server = $env:computername,
    		[Parameter(ValuefromPipeline=$true)][string]$GroupName = $null
    	)
     
    	$finalresult = @()
    	$computer = [ADSI]"WinNT://$server,computer"
     
    	if (!($groupName))
    	{
    		Try{
    			$Groups = $computer.psbase.Children | Where {$_.psbase.schemaClassName -eq "group"} | select -expand name
    		}Catch{	
    			# Affichage des résultats des Contrôles
    			New-Object -TypeName PSObject -Property @{	Server = $server
    														LocalGroup = "Erreur"
    														MemberGroup = "Erreur"
    														Type = "Erreur"
    													} | Select Server,LocalGroup,MemberGroup,Type
    		}
    	}
    	else
    	{
    		$groups = $groupName
    	}
     
    	foreach ($group in $groups)
    	{
    		$gmembers = $null
    		$GMembers = ([ADSI]("WinNT://$server/$group,group")).psbase.invoke("Members")
    		if(!([string]::IsNullOrEmpty($gmembers))){
    			foreach ($gmember in $gmembers)
    			{
    				$name = $gmember.GetType().InvokeMember("Name",'GetProperty', $null, $gmember, $null)
    				$sid = $gmember.GetType().InvokeMember("objectsid",'GetProperty', $null, $gmember, $null)
    				$UserSid = New-Object System.Security.Principal.SecurityIdentifier($sid, 0)
    				$class = $gmember.GetType().InvokeMember("Class",'GetProperty', $null, $gmember, $null)
    				$ads = $gmember.GetType().InvokeMember("adspath",'GetProperty', $null, $gmember, $null)
    				$ConvertFromSID = ConvertFrom-SID -sid $UserSid  -ComputerName $server
    				$members = $ConvertFromSID.Name
     
    				# Affichage des résultats des Contrôles
    				New-Object -TypeName PSObject -Property @{	Server = $server
    															LocalGroup = $group
    															MemberGroup = $members
    															Type = $ConvertFromSID.ObjectType
    														} | Select Server,LocalGroup,MemberGroup,Type
    			}
    		}else{
    				# Affichage des résultats des Contrôles
    				New-Object -TypeName PSObject -Property @{	Server = $server
    															LocalGroup = $group
    															MemberGroup = $null
    															Type = $null
    														} | Select Server,LocalGroup,MemberGroup,Type		
    		}
    	}  
    }
    # Sous fonction de AccessRightByDirectories. Recherche les membres locaux/domaine de groupes locaux/domaine
    Function GetGroupsMembers{
    	Param(
    			[parameter(Mandatory=$true)][string]$GroupName,
    			[parameter(Mandatory=$true)][string]$ObjectType,
    			[parameter(Mandatory=$true)][string]$Serveur
    	)	
     
    	# Si le membre est un groupe du domaine, on recherche ses membres sur le domaine, sinon c'est un membre local, on recherche ses membres dans la base SAM du serveur local
    	If($ObjectType -eq "group domain"){
    		# Recherche les utilisateurs (recurssivement) d'un groupe de domaine
    		Return Get-QADGroupMember -Identity $GroupName -Type 'user' -Indirect -SizeLimit 0 | Select Sid,@{N='MemberGroup';e={$_.Name}},Type,DN
    	}
    	ElseIf($ObjectType -eq "group local"){
    		# Recherche les utilisateurs (recurssivement) d'un groupe local
    		GetLocalGroupMembers -Server $Serveur -GroupName $GroupName | Select MemberGroup,Type | ForEach-Object{
    			If($_.Type -like "group*"){
    				# Si le membre local est un groupe, on rappel la fonction afin de déterminer ses membres
    				GetGroupsMembers -GroupName $_.MemberGroup -ObjectType $_.Type -Serveur $Serveur
    			}else{
    				# Retourne les membres locaux
    				Return $_
    			}
    		}
    	}
    }
    # Recherche les membres et leurs ACL par répertoire
    Function AccessRightByDirectories{
    	Param(
    			[parameter(Mandatory=$true)][string]$NetworkPath,
    			[parameter(Mandatory=$true)][array]$GroupsAdmin,
    			[parameter(Mandatory=$true)][string]$Serveur,
    			[parameter(Mandatory=$true)][array]$AccessRightReadAndWrite,
    			[parameter(Mandatory=$true)][array]$AccessRighBrowseFolder,
    			[parameter(Mandatory=$true)][array]$AccessRighRead
    	)
    	# Recherche Les membres et ACL du répertoire
    	Get-AlphaleonisACL -Path $item.NetworkPath -Server $item.Serveur -IsInherited $false | WHERE {($_.Identity -notmatch ([regex]"(^DOMAIN\\Gd-FRA)([0-9]+)-SHARE-(.+?)-(R[OW])$")) -and ($_.Identity -notcontains $null ) -and ($GroupsAdmin –notcontains $_.Identity) -and ($_.Identity -notcontains $null )} | Select Path,Identity,DN,Sid,Rights,ObjectType,Propagation,AccessControlType | ForEach-Object{
    		# Conversion par famille de droits des utilisateurs suivant leurs accès				
    		If($AccessRightReadAndWrite | Where-Object {$_.Rights -match $_.Rights}){
    			$AccessRightFamilly = "3" # Read/Write
    		}
    		ElseIf(($AccessRighBrowseFolder | Where-Object {$_.Rights -match $_}) -and ($_.Propagation -like "None")){
    			$AccessRightFamilly = "1" # Browse
    		}
    		ElseIf($AccessRighRead | Where-Object {$_.Rights -match $_}){
    			$AccessRightFamilly = "2" # Read
    		}
    		Else{
    			$AccessRightFamilly= "0" # Special
    		}
    		# Si le membre est un groupe, on détermine ses utilisateurs
    		If($_.ObjectType -like "group*")
    		{
    			# Recherche les membres du groupe
    			$GetGroupsMembers = GetGroupsMembers -GroupName $_.Identity -ObjectType $_.ObjectType -Serveur $Serveur
    			ForEach($GetGroupsMember in $GetGroupsMembers)
    			{
    				# Affichage des résultats
    				New-Object -TypeName PSObject -Property @{	Path = $item.NetworkPath 
    															Sid = $GetGroupsMember.Sid
    															DN = $GetGroupsMember.DN
    															Users = $GetGroupsMember.MemberGroup
    															AccessRightFamilly = $AccessRightFamilly
    														} | Select Path,Sid,DN,Users,AccessRightFamilly
    			}
    		}
    		# Sinon on affiche l'utilisateur
    		Else
    		{
    			# Affichage des résultats
    			New-Object -TypeName PSObject -Property @{	Path = $item.NetworkPath 
    														Sid = $_.Sid
    														DN = $_.DN
    														Users = $_.Identity
    														AccessRightFamilly = $AccessRightFamilly
    													} | Select Path,Sid,DN,Users,AccessRightFamilly
    		}
    	}
    }
    # Dédoublonnement en gardant le droits d'accès le plus élévé
    Function DeduplicationItems{
    	Param(
    			[parameter(Mandatory=$false)][object]$Items # Certains groupes sont vides et sans membres
    	)
     
    	$UsersWithAccessRightUnduplicated = $Items | group users | % {
    		$current=$_.group    
    		if ($current.Count -gt 1)
    		{ 
    			$Current|Sort AccessRightFamilly -Descending|select -first 1 
    		}
    		else
    		{  
    			$Current
    		}
    	}
    	Return $UsersWithAccessRightUnduplicated	
    }
    # Remplace les noms et descriptions des groupes
    Function ReplaceNameAndDescriptionGroups{
    	Param(
    		[parameter(Mandatory=$true)][string]$AccessRightFamilly,
    		[parameter(Mandatory=$true)][string]$Groupe,
    		[parameter(Mandatory=$true)][string]$DescriptionGroupe
    	)
     
    	If($AccessRightFamilly -eq 3){
    		$Groupe = $Groupe.Replace("-XX","-RW")
    		$DescriptionGroupe = $DescriptionGroupe.Replace("- XX","- Read/Write")
    		$Permission = "Modify"
    	}ElseIf($AccessRightFamilly -eq 2){
    		$Groupe = $Groupe.Replace("-XX","-RO")
    		$DescriptionGroupe = $DescriptionGroupe.Replace("- XX","- Read")
    		$Permission = "Read"
    	}ElseIf($AccessRightFamilly -eq 1){
    		$Groupe = $Groupe.Replace("-XX","-BW")
    		$DescriptionGroupe = $DescriptionGroupe.Replace("- XX","- Browse")
    		$Permission = ""
    	}ElseIf($AccessRightFamilly -eq 0){
    		$Groupe = $Groupe.Replace("-XX","-SP") 
    		$DescriptionGroupe = $DescriptionGroupe.Replace("- XX","- Special")
    		$Permission = ""
    	}
    	# Affichage des résultats
    	New-Object -TypeName PSObject -Property @{	Groupe = $Groupe
    												DescriptionGroupe = $DescriptionGroupe
    												Permission = $Permission
    											} | Select Groupe,DescriptionGroupe,Permission
     
    }
    # Ajout des ACL sur un répertoire
    Function AddNTFSPermissions{
    	Param(
    		[parameter(Mandatory=$true)][string]$Path,
    		[parameter(Mandatory=$true)][string]$User,
    		[parameter(Mandatory=$true)][string]$Permission,
    		[parameter(Mandatory=$true)][string]$AccessControlType
    	)
     
        $FileSystemRights = [System.Security.AccessControl.FileSystemRights]$Permission
        $InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
        $PropagationFlag = [System.Security.AccessControl.PropagationFlags]"None"
        $AccessControlType = [System.Security.AccessControl.AccessControlType]$AccessControlType
        $Account = [System.Security.Principal.NTAccount]$User
        $FileSystemAccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($Account, $FileSystemRights, $InheritanceFlag, $PropagationFlag, $AccessControlType)
        $DirectorySecurity = Get-ACL $Path
    	$DirectorySecurity.SetAccessRuleProtection($false,$false) # Active l'héritage
    	#$DirectorySecurity.Access | %{$DirectorySecurity.RemoveAccessRule($_)} | Out-Null # Supprime tous les ACL existantes
    	$DirectorySecurity.AddAccessRule($FileSystemAccessRule) # Ajoute les droits utilisateur
        $DirectorySecurity	| Set-ACL $Path
    }
    # Création du groupe et vérification
    Function CreateGroup{
    	Param(
    		[parameter(Mandatory=$true)][string]$Groupe,
    		[parameter(Mandatory=$true)][string]$DescriptionGroupe,
    		[parameter(Mandatory=$true)][string]$PathLDAP
    	)
     
    	# Test si le groupe existe ($True) sinon on le créer ($False)
    	$Result_QADGroup = Get-QADGroup -identity $Groupe | Measure | Select Count
    	If($Result_QADGroup.Count -eq 1){ # $True
    		$CTRL_Add_Group = "OK"
    		$CTRL_Add_Group_Com = "Groupe déjà présent dans l'AD"
    	}Else{ # $False
    		# Ajout du groupe
    		New-qadGroup -name $Groupe -samAccountName $Groupe -Description $DescriptionGroupe -ParentContainer $PathLDAP -grouptype 'Security' -groupscope 'Global'
    		$CTRL_Add_Group_Com = $null
    		# Test si le groupe a bien ajouté 
    		$Result_QADGroup = Get-QADGroup -identity $Groupe | Measure | Select Count
    		If($Result_QADGroup.Count -eq 1){ # $True
    			$CTRL_Add_Group = "OK"
    		}Else{ # $False
    			$CTRL_Add_Group = "KO"
    		}
    	}
     
    	# Affichage des résultats
    	New-Object -TypeName PSObject -Property @{	CTRL_Add_Group = $CTRL_Add_Group
    												CTRL_Add_Group_Com = $CTRL_Add_Group_Com
    											} | Select CTRL_Add_Group,CTRL_Add_Group_Com
    }
    # Ajout groupe dans les sécurités NTFS du répertoire
    Function AddGroupInRightAccessFolder{
    	Param(
    		[parameter(Mandatory=$true)][string]$NetworkPath,
    		[parameter(Mandatory=$true)][string]$Serveur,
    		[parameter(Mandatory=$true)][string]$Groupe,
    		[parameter(Mandatory=$true)][string]$Permission
    	)
     
    	$Result_AlphaleonisACL = Get-AlphaleonisACL -Path $NetworkPath -Server $Serveur -IsInherited $false | WHERE {$_.Identity -like "*$Groupe*"} | Measure | Select Count
    	If($Result_AlphaleonisACL.Count -eq 1){ # $True
    		$CTRL_Add_Access_Right_On_Folder = "OK"
    		$CTRL_Add_Access_Right_On_Folder_Com = "ACL déjà enregistré sur le répertoire"
    	}Else{ # $False
    		# Ajout de l'ACL
    		AddNTFSPermissions -Path $NetworkPath -User $Groupe -Permission $Permission -AccessControlType "Allow"
    		$CTRL_Add_Access_Right_On_Folder_Com = $null
    		# Test si l'acl a bien ajouté 
    		$Result_AlphaleonisACL = Get-AlphaleonisACL -Path $NetworkPath -Server $Serveur -IsInherited $false | WHERE {$_.Identity -like "*$Groupe*"} | Measure | Select Count
    		If($Result_AlphaleonisACL.Count -eq 1){ # $True
    			$CTRL_Add_Access_Right_On_Folder = "OK"
    		}Else{ # $False
    			$CTRL_Add_Access_Right_On_Folder = "KO"
    		}
    	}
     
    	# Affichage des résultats
    	New-Object -TypeName PSObject -Property @{	CTRL_Add_Access_Right_On_Folder = $CTRL_Add_Access_Right_On_Folder
    												CTRL_Add_Access_Right_On_Folder_Com = $CTRL_Add_Access_Right_On_Folder_Com
    											} | Select CTRL_Add_Access_Right_On_Folder,CTRL_Add_Access_Right_On_Folder_Com
    }
    # Ajout de l'utilisateur dans un groupe et vérification
    Function AddUser{
    	Param(
    		[parameter(Mandatory=$true)][string]$Groupe,
    		[parameter(Mandatory=$true)][string]$DN
    	)
     
    	# Ajout du membre dans le groupe s'il n'est pas présent
    	$Result_QADGroupMember = Get-QADGroupMember -identity $Groupe | WHERE { $_.DN -eq $DN} | Measure | Select Count
    	If($Result_QADGroupMember.Count -eq 1){ # $True
    		$CTRL_Add_User_On_Group = "OK"
    		$CTRL_Add_User_On_Group_Com = "Utilisateur déjà présent dans le groupe"
    	}Else{ # $False
    		# Ajout du membre dans le groupe
    		Add-ADGroupMember -Identity $Groupe -Member $DN
    		$CTRL_Add_User_On_Group_Com = $null
    		# Test si l'utilisateur est bien ajouté dans le groupe ; utilise ADSI car plus rapide que Get-QADGroupMember
    		$Result_QADGroupMember = Get-QADGroupMember -identity $Groupe | WHERE { $_.DN -eq $DN} | Measure | Select Count
    		If($Result_QADGroupMember.Count -eq 1){ # $True
    			$CTRL_Add_User_On_Group = "OK"
    		}Else{ # $False
    			$CTRL_Add_User_On_Group = "KO"
    		}
    	}
     
    	# Affichage des résultats
    	New-Object -TypeName PSObject -Property @{	CTRL_Add_User_On_Group = $CTRL_Add_User_On_Group
    												CTRL_Add_User_On_Group_Com = $CTRL_Add_User_On_Group_Com
    											} | Select CTRL_Add_User_On_Group,CTRL_Add_User_On_Group_Com
    }
     
    ######################################
    #                MAIN                #
    ######################################
     
    # Limite de recherche : ilimité
    Set-QADPSSnapinSettings -DefaultSizeLimit 0 
     
    # Conversion du CSV en UTF8
    (Get-Content $CSVPath) | Set-Content $CSVPath -Encoding UTF8
     
    # Suppression des LOG
    If(Test-Path $PathLog)
    {
    	Remove-Item  $PathLog -Force
    }
     
    # Check si l'OU existe
    If ((CheckOU -PathLDAP $PathLDAP) -eq $True) 
    {
    	####
    	# Barre chargement
    	####
    	$i = 0	# Variable compteur pour le Write-Progress
    	Write-Progress -activity "Génération des groupes, ajout des utilisateurs et attribution des accès : " -status "Avancement : calcul en cours..."
     
    	# Parcours le fichier CSV
    	$Csv = Import-Csv -Path $CsvPath -Delimiter ";"
    	ForEach ($item In $Csv)
    	{
    		# Progression barre chargement
    		$i++
    		Write-Progress -activity "Génération des groupes, ajout des utilisateurs et attribution des accès : " -status "Avancement : $i sur $(($csv | measure).Count)" -percentComplete $($i* 100/($csv | measure).Count)
     
    		##########
    		# Recherche les utilisateurs/droits ayant des accès aux répertoires
    		##########
    		# Test si le répertoire existe
    		If(TestAccessFolder -Path $item.NetworkPath)
    		{
    			#Recherche les membres et leurs ACL par répertoire
    			$item.NetworkPath
    			DeduplicationItems -Items (AccessRightByDirectories -NetworkPath $item.NetworkPath -GroupsAdmin $GroupsAdmin -Serveur $item.Serveur -AccessRightReadAndWrite $AccessRightReadAndWrite -AccessRighBrowseFolder $AccessRighBrowseFolder -AccessRighRead $AccessRighRead) | ForEach-Object{
    				# On ne traite pas les comptes locaux car pas possible de les ajouter dans un groupe de domaine AD
    				If(-not ($_.DN -like "Compte local")){
    					# Création du nom et description du groupe suivant le type de droits
    					$ResultReplaceNameAndDescriptionGroups = ReplaceNameAndDescriptionGroups -AccessRightFamilly $_.AccessRightFamilly -Groupe $item.Groupe -DescriptionGroupe  $item.DescriptionGroupe
    					# Création du groupe et vérification
    					$ResultCreateGroup = CreateGroup -Groupe $ResultReplaceNameAndDescriptionGroups.Groupe -DescriptionGroupe $ResultReplaceNameAndDescriptionGroups.DescriptionGroupe -PathLDAP $PathLDAP
    					# Ajout groupe dans les sécurités NTFS du répertoire
    					$ResultAddGroupInRightAccessFolder = AddGroupInRightAccessFolder -NetworkPath $item.NetworkPath -Serveur $item.Serveur -Groupe $ResultReplaceNameAndDescriptionGroups.Groupe -Permission $ResultReplaceNameAndDescriptionGroups.Permission
    					# Ajout de l'utilisateur dans un groupe et vérification
    					$ResultAddUser = AddUser -Groupe $ResultReplaceNameAndDescriptionGroups.Groupe -DN $_.DN
     
    					Write-Host "User : "$_.Users
    					Write-Host "Groupes : "$ResultReplaceNameAndDescriptionGroups.Groupe
    					Write-Host "CTRL_Add_Group : "$ResultCreateGroup.CTRL_Add_Group
    					Write-Host "CTRL_Add_Group_Com : "$ResultCreateGroup.CTRL_Add_Group_Com
    					Write-Host "CTRL_Add_Access_Right_On_Folder : "$ResultAddGroupInRightAccessFolder.CTRL_Add_Access_Right_On_Folder
    					Write-Host "CTRL_Add_Access_Right_On_Folder_Com : "$ResultAddGroupInRightAccessFolder.CTRL_Add_Access_Right_On_Folder_Com
    					Write-Host "CTRL_Add_User_On_Group : "$ResultAddUser.CTRL_Add_User_On_Group
    					Write-Host "CTRL_Add_User_On_Group_Com : "$ResultAddUser.CTRL_Add_User_On_Group_Com
    					Write-Host
     
    				} # Fin If pas de comptes locaux
    			} # Fin DeduplicationItems
    		}# Fin test si le répertoire existe
    	}# Fin Foreach csv	
     
    	####
    	# Fin barre chargement
    	####
    	Write-Progress -activity "Génération des groupes, ajout des utilisateurs et attribution des accès : " -status "FINI !"
    	sleep 5
    	Write-Progress -activity "Génération des groupes, ajout des utilisateurs et attribution des accès : " -completed
    }# Fin Check si l'OU existe

    Je verrai demain matin si mon jeu de test est passer sans erreur, car l'exécution est assez longue.

    Cependant, je remarque que la cmdlet "Get-QADGroupMember" bouffe énormément de mémoire et surtout ne la vide pas une fois la commande utilisé.

  13. #13
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    Echec ! J'ai mis à genou ma VM avec ses 8 go de RAM ! Les commandes PowerQuest doivent avoir un problème car après exécution, elles ne libèrent pas la mémoire et à chaque exécution, je cumule les consommations de mémoire RAM. La consommation monte en flèche !

    J'ai modifié mes fonctions qui utilisent des commandes PowerQuest avec des commandes à base de ADSI. Cela semble plus stable et surtout plus rapide d'exécution, mais je ne peux pas le certifier à 100% avant la fin de l'exécution de mon script.

    Petite question, comment faire la recherche de membre d'un groupe AD récursivement avec de ADSI ?

    J'utilise ceci pour avoir la liste des membre d'un groupe, mais c'est pas récursive :

    Code powershell : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    # Chemin LDAP du groupe et de l'utilisateur
    $LDAPGroup =[ADSI]"LDAP://CN=$Groupe,$PathLDAP"
    $LDAPUser = [ADSI]"LDAP://$DN"
     
    $LDAPGroup.IsMember($LDAPUser.ADsPath)

  14. #14
    Membre expert
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Juillet 2004
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Juillet 2004
    Messages : 2 725
    Points : 3 338
    Points
    3 338
    Par défaut
    Pourquoi utilises tu des cmdlets tierces ?
    Tu ne trouve pas ce dont tu as besoin avec celle de MS ?
    Par pitié !!!! :Si vous ne savez pas faire cliquez ici !
    Citation Envoyé par Marc-L
    C'est dommage que parfois tu sois aussi lourd que tu as l'air intelligent…

  15. #15
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    J'utilise souvent les cmdlet de powerquest car je les trouve plus puissante que ceux de base. Mais sur ce coup là, avec mon problème de mémoire, je ne vais pas les utiliser.

  16. #16
    Membre expert
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Juillet 2004
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Juillet 2004
    Messages : 2 725
    Points : 3 338
    Points
    3 338
    Par défaut
    Je réalise pas mal de scripts PS (AD, Exchange, WSUS...) et je n'ai jamais eu besoin de cmdlets tierces genre Powersquest ou autre.
    En plus hors de question pour moi d'installer ce genre de choses sur un serveur......

    Je réalise des fonctions complémentaires moi même selon mes besoins certes mais ce genre de truc (surtout maintenant que je voit ton topic et les fuites mémoires que ça engendre !) j'évite
    Par pitié !!!! :Si vous ne savez pas faire cliquez ici !
    Citation Envoyé par Marc-L
    C'est dommage que parfois tu sois aussi lourd que tu as l'air intelligent…

  17. #17
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    pourtant ils ont de bonnes commandes, mais sur ce coup là, je vais m'en passer.

    Je test la commande Get-ADGroupMember et elle est moins consommatrice de RAM. Rien à voir !

    Pour les ADSI, les requêtes sont plus rapide que les commandes MS et vu le nombre de donnée que je traite, je gagne du temps d'exécution.

  18. #18
    Membre expert
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Juillet 2004
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Juillet 2004
    Messages : 2 725
    Points : 3 338
    Points
    3 338
    Par défaut
    +1 pour ADSI et ADSI => MS


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $Group = [ADSI]"LDAP://CN=Administrateurs,CN=Builtin,DC=xxxxxx,DC=local"
    $Members = $Group.Member | %{[ADSI]"LDAP://$($_)"}
    Par pitié !!!! :Si vous ne savez pas faire cliquez ici !
    Citation Envoyé par Marc-L
    C'est dommage que parfois tu sois aussi lourd que tu as l'air intelligent…

  19. #19
    Membre actif
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Décembre 2006
    Messages
    1 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 080
    Points : 287
    Points
    287
    Par défaut
    merci pour le code. Cependant, je ne peux pas l'utilisé car je viens de voir que je n'ai pas le DN dans mon fichier de réponse et donc que je peux renseigné l'argument. Je pourrais utilisé une fonction intermédiaire pour le récupérer, mais autant utilisé Get-ADGroupMember directement.

    D'ailleurs avec Get-ADGroupMember, comment faire pour ne pas avoir les avertissements lorsque la commande ne trouve pas l'objet ? J'ai essayé avec un try catch, mais pas terrible.

    Avez vous des idées ?

  20. #20
    Membre expert
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Juillet 2004
    Messages
    2 725
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Juillet 2004
    Messages : 2 725
    Points : 3 338
    Points
    3 338
    Par défaut
    Avec :
    Un point c'est tout, il n'y a rien d'autre...
    C'est prévu pour ça !
    Et je ne vois pas en quoi c'est pas terrible....... Puisque ça à été inventé pour traité ça entre autre.
    Par pitié !!!! :Si vous ne savez pas faire cliquez ici !
    Citation Envoyé par Marc-L
    C'est dommage que parfois tu sois aussi lourd que tu as l'air intelligent…

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 3 123 DernièreDernière

Discussions similaires

  1. Réponses: 3
    Dernier message: 13/06/2008, 09h54
  2. problème de mémoire saturée
    Par paradeofphp dans le forum ASP.NET
    Réponses: 9
    Dernier message: 03/09/2007, 16h45
  3. Réponses: 1
    Dernier message: 16/01/2007, 10h21
  4. Réponses: 2
    Dernier message: 11/10/2006, 10h36
  5. [VB.net]system.outofmemoryexception
    Par grand_prophete dans le forum Windows Forms
    Réponses: 31
    Dernier message: 21/04/2006, 16h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo