EasyLife365.Collaboration.psm1
#region _classes class EL { [string]$Id [string]$DisplayName [object]$Metadata [System.Nullable[guid]]$TemplateId [System.Nullable[guid]]$PolicyId [object]$Policy EL ([object] $el) { $this.Id = $el.Id $this.DisplayName = $el.DisplayName $this.Metadata = $el.Extensions | Get-EasyMetaData $this.Policy = $el.Extensions | Get-EasyPolicyData if($this.Metadata.tId){ $this.TemplateId = $this.Metadata.tId } if($this.Policy.pId){ $this.PolicyId = $this.Policy.pId } } [void] NewTemplateId([guid]$tId,$type) { $this.Metadata = [PSCustomObject]@{ tId = $tId } $metadataHash = ($this.Metadata | ConvertTo-EasyHashtable) if($type -eq 'ELGuestUser'){ Write-Verbose "New-MgUserExtension userId: $($this.id) metadata: $($metadataHash | ConvertTo-Json -Compress)" New-MgUserExtension -UserId $this.Id -Id $script:elMetadataExtension -AdditionalProperties $metadataHash -ErrorAction Stop } elseif($type -eq 'ELGroup'){ Write-Verbose "New-MgUserExtension groupId: $($this.id) metadata: $($metadataHash | ConvertTo-Json -Compress)" New-MgGroupExtension -GroupId $this.Id -Id $script:elMetadataExtension -AdditionalProperties $metadataHash -ErrorAction Stop } } [void] SetTemplateId([guid]$tId,$type) { $this.Metadata.tId = $tId $metadataHash = ($this.Metadata | ConvertTo-EasyHashtable) if($type -eq 'ELGuestUser'){ Write-Verbose "Update-MgUserExtension userId: $($this.id) metadata: $($metadataHash | ConvertTo-Json -Compress)" Update-MgUserExtension -UserId $this.Id -ExtensionId $script:elMetadataExtension -AdditionalProperties $metadataHash -ErrorAction Stop } elseif($type -eq 'ELGroup'){ Write-Verbose "Update-MgUserExtension groupId: $($this.id) metadata: $($metadataHash | ConvertTo-Json -Compress)" Update-MgGroupExtension -GroupId $this.Id -ExtensionId $script:elMetadataExtension -AdditionalProperties $metadataHash -ErrorAction Stop } } [void] NewPolicyId([guid]$polId,$type) { $this.PolicyId = $polId if($type -eq 'ELGuestUser'){ Write-Verbose "New-MgUserExtension userId: $($this.id) pId: $($this.PolicyId)" New-MgUserExtension -UserId $this.Id -Id $script:elPolicyExtension -AdditionalProperties @{ pId = $this.PolicyId } -ErrorAction Stop } elseif($type -eq 'ELGroup'){ Write-Verbose "New-MgGroupExtension groupId: $($this.id) pId: $($this.PolicyId)" New-MgGroupExtension -GroupId $this.Id -Id $script:elPolicyExtension -AdditionalProperties @{ pId = $this.PolicyId } -ErrorAction Stop } } [void] SetPolicyId([guid]$polId,$type) { $this.PolicyId = $polId if($type -eq 'ELGuestUser'){ Write-Verbose "Update-MgUserExtension userId: $($this.id) pId: $($this.PolicyId)" Update-MgUserExtension -UserId $this.Id -ExtensionId $script:elPolicyExtension -AdditionalProperties @{ pId = $this.PolicyId } -ErrorAction Stop } elseif($type -eq 'ELGroup'){ Write-Verbose "Update-MgGroupExtension groupId: $($this.id) pId: $($this.PolicyId)" Update-MgGroupExtension -GroupId $this.Id -ExtensionId $script:elPolicyExtension -AdditionalProperties @{ pId = $this.PolicyId } -ErrorAction Stop } } [void] ClearPolicyId($type) { $this.PolicyId = $null if($type -eq 'ELGuestUser'){ $this.AccountDisabledState = $null $this.AccountDisabledDate = $null $this.AccountDisabledStepChange = $null $this.AccountDisabledStep = $null $this.NoOwnersEscalation = $null $this.MinimumOwnerStepChange = $null $this.MinimumOwnerStep = $null $this.MinimumOwnerState = $null $this.ConfirmationStepChange = $null $this.ConfirmationStep = $null $this.ConfirmationState = $null $this.ConfirmationDate = $null $this.InactivityStepChange = $null $this.InactivityStep = $null $this.InactivityState = $null $this.InactivityDate = $null $this.InvitationStepChange = $null $this.InvitationStep = $null $this.InvitationState = $null $this.InvitationDate = $null $this.NamingState = $null $this.ClassificationState = $null $this.ClassificationDate = $null $this.ClassificationStepChange = $null $this.ClassificationStep = $null Write-Verbose "Remove-MgUserExtension userId: $($this.id) extensionId: cloud.easyLife.policy " Remove-MgUserExtension -UserId $this.Id -ExtensionId $script:elPolicyExtension -ErrorAction Stop } elseif($type -eq 'ELGroup'){ $this.AccessReviewPolicyState = $null $this.ConfirmationPolicyState = $null $this.ExpirationPolicyState = $null $this.OwnerPolicyState = $null $this.NoOwnerEscalation = $null $this.IsArchived = $null Write-Verbose "Remove-MgGroupExtension groupId: $($this.id) extensionId: cloud.easyLife.policy " Remove-MgGroupExtension -GroupId $this.Id -ExtensionId $script:elPolicyExtension -ErrorAction Stop } } [void] SetMetadata([hashtable]$metadata,$type) { $metadataHash = ($this.Metadata | ConvertTo-EasyHashtable) foreach($key in $metadata.Keys){ if($metadataHash.contains($key)){ $metadataHash[$key] = $metadata[$key] } else { $metadataHash.Add($key,$metadata[$key]) } } $this.Metadata = $metadataHash if($type -eq 'ELGuestUser'){ Write-Verbose "Update-MgUserExtension userId: $($this.id) metadata: $($metadataHash | ConvertTo-Json -Compress)" Update-MgUserExtension -UserId $this.Id -ExtensionId $script:elMetadataExtension -AdditionalProperties $metadataHash -ErrorAction Stop } elseif($type -eq 'ELGroup'){ Write-Verbose "Update-MgUserExtension groupId: $($this.id) metadata: $($metadataHash | ConvertTo-Json -Compress)" Update-MgGroupExtension -GroupId $this.Id -ExtensionId $script:elMetadataExtension -AdditionalProperties $metadataHash -ErrorAction Stop } } [string] ToString() { return $this.DisplayName } } class ELGuestUser : EL { [string]$PrimaryOwner [string]$SecondaryOwner [string]$Mail [string]$CompanyName [string]$GivenName [string]$Surname [System.Nullable[datetime]]$createdDateTime [bool]$IsCompliant [string]$ResourceType [string]$AccountDisabledState [System.Nullable[datetime]]$AccountDisabledDate [System.Nullable[datetime]]$AccountDisabledStepChange [string]$AccountDisabledStep [boolean]$NoOwnersEscalation [System.Nullable[datetime]]$MinimumOwnerStepChange [string]$MinimumOwnerStep [string]$MinimumOwnerState [System.Nullable[datetime]]$ConfirmationStepChange [string]$ConfirmationStep [string]$ConfirmationState [System.Nullable[datetime]]$ConfirmationDate [System.Nullable[datetime]]$InactivityStepChange [string]$InactivityStep [string]$InactivityState [System.Nullable[datetime]]$InactivityDate [System.Nullable[datetime]]$InvitationStepChange [string]$InvitationStep [string]$InvitationState [System.Nullable[datetime]]$InvitationDate [string]$NamingState [string]$ClassificationState [System.Nullable[datetime]]$ClassificationDate [System.Nullable[datetime]]$ClassificationStepChange [string]$ClassificationStep [string]$ExtensionAttribute1 [string]$ExtensionAttribute2 [string]$ExtensionAttribute3 [string]$ExtensionAttribute4 [string]$ExtensionAttribute5 [string]$ExtensionAttribute6 [string]$ExtensionAttribute7 [string]$ExtensionAttribute8 [string]$ExtensionAttribute9 [string]$ExtensionAttribute10 ELGuestUser ([object] $elGuestUser, [bool]$fastMode ) : base($elGuestUser) { $this.Mail = $elGuestUser.Mail $this.CompanyName = $elGuestUser.CompanyName $this.GivenName = $elGuestUser.GivenName $this.Surname = $elGuestUser.Surname $this.createdDateTime = $elGuestUser.createdDateTime $pOwner = $elGuestUser.AdditionalProperties.$script:elUserExtension.primaryOwner $sOwner = $elGuestUser.AdditionalProperties.$script:elUserExtension.secondaryOwner if($pOwner){ if($fastMode) { $this.PrimaryOwner = $pOwner } else { $this.PrimaryOwner = (Get-MgUser -UserId $pOwner -Select UserPrincipalName).UserPrincipalName } } if($sOwner){ if($fastMode) { $this.SecondaryOwner = $sOwner } else { $this.SecondaryOwner = (Get-MgUser -UserId $sOwner -Select UserPrincipalName).UserPrincipalName } } $this.IsCompliant = $elGuestUser.AdditionalProperties.$script:elUserExtension.isCompliant $this.ResourceType = $elGuestUser.AdditionalProperties.$script:elUserExtension.resourceType $this.templateId = $elGuestUser.AdditionalProperties.$script:elUserExtension.templateId $this.policyId = $elGuestUser.AdditionalProperties.$script:elUserExtension.policyId $this.extensionAttribute1 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute1 $this.extensionAttribute2 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute2 $this.extensionAttribute3 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute3 $this.extensionAttribute4 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute4 $this.extensionAttribute5 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute5 $this.extensionAttribute6 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute6 $this.extensionAttribute7 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute7 $this.extensionAttribute8 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute8 $this.extensionAttribute9 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute9 $this.extensionAttribute10 = $elGuestUser.AdditionalProperties.$script:elUserExtension.extensionAttribute10 $this.AccountDisabledState = $this.Policy.adSta $this.AccountDisabledDate = $this.Policy.adCh $this.AccountDisabledStep = $this.Policy.adSt $this.AccountDisabledStepChange = $this.Policy.adStCh $this.NoOwnersEscalation = $this.Policy.noEsca $this.MinimumOwnerState = $this.Policy.owSta $this.MinimumOwnerStep = $this.Policy.owSt $this.MinimumOwnerStepChange = $this.Policy.owStCh $this.ConfirmationState = $this.Policy.coSta $this.ConfirmationDate = $this.Policy.coCh $this.ConfirmationStep = $this.Policy.coSt $this.ConfirmationStepChange = $this.Policy.coStCh $this.InactivityState = $this.Policy.inSta $this.InactivityDate = $this.Policy.inCh $this.InactivityStep = $this.Policy.inSt $this.InactivityStepChange = $this.Policy.inStCh $this.InvitationState = $this.Policy.invSta $this.InvitationDate = $this.Policy.invCh $this.InvitationStep = $this.Policy.invSt $this.InvitationStepChange = $this.Policy.invStCh $this.NamingState = $this.Policy.naSta $this.ClassificationState = $this.Policy.clSta $this.ClassificationDate = $this.Policy.clCh $this.ClassificationStep = $this.Policy.clSt $this.ClassificationStepChange = $this.Policy.clStCh } } class ELGroup : EL { [string]$Description [string]$Mail [System.Nullable[datetime]]$CreatedDateTime [string]$MailNickname [string]$Visibility [string[]]$GroupTypes [string[]]$Owner [boolean]$NoOwnersEscalation [System.Nullable[datetime]]$ConfirmationStepChange [string]$ConfirmationStep [string]$ConfirmationState [System.Nullable[datetime]]$ConfirmationDate [System.Nullable[datetime]]$ConfirmationFeedbackDate [System.Nullable[datetime]]$ExpirationStepChange [string]$ExpirationStep [string]$ExpirationState [System.Nullable[datetime]]$ExpirationDate [System.Nullable[datetime]]$ExpirationFeedbackDate [System.Nullable[datetime]]$MinimumOwnerStepChange [string]$MinimumOwnerStep [string]$MinimumOwnerState [System.Nullable[datetime]]$AccessReviewStepChange [string]$AccessReviewStep [string]$AccessReviewState [System.Nullable[datetime]]$AccessReviewDate [System.Nullable[datetime]]$AccessReviewFeedbackDate ELGroup ([object] $ELGroup, [bool]$fastMode) : base($ELGroup) { $this.Description = $ELGroup.Description $this.Mail = $ELGroup.Mail $this.Visibility = $ELGroup.Visibility $this.MailNickname = $ELGroup.MailNickname $this.CreatedDateTime = $ELGroup.CreatedDateTime $this.GroupTypes = $ELGroup.GroupTypes if(-not($fastMode)){ $this.Owner = $ELGroup.Owners.AdditionalProperties.userPrincipalName } $this.NoOwnersEscalation = $this.Policy.noEsca $this.ConfirmationStepChange = $this.Policy.coStCh $this.ConfirmationStep = $this.Policy.coSt $this.ConfirmationState = $this.Policy.coSta $this.ConfirmationDate = $this.Policy.coCh $this.ConfirmationFeedbackDate = $this.Policy.coFeDa $this.ExpirationStepChange = $this.Policy.exStCh $this.ExpirationStep = $this.Policy.exSt $this.ExpirationState = $this.Policy.exSta $this.ExpirationDate = $this.Policy.exCh $this.ExpirationFeedbackDate = $this.Policy.exFeDa $this.MinimumOwnerStepChange = $this.Policy.owStCh $this.MinimumOwnerStep = $this.Policy.owSt $this.MinimumOwnerState = $this.Policy.owSta $this.AccessReviewStepChange = $this.Policy.arStCh $this.AccessReviewStep = $this.Policy.arSt $this.AccessReviewState = $this.Policy.arSta $this.AccessReviewDate = $this.Policy.arCh $this.AccessReviewFeedbackDate = $this.Policy.arFeDa } } class ELTeam : ELGroup { [bool]$IsArchived [string]$WebUrl ELTeam ([object] $ELGroup, [object] $ELTeam, [bool]$fastMode) : base($ELGroup,$fastMode) { $this.Description = $ELGroup.Description $this.Mail = $ELGroup.Mail $this.Visibility = $ELGroup.Visibility $this.MailNickname = $ELGroup.MailNickname $this.CreatedDateTime = $ELGroup.CreatedDateTime $this.GroupTypes = $ELGroup.GroupTypes $this.IsArchived = $ELTeam.isArchived $this.WebUrl = $ELTeam.WebUrl $this.NoOwnersEscalation = $this.Policy.noEsca $this.ConfirmationStepChange = $this.Policy.coStCh $this.ConfirmationStep = $this.Policy.coSt $this.ConfirmationState = $this.Policy.coSta $this.ConfirmationDate = $this.Policy.coCh $this.ConfirmationFeedbackDate = $this.Policy.coFeDa $this.ExpirationStepChange = $this.Policy.exStCh $this.ExpirationStep = $this.Policy.exSt $this.ExpirationState = $this.Policy.exSta $this.ExpirationDate = $this.Policy.exCh $this.ExpirationFeedbackDate = $this.Policy.exFeDa $this.MinimumOwnerStepChange = $this.Policy.owStCh $this.MinimumOwnerStep = $this.Policy.owSt $this.MinimumOwnerState = $this.Policy.owSta $this.AccessReviewStepChange = $this.Policy.arStCh $this.AccessReviewStep = $this.Policy.arSt $this.AccessReviewState = $this.Policy.arSta $this.AccessReviewDate = $this.Policy.arCh $this.AccessReviewFeedbackDate = $this.Policy.arFeDa } } class ELTelemetry { [string]$name = 'Microsoft.ApplicationInsights.Event' [System.Nullable[datetime]]$time = [datetime]::UtcNow [guid]$iKey = $elAiInstaceKey [hashtable]$tags = @{'ai.cloud.roleInstance' = (Get-MgContext).TenantId} [hashtable]$data ELTelemetry() { } ELTelemetry([hashtable]$d) { $this.data = $d } ELTelemetry([guid]$k,[hashtable]$t,[hashtable]$d) { $this.iKey = $k $this.tags = $t $this.data = $d } [string] ToJson(){ return ($this | ConvertTo-Json -Compress -Depth 100) } } #endregion _classes #region _constants New-Variable -Name elPolicyExtension -Option Constant -Value 'cloud.easyLife.policy' New-Variable -Name elMetadataExtension -Option Constant -Value 'cloud.easyLife.metadata' New-Variable -Name elPowerShellClientId -Option Constant -Value '14b899c6-0b3a-4f59-8807-e9df5fb0fb1e' New-Variable -Name elAiInstaceKey -Option Constant -Value '71103f09-7433-40bb-b664-e851ce5bf6b1' New-Variable -Name elRequiredScopes -Option Constant -Value @{ 'Get' = @('User.Read.All', 'Group.Read.All','Team.ReadBasic.All') 'Set' = @('User.ReadWrite.All', 'Group.ReadWrite.All','Team.ReadBasic.All') } New-Variable -Name elUserExtension -Option Constant -Value 'easylife365_user' #endregion _constants #region ConvertTo-EasyHashtable function ConvertTo-EasyHashtable { param ( [Parameter(Mandatory,ValueFromPipeline)] [object]$inputObject ) $output = @{}; $inputObject | Get-Member -MemberType *Property | ForEach-Object { $output.($_.name) = $inputObject.($_.name); } return $output; } #endregion ConvertTo-EasyHashtable #region Get-EasyAppRoleId function Get-EasyAppRoleId { [CmdletBinding()] param ( [object]$graphObject, [string[]]$AppRoles ) process { $AppRoles | ForEach-Object { $scope = $_ $graphObject.AppRoles.where{$_.Value -eq $scope} | Select-Object Id,Value } } } #endregion Get-EasyAppRoleId #region Get-EasyLatestModuleVersion function Get-EasyLatestModuleVersion { [CmdletBinding()] param ( [Parameter()] [string]$name = 'easylife365.collaboration' ) process { (Invoke-RestMethod "https://www.powershellgallery.com/api/v2/FindPackagesById()?id='$name'")[-1].properties.version } } #endregion Get-EasyLatestModuleVersion #region Get-EasyMetaData function Get-EasyMetaData { [CmdletBinding()] param ( [Parameter(ValueFromPipeline)] [object] $inputObject ) process { $objParam = @{ TypeName = 'pscustomobject' Property = $inputObject.where{$_.id -eq $script:elMetadataExtension}.AdditionalProperties } if($objParam.Property){ New-Object @objParam | Select-Object -ExcludeProperty '@odata.type','extensionName' } } } #endregion Get-EasyMetaData #region Get-EasyPolicyData function Get-EasyPolicyData { [CmdletBinding()] param ( [Parameter(ValueFromPipeline)] [object] $inputObject ) process { $objParam = @{ TypeName = 'pscustomobject' Property = $inputObject.where{$_.id -eq $script:elPolicyExtension}.AdditionalProperties } if($objParam.Property){ New-Object @objParam | Select-Object -ExcludeProperty '*@odata.type','extensionName' } } } #endregion Get-EasyPolicyData #region Get-EasyTeamsActivity function Get-EasyTeamsActivity { [CmdletBinding()] param ( [Parameter()] [ValidateSet('D7', 'D30', 'D90', 'D180')] $Period = 'D30', [Parameter()] [ValidateSet('ActivityDetail','ActivityCounts','ActivityDistributionCounts')] $Report = 'ActivityDetail' ) process { $uri = "https://graph.microsoft.com/beta/reports/getTeamsTeam{0}(period='{1}')?`$format=application/json" -f $Report, $Period $res = Invoke-MgGraphRequest -Uri $uri $res.value } } #endregion Get-EasyTeamsActivity #region Get-EasyUserId function Get-EasyUserId { [CmdletBinding()] param ( $userId ) process { try { (Get-MgUser -UserId $userId -ErrorAction Stop).Id } catch { Write-Warning "Could not find user with id: $userId" } } } #endregion Get-EasyUserId #region New-EasyTelemetryData function New-EasyTelemetryData { param( [Parameter()] [ValidateSet('Event','Exception')] $type ) switch($type){ 'Event' { @{ baseType = "EventData" baseData = @{ ver = 2 name = $name properties = @{ moduleVersion = $moduleVersion commandLine = $commandLine duration = $duration } } } } 'Exception' { @{ baseType = "ExceptionData" baseData = @{ ver = 2 handledAt = "UserCode" properties = @{ moduleVersion = $moduleVersion commandLine = $commandLine duration = $duration } exceptions = @() } } } } } #endregion New-EasyTelemetryData #region Select-EasyGroupProperty function Select-EasyGroupProperty { [CmdletBinding()] param ( [Parameter(ValueFromPipeline)] [object]$InputObject ) process { $policyProperty = $InputObject.Extensions.where{$_.id -eq "cloud.easyLife.policy"}.AdditionalProperties $Policy = New-Object -TypeName pscustomobject -Property $policyProperty $selectProperty = 'id','displayName','description','mail','groupTypes',@{ Name = 'policyId' Expression = {$Policy.pId} },@{ Name = 'ownerPolicyState' Expression= {$Policy.owSta} },@{ Name = 'accessReviewPolicyState' Expression= {$Policy.arSta} },@{ Name = 'expirationPolicyState' Expression= {$Policy.exSta} },@{ Name = 'confirmationPolicyState' Expression= {$Policy.coSta} },@{ Name = 'isArchived' Expression= {$Policy.isArchived} },@{ Name = 'noOwnerEscalation' Expression= {$Policy.noEsca} },@{ Name = 'Metadata' Expression = { @($InputObject.Extensions | Get-EasyMetaData)[0] } } $InputObject | Select-Object -Property $selectProperty } } #endregion Select-EasyGroupProperty #region Send-EasyTelemetryEvent function Send-EasyTelemetryEvent { [CmdletBinding()] param( [string] $IngestionEndpoint = 'https://westeurope-5.in.applicationinsights.azure.com', [ELTelemetry] $Body, [switch] $PassThru ) process { # The rest request fails with PS5.1 if($EasyLife365DisableTelemetry -eq $true -or $PSEdition -eq 'Desktop'){ Write-Verbose "Sending telemetry is disabled on this system." } else { $Body.time = [datetime]::UtcNow $null = Invoke-RestMethod -Uri "$IngestionEndpoint/v2/track" -Method 'POST' -UseBasicParsing -Body ($Body.ToJson()) if($PassThru){ $Body } } } } #endregion Send-EasyTelemetryEvent #region Set-EasyGroup function Set-EasyGroup { <# .SYNOPSIS Set EasyLife properties for group objects through the Graph API. .DESCRIPTION This function uses Set-MgGroup and Set-MgGroupExtension to set EasyLife properties, such as PolicyId and TemplateId, of groups-based objects through the Graph API. .NOTES The alias Set-EasyTeam can be used. .LINK https://docs.easylife365.cloud .EXAMPLE Get-EasyGroup -Id 0b158de6-5fe8-49d9-81bb-22c23860d3a4 | Set-EasyGroup -PolicyId 2570b1bb-50bc-41a9-9d38-85888e8a04a1 This example sets the EasyLife policy to 2570b1bb-50bc-41a9-9d38-85888e8a04a1 for the Group with the Id 0b158de6-5fe8-49d9-81bb-22c23860d3a4. To get the id of a policy, open the policy in the EasyLife cockpit and copy the guid from the URL. .EXAMPLE Set-EasyGroup -Id 0b158de6-5fe8-49d9-81bb-22c23860d3a4 -TemplateId 51436a74-87aa-43d8-8139-928a26a33e80 This example sets the EasyLife policy to 51436a74-87aa-43d8-8139-928a26a33e80 for the Group with the Id 0b158de6-5fe8-49d9-81bb-22c23860d3a4 To get the id of a template, open the template in the EasyLife cockpit and copy the guid from the URL. #> [CmdletBinding(DefaultParameterSetName='byGroupId',SupportsShouldProcess)] param ( [Parameter(Mandatory,ParameterSetName='byGroupId')] [ValidateNotNullOrEmpty()] [string]$GroupId, [Parameter(ParameterSetName='inputObject',ValueFromPipeline)] [ValidateNotNullOrEmpty()] [object]$InputObject, [string]$DisplayName, [guid]$PolicyId, [guid]$TemplateId, [hashtable]$Metadata, [switch]$PassThru ) process { if(-not($InputObject)){ $InputObject = Get-EasyGroup -Id $GroupId } $bodyParameter = @{} switch($PSBoundParameters.Keys){ 'DisplayName' { $bodyParameter.DisplayName = $DisplayName } 'PolicyId' { $InputObject | Set-EasyPolicyId -PolicyId $PolicyId } 'TemplateId' { $InputObject | Set-EasyTemplateId -TemplateId $TemplateId } 'Metadata' { $InputObject | Set-EasyMetadata -Metadata $Metadata } } if($bodyParameter.Keys -ne '') { if($PSCmdlet.ShouldProcess("Updating Group $($InputObject.DisplayName) with $($bodyParameter| ConvertTo-Json -Compress)",$null,$null)) { Update-MgGroup -GroupId $InputObject.Id -BodyParameter $bodyParameter } } if($PassThru){ $InputObject } } } # New-Alias -Name Set-EasyTeam -Value Set-EasyGroup #endregion Set-EasyGroup #region Set-EasyGuestUser function Set-EasyGuestUser { <# .SYNOPSIS Set EasyLife properties of (guest) user accounts through the Graph API. .DESCRIPTION This function uses Set-MgUser and Set-MgUserExtension to set EasyLife properties such as owner, metadata, and policy. This function does not differentiate between users and guest users, use with caution. .NOTES None. .LINK https://docs.easylife365.cloud .EXAMPLE Get-EasyGuestUser -Id 0cefd2d0-ae5a-4ca3-98e9-e8df5418226c | Set-EasyGuestUser -PolicyId 87954648-18f5-4091-93fb-db0d38eca208 This example sets the EasyLife policy to 87954648-18f5-4091-93fb-db0d38eca208 for the user with the Id 0cefd2d0-ae5a-4ca3-98e9-e8df5418226c. To get the id of a policy, open the policy in the EasyLife cockpit and copy the guid from the URL. .EXAMPLE Set-EasyGuestUser -Id 0cefd2d0-ae5a-4ca3-98e9-e8df5418226c -TemplateId 33373f13-8669-40de-b6da-b4a2b0a55e83 This example sets the EasyLife template to 33373f13-8669-40de-b6da-b4a2b0a55e83 for the user with the Id 0cefd2d0-ae5a-4ca3-98e9-e8df5418226c. To get the id of a tempate, open the template in the EasyLife cockpit and copy the guid from the URL. #> [CmdletBinding(DefaultParameterSetName='byUserId',SupportsShouldProcess)] param ( [Parameter(Mandatory,ParameterSetName='byUserId')] [ValidateNotNullOrEmpty()] [string]$UserId, [Parameter(ParameterSetName='inputObject',ValueFromPipeline)] [ValidateNotNullOrEmpty()] [object]$InputObject, [string]$DisplayName, [guid]$PolicyId, [guid]$TemplateId, [hashtable]$Metadata, [switch]$PassThru ) process { if(-not($InputObject)){ $InputObject = Get-EasyGuestUser -Id $UserId } $bodyParameter = @{} switch($PSBoundParameters.Keys){ 'DisplayName' { $bodyParameter.DisplayName = $DisplayName } 'PolicyId' { $InputObject | Set-EasyPolicyId -PolicyId $PolicyId } 'TemplateId' { $InputObject | Set-EasyTemplateId -TemplateId $TemplateId } 'Metadata' { $InputObject | Set-EasyMetadata -Metadata $Metadata } } if($bodyParameter.Keys -ne '') { if($PSCmdlet.ShouldProcess("Updating User $($InputObject.DisplayName) with $($bodyParameter| ConvertTo-Json -Compress)",$null,$null)) { Update-MgUser -UserId $InputObject.Id -BodyParameter $bodyParameter } } if($PassThru){ $InputObject } } } #endregion Set-EasyGuestUser #region Set-EasyMetadata function Set-EasyMetadata { [CmdletBinding(DefaultParameterSetName='user',SupportsShouldProcess)] param ( [Parameter(Mandatory,ParameterSetName='user')] [ValidateNotNullOrEmpty()] $UserId, [Parameter(Mandatory,ParameterSetName='group')] [ValidateNotNullOrEmpty()] $GroupId, [Parameter(Mandatory,ValueFromPipeline,ParameterSetName='inputObject')] [ValidateNotNullOrEmpty()] $InputObject, [Parameter(Mandatory)] [hashtable] $Metadata ) begin { $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName } process { switch($PSBoundParameters.Keys){ 'UserId'{ $InputObject = Get-EasyGuestUser -Id $UserId } 'GroupId'{ $InputObject = Get-EasyGroup -Id $GroupId } } $type = $InputObject.GetType().Name Write-Verbose "InputObject is of type $type" if($InputObject.Metadata -eq $null){ if($PSCmdlet.ShouldProcess("Add metadata extension to object $($InputObject.DisplayName)",$null,$null)){ try { $InputObject.NewTemplateId([guid]::Empty,$type) } catch { Send-EasyTelemetryEvent -Type Exception -Message $_.Exception -PassThru $diag.success = $false } } } else { if($PSCmdlet.ShouldProcess("Set metadata for object $($InputObject.DisplayName)",$null,$null)){ try{ $InputObject.SetMetadata($metadata,$type) } catch { Send-EasyTelemetryEvent -Type Exception -Message $_.Exception -PassThru $diag.success = $false } } } } end { $sw.Stop() $diag.Duration = $sw.ElapsedMilliseconds Send-EasyTelemetryEvent -Type Request -Request $diag -CommandLine $MyInvocation.Line } } #endregion Set-EasyMetadata #region Set-EasyPolicyId function Set-EasyPolicyId { [CmdletBinding(DefaultParameterSetName='user',SupportsShouldProcess)] param ( [Parameter(Mandatory,ParameterSetName='user')] [ValidateNotNullOrEmpty()] $UserId, [Parameter(Mandatory,ParameterSetName='group')] [ValidateNotNullOrEmpty()] $GroupId, [Parameter(Mandatory,ValueFromPipeline,ParameterSetName='inputObject')] [ValidateNotNullOrEmpty()] $InputObject, [Parameter(Mandatory)] [guid] $PolicyId ) begin { $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName } process { switch($PSBoundParameters.Keys){ 'UserId'{ $InputObject = Get-EasyGuestUser -Id $UserId } 'GroupId'{ $InputObject = Get-EasyGroup -Id $GroupId } } $type = $InputObject.GetType().Name Write-Verbose "InputObject is of type $type" if($InputObject.PolicyId -eq [guid]::Empty){ # input object does not have a policy, create policy attribute and set policy if($PSCmdlet.ShouldProcess("Add policyId extension with $PolicyId to object $($InputObject.DisplayName)",$null,$null)){ try { $InputObject.newPolicyId($PolicyId,$type) } catch { Send-EasyTelemetryEvent -Type Exception -Message $_.Exception -PassThru $diag.success = $false } } } else { if($PolicyId -eq [guid]::Empty){ # input object has a policy, assume user wants to clear it, remove policy attribute if($PSCmdlet.ShouldProcess("Set policyId to $PolicyId for object $($InputObject.DisplayName)",$null,$null)){ try { $InputObject.ClearPolicyId($type) } catch { Send-EasyTelemetryEvent -Type Exception -Message $_.Exception -PassThru $diag.success = $false } } } else { # input object already has a policy, update policyId if($PSCmdlet.ShouldProcess("Set policyId to $PolicyId for object $($InputObject.DisplayName)",$null,$null)){ try { $InputObject.setPolicyId($PolicyId,$type) } catch { Send-EasyTelemetryEvent -Type Exception -Message $_.Exception -PassThru $diag.success = $false } } } } } end { $sw.Stop() $diag.Duration = $sw.ElapsedMilliseconds Send-EasyTelemetryEvent -Type Request -Request $diag -CommandLine $MyInvocation.Line } } #endregion Set-EasyPolicyId #region Set-EasyTemplateId function Set-EasyTemplateId { [CmdletBinding(DefaultParameterSetName='user',SupportsShouldProcess)] param ( [Parameter(Mandatory,ParameterSetName='user')] [ValidateNotNullOrEmpty()] $UserId, [Parameter(Mandatory,ParameterSetName='group')] [ValidateNotNullOrEmpty()] $GroupId, [Parameter(Mandatory,ValueFromPipeline,ParameterSetName='inputObject')] [ValidateNotNullOrEmpty()] $InputObject, [Parameter(Mandatory)] [guid] $TemplateId ) begin { $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName } process { switch($PSBoundParameters.Keys){ 'UserId'{ $InputObject = Get-EasyGuestUser -Id $UserId } 'GroupId'{ $InputObject = Get-EasyGroup -Id $GroupId } } $type = $InputObject.GetType().Name Write-Verbose "InputObject is of type $type" if($InputObject.Metadata -eq $null){ if($PSCmdlet.ShouldProcess("Add metadata extension to object $($InputObject.DisplayName)",$null,$null)){ $InputObject.newTemplateId($TemplateId,$type) } } else { if($PSCmdlet.ShouldProcess("Set templateId to $TemplateId for object $($InputObject.DisplayName)",$null,$null)){ $InputObject.setTemplateId($TemplateId,$type) } } } end { $sw.Stop() $diag.data.baseData.properties.duration = $sw.ElapsedMilliseconds $diag.data.baseData.properties.commandLine = $MyInvocation.Line Send-EasyTelemetryEvent -Body $diag } } #endregion Set-EasyTemplateId #region Start-EasyDiagnostics function Start-EasyDiagnostics { [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$Name ) process { [System.Diagnostics.Stopwatch]::StartNew() $diag = [ELTelemetry]::new() $diag.data = New-EasyTelemetryData -type Event $diag.data.baseData.name = $Name $diag.data.baseData.properties.moduleVersion = $MyInvocation.MyCommand.Module.Version.ToString() $diag } } #endregion Start-EasyDiagnostics #region Test-EasyLife365ModuleVersion function Test-EasyLife365ModuleVersion { [CmdletBinding()] param() process { $importedModule = Get-Module EasyLife365.Collaboration $latestVersion = Get-EasyLatestModuleVersion $importedVersion = $importedModule.Version Write-Verbose "You have imported module version [$importedVersion] the latest version available on the PowerShell Gallery is [$latestVersion]" if($latestVersion -gt $importedVersion){ $messageData = [System.Management.Automation.HostInformationMessage]@{ Message = "`r`nYou are using an outdated version of the module, please update to version [$latestVersion] by typing: Update-Module EasyLife365.Collaboration`r`n"; ForegroundColor = 'Yellow' BackgroundColor = $Host.UI.RawUI.BackgroundColor } Write-Information -MessageData $messageData -InformationAction Continue } } } #endregion Test-EasyLife365ModuleVersion #region Connect-EasyLife365 function Connect-EasyLife365 { <# .SYNOPSIS Connect to EasyLife 365. .DESCRIPTION This function uses the Microsoft.Graph.Authentication module to connect to the Graph API with the scopes: User.ReadWrite.All, Group.ReadWrite.All. .NOTES Currently, this fuction only connects to the Graph API. Connection to the EasyLife API is not yet available. You need to have permissions to consent the use of Microsoft Graph PowerShell in your Azure AD. .LINK https://docs.easylife365.cloud/docs/add-ons/powershell/connect-easylife365/ .INPUTS None You cannot pipe values to this cmdlet. .OUTPUTS None This function does not write object to the pipeline. It writes an informational message to the Information output stream. .PARAMETER Identity Use this parameter to connect with a managed identity in Azure Automation or Azure Function Apps. .EXAMPLE Connect-EasyLife365 This example connects to the Graph API using the scopes User.ReadWrite.All, Group.ReadWrite.All, Team.ReadBasic.All. .EXAMPLE Connect-EasyLife365 -Scopes 'User.Read.All', 'Group.Read.All', 'Team.ReadBasic.All' This example connects to the Graph API using the scopes User.Read.All, Group.Read.All, Team.ReadBasic.All. .EXAMPLE Connect-EasyLife365 -ClientId '00df8f0a-c19b-4c56-83dc-c1aaf622fe64' -Scopes 'User.Read.All', 'Group.Read.All', 'Team.ReadBasic.All' This example connects to the Graph API using the AAD application with ID '00df8f0a-c19b-4c56-83dc-c1aaf622fe64' and the scopes User.Read.All, Group.Read.All, Team.ReadBasic.All. .EXAMPLE Connect-EasyLife365 -Identity This example connects to the Graph API using a managed identity. This can be used in Azure Automation Accounts or Azure Function Apps. Please note that the required permissions must be granted to the managed identity's service principal before. You can use Grant-EasyAppPermissions to grant the required permissions to your service principal. .EXAMPLE Connect-MgGraph -Scopes User.ReadWrite.All, Group.ReadWrite.All, Team.ReadBasic.All This example uses Connect-MgGraph to connect to the Graph API. You can use existing Graph contexts as long as they contain the required scopes. #> [CmdletBinding(DefaultParameterSetName='byClientIdAndScope', HelpUri = 'https://docs.easylife365.cloud/docs/add-ons/powershell/connect-easylife365/')] param ( [Parameter(ParameterSetName='byIdentity')] [switch] $Identity, [Parameter(ParameterSetName='byClientIdAndScope')] [string]$ClientId = $elPowerShellClientId, [Parameter(ParameterSetName='byClientIdAndScope')] [string[]]$Scopes = @('User.ReadWrite.All', 'Group.ReadWrite.All', 'Team.ReadBasic.All') ) begin { $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName } process { # v2 of the graph api will have an -identity switch for connect-mggraph, until then we need to work around like this if($Identity){ $null = Connect-AzAccount -Identity $token = (Get-AzAccessToken -ResourceTypeName MSGraph).Token $graphParam = @{ AccessToken = $token } } else { $graphParam = @{ ClientId = $ClientId Scopes = $Scopes } } Write-Verbose "Invoking Connect-MgGraph with $($graphParam | ConvertTo-Json -Compress)" Connect-MgGraph @graphParam | Out-Null if($?){ $ctx = Get-MgContext Write-Information "`r`nWelcome to EasyLife $($ctx.Account), you are connected to the tenant $($ctx.TenantId) via $($ctx.AppName) with ClientId $($ctx.ClientId).`r`n" -InformationAction Continue } Test-EasyLife365ModuleVersion $sw.Stop() $diag.data.baseData.properties.duration = $sw.ElapsedMilliseconds $diag.data.baseData.properties.commandLine = $MyInvocation.Line Send-EasyTelemetryEvent -Body $diag } } #endregion Connect-EasyLife365 #region Get-EasyGroup function Get-EasyGroup { <# .SYNOPSIS Get EasyLife Unified Groups from the Graph API. .DESCRIPTION This function uses Get-MgGroup to retrieve Unified Groups from the Graph API. It expands properties relevant to EasyLife such as policy states and metadata. .NOTES None. .LINK https://docs.easylife365.cloud/docs/add-ons/powershell/get-easygroup/ .INPUTS None You cannot pipe values to this cmdlet. .OUTPUTS [ELGroup] This function returns object of the type ELGroup. .PARAMETER Id Use this parameter to retrieve a group with the specified Id. .PARAMETER All Use this parameter to retrieve all unified groups. .PARAMETER Top Use this parameter to retrieve the specified number of groups. .PARAMETER DisplayName Use this parameter to retrieve groups that have a DisplayName that starts with the given value. .PARAMETER PropertySet Use this parameter to select a set of attributes to be retrieved from the Graph API. This can be useful for automation or when dealing with a large number of objects. Currently, the only available set it Minimum. .EXAMPLE Get-EasyGroup This example returns up to 100 groups and their properties. .EXAMPLE Get-EasyGroup -All This example returns all groups and their properties. .EXAMPLE Get-EasyGroup -Top 3 This example returns 3 groups and their properties. .EXAMPLE Get-EasyGroup -DisplayName Project This example returns all groups that have a DisplayName that starts with Project. .EXAMPLE Get-EasyGroup -All -PropertySet Minimum This example returns all groups with a minimum set of attributes that can be retrieved quickly. The resulting objects will not have the Owners property populated. #> [CmdletBinding(DefaultParameterSetName='byDisplayName', HelpUri = 'https://docs.easylife365.cloud/docs/add-ons/powershell/get-easygroup/')] [OutputType([ELGroup])] param ( [Parameter(ParameterSetName='byId')] [ValidateNotNullOrEmpty()] [string]$Id, [Parameter(ParameterSetName='byDisplayName')] [ValidateNotNullOrEmpty()] [string]$DisplayName, [Parameter(ParameterSetName='byDisplayName')] [Parameter(ParameterSetName='all')] [int]$Top, [Parameter(ParameterSetName='all')] [switch]$All, [Parameter()] [ValidateSet('Minimum')] $PropertySet ) begin { $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName } process{ $mgGroupParam = @{ Filter = "groupTypes/any(c:c eq 'Unified')" Select = 'id','displayName','description','mail','groupTypes','extensions','createdDateTime','mailNickname','visibility' ExpandProperty = "extensions,Owners(`$select=userPrincipalName)" } switch($PSBoundParameters.Keys){ 'Id' { $mgGroupParam.Remove('Filter') $mgGroupParam.Add('GroupId',$Id) } 'DisplayName' { $mgGroupParam.Filter += " and startsWith(DisplayName,'$DisplayName')" } 'Top' { $mgGroupParam.add('Top',$Top) } 'All' { $mgGroupParam.add('All',([switch]::Present)) } 'PropertySet' { switch($PropertySet){ 'Minimum' { $mgGroupParam.ExpandProperty = "extensions" } } } } Write-Verbose "Invoking Get-MgGroup with $($mgGroupParam | ConvertTo-Json -Compress)" Get-MgGroup @mgGroupParam | ForEach-Object { [ELGroup]::new($_,[bool]$SkipOwners) } } end { $sw.Stop() $diag.data.baseData.properties.duration = $sw.ElapsedMilliseconds $diag.data.baseData.properties.commandLine = $MyInvocation.Line Send-EasyTelemetryEvent -Body $diag } } #endregion Get-EasyGroup #region Get-EasyGuestUser function Get-EasyGuestUser { <# .SYNOPSIS Get EasyLife guest user accounts from the Graph API. .DESCRIPTION This function uses Get-MgUser to retrieve guest user accounts from the Graph API. It expands properties relevant to EasyLife such as owners and metadata. .NOTES None. .LINK https://docs.easylife365.cloud/docs/add-ons/powershell/get-easyguestuser/ .INPUTS None You cannot pipe values to this cmdlet. .OUTPUTS [ELGuestUser] This function returns object of the type ELGuestUser. .EXAMPLE Get-EasyGuestUser This example returns up to 100 guest user accounts and their properties. .EXAMPLE Get-EasyGuestUser -All This example returns all guest user accounts and their properties. .EXAMPLE Get-EasyGuestUser -Top 3 This example returns 3 guest user accounts and their properties. .EXAMPLE Get-EasyGuestUser -DisplayName Thomas This example returns all guest user accounts that have a DisplayName that starts with Thomas. .EXAMPLE Get-EasyGuestUser -All -PropertySet Minimum This example returns all guest user accounts with a minimum set of attributes that can be retrieved quickly. The resulting objects will contain the owner's object id instead of the owner's user principal name. #> [CmdletBinding(DefaultParameterSetName='byDisplayName', HelpUri = 'https://docs.easylife365.cloud/docs/add-ons/powershell/get-easyguestuser/')] [OutputType([ELGuestUser])] param ( [Parameter(ParameterSetName='byId')] [ValidateNotNullOrEmpty()] [string]$Id, [Parameter(ParameterSetName='byDisplayName')] [ValidateNotNullOrEmpty()] [string]$DisplayName, [Parameter(ParameterSetName='byDisplayName')] [Parameter(ParameterSetName='all')] [int]$Top, [Parameter(ParameterSetName='all')] [switch]$All, [Parameter()] [ValidateSet('Minimum')] $PropertySet ) begin { $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName $mgUserParam = @{ Filter = "userType eq 'Guest'" ExpandProperty = "extensions" Select = 'id','displayName','GivenName','Surname','CompanyName','mail','accountEnabled',$script:elUserExtension,'externalUserState','externalUserStateChangeDateTime','createdDateTime' } switch($PSBoundParameters.Keys){ 'Id' { $mgUserParam.Remove('Filter') $mgUserParam.Add('UserId',$Id) } 'DisplayName' { $mgUserParam.Filter += " and startsWith(DisplayName,'$DisplayName')" } 'Top' { $mgUserParam.add('Top',$Top) } 'All' { $mgUserParam.add('All',([switch]::Present)) } 'PropertySet' { switch($PropertySet){ 'Minimum' { $fastMode = $true } Default { $fastMode = $false } } } } } process { Write-Verbose "Invoking Get-MgUser with $($mgUserParam | ConvertTo-Json -Compress)" Get-MgUser @mgUserParam | ForEach-Object { [ELGuestUser]::new($_,$fastMode) } } end { $sw.stop() $diag.data.baseData.properties.duration = $sw.ElapsedMilliseconds $diag.data.baseData.properties.commandLine = $MyInvocation.Line Send-EasyTelemetryEvent -Body $diag } } #endregion Get-EasyGuestUser #region Get-EasyTeam function Get-EasyTeam { <# .SYNOPSIS Get EasyLife Teams from the Graph API. .DESCRIPTION This function uses Get-MgGroup and Get-MgTeam to retrieve Teams from the Graph API. It expands properties relevant to EasyLife such as policy states and metadata. .NOTES This function makes two requests to the Graph API for each Team, hence it is slower than Get-EasyGroup. .LINK https://docs.easylife365.cloud/docs/add-ons/powershell/get-easyTeam/ .INPUTS None You cannot pipe values to this cmdlet. .OUTPUTS [ELTeam] This function returns object of the type ELTeam. .PARAMETER Id Use this parameter to retrieve a teams with the specified Id. .PARAMETER All Use this parameter to retrieve all unified teams. .PARAMETER Top Use this parameter to retrieve the specified number of teams. .PARAMETER DisplayName Use this parameter to retrieve teams that have a DisplayName that starts with the given value. .EXAMPLE Get-EasyTeam This example returns up to 100 Teams and their properties. .EXAMPLE Get-EasyTeam -All This example returns all Teams and their properties. .EXAMPLE Get-EasyTeam -Top 3 This example returns 3 Teams and their properties. .EXAMPLE Get-EasyTeam -DisplayName Project This example returns all Teams that have a DisplayName that starts with Project. .EXAMPLE Get-EasyTeam -All -PropertySet Minimum This example returns all Teams with a minimum set of attributes that can be retrieved quickly. The resulting objects will not have the Owners and WebUrl properties populated. #> [CmdletBinding(DefaultParameterSetName='byDisplayName', HelpUri = 'https://docs.easylife365.cloud/docs/add-ons/powershell/get-easyTeam/')] [OutputType([ELTeam])] param ( [Parameter(ParameterSetName='byId')] [ValidateNotNullOrEmpty()] [string]$Id, [Parameter(ParameterSetName='byDisplayName')] [ValidateNotNullOrEmpty()] [string]$DisplayName, [Parameter(ParameterSetName='byDisplayName')] [Parameter(ParameterSetName='all')] [int]$Top, [Parameter(ParameterSetName='all')] [switch]$All, [Parameter()] [ValidateSet('Minimum')] $PropertySet ) begin { $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName } process{ $mgGroupParam = @{ Filter = "groupTypes/any(c:c eq 'Unified') and resourceProvisioningOptions/Any(x:x eq 'Team')" Select = 'id','displayName','description','mail','groupTypes','extensions','createdDateTime','mailNickname','visibility' ExpandProperty = "extensions,Owners(`$select=userPrincipalName)" } switch($PSBoundParameters.Keys){ 'Id' { $mgGroupParam.Remove('Filter') $mgGroupParam.Add('GroupId',$Id) } 'DisplayName' { $mgGroupParam.Filter += " and startsWith(DisplayName,'$DisplayName')" } 'Top' { $mgGroupParam.add('Top',$Top) } 'All' { $mgGroupParam.add('All',([switch]::Present)) } 'PropertySet' { switch($PropertySet){ 'Minimum' { $mgGroupParam.ExpandProperty = "extensions(`$filter = startsWith(id, 'cloud.easyLife'))" $fastMode = $true } Default { $fastMode = $false } } } } Write-Verbose "Invoking Get-MgGroup with $($mgGroupParam | ConvertTo-Json -Compress)" Get-MgGroup @mgGroupParam | ForEach-Object { $mgGroup = $_ $mgTeam = if($fastMode) {$null} else {Get-MgTeam -TeamId $_.id} [ELTeam]::new($mgGroup, $mgTeam, $fastMode) } } end { $sw.Stop() $diag.data.baseData.properties.duration = $sw.ElapsedMilliseconds $diag.data.baseData.properties.commandLine = $MyInvocation.Line Send-EasyTelemetryEvent -Body $diag } } #endregion Get-EasyTeam #region Grant-EasyAppPermissions function Grant-EasyAppPermissions { <# .SYNOPSIS Grant reqiured Graph API permissions to service principals. .DESCRIPTION This function uses New-MgServicePrincipalAppRoleAssignedTo to assign all required application permissions for the EasyLife365.Collaboration module to a service principal in your Azure Active Directory. You can use this function to grant required permissions to managed identities of Azure Automation Accounts for Function Apps that run the EasyLife365.Collabotration powershell module and use Connect-EasyLife365 -Identity to sign in. .NOTES This function requires the scopes AppRoleAssignment.ReadWrite.All and Application.Read.All only during setup. These application permissions will not be granted to the service principal. You can find the ServicePrincipalId in the Identity tab of the Automation Account or Function App in the Azure Portal. .LINK https://docs.easylife365.cloud/docs/add-ons/powershell/grant-easyapppermissions/ .INPUTS None You cannot pipe values to this cmdlet. .OUTPUTS [MicrosoftGraphAppRoleAssignment] This function returns object of the type MicrosoftGraphAppRoleAssignment. .PARAMETER ServicePrincipalId Use this parameter to specify the object id of the service principal that will be granted permissions. .PARAMETER AppRoles Use this parameter to specify which application permissions shall be granted to the service principal. Use 'Read' to grant User.Read.All, Group.Read.All, Team.ReadBasic.All. Use 'Write' to grant User.ReadWrite.All, Group.ReadWrite.All, Team.ReadBasic.All. Use a custom set of permissions by specifying the name of each application permission like this: 'Group.ReadWrite.All', 'Team.ReadBasic.All'. .EXAMPLE Grant-EasyAppPermissions -ServicePrincipalId da9ea79a-55d4-463f-b1a2-4b5ab1060909 This example grants the application permissions User.Read.All, Group.Read.All, Team.ReadBasic.All to the service principal with the id da9ea79a-55d4-463f-b1a2-4b5ab1060909. .EXAMPLE Grant-EasyAppPermissions -ServicePrincipalId da9ea79a-55d4-463f-b1a2-4b5ab1060909 -AppRoles Write This example grants the application permissions User.ReadWrite.All, Group.ReadWrite.All, Team.ReadBasic.All to the service principal with the id da9ea79a-55d4-463f-b1a2-4b5ab1060909. .EXAMPLE Grant-EasyAppPermissions -ServicePrincipalId da9ea79a-55d4-463f-b1a2-4b5ab1060909 -AppRoles 'User.ReadWrite.All', 'Group.ReadWrite.All', 'Team.ReadBasic.All', 'Application.Read.All This example grants a custom set of application permissions to the service principal with the id da9ea79a-55d4-463f-b1a2-4b5ab1060909. #> [CmdletBinding(SupportsShouldProcess,HelpUri='https://docs.easylife365.cloud/docs/add-ons/powershell/grant-easyapppermissions/')] param ( [Parameter(Mandatory)] [guid]$ServicePrincipalId, [string[]]$AppRoles = "Read" ) process { $modules = Get-Module Microsoft.Graph.Authentication,Microsoft.Graph.Applications -ListAvailable if($modules.Count -ge 2){ Write-Information "Found Graph Modules, importing" -InformationAction Continue Import-Module Microsoft.Graph.Authentication,Microsoft.Graph.Applications } else { Write-Warning "Could not find Graph Modules, please install with the following command:`r`nInstall-Module Microsoft.Graph.Authentication,Microsoft.Graph.Applications" return } # we need to have the scope Application.Read.All otherwise Get-MgServicePrincipal will fail $ctx = Get-MgContext $ctxScopes = $ctx.Scopes if($ctxScopes -notcontains 'AppRoleAssignment.ReadWrite.All' -and $ctxScopes -notcontains 'Application.Read.All') { Write-Warning "Graph Context does not have all required scopes, please connect with the following command:`r`nConnect-MgGraph -Scopes AppRoleAssignment.ReadWrite.All, Application.Read.All" return } else { Write-Information "Using existing Graph context with account $($ctx.Account)" -InformationAction Continue } # get microsoft graph enterprise application, it holds all the roles and we need its object id $graphObject = Get-MgServicePrincipal -Filter "DisplayName eq 'Microsoft Graph'" switch($AppRoles){ 'Read' { $appRolesWithId = Get-EasyAppRoleId -graphObject $graphObject -AppRoles $elRequiredScopes.Get } 'Write' { $appRolesWithId = Get-EasyAppRoleId -graphObject $graphObject -AppRoles $elRequiredScopes.Set } Default { $appRolesWithId = Get-EasyAppRoleId -graphObject $graphObject -AppRoles $AppRoles } } # once we have the ids of the application permissions, we grant them to the service principal $appRolesWithId | ForEach-Object { Write-Verbose "Granting permission [$($_.Value)] to service principal [$servicePrincipalId]" $params = @{ ServicePrincipalId = $servicePrincipalId PrincipalId = $servicePrincipalId ResourceId = $graphObject.Id AppRoleId = $_.Id } if ($PSCmdlet.ShouldProcess($servicePrincipalId, "Add permission $($_.Id)")) { New-MgServicePrincipalAppRoleAssignedTo @params | Select-Object PrincipalDisplayName,PrincipalId,AppRoleId } } } } #endregion Grant-EasyAppPermissions |