EasyLife365.psm1
#region _classes class EL { [string]$Id [string]$DisplayName [object]$Metadata [guid]$TemplateId [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 = [guid]::Empty 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 } } } class ELGuestUser : EL { [string]$PrimaryOwner [string]$SecondaryOwner [string]$Mail [string]$CompanyName [string]$GivenName [string]$Surname [bool]$IsCompliant [string]$AccountDisabledState [string]$AccountDisabledDate [string]$AccountDisabledStepChange [string]$AccountDisabledStep [string]$NoOwnersEscalation [string]$MinimumOwnerStepChange [string]$MinimumOwnerStep [string]$MinimumOwnerState [string]$ConfirmationStepChange [string]$ConfirmationStep [string]$ConfirmationState [string]$ConfirmationDate [string]$InactivityStepChange [string]$InactivityStep [string]$InactivityState [string]$InactivityDate [string]$InvitationStepChange [string]$InvitationStep [string]$InvitationState [string]$InvitationDate [string]$NamingState [string]$ClassificationState [string]$ClassificationDate [string]$ClassificationStepChange [string]$ClassificationStep ELGuestUser ([object] $elGuestUser) : base($elGuestUser) { $this.Mail = $elGuestUser.Mail $this.CompanyName = $elGuestUser.CompanyName $this.GivenName = $elGuestUser.GivenName $this.Surname = $elGuestUser.Surname $pOwner = $elGuestUser.AdditionalProperties.easylife365_usermetadata.primaryOwner $sOwner = $elGuestUser.AdditionalProperties.easylife365_usermetadata.secondaryOwner if($pOwner){ $this.PrimaryOwner = (Get-MgUser -UserId $pOwner -Select UserPrincipalName).UserPrincipalName } if($sOwner){ $this.SecondaryOwner = (Get-MgUser -UserId $sOwner -Select UserPrincipalName).UserPrincipalName } $this.IsCompliant = $elGuestUser.AdditionalProperties.easylife365_usermetadata.isCompliant $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 [bool]$IsArchived [string[]]$GroupTypes [string[]]$Owner [string]$AccessReviewPolicyState [string]$AccessReviewPolicyChanged [string]$ConfirmationPolicyState [string]$ConfirmationPolicyChanged [string]$ExpirationPolicyState [string]$ExpirationPolicyChanged [string]$OwnerPolicyState [string]$OwnerPolicyChanged [string]$NoOwnerEscalation ELGroup ([object] $ELGroup) : base($ELGroup) { $this.Description = $ELGroup.Description $this.Mail = $ELGroup.Mail $this.GroupTypes = $ELGroup.GroupTypes $this.Owner = $ELGroup | Get-EasyGroupOwner $this.AccessReviewPolicyState = $this.Policy.arSta $this.AccessReviewPolicyChanged = $this.Policy.arCh $this.ConfirmationPolicyState = $this.Policy.coSta $this.ConfirmationPolicyChanged = $this.Policy.coCh $this.ExpirationPolicyState = $this.Policy.exSta $this.ExpirationPolicyChanged = $this.Policy.exCh $this.OwnerPolicyState = $this.Policy.owSta $this.OwnerPolicyChanged = $this.Policy.owCh $this.NoOwnerEscalation = $this.Policy.noEsca $this.IsArchived = $this.Policy.isArchived } } class ELTelemetry { [string]$name = 'Microsoft.ApplicationInsights.Event' [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-EasyGroup' = @('User.ReadWrite.All', 'Group.ReadWrite.All') 'Get-EasyTeam' = @('User.ReadWrite.All', 'Group.ReadWrite.All') 'Get-EasyGuestUser' = @('User.ReadWrite.All', 'Group.ReadWrite.All') } #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-EasyGroupOwner function Get-EasyGroupOwner { [CmdletBinding()] param ( [Parameter(ValueFromPipeline)] [object] $inputObject ) process { $ownerProperty = (Get-MgGroupOwner -GroupId $InputObject.id -select userPrincipalName).AdditionalProperties if($ownerProperty){ $ownerProperty | ForEach-Object { (New-Object -TypeName pscustomobject -Property $_).userPrincipalName } } } } #endregion Get-EasyGroupOwner #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 Send-EasyTelemetryEvent function Send-EasyTelemetryEvent { [CmdletBinding()] param( [string] $IngestionEndpoint = 'https://westeurope-5.in.applicationinsights.azure.com', [ELTelemetry] $Body, [switch] $PassThru ) process { if($EasyLife365DisableTelemetry){ 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 ) begin { Test-EasyCmdletRequieredScopes -cmdlet $MyInvocation.InvocationName } 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 ) begin { Test-EasyCmdletRequieredScopes -cmdlet $MyInvocation.InvocationName } 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-EasyCmdletRequieredScopes function Test-EasyCmdletRequieredScopes { [CmdletBinding()] param ( $cmdlet ) process { $scopes = (Get-MgContext).Scopes $requiredScopes = $elRequiredScopes[$cmdlet] $requiredScopes.foreach{ if($scopes -notcontains $_){ Write-Warning "Please connect to Microsoft Graph with the following scopes: $($requiredScopes -join ', ')" break } } } } #endregion Test-EasyCmdletRequieredScopes #region Test-EasyLife365ModuleVersion $findLatestModule = Start-Job -Scriptblock { Find-Module -Name EasyLife365 -Repository PSGallery } function Test-EasyLife365ModuleVersion { [CmdletBinding()] param() process { $importedModule = Get-Module EasyLife365 $latestModule = $findLatestModule | Wait-Job | Receive-Job -Keep $latestVersion = $latestModule.version $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 [$($latestModule.Version)] by typing: Update-Module EasyLife365`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/ .EXAMPLE Connect-EasyLife365 This example connects to the Graph API using the scopes User.ReadWrite.All, Group.ReadWrite.All. #> [CmdletBinding(HelpUri = 'https://docs.easylife365.cloud/docs/add-ons/powershell/connect-easylife365/')] param ( [Parameter()] [switch] $Identity ) begin { $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName } process { $graphParam = @{ ApplicationId = $elPowerShellClientId } if($Identity){ $graphParam.add('Identity',[switch]::present) } else { $graphParam.add('scopes', 'User.ReadWrite.All, Group.ReadWrite.All') } Connect-MgGraph @graphParam 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 groups from the Graph API. .DESCRIPTION This function uses Get-MgGroup to retrieve groups from the Graph API. It expands properties relevant to EasyLife such as policy states and metadata. .NOTES If you use the alias Get-EasyTeam to invoke this function, the filter is updated and only Groups with resourceProvisioningOptions set to Team are returned. .LINK https://docs.easylife365.cloud/docs/add-ons/powershell/get-easygroup/ .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. #> [CmdletBinding(DefaultParameterSetName='byDisplayName', HelpUri = 'https://docs.easylife365.cloud/docs/add-ons/powershell/get-easygroup/')] 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 ) begin { Test-EasyCmdletRequieredScopes -cmdlet $MyInvocation.InvocationName $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName } process{ $mgGroupParam = @{ Filter = "groupTypes/any(c:c eq 'Unified')" ExpandProperty = "extensions(`$filter = startsWith(id, 'cloud.easyLife'))" Select = 'id','displayName','description','mail','groupTypes','extensions' } # if the alias Get-EasyTeams is used, update filter to only retrieve teams if ($MyInvocation.InvocationName -like 'Get-EasyTeam') { $mgGroupParam.Filter += " and resourceProvisioningOptions/Any(x:x eq 'Team')" } if($Id){ $mgGroupParam.Remove('Filter') $mgGroupParam.Add('GroupId',$Id) } if($DisplayName){ $mgGroupParam.Filter += " and startsWith(DisplayName,'$DisplayName')" } if($Top){ $mgGroupParam.add('Top',$Top) } if($All){ $mgGroupParam.add('All',([switch]::Present)) } Write-Verbose "Invoking Get-MgGroup with $($mgGroupParam | ConvertTo-Json -Compress)" Get-MgGroup @mgGroupParam | ForEach-Object { [ELGroup]::new($_) } } end { $sw.Stop() $diag.data.baseData.properties.duration = $sw.ElapsedMilliseconds $diag.data.baseData.properties.commandLine = $MyInvocation.Line Send-EasyTelemetryEvent -Body $diag } } New-Alias -Name Get-EasyTeam -Value Get-EasyGroup #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/ .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. #> [CmdletBinding(DefaultParameterSetName='byDisplayName', HelpUri = 'https://docs.easylife365.cloud/docs/add-ons/powershell/get-easyguestuser/')] 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 ) begin { Test-EasyCmdletRequieredScopes -cmdlet $MyInvocation.InvocationName $sw,$diag = Start-EasyDiagnostics -Name $MyInvocation.InvocationName $mgUserParam = @{ Filter = "userType eq 'Guest'" ExpandProperty = "extensions(`$filter = startsWith(id, 'cloud.easyLife'))" Select = 'id','displayName','GivenName','Surname','CompanyName','mail','accountEnabled','easylife365_usermetadata','externalUserState','externalUserStateChangeDateTime','createdDateTime' } if($Id){ $mgUserParam.Remove('Filter') $mgUserParam.Add('UserId',$Id) } if($DisplayName){ $mgUserParam.Filter += " and startsWith(DisplayName,'$DisplayName')" } if($all){ $mgUserParam.add('All',[switch]::Present) } if($top){ $mgUserParam.add('Top',$Top) } } process { Write-Verbose "Invoking Get-MgUser with $($mgUserParam | ConvertTo-Json -Compress)" Get-MgUser @mgUserParam | ForEach-Object { [ELGuestUser]::new($_) } } end { $sw.stop() $diag.data.baseData.properties.duration = $sw.ElapsedMilliseconds $diag.data.baseData.properties.commandLine = $MyInvocation.Line Send-EasyTelemetryEvent -Body $diag } } #endregion Get-EasyGuestUser |