From 884977334c3f6b3bed7a7199d60c26f66f3e9c29 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 7 Jan 2025 18:29:03 -0500 Subject: [PATCH] sharepoint / onedrive fixes --- .../CIPPCore/Public/Add-CIPPGroupMember.ps1 | 8 +- .../Invoke-ExecSetSharePointMember.ps1 | 6 +- .../Teams-Sharepoint/Invoke-ListSites.ps1 | 112 ++++++++++++------ 3 files changed, 80 insertions(+), 46 deletions(-) diff --git a/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 b/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 index b29972bcce3a..c81175d2c9ef 100644 --- a/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPGroupMember.ps1 @@ -12,18 +12,16 @@ function Add-CIPPGroupMember( $addmemberbody = "{ `"members@odata.bind`": $(ConvertTo-Json @($MemberIDs)) }" if ($GroupType -eq 'Distribution list' -or $GroupType -eq 'Mail-Enabled Security') { $Params = @{ Identity = $GroupId; Member = $member; BypassSecurityGroupManagerCheck = $true } - New-ExoRequest -tenantid $TenantFilter -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } else { - New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupId)" -tenantid $TenantFilter -type patch -body $addmemberbody -Verbose + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/groups/$($GroupId)" -tenantid $TenantFilter -type patch -body $addmemberbody -Verbose } $Message = "Successfully added user $($Member) to $($GroupId)." Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $Message -Sev 'Info' return $message - return } catch { - $message = "Failed to add user $($Member) to $($GroupId)" + $message = "Failed to add user $($Member) to $($GroupId) - $($_.Exception.Message)" Write-LogMessage -user $ExecutingUser -API $APIName -tenant $TenantFilter -message $message -Sev 'error' -LogData (Get-CippException -Exception $_) return $message } - } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 index 9c59f13662c3..b2f876599c1c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetSharePointMember.ps1 @@ -11,11 +11,11 @@ Function Invoke-ExecSetSharePointMember { param($Request, $TriggerMetadata) if ($Request.body.SharePointType -eq 'Group') { - $GroupId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=mail eq '$($Request.Body.GroupID)'" -tenantid $Request.Body.TenantFilter).id + $GroupId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=mail eq '$($Request.Body.GroupID)' or proxyAddresses/any(x:endsWith(x,'$($Request.Body.GroupID)'))&`$count=true" -ComplexFilter -tenantid $Request.Body.TenantFilter).id if ($Request.body.Add -eq $true) { - $Results = Add-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $Request.Body.input -TenantFilter $Request.Body.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' + $Results = Add-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $Request.Body.user.value -TenantFilter $Request.Body.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' } else { - $UserID = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($Request.Body.input)" -tenantid $Request.Body.TenantFilter).id + $UserID = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($Request.Body.user.value)" -tenantid $Request.Body.TenantFilter).id $Results = Remove-CIPPGroupMember -GroupType 'Team' -GroupID $GroupID -Member $UserID -TenantFilter $Request.Body.TenantFilter -ExecutingUser $request.headers.'x-ms-client-principal' } } else { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 index d94c6b0ce4bd..35017077da0f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 @@ -10,72 +10,108 @@ Function Invoke-ListSites { [CmdletBinding()] param($Request, $TriggerMetadata) - $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + $TenantFilter = $Request.Query.TenantFilter + $Type = $request.query.Type + $UserUPN = $request.query.UserUPN + if (!$TenantFilter) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = 'TenantFilter is required' + }) + return + } - # Write to the Azure Functions log stream. - Write-Host 'PowerShell HTTP trigger function processed a request.' + if (!$Type) { + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = 'Type is required' + }) + return + } + + $Tenant = Get-Tenants -TenantFilter $TenantFilter + $TenantId = $Tenant.customerId + + if ($Type -eq 'SharePointSiteUsage') { + $Filter = 'isPersonalSite eq false' + } else { + $Filter = 'isPersonalSite eq true' + } - # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter - $type = $request.query.Type - $UserUPN = $request.query.UserUPN try { - $Result = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/get$($type)Detail(period='D7')" -tenantid $TenantFilter | ConvertFrom-Csv + $BulkRequests = @( + @{ + id = 'listAllSites' + method = 'GET' + url = "sites/getAllSites?`$filter=$($Filter)&`$select=id,createdDateTime,description,name,displayName,isPersonalSite,lastModifiedDateTime,webUrl,siteCollection,sharepointIds" + } + @{ + id = 'usage' + method = 'GET' + url = "reports/get$($type)Detail(period='D7')?`$format=application/json" + } + ) - if ($UserUPN) { - $ParsedRequest = $Result | Where-Object { $_.'Owner Principal Name' -eq $UserUPN } - } else { - $ParsedRequest = $Result + $Result = New-GraphBulkRequest -tenantid $TenantFilter -Requests @($BulkRequests) -asapp $true + $Sites = ($Result | Where-Object { $_.id -eq 'listAllSites' }).body.value + $UsageBase64 = ($Result | Where-Object { $_.id -eq 'usage' }).body + $UsageJson = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($UsageBase64)) + $Usage = ($UsageJson | ConvertFrom-Json).value + + $GraphRequest = foreach ($Site in $Sites) { + $SiteUsage = $Usage | Where-Object { $_.siteId -eq $Site.sharepointIds.siteId } + [PSCustomObject]@{ + siteId = $Site.sharepointIds.siteId + webId = $Site.sharepointIds.webId + createdDateTime = $Site.createdDateTime + displayName = $Site.displayName + webUrl = $Site.webUrl + ownerDisplayName = $SiteUsage.ownerDisplayName + ownerPrincipalName = $SiteUsage.ownerPrincipalName + lastActivityDate = $SiteUsage.lastActivityDate + fileCount = $SiteUsage.fileCount + storageUsedInGigabytes = [math]::round($SiteUsage.storageUsedInBytes / 1GB, 2) + storageAllocatedInGigabytes = [math]::round($SiteUsage.storageAllocatedInBytes / 1GB, 2) + storageUsedInBytes = $SiteUsage.storageUsedInBytes + storageAllocatedInBytes = $SiteUsage.storageAllocatedInBytes + rootWebTemplate = $SiteUsage.rootWebTemplate + reportRefreshDate = $SiteUsage.reportRefreshDate + AutoMapUrl = '' + } } - $GraphRequest = $ParsedRequest | Select-Object AutoMapUrl, @{ Name = 'UPN'; Expression = { $_.'Owner Principal Name' } }, - @{ Name = 'displayName'; Expression = { $_.'Owner Display Name' } }, - @{ Name = 'LastActive'; Expression = { $_.'Last Activity Date' } }, - @{ Name = 'FileCount'; Expression = { [int]$_.'File Count' } }, - @{ Name = 'UsedGB'; Expression = { [math]::round($_.'Storage Used (Byte)' / 1GB, 2) } }, - @{ Name = 'URL'; Expression = { $_.'Site URL' } }, - @{ Name = 'Allocated'; Expression = { [math]::round($_.'Storage Allocated (Byte)' / 1GB, 2) } }, - @{ Name = 'Template'; Expression = { $_.'Root Web Template' } }, - @{ Name = 'siteid'; Expression = { $_.'site Id' } } - #Temporary workaround for url as report is broken. - #This API is so stupid its great. - $URLs = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/sites/getAllSites?$select=SharePointIds,name,webUrl,displayName,siteCollection' -asapp $true -tenantid $TenantFilter $int = 0 if ($Type -eq 'SharePointSiteUsage') { - $Requests = foreach ($url in $URLs) { + $Requests = foreach ($Site in $GraphRequest) { @{ id = $int++ method = 'GET' - url = "sites/$($url.sharepointIds.siteId)/lists?`$select=id,name,list,parentReference" + url = "sites/$($Site.siteId)/lists?`$select=id,name,list,parentReference" } } $Requests = (New-GraphBulkRequest -tenantid $TenantFilter -scope 'https://graph.microsoft.com/.default' -Requests @($Requests) -asapp $true).body.value | Where-Object { $_.list.template -eq 'DocumentLibrary' } + $GraphRequest = foreach ($Site in $GraphRequest) { + $ListId = ($Requests | Where-Object { $_.parentReference.siteId -like "*$($Site.siteId)*" }).id + $site.AutoMapUrl = "tenantId=$($TenantId)&webId={$($Site.webId)}&siteid={$($Site.siteId)}&webUrl=$($Site.webUrl)&listId={$($ListId)}" + $site + } } - $GraphRequest = foreach ($site in $GraphRequest) { - $SiteURLs = ($URLs.SharePointIds | Where-Object { $_.siteId -eq $site.SiteId }) - $site.URL = $SiteURLs.siteUrl - $ListId = ($Requests | Where-Object { $_.parentReference.siteId -like "*$($SiteURLs.siteId)*" }).id - $site.AutoMapUrl = "tenantId=$($SiteUrls.tenantId)&webId={$($SiteUrls.webId)}&siteid={$($SiteURLs.siteId)}&webUrl=$($SiteURLs.siteUrl)&listId={$($ListId)}" - $site - } - $StatusCode = [HttpStatusCode]::OK - + } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message $StatusCode = [HttpStatusCode]::Forbidden $GraphRequest = $ErrorMessage } if ($Request.query.URLOnly -eq 'true') { - $GraphRequest = $GraphRequest | Where-Object { $null -ne $_.URL } + $GraphRequest = $GraphRequest | Where-Object { $null -ne $_.webUrl } } # Associate values to output bindings by calling 'Push-OutputBinding'. Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = $StatusCode - Body = @($GraphRequest | Sort-Object -Property UPN) + Body = @($GraphRequest | Sort-Object -Property displayName) }) }