Added sample CSV files for user/sites importation.
All checks were successful
Release zip package / release (push) Successful in 1s
All checks were successful
Release zip package / release (push) Successful in 1s
Fixed a few bugs.
This commit is contained in:
@@ -5229,30 +5229,41 @@ $btnBulkCsv.Add_Click({
|
|||||||
$ofd = New-Object System.Windows.Forms.OpenFileDialog
|
$ofd = New-Object System.Windows.Forms.OpenFileDialog
|
||||||
$ofd.Filter = "CSV (*.csv)|*.csv|All (*.*)|*.*"
|
$ofd.Filter = "CSV (*.csv)|*.csv|All (*.*)|*.*"
|
||||||
if ($ofd.ShowDialog($form) -ne "OK") { return }
|
if ($ofd.ShowDialog($form) -ne "OK") { return }
|
||||||
|
# Try semicolon first (handles commas inside fields), fall back to comma
|
||||||
|
$content = Get-Content $ofd.FileName -Raw
|
||||||
|
if ($content -match ';') {
|
||||||
|
$rows = Import-Csv $ofd.FileName -Delimiter ';'
|
||||||
|
} else {
|
||||||
$rows = Import-Csv $ofd.FileName
|
$rows = Import-Csv $ofd.FileName
|
||||||
|
}
|
||||||
$count = 0
|
$count = 0
|
||||||
foreach ($r in $rows) {
|
foreach ($r in $rows) {
|
||||||
# Accepted column names (case-insensitive via PSObject)
|
# Read columns via PSObject properties (case-insensitive)
|
||||||
$name = if ($r.Name) { $r.Name } elseif ($r.name) { $r.name }
|
$props = @{}
|
||||||
elseif ($r.Title) { $r.Title } elseif ($r.title) { $r.title } else { "" }
|
foreach ($p in $r.PSObject.Properties) { $props[$p.Name.ToLower()] = "$($p.Value)".Trim() }
|
||||||
$alias = if ($r.Alias) { $r.Alias } elseif ($r.alias) { $r.alias }
|
|
||||||
elseif ($r.URL) { $r.URL } elseif ($r.url) { $r.url } else { "" }
|
|
||||||
$type = if ($r.Type) { $r.Type } elseif ($r.type) { $r.type } else { "Team" }
|
|
||||||
$tpl = if ($r.Template) { $r.Template } elseif ($r.template) { $r.template } else { "" }
|
|
||||||
$own = if ($r.Owners) { $r.Owners } elseif ($r.owners) { $r.owners }
|
|
||||||
elseif ($r.Owner) { $r.Owner } elseif ($r.owner) { $r.owner } else { "" }
|
|
||||||
$mem = if ($r.Members) { $r.Members } elseif ($r.members) { $r.members } else { "" }
|
|
||||||
|
|
||||||
if (-not $name -or -not $alias) { continue }
|
$name = if ($props['name']) { $props['name'] } elseif ($props['title']) { $props['title'] } else { "" }
|
||||||
|
$alias = if ($props['alias']) { $props['alias'] } elseif ($props['url']) { $props['url'] } else { "" }
|
||||||
|
$type = if ($props['type']) { $props['type'] } else { "Team" }
|
||||||
|
$tpl = if ($props['template']) { $props['template'] } else { "" }
|
||||||
|
$own = if ($props['owners']) { $props['owners'] } elseif ($props['owner']) { $props['owner'] } else { "" }
|
||||||
|
$mem = if ($props['members']) { $props['members'] } else { "" }
|
||||||
|
|
||||||
|
# Name is required; skip empty rows
|
||||||
|
if (-not $name) { continue }
|
||||||
|
# Auto-generate alias from name if not provided
|
||||||
|
if (-not $alias) {
|
||||||
|
$alias = $name.ToLower() -replace '[^a-z0-9\-]', '-' -replace '-+', '-' -replace '^-|-$', ''
|
||||||
|
}
|
||||||
# Normalize type
|
# Normalize type
|
||||||
if ($type -match '^[Cc]omm') { $type = "Communication" } else { $type = "Team" }
|
if ($type -match '^[Cc]omm') { $type = "Communication" } else { $type = "Team" }
|
||||||
Add-BulkListItem @{
|
Add-BulkListItem @{
|
||||||
Name = $name.Trim()
|
Name = $name
|
||||||
Alias = $alias.Trim()
|
Alias = $alias
|
||||||
Type = $type
|
Type = $type
|
||||||
Template = $tpl.Trim()
|
Template = $tpl
|
||||||
Owners = $own.Trim()
|
Owners = $own
|
||||||
Members = $mem.Trim()
|
Members = $mem
|
||||||
}
|
}
|
||||||
$count++
|
$count++
|
||||||
}
|
}
|
||||||
@@ -5340,32 +5351,83 @@ $btnBulkCreate.Add_Click({
|
|||||||
$name = $entry.Name
|
$name = $entry.Name
|
||||||
$alias = $entry.Alias
|
$alias = $entry.Alias
|
||||||
$isTeam = $entry.Type -ne "Communication"
|
$isTeam = $entry.Type -ne "Communication"
|
||||||
$owners = @($entry.Owners -split '[,;]' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
|
$ownerRaw = "$($entry.Owners)"
|
||||||
$members = @($entry.Members -split '[,;]' | ForEach-Object { $_.Trim() } | Where-Object { $_ })
|
$memberRaw = "$($entry.Members)"
|
||||||
|
$owners = [string[]]@($ownerRaw -split '[,;\s]+' | Where-Object { $_ -match '\S' })
|
||||||
|
$members = [string[]]@($memberRaw -split '[,;\s]+' | Where-Object { $_ -match '\S' })
|
||||||
$tplName = $entry.Template
|
$tplName = $entry.Template
|
||||||
|
|
||||||
BgLog "[$idx/$total] Creating '$name' (alias: $alias, type: $($entry.Type))..." "White"
|
BgLog "[$idx/$total] Creating '$name' (alias: $alias, type: $($entry.Type))..." "White"
|
||||||
|
BgLog " DEBUG owners raw='$ownerRaw' parsed=[$($owners -join '|')] count=$($owners.Count)" "Gray"
|
||||||
|
BgLog " DEBUG members raw='$memberRaw' parsed=[$($members -join '|')] count=$($members.Count)" "Gray"
|
||||||
|
|
||||||
|
# TeamSite requires at least one owner
|
||||||
|
if ($isTeam -and $owners.Count -eq 0) {
|
||||||
|
BgLog " ERREUR : TeamSite requires at least one owner — skipping '$name'" "Red"
|
||||||
|
$Sync.Queue.Enqueue(@{ Text = "##STATUS##"; Index = ($idx - 1); Value = "Error: no owner" })
|
||||||
|
$Sync.ErrCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
# Update status
|
# Update status
|
||||||
$Sync.Queue.Enqueue(@{ Text = "##STATUS##"; Index = ($idx - 1); Value = "Creating..." })
|
$Sync.Queue.Enqueue(@{ Text = "##STATUS##"; Index = ($idx - 1); Value = "Creating..." })
|
||||||
|
|
||||||
try {
|
try {
|
||||||
# Create the site
|
# Create the site WITHOUT owners/members (PnP bug: odata.bind empty array)
|
||||||
|
# Current user becomes default owner; we add owners/members after creation
|
||||||
Connect-PnPOnline -Url $adminUrl -Interactive -ClientId $Params.ClientId
|
Connect-PnPOnline -Url $adminUrl -Interactive -ClientId $Params.ClientId
|
||||||
$newUrl = if ($isTeam) {
|
if ($isTeam) {
|
||||||
if ($owners.Count -gt 0) {
|
BgLog " Creating TeamSite '$alias' (owners/members added after)..." "DarkGray"
|
||||||
New-PnPSite -Type TeamSite -Title $name -Alias $alias -Owners $owners -Wait
|
$newUrl = New-PnPSite -Type TeamSite -Title $name -Alias $alias -Wait
|
||||||
} else {
|
} else {
|
||||||
New-PnPSite -Type TeamSite -Title $name -Alias $alias -Wait
|
BgLog " Creating CommunicationSite '$alias'..." "DarkGray"
|
||||||
}
|
$newUrl = New-PnPSite -Type CommunicationSite -Title $name -Url "$base/sites/$alias" -Wait
|
||||||
} else {
|
|
||||||
New-PnPSite -Type CommunicationSite -Title $name -Url "$base/sites/$alias" -Wait
|
|
||||||
}
|
}
|
||||||
BgLog " Site cree : $newUrl" "LightGreen"
|
BgLog " Site cree : $newUrl" "LightGreen"
|
||||||
|
|
||||||
# Connect to the new site for template + members
|
# Connect to the new site for owners/members/template
|
||||||
Connect-PnPOnline -Url $newUrl -Interactive -ClientId $Params.ClientId
|
Connect-PnPOnline -Url $newUrl -Interactive -ClientId $Params.ClientId
|
||||||
|
|
||||||
|
# Assign owners & members post-creation
|
||||||
|
if ($isTeam) {
|
||||||
|
$groupId = $null
|
||||||
|
try { $groupId = (Get-PnPSite -Includes GroupId).GroupId.Guid } catch {}
|
||||||
|
if ($groupId) {
|
||||||
|
foreach ($o in $owners) {
|
||||||
|
try {
|
||||||
|
Add-PnPMicrosoft365GroupOwner -Identity $groupId -Users $o -ErrorAction Stop
|
||||||
|
BgLog " Owner added: $o" "Cyan"
|
||||||
|
} catch { BgLog " Warn owner '$o': $($_.Exception.Message)" "DarkYellow" }
|
||||||
|
}
|
||||||
|
foreach ($m in $members) {
|
||||||
|
try {
|
||||||
|
Add-PnPMicrosoft365GroupMember -Identity $groupId -Users $m -ErrorAction Stop
|
||||||
|
BgLog " Member added: $m" "Cyan"
|
||||||
|
} catch { BgLog " Warn member '$m': $($_.Exception.Message)" "DarkYellow" }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BgLog " Could not get M365 GroupId — owners/members not assigned" "DarkYellow"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# CommunicationSite — classic SharePoint groups
|
||||||
|
if ($owners.Count -gt 0) {
|
||||||
|
$ownerGrp = Get-PnPGroup | Where-Object { $_.Title -like "*Propri*" -or $_.Title -like "*Owner*" } | Select-Object -First 1
|
||||||
|
if ($ownerGrp) {
|
||||||
|
foreach ($o in $owners) {
|
||||||
|
try { Add-PnPGroupMember -LoginName $o -Group $ownerGrp.Title -ErrorAction SilentlyContinue } catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($members.Count -gt 0) {
|
||||||
|
$memberGrp = Get-PnPGroup | Where-Object { $_.Title -like "*Membre*" -or $_.Title -like "*Member*" } | Select-Object -First 1
|
||||||
|
if ($memberGrp) {
|
||||||
|
foreach ($m in $members) {
|
||||||
|
try { Add-PnPGroupMember -LoginName $m -Group $memberGrp.Title -ErrorAction SilentlyContinue } catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Apply template if specified
|
# Apply template if specified
|
||||||
if ($tplName -and $Params.Templates.ContainsKey($tplName)) {
|
if ($tplName -and $Params.Templates.ContainsKey($tplName)) {
|
||||||
$tpl = $Params.Templates[$tplName]
|
$tpl = $Params.Templates[$tplName]
|
||||||
@@ -5406,30 +5468,7 @@ $btnBulkCreate.Add_Click({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add members
|
|
||||||
if ($members.Count -gt 0) {
|
|
||||||
$memberGroup = Get-PnPGroup | Where-Object { $_.Title -like "*Membres*" -or $_.Title -like "*Members*" } | Select-Object -First 1
|
|
||||||
if ($memberGroup) {
|
|
||||||
foreach ($m in $members) {
|
|
||||||
try {
|
|
||||||
Add-PnPGroupMember -LoginName $m -Group $memberGroup.Title -ErrorAction SilentlyContinue
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
BgLog " $($members.Count) member(s) added." "Cyan"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add owners for Communication sites (TeamSite owners set at creation)
|
|
||||||
if (-not $isTeam -and $owners.Count -gt 0) {
|
|
||||||
$ownerGroup = Get-PnPGroup | Where-Object { $_.Title -like "*Propri*" -or $_.Title -like "*Owner*" } | Select-Object -First 1
|
|
||||||
if ($ownerGroup) {
|
|
||||||
foreach ($o in $owners) {
|
|
||||||
try {
|
|
||||||
Add-PnPGroupMember -LoginName $o -Group $ownerGroup.Title -ErrorAction SilentlyContinue
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$Sync.Queue.Enqueue(@{ Text = "##STATUS##"; Index = ($idx - 1); Value = "OK" })
|
$Sync.Queue.Enqueue(@{ Text = "##STATUS##"; Index = ($idx - 1); Value = "OK" })
|
||||||
$Sync.CreatedSites.Add([PSCustomObject]@{
|
$Sync.CreatedSites.Add([PSCustomObject]@{
|
||||||
|
|||||||
8
examples/bulk_add_members.csv
Normal file
8
examples/bulk_add_members.csv
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Email
|
||||||
|
user1@contoso.com
|
||||||
|
user2@contoso.com
|
||||||
|
user3@contoso.com
|
||||||
|
manager1@contoso.com
|
||||||
|
designer@contoso.com
|
||||||
|
analyste@contoso.com
|
||||||
|
stagiaire@contoso.com
|
||||||
|
6
examples/bulk_create_sites.csv
Normal file
6
examples/bulk_create_sites.csv
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Name;Alias;Type;Template;Owners;Members
|
||||||
|
Projet Alpha;projet-alpha;Team;;admin@contoso.com;user1@contoso.com, user2@contoso.com
|
||||||
|
Projet Beta;;Team;;admin@contoso.com;user3@contoso.com, user4@contoso.com
|
||||||
|
Communication RH;;Communication;;rh-admin@contoso.com;manager1@contoso.com, manager2@contoso.com
|
||||||
|
Equipe Marketing;equipe-marketing;Team;;marketing-lead@contoso.com;designer@contoso.com, redacteur@contoso.com
|
||||||
|
Portail Intranet;;Communication;;it-admin@contoso.com;
|
||||||
|
Reference in New Issue
Block a user