Question Doublons générés lors du traitement import AD

Plus d'informations
il y a 2 ans 8 mois #31074 par witness
Merci
sympa

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 2 ans 8 mois - il y a 2 ans 8 mois #31075 par Laurent Dardenne
Un premier jet, autant battre le fer tant qu'il est chaud :
$Pattern='^(?<Nom>.*?)(?<Nombre>\d*)$'
'AccountName255' -match $Pattern

[int]$Indice=$Matches.Nombre

$Delegate={
param( $Match)
$Indice++
return "$($match.Groups['Nom'].Value)$Indice"
}

[Regex]::Replace('AccountName255', $Pattern, $Delegate)
#AccountName256
Reste peut être un pb de portée pour $Indice...

Tutoriels PowerShell
Dernière édition: il y a 2 ans 8 mois par Laurent Dardenne. Raison: correction résultat

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 2 ans 8 mois - il y a 2 ans 8 mois #31078 par Laurent Dardenne
Une ébauche :
#Account.ps1
Param()
#Décompose un nom de compte AD
$Pattern='^(?<Nom>.*?)(?<Nombre>\d*)$'

#Simule le résultat d'une requête AD
Function Get-AccountName{ @('AccountName100','AccountName1','AccountName21')}

Function New-AccountName{
#Récupère un nom de compte normé du pipeline
#renvoi un objet personnalisé, sa propriété 'Nombre' (de type entier) permettra le tri
param(
[Parameter(ValueFromPipeline)]
[string] $AccountName,

[string] $Pattern
)
process {
if ($AccountName -match $Pattern)
{ [PSCustomObject]@{Nom=$Matches.Nom;Nombre=[int]$Matches.Nombre;Origine=$AccountName} }
else
{ throw "Le nom de compte '$AccountName' n'est pas normé." }
}
}
#Récupère le nom de compte ayant le numéro le plus élevé
$LastAccount=Get-AccountName|New-AccountName -Pattern $Pattern|Sort-Object -Property Nombre -Desc|Select-Object -First 1
Write-Debug "LastAccount='$LastAccount'"

$LastAccountName=$LastAccount.Nom
Write-Debug "LastAccountName='$LastAccountName'"

#Initialise la variable, permet de la récupérer en fin de création de compte
[int]$script:Compteur=-1

$Delegate={
param( $Match)
#Write-Debug "Before $script:Compteur"

#La portée script permet d'adresser la variable déclarée dans l'appelant
If ($script:Compteur -eq -1)
{$script:Compteur=1+$Match.Groups['Nombre'].Value}
Else
{ $Script:Compteur++ }
#Write-Debug "After $script:Compteur"
Return "$($Match.Groups['Nom'].Value)$script:Compteur"
}

#Lors du premier appel on doit connaitre le nombre de duplication de compte afin d'initialiser le compteur.
#On passe en premier paramètre de Replace() le nom de compte ayant le nombre le plus élévé.
[Regex]::Replace($LastAccount.Origine, $Pattern, $Delegate)
Write-host "Premier appel Compteur=$script:Compteur" -ForegroundColor Green

#Le nom de compte passé dans les appels suivants peut être sans numéro, car le compteur existe avec la valeur attendue
[Regex]::Replace('AccountName', $Pattern, $Delegate)
Write-host "Second appel Compteur=$script:Compteur" -ForegroundColor Green

[Regex]::Replace('AccountName', $Pattern, $Delegate)
Write-host "Troisième appel Compteur=$script:Compteur" -ForegroundColor Green
]

Par contre si on utilise ce jeu de test :
Function Get-AccountName{ @('Riri100','Riri1','Riri21','Fifi1','Fifi2','Loulou')}
Les noms de compte qui ne sont pas dupliqués ne matche pas la regex et la variable $compteur devrait être une hashtable (cache des occurences dupliquées).
Il peut y avoir d'autres solutions/approches.

Tutoriels PowerShell
Dernière édition: il y a 2 ans 8 mois par Laurent Dardenne. Raison: coquille

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 2 ans 8 mois #31079 par witness
Merci Laurent,
Je vais regarder tout ça.

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 2 ans 8 mois #31081 par Laurent Dardenne
Une version basée sur l'usage d'un cache simple :
Param()
#Décompose un nom de compte AD
$script:Pattern='^(?<Nom>.*?)(?<Nombre>\d*)$'

