microsoft-365/AddSharepointPerms.ps1
|
# & ([scriptblock]::Create((irm -Uri "https://raw.githubusercontent.com/J-Ranck-Electric/powershell-scripts/main/AddSharepointPerms.ps1" -Headers @{ Authorization = "token $token" }))) -LibraryName "Jobs" -RootFolder "SSM" -TargetFolderName "Contract Documents" -MaxDepth 2 -Recipients "owitbeck@jranck.com" -Roles "write" -WhatIf [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$LibraryName, [Parameter(Mandatory = $false)] [string]$RootFolder = "", [Parameter(Mandatory = $true)] [string]$TargetFolderName, [Parameter(Mandatory = $false)] [int]$MaxDepth = [int]::MaxValue, [Parameter(Mandatory = $true)] [string[]]$Recipients, [Parameter(Mandatory = $true)] [ValidateSet("read", "write", "owner")] [string[]]$Roles, [Parameter(Mandatory = $false)] [switch]$WhatIf ) # Function to ensure required modules are installed function Test-AndInstallModule { param ( [Parameter(Mandatory = $true)] [string]$ModuleName ) if (-not (Get-Module -Name $ModuleName -ListAvailable)) { Write-Host "Module $ModuleName is not installed. Installing now..." -ForegroundColor Yellow try { Install-Module -Name $ModuleName -Scope CurrentUser -Force -AllowClobber -ErrorAction Stop Write-Host "Module $ModuleName installed successfully." -ForegroundColor Green } catch { Write-Error "Failed to install module $ModuleName. Error: $_" exit 1 } } # Import the module try { Import-Module -Name $ModuleName -ErrorAction Stop } catch { Write-Error "Failed to import module $ModuleName. Error: $_" exit 1 } } # Install and import required modules $requiredModules = @("Microsoft.Graph.Sites", "Microsoft.Graph.Authentication") foreach ($module in $requiredModules) { Test-AndInstallModule -ModuleName $module } # Connect to Microsoft Graph Connect-MgGraph -Scopes "Sites.Read.All, Files.ReadWrite.All" -NoWelcome # Format recipients for sharing parameters $recipientsArray = @() foreach ($recipient in $Recipients) { $recipientsArray += @{ email = $recipient } } # Prepare sharing parameters $sharingParams = @{ requireSignIn = $true recipients = $recipientsArray roles = $Roles } # Get site ID using Invoke-MgGraphRequest $siteUrl = "https://graph.microsoft.com/v1.0/sites/jranck.sharepoint.com:/sites/I-Drive" $siteResponse = Invoke-MgGraphRequest -Uri $siteUrl -Method GET $siteId = $siteResponse.id # Get all drives (document libraries) in the site using Invoke-MgGraphRequest $drivesUrl = "https://graph.microsoft.com/v1.0/sites/$siteId/drives" $drivesResponse = Invoke-MgGraphRequest -Uri $drivesUrl -Method GET $drives = $drivesResponse.value # Find the specific library you want to work with $drive = $drives | Where-Object Name -eq $LibraryName if ($null -eq $drive) { Write-Host "Library '$LibraryName' not found. Available libraries:" -ForegroundColor Red $drives | Select-Object Name, Id | Format-Table exit } $driveId = $drive.id # Initialize array to store found folders $script:foundFolders = @() # Function to get folder by path using Invoke-MgGraphRequest function Get-FolderByPath { param( [string]$FolderPath ) try { $encodedPath = [System.Web.HttpUtility]::UrlEncode($FolderPath) $folderUrl = "https://graph.microsoft.com/v1.0/drives/$driveId/root:/$encodedPath" $folderResponse = Invoke-MgGraphRequest -Uri $folderUrl -Method GET return $folderResponse } catch { Write-Host "Error getting folder at path $FolderPath : $_" -ForegroundColor Red return $null } } # Function to search folders at specific depth level function Search-FoldersAtLevel { param( [Parameter(Mandatory = $true)] [string]$FolderId, [Parameter(Mandatory = $true)] [string]$FolderPath, [Parameter(Mandatory = $true)] [int]$TargetDepth, [Parameter(Mandatory = $true)] [int]$CurrentDepth ) # If we've reached target depth, check for target folders if ($CurrentDepth -eq $TargetDepth) { Write-Host "Searching at depth ${CurrentDepth}: $FolderPath" -ForegroundColor Cyan # Get all folders at this level $foldersUrl = "https://graph.microsoft.com/v1.0/drives/$driveId/items/$FolderId/children?`$filter=folder ne null" $foldersResponse = Invoke-MgGraphRequest -Uri $foldersUrl -Method GET $folders = $foldersResponse.value # Check for target folders foreach ($folder in $folders) { if ($folder.name -eq $TargetFolderName) { $currentPath = "$FolderPath/$($folder.name)" Write-Host "Found target folder: $currentPath" -ForegroundColor Green $script:foundFolders += [PSCustomObject]@{ Name = $folder.name Path = $currentPath ItemId = $folder.id CreatedDate = $folder.createdDateTime LastModified = $folder.lastModifiedDateTime Depth = $CurrentDepth } } } return } # If not at target depth yet, get folders and continue recursion $foldersUrl = "https://graph.microsoft.com/v1.0/drives/$driveId/items/$FolderId/children?`$filter=folder ne null" $foldersResponse = Invoke-MgGraphRequest -Uri $foldersUrl -Method GET $folders = $foldersResponse.value foreach ($folder in $folders) { Search-FoldersAtLevel -FolderId $folder.id -FolderPath "$FolderPath/$($folder.name)" -TargetDepth $TargetDepth -CurrentDepth ($CurrentDepth + 1) } } try { # Get the starting folder using Invoke-MgGraphRequest if ([string]::IsNullOrEmpty($RootFolder)) { $rootFolderUrl = "https://graph.microsoft.com/v1.0/drives/$driveId/root" $rootFolderResponse = Invoke-MgGraphRequest -Uri $rootFolderUrl -Method GET $rootFolderItem = $rootFolderResponse $rootFolderPath = "/$LibraryName" } else { $rootFolderUrl = "https://graph.microsoft.com/v1.0/drives/$driveId/root:/$RootFolder" $rootFolderResponse = Invoke-MgGraphRequest -Uri $rootFolderUrl -Method GET $rootFolderItem = $rootFolderResponse $rootFolderPath = "/$LibraryName/$RootFolder" } # Search for target folders at each depth level Write-Host "Starting search for '$TargetFolderName' folders in '$rootFolderPath' up to depth $MaxDepth" -ForegroundColor Yellow # Check if the root folder itself matches target name if ($rootFolderItem.name -eq $TargetFolderName) { Write-Host "Found target folder at root level: $rootFolderPath" -ForegroundColor Green $script:foundFolders += [PSCustomObject]@{ Name = $rootFolderItem.name Path = $rootFolderPath ItemId = $rootFolderItem.id CreatedDate = $rootFolderItem.createdDateTime LastModified = $rootFolderItem.lastModifiedDateTime Depth = 0 } } # Search at each depth level from 1 to maxDepth for ($depth = 1; $depth -le $MaxDepth; $depth++) { Write-Host "`nSearching at depth level $depth..." -ForegroundColor Magenta Search-FoldersAtLevel -FolderId $rootFolderItem.id -FolderPath $rootFolderPath -TargetDepth $depth -CurrentDepth 1 } # Display all found folders Write-Host "`nAll '$TargetFolderName' folders found: $($script:foundFolders.Count) folders" -ForegroundColor Yellow $script:foundFolders | Sort-Object Path | Format-Table Name, Path, Depth, CreatedDate, LastModified -AutoSize # Share each found folder with the specified user Write-Host "`nSharing folders with recipients: $($Recipients -join ', ')..." -ForegroundColor Yellow # Initialize counters for summary $successCount = 0 $failCount = 0 $whatIfCount = 0 $errorFolders = @() foreach ($folder in $script:foundFolders) { try { Write-Host "Sharing folder: $($folder.Path)" -ForegroundColor Cyan if ($WhatIf) { Write-Host "WhatIf: Sharing would be done here for folder: $($folder.Path)" -ForegroundColor Yellow $whatIfCount++ } else { Invoke-MgInviteDriveItem -DriveId $driveId -DriveItemId $folder.ItemId -BodyParameter $sharingParams Write-Host "Successfully shared folder: $($folder.Path)" -ForegroundColor Green $successCount++ } } catch { Write-Host "Error sharing folder $($folder.Path): $_" -ForegroundColor Red $failCount++ $errorFolders += $folder.Path } } # Display summary Write-Host "`n===== SHARING SUMMARY =====" -ForegroundColor Cyan if ($WhatIf) { Write-Host "WhatIf mode: $whatIfCount folders would be shared" -ForegroundColor Yellow } else { Write-Host "Successfully shared: $successCount folders" -ForegroundColor Green Write-Host "Failed to share: $failCount folders" -ForegroundColor $(if($failCount -gt 0){"Red"}else{"Green"}) } if ($failCount -gt 0) { Write-Host "`nFolders that failed to share:" -ForegroundColor Red $errorFolders | ForEach-Object { Write-Host "- $_" -ForegroundColor Red } } Write-Host "=========================" -ForegroundColor Cyan } catch { Write-Host "Error: $_" -ForegroundColor Red Write-Host "Please check if the library and folder path exist." -ForegroundColor Yellow } |