Function Update-Cache{
    param(
        [Parameter(Mandatory=$True,position=0)]
    [string] $Nom,
        [Parameter(Mandatory=$True,position=1)]
    [int] $Compteur
 )

 if (-not $script:Cache.ContainsKey($Nom))
 {
    Write-Debug "Cache: Ajoute '$Nom' '$Compteur'"
    $Script:Cache.Add($Nom,$Compteur)
 }
 else
 {
    if($Compteur -gt $Script:Cache.$Nom)
    {
       Write-Debug "Cache: MAJ du compteur '$($Script:Cache.$Nom)' --> '$Compteur'"
       $Script:Cache.$Nom=$Compteur
    }
 }
}

$Script:Cache=@{}
#Simule le résultat d'une requête AD
#todo Function Get-AccountName{ @('','1','22','A','a1','Riri100','Riri1','Riri21','Fifi1','Fifi2','Loulou')}
Function Get-AccountName{ @('Riri100','Riri1','Riri21','Fifi1','Fifi2','Loulou')}

#Liste des nouveaux comptes a ajouter
Function Get-NewName{ @('Riri','Fifi','Loulou','Donald')}
Function Split-AccountName{
    #Récupère un nom de compte normé du pipeline
    #renvoi un objet personnalisé, sa propriété 'Nombre' (de type entier) permettra le tri
  param(
       [Parameter(ValueFromPipeline)]
      [string] $AccountName
    )
 process {
   if ($AccountName -match $script:Pattern)
   {
      if ($Matches.Nombre -ne [string]::Empty)
      { [PSCustomObject]@{Nom=$Matches.Nom;Nombre=[int]$Matches.Nombre;Origine=$AccountName} }
      else
      {
         #Le premier nom de compte inexistant dans l'AD n'est pas postfixé par un nombre
        [PSCustomObject]@{Nom=$Matches.Nom;Nombre=0;Origine=$AccountName}
      }
   }
   else
   { Write-Error "Le nom de compte '$AccountName' n'est pas normé." }
 }
}
#Récupère les noms de compte ayant le numéro le plus élevé en renseignant le cache
#todo regrouper par nom : Get-AccountName|Split-AccountName|Group-Object -Property Nom -AsHashTable -AsString
Get-AccountName|
 Split-AccountName|
 Foreach-Object {
    Write-host "Traite '$_'" -ForegroundColor Green
    Update-Cache $_.Nom $_.Nombre
 }
$Cache # todo remove line

#voir : https://docs.microsoft.com/fr-fr/dotnet/api/system.text.regularexpressions.matchevaluator?view=netframework-4.5
$Delegate={
 param( $Match)
    $Nom=$Match.Groups['Nom'].Value
    [int]$Compteur=$Match.Groups['Nombre'].Value

    Update-Cache $Nom $Compteur
    $Compteur=$script:Cache.$Nom
    Write-Debug "Delegate: Before $Compteur"
    $script:Cache.$Nom=++$Compteur
    Write-Debug "Delegate: After $Compteur"
    Return "$($Match.Groups['Nom'].Value)$Compteur"
}

Get-NewName|
 ForEach-Object {
    Write-host "Recherche de doublon pour le compte '$_'" -ForegroundColor White
    $NewAccountName=[Regex]::Replace($_, $script:Pattern, $Delegate)
    Write-host "Nouveau nom dupliqué '$NewAccountName'" -ForegroundColor Green
}
$Cache
Reste le cas d'un nouveau nom de compte inexistant en base, ici le code l'incrémente.
Je te laisse créer des jeux de test et gérer les possibles cas d'erreur.
Comme je ne connais pas ton infra ni ta norme de nommage AD il y a surement des choses à adapter.
Et si qq à une autre solution on la lira avec plaisir :-)

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 2 ans 8 mois #31090 par witness
Merci, mais je ne m'attendais pas à un bloc de code aussi important 

Connexion ou Créer un compte pour participer à la conversation.

Temps de génération de la page : 0.098 secondes
Propulsé par Kunena