From 299bab324de22143a56f85b200d4067d7410a45f Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Wed, 4 Nov 2020 22:17:09 +0100 Subject: [PATCH 01/33] beta version --- .../MSFT_AADConditionalAccessPolicy.psm1 | 1035 +++++++++++++++++ ...MSFT_AADConditionalAccessPolicy.schema.mof | 39 + .../MSFT_AADConditionalAccessPolicy/Readme.md | 16 + 3 files changed, 1090 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/Readme.md diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 new file mode 100644 index 0000000000..a8a91635ff --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -0,0 +1,1035 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.String] + [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] + $State, + + #ConditionalAccessApplicationCondition + [Parameter()] + [System.String[]] + $IncludeApplications, + + [Parameter()] + [System.String[]] + $ExcludeApplications, + + [Parameter()] + [System.String[]] + $IncludeUserActions, + + #[Parameter()] + #[System.String[]] + #$IncludeProtectionLevels, + #not exposed yet + + #ConditionalAccessUserCondition + [Parameter()] + [System.String[]] + $IncludeUsers, + + [Parameter()] + [System.String[]] + $ExcludeUsers, + + [Parameter()] + [System.String[]] + $IncludeGroups, + + [Parameter()] + [System.String[]] + $ExcludeGroups, + + [Parameter()] + [System.String[]] + $IncludeRoles, + + [Parameter()] + [System.String[]] + $ExcludeRoles, + + #ConditionalAccessPlatformCondition + [Parameter()] + [System.String[]] + $IncludePlatforms, + + [Parameter()] + [System.String[]] + $ExcludePlatforms, + + #ConditionalAccessLocationCondition + [Parameter()] + [System.String[]] + $IncludeLocations, + + [Parameter()] + [System.String[]] + $ExcludeLocations, + + #ConditionalAccessDevicesCondition + [Parameter()] + [System.String[]] + $IncludeDeviceStates, + + [Parameter()] + [System.String[]] + $ExcludeDeviceStates, + + #Further conditions + [Parameter()] + [System.String[]] + $UserRiskLevels, + + [Parameter()] + [System.String[]] + $SignInRiskLevels, + + [Parameter()] + [System.String[]] + $ClientAppTypes, + + #ConditionalAccessGrantControls + [Parameter()] + [ValidateSet('AND', 'OR')] + [System.String] + $GrantControl_Operator, + + [Parameter()] + [System.String[]] + $BuiltInControls, + + #[Parameter()] + #[System.String[]] + #$CustomAuthenticationFactors, + #not exposed yet + + #[Parameter()] + #[System.String[]] + #$TermsOfUse, + #not exposed yet + + #ConditionalAccessSessionControls + [Parameter()] + [System.Boolean] + $ApplicationEnforcedRestrictions_IsEnabled, + + [Parameter()] + [System.Boolean] + $CloudAppSecurity_IsEnabled, + + [Parameter()] + [System.String] + $CloudAppSecurity_Type, + + [Parameter()] + [System.Int32] + $SignInFrequency_Value, + + [Parameter()] + [ValidateSet('Days', 'Hours')] + [System.String] + $SignInFrequency_Type, + + [Parameter()] + [System.Boolean] + $SignInFrequency_IsEnabled, + + [Parameter()] + [ValidateSet('Always', 'Never')] + [System.String] + $PersistentBrowser_Mode, + + [Parameter()] + [System.Boolean] + $PersistentBrowser_IsEnabled, + + #generic + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $GlobalAdminAccount, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + + Write-Verbose -Message "Getting configuration of AzureAD Conditional Access Policy" + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") + $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() + $data.Add("Resource", $ResourceName) + $data.Add("Method", $MyInvocation.MyCommand) + $data.Add("Principal", $GlobalAdminAccount.UserName) + $data.Add("TenantId", $TenantId) + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $ConnectionMode = New-M365DSCConnection -Platform 'AzureAD' -InboundParameters $PSBoundParameters + + if ($PSBoundParameters.ContainsKey("Id")) + { + Write-Verbose -Message "PolicyID was specified" + try + { + $Policy = Get-AzureADMSConditionalAccessPolicy -PolicyId $Id + } + catch + { + $Policy = Get-AzureADMSConditionalAccessPolicy | Where-Object { $_.DisplayName -eq $DisplayName} + if ($Policy.Length -gt 1) + { + throw "Duplicate CA Policies named $DisplayName exist in tenant" + } + } + } + else + { + Write-Verbose -Message "Id was NOT specified" + ## Can retreive multiple CA Policies since displayname is not unique + $Policy = Get-AzureADMSConditionalAccessPolicy | Where-Object { $_.DisplayName -eq $DisplayName} + if ($Policy.Length -gt 1) + { + throw "Duplicate CA Policies named $DisplayName exist in tenant" + } + } + + if ($null -eq $Policy) + { + $currentValues = $PSBoundParameters + $currentValues.Ensure = "Absent" + return $currentValues + } + else + { + Write-Verbose -Message "Found existing Conditional Access policy" + + $result = @{ + DisplayName = $Policy.DisplayName + Id = $Policy.Id + State = $Policy.State + IncludeApplications = [System.String[]]$Policy.Conditions.Applications.IncludeApplications#no translation of GUIDs + ExcludeApplications = [System.String[]]$Policy.Conditions.Applications.ExcludeApplications#no translation of GUIDs + IncludeUserActions = [System.String[]]$Policy.Conditions.Applications.IncludeUserActions#no translation needed + #IncludeProtectionLevels = [System.String[]]$Policy.Conditions.Applications.IncludeProtectionLevels + IncludeUsers = $Policy.Conditions.Users.IncludeUsers | ForEach-Object { if($_ -notmatch 'GuestsOrExternalUsers|All' -and $_){ (Get-AzureADUser -ObjectId $_).userprincipalname} else {$_}}#translate user GUIDs to UPN, except id value is GuestsOrExternalUsers or All + ExcludeUsers = $Policy.Conditions.Users.ExcludeUsers | ForEach-Object { if($_ -notmatch 'GuestsOrExternalUsers|All' -and $_){ (Get-AzureADUser -ObjectId $_).userprincipalname} else {$_}}#translate user GUIDs to UPN, except id value is GuestsOrExternalUsers or All + IncludeGroups = $policy.Conditions.Users.IncludeGroups | ForEach-Object { if($_){(Get-AzureADGroup -ObjectId $_).displayname}}#convert Group GUIDs to displayname + ExcludeGroups = $Policy.Conditions.Users.ExcludeGroups | ForEach-Object { if($_){(Get-AzureADGroup -ObjectId $_).displayname}}#convert Group GUIDs to displayname + IncludeRoles = if($Policy.Conditions.Users.IncludeRoles)#translate role template guids to role name + { + $rolelookup=@{} + Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.ObjectId]=$_.DisplayName} + $Policy.Conditions.Users.IncludeRoles | ForEach-Object {$rolelookup[$_]} + } + else {$null} + + ExcludeRoles = if($Policy.Conditions.Users.ExcludeRoles)#translate role template guids to role name + { + $rolelookup=@{} + Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.ObjectId]=$_.DisplayName} + $Policy.Conditions.Users.ExcludeRoles | ForEach-Object {$rolelookup[$_]} + } + else {$null} + + IncludePlatforms = [System.String[]]$Policy.Conditions.Platforms.IncludePlatforms#no translation needed + ExcludePlatforms = [System.String[]]$Policy.Conditions.Platforms.ExcludePlatforms#no translation needed + IncludeLocations = $Policy.Conditions.Locations.IncludeLocations | ForEach-Object { if($_ -notmatch 'All' -and $_){ (Get-AzureADMSNamedLocationPolicy -PolicyId $_).DisplayName} else {$_}}#translate location GUIDs to Displayname, except if value is All or AllTrusted + ExcludeLocations = $Policy.Conditions.Locations.ExcludeLocations | ForEach-Object { if($_ -notmatch 'All' -and $_){ (Get-AzureADMSNamedLocationPolicy -PolicyId $_).DisplayName} else {$_}}#translate location GUIDs to Displayname, except if value is All or AllTrusted + IncludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.IncludeDeviceStates#no translation needed + ExcludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.ExcludeDeviceStates#no translation needed + UserRiskLevels = [System.String[]]$Policy.Conditions.UserRiskLevels#no translation needed + SignInRiskLevels = [System.String[]]$Policy.Conditions.SignInRiskLevels#no translation needed + ClientAppTypes = [System.String[]]$Policy.Conditions.ClientAppTypes#no translation needed + GrantControl_Operator = $Policy.GrantControls._Operator#no translation or conversion needed + BuiltInControls = [System.String[]]$Policy.GrantControls.BuiltInControls#no translation needed + ApplicationEnforcedRestrictions_IsEnabled = $Policy.SessionControls.ApplicationEnforcedRestrictions.IsEnabled#no translation or conversion needed + CloudAppSecurity_IsEnabled = $Policy.SessionControls.CloudAppSecurity.IsEnabled#no translation or conversion needed + CloudAppSecurity_Type = [System.String]$Policy.SessionControls.CloudAppSecurity.CloudAppSecurityType#no translation needed + SignInFrequency_Value = $Policy.SessionControls.SignInFrequency.Value#no translation or conversion needed + SignInFrequency_Type = [System.String]$Policy.SessionControls.SignInFrequency.Type#no translation needed + SignInFrequency_IsEnabled = $Policy.SessionControls.SignInFrequency.IsEnabled#no translation or conversion needed + PersistentBrowser_Mode = [System.String]$Policy.SessionControls.PersistentBrowser.Mode#no translation needed + PersistentBrowser_IsEnabled = $Policy.SessionControls.PersistentBrowser.IsEnabled#no translation or conversion needed +#Standard part + Ensure = "Present" + GlobalAdminAccount = $GlobalAdminAccount + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + Write-Verbose -Message "Get-TargetResource Result: `n $(Convert-M365DscHashtableToString -Hashtable $result)" + return $result + } + +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] + [System.String] + $State, + + #ConditionalAccessApplicationCondition + [Parameter()] + [System.String[]] + $IncludeApplications, + + [Parameter()] + [System.String[]] + $ExcludeApplications, + + [Parameter()] + [System.String[]] + $IncludeUserActions, + + #[Parameter()] + #[System.String[]] + #$IncludeProtectionLevels, + #not exposed yet + + #ConditionalAccessUserCondition + [Parameter()] + [System.String[]] + $IncludeUsers, + + [Parameter()] + [System.String[]] + $ExcludeUsers, + + [Parameter()] + [System.String[]] + $IncludeGroups, + + [Parameter()] + [System.String[]] + $ExcludeGroups, + + [Parameter()] + [System.String[]] + $IncludeRoles, + + [Parameter()] + [System.String[]] + $ExcludeRoles, + + #ConditionalAccessPlatformCondition + [Parameter()] + [System.String[]] + $IncludePlatforms, + + [Parameter()] + [System.String[]] + $ExcludePlatforms, + + #ConditionalAccessLocationCondition + [Parameter()] + [System.String[]] + $IncludeLocations, + + [Parameter()] + [System.String[]] + $ExcludeLocations, + + #ConditionalAccessDevicesCondition + [Parameter()] + [System.String[]] + $IncludeDeviceStates, + + [Parameter()] + [System.String[]] + $ExcludeDeviceStates, + + #Further conditions + [Parameter()] + [System.String[]] + $UserRiskLevels, + + [Parameter()] + [System.String[]] + $SignInRiskLevels, + + [Parameter()] + [System.String[]] + $ClientAppTypes, + + #ConditionalAccessGrantControls + [Parameter()] + [ValidateSet('AND', 'OR')] + [System.String] + $GrantControl_Operator, + + [Parameter()] + [System.String[]] + $BuiltInControls, + + #[Parameter()] + #[System.String[]] + #$CustomAuthenticationFactors, + #not exposed yet + + #[Parameter()] + #[System.String[]] + #$TermsOfUse, + #not exposed yet + + #ConditionalAccessSessionControls + [Parameter()] + [System.Boolean] + $ApplicationEnforcedRestrictions_IsEnabled, + + [Parameter()] + [System.Boolean] + $CloudAppSecurity_IsEnabled, + + [Parameter()] + [System.String] + $CloudAppSecurity_Type, + + [Parameter()] + [System.Int32] + $SignInFrequency_Value, + + [Parameter()] + [ValidateSet('Days', 'Hours')] + [System.String] + $SignInFrequency_Type, + + [Parameter()] + [System.Boolean] + $SignInFrequency_IsEnabled, + + [Parameter()] + [ValidateSet('Always', 'Never')] + [System.String] + $PersistentBrowser_Mode, + + [Parameter()] + [System.Boolean] + $PersistentBrowser_IsEnabled, + + #generic + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $GlobalAdminAccount, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + + Write-Verbose -Message "Setting configuration of Conditional Access Policies" + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") + $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() + $data.Add("Resource", $ResourceName) + $data.Add("Method", $MyInvocation.MyCommand) + $data.Add("Principal", $GlobalAdminAccount.UserName) + $data.Add("TenantId", $TenantId) + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $currentPolicy = Get-TargetResource @PSBoundParameters + $currentParameters = $PSBoundParameters + $currentParameters.Remove("ApplicationId") + $currentParameters.Remove("TenantId") + $currentParameters.Remove("CertificateThumbprint") + $currentParameters.Remove("GlobalAdminAccount") + $currentParameters.Remove("Ensure") + + if ($Ensure -eq 'Present')#create policy attribute objects + { + $NewParameters=@{} + $NewParameters.Add("DisplayName",$DisplayName) + $NewParameters.Add("State",$State) + #create Conditions object + $conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet + #create and provision Application Condition object + $conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition + $conditions.Applications.IncludeApplications = $IncludeApplications + $conditions.Applications.ExcludeApplications = $ExcludeApplications + $conditions.Applications.IncludeUserActions = $IncludeUserActions + #create and provision User Condition object + $conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition + $IncludeUsers | foreach-object#translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All + { + if($_) + { + if($_ -notmatch 'GuestsOrExternalUsers|All') + { + $user=$null + $user=(Get-AzureADUser -ObjectId $_).ObjectId + if($null -eq $user) + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't find user $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + elseif (condition) + { + $conditions.Users.IncludeUsers += $user + } + } + else + { + $conditions.Users.IncludeUsers += $_ + } + } + } + $ExcludeUsers | foreach-object#translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All + { + if($_) + { + if($_ -notmatch 'GuestsOrExternalUsers|All') + { + $user=$null + $user=(Get-AzureADUser -ObjectId $_).ObjectId + if($null -eq $user) + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't find user $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + elseif (condition) + { + $conditions.Users.ExcludeUsers += $user + } + } + else + { + $conditions.Users.ExcludeUsers += $_ + } + } + } + $IncludeGroups | foreach-object#translate user Group names to GUID + { + if($_) + { + $Group=$null + $Group = Get-AzureADGroup -Filter "DisplayName eq '$_'" + if ($Group.Length -gt 1) + { + New-M365DSCLogEntry -Error $_ -Message "Duplicate group found with displayname $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + elseif($null -eq $Group) + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't find group $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + else + { + $conditions.Users.IncludeGroups += $Group + } + + } + } + $ExcludeGroups | foreach-object#translate user Group names to GUID + { + if($_) + { + $Group=$null + $Group = Get-AzureADGroup -Filter "DisplayName eq '$_'" + if ($Group.Length -gt 1) + { + New-M365DSCLogEntry -Error $_ -Message "Duplicate group found with displayname $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + elseif($null -eq $Group) + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't find group $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + else + { + $conditions.Users.ExcludeGroups += $Group + } + + } + } + if ($IncludeRoles)#translate role names to template guid if defined + { + $rolelookup=@{} + Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.DisplayName]=$_.ObjectId} + $IncludeRoles | foreach-object + { + if($_) + { + if($null -eq $rolelookup[$_]) + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't find role $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + else { + { + $conditions.Users.IncludeRoles += $rolelookup[$_] + } + } + + } + } + } + if ($ExcludeRoles)#translate role names to template guid if defined + { + $rolelookup=@{} + Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.DisplayName]=$_.ObjectId} + $ExcludeRoles | foreach-object + { + if($_) + { + if($null -eq $rolelookup[$_]) + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't find role $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + else { + { + $conditions.Users.ExcludeRoles += $rolelookup[$_] + } + } + + } + } + } + if ($IncludePlatforms -or $ExcludePlatforms)#create and provision Platform condition object if used + { + $conditions.Platforms = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition + $conditions.Platforms.IncludePlatforms=$IncludePlatforms #no translation or conversion needed + $conditions.Platforms.ExcludePlatforms=$ExcludePlatforms#no translation or conversion needed + } + + if ($IncludeLocations -or $ExcludeLocations)#create and provision Location condition object if used, translate Location names to guid + { + $conditions.Locations = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessLocationCondition + $LocationLookup=@{} + Get-AzureADMSNamedLocationPolicy | ForEach-Object {$LocationLookup[$_.DisplayName]=$_.Id} + $IncludeLocations| foreach-object + { + if($_) + { + if($null -eq $LocationLookup[$_]) + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't find Location $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + elseif ($_ -eq "All" -or $_ -eq "AllTrusted") { + $conditions.Locations.IncludeLocations += $_ + } + else { + { + $conditions.Locations.IncludeLocations += $LocationLookup[$_] + } + } + } + $ExcludeLocations| foreach-object + { + if($_) + { + if($null -eq $LocationLookup[$_]) + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't find Location $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + elseif ($_ -eq "All" -or $_ -eq "AllTrusted") { + $conditions.Locations.ExcludeLocations += $_ + } + else { + { + $conditions.Locations.ExcludeLocations += $LocationLookup[$_] + } + } + } + } + } + + + if ($IncludeDeviceStates -or $ExcludeDeviceStates)#create and provision Device condition object if used + { + $conditions.Devices = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessDevicesCondition + $conditions.Devices.IncludeDeviceStates=$IncludeDeviceStates#no translation or conversion needed + $conditions.Devices.ExcludeDeviceStates=$ExcludeDeviceStates#no translation or conversion needed + } + $Conditions.UserRiskLevels = $UserRiskLevels#no translation or conversion needed + $Conditions.SignInRiskLevels = $SignInRiskLevels #no translation or conversion needed + $Conditions.ClientAppTypes = $ClientAppTypes#no translation or conversion needed + + $NewParameters.Add("Conditions",$Conditions)#add all conditions to the parameter list + #create and provision Grant Control object + $GrantControls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls + $GrantControls._Operator = $GrantControl_Operator + $GrantControls.BuiltInControls = $BuiltInControls #no translation or conversion needed + $NewParameters.Add("GrantControls",$GrantControls)#add GrantControls to the parameter list + + if ($ApplicationEnforcedRestrictions_IsEnabled -or $CloudAppSecurity_IsEnabled -or $SignInFrequency_IsEnabled -or $PersistentBrowser_IsEnabled) + { + #create and provision Session Control object if used + $sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSessionControls + if ($ApplicationEnforcedRestrictions_IsEnabled)#create and provision ApplicationEnforcedRestrictions object if used + { + $sessioncontrols.ApplicationEnforcedRestrictions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationEnforcedRestrictions + $sessioncontrols.ApplicationEnforcedRestrictions.IsEnabled = $true + } + if ($CloudAppSecurity_IsEnabled)#create and provision CloudAppSecurity object if used + { + $sessioncontrols.CloudAppSecurity = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessCloudAppSecurity + $sessioncontrols.CloudAppSecurity.IsEnabled=$true + $sessioncontrols.CloudAppSecurity.CloudAppSecurityType=$CloudAppSecurity_Type + } + if ($SignInFrequency_IsEnabled)#create and provision SignInFrequency object if used + { + $sessioncontrols.SignInFrequency = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency + $sessioncontrols.SignInFrequency.IsEnabled =$true + $sessioncontrols.SignInFrequency.Type = $SignInFrequency_Type + $sessioncontrols.SignInFrequency.Value = $SignInFrequency_Value + } + if ($PersistentBrowser_IsEnabled)#create and provision PersistentBrowser object if used + { + $sessioncontrols.PersistentBrowser = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser + $sessioncontrols.PersistentBrowser.IsEnabled =$true + $sessioncontrols.PersistentBrowser.Mode=$PersistentBrowser_Mode + } + $NewParameters.Add("SessionControls",$sessioncontrols)#add SessionControls to the parameter list + } + + + + } + } + if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') + { + $NewParameters.Add("PolicyId",$Id) + try + { + Set-AzureADMSConditionalAccessPolicy @NewParameters + } + catch + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't set policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + } + elseif ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Absent') + { + try + { + New-AzureADMSConditionalAccessPolicy @NewParameters + } + catch + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't create Policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + } + elseif ($Ensure -eq 'Absent' -and $currentPolicy.Ensure -eq 'Present') + { + try + { + Remove-AzureADMSConditionalAccessPolicy -PolicyId $currentPolicy.ID + } + catch + { + New-M365DSCLogEntry -Error $_ -Message "Couldn't delete Policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] + [System.String] + $State, + + #ConditionalAccessApplicationCondition + [Parameter()] + [System.String[]] + $IncludeApplications, + + [Parameter()] + [System.String[]] + $ExcludeApplications, + + [Parameter()] + [System.String[]] + $IncludeUserActions, + + #[Parameter()] + #[System.String[]] + #$IncludeProtectionLevels, + #not exposed yet + + #ConditionalAccessUserCondition + [Parameter()] + [System.String[]] + $IncludeUsers, + + [Parameter()] + [System.String[]] + $ExcludeUsers, + + [Parameter()] + [System.String[]] + $IncludeGroups, + + [Parameter()] + [System.String[]] + $ExcludeGroups, + + [Parameter()] + [System.String[]] + $IncludeRoles, + + [Parameter()] + [System.String[]] + $ExcludeRoles, + + #ConditionalAccessPlatformCondition + [Parameter()] + [System.String[]] + $IncludePlatforms, + + [Parameter()] + [System.String[]] + $ExcludePlatforms, + + #ConditionalAccessLocationCondition + [Parameter()] + [System.String[]] + $IncludeLocations, + + [Parameter()] + [System.String[]] + $ExcludeLocations, + + #ConditionalAccessDevicesCondition + [Parameter()] + [System.String[]] + $IncludeDeviceStates, + + [Parameter()] + [System.String[]] + $ExcludeDeviceStates, + + #Further conditions + [Parameter()] + [System.String[]] + $UserRiskLevels, + + [Parameter()] + [System.String[]] + $SignInRiskLevels, + + [Parameter()] + [System.String[]] + $ClientAppTypes, + + #ConditionalAccessGrantControls + [Parameter()] + [ValidateSet('AND', 'OR')] + [System.String] + $GrantControl_Operator, + + [Parameter()] + [System.String[]] + $BuiltInControls, + + #[Parameter()] + #[System.String[]] + #$CustomAuthenticationFactors, + #not exposed yet + + #[Parameter()] + #[System.String[]] + #$TermsOfUse, + #not exposed yet + + #ConditionalAccessSessionControls + [Parameter()] + [System.Boolean] + $ApplicationEnforcedRestrictions_IsEnabled, + + [Parameter()] + [System.Boolean] + $CloudAppSecurity_IsEnabled, + + [Parameter()] + [System.String] + $CloudAppSecurity_Type, + + [Parameter()] + [System.Int32] + $SignInFrequency_Value, + + [Parameter()] + [ValidateSet('Days', 'Hours')] + [System.String] + $SignInFrequency_Type, + + [Parameter()] + [System.Boolean] + $SignInFrequency_IsEnabled, + + [Parameter()] + [ValidateSet('Always', 'Never')] + [System.String] + $PersistentBrowser_Mode, + + [Parameter()] + [System.Boolean] + $PersistentBrowser_IsEnabled, + + #generic + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $GlobalAdminAccount, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + + Write-Verbose -Message "Testing configuration of AzureAD Groups" + + $CurrentValues = Get-TargetResource @PSBoundParameters + + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + $ValuesToCheck = $PSBoundParameters + $ValuesToCheck.Remove('GlobalAdminAccount') | Out-Null + $ValuesToCheck.Remove('Id') | Out-Null + + $TestResult = Test-Microsoft365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $ValuesToCheck.Keys + + Write-Verbose -Message "Test-TargetResource returned $TestResult" + + return $TestResult +} + +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter()] + [System.Management.Automation.PSCredential] + $GlobalAdminAccount, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") + $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() + $data.Add("Resource", $ResourceName) + $data.Add("Method", $MyInvocation.MyCommand) + $data.Add("Principal", $GlobalAdminAccount.UserName) + $data.Add("TenantId", $TenantId) + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $ConnectionMode = New-M365DSCConnection -Platform 'AzureAD' -InboundParameters $PSBoundParameters + + [array] $Policies = Get-AzureADMSConditionalAccessPolicy + $i = 1 + $dscContent = '' + Write-Host "`r`n" -NoNewLine + foreach ($Policy in $Policies) + { + Write-Host " |---[$i/$($Policies.Count)] $($Policy.DisplayName)" -NoNewLine + $Params = @{ + GlobalAdminAccount = $GlobalAdminAccount + DisplayName = $Policy.DisplayName + Id = $Policy.Id + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + $dscContent += Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -GlobalAdminAccount $GlobalAdminAccount + Write-Host $Global:M365DSCEmojiGreenCheckMark + $i++ + } + return $dscContent +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof new file mode 100644 index 0000000000..6d31721a8a --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof @@ -0,0 +1,39 @@ +[ClassVersion("1.0.0.0"), FriendlyName("AADConditionalAccessPolicy")] +class MSFT_AADConditionalAccessPolicy : OMI_BaseResource +{ + [Key, Description("DisplayName of the AAD CA Policy")] String DisplayName; + [Write, Description("Specifies the GUID for the Policy.")] String Id; + [Write, Description("Specifies the State of the Policy."), ValueMap{"disabled","enabled","enabledForReportingButNotEnforced"}, Values{"disabled","enabled","enabledForReportingButNotEnforced"}] String State; + [Write, Description("Cloud Apps in scope of the Policy.")] String IncludeApplications[]; + [Write, Description("Cloud Apps out of scope of the Policy.")] String ExcludeApplications[]; + [Write, Description("User Actions in scope of the Policy.")] String IncludeUserActions[]; + [Write, Description("Users in scope of the Policy.")] String IncludeUsers[]; + [Write, Description("Users out of scope of the Policy.")] String ExcludeUsers[]; + [Write, Description("Groups in scope of the Policy.")] String IncludeGroups[]; + [Write, Description("Groups out of scope of the Policy.")] String ExcludeGroups[]; + [Write, Description("AAD Admin Roles in scope of the Policy.")] String IncludeRoles[]; + [Write, Description("AAD Admin Roles out of scope of the Policy.")] String ExcludeRoles[]; + [Write, Description("Client Device Platforms in scope of the Policy.")] String IncludePlatforms[]; + [Write, Description("Client Device Platforms out of scope of the Policy.")] String ExcludePlatforms[]; + [Write, Description("AAD Named Locations in scope of the Policy.")] String IncludeLocations[]; + [Write, Description("AAD Named Locations out of scope of the Policy.")] String ExcludeLocations[]; + [Write, Description("Client Device Compliance states in scope of the Policy.")] String IncludeDeviceStates[]; + [Write, Description("Client Device Compliance states out of scope of the Policy.")] String ExcludeDeviceStates[]; + [Write, Description("AAD Identity Protection User Risk Levels in scope of the Policy.")] String UserRiskLevels[]; + [Write, Description("AAD Identity Protection Sign-in Risk Levels in scope of the Policy.")] String SignInRiskLevels[]; + [Write, Description("Client App types in scope of the Policy.")] String ClientAppTypes[]; + [Write, Description("Operator to be used for Grant Controls."), ValueMap{"AND","OR"}, Values{"AND","OR"}] String GrantControl_Operator; + [Write, Description("List of built-in Grant Controls to be applied by the Policy.")] String BuiltInControls[]; + [Write, Description("Specifies, whether Application Enforced Restrictions are enabled in the Policy.")] Boolean ApplicationEnforcedRestrictions_IsEnabled; + [Write, Description("Specifies, whether Cloud App Security is enforced by the Policy.")] Boolean CloudAppSecurity_IsEnabled; + [Write, Description("Specifies, what Cloud App Security control is enforced by the Policy.")] String CloudAppSecurity_Type; + [Write, Description("Sign in frequency time in the given unit to be enforced by the policy.")] Int32 SignInFrequency_Value; + [Write, Description("Sign in frequency unit (days/hours) to be interpreted by the policy."), ValueMap{"Days","Hours"}, Values{"Days","Hours"}] String SignInFrequency_Type; + [Write, Description("Specifies, whether sign-in frequency is enforced by the Policy.")] Boolean SignInFrequency_IsEnabled; + [Write, Description("Specifies, whether Browser Persistence is controlled by the Policy.")] Boolean PersistentBrowser_IsEnabled; + [Write, Description("Specifies, what Browser Persistence control is enforced by the Policy."), ValueMap{"Always","Never"}, Values{"Always","Never"}] String PersistentBrowser_Mode; + [Write, Description("Credentials of the Azure Active Directory Admin"), EmbeddedInstance("MSFT_Credential")] String GlobalAdminAccount; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/Readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/Readme.md new file mode 100644 index 0000000000..51536a5659 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/Readme.md @@ -0,0 +1,16 @@ +# AADConditionalAccessPolicy + +## Description + +This resource configures an Azure Active Directory Conditional Access Policy. + +## Azure AD Permissions + +To authenticate via Azure Active Directory, this resource required the following Application permissions: + +* **Automate** + * None +* **Export** + * None + +NOTE: All permisions listed above require admin consent. From 0a5b9f1e1d0e59c80fd1772df12398e40bb85b01 Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Wed, 4 Nov 2020 23:27:49 +0100 Subject: [PATCH 02/33] Update MSFT_AADConditionalAccessPolicy.schema.mof --- .../MSFT_AADConditionalAccessPolicy.schema.mof | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof index 6d31721a8a..a1871eaea6 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof @@ -27,11 +27,12 @@ class MSFT_AADConditionalAccessPolicy : OMI_BaseResource [Write, Description("Specifies, whether Application Enforced Restrictions are enabled in the Policy.")] Boolean ApplicationEnforcedRestrictions_IsEnabled; [Write, Description("Specifies, whether Cloud App Security is enforced by the Policy.")] Boolean CloudAppSecurity_IsEnabled; [Write, Description("Specifies, what Cloud App Security control is enforced by the Policy.")] String CloudAppSecurity_Type; - [Write, Description("Sign in frequency time in the given unit to be enforced by the policy.")] Int32 SignInFrequency_Value; - [Write, Description("Sign in frequency unit (days/hours) to be interpreted by the policy."), ValueMap{"Days","Hours"}, Values{"Days","Hours"}] String SignInFrequency_Type; + [Write, Description("Sign in frequency time in the given unit to be enforced by the policy.")] UInt32 SignInFrequency_Value; + [Write, Description("Sign in frequency unit (days/hours) to be interpreted by the policy."), ValueMap{"Days","Hours",""}, Values{"Days","Hours",""}] String SignInFrequency_Type; [Write, Description("Specifies, whether sign-in frequency is enforced by the Policy.")] Boolean SignInFrequency_IsEnabled; [Write, Description("Specifies, whether Browser Persistence is controlled by the Policy.")] Boolean PersistentBrowser_IsEnabled; - [Write, Description("Specifies, what Browser Persistence control is enforced by the Policy."), ValueMap{"Always","Never"}, Values{"Always","Never"}] String PersistentBrowser_Mode; + [Write, Description("Specifies, what Browser Persistence control is enforced by the Policy."), ValueMap{"Always","Never",""}, Values{"Always","Never",""}] String PersistentBrowser_Mode; + [Write, Description("Specify if the Azure AD CA Policy should exist or not."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; [Write, Description("Credentials of the Azure Active Directory Admin"), EmbeddedInstance("MSFT_Credential")] String GlobalAdminAccount; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; From 48d678462054ff5dc7cae15a8603ec09e3131c6b Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Thu, 5 Nov 2020 18:40:23 +0100 Subject: [PATCH 03/33] Update MSFT_AADConditionalAccessPolicy.psm1 --- .../MSFT_AADConditionalAccessPolicy.psm1 | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index a8a91635ff..02bc7f50ff 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -138,7 +138,7 @@ function Get-TargetResource $SignInFrequency_Value, [Parameter()] - [ValidateSet('Days', 'Hours')] + [ValidateSet('Days', 'Hours','')] [System.String] $SignInFrequency_Type, @@ -147,7 +147,7 @@ function Get-TargetResource $SignInFrequency_IsEnabled, [Parameter()] - [ValidateSet('Always', 'Never')] + [ValidateSet('Always', 'Never','')] [System.String] $PersistentBrowser_Mode, @@ -302,8 +302,8 @@ function Set-TargetResource $Id, [Parameter()] - [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] [System.String] + [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] $State, #ConditionalAccessApplicationCondition @@ -427,7 +427,7 @@ function Set-TargetResource $SignInFrequency_Value, [Parameter()] - [ValidateSet('Days', 'Hours')] + [ValidateSet('Days', 'Hours','')] [System.String] $SignInFrequency_Type, @@ -436,7 +436,7 @@ function Set-TargetResource $SignInFrequency_IsEnabled, [Parameter()] - [ValidateSet('Always', 'Never')] + [ValidateSet('Always', 'Never','')] [System.String] $PersistentBrowser_Mode, @@ -500,8 +500,9 @@ function Set-TargetResource $conditions.Applications.IncludeUserActions = $IncludeUserActions #create and provision User Condition object $conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition - $IncludeUsers | foreach-object#translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All + $IncludeUsers | foreach-object { + #translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All if($_) { if($_ -notmatch 'GuestsOrExternalUsers|All') @@ -523,8 +524,9 @@ function Set-TargetResource } } } - $ExcludeUsers | foreach-object#translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All + $ExcludeUsers | foreach-object { + #translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All if($_) { if($_ -notmatch 'GuestsOrExternalUsers|All') @@ -546,8 +548,9 @@ function Set-TargetResource } } } - $IncludeGroups | foreach-object#translate user Group names to GUID + $IncludeGroups | foreach-object { + #translate user Group names to GUID if($_) { $Group=$null @@ -567,8 +570,9 @@ function Set-TargetResource } } - $ExcludeGroups | foreach-object#translate user Group names to GUID + $ExcludeGroups | foreach-object { + #translate user Group names to GUID if($_) { $Group=$null @@ -588,8 +592,9 @@ function Set-TargetResource } } - if ($IncludeRoles)#translate role names to template guid if defined + if ($IncludeRoles) { + #translate role names to template guid if defined $rolelookup=@{} Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.DisplayName]=$_.ObjectId} $IncludeRoles | foreach-object @@ -609,8 +614,9 @@ function Set-TargetResource } } } - if ($ExcludeRoles)#translate role names to template guid if defined + if ($ExcludeRoles) { + #translate role names to template guid if defined $rolelookup=@{} Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.DisplayName]=$_.ObjectId} $ExcludeRoles | foreach-object @@ -630,15 +636,17 @@ function Set-TargetResource } } } - if ($IncludePlatforms -or $ExcludePlatforms)#create and provision Platform condition object if used + if ($IncludePlatforms -or $ExcludePlatforms) { + #create and provision Platform condition object if used $conditions.Platforms = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition $conditions.Platforms.IncludePlatforms=$IncludePlatforms #no translation or conversion needed $conditions.Platforms.ExcludePlatforms=$ExcludePlatforms#no translation or conversion needed } - if ($IncludeLocations -or $ExcludeLocations)#create and provision Location condition object if used, translate Location names to guid + if ($IncludeLocations -or $ExcludeLocations) { + #create and provision Location condition object if used, translate Location names to guid $conditions.Locations = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessLocationCondition $LocationLookup=@{} Get-AzureADMSNamedLocationPolicy | ForEach-Object {$LocationLookup[$_.DisplayName]=$_.Id} @@ -680,8 +688,9 @@ function Set-TargetResource } - if ($IncludeDeviceStates -or $ExcludeDeviceStates)#create and provision Device condition object if used + if ($IncludeDeviceStates -or $ExcludeDeviceStates) { + #create and provision Device condition object if used $conditions.Devices = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessDevicesCondition $conditions.Devices.IncludeDeviceStates=$IncludeDeviceStates#no translation or conversion needed $conditions.Devices.ExcludeDeviceStates=$ExcludeDeviceStates#no translation or conversion needed @@ -701,26 +710,30 @@ function Set-TargetResource { #create and provision Session Control object if used $sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSessionControls - if ($ApplicationEnforcedRestrictions_IsEnabled)#create and provision ApplicationEnforcedRestrictions object if used + if ($ApplicationEnforcedRestrictions_IsEnabled) { + #create and provision ApplicationEnforcedRestrictions object if used $sessioncontrols.ApplicationEnforcedRestrictions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationEnforcedRestrictions $sessioncontrols.ApplicationEnforcedRestrictions.IsEnabled = $true } - if ($CloudAppSecurity_IsEnabled)#create and provision CloudAppSecurity object if used + if ($CloudAppSecurity_IsEnabled) { + #create and provision CloudAppSecurity object if used $sessioncontrols.CloudAppSecurity = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessCloudAppSecurity $sessioncontrols.CloudAppSecurity.IsEnabled=$true $sessioncontrols.CloudAppSecurity.CloudAppSecurityType=$CloudAppSecurity_Type } - if ($SignInFrequency_IsEnabled)#create and provision SignInFrequency object if used + if ($SignInFrequency_IsEnabled) { + #create and provision SignInFrequency object if used $sessioncontrols.SignInFrequency = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency $sessioncontrols.SignInFrequency.IsEnabled =$true $sessioncontrols.SignInFrequency.Type = $SignInFrequency_Type $sessioncontrols.SignInFrequency.Value = $SignInFrequency_Value } - if ($PersistentBrowser_IsEnabled)#create and provision PersistentBrowser object if used + if ($PersistentBrowser_IsEnabled) { + #create and provision PersistentBrowser object if used $sessioncontrols.PersistentBrowser = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser $sessioncontrols.PersistentBrowser.IsEnabled =$true $sessioncontrols.PersistentBrowser.Mode=$PersistentBrowser_Mode @@ -783,8 +796,8 @@ function Test-TargetResource $Id, [Parameter()] - [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] [System.String] + [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] $State, #ConditionalAccessApplicationCondition @@ -908,7 +921,7 @@ function Test-TargetResource $SignInFrequency_Value, [Parameter()] - [ValidateSet('Days', 'Hours')] + [ValidateSet('Days', 'Hours','')] [System.String] $SignInFrequency_Type, @@ -917,7 +930,7 @@ function Test-TargetResource $SignInFrequency_IsEnabled, [Parameter()] - [ValidateSet('Always', 'Never')] + [ValidateSet('Always', 'Never','')] [System.String] $PersistentBrowser_Mode, @@ -926,7 +939,6 @@ function Test-TargetResource $PersistentBrowser_IsEnabled, #generic - [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] @@ -949,7 +961,7 @@ function Test-TargetResource $CertificateThumbprint ) - Write-Verbose -Message "Testing configuration of AzureAD Groups" + Write-Verbose -Message "Testing configuration of AzureAD CA Policies" $CurrentValues = Get-TargetResource @PSBoundParameters @@ -959,7 +971,7 @@ function Test-TargetResource $ValuesToCheck.Remove('GlobalAdminAccount') | Out-Null $ValuesToCheck.Remove('Id') | Out-Null - $TestResult = Test-Microsoft365DSCParameterState -CurrentValues $CurrentValues ` + $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` -Source $($MyInvocation.MyCommand.Source) ` -DesiredValues $PSBoundParameters ` -ValuesToCheck $ValuesToCheck.Keys From 4d45419ceb7ec16a3455f992d636b97f2dbd4f8c Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Tue, 17 Nov 2020 22:07:48 +0100 Subject: [PATCH 04/33] Update MSFT_AADConditionalAccessPolicy.psm1 --- .../MSFT_AADConditionalAccessPolicy.psm1 | 116 +++++++++++------- 1 file changed, 69 insertions(+), 47 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index 02bc7f50ff..747c78da56 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -467,7 +467,8 @@ function Set-TargetResource $CertificateThumbprint ) - Write-Verbose -Message "Setting configuration of Conditional Access Policies" + Write-Verbose -Message "Set-Targetresource: Start processing" + Write-Verbose -Message "Set-Targetresource: Starting telemetry" #region Telemetry $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() @@ -477,121 +478,132 @@ function Set-TargetResource $data.Add("TenantId", $TenantId) Add-M365DSCTelemetryEvent -Data $data #endregion - + Write-Verbose -Message "Set-Targetresource: Finished telemetry" + Write-Verbose -Message "Set-Targetresource: Running Get-TargetResource" $currentPolicy = Get-TargetResource @PSBoundParameters + Write-Verbose -Message "Set-Targetresource: Cleaning up parameters" $currentParameters = $PSBoundParameters - $currentParameters.Remove("ApplicationId") - $currentParameters.Remove("TenantId") - $currentParameters.Remove("CertificateThumbprint") - $currentParameters.Remove("GlobalAdminAccount") - $currentParameters.Remove("Ensure") + $currentParameters.Remove("ApplicationId") | Out-Null + $currentParameters.Remove("TenantId") | Out-Null + $currentParameters.Remove("CertificateThumbprint") | Out-Null + $currentParameters.Remove("GlobalAdminAccount") | Out-Null + $currentParameters.Remove("Ensure") | Out-Null if ($Ensure -eq 'Present')#create policy attribute objects { + Write-Verbose -Message "Set-Targetresource: Policy $Displayname Ensure Present" $NewParameters=@{} $NewParameters.Add("DisplayName",$DisplayName) $NewParameters.Add("State",$State) #create Conditions object + Write-Verbose -Message "Set-Targetresource: create Conditions object" $conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet #create and provision Application Condition object + Write-Verbose -Message "Set-Targetresource: create Application Condition object" $conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition $conditions.Applications.IncludeApplications = $IncludeApplications $conditions.Applications.ExcludeApplications = $ExcludeApplications $conditions.Applications.IncludeUserActions = $IncludeUserActions #create and provision User Condition object + Write-Verbose -Message "Set-Targetresource: create and provision User Condition object" $conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition - $IncludeUsers | foreach-object + Write-Verbose -Message "Set-Targetresource: process includeusers" + foreach ($includeuser in $IncludeUsers) { #translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All - if($_) + if($includeuser) { - if($_ -notmatch 'GuestsOrExternalUsers|All') + if($includeuser -notmatch 'GuestsOrExternalUsers|All') { - $user=$null - $user=(Get-AzureADUser -ObjectId $_).ObjectId - if($null -eq $user) + $userguid=$null + $userguid=(Get-AzureADUser -ObjectId $includeuser).ObjectId + if($null -eq $userguid) { - New-M365DSCLogEntry -Error $_ -Message "Couldn't find user $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error $includeuser -Message "Couldn't find user $includeuser , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } elseif (condition) { - $conditions.Users.IncludeUsers += $user + $conditions.Users.IncludeUsers += $userguid } } else { - $conditions.Users.IncludeUsers += $_ + $conditions.Users.IncludeUsers += $includeuser } } } - $ExcludeUsers | foreach-object + Write-Verbose -Message "Set-Targetresource: process excludeusers" + foreach ($excludeuser in $ExcludeUsers) { #translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All - if($_) + if($excludeuser) { - if($_ -notmatch 'GuestsOrExternalUsers|All') + if($excludeuser -notmatch 'GuestsOrExternalUsers|All') { - $user=$null - $user=(Get-AzureADUser -ObjectId $_).ObjectId - if($null -eq $user) + $userguid=$null + $userguid=(Get-AzureADUser -ObjectId $excludeuser).ObjectId + if($null -eq $userguid) { - New-M365DSCLogEntry -Error $_ -Message "Couldn't find user $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error $excludeuser -Message "Couldn't find user $excludeuser , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } elseif (condition) { - $conditions.Users.ExcludeUsers += $user + $conditions.Users.ExcludeUsers += $userguid } } else { - $conditions.Users.ExcludeUsers += $_ + $conditions.Users.ExcludeUsers += $excludeuser } } } - $IncludeGroups | foreach-object + Write-Verbose -Message "Set-Targetresource: process includegroups" + foreach($includegroup in $IncludeGroups) { #translate user Group names to GUID - if($_) + if($includegroup) { - $Group=$null - $Group = Get-AzureADGroup -Filter "DisplayName eq '$_'" - if ($Group.Length -gt 1) + $Groupguid=$null + $Groupguid = Get-AzureADGroup -Filter "DisplayName eq '$includegroup'" + if ($Groupguid.Length -gt 1) { - New-M365DSCLogEntry -Error $_ -Message "Duplicate group found with displayname $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error $includegroup -Message "Duplicate group found with displayname $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - elseif($null -eq $Group) + elseif($null -eq $Groupguid) { - New-M365DSCLogEntry -Error $_ -Message "Couldn't find group $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error $includegroup -Message "Couldn't find group $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } else { - $conditions.Users.IncludeGroups += $Group + $conditions.Users.IncludeGroups += $Groupguid } } } - $ExcludeGroups | foreach-object + Write-Verbose -Message "Set-Targetresource: process excludegroups" + foreach($excludegroup in $ExcludeGroups) { #translate user Group names to GUID - if($_) + if($excludegroup) { - $Group=$null - $Group = Get-AzureADGroup -Filter "DisplayName eq '$_'" - if ($Group.Length -gt 1) + $Groupguid=$null + $Groupguid = Get-AzureADGroup -Filter "DisplayName eq '$excludegroup'" + if ($Groupguid.Length -gt 1) { - New-M365DSCLogEntry -Error $_ -Message "Duplicate group found with displayname $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error $excludegroup -Message "Duplicate group found with displayname $excludegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - elseif($null -eq $Group) + elseif($null -eq $Groupguid) { - New-M365DSCLogEntry -Error $_ -Message "Couldn't find group $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error $excludegroup -Message "Couldn't find group $excludegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } else { - $conditions.Users.ExcludeGroups += $Group + $conditions.Users.ExcludeGroups += $Groupguid } } } + Write-Verbose -Message "Set-Targetresource: process includeroles" if ($IncludeRoles) { #translate role names to template guid if defined @@ -614,6 +626,7 @@ function Set-TargetResource } } } + Write-Verbose -Message "Set-Targetresource: process excluderoles" if ($ExcludeRoles) { #translate role names to template guid if defined @@ -636,6 +649,7 @@ function Set-TargetResource } } } + Write-Verbose -Message "Set-Targetresource: process includeplatforms" if ($IncludePlatforms -or $ExcludePlatforms) { #create and provision Platform condition object if used @@ -643,7 +657,7 @@ function Set-TargetResource $conditions.Platforms.IncludePlatforms=$IncludePlatforms #no translation or conversion needed $conditions.Platforms.ExcludePlatforms=$ExcludePlatforms#no translation or conversion needed } - + Write-Verbose -Message "Set-Targetresource: process include and exclude locations" if ($IncludeLocations -or $ExcludeLocations) { #create and provision Location condition object if used, translate Location names to guid @@ -687,7 +701,7 @@ function Set-TargetResource } } - +Write-Verbose -Message "Set-Targetresource: process device states" if ($IncludeDeviceStates -or $ExcludeDeviceStates) { #create and provision Device condition object if used @@ -695,20 +709,24 @@ function Set-TargetResource $conditions.Devices.IncludeDeviceStates=$IncludeDeviceStates#no translation or conversion needed $conditions.Devices.ExcludeDeviceStates=$ExcludeDeviceStates#no translation or conversion needed } +Write-Verbose -Message "Set-Targetresource: process risk levels and app types" $Conditions.UserRiskLevels = $UserRiskLevels#no translation or conversion needed $Conditions.SignInRiskLevels = $SignInRiskLevels #no translation or conversion needed $Conditions.ClientAppTypes = $ClientAppTypes#no translation or conversion needed - +Write-Verbose -Message "Set-Targetresource: Adding processed conditions" $NewParameters.Add("Conditions",$Conditions)#add all conditions to the parameter list #create and provision Grant Control object +Write-Verbose -Message "Set-Targetresource: create and provision Grant Control object" $GrantControls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls $GrantControls._Operator = $GrantControl_Operator $GrantControls.BuiltInControls = $BuiltInControls #no translation or conversion needed + Write-Verbose -Message "Set-Targetresource: Adding processed grant controls" $NewParameters.Add("GrantControls",$GrantControls)#add GrantControls to the parameter list - +Write-Verbose -Message "Set-Targetresource: process session controls" if ($ApplicationEnforcedRestrictions_IsEnabled -or $CloudAppSecurity_IsEnabled -or $SignInFrequency_IsEnabled -or $PersistentBrowser_IsEnabled) { #create and provision Session Control object if used + Write-Verbose -Message "Set-Targetresource:reate and provision Session Control object" $sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSessionControls if ($ApplicationEnforcedRestrictions_IsEnabled) { @@ -747,10 +765,13 @@ function Set-TargetResource } if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') { + $NewParameters.Add("PolicyId",$Id) try { + Write-Verbose -Message "Set-Targetresource: execute policy change in AAD" Set-AzureADMSConditionalAccessPolicy @NewParameters + Write-Verbose -Message "Set-Targetresource: executed policy change in AAD" } catch { @@ -779,6 +800,7 @@ function Set-TargetResource New-M365DSCLogEntry -Error $_ -Message "Couldn't delete Policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } } + Write-Verbose -Message "Set-Targetresource: finished processing Policy $Displayname" } function Test-TargetResource From 381cea38f2ecd04f7922552dde01521a5cc4e6aa Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 18 Nov 2020 08:39:17 -0500 Subject: [PATCH 05/33] Updates --- .../MSFT_TeamsChannelTab.psm1 | 665 ++++++++++++++++++ .../MSFT_TeamsChannelTab.schema.mof | 33 + .../MSFT_TeamsChannelTab/readme.md | 25 + Modules/Microsoft365DSC/Microsoft365DSC.psd1 | 10 +- .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 3 +- 5 files changed, 734 insertions(+), 2 deletions(-) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/readme.md diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 new file mode 100644 index 0000000000..62d6773f32 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -0,0 +1,665 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + [ValidateLength(1, 256)] + $DisplayName, + + [Parameter(Mandatory = $true)] + [System.String] + [ValidateLength(1, 256)] + $TeamName, + + [Parameter()] + [System.String] + [ValidateLength(1, 256)] + $ChannelName, + + [Parameter()] + [System.String] + $ContentUrl, + + [Parameter()] + [System.String] + $WebSiteUrl, + + [Parameter()] + [ValidateSet("Present", "Absent")] + [System.String] + $Ensure = "Present", + + [Parameter(Mandatory = $true)] + [System.String] + $ApplicationId, + + [Parameter(Mandatory = $true)] + [System.String] + $TenantId, + + [Parameter(Mandatory = $true)] + [System.String] + $CertificateThumbprint + ) + Write-Verbose -Message "Getting configuration of Team $DisplayName" + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") + $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() + $data.Add("Resource", $ResourceName) + $data.Add("Method", $MyInvocation.MyCommand) + $data.Add("Principal", $GlobalAdminAccount.UserName) + $data.Add("TenantId", $TenantId) + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $nullReturn = $PSBoundParameters + $nullReturn.Ensure = "Absent" + + Write-Verbose -Message "Checking for existence of Team $DisplayName" + + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + try + { + # Get the Team ID + try + { + $teamInstance = get-MgGroup -filter "displayName eq '$TeamName'" -ErrorAction Stop | %{ @{ TeamId=$_.Id } } | get-MgTeam -ErrorAction Stop + } + catch + { + Write-Host " $($Global:M365DSCEmojiRedX) The specified Service Principal doesn't have access to read Group information. Permission Required: Group.Read.All & Team.ReadBasic.All" + Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId + } + + if ($null -eq $teamInstance) + { + Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantID + throw "Team {$TeamName} was not found." + } + + # Get the Channel ID + $channelInstance = Get-MgTeamChannel -TeamId $teamInstance.Id | Where-Object -FilterScript {$_.DisplayName -eq $ChannelName} + + if ($null -eq $channelInstance) + { + Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantID + throw "Channel {$ChannelName} was not found." + } + + # Get the Channel Tab + $tabInstance = Get-MgTeamChannelTab -TeamId $teamInstance.Id ` + -ChannelId $channelInstance.Id | Where-Object -FilterScript {$_.DisplayName -eq $DisplayName} + + if ($null -eq $tabInstance) + { + $nullResult = $PSBoundParameters + $nullResult.Ensure = "Present" + return $nullResult + } + + return @{ + DisplayName = $DisplayName + TeamName = $TeamName + ChannelName = $ChannelName + ContentUrl = $ContentUrl + $WebSiteUrl = $WebSiteUrl + ApplicationId = $ApplicationId + TenantId = $TenantID + CertificateThumbprint = $CertificateThumbprint + } + } + catch + { + try + { + Write-Verbose -Message $_ + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + throw $_ + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + [ValidateLength(1, 256)] + $DisplayName, + + [Parameter()] + [System.String] + $GroupID, + + [Parameter()] + [System.String] + [ValidateLength(1, 1024)] + $Description, + + [Parameter()] + [System.String] + $MailNickName, + + [Parameter()] + [System.String[]] + $Owner, + + [Parameter()] + [System.String] + [ValidateSet("Public", "Private", "HiddenMembership")] + $Visibility, + + [Parameter()] + [System.Boolean] + $AllowAddRemoveApps, + + [Parameter()] + [System.Boolean] + $AllowGiphy, + + [Parameter()] + [ValidateSet("Strict", "Moderate")] + [System.String] + $GiphyContentRating, + + [Parameter()] + [System.Boolean] + $AllowStickersAndMemes, + + [Parameter()] + [System.Boolean] + $AllowCustomMemes, + + [Parameter()] + [System.Boolean] + $AllowUserEditMessages, + + [Parameter()] + [System.Boolean] + $AllowUserDeleteMessages, + + [Parameter()] + [System.Boolean] + $AllowOwnerDeleteMessages, + + [Parameter()] + [System.Boolean] + $AllowCreateUpdateRemoveConnectors, + + [Parameter()] + [System.Boolean] + $AllowCreateUpdateRemoveTabs, + + [Parameter()] + [System.Boolean] + $AllowCreateUpdateChannels, + + [Parameter()] + [System.Boolean] + $AllowDeleteChannels, + + [Parameter()] + [System.Boolean] + $AllowTeamMentions, + + [Parameter()] + [System.Boolean] + $AllowChannelMentions, + + [Parameter()] + [System.Boolean] + $AllowGuestCreateUpdateChannels, + + [Parameter()] + [System.Boolean] + $AllowGuestDeleteChannels, + + [Parameter()] + [System.Boolean] + $ShowInTeamsSearchAndSuggestions, + + [Parameter()] + [ValidateSet("Present", "Absent")] + [System.String] + $Ensure = "Present", + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.Management.Automation.PSCredential] + $GlobalAdminAccount + ) + + Write-Verbose -Message "Setting configuration of Team $DisplayName" + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") + $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() + $data.Add("Resource", $ResourceName) + $data.Add("Method", $MyInvocation.MyCommand) + $data.Add("Principal", $GlobalAdminAccount.UserName) + $data.Add("TenantId", $TenantId) + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftTeams' -InboundParameters $PSBoundParameters + + $team = Get-TargetResource @PSBoundParameters + + $CurrentParameters = $PSBoundParameters + $CurrentParameters.Remove("Ensure") + + if ($Ensure -eq "Present" -and ($team.Ensure -eq "Present")) + { + ## Can't pass Owner parm into set opertaion + if ($CurrentParameters.ContainsKey("Owner")) + { + $CurrentParameters.Remove("Owner") + } + if (-not $CurrentParameters.ContainsKey("GroupID")) + { + $CurrentParameters.Add("GroupID", $team.GroupID) + } + if ($ConnectionMode -eq 'Credential') + { + $CurrentParameters.Remove("GlobalAdminAccount") + } + else + { + $CurrentParameters.Remove("ApplicationId") + $CurrentParameters.Remove("TenantId") + $CurrentParameters.Remove("CertificateThumbprint") + } + Set-Team @CurrentParameters + Write-Verbose -Message "Updating team $DisplayName" + } + elseif ($Ensure -eq "Present" -and ($team.Ensure -eq "Absent")) + { + ## GroupID not used on New-Team cmdlet + if ($CurrentParameters.ContainsKey("GroupID")) + { + $CurrentParameters.Remove("GroupID") + } + Write-Verbose -Message "Creating team $DisplayName" + if ($null -ne $Owner) + { + $CurrentParameters.Owner = ([array]$Owner[0]).ToString() + } + + if ($ConnectionMode -eq "ServicePrincipal") + { + $ConnectionMode = New-M365DSCConnection -Platform 'AzureAD' ` + -InboundParameters $PSBoundParameters + $group = New-AzureADMSGroup -DisplayName $DisplayName -GroupTypes "Unified" -MailEnabled $true -SecurityEnabled $true -MailNickname $MailNickName + $currentOwner = (($CurrentParameters.Owner)[0]) + + Write-Verbose -Message "Retrieving Group Owner {$currentOwner}" + $ownerUser = Get-AzureADUser -SearchString $currentOwner + + Write-Verbose -Message "Adding Owner {$($ownerUser.ObjectId)} to Group {$($group.Id)}" + try + { + Add-AzureADGroupOwner -ObjectId $group.Id -RefObjectId $ownerUser.ObjectId -ErrorAction Stop + } + catch + { + Write-Verbose -Message "Adding Owner - Sleeping for 15 seconds" + Start-Sleep -Seconds 15 + Add-AzureADGroupOwner -ObjectId $group.Id -RefObjectId $ownerUser.ObjectId + } + + try + { + New-Team -GroupId $group.Id -ErrorAction Stop + } + catch + { + Write-Verbose -Message "Creating Team - Sleeping for 15 seconds" + Start-Sleep -Seconds 15 + New-Team -GroupId $group.Id + } + } + else + { + $CurrentParameters.Remove("GlobalAdminAccount") + New-Team @CurrentParameters + } + } + elseif ($Ensure -eq "Absent" -and ($team.Ensure -eq "Present")) + { + Write-Verbose -Message "Removing team $DisplayName" + Remove-Team -GroupId $team.GroupId + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + [ValidateLength(1, 256)] + $DisplayName, + + [Parameter()] + [System.String] + $GroupID, + + [Parameter()] + [System.String] + [ValidateLength(1, 1024)] + $Description, + + [Parameter()] + [System.String] + $MailNickName, + + [Parameter()] + [System.String[]] + $Owner, + + [Parameter()] + [System.String] + [ValidateSet("Public", "Private", "HiddenMembership")] + $Visibility, + + [Parameter()] + [System.Boolean] + $AllowAddRemoveApps, + + [Parameter()] + [System.Boolean] + $AllowGiphy, + + [Parameter()] + [ValidateSet("Strict", "Moderate")] + [System.String] + $GiphyContentRating, + + [Parameter()] + [System.Boolean] + $AllowStickersAndMemes, + + [Parameter()] + [System.Boolean] + $AllowCustomMemes, + + [Parameter()] + [System.Boolean] + $AllowUserEditMessages, + + [Parameter()] + [System.Boolean] + $AllowUserDeleteMessages, + + [Parameter()] + [System.Boolean] + $AllowOwnerDeleteMessages, + + [Parameter()] + [System.Boolean] + $AllowCreateUpdateRemoveConnectors, + + [Parameter()] + [System.Boolean] + $AllowCreateUpdateRemoveTabs, + + [Parameter()] + [System.Boolean] + $AllowCreateUpdateChannels, + + [Parameter()] + [System.Boolean] + $AllowDeleteChannels, + + [Parameter()] + [System.Boolean] + $AllowTeamMentions, + + [Parameter()] + [System.Boolean] + $AllowChannelMentions, + + [Parameter()] + [System.Boolean] + $AllowGuestCreateUpdateChannels, + + [Parameter()] + [System.Boolean] + $AllowGuestDeleteChannels, + + [Parameter()] + [System.Boolean] + $ShowInTeamsSearchAndSuggestions, + + [Parameter()] + [ValidateSet("Present", "Absent")] + [System.String] + $Ensure = "Present", + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.Management.Automation.PSCredential] + $GlobalAdminAccount + ) + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") + $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() + $data.Add("Resource", $ResourceName) + $data.Add("Method", $MyInvocation.MyCommand) + $data.Add("Principal", $GlobalAdminAccount.UserName) + $data.Add("TenantId", $TenantId) + Add-M365DSCTelemetryEvent -Data $data + #endregion + + Write-Verbose -Message "Testing configuration of Team $DisplayName" + + $CurrentValues = Get-TargetResource @PSBoundParameters + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + If (!$PSBoundParameters.ContainsKey('Ensure')) + { + $PSBoundParameters.Add('Ensure', $Ensure) + } + $ValuesToCheck = $PSBoundParameters + $ValuesToCheck.Remove('GlobalAdminAccount') | Out-Null + $ValuesToCheck.Remove('GroupID') | Out-Null + + if ($null -eq $CurrentValues.Owner) + { + $ValuesToCheck.Remove("Owner") | Out-Null + } + + $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $ValuesToCheck.Keys + + Write-Verbose -Message "Test-TargetResource returned $TestResult" + + return $TestResult +} + +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.Management.Automation.PSCredential] + $GlobalAdminAccount + ) + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") + $data = [System.Collections.Generic.Dictionary[[String], [String]]]::new() + $data.Add("Resource", $ResourceName) + $data.Add("Method", $MyInvocation.MyCommand) + $data.Add("Principal", $GlobalAdminAccount.UserName) + $data.Add("TenantId", $TenantId) + Add-M365DSCTelemetryEvent -Data $data + #endregion + + try + { + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraphBeta' ` + -InboundParameters $PSBoundParameters + + [array]$teams = get-mggroup -filter "resourceProvisioningOptions/Any(x:x eq 'Team')" + $i = 1 + $dscContent = "" + Write-Host "`r`n" -NoNewline + foreach ($team in $teams) + { + Write-Host " |---[$i/$($teams.Length)] $($team.DisplayName)" + + $channels = $null + try + { + [array]$channels = Get-MgTeamChannel -TeamId $team.Id -ErrorAction Stop + } + catch + { + Write-Host " $($Global:M365DSCEmojiRedX) The specified Service Principal doesn't have access to read Channel information. Permission Required: Channel.ReadBasic.All" + Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId + } + + $j = 1 + foreach ($channel in $channels) + { + Write-Host " |---[$j/$($channels.Length)] $($channel.DisplayName)" + + $tabs = $null + try + { + [array]$tabs = Get-MgTeamChannelTab -TeamId $team.Id ` + -ChannelId $channel.Id -ErrorAction Stop + } + catch + { + Write-Host " $($Global:M365DSCEmojiRedX) The specified Service Principal doesn't have access to read Tab information. Permission Required: TeamsTab.Read.All" + Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId + } + + $k =1 + foreach ($tab in $tabs) + { + Write-Host " |---[$k/$($tabs.Length)] $($tab.DisplayName)" -NoNewline + $params = @{ + TeamName = $team.DisplayName + ChannelName = $channel.DisplayName + DisplayName = $tab.DisplayName + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + $Results = Get-TargetResource @params + + $dscContent = "" + if ($null -ne $Results) + { + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + $dscContent += Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results + } + Write-Host $Global:M365DSCEmojiGreenCheckmark + $k++ + } + $j++ + } + $i++ + } + + return $dscContent + } + catch + { + try + { + Write-Verbose -Message $_ + Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId + } + catch + { + Write-Verbose -Message $_ + } + return "" + } +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof new file mode 100644 index 0000000000..8ddceb14f5 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof @@ -0,0 +1,33 @@ +[ClassVersion("1.0.0.0"), FriendlyName("TeamsTeam")] +class MSFT_TeamsTeam : OMI_BaseResource +{ + [Key, Description("Display Name of the Team")] string DisplayName; + [Write, Description("Description of Team.")] string Description; + [Write, Description("Team group ID, only used to target a Team when duplicated display names occurs.")] string GroupID; + [Write, Description("MailNickName of O365 Group associated with Team")] string MailNickName; + [Write, Description("Owners of the Team")] string Owner[]; + [Write, Description("Visibility of the Team"),ValueMap{"Public","Private", "HiddenMembership"},Values{"Public","Private", "HiddenMembership"}] String Visibility; + [Write, Description("Allow add or remove apps from the Team.")] Boolean AllowAddRemoveApps; + [Write, Description("Allow giphy in Team.")] Boolean AllowGiphy; + [Write, Description("Giphy content rating of the Team."),ValueMap{"Strict","Moderate"}, Values{"Strict","Moderate"}] string GiphyContentRating; + [Write, Description("Allow stickers and mimes in the Team.")] Boolean AllowStickersAndMemes; + [Write, Description("Allow custom memes in Team.")] Boolean AllowCustomMemes; + [Write, Description("Allow members to edit messages within Team.")] Boolean AllowUserEditMessages; + [Write, Description("Allow members to delete messages within Team.")] Boolean AllowUserDeleteMessages; + [Write, Description("Allow owners to delete messages within Team.")] Boolean AllowOwnerDeleteMessages; + [Write, Description("Allow members to delete channels within Team.")] Boolean AllowDeleteChannels; + [Write, Description("Allow members to manage connectors within Team.")] Boolean AllowCreateUpdateRemoveConnectors; + [Write, Description("Allow members to manage tabs within Team.")] Boolean AllowCreateUpdateRemoveTabs; + [Write, Description("Allow mentions in Team.")] Boolean AllowTeamMentions; + [Write, Description("Allow channel mention in Team.")] Boolean AllowChannelMentions; + [Write, Description("Allow guests to create and update channels in Team.")] Boolean AllowGuestCreateUpdateChannels; + [Write, Description("Allow guests to delete channel in Team.")] Boolean AllowGuestDeleteChannels; + [Write, Description("Allow members to create and update channels within Team.")] Boolean AllowCreateUpdateChannels; + [Write, Description("determines whether or not private teams should be searchable from Teams clients for users who do not belong to that team. Set to $false to make those teams not discoverable from Teams clients.")] Boolean ShowInTeamsSearchAndSuggestions; + [Write, Description("Present ensures the Team exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; + [Write, Description("Credentials of the SharePoint Global Admin"), EmbeddedInstance("MSFT_Credential")] String GlobalAdminAccount; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; +}; + diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/readme.md new file mode 100644 index 0000000000..49d571720e --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/readme.md @@ -0,0 +1,25 @@ +# TeamsChannelTab + +## Description + +This resource configures a new Custom tab in a Channel. + +## Azure AD Permissions + +To authenticate via Azure Active Directory, this resource +required the following Application permissions: + +* **Automate** + * Microsoft.Graph + * Channel.ReadBasic.All + * Group.Read.All + * Team.ReadBasic.All + * TeamsTab.ReadWrite.All +* **Export** + * Microsoft.Graph + * Channel.ReadBasic.All + * Group.Read.All + * Team.ReadBasic.All + * TeamsTab.Read.All + +NOTE: All permisions listed above require admin consent. diff --git a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 index 8594e04897..94f369f434 100644 --- a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 +++ b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 @@ -67,6 +67,10 @@ ModuleName = "Microsoft.Graph.Authentication" RequiredVersion = "1.1.0" }, + @{ + ModuleName = "Microsoft.Graph.Groups" + RequiredVersion = "1.1.0" + }, @{ ModuleName = "Microsoft.Graph.Groups.Planner" RequiredVersion = "0.9.1" @@ -83,6 +87,10 @@ ModuleName = "Microsoft.Graph.Planner" RequiredVersion = "1.1.0" }, + @{ + ModuleName = "Microsoft.Graph.Teams" + RequiredVersion = "1.1.0" + }, @{ ModuleName = "Microsoft.PowerApps.Administration.PowerShell" RequiredVersion = "2.0.96" @@ -93,7 +101,7 @@ }, @{ ModuleName = "MSCloudLoginAssistant" - RequiredVersion = "1.0.41" + RequiredVersion = "1.0.42" }, @{ ModuleName = "ReverseDSC" diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index 57cd942ef0..865104772d 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -987,7 +987,8 @@ function New-M365DSCConnection [Parameter(Mandatory = $true)] [ValidateSet("Azure", "AzureAD", "ExchangeOnline", "Intune", ` "SecurityComplianceCenter", "PnP", "PowerPlatforms", ` - "MicrosoftTeams", "SkypeForBusiness", "MicrosoftGraph")] + "MicrosoftTeams", "SkypeForBusiness", "MicrosoftGraph", ` + "MicrosoftGraphBeta")] [System.String] $Platform, From 8c7caa2841d2706a39b575cba1da5357235addc3 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 18 Nov 2020 12:35:11 -0500 Subject: [PATCH 06/33] Updates --- .../MSFT_TeamsChannelTab.psm1 | 16 +++++++-- .../MSFT_TeamsChannelTab.schema.mof | 35 +++++-------------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index 62d6773f32..d68d27c946 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -19,6 +19,10 @@ function Get-TargetResource [ValidateLength(1, 256)] $ChannelName, + [Parameter()] + [System.String] + $TeamId, + [Parameter()] [System.String] $ContentUrl, @@ -61,7 +65,7 @@ function Get-TargetResource Write-Verbose -Message "Checking for existence of Team $DisplayName" - $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraph' ` + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraphBeta' ` -InboundParameters $PSBoundParameters try @@ -69,7 +73,14 @@ function Get-TargetResource # Get the Team ID try { - $teamInstance = get-MgGroup -filter "displayName eq '$TeamName'" -ErrorAction Stop | %{ @{ TeamId=$_.Id } } | get-MgTeam -ErrorAction Stop + if ($null -eq $TeamId) + { + $teamInstance = get-MgGroup -filter "displayName eq '$TeamName' and resourceProvisioningOptions/Any(x:x eq 'Team')" -ErrorAction Stop | %{ @{ TeamId=$_.Id } } | get-MgTeam -ErrorAction Stop + } + else + { + $teamInstance = get-MgTeam -TeamId $TeamId -ErrorAction Stop + } } catch { @@ -617,6 +628,7 @@ function Export-TargetResource Write-Host " |---[$k/$($tabs.Length)] $($tab.DisplayName)" -NoNewline $params = @{ TeamName = $team.DisplayName + TeamId = $team.Id ChannelName = $channel.DisplayName DisplayName = $tab.DisplayName ApplicationId = $ApplicationId diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof index 8ddceb14f5..45b3711c8c 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof @@ -1,30 +1,13 @@ -[ClassVersion("1.0.0.0"), FriendlyName("TeamsTeam")] -class MSFT_TeamsTeam : OMI_BaseResource +[ClassVersion("1.0.0.0"), FriendlyName("TeamsChannelTab")] +class MSFT_TeamsChannelTab : OMI_BaseResource { - [Key, Description("Display Name of the Team")] string DisplayName; - [Write, Description("Description of Team.")] string Description; - [Write, Description("Team group ID, only used to target a Team when duplicated display names occurs.")] string GroupID; - [Write, Description("MailNickName of O365 Group associated with Team")] string MailNickName; - [Write, Description("Owners of the Team")] string Owner[]; - [Write, Description("Visibility of the Team"),ValueMap{"Public","Private", "HiddenMembership"},Values{"Public","Private", "HiddenMembership"}] String Visibility; - [Write, Description("Allow add or remove apps from the Team.")] Boolean AllowAddRemoveApps; - [Write, Description("Allow giphy in Team.")] Boolean AllowGiphy; - [Write, Description("Giphy content rating of the Team."),ValueMap{"Strict","Moderate"}, Values{"Strict","Moderate"}] string GiphyContentRating; - [Write, Description("Allow stickers and mimes in the Team.")] Boolean AllowStickersAndMemes; - [Write, Description("Allow custom memes in Team.")] Boolean AllowCustomMemes; - [Write, Description("Allow members to edit messages within Team.")] Boolean AllowUserEditMessages; - [Write, Description("Allow members to delete messages within Team.")] Boolean AllowUserDeleteMessages; - [Write, Description("Allow owners to delete messages within Team.")] Boolean AllowOwnerDeleteMessages; - [Write, Description("Allow members to delete channels within Team.")] Boolean AllowDeleteChannels; - [Write, Description("Allow members to manage connectors within Team.")] Boolean AllowCreateUpdateRemoveConnectors; - [Write, Description("Allow members to manage tabs within Team.")] Boolean AllowCreateUpdateRemoveTabs; - [Write, Description("Allow mentions in Team.")] Boolean AllowTeamMentions; - [Write, Description("Allow channel mention in Team.")] Boolean AllowChannelMentions; - [Write, Description("Allow guests to create and update channels in Team.")] Boolean AllowGuestCreateUpdateChannels; - [Write, Description("Allow guests to delete channel in Team.")] Boolean AllowGuestDeleteChannels; - [Write, Description("Allow members to create and update channels within Team.")] Boolean AllowCreateUpdateChannels; - [Write, Description("determines whether or not private teams should be searchable from Teams clients for users who do not belong to that team. Set to $false to make those teams not discoverable from Teams clients.")] Boolean ShowInTeamsSearchAndSuggestions; - [Write, Description("Present ensures the Team exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; + [Key, Description("Display Name of the Channel Tab.")]String DisplayName; + [Required, Description("Display Name of the Team.")]String TeamName; + [Required, Description("Display Name of the Channel.")]String ChannelName; + [Write, Description("Unique Id of the Team of the instance on the source tenant.")]String TeamId; + [Write, Description("Url of the tab's content.")]String ContentUrl; + [Write, Description("Url of the website linked to the Channel Tab.")]String WebSiteUrl; + [Write, Description("Present ensures the Tab exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; [Write, Description("Credentials of the SharePoint Global Admin"), EmbeddedInstance("MSFT_Credential")] String GlobalAdminAccount; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; From 82d2e8c3e4f7376b07a715eddf36bf1b82a304ab Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 18 Nov 2020 12:44:56 -0500 Subject: [PATCH 07/33] Changes --- .github/workflows/AzureCloud - Full-Circle - EXO.yml | 2 +- .github/workflows/AzureCloud - Full-Circle - O365.yml | 2 +- .github/workflows/AzureCloud - Full-Circle - OD.yml | 2 +- .github/workflows/AzureCloud - Full-Circle - PP.yml | 2 +- .github/workflows/AzureCloud - Full-Circle - SC.yml | 2 +- .github/workflows/AzureCloud - Full-Circle - SPO.yml | 2 +- .github/workflows/AzureCloud - Full-Circle - TEAMS.yml | 2 +- .github/workflows/AzureCloud - Integration.yml | 4 ++-- .github/workflows/AzureUSGovernment - Integration.yml | 4 ++-- .github/workflows/CodeCoverage.yml | 4 ++-- .../MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 | 3 +++ 11 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.github/workflows/AzureCloud - Full-Circle - EXO.yml b/.github/workflows/AzureCloud - Full-Circle - EXO.yml index b73a4d5fb2..59ef89b9d2 100644 --- a/.github/workflows/AzureCloud - Full-Circle - EXO.yml +++ b/.github/workflows/AzureCloud - Full-Circle - EXO.yml @@ -5,7 +5,7 @@ jobs: # This workflow contains a single job called "build" FullCircle-EXO: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/AzureCloud - Full-Circle - O365.yml b/.github/workflows/AzureCloud - Full-Circle - O365.yml index f89b54d048..baf17d4a3e 100644 --- a/.github/workflows/AzureCloud - Full-Circle - O365.yml +++ b/.github/workflows/AzureCloud - Full-Circle - O365.yml @@ -5,7 +5,7 @@ jobs: # This workflow contains a single job called "build" FullCircle-O365: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/AzureCloud - Full-Circle - OD.yml b/.github/workflows/AzureCloud - Full-Circle - OD.yml index a3ddf7571b..eb1b0e3130 100644 --- a/.github/workflows/AzureCloud - Full-Circle - OD.yml +++ b/.github/workflows/AzureCloud - Full-Circle - OD.yml @@ -5,7 +5,7 @@ jobs: # This workflow contains a single job called "build" FullCircle-OD: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/AzureCloud - Full-Circle - PP.yml b/.github/workflows/AzureCloud - Full-Circle - PP.yml index 1753df4f8d..ce10da750a 100644 --- a/.github/workflows/AzureCloud - Full-Circle - PP.yml +++ b/.github/workflows/AzureCloud - Full-Circle - PP.yml @@ -5,7 +5,7 @@ jobs: # This workflow contains a single job called "build" FullCircle-PP: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/AzureCloud - Full-Circle - SC.yml b/.github/workflows/AzureCloud - Full-Circle - SC.yml index d4fe627187..58df5274f5 100644 --- a/.github/workflows/AzureCloud - Full-Circle - SC.yml +++ b/.github/workflows/AzureCloud - Full-Circle - SC.yml @@ -5,7 +5,7 @@ jobs: # This workflow contains a single job called "build" FullCircle-SC: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/AzureCloud - Full-Circle - SPO.yml b/.github/workflows/AzureCloud - Full-Circle - SPO.yml index ce11327672..610feba2dc 100644 --- a/.github/workflows/AzureCloud - Full-Circle - SPO.yml +++ b/.github/workflows/AzureCloud - Full-Circle - SPO.yml @@ -5,7 +5,7 @@ jobs: # This workflow contains a single job called "build" FullCircle-SPO: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/AzureCloud - Full-Circle - TEAMS.yml b/.github/workflows/AzureCloud - Full-Circle - TEAMS.yml index 94b836707d..210f31cfe4 100644 --- a/.github/workflows/AzureCloud - Full-Circle - TEAMS.yml +++ b/.github/workflows/AzureCloud - Full-Circle - TEAMS.yml @@ -5,7 +5,7 @@ jobs: # This workflow contains a single job called "build" FullCircle-TEAMS: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/AzureCloud - Integration.yml b/.github/workflows/AzureCloud - Integration.yml index 9ac0d25db2..3530fe4bd8 100644 --- a/.github/workflows/AzureCloud - Integration.yml +++ b/.github/workflows/AzureCloud - Integration.yml @@ -3,9 +3,9 @@ on: [push] jobs: # This workflow contains a single job called "build" - build: + Public-Cloud-Integration: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/AzureUSGovernment - Integration.yml b/.github/workflows/AzureUSGovernment - Integration.yml index 10f57e4fa9..7e940fd7f3 100644 --- a/.github/workflows/AzureUSGovernment - Integration.yml +++ b/.github/workflows/AzureUSGovernment - Integration.yml @@ -3,9 +3,9 @@ on: [push] jobs: # This workflow contains a single job called "build" - build: + GCC-Integration: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/.github/workflows/CodeCoverage.yml b/.github/workflows/CodeCoverage.yml index e6cfe1b24c..cc4f1a1943 100644 --- a/.github/workflows/CodeCoverage.yml +++ b/.github/workflows/CodeCoverage.yml @@ -3,9 +3,9 @@ on: [push] jobs: # This workflow contains a single job called "build" - build: + CodeCoverage: # The type of runner that the job will run on - runs-on: self-hosted + runs-on: windows-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index d68d27c946..5959056170 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -637,7 +637,10 @@ function Export-TargetResource } $Results = Get-TargetResource @params +<<<<<<< Updated upstream $dscContent = "" +======= +>>>>>>> Stashed changes if ($null -ne $Results) { $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` From ade79891365476036f9eff8661cc2a2716864dbf Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 18 Nov 2020 14:14:38 -0500 Subject: [PATCH 08/33] Changes --- .../MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index 5959056170..32f91d34e7 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -125,7 +125,7 @@ function Get-TargetResource TeamName = $TeamName ChannelName = $ChannelName ContentUrl = $ContentUrl - $WebSiteUrl = $WebSiteUrl + WebSiteUrl = $WebSiteUrl ApplicationId = $ApplicationId TenantId = $TenantID CertificateThumbprint = $CertificateThumbprint @@ -637,10 +637,6 @@ function Export-TargetResource } $Results = Get-TargetResource @params -<<<<<<< Updated upstream - $dscContent = "" -======= ->>>>>>> Stashed changes if ($null -ne $Results) { $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` From eaf3e7db8299aa1ec620c5024f318f8544162137 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 19 Nov 2020 06:21:25 -0500 Subject: [PATCH 09/33] update --- .../MSFT_TeamsChannel/MSFT_TeamsChannel.psm1 | 12 +- .../MSFT_TeamsChannelTab.psm1 | 341 ++++-------------- .../MSFT_TeamsChannelTab.schema.mof | 1 - .../MSFT_TeamsTeam/MSFT_TeamsTeam.psm1 | 16 +- 4 files changed, 85 insertions(+), 285 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannel/MSFT_TeamsChannel.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannel/MSFT_TeamsChannel.psm1 index ffc885c61f..8ff6b1ed59 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannel/MSFT_TeamsChannel.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannel/MSFT_TeamsChannel.psm1 @@ -196,13 +196,13 @@ function Set-TargetResource } Write-Verbose -Message "Retrieve team GroupId: $($team.GroupId)" - $CurrentParameters.Remove("TeamName") + $CurrentParameters.Remove("TeamName") | Out-Null $CurrentParameters.Add("GroupId", $team.GroupId) - $CurrentParameters.Remove("GlobalAdminAccount") - $CurrentParameters.Remove("ApplicationId") - $CurrentParameters.Remove("TenantId") - $CurrentParameters.Remove("CertificateThumbprint") - $CurrentParameters.Remove("Ensure") + $CurrentParameters.Remove("GlobalAdminAccount") | Out-Null + $CurrentParameters.Remove("ApplicationId") | Out-Null + $CurrentParameters.Remove("TenantId") | Out-Null + $CurrentParameters.Remove("CertificateThumbprint") | Out-Null + $CurrentParameters.Remove("Ensure") | Out-Null if ($Ensure -eq "Present") { diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index 32f91d34e7..69f619ad17 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -14,7 +14,7 @@ function Get-TargetResource [ValidateLength(1, 256)] $TeamName, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] [ValidateLength(1, 256)] $ChannelName, @@ -48,7 +48,7 @@ function Get-TargetResource [System.String] $CertificateThumbprint ) - Write-Verbose -Message "Getting configuration of Team $DisplayName" + Write-Verbose -Message "Getting configuration of Tab $DisplayName" #region Telemetry $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") @@ -63,8 +63,6 @@ function Get-TargetResource $nullReturn = $PSBoundParameters $nullReturn.Ensure = "Absent" - Write-Verbose -Message "Checking for existence of Team $DisplayName" - $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraphBeta' ` -InboundParameters $PSBoundParameters @@ -73,18 +71,22 @@ function Get-TargetResource # Get the Team ID try { - if ($null -eq $TeamId) + if ([System.String]::IsNullOrEmpty($TeamId)) { - $teamInstance = get-MgGroup -filter "displayName eq '$TeamName' and resourceProvisioningOptions/Any(x:x eq 'Team')" -ErrorAction Stop | %{ @{ TeamId=$_.Id } } | get-MgTeam -ErrorAction Stop + Write-Verbose -Message "Getting team by Name {$TeamName}" + $filter = "displayName eq '$TeamName' and resourceProvisioningOptions/Any(x:x eq 'Team')" + $teamInstance = get-MgGroup -filter $filter -ErrorAction Stop | %{ @{ TeamId=$_.Id } } | get-MgTeam -ErrorAction Stop } else { + Write-Verbose -Message "Getting team by Id {$TeamId}" $teamInstance = get-MgTeam -TeamId $TeamId -ErrorAction Stop } } catch { - Write-Host " $($Global:M365DSCEmojiRedX) The specified Service Principal doesn't have access to read Group information. Permission Required: Group.Read.All & Team.ReadBasic.All" + Write-Verbose -Message "$($_.Message)`r`n$($_.StackTrace)" + Write-Verbose "The specified Service Principal doesn't have access to read Group information. Permission Required: Group.Read.All & Team.ReadBasic.All" Add-M365DSCEvent -Message $_ -EntryType 'Error' ` -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantId @@ -92,10 +94,11 @@ function Get-TargetResource if ($null -eq $teamInstance) { - Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + $Message = "Team {$TeamName} was not found." + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantID - throw "Team {$TeamName} was not found." + throw $Message } # Get the Channel ID @@ -123,6 +126,7 @@ function Get-TargetResource return @{ DisplayName = $DisplayName TeamName = $TeamName + TeamId = $TeamId ChannelName = $ChannelName ContentUrl = $ContentUrl WebSiteUrl = $WebSiteUrl @@ -167,117 +171,44 @@ function Set-TargetResource [ValidateLength(1, 256)] $DisplayName, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] - $GroupID, + [ValidateLength(1, 256)] + $TeamName, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] - [ValidateLength(1, 1024)] - $Description, + [ValidateLength(1, 256)] + $ChannelName, [Parameter()] [System.String] - $MailNickName, - - [Parameter()] - [System.String[]] - $Owner, + $TeamId, [Parameter()] [System.String] - [ValidateSet("Public", "Private", "HiddenMembership")] - $Visibility, - - [Parameter()] - [System.Boolean] - $AllowAddRemoveApps, - - [Parameter()] - [System.Boolean] - $AllowGiphy, + $ContentUrl, [Parameter()] - [ValidateSet("Strict", "Moderate")] [System.String] - $GiphyContentRating, - - [Parameter()] - [System.Boolean] - $AllowStickersAndMemes, - - [Parameter()] - [System.Boolean] - $AllowCustomMemes, - - [Parameter()] - [System.Boolean] - $AllowUserEditMessages, - - [Parameter()] - [System.Boolean] - $AllowUserDeleteMessages, - - [Parameter()] - [System.Boolean] - $AllowOwnerDeleteMessages, - - [Parameter()] - [System.Boolean] - $AllowCreateUpdateRemoveConnectors, - - [Parameter()] - [System.Boolean] - $AllowCreateUpdateRemoveTabs, - - [Parameter()] - [System.Boolean] - $AllowCreateUpdateChannels, - - [Parameter()] - [System.Boolean] - $AllowDeleteChannels, - - [Parameter()] - [System.Boolean] - $AllowTeamMentions, - - [Parameter()] - [System.Boolean] - $AllowChannelMentions, - - [Parameter()] - [System.Boolean] - $AllowGuestCreateUpdateChannels, - - [Parameter()] - [System.Boolean] - $AllowGuestDeleteChannels, - - [Parameter()] - [System.Boolean] - $ShowInTeamsSearchAndSuggestions, + $WebSiteUrl, [Parameter()] [ValidateSet("Present", "Absent")] [System.String] $Ensure = "Present", - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $ApplicationId, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $TenantId, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] - $CertificateThumbprint, - - [Parameter()] - [System.Management.Automation.PSCredential] - $GlobalAdminAccount + $CertificateThumbprint ) Write-Verbose -Message "Setting configuration of Team $DisplayName" @@ -292,93 +223,44 @@ function Set-TargetResource Add-M365DSCTelemetryEvent -Data $data #endregion - $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftTeams' -InboundParameters $PSBoundParameters + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraphBeta' ` + -InboundParameters $PSBoundParameters - $team = Get-TargetResource @PSBoundParameters + $tab = Get-TargetResource @PSBoundParameters $CurrentParameters = $PSBoundParameters - $CurrentParameters.Remove("Ensure") - - if ($Ensure -eq "Present" -and ($team.Ensure -eq "Present")) + $CurrentParameters.Remove("Ensure") | Out-Null + $CurrentParameters.Remove("ApplicationId") | Out-Null + $CurrentParameters.Remove("TenantId") | Out-Null + $CurrentParameters.Remove("CertificateThumbprint") | Out-Null + + $ChannelInstance = Get-MgTeamChannel -TeamId $tab.TeamId ` + -Filter "DisplayName eq '$ChannelName'" + $tabInstance = Get-MgTeamChannelTab -TeamId $tab.TeamId ` + -ChannelId $ChannelInstance.Id ` + -Filter "DisplayName eq '$DisplayName" + if ($Ensure -eq "Present" -and ($tab.Ensure -eq "Present")) { - ## Can't pass Owner parm into set opertaion - if ($CurrentParameters.ContainsKey("Owner")) - { - $CurrentParameters.Remove("Owner") - } - if (-not $CurrentParameters.ContainsKey("GroupID")) - { - $CurrentParameters.Add("GroupID", $team.GroupID) - } - if ($ConnectionMode -eq 'Credential') - { - $CurrentParameters.Remove("GlobalAdminAccount") - } - else - { - $CurrentParameters.Remove("ApplicationId") - $CurrentParameters.Remove("TenantId") - $CurrentParameters.Remove("CertificateThumbprint") - } - Set-Team @CurrentParameters - Write-Verbose -Message "Updating team $DisplayName" + Write-Verbose -Message "Updating current instance of tab {$($tabInstance.DisplayName)}" + $CurrentParameters.Add("ChannelId", $ChannelInstance.Id) + $CurrentParameters.Add("TeamsTabId", $tabInstance.Id) + Update-MgTeamChannelTab @CurrentParameters | Out-Null } elseif ($Ensure -eq "Present" -and ($team.Ensure -eq "Absent")) { - ## GroupID not used on New-Team cmdlet - if ($CurrentParameters.ContainsKey("GroupID")) - { - $CurrentParameters.Remove("GroupID") - } - Write-Verbose -Message "Creating team $DisplayName" - if ($null -ne $Owner) - { - $CurrentParameters.Owner = ([array]$Owner[0]).ToString() - } - - if ($ConnectionMode -eq "ServicePrincipal") - { - $ConnectionMode = New-M365DSCConnection -Platform 'AzureAD' ` - -InboundParameters $PSBoundParameters - $group = New-AzureADMSGroup -DisplayName $DisplayName -GroupTypes "Unified" -MailEnabled $true -SecurityEnabled $true -MailNickname $MailNickName - $currentOwner = (($CurrentParameters.Owner)[0]) - - Write-Verbose -Message "Retrieving Group Owner {$currentOwner}" - $ownerUser = Get-AzureADUser -SearchString $currentOwner - - Write-Verbose -Message "Adding Owner {$($ownerUser.ObjectId)} to Group {$($group.Id)}" - try - { - Add-AzureADGroupOwner -ObjectId $group.Id -RefObjectId $ownerUser.ObjectId -ErrorAction Stop - } - catch - { - Write-Verbose -Message "Adding Owner - Sleeping for 15 seconds" - Start-Sleep -Seconds 15 - Add-AzureADGroupOwner -ObjectId $group.Id -RefObjectId $ownerUser.ObjectId - } - - try - { - New-Team -GroupId $group.Id -ErrorAction Stop - } - catch - { - Write-Verbose -Message "Creating Team - Sleeping for 15 seconds" - Start-Sleep -Seconds 15 - New-Team -GroupId $group.Id - } - } - else - { - $CurrentParameters.Remove("GlobalAdminAccount") - New-Team @CurrentParameters - } + Write-Verbose -Message "Creating new tab {$DisplayName}" + $CurrentParameters.Add("ChannelId", $ChannelInstance.Id) + New-MgTeamChannelTab @CurrentParameters | Out-Null } elseif ($Ensure -eq "Absent" -and ($team.Ensure -eq "Present")) { - Write-Verbose -Message "Removing team $DisplayName" - Remove-Team -GroupId $team.GroupId + Write-Verbose -Message "Removing existing tab {$DisplayName}" + $RemoveParams = @{ + ChannelId = $ChannelInstance.Id + TeamId = $tab.TeamId + TeamsTabId = $tabInstance.Id + } + Remove-MgTeamChannelTab @RemoveParams | Out-Null } } @@ -393,117 +275,44 @@ function Test-TargetResource [ValidateLength(1, 256)] $DisplayName, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] - $GroupID, + [ValidateLength(1, 256)] + $TeamName, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] - [ValidateLength(1, 1024)] - $Description, + [ValidateLength(1, 256)] + $ChannelName, [Parameter()] [System.String] - $MailNickName, - - [Parameter()] - [System.String[]] - $Owner, + $TeamId, [Parameter()] [System.String] - [ValidateSet("Public", "Private", "HiddenMembership")] - $Visibility, - - [Parameter()] - [System.Boolean] - $AllowAddRemoveApps, - - [Parameter()] - [System.Boolean] - $AllowGiphy, + $ContentUrl, [Parameter()] - [ValidateSet("Strict", "Moderate")] [System.String] - $GiphyContentRating, - - [Parameter()] - [System.Boolean] - $AllowStickersAndMemes, - - [Parameter()] - [System.Boolean] - $AllowCustomMemes, - - [Parameter()] - [System.Boolean] - $AllowUserEditMessages, - - [Parameter()] - [System.Boolean] - $AllowUserDeleteMessages, - - [Parameter()] - [System.Boolean] - $AllowOwnerDeleteMessages, - - [Parameter()] - [System.Boolean] - $AllowCreateUpdateRemoveConnectors, - - [Parameter()] - [System.Boolean] - $AllowCreateUpdateRemoveTabs, - - [Parameter()] - [System.Boolean] - $AllowCreateUpdateChannels, - - [Parameter()] - [System.Boolean] - $AllowDeleteChannels, - - [Parameter()] - [System.Boolean] - $AllowTeamMentions, - - [Parameter()] - [System.Boolean] - $AllowChannelMentions, - - [Parameter()] - [System.Boolean] - $AllowGuestCreateUpdateChannels, - - [Parameter()] - [System.Boolean] - $AllowGuestDeleteChannels, - - [Parameter()] - [System.Boolean] - $ShowInTeamsSearchAndSuggestions, + $WebSiteUrl, [Parameter()] [ValidateSet("Present", "Absent")] [System.String] $Ensure = "Present", - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $ApplicationId, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] $TenantId, - [Parameter()] + [Parameter(Mandatory = $true)] [System.String] - $CertificateThumbprint, - - [Parameter()] - [System.Management.Automation.PSCredential] - $GlobalAdminAccount + $CertificateThumbprint ) #region Telemetry $ResourceName = $MyInvocation.MyCommand.ModuleName.Replace("MSFT_", "") @@ -515,25 +324,17 @@ function Test-TargetResource Add-M365DSCTelemetryEvent -Data $data #endregion - Write-Verbose -Message "Testing configuration of Team $DisplayName" + Write-Verbose -Message "Testing configuration of Tab $DisplayName" $CurrentValues = Get-TargetResource @PSBoundParameters Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" - If (!$PSBoundParameters.ContainsKey('Ensure')) - { - $PSBoundParameters.Add('Ensure', $Ensure) - } $ValuesToCheck = $PSBoundParameters - $ValuesToCheck.Remove('GlobalAdminAccount') | Out-Null - $ValuesToCheck.Remove('GroupID') | Out-Null - - if ($null -eq $CurrentValues.Owner) - { - $ValuesToCheck.Remove("Owner") | Out-Null - } + $ValuesToCheck.Remove('TenantId') | Out-Null + $ValuesToCheck.Remove('ApplicationId') | Out-Null + $ValuesToCheck.Remove('CertificateThumbprint') | Out-Null $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` -Source $($MyInvocation.MyCommand.Source) ` diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof index 45b3711c8c..eb6cea7cf9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof @@ -8,7 +8,6 @@ class MSFT_TeamsChannelTab : OMI_BaseResource [Write, Description("Url of the tab's content.")]String ContentUrl; [Write, Description("Url of the website linked to the Channel Tab.")]String WebSiteUrl; [Write, Description("Present ensures the Tab exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; - [Write, Description("Credentials of the SharePoint Global Admin"), EmbeddedInstance("MSFT_Credential")] String GlobalAdminAccount; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsTeam/MSFT_TeamsTeam.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsTeam/MSFT_TeamsTeam.psm1 index e61141f359..dc74c4e7c5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsTeam/MSFT_TeamsTeam.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsTeam/MSFT_TeamsTeam.psm1 @@ -378,14 +378,14 @@ function Set-TargetResource $team = Get-TargetResource @PSBoundParameters $CurrentParameters = $PSBoundParameters - $CurrentParameters.Remove("Ensure") + $CurrentParameters.Remove("Ensure") | Out-Null if ($Ensure -eq "Present" -and ($team.Ensure -eq "Present")) { ## Can't pass Owner parm into set opertaion if ($CurrentParameters.ContainsKey("Owner")) { - $CurrentParameters.Remove("Owner") + $CurrentParameters.Remove("Owner") | Out-Null } if (-not $CurrentParameters.ContainsKey("GroupID")) { @@ -393,13 +393,13 @@ function Set-TargetResource } if ($ConnectionMode -eq 'Credential') { - $CurrentParameters.Remove("GlobalAdminAccount") + $CurrentParameters.Remove("GlobalAdminAccount") | Out-Null } else { - $CurrentParameters.Remove("ApplicationId") - $CurrentParameters.Remove("TenantId") - $CurrentParameters.Remove("CertificateThumbprint") + $CurrentParameters.Remove("ApplicationId") | Out-Null + $CurrentParameters.Remove("TenantId") | Out-Null + $CurrentParameters.Remove("CertificateThumbprint") | Out-Null } Set-Team @CurrentParameters Write-Verbose -Message "Updating team $DisplayName" @@ -409,7 +409,7 @@ function Set-TargetResource ## GroupID not used on New-Team cmdlet if ($CurrentParameters.ContainsKey("GroupID")) { - $CurrentParameters.Remove("GroupID") + $CurrentParameters.Remove("GroupID") | Out-Null } Write-Verbose -Message "Creating team $DisplayName" if ($null -ne $Owner) @@ -452,7 +452,7 @@ function Set-TargetResource } else { - $CurrentParameters.Remove("GlobalAdminAccount") + $CurrentParameters.Remove("GlobalAdminAccount") | Out-Null New-Team @CurrentParameters } } From 60ff2676d78386b567fa0d3a983023b5e10c66bf Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Nov 2020 14:33:55 -0500 Subject: [PATCH 10/33] Update MSFT_TeamsChannelTab.psm1 --- .../MSFT_TeamsChannelTab.psm1 | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index 69f619ad17..53569700e2 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -74,13 +74,14 @@ function Get-TargetResource if ([System.String]::IsNullOrEmpty($TeamId)) { Write-Verbose -Message "Getting team by Name {$TeamName}" + Write-Verbose -Message "PROFILE === $((Get-MgProfile).Name)" $filter = "displayName eq '$TeamName' and resourceProvisioningOptions/Any(x:x eq 'Team')" - $teamInstance = get-MgGroup -filter $filter -ErrorAction Stop | %{ @{ TeamId=$_.Id } } | get-MgTeam -ErrorAction Stop + $teamInstance = Get-MgGroup -Filter $filter -ErrorAction Stop | ForEach-Object { @{ TeamId = $_.Id } } | Get-MgTeam -ErrorAction Stop } else { Write-Verbose -Message "Getting team by Id {$TeamId}" - $teamInstance = get-MgTeam -TeamId $TeamId -ErrorAction Stop + $teamInstance = Get-MgTeam -TeamId $TeamId -ErrorAction Stop } } catch @@ -102,7 +103,7 @@ function Get-TargetResource } # Get the Channel ID - $channelInstance = Get-MgTeamChannel -TeamId $teamInstance.Id | Where-Object -FilterScript {$_.DisplayName -eq $ChannelName} + $channelInstance = Get-MgTeamChannel -TeamId $teamInstance.Id | Where-Object -FilterScript { $_.DisplayName -eq $ChannelName } if ($null -eq $channelInstance) { @@ -114,7 +115,7 @@ function Get-TargetResource # Get the Channel Tab $tabInstance = Get-MgTeamChannelTab -TeamId $teamInstance.Id ` - -ChannelId $channelInstance.Id | Where-Object -FilterScript {$_.DisplayName -eq $DisplayName} + -ChannelId $channelInstance.Id | Where-Object -FilterScript { $_.DisplayName -eq $DisplayName } if ($null -eq $tabInstance) { @@ -382,8 +383,8 @@ function Export-TargetResource { $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraphBeta' ` -InboundParameters $PSBoundParameters - - [array]$teams = get-mggroup -filter "resourceProvisioningOptions/Any(x:x eq 'Team')" + + [array]$teams = Get-MgGroup -Filter "resourceProvisioningOptions/Any(x:x eq 'Team')" $i = 1 $dscContent = "" Write-Host "`r`n" -NoNewline @@ -423,7 +424,7 @@ function Export-TargetResource -TenantId $TenantId } - $k =1 + $k = 1 foreach ($tab in $tabs) { Write-Host " |---[$k/$($tabs.Length)] $($tab.DisplayName)" -NoNewline From 16aab388b28f3c7175729c94dd1d52d2d3880e84 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 20 Nov 2020 14:39:12 -0500 Subject: [PATCH 11/33] Update MSFT_TeamsMeetingPolicy.schema.mof --- .../MSFT_TeamsMeetingPolicy.schema.mof | Bin 21966 -> 21972 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsMeetingPolicy/MSFT_TeamsMeetingPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsMeetingPolicy/MSFT_TeamsMeetingPolicy.schema.mof index dcc7aba1035bbffd560b4f086896ffd94fa77bc9..4ddb7b5b20f538bc4aeba27f1e05cdc628be05a6 100644 GIT binary patch delta 62 zcmX@Nn(@kN#toMO)k7Fk84?+C8HyR4!E`D^5s-ER;vxoDhCGH8h5&{ThN#I8g-a*f M`L=C-7xaJ$07Z}z+W-In delta 19 bcmcbzn(^Ff#toMOH&61DVch&B=m8S|Vtol& From fede954aaad35feb2f495fa922529505bbb57a5b Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Sun, 22 Nov 2020 07:56:03 -0500 Subject: [PATCH 12/33] Update MSFT_TeamsChannelTab.psm1 --- .../MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index 53569700e2..7b060d411b 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -74,8 +74,10 @@ function Get-TargetResource if ([System.String]::IsNullOrEmpty($TeamId)) { Write-Verbose -Message "Getting team by Name {$TeamName}" - Write-Verbose -Message "PROFILE === $((Get-MgProfile).Name)" + Write-Verbose -Message "PROFILE === $(Get-MgProfile -Verbose | Out-String)" $filter = "displayName eq '$TeamName' and resourceProvisioningOptions/Any(x:x eq 'Team')" + Write-Verbose -Message "Filter == $filter" + Select-MgProfile Beta $teamInstance = Get-MgGroup -Filter $filter -ErrorAction Stop | ForEach-Object { @{ TeamId = $_.Id } } | Get-MgTeam -ErrorAction Stop } else @@ -86,7 +88,7 @@ function Get-TargetResource } catch { - Write-Verbose -Message "$($_.Message)`r`n$($_.StackTrace)" + Write-Verbose -Message $_ Write-Verbose "The specified Service Principal doesn't have access to read Group information. Permission Required: Group.Read.All & Team.ReadBasic.All" Add-M365DSCEvent -Message $_ -EntryType 'Error' ` -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` @@ -120,7 +122,7 @@ function Get-TargetResource if ($null -eq $tabInstance) { $nullResult = $PSBoundParameters - $nullResult.Ensure = "Present" + $nullResult.Ensure = "Absent" return $nullResult } @@ -134,6 +136,7 @@ function Get-TargetResource ApplicationId = $ApplicationId TenantId = $TenantID CertificateThumbprint = $CertificateThumbprint + Ensure = "Present" } } catch From 5dd83102859a5786557c309ad66fdda9c5df3e0d Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Tue, 24 Nov 2020 00:00:27 +0100 Subject: [PATCH 13/33] Update MSFT_AADConditionalAccessPolicy.psm1 --- .../MSFT_AADConditionalAccessPolicy.psm1 | 664 ++++++++++++------ 1 file changed, 466 insertions(+), 198 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index 747c78da56..1478de4ffc 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -14,7 +14,7 @@ function Get-TargetResource [Parameter()] [System.String] - [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] + [ValidateSet('disabled', 'enabled', 'enabledForReportingButNotEnforced')] $State, #ConditionalAccessApplicationCondition @@ -138,7 +138,7 @@ function Get-TargetResource $SignInFrequency_Value, [Parameter()] - [ValidateSet('Days', 'Hours','')] + [ValidateSet('Days', 'Hours', '')] [System.String] $SignInFrequency_Type, @@ -147,7 +147,7 @@ function Get-TargetResource $SignInFrequency_IsEnabled, [Parameter()] - [ValidateSet('Always', 'Never','')] + [ValidateSet('Always', 'Never', '')] [System.String] $PersistentBrowser_Mode, @@ -200,7 +200,7 @@ function Get-TargetResource } catch { - $Policy = Get-AzureADMSConditionalAccessPolicy | Where-Object { $_.DisplayName -eq $DisplayName} + $Policy = Get-AzureADMSConditionalAccessPolicy | Where-Object { $_.DisplayName -eq $DisplayName } if ($Policy.Length -gt 1) { throw "Duplicate CA Policies named $DisplayName exist in tenant" @@ -211,7 +211,7 @@ function Get-TargetResource { Write-Verbose -Message "Id was NOT specified" ## Can retreive multiple CA Policies since displayname is not unique - $Policy = Get-AzureADMSConditionalAccessPolicy | Where-Object { $_.DisplayName -eq $DisplayName} + $Policy = Get-AzureADMSConditionalAccessPolicy | Where-Object { $_.DisplayName -eq $DisplayName } if ($Policy.Length -gt 1) { throw "Duplicate CA Policies named $DisplayName exist in tenant" @@ -226,61 +226,287 @@ function Get-TargetResource } else { - Write-Verbose -Message "Found existing Conditional Access policy" + Write-Verbose -Message "Get-TargetResource: Found existing Conditional Access policy" + $PolicyDisplayName = $Policy.DisplayName - $result = @{ - DisplayName = $Policy.DisplayName - Id = $Policy.Id - State = $Policy.State - IncludeApplications = [System.String[]]$Policy.Conditions.Applications.IncludeApplications#no translation of GUIDs - ExcludeApplications = [System.String[]]$Policy.Conditions.Applications.ExcludeApplications#no translation of GUIDs - IncludeUserActions = [System.String[]]$Policy.Conditions.Applications.IncludeUserActions#no translation needed - #IncludeProtectionLevels = [System.String[]]$Policy.Conditions.Applications.IncludeProtectionLevels - IncludeUsers = $Policy.Conditions.Users.IncludeUsers | ForEach-Object { if($_ -notmatch 'GuestsOrExternalUsers|All' -and $_){ (Get-AzureADUser -ObjectId $_).userprincipalname} else {$_}}#translate user GUIDs to UPN, except id value is GuestsOrExternalUsers or All - ExcludeUsers = $Policy.Conditions.Users.ExcludeUsers | ForEach-Object { if($_ -notmatch 'GuestsOrExternalUsers|All' -and $_){ (Get-AzureADUser -ObjectId $_).userprincipalname} else {$_}}#translate user GUIDs to UPN, except id value is GuestsOrExternalUsers or All - IncludeGroups = $policy.Conditions.Users.IncludeGroups | ForEach-Object { if($_){(Get-AzureADGroup -ObjectId $_).displayname}}#convert Group GUIDs to displayname - ExcludeGroups = $Policy.Conditions.Users.ExcludeGroups | ForEach-Object { if($_){(Get-AzureADGroup -ObjectId $_).displayname}}#convert Group GUIDs to displayname - IncludeRoles = if($Policy.Conditions.Users.IncludeRoles)#translate role template guids to role name + Write-Verbose -Message "Get-TargetResource: Process IncludeUsers" + #translate IncludeUser GUIDs to UPN, except id value is GuestsOrExternalUsers or All + $IncludeUsers = $null + if ($Policy.Conditions.Users.IncludeUsers) + { + $IncludeUsers = @() + foreach ($IncludeUserGUID in $Policy.Conditions.Users.IncludeUsers) + { + if ($IncludeUserGUID -notin "GuestsOrExternalUsers", "All") + { + $IncludeUser = $null + try + { + $IncludeUser = (Get-AzureADUser -ObjectId $IncludeUserGUID).userprincipalname + } + catch + { + New-M365DSCLogEntry -Error "$_" -Message "Couldn't find user $IncludeUserGUID , that is defined in policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + if ($IncludeUser) + { + $IncludeUsers += $IncludeUser + } + } + else + { + $IncludeUsers += $IncludeUserGUID + } + } + } + + Write-Verbose -Message "Get-TargetResource: Process ExcludeUsers" + #translate ExcludeUser GUIDs to UPN, except id value is GuestsOrExternalUsers or All + $ExcludeUsers = $null + if ($Policy.Conditions.Users.ExcludeUsers) + { + $ExcludeUsers = @() + foreach ($ExcludeUserGUID in $Policy.Conditions.Users.ExcludeUsers) + { + if ($ExcludeUserGUID -notin "GuestsOrExternalUsers", "All") + { + $ExcludeUser = $null + try + { + $ExcludeUser = (Get-AzureADUser -ObjectId $ExcludeUserGUID).userprincipalname + } + catch + { + New-M365DSCLogEntry -Error "$_" -Message "Couldn't find user $ExcludeUserGUID , that is defined in policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + if ($ExcludeUser) + { + $ExcludeUsers += $ExcludeUser + } + } + else + { + $ExcludeUsers += $ExcludeUserGUID + } + } + } + + Write-Verbose -Message "Get-TargetResource: Process IncludeGroups" + #translate IncludeGroup GUIDs to DisplayName + $IncludeGroups = $null + if ($Policy.Conditions.Users.IncludeGroups) + { + $IncludeGroups = @() + foreach ($IncludeGroupGUID in $Policy.Conditions.Users.IncludeGroups) + { + $IncludeGroup = $null + try + { + $IncludeGroup = (Get-AzureADGroup -ObjectId $IncludeGroupGUID).displayname + } + catch + { + New-M365DSCLogEntry -Error "$_" -Message "Couldn't find Group $IncludeGroupGUID , that is defined in policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + if ($IncludeGroup) + { + $IncludeGroups += $IncludeGroup + } + } + } + + Write-Verbose -Message "Get-TargetResource: Process ExcludeGroups" + #translate ExcludeGroup GUIDs to DisplayName + $ExcludeGroups = $null + if ($Policy.Conditions.Users.ExcludeGroups) + { + $ExcludeGroups = @() + foreach ($ExcludeGroupGUID in $Policy.Conditions.Users.ExcludeGroups) + { + $ExcludeGroup = $null + try + { + $ExcludeGroup = (Get-AzureADGroup -ObjectId $ExcludeGroupGUID).displayname + } + catch + { + New-M365DSCLogEntry -Error "$_" -Message "Couldn't find Group $ExcludeGroupGUID , that is defined in policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + if ($ExcludeGroup) + { + $ExcludeGroups += $ExcludeGroup + } + } + } + + + $IncludeRoles = $null + $ExcludeRoles = $null + #translate role template guids to role name + if ($Policy.Conditions.Users.IncludeRoles -or $Policy.Conditions.Users.ExcludeRoles) + { + Write-Verbose -Message "Get-TargetResource: Role condition defined, processing" + #build role translation table + $rolelookup = @{} + foreach ($role in Get-AzureADDirectoryRoleTemplate) + { + $rolelookup[$role.ObjectId] = $role.DisplayName + } + + Write-Verbose -Message "Get-TargetResource: Processing IncludeRoles" + if ($Policy.Conditions.Users.IncludeRoles) + { + $IncludeRoles = @() + foreach ($IncludeRoleGUID in $Policy.Conditions.Users.IncludeRoles) + { + if ($null -eq $rolelookup[$IncludeRoleGUID]) + { + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find role $IncludeRoleGUID , couldn't add to policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + else + { + $IncludeRoles += $rolelookup[$IncludeRoleGUID] + } + } + } + + Write-Verbose -Message "Get-TargetResource: Processing ExcludeRoles" + if ($Policy.Conditions.Users.ExcludeRoles) + { + $ExcludeRoles = @() + foreach ($ExcludeRoleGUID in $Policy.Conditions.Users.ExcludeRoles) + { + if ($null -eq $rolelookup[$ExcludeRoleGUID]) + { + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find role $ExcludeRoleGUID , couldn't add to policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + else + { + $ExcludeRoles += $rolelookup[$ExcludeRoleGUID] + } + } + } + + } + + $IncludeLocations = $null + $ExcludeLocations = $null + #translate Location template guids to Location name + if ($Policy.Conditions.Locations.IncludeLocations -or $Policy.Conditions.Locations.ExcludeLocations) + { + Write-Verbose -Message "Get-TargetResource: Location condition defined, processing" + #build Location translation table + $Locationlookup = @{} + foreach ($Location in Get-AzureADMSNamedLocationPolicy) { - $rolelookup=@{} - Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.ObjectId]=$_.DisplayName} - $Policy.Conditions.Users.IncludeRoles | ForEach-Object {$rolelookup[$_]} + $Locationlookup[$Location.Id] = $Location.DisplayName } - else {$null} - ExcludeRoles = if($Policy.Conditions.Users.ExcludeRoles)#translate role template guids to role name + Write-Verbose -Message "Get-TargetResource: Processing IncludeLocations" + if ($Policy.Conditions.Locations.IncludeLocations) { - $rolelookup=@{} - Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.ObjectId]=$_.DisplayName} - $Policy.Conditions.Users.ExcludeRoles | ForEach-Object {$rolelookup[$_]} + $IncludeLocations = @() + foreach ($IncludeLocationGUID in $Policy.Conditions.Locations.IncludeLocations) + { + if ($IncludeLocationGUID -in "All", "AllTrusted") + { + $IncludeLocations += $IncludeLocationGUID + } + elseif ($null -eq $Locationlookup[$IncludeLocationGUID]) + { + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find Location $IncludeLocationGUID , couldn't add to policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + else + { + $IncludeLocations += $Locationlookup[$IncludeLocationGUID] + } + } } - else {$null} - - IncludePlatforms = [System.String[]]$Policy.Conditions.Platforms.IncludePlatforms#no translation needed - ExcludePlatforms = [System.String[]]$Policy.Conditions.Platforms.ExcludePlatforms#no translation needed - IncludeLocations = $Policy.Conditions.Locations.IncludeLocations | ForEach-Object { if($_ -notmatch 'All' -and $_){ (Get-AzureADMSNamedLocationPolicy -PolicyId $_).DisplayName} else {$_}}#translate location GUIDs to Displayname, except if value is All or AllTrusted - ExcludeLocations = $Policy.Conditions.Locations.ExcludeLocations | ForEach-Object { if($_ -notmatch 'All' -and $_){ (Get-AzureADMSNamedLocationPolicy -PolicyId $_).DisplayName} else {$_}}#translate location GUIDs to Displayname, except if value is All or AllTrusted - IncludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.IncludeDeviceStates#no translation needed - ExcludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.ExcludeDeviceStates#no translation needed - UserRiskLevels = [System.String[]]$Policy.Conditions.UserRiskLevels#no translation needed - SignInRiskLevels = [System.String[]]$Policy.Conditions.SignInRiskLevels#no translation needed - ClientAppTypes = [System.String[]]$Policy.Conditions.ClientAppTypes#no translation needed - GrantControl_Operator = $Policy.GrantControls._Operator#no translation or conversion needed - BuiltInControls = [System.String[]]$Policy.GrantControls.BuiltInControls#no translation needed - ApplicationEnforcedRestrictions_IsEnabled = $Policy.SessionControls.ApplicationEnforcedRestrictions.IsEnabled#no translation or conversion needed - CloudAppSecurity_IsEnabled = $Policy.SessionControls.CloudAppSecurity.IsEnabled#no translation or conversion needed - CloudAppSecurity_Type = [System.String]$Policy.SessionControls.CloudAppSecurity.CloudAppSecurityType#no translation needed - SignInFrequency_Value = $Policy.SessionControls.SignInFrequency.Value#no translation or conversion needed - SignInFrequency_Type = [System.String]$Policy.SessionControls.SignInFrequency.Type#no translation needed - SignInFrequency_IsEnabled = $Policy.SessionControls.SignInFrequency.IsEnabled#no translation or conversion needed - PersistentBrowser_Mode = [System.String]$Policy.SessionControls.PersistentBrowser.Mode#no translation needed - PersistentBrowser_IsEnabled = $Policy.SessionControls.PersistentBrowser.IsEnabled#no translation or conversion needed -#Standard part - Ensure = "Present" - GlobalAdminAccount = $GlobalAdminAccount - ApplicationId = $ApplicationId - TenantId = $TenantId - CertificateThumbprint = $CertificateThumbprint + + Write-Verbose -Message "Get-TargetResource: Processing ExcludeLocations" + if ($Policy.Conditions.Locations.ExcludeLocations) + { + $ExcludeLocations = @() + foreach ($ExcludeLocationGUID in $Policy.Conditions.Locations.ExcludeLocations) + { + if ($ExcludeLocationGUID -in "All", "AllTrusted") + { + $ExcludeLocations += $ExcludeLocationGUID + } + elseif ($null -eq $Locationlookup[$ExcludeLocationGUID]) + { + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find Location $ExcludeLocationGUID , couldn't add to policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + } + else + { + $ExcludeLocations += $Locationlookup[$ExcludeLocationGUID] + } + } + } + + + } + + $result = @{ + DisplayName = $Policy.DisplayName + Id = $Policy.Id + State = $Policy.State + IncludeApplications = [System.String[]]$Policy.Conditions.Applications.IncludeApplications + #no translation of Application GUIDs + ExcludeApplications = [System.String[]]$Policy.Conditions.Applications.ExcludeApplications + #no translation of GUIDs + IncludeUserActions = [System.String[]]$Policy.Conditions.Applications.IncludeUserActions + #no translation needed + #IncludeProtectionLevels = [System.String[]]$Policy.Conditions.Applications.IncludeProtectionLevels + IncludeUsers = $IncludeUsers + ExcludeUsers = $ExcludeUsers + IncludeGroups = $IncludeGroups + ExcludeGroups = $ExcludeGroups + IncludeRoles = $IncludeRoles + ExcludeRoles = $ExcludeRoles + + IncludePlatforms = [System.String[]]$Policy.Conditions.Platforms.IncludePlatforms + #no translation needed + ExcludePlatforms = [System.String[]]$Policy.Conditions.Platforms.ExcludePlatforms + #no translation needed + IncludeLocations = $IncludeLocations + ExcludeLocations = $ExcludeLocations + IncludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.IncludeDeviceStates + #no translation needed + ExcludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.ExcludeDeviceStates + #no translation needed + UserRiskLevels = [System.String[]]$Policy.Conditions.UserRiskLevels + #no translation needed + SignInRiskLevels = [System.String[]]$Policy.Conditions.SignInRiskLevels + #no translation needed + ClientAppTypes = [System.String[]]$Policy.Conditions.ClientAppTypes + #no translation needed + GrantControl_Operator = $Policy.GrantControls._Operator + #no translation or conversion needed + BuiltInControls = [System.String[]]$Policy.GrantControls.BuiltInControls + #no translation needed + ApplicationEnforcedRestrictions_IsEnabled = $Policy.SessionControls.ApplicationEnforcedRestrictions.IsEnabled + #no translation or conversion needed + CloudAppSecurity_IsEnabled = $Policy.SessionControls.CloudAppSecurity.IsEnabled + #no translation or conversion needed + CloudAppSecurity_Type = [System.String]$Policy.SessionControls.CloudAppSecurity.CloudAppSecurityType + #no translation needed + SignInFrequency_Value = $Policy.SessionControls.SignInFrequency.Value + #no translation or conversion needed + SignInFrequency_Type = [System.String]$Policy.SessionControls.SignInFrequency.Type + #no translation needed + SignInFrequency_IsEnabled = $Policy.SessionControls.SignInFrequency.IsEnabled + #no translation or conversion needed + PersistentBrowser_Mode = [System.String]$Policy.SessionControls.PersistentBrowser.Mode + #no translation needed + PersistentBrowser_IsEnabled = $Policy.SessionControls.PersistentBrowser.IsEnabled + #no translation or conversion needed + #Standard part + Ensure = "Present" + GlobalAdminAccount = $GlobalAdminAccount + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint } Write-Verbose -Message "Get-TargetResource Result: `n $(Convert-M365DscHashtableToString -Hashtable $result)" return $result @@ -303,7 +529,7 @@ function Set-TargetResource [Parameter()] [System.String] - [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] + [ValidateSet('disabled', 'enabled', 'enabledForReportingButNotEnforced')] $State, #ConditionalAccessApplicationCondition @@ -427,7 +653,7 @@ function Set-TargetResource $SignInFrequency_Value, [Parameter()] - [ValidateSet('Days', 'Hours','')] + [ValidateSet('Days', 'Hours', '')] [System.String] $SignInFrequency_Type, @@ -436,7 +662,7 @@ function Set-TargetResource $SignInFrequency_IsEnabled, [Parameter()] - [ValidateSet('Always', 'Never','')] + [ValidateSet('Always', 'Never', '')] [System.String] $PersistentBrowser_Mode, @@ -492,9 +718,9 @@ function Set-TargetResource if ($Ensure -eq 'Present')#create policy attribute objects { Write-Verbose -Message "Set-Targetresource: Policy $Displayname Ensure Present" - $NewParameters=@{} - $NewParameters.Add("DisplayName",$DisplayName) - $NewParameters.Add("State",$State) + $NewParameters = @{} + $NewParameters.Add("DisplayName", $DisplayName) + $NewParameters.Add("State", $State) #create Conditions object Write-Verbose -Message "Set-Targetresource: create Conditions object" $conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet @@ -511,17 +737,22 @@ function Set-TargetResource foreach ($includeuser in $IncludeUsers) { #translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All - if($includeuser) + if ($includeuser) { - if($includeuser -notmatch 'GuestsOrExternalUsers|All') + if ($includeuser -notin "GuestsOrExternalUsers", "All") { - $userguid=$null - $userguid=(Get-AzureADUser -ObjectId $includeuser).ObjectId - if($null -eq $userguid) + $userguid = $null + try + { $userguid = (Get-AzureADUser -ObjectId $includeuser).ObjectId + } + catch + { New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + } + if ($null -eq $userguid) { - New-M365DSCLogEntry -Error $includeuser -Message "Couldn't find user $includeuser , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find user $includeuser , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - elseif (condition) + else { $conditions.Users.IncludeUsers += $userguid } @@ -536,17 +767,22 @@ function Set-TargetResource foreach ($excludeuser in $ExcludeUsers) { #translate user UPNs to GUID, except id value is GuestsOrExternalUsers or All - if($excludeuser) + if ($excludeuser) { - if($excludeuser -notmatch 'GuestsOrExternalUsers|All') + if ($excludeuser -notin "GuestsOrExternalUsers", "All") { - $userguid=$null - $userguid=(Get-AzureADUser -ObjectId $excludeuser).ObjectId - if($null -eq $userguid) + $userguid = $null + try + { $userguid = (Get-AzureADUser -ObjectId $excludeuser).ObjectId + } + catch + { New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + } + if ($null -eq $userguid) { - New-M365DSCLogEntry -Error $excludeuser -Message "Couldn't find user $excludeuser , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find user $excludeuser , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - elseif (condition) + else { $conditions.Users.ExcludeUsers += $userguid } @@ -558,20 +794,25 @@ function Set-TargetResource } } Write-Verbose -Message "Set-Targetresource: process includegroups" - foreach($includegroup in $IncludeGroups) + foreach ($includegroup in $IncludeGroups) { #translate user Group names to GUID - if($includegroup) + if ($includegroup) { - $Groupguid=$null - $Groupguid = Get-AzureADGroup -Filter "DisplayName eq '$includegroup'" + $Groupguid = $null + try + { $Groupguid = (Get-AzureADGroup -Filter "DisplayName eq '$includegroup'").ObjectId + } + catch + { New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + } if ($Groupguid.Length -gt 1) { - New-M365DSCLogEntry -Error $includegroup -Message "Duplicate group found with displayname $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Duplicate Object found" -Message "Duplicate group found with displayname $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - elseif($null -eq $Groupguid) + elseif ($null -eq $Groupguid) { - New-M365DSCLogEntry -Error $includegroup -Message "Couldn't find group $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find group $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } else { @@ -581,20 +822,25 @@ function Set-TargetResource } } Write-Verbose -Message "Set-Targetresource: process excludegroups" - foreach($excludegroup in $ExcludeGroups) + foreach ($excludegroup in $ExcludeGroups) { #translate user Group names to GUID - if($excludegroup) + if ($excludegroup) { - $Groupguid=$null - $Groupguid = Get-AzureADGroup -Filter "DisplayName eq '$excludegroup'" + $Groupguid = $null + try + { $Groupguid = (Get-AzureADGroup -Filter "DisplayName eq '$excludegroup'").ObjectId + } + catch + { New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + } if ($Groupguid.Length -gt 1) { - New-M365DSCLogEntry -Error $excludegroup -Message "Duplicate group found with displayname $excludegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Duplicate Object found" -Message "Duplicate group found with displayname $excludegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - elseif($null -eq $Groupguid) + elseif ($null -eq $Groupguid) { - New-M365DSCLogEntry -Error $excludegroup -Message "Couldn't find group $excludegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find group $excludegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } else { @@ -607,22 +853,22 @@ function Set-TargetResource if ($IncludeRoles) { #translate role names to template guid if defined - $rolelookup=@{} - Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.DisplayName]=$_.ObjectId} - $IncludeRoles | foreach-object + $rolelookup = @{} + foreach ($role in Get-AzureADDirectoryRoleTemplate) + { $rolelookup[$role.DisplayName] = $role.ObjectId + } + foreach ($IncludeRole in $IncludeRoles) { - if($_) + if ($IncludeRole) { - if($null -eq $rolelookup[$_]) + if ($null -eq $rolelookup[$IncludeRole]) { - New-M365DSCLogEntry -Error $_ -Message "Couldn't find role $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find role $IncludeRole , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - else { - { - $conditions.Users.IncludeRoles += $rolelookup[$_] - } + else + { + $conditions.Users.IncludeRoles += $rolelookup[$IncludeRole] } - } } } @@ -630,20 +876,21 @@ function Set-TargetResource if ($ExcludeRoles) { #translate role names to template guid if defined - $rolelookup=@{} - Get-AzureADDirectoryRoleTemplate | ForEach-Object {$rolelookup[$_.DisplayName]=$_.ObjectId} - $ExcludeRoles | foreach-object + $rolelookup = @{} + foreach ($role in Get-AzureADDirectoryRoleTemplate) + { $rolelookup[$role.DisplayName] = $role.ObjectId + } + foreach ($ExcludeRole in $ExcludeRoles) { - if($_) + if ($ExcludeRole) { - if($null -eq $rolelookup[$_]) + if ($null -eq $rolelookup[$ExcludeRole]) { - New-M365DSCLogEntry -Error $_ -Message "Couldn't find role $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find role $ExcludeRole , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - else { - { - $conditions.Users.ExcludeRoles += $rolelookup[$_] - } + else + { + $conditions.Users.ExcludeRoles += $rolelookup[$ExcludeRole] } } @@ -654,132 +901,148 @@ function Set-TargetResource { #create and provision Platform condition object if used $conditions.Platforms = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition - $conditions.Platforms.IncludePlatforms=$IncludePlatforms #no translation or conversion needed - $conditions.Platforms.ExcludePlatforms=$ExcludePlatforms#no translation or conversion needed + $conditions.Platforms.IncludePlatforms = $IncludePlatforms + #no translation or conversion needed + $conditions.Platforms.ExcludePlatforms = $ExcludePlatforms + #no translation or conversion needed } Write-Verbose -Message "Set-Targetresource: process include and exclude locations" if ($IncludeLocations -or $ExcludeLocations) { + Write-Verbose -Message "Set-Targetresource: locations specified" #create and provision Location condition object if used, translate Location names to guid $conditions.Locations = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessLocationCondition - $LocationLookup=@{} - Get-AzureADMSNamedLocationPolicy | ForEach-Object {$LocationLookup[$_.DisplayName]=$_.Id} - $IncludeLocations| foreach-object + $LocationLookup = @{} + foreach ($Location in Get-AzureADMSNamedLocationPolicy) + { + $LocationLookup[$Location.DisplayName] = $Location.Id + } + foreach ($IncludeLocation in $IncludeLocations) { - if($_) + if ($IncludeLocation) { - if($null -eq $LocationLookup[$_]) + if ($IncludeLocation -in "All", "AllTrusted") { - New-M365DSCLogEntry -Error $_ -Message "Couldn't find Location $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $conditions.Locations.IncludeLocations += $IncludeLocation } - elseif ($_ -eq "All" -or $_ -eq "AllTrusted") { - $conditions.Locations.IncludeLocations += $_ + elseif ($null -eq $LocationLookup[$IncludeLocation]) + { + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find Location $IncludeLocation , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - else { - { - $conditions.Locations.IncludeLocations += $LocationLookup[$_] - } + else + { + $conditions.Locations.IncludeLocations += $LocationLookup[$IncludeLocation] } } - $ExcludeLocations| foreach-object + } + foreach ($ExcludeLocation in $ExcludeLocations) { - if($_) + if ($ExcludeLocation) { - if($null -eq $LocationLookup[$_]) + if ($ExcludeLocation -eq "All" -or $ExcludeLocation -eq "AllTrusted") { - New-M365DSCLogEntry -Error $_ -Message "Couldn't find Location $_ , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $conditions.Locations.ExcludeLocations += $ExcludeLocation } - elseif ($_ -eq "All" -or $_ -eq "AllTrusted") { - $conditions.Locations.ExcludeLocations += $_ + elseif ($null -eq $LocationLookup[$ExcludeLocation]) + { + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find Location $ExcludeLocation , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - else { - { - $conditions.Locations.ExcludeLocations += $LocationLookup[$_] - } + else + { + $conditions.Locations.ExcludeLocations += $LocationLookup[$ExcludeLocation] } } } } -Write-Verbose -Message "Set-Targetresource: process device states" - if ($IncludeDeviceStates -or $ExcludeDeviceStates) - { - #create and provision Device condition object if used - $conditions.Devices = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessDevicesCondition - $conditions.Devices.IncludeDeviceStates=$IncludeDeviceStates#no translation or conversion needed - $conditions.Devices.ExcludeDeviceStates=$ExcludeDeviceStates#no translation or conversion needed - } -Write-Verbose -Message "Set-Targetresource: process risk levels and app types" - $Conditions.UserRiskLevels = $UserRiskLevels#no translation or conversion needed - $Conditions.SignInRiskLevels = $SignInRiskLevels #no translation or conversion needed - $Conditions.ClientAppTypes = $ClientAppTypes#no translation or conversion needed -Write-Verbose -Message "Set-Targetresource: Adding processed conditions" - $NewParameters.Add("Conditions",$Conditions)#add all conditions to the parameter list - #create and provision Grant Control object -Write-Verbose -Message "Set-Targetresource: create and provision Grant Control object" - $GrantControls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls - $GrantControls._Operator = $GrantControl_Operator - $GrantControls.BuiltInControls = $BuiltInControls #no translation or conversion needed - Write-Verbose -Message "Set-Targetresource: Adding processed grant controls" - $NewParameters.Add("GrantControls",$GrantControls)#add GrantControls to the parameter list -Write-Verbose -Message "Set-Targetresource: process session controls" - if ($ApplicationEnforcedRestrictions_IsEnabled -or $CloudAppSecurity_IsEnabled -or $SignInFrequency_IsEnabled -or $PersistentBrowser_IsEnabled) - { - #create and provision Session Control object if used - Write-Verbose -Message "Set-Targetresource:reate and provision Session Control object" - $sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSessionControls - if ($ApplicationEnforcedRestrictions_IsEnabled) + Write-Verbose -Message "Set-Targetresource: process device states" + if ($IncludeDeviceStates -or $ExcludeDeviceStates) { - #create and provision ApplicationEnforcedRestrictions object if used - $sessioncontrols.ApplicationEnforcedRestrictions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationEnforcedRestrictions - $sessioncontrols.ApplicationEnforcedRestrictions.IsEnabled = $true + #create and provision Device condition object if used + $conditions.Devices = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessDevicesCondition + $conditions.Devices.IncludeDeviceStates = $IncludeDeviceStates + #no translation or conversion needed + $conditions.Devices.ExcludeDeviceStates = $ExcludeDeviceStates + #no translation or conversion needed } - if ($CloudAppSecurity_IsEnabled) + Write-Verbose -Message "Set-Targetresource: process risk levels and app types" + $Conditions.UserRiskLevels = $UserRiskLevels + #no translation or conversion needed + $Conditions.SignInRiskLevels = $SignInRiskLevels + #no translation or conversion needed + $Conditions.ClientAppTypes = $ClientAppTypes + #no translation or conversion needed + Write-Verbose -Message "Set-Targetresource: Adding processed conditions" + #add all conditions to the parameter list + $NewParameters.Add("Conditions", $Conditions) + #create and provision Grant Control object + Write-Verbose -Message "Set-Targetresource: create and provision Grant Control object" + $GrantControls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls + $GrantControls._Operator = $GrantControl_Operator + $GrantControls.BuiltInControls = $BuiltInControls + #no translation or conversion needed + Write-Verbose -Message "Set-Targetresource: Adding processed grant controls" + $NewParameters.Add("GrantControls", $GrantControls) + #add GrantControls to the parameter list + Write-Verbose -Message "Set-Targetresource: process session controls" + if ($ApplicationEnforcedRestrictions_IsEnabled -or $CloudAppSecurity_IsEnabled -or $SignInFrequency_IsEnabled -or $PersistentBrowser_IsEnabled) { - #create and provision CloudAppSecurity object if used - $sessioncontrols.CloudAppSecurity = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessCloudAppSecurity - $sessioncontrols.CloudAppSecurity.IsEnabled=$true - $sessioncontrols.CloudAppSecurity.CloudAppSecurityType=$CloudAppSecurity_Type - } - if ($SignInFrequency_IsEnabled) - { - #create and provision SignInFrequency object if used - $sessioncontrols.SignInFrequency = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency - $sessioncontrols.SignInFrequency.IsEnabled =$true - $sessioncontrols.SignInFrequency.Type = $SignInFrequency_Type - $sessioncontrols.SignInFrequency.Value = $SignInFrequency_Value - } - if ($PersistentBrowser_IsEnabled) - { - #create and provision PersistentBrowser object if used - $sessioncontrols.PersistentBrowser = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser - $sessioncontrols.PersistentBrowser.IsEnabled =$true - $sessioncontrols.PersistentBrowser.Mode=$PersistentBrowser_Mode + #create and provision Session Control object if used + Write-Verbose -Message "Set-Targetresource: Create and provision Session Control object" + $sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSessionControls + if ($ApplicationEnforcedRestrictions_IsEnabled) + { + #create and provision ApplicationEnforcedRestrictions object if used + $sessioncontrols.ApplicationEnforcedRestrictions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationEnforcedRestrictions + $sessioncontrols.ApplicationEnforcedRestrictions.IsEnabled = $true + } + if ($CloudAppSecurity_IsEnabled) + { + #create and provision CloudAppSecurity object if used + $sessioncontrols.CloudAppSecurity = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessCloudAppSecurity + $sessioncontrols.CloudAppSecurity.IsEnabled = $true + $sessioncontrols.CloudAppSecurity.CloudAppSecurityType = $CloudAppSecurity_Type + } + if ($SignInFrequency_IsEnabled) + { + #create and provision SignInFrequency object if used + $sessioncontrols.SignInFrequency = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency + $sessioncontrols.SignInFrequency.IsEnabled = $true + $sessioncontrols.SignInFrequency.Type = $SignInFrequency_Type + $sessioncontrols.SignInFrequency.Value = $SignInFrequency_Value + } + if ($PersistentBrowser_IsEnabled) + { + #create and provision PersistentBrowser object if used + $sessioncontrols.PersistentBrowser = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser + $sessioncontrols.PersistentBrowser.IsEnabled = $true + $sessioncontrols.PersistentBrowser.Mode = $PersistentBrowser_Mode + } + $NewParameters.Add("SessionControls", $sessioncontrols) + #add SessionControls to the parameter list } - $NewParameters.Add("SessionControls",$sessioncontrols)#add SessionControls to the parameter list - } - } - } + } if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') { - - $NewParameters.Add("PolicyId",$Id) + Write-Verbose -Message "Set-Targetresource: Change policy $DisplayName" + $NewParameters.Add("PolicyId", $Id) try { - Write-Verbose -Message "Set-Targetresource: execute policy change in AAD" - Set-AzureADMSConditionalAccessPolicy @NewParameters - Write-Verbose -Message "Set-Targetresource: executed policy change in AAD" + Set-AzureADMSConditionalAccessPolicy @NewParameters } catch { New-M365DSCLogEntry -Error $_ -Message "Couldn't set policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + Write-Verbose -Message "Set-Targetresource: Failed change policy $DisplayName" + Write-Verbose -Message $_ } } elseif ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Absent') { + Write-Verbose -Message "Set-Targetresource: create policy $DisplayName" try { New-AzureADMSConditionalAccessPolicy @NewParameters @@ -787,10 +1050,13 @@ Write-Verbose -Message "Set-Targetresource: process session controls" catch { New-M365DSCLogEntry -Error $_ -Message "Couldn't create Policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + Write-Verbose -Message "Set-Targetresource: Failed creating policy" + Write-Verbose -Message $_ } } elseif ($Ensure -eq 'Absent' -and $currentPolicy.Ensure -eq 'Present') { + Write-Verbose -Message "Set-Targetresource: delete policy $DisplayName" try { Remove-AzureADMSConditionalAccessPolicy -PolicyId $currentPolicy.ID @@ -798,6 +1064,8 @@ Write-Verbose -Message "Set-Targetresource: process session controls" catch { New-M365DSCLogEntry -Error $_ -Message "Couldn't delete Policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + Write-Verbose -Message "Set-Targetresource: Failed deleting policy $DisplayName" + Write-Verbose -Message $_ } } Write-Verbose -Message "Set-Targetresource: finished processing Policy $Displayname" @@ -819,7 +1087,7 @@ function Test-TargetResource [Parameter()] [System.String] - [ValidateSet('disabled', 'enabled','enabledForReportingButNotEnforced')] + [ValidateSet('disabled', 'enabled', 'enabledForReportingButNotEnforced')] $State, #ConditionalAccessApplicationCondition @@ -943,7 +1211,7 @@ function Test-TargetResource $SignInFrequency_Value, [Parameter()] - [ValidateSet('Days', 'Hours','')] + [ValidateSet('Days', 'Hours', '')] [System.String] $SignInFrequency_Type, @@ -952,7 +1220,7 @@ function Test-TargetResource $SignInFrequency_IsEnabled, [Parameter()] - [ValidateSet('Always', 'Never','')] + [ValidateSet('Always', 'Never', '')] [System.String] $PersistentBrowser_Mode, @@ -1040,10 +1308,10 @@ function Export-TargetResource [array] $Policies = Get-AzureADMSConditionalAccessPolicy $i = 1 $dscContent = '' - Write-Host "`r`n" -NoNewLine + Write-Host "`r`n" -NoNewline foreach ($Policy in $Policies) { - Write-Host " |---[$i/$($Policies.Count)] $($Policy.DisplayName)" -NoNewLine + Write-Host " |---[$i/$($Policies.Count)] $($Policy.DisplayName)" -NoNewline $Params = @{ GlobalAdminAccount = $GlobalAdminAccount DisplayName = $Policy.DisplayName From 6a4413d28a1ef57f99511982dbaa91e29c75b14a Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Tue, 24 Nov 2020 01:16:47 +0100 Subject: [PATCH 14/33] Update MSFT_AADConditionalAccessPolicy.psm1 --- .../MSFT_AADConditionalAccessPolicy.psm1 | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index 1478de4ffc..a9112cdad7 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -799,54 +799,58 @@ function Set-TargetResource #translate user Group names to GUID if ($includegroup) { - $Groupguid = $null + $GroupLookup = $null try - { $Groupguid = (Get-AzureADGroup -Filter "DisplayName eq '$includegroup'").ObjectId + { $GroupLookup = Get-AzureADGroup -Filter "DisplayName eq '$includegroup'" } catch - { New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + { + New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + Write-Verbose -Message $_ } - if ($Groupguid.Length -gt 1) + if ($GroupLookup.Length -gt 1) { - New-M365DSCLogEntry -Error "Duplicate Object found" -Message "Duplicate group found with displayname $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Duplicate Object found" -Message "Duplicate group found with displayname $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - elseif ($null -eq $Groupguid) + elseif ($null -eq $GroupLookup) { New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find group $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } else { - $conditions.Users.IncludeGroups += $Groupguid + Write-Verbose -Message "adding group to includegroups" + $conditions.Users.IncludeGroups+=$GroupLookup.ObjectId } - } } Write-Verbose -Message "Set-Targetresource: process excludegroups" - foreach ($excludegroup in $ExcludeGroups) + foreach ($ExcludeGroup in $ExcludeGroups) { #translate user Group names to GUID - if ($excludegroup) + if ($ExcludeGroup) { - $Groupguid = $null + $GroupLookup = $null try - { $Groupguid = (Get-AzureADGroup -Filter "DisplayName eq '$excludegroup'").ObjectId + { $GroupLookup = Get-AzureADGroup -Filter "DisplayName eq '$ExcludeGroup'" } catch - { New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + { + New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + Write-Verbose -Message $_ } - if ($Groupguid.Length -gt 1) + if ($GroupLookup.Length -gt 1) { - New-M365DSCLogEntry -Error "Duplicate Object found" -Message "Duplicate group found with displayname $excludegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Duplicate Object found" -Message "Duplicate group found with displayname $ExcludeGroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } - elseif ($null -eq $Groupguid) + elseif ($null -eq $GroupLookup) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find group $excludegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find group $ExcludeGroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName } else { - $conditions.Users.ExcludeGroups += $Groupguid + Write-Verbose -Message "adding group to ExcludeGroups" + $conditions.Users.ExcludeGroups+=$GroupLookup.ObjectId } - } } Write-Verbose -Message "Set-Targetresource: process includeroles" @@ -1022,8 +1026,6 @@ function Set-TargetResource #add SessionControls to the parameter list } - - } if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') { From e8d1b0ff3076086badd300808a72aecc9933add0 Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Tue, 24 Nov 2020 13:49:12 +0100 Subject: [PATCH 15/33] Update MSFT_AADConditionalAccessPolicy.psm1 --- .../MSFT_AADConditionalAccessPolicy.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index a9112cdad7..94f68396e9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -1030,7 +1030,7 @@ function Set-TargetResource if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') { Write-Verbose -Message "Set-Targetresource: Change policy $DisplayName" - $NewParameters.Add("PolicyId", $Id) + $NewParameters.Add("PolicyId", $currentPolicy.Id) try { Set-AzureADMSConditionalAccessPolicy @NewParameters From 62908650507b15189ab3e2ba09b6d5210cd5ec0d Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Tue, 8 Dec 2020 12:57:35 -0500 Subject: [PATCH 16/33] Update MSFT_TeamsChannelTab.psm1 --- .../MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index 7b060d411b..e947a974c1 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -66,6 +66,9 @@ function Get-TargetResource $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraphBeta' ` -InboundParameters $PSBoundParameters + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftTeams' ` + -InboundParameters $PSBoundParameters + try { # Get the Team ID @@ -74,16 +77,12 @@ function Get-TargetResource if ([System.String]::IsNullOrEmpty($TeamId)) { Write-Verbose -Message "Getting team by Name {$TeamName}" - Write-Verbose -Message "PROFILE === $(Get-MgProfile -Verbose | Out-String)" - $filter = "displayName eq '$TeamName' and resourceProvisioningOptions/Any(x:x eq 'Team')" - Write-Verbose -Message "Filter == $filter" - Select-MgProfile Beta - $teamInstance = Get-MgGroup -Filter $filter -ErrorAction Stop | ForEach-Object { @{ TeamId = $_.Id } } | Get-MgTeam -ErrorAction Stop + $teamInstance = Get-Team | Where-Object -FilterScript {$_.DisplayName -eq $TeamName} } else { Write-Verbose -Message "Getting team by Id {$TeamId}" - $teamInstance = Get-MgTeam -TeamId $TeamId -ErrorAction Stop + $teamInstance = Get-Team -GroupId $TeamId -ErrorAction Stop } } catch From 966bcee778e37ce890390a200c0133790a5960d9 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 9 Dec 2020 08:20:03 -0500 Subject: [PATCH 17/33] Updates --- .../MSFT_TeamsChannelTab.psm1 | 50 ++++++++-------- .../MSFT_TeamsChannelTab.schema.mof | 2 +- Modules/Microsoft365DSC/Microsoft365DSC.psd1 | 57 ++++++++----------- 3 files changed, 52 insertions(+), 57 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index e947a974c1..fc2f38f8e7 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -24,8 +24,8 @@ function Get-TargetResource $TeamId, [Parameter()] - [System.String] - $ContentUrl, + [System.UInt32] + $SortOrderIndex, [Parameter()] [System.String] @@ -63,9 +63,6 @@ function Get-TargetResource $nullReturn = $PSBoundParameters $nullReturn.Ensure = "Absent" - $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraphBeta' ` - -InboundParameters $PSBoundParameters - $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftTeams' ` -InboundParameters $PSBoundParameters @@ -77,7 +74,7 @@ function Get-TargetResource if ([System.String]::IsNullOrEmpty($TeamId)) { Write-Verbose -Message "Getting team by Name {$TeamName}" - $teamInstance = Get-Team | Where-Object -FilterScript {$_.DisplayName -eq $TeamName} + $teamInstance = Get-Team | Where-Object -FilterScript { $_.DisplayName -eq $TeamName } } else { @@ -103,8 +100,11 @@ function Get-TargetResource throw $Message } + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters # Get the Channel ID - $channelInstance = Get-MgTeamChannel -TeamId $teamInstance.Id | Where-Object -FilterScript { $_.DisplayName -eq $ChannelName } + Write-Verbose -Message "Getting Channels for Team {$TeamName} with ID {$($teamInstance.GroupId)}" + $channelInstance = Get-MgTeamChannel -TeamId $teamInstance.GroupId | Where-Object -FilterScript { $_.DisplayName -eq $ChannelName } if ($null -eq $channelInstance) { @@ -115,7 +115,8 @@ function Get-TargetResource } # Get the Channel Tab - $tabInstance = Get-MgTeamChannelTab -TeamId $teamInstance.Id ` + Write-Verbose -Message "Getting Tabs for Channel {$ChannelName}" + $tabInstance = Get-MgTeamChannelTab -TeamId $teamInstance.GroupId ` -ChannelId $channelInstance.Id | Where-Object -FilterScript { $_.DisplayName -eq $DisplayName } if ($null -eq $tabInstance) @@ -126,12 +127,12 @@ function Get-TargetResource } return @{ - DisplayName = $DisplayName + DisplayName = $tabInstance.DisplayName TeamName = $TeamName - TeamId = $TeamId - ChannelName = $ChannelName - ContentUrl = $ContentUrl - WebSiteUrl = $WebSiteUrl + TeamId = $Team.GroupId + ChannelName = $channelInstance.DisplayName + SortOrderIndex = $tabInstance.SortOrderIndex + WebSiteUrl = $tabInstance.WebUrl ApplicationId = $ApplicationId TenantId = $TenantID CertificateThumbprint = $CertificateThumbprint @@ -189,8 +190,8 @@ function Set-TargetResource $TeamId, [Parameter()] - [System.String] - $ContentUrl, + [System.UInt32] + $SortOrderIndex, [Parameter()] [System.String] @@ -226,7 +227,7 @@ function Set-TargetResource Add-M365DSCTelemetryEvent -Data $data #endregion - $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraphBeta' ` + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraph' ` -InboundParameters $PSBoundParameters $tab = Get-TargetResource @PSBoundParameters @@ -293,8 +294,8 @@ function Test-TargetResource $TeamId, [Parameter()] - [System.String] - $ContentUrl, + [System.UInt32] + $SortOrderIndex, [Parameter()] [System.String] @@ -383,10 +384,13 @@ function Export-TargetResource try { - $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraphBeta' ` + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftTeams' ` -InboundParameters $PSBoundParameters - [array]$teams = Get-MgGroup -Filter "resourceProvisioningOptions/Any(x:x eq 'Team')" + [array]$teams = Get-Team $i = 1 $dscContent = "" Write-Host "`r`n" -NoNewline @@ -397,7 +401,7 @@ function Export-TargetResource $channels = $null try { - [array]$channels = Get-MgTeamChannel -TeamId $team.Id -ErrorAction Stop + [array]$channels = Get-MgTeamChannel -TeamId $team.GroupId -ErrorAction Stop } catch { @@ -415,7 +419,7 @@ function Export-TargetResource $tabs = $null try { - [array]$tabs = Get-MgTeamChannelTab -TeamId $team.Id ` + [array]$tabs = Get-MgTeamChannelTab -TeamId $team.GroupId ` -ChannelId $channel.Id -ErrorAction Stop } catch @@ -432,7 +436,7 @@ function Export-TargetResource Write-Host " |---[$k/$($tabs.Length)] $($tab.DisplayName)" -NoNewline $params = @{ TeamName = $team.DisplayName - TeamId = $team.Id + TeamId = $team.GroupId ChannelName = $channel.DisplayName DisplayName = $tab.DisplayName ApplicationId = $ApplicationId diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof index eb6cea7cf9..37f1b9f9ab 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof @@ -5,7 +5,7 @@ class MSFT_TeamsChannelTab : OMI_BaseResource [Required, Description("Display Name of the Team.")]String TeamName; [Required, Description("Display Name of the Channel.")]String ChannelName; [Write, Description("Unique Id of the Team of the instance on the source tenant.")]String TeamId; - [Write, Description("Url of the tab's content.")]String ContentUrl; + [Write, Description("Index of the sort order for the custom tab.")]UInt32 SortOrderIndex; [Write, Description("Url of the website linked to the Channel Tab.")]String WebSiteUrl; [Write, Description("Present ensures the Tab exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; diff --git a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 index 1ebd459adc..a60d11d4a3 100644 --- a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 +++ b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 @@ -3,7 +3,7 @@ # # Generated by: Microsoft Corporation # -# Generated on: 2020-11-18 +# Generated on: 2020-12-02 @{ @@ -11,7 +11,7 @@ # RootModule = '' # Version number of this module. - ModuleVersion = '1.20.1118.1' + ModuleVersion = '1.20.1202.1' # Supported PSEditions # CompatiblePSEditions = @() @@ -53,7 +53,7 @@ RequiredModules = @( @{ ModuleName = "AzureADPreview" - RequiredVersion = "2.0.2.119" + RequiredVersion = "2.0.2.129" }, @{ ModuleName = "DSCParser" @@ -61,15 +61,11 @@ }, @{ ModuleName = "ExchangeOnlineManagement" - RequiredVersion = "2.0.1" + RequiredVersion = "2.0.3" }, @{ ModuleName = "Microsoft.Graph.Authentication" - RequiredVersion = "1.1.0" - }, - @{ - ModuleName = "Microsoft.Graph.Groups" - RequiredVersion = "1.1.0" + RequiredVersion = "1.2.0" }, @{ ModuleName = "Microsoft.Graph.Groups.Planner" @@ -85,15 +81,15 @@ }, @{ ModuleName = "Microsoft.Graph.Planner" - RequiredVersion = "1.1.0" + RequiredVersion = "1.2.0" }, @{ ModuleName = "Microsoft.Graph.Teams" - RequiredVersion = "1.1.0" + RequiredVersion = "1.2.0" }, @{ ModuleName = "Microsoft.PowerApps.Administration.PowerShell" - RequiredVersion = "2.0.96" + RequiredVersion = "2.0.99" }, @{ ModuleName = "MicrosoftTeams" @@ -109,7 +105,7 @@ }, @{ ModuleName = "SharePointPnPPowerShellOnline" - RequiredVersion = "3.26.2010.0" + RequiredVersion = "3.28.2012.0" } ) @@ -184,26 +180,21 @@ IconUri = 'https://github.com/microsoft/Microsoft365DSC/blob/Dev/Modules/Microsoft365DSC/Dependencies/Images/Logo.png?raw=true' # ReleaseNotes of this module - ReleaseNotes = "* EXOMalwareFilterPolicy - * Fix an issue when the CustomFromAddress is empty; - (Issue #901) - * EXORemoteDomain - * Fixed an issue where only non-null parameters are - used in the Set-TargetResource resource; - (Issue #898) - * SCRetentionEventType - * Initial Release; - * SPOSiteScript - * BREAKING CHANGE: Title is now the primary key for the - resource and Service Principal is now supported for - authentication. - * MODULES - * M365DSCStringEncoding - New resource to handle encoding issues in exported content; - (Issue #904) - * M365DSCLogEngine - Added Export-M365DiagnosticData function to export diagnostic - information to a Zip file." + ReleaseNotes = "* EXOOwaMailboxPolicy + * Fixed an issue trying to remove a policy; + * TeamsMessagingPolicy + * Added AllowUserEditMessage property. + * TeamsMeetingPolicy + * Added 'OrganizerOnly' as a support value for property + AutoAdmittedUsers. + * Temporarly removed the use of AllowAnonymousUsersToDialOut + since it is currently disabled on the API side. + * EXPORT + * Fixed an issue where an Export using the -Workloads + parameter with a Service Principal did not export + any resource; + * DEPENDENCIES + * Upgrade AzureADPreview to version 2.0.2.129;" # Flag to indicate whether the module requires explicit user acceptance for install/update # RequireLicenseAcceptance = $false From 46223f28a97069eb704e0c732bf1bc5fd0c53ec1 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 9 Dec 2020 15:54:15 -0500 Subject: [PATCH 18/33] Updates --- .../MSFT_TeamsChannelTab.psm1 | 56 +++++++++++++++++-- .../MSFT_TeamsChannelTab.schema.mof | 1 + .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 3 + 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index fc2f38f8e7..d3007d9445 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -23,6 +23,10 @@ function Get-TargetResource [System.String] $TeamId, + [Parameter()] + [System.String] + $TeamsApp, + [Parameter()] [System.UInt32] $SortOrderIndex, @@ -133,6 +137,7 @@ function Get-TargetResource ChannelName = $channelInstance.DisplayName SortOrderIndex = $tabInstance.SortOrderIndex WebSiteUrl = $tabInstance.WebUrl + TeamsApp = $tabInstance.teamApp.id ApplicationId = $ApplicationId TenantId = $TenantID CertificateThumbprint = $CertificateThumbprint @@ -189,6 +194,10 @@ function Set-TargetResource [System.String] $TeamId, + [Parameter()] + [System.String] + $TeamsApp, + [Parameter()] [System.UInt32] $SortOrderIndex, @@ -242,21 +251,27 @@ function Set-TargetResource -Filter "DisplayName eq '$ChannelName'" $tabInstance = Get-MgTeamChannelTab -TeamId $tab.TeamId ` -ChannelId $ChannelInstance.Id ` - -Filter "DisplayName eq '$DisplayName" + -Filter "DisplayName eq '$DisplayName'" if ($Ensure -eq "Present" -and ($tab.Ensure -eq "Present")) { Write-Verbose -Message "Updating current instance of tab {$($tabInstance.DisplayName)}" $CurrentParameters.Add("ChannelId", $ChannelInstance.Id) $CurrentParameters.Add("TeamsTabId", $tabInstance.Id) + $CurrentParameters.Remove("TeamName") | Out-Null + $CurrentParameters.Remove("ChannelName") | Out-Null Update-MgTeamChannelTab @CurrentParameters | Out-Null } - elseif ($Ensure -eq "Present" -and ($team.Ensure -eq "Absent")) + elseif ($Ensure -eq "Present" -and ($tab.Ensure -eq "Absent")) { Write-Verbose -Message "Creating new tab {$DisplayName}" + Write-Verbose -Message "Params: $($CurrentParameters | Out-String)" + $CurrentParameters.Add("TeamsId", $tab.TeamId) $CurrentParameters.Add("ChannelId", $ChannelInstance.Id) - New-MgTeamChannelTab @CurrentParameters | Out-Null + $CurrentParameters.Remove("TeamName") | Out-Null + $CurrentParameters.Remove("ChannelName") | Out-Null + New-M365DSCTeamsChannelTab -Parameters $CurrentParameters } - elseif ($Ensure -eq "Absent" -and ($team.Ensure -eq "Present")) + elseif ($Ensure -eq "Absent" -and ($tab.Ensure -eq "Present")) { Write-Verbose -Message "Removing existing tab {$DisplayName}" $RemoveParams = @{ @@ -293,6 +308,10 @@ function Test-TargetResource [System.String] $TeamId, + [Parameter()] + [System.String] + $TeamsApp, + [Parameter()] [System.UInt32] $SortOrderIndex, @@ -329,6 +348,7 @@ function Test-TargetResource #endregion Write-Verbose -Message "Testing configuration of Tab $DisplayName" + Write-Verbose -Message "Parameters: $($PSBoundParameters | Out-String)" $CurrentValues = Get-TargetResource @PSBoundParameters @@ -481,4 +501,32 @@ function Export-TargetResource } } +function New-M365DSCTeamsChannelTab +{ + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [System.Collections.HashTable] + $Parameters + ) + + $jsonContent = @" + { + "displayName": "$($Parameters.DisplayName)", + "teamsApp@odata.bind": "$($Parameters.TeamsApp)", + "configuration": "{ + "websiteUrl": "$($Parameters.WebSiteUrl)", + "contentUrl": "$($Parameters.WebSiteUrl)" + } + } +"@ + $Url = "https://graph.microsoft.com/v1.0/teams/$($Parameters.TeamId)/channel/$($Parameters.ChannelId)/tabs" + Write-Verbose -Message "Creating new Teams Tab with JSON payload: `r`n$JSONContent" + Write-Verbose -Message "POST to {$Url}" + Invoke-MgGraphRequest -Method POST ` + -Uri $Url ` + -Body $JSONContent ` + -Headers @{"Content-Type" = "application/json" } | Out-Null +} + Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof index 37f1b9f9ab..b54e20a0d4 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof @@ -5,6 +5,7 @@ class MSFT_TeamsChannelTab : OMI_BaseResource [Required, Description("Display Name of the Team.")]String TeamName; [Required, Description("Display Name of the Channel.")]String ChannelName; [Write, Description("Unique Id of the Team of the instance on the source tenant.")]String TeamId; + [Write, Description("Id of the Teams App associated with the custom tab.")]String TeamsApp; [Write, Description("Index of the sort order for the custom tab.")]UInt32 SortOrderIndex; [Write, Description("Url of the website linked to the Channel Tab.")]String WebSiteUrl; [Write, Description("Present ensures the Tab exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index bed5b8e514..de580b42e9 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -1005,6 +1005,9 @@ function New-M365DSCConnection $SkipModuleReload = $false ) + Write-Verbose -Message "Attempting connection to {$Platform} with:" + Write-Verbose -Message "$($InboundParameters | Out-String)" + if ($SkipModuleReload -eq $true) { $Global:CurrentModeIsExport = $true From 3b6a07c412841139f93362d981367772b46f98eb Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Thu, 10 Dec 2020 09:45:38 +0100 Subject: [PATCH 19/33] Update MSFT_AADConditionalAccessPolicy.psm1 --- .../MSFT_AADConditionalAccessPolicy.psm1 | 569 +++++++++++++++++- 1 file changed, 544 insertions(+), 25 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index 94f68396e9..2f535e7535 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -246,7 +246,26 @@ function Get-TargetResource } catch { - New-M365DSCLogEntry -Error "$_" -Message "Couldn't find user $IncludeUserGUID , that is defined in policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + try + { + Write-Verbose -Message $_ + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message "Couldn't find user $IncludeUserGUID , that is defined in policy $PolicyDisplayName" -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } if ($IncludeUser) { @@ -277,7 +296,27 @@ function Get-TargetResource } catch { - New-M365DSCLogEntry -Error "$_" -Message "Couldn't find user $ExcludeUserGUID , that is defined in policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find user $ExcludeUserGUID , that is defined in policy $PolicyDisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } if ($ExcludeUser) { @@ -306,7 +345,27 @@ function Get-TargetResource } catch { - New-M365DSCLogEntry -Error "$_" -Message "Couldn't find Group $IncludeGroupGUID , that is defined in policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find Group $IncludeGroupGUID , that is defined in policy $PolicyDisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } if ($IncludeGroup) { @@ -330,7 +389,27 @@ function Get-TargetResource } catch { - New-M365DSCLogEntry -Error "$_" -Message "Couldn't find Group $ExcludeGroupGUID , that is defined in policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find Group $ExcludeGroupGUID , that is defined in policy $PolicyDisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } if ($ExcludeGroup) { @@ -361,7 +440,27 @@ function Get-TargetResource { if ($null -eq $rolelookup[$IncludeRoleGUID]) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find role $IncludeRoleGUID , couldn't add to policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find role $IncludeRoleGUID , couldn't add to policy $PolicyDisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -378,7 +477,28 @@ function Get-TargetResource { if ($null -eq $rolelookup[$ExcludeRoleGUID]) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find role $ExcludeRoleGUID , couldn't add to policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find role $ExcludeRoleGUID , couldn't add to policy $PolicyDisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -414,7 +534,28 @@ function Get-TargetResource } elseif ($null -eq $Locationlookup[$IncludeLocationGUID]) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find Location $IncludeLocationGUID , couldn't add to policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find Location $IncludeLocationGUID , couldn't add to policy $PolicyDisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -435,7 +576,28 @@ function Get-TargetResource } elseif ($null -eq $Locationlookup[$ExcludeLocationGUID]) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find Location $ExcludeLocationGUID , couldn't add to policy $PolicyDisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find Location $ExcludeLocationGUID , couldn't add to policy $PolicyDisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -746,11 +908,54 @@ function Set-TargetResource { $userguid = (Get-AzureADUser -ObjectId $includeuser).ObjectId } catch - { New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + { + $Message = $_ + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } if ($null -eq $userguid) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find user $includeuser , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find user $includeuser , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -776,11 +981,54 @@ function Set-TargetResource { $userguid = (Get-AzureADUser -ObjectId $excludeuser).ObjectId } catch - { New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + { + $Message = $_ + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } if ($null -eq $userguid) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find user $excludeuser , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find user $excludeuser , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -805,16 +1053,78 @@ function Set-TargetResource } catch { - New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + $Message = $_ + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + Write-Verbose -Message $_ } if ($GroupLookup.Length -gt 1) { - New-M365DSCLogEntry -Error "Duplicate Object found" -Message "Duplicate group found with displayname $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Duplicate group found with displayname $includegroup , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } elseif ($null -eq $GroupLookup) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find group $includegroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find group $includegroup , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -835,16 +1145,78 @@ function Set-TargetResource } catch { - New-M365DSCLogEntry -Error $_ -Source $MyInvocation.MyCommand.ModuleName + $Message = $_ + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } Write-Verbose -Message $_ } if ($GroupLookup.Length -gt 1) { - New-M365DSCLogEntry -Error "Duplicate Object found" -Message "Duplicate group found with displayname $ExcludeGroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Duplicate group found with displayname $ExcludeGroup , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } elseif ($null -eq $GroupLookup) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find group $ExcludeGroup , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find group $ExcludeGroup , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -867,7 +1239,28 @@ function Set-TargetResource { if ($null -eq $rolelookup[$IncludeRole]) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find role $IncludeRole , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find role $IncludeRole , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -890,7 +1283,28 @@ function Set-TargetResource { if ($null -eq $rolelookup[$ExcludeRole]) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find role $ExcludeRole , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find role $ExcludeRole , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -931,7 +1345,28 @@ function Set-TargetResource } elseif ($null -eq $LocationLookup[$IncludeLocation]) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find Location $IncludeLocation , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find Location $IncludeLocation , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -949,7 +1384,28 @@ function Set-TargetResource } elseif ($null -eq $LocationLookup[$ExcludeLocation]) { - New-M365DSCLogEntry -Error "Object not found" -Message "Couldn't find Location $ExcludeLocation , couldn't add to policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = "Couldn't find Location $ExcludeLocation , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + } else { @@ -1037,7 +1493,28 @@ function Set-TargetResource } catch { - New-M365DSCLogEntry -Error $_ -Message "Couldn't set policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = $_ + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + Write-Verbose -Message "Set-Targetresource: Failed change policy $DisplayName" Write-Verbose -Message $_ } @@ -1051,7 +1528,28 @@ function Set-TargetResource } catch { - New-M365DSCLogEntry -Error $_ -Message "Couldn't create Policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = $_ + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + Write-Verbose -Message "Set-Targetresource: Failed creating policy" Write-Verbose -Message $_ } @@ -1065,7 +1563,28 @@ function Set-TargetResource } catch { - New-M365DSCLogEntry -Error $_ -Message "Couldn't delete Policy $DisplayName" -Source $MyInvocation.MyCommand.ModuleName + $Message = $_ + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } + Write-Verbose -Message "Set-Targetresource: Failed deleting policy $DisplayName" Write-Verbose -Message $_ } From 6c72d1194ef083ef8cffd18dc314cd2c92e67761 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Thu, 10 Dec 2020 09:04:00 -0500 Subject: [PATCH 20/33] O365User - Support Ensure = Absent --- CHANGELOG.md | 6 + .../MSFT_O365User/MSFT_O365User.psm1 | 196 +++++++++--------- 2 files changed, 108 insertions(+), 94 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03b4892eab..1d13b04dc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change log for Microsoft365DSC +# 1.20.1216.1 + +* O365User + * Added support for removing existing users with + Ensure = 'Absent'; + # 1.20.1209.1 * IntuneAppProtectionPolicyiOS diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_O365User/MSFT_O365User.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_O365User/MSFT_O365User.psm1 index 4a00516481..c1eeea340f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_O365User/MSFT_O365User.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_O365User/MSFT_O365User.psm1 @@ -370,124 +370,132 @@ function Set-TargetResource -InboundParameters $PSBoundParameters $user = Get-TargetResource @PSBoundParameters - $PasswordPolicies = $null - if ($PasswordNeverExpires) + if ($user.Ensure -eq 'Present' -and $Ensure -eq 'Absent') { - $PasswordPolicies = 'DisablePasswordExpiration' + Write-Verbose -Message "Removing User {$UserPrincipalName}" + Remove-AzureADUser -ObjectId $UserPrincipalName } else { - $PasswordPolicies = "None" - } - $CreationParams = @{ - City = $City - Country = $Country - Department = $Department - DisplayName = $DisplayName - FacsimileTelephoneNumber = $Fax - GivenName = $FirstName - JobTitle = $Title - Mobile = $MobilePhone - PasswordPolicies = $PasswordPolicies - PhysicalDeliveryOfficeName = $Office - PostalCode = $PostalCode - PreferredLanguage = $PreferredLanguage - State = $State - StreetAddress = $StreetAddress - Surname = $LastName - TelephoneNumber = $PhoneNumber - UsageLocation = $UsageLocation - UserPrincipalName = $UserPrincipalName - UserType = $UserType - } - $CreationParams = Remove-NullEntriesFromHashtable -Hash $CreationParams - - $licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses - - foreach ($licenseSkuPart in $LicenseAssignment) - { - Write-Verbose -Message "Adding License {$licenseSkuPart} to the Queue" - $license = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense - $license.SkuId = (Get-AzureADSubscribedSku | Where-Object -Property SkuPartNumber -Value $licenseSkuPart -EQ).SkuID + $PasswordPolicies = $null + if ($PasswordNeverExpires) + { + $PasswordPolicies = 'DisablePasswordExpiration' + } + else + { + $PasswordPolicies = "None" + } + $CreationParams = @{ + City = $City + Country = $Country + Department = $Department + DisplayName = $DisplayName + FacsimileTelephoneNumber = $Fax + GivenName = $FirstName + JobTitle = $Title + Mobile = $MobilePhone + PasswordPolicies = $PasswordPolicies + PhysicalDeliveryOfficeName = $Office + PostalCode = $PostalCode + PreferredLanguage = $PreferredLanguage + State = $State + StreetAddress = $StreetAddress + Surname = $LastName + TelephoneNumber = $PhoneNumber + UsageLocation = $UsageLocation + UserPrincipalName = $UserPrincipalName + UserType = $UserType + } + $CreationParams = Remove-NullEntriesFromHashtable -Hash $CreationParams - # Set the Office license as the license we want to add in the $licenses object - $licenses.AddLicenses += $license - } + $licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses - foreach ($currentLicense in $user.LicenseAssignment) - { - if (-not $LicenseAssignment.Contains($currentLicense)) + foreach ($licenseSkuPart in $LicenseAssignment) { - Write-Verbose -Message "Removing {$currentLicense} from user {$UserPrincipalName}" - $license = (Get-AzureADSubscribedSku | Where-Object -Property SkuPartNumber -Value $currentLicense -EQ).SkuID - $licenses.RemoveLicenses += $license - } - } + Write-Verbose -Message "Adding License {$licenseSkuPart} to the Queue" + $license = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense + $license.SkuId = (Get-AzureADSubscribedSku | Where-Object -Property SkuPartNumber -Value $licenseSkuPart -EQ).SkuID - if ($user.UserPrincipalName) - { + # Set the Office license as the license we want to add in the $licenses object + $licenses.AddLicenses += $license + } - if ($null -ne $licenses -and ` - ($licenses.AddLicenses.Length -gt 0 -or $licenses.RemoveLicenses.Length -gt 0)) + foreach ($currentLicense in $user.LicenseAssignment) { - Write-Verbose -Message "Updating License Assignment {$($licenses[0] | Out-String)}" - try - { - Write-Verbose -Message "Assigning $($licenses.Count) licences to existing user" - Set-AzureADUserLicense -ObjectId $UserPrincipalName ` - -AssignedLicenses $licenses ` - -ErrorAction SilentlyContinue - } - catch + if (-not $LicenseAssignment.Contains($currentLicense)) { - $Message = "License {$($LicenseAssignment)} doesn't exist in tenant." - Write-Verbose $Message - New-M365DSCLogEntry -Error $_ -Message $Message -Source $MyInvocation.MyCommand.ModuleName + Write-Verbose -Message "Removing {$currentLicense} from user {$UserPrincipalName}" + $license = (Get-AzureADSubscribedSku | Where-Object -Property SkuPartNumber -Value $currentLicense -EQ).SkuID + $licenses.RemoveLicenses += $license } } - Write-Verbose -Message "Updating Office 365 User $UserPrincipalName Information" - $CreationParams.Add("ObjectID", $UserPrincipalName) - $user = Set-AzureADUser @CreationParams - } - else - { - Write-Verbose -Message "Creating Office 365 User $UserPrincipalName" - $CreationParams.Add("AccountEnabled", $true) - $PasswordProfile = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordProfile - $PasswordProfile.Password = 'TempP@ss' - $CreationParams.Add("PasswordProfile", $PasswordProfile) - $CreationParams.Add("MailNickName", $UserPrincipalName.Split('@')[0]) - $user = New-AzureADUser @CreationParams - Set-AzureADUserPassword -ObjectId $UserPrincipalName -Password $Password.Password | Out-Null - - try + if ($user.UserPrincipalName) { + if ($null -ne $licenses -and ` - ($licenses.AddLicenses.Length -gt 0)) + ($licenses.AddLicenses.Length -gt 0 -or $licenses.RemoveLicenses.Length -gt 0)) { - Write-Verbose -Message "Assigning $($licenses.Count) licences to new user" - Set-AzureADUserLicense -ObjectId $UserPrincipalName ` - -AssignedLicenses $licenses ` - -ErrorAction SilentlyContinue + Write-Verbose -Message "Updating License Assignment {$($licenses[0] | Out-String)}" + try + { + Write-Verbose -Message "Assigning $($licenses.Count) licences to existing user" + Set-AzureADUserLicense -ObjectId $UserPrincipalName ` + -AssignedLicenses $licenses ` + -ErrorAction SilentlyContinue + } + catch + { + $Message = "License {$($LicenseAssignment)} doesn't exist in tenant." + Write-Verbose $Message + New-M365DSCLogEntry -Error $_ -Message $Message -Source $MyInvocation.MyCommand.ModuleName + } } + + Write-Verbose -Message "Updating Office 365 User $UserPrincipalName Information" + $CreationParams.Add("ObjectID", $UserPrincipalName) + $user = Set-AzureADUser @CreationParams } - catch + else { - $Message = "Could not assign license {$($licenses.AddLicenses)} to user {$UserPrincipalName}" - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) + Write-Verbose -Message "Creating Office 365 User $UserPrincipalName" + $CreationParams.Add("AccountEnabled", $true) + $PasswordProfile = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordProfile + $PasswordProfile.Password = 'TempP@ss' + $CreationParams.Add("PasswordProfile", $PasswordProfile) + $CreationParams.Add("MailNickName", $UserPrincipalName.Split('@')[0]) + $user = New-AzureADUser @CreationParams + Set-AzureADUserPassword -ObjectId $UserPrincipalName -Password $Password.Password | Out-Null + + try { - $tenantIdValue = $TenantId + if ($null -ne $licenses -and ` + ($licenses.AddLicenses.Length -gt 0)) + { + Write-Verbose -Message "Assigning $($licenses.Count) licences to new user" + Set-AzureADUserLicense -ObjectId $UserPrincipalName ` + -AssignedLicenses $licenses ` + -ErrorAction SilentlyContinue + } } - elseif ($null -ne $GlobalAdminAccount) + catch { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + $Message = "Could not assign license {$($licenses.AddLicenses)} to user {$UserPrincipalName}" + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + New-M365DSCLogEntry -Error $_ -Message $Message ` + -Source $MyInvocation.MyCommand.ModuleName ` + -TenantId $tenantIdValue + throw $Message } - New-M365DSCLogEntry -Error $_ -Message $Message ` - -Source $MyInvocation.MyCommand.ModuleName ` - -TenantId $tenantIdValue - throw $Message } } } From 1506f7b0424bbb12b02a04b2a3acde23a5805d27 Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Thu, 10 Dec 2020 22:05:44 +0100 Subject: [PATCH 21/33] Create Microsoft365DSC.AADConditionalAccessPolicy.Tests.ps1 --- ...65DSC.AADConditionalAccessPolicy.Tests.ps1 | 612 ++++++++++++++++++ 1 file changed, 612 insertions(+) create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADConditionalAccessPolicy.Tests.ps1 diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADConditionalAccessPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADConditionalAccessPolicy.Tests.ps1 new file mode 100644 index 0000000000..21d1e8ce37 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADConditionalAccessPolicy.Tests.ps1 @@ -0,0 +1,612 @@ +[CmdletBinding()] +param( +) +$M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` + -ChildPath "..\..\Unit" ` + -Resolve +$CmdletModule = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath "\Stubs\Microsoft365.psm1" ` + -Resolve) +$GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath "\Stubs\Generic.psm1" ` + -Resolve) +Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` + -ChildPath "\UnitTestHelper.psm1" ` + -Resolve) + +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource "AADConditionalAccessPolicy" -GenericStubModule $GenericStubPath + +Describe -Name $Global:DscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope + + BeforeAll { + $secpasswd = ConvertTo-SecureString "Pass@word1)" -AsPlainText -Force + $GlobalAdminAccount = New-Object System.Management.Automation.PSCredential ("tenantadmin", $secpasswd) + + Mock -CommandName Update-M365DSCExportAuthenticationResults -MockWith { + return @{} + } + + Mock -CommandName Get-M365DSCExportContentForResource -MockWith { + + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credential" + } + + Mock -CommandName New-AzureADMSConditionalAccessPolicy -MockWith { + } + + Mock -CommandName Set-AzureADMSConditionalAccessPolicy -MockWith { + } + + Mock -CommandName Remove-AzureADMSConditionalAccessPolicy -MockWith { + } + } + + # Test contexts + Context -Name "When Conditional Access Policy doesn't exist but should" -Fixture { + BeforeAll { + $testParams = @{ + BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") + CloudAppSecurity_IsEnabled = $True + CloudAppSecurity_Type = "MonitorOnly" + DisplayName = "Allin" + Ensure = "Present" + ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") + ExcludeDeviceStates = @("Compliant","DomainJoined") + ExcludeGroups = @("Group 01") + ExcludeLocations = "Contoso LAN" + ExcludePlatforms = @("Windows","WindowsPhone","MacOS") + ExcludeRoles = @("Compliance Administrator") + ExcludeUsers = "alexw@contoso.com" + GlobalAdminAccount = $Credsglobaladmin + GrantControl_Operator = "AND" + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + IncludeApplications = @("All") + IncludeDeviceStates = @("All") + IncludeGroups = @("Group 01") + IncludeLocations = "AllTrusted" + IncludePlatforms = @("Android","IOS") + IncludeRoles = @("Compliance Administrator") + IncludeUserActions = @("urn:user:registersecurityinfo") + IncludeUsers = "All" + PersistentBrowser_IsEnabled = $True + PersistentBrowser_Mode = "Always" + SignInFrequency_IsEnabled = $True + SignInFrequency_Type = "Days" + SignInFrequency_Value = 5 + SignInRiskLevels = @("High") + State = "disabled" + UserRiskLevels = @("High") + } + + Mock -CommandName Get-AzureADMSConditionalAccessPolicy -MockWith { + return $null + } + Mock -CommandName Get-AzureADUser -MockWith { + return @{ + ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" + UserPrincipalName = "alexw@contoso.com" + } + } + Mock -CommandName Get-AzureADGroup -MockWith { + return @{ + ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" + DisplayName = "Group 01" + } + } + Mock -CommandName Get-AzureADDirectoryRoleTemplate -MockWith { + return @{ + ObjectId = "17315797-102d-40b4-93e0-432062caca18" + DisplayName = "Compliance Administrator" + } + } + Mock -CommandName Get-AzureADMSNamedLocationPolicy -MockWith { + return @{ + Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + DisplayName = "Contoso LAN" + } + } + } + + It "Should return absent from the Get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + + It "Should return false from the Test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should create the policy in the Set method" { + Set-TargetResource @testParams + Should -Invoke -CommandName New-AzureADMSConditionalAccessPolicy -Exactly 1 + } + } + + Context -Name "Policy exists but is not in the Desired State" -Fixture { + BeforeAll { + $testParams = @{ + ApplicationEnforcedRestrictions_IsEnabled = $True + BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") + CloudAppSecurity_IsEnabled = $True + CloudAppSecurity_Type = "MonitorOnly" + DisplayName = "Allin" + Ensure = "Present" + ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") + ExcludeDeviceStates = @("Compliant","DomainJoined") + ExcludeGroups = @("Group 01") + ExcludeLocations = "Contoso LAN" + ExcludePlatforms = @("Windows","WindowsPhone","MacOS") + ExcludeRoles = @("Compliance Administrator") + ExcludeUsers = "alexw@contoso.com" + GlobalAdminAccount = $Credsglobaladmin + GrantControl_Operator = "AND" + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + IncludeApplications = @("All") + IncludeDeviceStates = @("All") + IncludeGroups = @("Group 01") + IncludeLocations = "AllTrusted" + IncludePlatforms = @("Android","IOS") + IncludeRoles = @("Compliance Administrator") + IncludeUserActions = @("urn:user:registersecurityinfo") + IncludeUsers = "All" + PersistentBrowser_IsEnabled = $True + PersistentBrowser_Mode = "Always" + SignInFrequency_IsEnabled = $True + SignInFrequency_Type = "Days" + SignInFrequency_Value = 5 + SignInRiskLevels = @("High") + State = "disabled" + UserRiskLevels = @("High") + } + + Mock -CommandName Get-AzureADMSConditionalAccessPolicy -MockWith { + return @{ + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + DisplayName = "Allin" + State = "enabled" + Conditions = @{ + Applications = @{ + IncludeApplications = @("All") + ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") + IncludeUserActions = @("urn:user:registersecurityinfo") + } + Users = @{ + IncludeUsers = "All" + ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" + IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + } + Platforms = @{ + IncludePlatforms = @("Android","IOS") + ExcludePlatforms = @("Windows","WindowsPhone","MacOS") + } + Locations = @{ + IncludeLocations = "AllTrusted" + ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + } + Devices = @{ + IncludeDeviceStates = @("All") + ExcludeDeviceStates = @("Compliant","DomainJoined") + } + ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") + SignInRiskLevels = @("High") + UserRiskLevels = @("High") + } + GrantControls = @{ + _Operator = "AND" + BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + } + SessionControls = @{ + ApplicationEnforcedRestrictions = @{ + IsEnabled = $True + } + CloudAppSecurity = @{ + IsEnabled = $True + CloudAppSecurityType = "MonitorOnly" + } + SignInFrequency = @{ + IsEnabled = $True + Type = "Days" + Value = 5 + } + PersistentBrowser = @{ + IsEnabled = $True + Mode = "Always" + } + } + } + } + Mock -CommandName Get-AzureADUser -MockWith { + return @{ + ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" + UserPrincipalName = "alexw@contoso.com" + } + } + Mock -CommandName Get-AzureADGroup -MockWith { + return @{ + ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" + DisplayName = "Group 01" + } + } + Mock -CommandName Get-AzureADDirectoryRoleTemplate -MockWith { + return @{ + ObjectId = "17315797-102d-40b4-93e0-432062caca18" + DisplayName = "Compliance Administrator" + } + } + Mock -CommandName Get-AzureADMSNamedLocationPolicy -MockWith { + return @{ + Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + DisplayName = "Contoso LAN" + } + } + } + + It "Should return Present from the Get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It "Should return false from the Test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should update the settings from the Set method" { + Set-TargetResource @testParams + Should -Invoke -CommandName Set-AzureADMSConditionalAccessPolicy -Exactly 1 + } + } + + Context -Name "Policy exists and is already in the Desired State" -Fixture { + BeforeAll { + $testParams = @{ + ApplicationEnforcedRestrictions_IsEnabled = $True + BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") + CloudAppSecurity_IsEnabled = $True + CloudAppSecurity_Type = "MonitorOnly" + DisplayName = "Allin" + Ensure = "Present" + ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") + ExcludeDeviceStates = @("Compliant","DomainJoined") + ExcludeGroups = @("Group 01") + ExcludeLocations = "Contoso LAN" + ExcludePlatforms = @("Windows","WindowsPhone","MacOS") + ExcludeRoles = @("Compliance Administrator") + ExcludeUsers = "alexw@contoso.com" + GlobalAdminAccount = $Credsglobaladmin + GrantControl_Operator = "AND" + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + IncludeApplications = @("All") + IncludeDeviceStates = @("All") + IncludeGroups = @("Group 01") + IncludeLocations = "AllTrusted" + IncludePlatforms = @("Android","IOS") + IncludeRoles = @("Compliance Administrator") + IncludeUserActions = @("urn:user:registersecurityinfo") + IncludeUsers = "All" + PersistentBrowser_IsEnabled = $True + PersistentBrowser_Mode = "Always" + SignInFrequency_IsEnabled = $True + SignInFrequency_Type = "Days" + SignInFrequency_Value = 5 + SignInRiskLevels = @("High") + State = "disabled" + UserRiskLevels = @("High") + } + + Mock -CommandName Get-AzureADMSConditionalAccessPolicy -MockWith { + return @{ + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + DisplayName = "Allin" + State = "disabled" + Conditions = @{ + Applications = @{ + IncludeApplications = @("All") + ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") + IncludeUserActions = @("urn:user:registersecurityinfo") + } + Users = @{ + IncludeUsers = "All" + ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" + IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + } + Platforms = @{ + IncludePlatforms = @("Android","IOS") + ExcludePlatforms = @("Windows","WindowsPhone","MacOS") + } + Locations = @{ + IncludeLocations = "AllTrusted" + ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + } + Devices = @{ + IncludeDeviceStates = @("All") + ExcludeDeviceStates = @("Compliant","DomainJoined") + } + ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") + SignInRiskLevels = @("High") + UserRiskLevels = @("High") + } + GrantControls = @{ + _Operator = "AND" + BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + } + SessionControls = @{ + ApplicationEnforcedRestrictions = @{ + IsEnabled = $True + } + CloudAppSecurity = @{ + IsEnabled = $True + CloudAppSecurityType = "MonitorOnly" + } + SignInFrequency = @{ + IsEnabled = $True + Type = "Days" + Value = 5 + } + PersistentBrowser = @{ + IsEnabled = $True + Mode = "Always" + } + } + } + } + Mock -CommandName Get-AzureADUser -MockWith { + return @{ + ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" + UserPrincipalName = "alexw@contoso.com" + } + } + Mock -CommandName Get-AzureADGroup -MockWith { + return @{ + ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" + DisplayName = "Group 01" + } + } + Mock -CommandName Get-AzureADDirectoryRoleTemplate -MockWith { + return @{ + ObjectId = "17315797-102d-40b4-93e0-432062caca18" + DisplayName = "Compliance Administrator" + } + } + Mock -CommandName Get-AzureADMSNamedLocationPolicy -MockWith { + return @{ + Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + DisplayName = "Contoso LAN" + } + } + + } + + It "Should return Present from the Get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It "Should return true from the Test method" { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "Policy exists but it should not" -Fixture { + BeforeAll { + $testParams = @{ + ApplicationEnforcedRestrictions_IsEnabled = $True + BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") + CloudAppSecurity_IsEnabled = $True + CloudAppSecurity_Type = "MonitorOnly" + DisplayName = "Allin" + Ensure = "Absent" + ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") + ExcludeDeviceStates = @("Compliant","DomainJoined") + ExcludeGroups = @("Group 01") + ExcludeLocations = "Contoso LAN" + ExcludePlatforms = @("Windows","WindowsPhone","MacOS") + ExcludeRoles = @("Compliance Administrator") + ExcludeUsers = "alexw@contoso.com" + GlobalAdminAccount = $Credsglobaladmin + GrantControl_Operator = "AND" + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + IncludeApplications = @("All") + IncludeDeviceStates = @("All") + IncludeGroups = @("Group 01") + IncludeLocations = "AllTrusted" + IncludePlatforms = @("Android","IOS") + IncludeRoles = @("Compliance Administrator") + IncludeUserActions = @("urn:user:registersecurityinfo") + IncludeUsers = "All" + PersistentBrowser_IsEnabled = $True + PersistentBrowser_Mode = "Always" + SignInFrequency_IsEnabled = $True + SignInFrequency_Type = "Days" + SignInFrequency_Value = 5 + SignInRiskLevels = @("High") + State = "disabled" + UserRiskLevels = @("High") + } + + Mock -CommandName Get-AzureADMSConditionalAccessPolicy -MockWith { + return @{ + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + DisplayName = "Allin" + State = "disabled" + Conditions = @{ + Applications = @{ + IncludeApplications = @("All") + ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") + IncludeUserActions = @("urn:user:registersecurityinfo") + } + Users = @{ + IncludeUsers = "All" + ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" + IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + } + Platforms = @{ + IncludePlatforms = @("Android","IOS") + ExcludePlatforms = @("Windows","WindowsPhone","MacOS") + } + Locations = @{ + IncludeLocations = "AllTrusted" + ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + } + Devices = @{ + IncludeDeviceStates = @("All") + ExcludeDeviceStates = @("Compliant","DomainJoined") + } + ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") + SignInRiskLevels = @("High") + UserRiskLevels = @("High") + } + GrantControls = @{ + _Operator = "AND" + BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + } + SessionControls = @{ + ApplicationEnforcedRestrictions = @{ + IsEnabled = $True + } + CloudAppSecurity = @{ + IsEnabled = $True + CloudAppSecurityType = "MonitorOnly" + } + SignInFrequency = @{ + IsEnabled = $True + Type = "Days" + Value = 5 + } + PersistentBrowser = @{ + IsEnabled = $True + Mode = "Always" + } + } + } + } + Mock -CommandName Get-AzureADUser -MockWith { + return @{ + ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" + UserPrincipalName = "alexw@contoso.com" + } + } + Mock -CommandName Get-AzureADGroup -MockWith { + return @{ + ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" + DisplayName = "Group 01" + } + } + Mock -CommandName Get-AzureADDirectoryRoleTemplate -MockWith { + return @{ + ObjectId = "17315797-102d-40b4-93e0-432062caca18" + DisplayName = "Compliance Administrator" + } + } + Mock -CommandName Get-AzureADMSNamedLocationPolicy -MockWith { + return @{ + Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + DisplayName = "Contoso LAN" + } + } + } + + It "Should return Present from the Get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It "Should return false from the Test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should remove the policy from the Set method" { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-AzureADMSConditionalAccessPolicy -Exactly 1 + } + } + + Context -Name "ReverseDSC Tests" -Fixture { + BeforeAll { + $testParams = @{ + GlobalAdminAccount = $GlobalAdminAccount + } + + Mock -CommandName Get-AzureADMSConditionalAccessPolicy -MockWith { + return @{ + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + DisplayName = "Allin" + State = "disabled" + Conditions = @{ + Applications = @{ + IncludeApplications = @("All") + ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") + IncludeUserActions = @("urn:user:registersecurityinfo") + } + Users = @{ + IncludeUsers = "All" + ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" + IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + } + Platforms = @{ + IncludePlatforms = @("Android","IOS") + ExcludePlatforms = @("Windows","WindowsPhone","MacOS") + } + Locations = @{ + IncludeLocations = "AllTrusted" + ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + } + Devices = @{ + IncludeDeviceStates = @("All") + ExcludeDeviceStates = @("Compliant","DomainJoined") + } + ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") + SignInRiskLevels = @("High") + UserRiskLevels = @("High") + } + GrantControls = @{ + _Operator = "AND" + BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + } + SessionControls = @{ + ApplicationEnforcedRestrictions = @{ + IsEnabled = $True + } + CloudAppSecurity = @{ + IsEnabled = $True + CloudAppSecurityType = "MonitorOnly" + } + SignInFrequency = @{ + IsEnabled = $True + Type = "Days" + Value = 5 + } + PersistentBrowser = @{ + IsEnabled = $True + Mode = "Always" + } + } + } + } + } + + It "Should Reverse Engineer resource from the Export method" { + Export-TargetResource @testParams + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope From 55e40a94046a5bc7f4b9932700998a9a83c9c92b Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Fri, 11 Dec 2020 10:53:35 +0100 Subject: [PATCH 22/33] Create 1-ConfigureAADConditionalAccessPolicy.ps1 --- .../1-ConfigureAADConditionalAccessPolicy.ps1 | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 new file mode 100644 index 0000000000..6cb84a044a --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 @@ -0,0 +1,48 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + AADConditionalAccessPolicy Allin-example + { + GlobalAdminAccount = $credsGlobalAdmin; + BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication"); + ClientAppTypes = @("ExchangeActiveSync","Browser","MobileAppsAndDesktopClients","Other"); + CloudAppSecurity_IsEnabled = $True; + CloudAppSecurity_Type = "MonitorOnly"; + DisplayName = "Allin-example"; + Ensure = "Present"; + ExcludeApplications = @("803ee9ca-3f7f-4824-bd6e-0b99d720c35c","00000012-0000-0000-c000-000000000000","00000007-0000-0000-c000-000000000000","Office365"); + ExcludeDeviceStates = @("Compliant","DomainJoined"); + ExcludeLocations = @("Blocked Countries"); + ExcludePlatforms = @("Windows","WindowsPhone","MacOS"); + ExcludeRoles = @("Company Administrator","Application Administrator","Application Developer","Cloud Application Administrator","Cloud Device Administrator"); + ExcludeUsers = @("admin@$OrganizationName","AAdmin@$OrganizationName","CAAdmin@$OrganizationName","AllanD@$OrganizationName","AlexW@$OrganizationName","GuestsOrExternalUsers"); + GrantControl_Operator = "OR"; + IncludeApplications = @("All"); + IncludeDeviceStates = @("All"); + IncludeLocations = @("AllTrusted"); + IncludePlatforms = @("Android","IOS"); + IncludeUserActions = @(); + IncludeUsers = @("All"); + PersistentBrowser_Mode = ""; + SignInFrequency_IsEnabled = $True; + SignInFrequency_Type = "Hours"; + SignInFrequency_Value = 5; + SignInRiskLevels = @("High","Medium"); + State = "disabled"; + UserRiskLevels = @("High","Medium"); + } + } +} From 9b9cb78ae1e90b964954046d87b1a5097e78f3e9 Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Fri, 11 Dec 2020 14:21:35 +0100 Subject: [PATCH 23/33] fixes after code review --- .../MSFT_AADConditionalAccessPolicy.psm1 | 1116 ++++++++--------- ...MSFT_AADConditionalAccessPolicy.schema.mof | 18 +- .../MSFT_AADConditionalAccessPolicy/Readme.md | 22 +- .../1-ConfigureAADConditionalAccessPolicy.ps1 | 54 +- ...65DSC.AADConditionalAccessPolicy.Tests.ps1 | 624 ++++----- 5 files changed, 910 insertions(+), 924 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 index 2f535e7535..0a0067f6fa 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.psm1 @@ -30,11 +30,6 @@ function Get-TargetResource [System.String[]] $IncludeUserActions, - #[Parameter()] - #[System.String[]] - #$IncludeProtectionLevels, - #not exposed yet - #ConditionalAccessUserCondition [Parameter()] [System.String[]] @@ -104,56 +99,46 @@ function Get-TargetResource [Parameter()] [ValidateSet('AND', 'OR')] [System.String] - $GrantControl_Operator, + $GrantControlOperator, [Parameter()] [System.String[]] $BuiltInControls, - #[Parameter()] - #[System.String[]] - #$CustomAuthenticationFactors, - #not exposed yet - - #[Parameter()] - #[System.String[]] - #$TermsOfUse, - #not exposed yet - #ConditionalAccessSessionControls [Parameter()] [System.Boolean] - $ApplicationEnforcedRestrictions_IsEnabled, + $ApplicationEnforcedRestrictionsIsEnabled, [Parameter()] [System.Boolean] - $CloudAppSecurity_IsEnabled, + $CloudAppSecurityIsEnabled, [Parameter()] [System.String] - $CloudAppSecurity_Type, + $CloudAppSecurityType, [Parameter()] [System.Int32] - $SignInFrequency_Value, + $SignInFrequencyValue, [Parameter()] [ValidateSet('Days', 'Hours', '')] [System.String] - $SignInFrequency_Type, + $SignInFrequencyType, [Parameter()] [System.Boolean] - $SignInFrequency_IsEnabled, + $SignInFrequencyIsEnabled, [Parameter()] [ValidateSet('Always', 'Never', '')] [System.String] - $PersistentBrowser_Mode, + $PersistentBrowserMode, [Parameter()] [System.Boolean] - $PersistentBrowser_IsEnabled, + $PersistentBrowserIsEnabled, #generic [Parameter()] @@ -347,25 +332,25 @@ function Get-TargetResource { $Message = "Couldn't find Group $IncludeGroupGUID , that is defined in policy $PolicyDisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } if ($IncludeGroup) { @@ -391,25 +376,25 @@ function Get-TargetResource { $Message = "Couldn't find Group $ExcludeGroupGUID , that is defined in policy $PolicyDisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } if ($ExcludeGroup) { @@ -442,25 +427,25 @@ function Get-TargetResource { $Message = "Couldn't find role $IncludeRoleGUID , couldn't add to policy $PolicyDisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ - } + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -479,26 +464,25 @@ function Get-TargetResource { $Message = "Couldn't find role $ExcludeRoleGUID , couldn't add to policy $PolicyDisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -536,26 +520,25 @@ function Get-TargetResource { $Message = "Couldn't find Location $IncludeLocationGUID , couldn't add to policy $PolicyDisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -578,26 +561,25 @@ function Get-TargetResource { $Message = "Couldn't find Location $ExcludeLocationGUID , couldn't add to policy $PolicyDisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -610,70 +592,68 @@ function Get-TargetResource } $result = @{ - DisplayName = $Policy.DisplayName - Id = $Policy.Id - State = $Policy.State - IncludeApplications = [System.String[]]$Policy.Conditions.Applications.IncludeApplications + DisplayName = $Policy.DisplayName + Id = $Policy.Id + State = $Policy.State + IncludeApplications = [System.String[]]$Policy.Conditions.Applications.IncludeApplications #no translation of Application GUIDs - ExcludeApplications = [System.String[]]$Policy.Conditions.Applications.ExcludeApplications + ExcludeApplications = [System.String[]]$Policy.Conditions.Applications.ExcludeApplications #no translation of GUIDs - IncludeUserActions = [System.String[]]$Policy.Conditions.Applications.IncludeUserActions + IncludeUserActions = [System.String[]]$Policy.Conditions.Applications.IncludeUserActions #no translation needed - #IncludeProtectionLevels = [System.String[]]$Policy.Conditions.Applications.IncludeProtectionLevels - IncludeUsers = $IncludeUsers - ExcludeUsers = $ExcludeUsers - IncludeGroups = $IncludeGroups - ExcludeGroups = $ExcludeGroups - IncludeRoles = $IncludeRoles - ExcludeRoles = $ExcludeRoles - - IncludePlatforms = [System.String[]]$Policy.Conditions.Platforms.IncludePlatforms + IncludeUsers = $IncludeUsers + ExcludeUsers = $ExcludeUsers + IncludeGroups = $IncludeGroups + ExcludeGroups = $ExcludeGroups + IncludeRoles = $IncludeRoles + ExcludeRoles = $ExcludeRoles + + IncludePlatforms = [System.String[]]$Policy.Conditions.Platforms.IncludePlatforms #no translation needed - ExcludePlatforms = [System.String[]]$Policy.Conditions.Platforms.ExcludePlatforms + ExcludePlatforms = [System.String[]]$Policy.Conditions.Platforms.ExcludePlatforms #no translation needed - IncludeLocations = $IncludeLocations - ExcludeLocations = $ExcludeLocations - IncludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.IncludeDeviceStates + IncludeLocations = $IncludeLocations + ExcludeLocations = $ExcludeLocations + IncludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.IncludeDeviceStates #no translation needed - ExcludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.ExcludeDeviceStates + ExcludeDeviceStates = [System.String[]]$Policy.Conditions.Devices.ExcludeDeviceStates #no translation needed - UserRiskLevels = [System.String[]]$Policy.Conditions.UserRiskLevels + UserRiskLevels = [System.String[]]$Policy.Conditions.UserRiskLevels #no translation needed - SignInRiskLevels = [System.String[]]$Policy.Conditions.SignInRiskLevels + SignInRiskLevels = [System.String[]]$Policy.Conditions.SignInRiskLevels #no translation needed - ClientAppTypes = [System.String[]]$Policy.Conditions.ClientAppTypes + ClientAppTypes = [System.String[]]$Policy.Conditions.ClientAppTypes #no translation needed - GrantControl_Operator = $Policy.GrantControls._Operator + GrantControlOperator = $Policy.GrantControls._Operator #no translation or conversion needed - BuiltInControls = [System.String[]]$Policy.GrantControls.BuiltInControls + BuiltInControls = [System.String[]]$Policy.GrantControls.BuiltInControls #no translation needed - ApplicationEnforcedRestrictions_IsEnabled = $Policy.SessionControls.ApplicationEnforcedRestrictions.IsEnabled + ApplicationEnforcedRestrictionsIsEnabled = $Policy.SessionControls.ApplicationEnforcedRestrictions.IsEnabled #no translation or conversion needed - CloudAppSecurity_IsEnabled = $Policy.SessionControls.CloudAppSecurity.IsEnabled + CloudAppSecurityIsEnabled = $Policy.SessionControls.CloudAppSecurity.IsEnabled #no translation or conversion needed - CloudAppSecurity_Type = [System.String]$Policy.SessionControls.CloudAppSecurity.CloudAppSecurityType + CloudAppSecurityType = [System.String]$Policy.SessionControls.CloudAppSecurity.CloudAppSecurityType #no translation needed - SignInFrequency_Value = $Policy.SessionControls.SignInFrequency.Value + SignInFrequencyValue = $Policy.SessionControls.SignInFrequency.Value #no translation or conversion needed - SignInFrequency_Type = [System.String]$Policy.SessionControls.SignInFrequency.Type + SignInFrequencyType = [System.String]$Policy.SessionControls.SignInFrequency.Type #no translation needed - SignInFrequency_IsEnabled = $Policy.SessionControls.SignInFrequency.IsEnabled + SignInFrequencyIsEnabled = $Policy.SessionControls.SignInFrequency.IsEnabled #no translation or conversion needed - PersistentBrowser_Mode = [System.String]$Policy.SessionControls.PersistentBrowser.Mode + PersistentBrowserMode = [System.String]$Policy.SessionControls.PersistentBrowser.Mode #no translation needed - PersistentBrowser_IsEnabled = $Policy.SessionControls.PersistentBrowser.IsEnabled + PersistentBrowserIsEnabled = $Policy.SessionControls.PersistentBrowser.IsEnabled #no translation or conversion needed #Standard part - Ensure = "Present" - GlobalAdminAccount = $GlobalAdminAccount - ApplicationId = $ApplicationId - TenantId = $TenantId - CertificateThumbprint = $CertificateThumbprint + Ensure = "Present" + GlobalAdminAccount = $GlobalAdminAccount + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint } Write-Verbose -Message "Get-TargetResource Result: `n $(Convert-M365DscHashtableToString -Hashtable $result)" return $result } - } function Set-TargetResource @@ -707,11 +687,6 @@ function Set-TargetResource [System.String[]] $IncludeUserActions, - #[Parameter()] - #[System.String[]] - #$IncludeProtectionLevels, - #not exposed yet - #ConditionalAccessUserCondition [Parameter()] [System.String[]] @@ -781,56 +756,46 @@ function Set-TargetResource [Parameter()] [ValidateSet('AND', 'OR')] [System.String] - $GrantControl_Operator, + $GrantControlOperator, [Parameter()] [System.String[]] $BuiltInControls, - #[Parameter()] - #[System.String[]] - #$CustomAuthenticationFactors, - #not exposed yet - - #[Parameter()] - #[System.String[]] - #$TermsOfUse, - #not exposed yet - #ConditionalAccessSessionControls [Parameter()] [System.Boolean] - $ApplicationEnforcedRestrictions_IsEnabled, + $ApplicationEnforcedRestrictionsIsEnabled, [Parameter()] [System.Boolean] - $CloudAppSecurity_IsEnabled, + $CloudAppSecurityIsEnabled, [Parameter()] [System.String] - $CloudAppSecurity_Type, + $CloudAppSecurityType, [Parameter()] [System.Int32] - $SignInFrequency_Value, + $SignInFrequencyValue, [Parameter()] [ValidateSet('Days', 'Hours', '')] [System.String] - $SignInFrequency_Type, + $SignInFrequencyType, [Parameter()] [System.Boolean] - $SignInFrequency_IsEnabled, + $SignInFrequencyIsEnabled, [Parameter()] [ValidateSet('Always', 'Never', '')] [System.String] - $PersistentBrowser_Mode, + $PersistentBrowserMode, [Parameter()] [System.Boolean] - $PersistentBrowser_IsEnabled, + $PersistentBrowserIsEnabled, #generic [Parameter()] @@ -911,51 +876,49 @@ function Set-TargetResource { $Message = $_ try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } if ($null -eq $userguid) { $Message = "Couldn't find user $includeuser , couldn't add to policy $DisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -984,51 +947,49 @@ function Set-TargetResource { $Message = $_ try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } if ($null -eq $userguid) { $Message = "Couldn't find user $excludeuser , couldn't add to policy $DisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -1052,84 +1013,84 @@ function Set-TargetResource { $GroupLookup = Get-AzureADGroup -Filter "DisplayName eq '$includegroup'" } catch - { + { $Message = $_ try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } Write-Verbose -Message $_ } if ($GroupLookup.Length -gt 1) { - $Message = "Duplicate group found with displayname $includegroup , couldn't add to policy $DisplayName" - try - { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue - } - catch - { - Write-Verbose -Message $_ - } + $Message = "Duplicate group found with displayname $includegroup , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } elseif ($null -eq $GroupLookup) { $Message = "Couldn't find group $includegroup , couldn't add to policy $DisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { Write-Verbose -Message "adding group to includegroups" - $conditions.Users.IncludeGroups+=$GroupLookup.ObjectId + $conditions.Users.IncludeGroups += $GroupLookup.ObjectId } } } @@ -1144,84 +1105,84 @@ function Set-TargetResource { $GroupLookup = Get-AzureADGroup -Filter "DisplayName eq '$ExcludeGroup'" } catch - { + { $Message = $_ try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } Write-Verbose -Message $_ } if ($GroupLookup.Length -gt 1) { - $Message = "Duplicate group found with displayname $ExcludeGroup , couldn't add to policy $DisplayName" - try - { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue - } - catch - { - Write-Verbose -Message $_ - } + $Message = "Duplicate group found with displayname $ExcludeGroup , couldn't add to policy $DisplayName" + try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } elseif ($null -eq $GroupLookup) { $Message = "Couldn't find group $ExcludeGroup , couldn't add to policy $DisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { Write-Verbose -Message "adding group to ExcludeGroups" - $conditions.Users.ExcludeGroups+=$GroupLookup.ObjectId + $conditions.Users.ExcludeGroups += $GroupLookup.ObjectId } } } @@ -1241,26 +1202,25 @@ function Set-TargetResource { $Message = "Couldn't find role $IncludeRole , couldn't add to policy $DisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -1285,26 +1245,25 @@ function Set-TargetResource { $Message = "Couldn't find role $ExcludeRole , couldn't add to policy $DisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -1347,30 +1306,29 @@ function Set-TargetResource { $Message = "Couldn't find Location $IncludeLocation , couldn't add to policy $DisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { - $conditions.Locations.IncludeLocations += $LocationLookup[$IncludeLocation] + $conditions.Locations.IncludeLocations += $LocationLookup[$IncludeLocation] } } } @@ -1386,26 +1344,25 @@ function Set-TargetResource { $Message = "Couldn't find Location $ExcludeLocation , couldn't add to policy $DisplayName" try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } - + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } } else { @@ -1415,105 +1372,105 @@ function Set-TargetResource } } - Write-Verbose -Message "Set-Targetresource: process device states" - if ($IncludeDeviceStates -or $ExcludeDeviceStates) - { - #create and provision Device condition object if used - $conditions.Devices = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessDevicesCondition - $conditions.Devices.IncludeDeviceStates = $IncludeDeviceStates - #no translation or conversion needed - $conditions.Devices.ExcludeDeviceStates = $ExcludeDeviceStates - #no translation or conversion needed - } - Write-Verbose -Message "Set-Targetresource: process risk levels and app types" - $Conditions.UserRiskLevels = $UserRiskLevels - #no translation or conversion needed - $Conditions.SignInRiskLevels = $SignInRiskLevels - #no translation or conversion needed - $Conditions.ClientAppTypes = $ClientAppTypes + Write-Verbose -Message "Set-Targetresource: process device states" + if ($IncludeDeviceStates -or $ExcludeDeviceStates) + { + #create and provision Device condition object if used + $conditions.Devices = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessDevicesCondition + $conditions.Devices.IncludeDeviceStates = $IncludeDeviceStates #no translation or conversion needed - Write-Verbose -Message "Set-Targetresource: Adding processed conditions" - #add all conditions to the parameter list - $NewParameters.Add("Conditions", $Conditions) - #create and provision Grant Control object - Write-Verbose -Message "Set-Targetresource: create and provision Grant Control object" - $GrantControls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls - $GrantControls._Operator = $GrantControl_Operator - $GrantControls.BuiltInControls = $BuiltInControls + $conditions.Devices.ExcludeDeviceStates = $ExcludeDeviceStates #no translation or conversion needed - Write-Verbose -Message "Set-Targetresource: Adding processed grant controls" - $NewParameters.Add("GrantControls", $GrantControls) - #add GrantControls to the parameter list - Write-Verbose -Message "Set-Targetresource: process session controls" - if ($ApplicationEnforcedRestrictions_IsEnabled -or $CloudAppSecurity_IsEnabled -or $SignInFrequency_IsEnabled -or $PersistentBrowser_IsEnabled) + } + Write-Verbose -Message "Set-Targetresource: process risk levels and app types" + $Conditions.UserRiskLevels = $UserRiskLevels + #no translation or conversion needed + $Conditions.SignInRiskLevels = $SignInRiskLevels + #no translation or conversion needed + $Conditions.ClientAppTypes = $ClientAppTypes + #no translation or conversion needed + Write-Verbose -Message "Set-Targetresource: Adding processed conditions" + #add all conditions to the parameter list + $NewParameters.Add("Conditions", $Conditions) + #create and provision Grant Control object + Write-Verbose -Message "Set-Targetresource: create and provision Grant Control object" + $GrantControls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls + $GrantControls._Operator = $GrantControlOperator + $GrantControls.BuiltInControls = $BuiltInControls + #no translation or conversion needed + Write-Verbose -Message "Set-Targetresource: Adding processed grant controls" + $NewParameters.Add("GrantControls", $GrantControls) + #add GrantControls to the parameter list + Write-Verbose -Message "Set-Targetresource: process session controls" + if ($ApplicationEnforcedRestrictionsIsEnabled -or $CloudAppSecurityIsEnabled -or $SignInFrequencyIsEnabled -or $PersistentBrowserIsEnabled) + { + #create and provision Session Control object if used + Write-Verbose -Message "Set-Targetresource: Create and provision Session Control object" + $sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSessionControls + if ($ApplicationEnforcedRestrictionsIsEnabled) { - #create and provision Session Control object if used - Write-Verbose -Message "Set-Targetresource: Create and provision Session Control object" - $sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSessionControls - if ($ApplicationEnforcedRestrictions_IsEnabled) - { - #create and provision ApplicationEnforcedRestrictions object if used - $sessioncontrols.ApplicationEnforcedRestrictions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationEnforcedRestrictions - $sessioncontrols.ApplicationEnforcedRestrictions.IsEnabled = $true - } - if ($CloudAppSecurity_IsEnabled) - { - #create and provision CloudAppSecurity object if used - $sessioncontrols.CloudAppSecurity = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessCloudAppSecurity - $sessioncontrols.CloudAppSecurity.IsEnabled = $true - $sessioncontrols.CloudAppSecurity.CloudAppSecurityType = $CloudAppSecurity_Type - } - if ($SignInFrequency_IsEnabled) - { - #create and provision SignInFrequency object if used - $sessioncontrols.SignInFrequency = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency - $sessioncontrols.SignInFrequency.IsEnabled = $true - $sessioncontrols.SignInFrequency.Type = $SignInFrequency_Type - $sessioncontrols.SignInFrequency.Value = $SignInFrequency_Value - } - if ($PersistentBrowser_IsEnabled) - { - #create and provision PersistentBrowser object if used - $sessioncontrols.PersistentBrowser = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser - $sessioncontrols.PersistentBrowser.IsEnabled = $true - $sessioncontrols.PersistentBrowser.Mode = $PersistentBrowser_Mode - } - $NewParameters.Add("SessionControls", $sessioncontrols) - #add SessionControls to the parameter list + #create and provision ApplicationEnforcedRestrictions object if used + $sessioncontrols.ApplicationEnforcedRestrictions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationEnforcedRestrictions + $sessioncontrols.ApplicationEnforcedRestrictions.IsEnabled = $true } - + if ($CloudAppSecurityIsEnabled) + { + #create and provision CloudAppSecurity object if used + $sessioncontrols.CloudAppSecurity = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessCloudAppSecurity + $sessioncontrols.CloudAppSecurity.IsEnabled = $true + $sessioncontrols.CloudAppSecurity.CloudAppSecurityType = $CloudAppSecurityType + } + if ($SignInFrequencyIsEnabled) + { + #create and provision SignInFrequency object if used + $sessioncontrols.SignInFrequency = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency + $sessioncontrols.SignInFrequency.IsEnabled = $true + $sessioncontrols.SignInFrequency.Type = $SignInFrequencyType + $sessioncontrols.SignInFrequency.Value = $SignInFrequencyValue + } + if ($PersistentBrowserIsEnabled) + { + #create and provision PersistentBrowser object if used + $sessioncontrols.PersistentBrowser = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser + $sessioncontrols.PersistentBrowser.IsEnabled = $true + $sessioncontrols.PersistentBrowser.Mode = $PersistentBrowserMode + } + $NewParameters.Add("SessionControls", $sessioncontrols) + #add SessionControls to the parameter list } + + } if ($Ensure -eq 'Present' -and $currentPolicy.Ensure -eq 'Present') { Write-Verbose -Message "Set-Targetresource: Change policy $DisplayName" $NewParameters.Add("PolicyId", $currentPolicy.Id) try { - Set-AzureADMSConditionalAccessPolicy @NewParameters + Set-AzureADMSConditionalAccessPolicy @NewParameters } catch { $Message = $_ try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } Write-Verbose -Message "Set-Targetresource: Failed change policy $DisplayName" Write-Verbose -Message $_ @@ -1530,25 +1487,25 @@ function Set-TargetResource { $Message = $_ try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } Write-Verbose -Message "Set-Targetresource: Failed creating policy" Write-Verbose -Message $_ @@ -1565,25 +1522,25 @@ function Set-TargetResource { $Message = $_ try + { + Write-Verbose -Message $Message + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) { - Write-Verbose -Message $Message - $tenantIdValue = "" - if (-not [System.String]::IsNullOrEmpty($TenantId)) - { - $tenantIdValue = $TenantId - } - elseif ($null -ne $GlobalAdminAccount) - { - $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] - } - Add-M365DSCEvent -Message $Message -EntryType 'Error' ` - -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` - -TenantId $tenantIdValue + $tenantIdValue = $TenantId } - catch + elseif ($null -ne $GlobalAdminAccount) { - Write-Verbose -Message $_ + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] } + Add-M365DSCEvent -Message $Message -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ + } Write-Verbose -Message "Set-Targetresource: Failed deleting policy $DisplayName" Write-Verbose -Message $_ @@ -1624,11 +1581,6 @@ function Test-TargetResource [System.String[]] $IncludeUserActions, - #[Parameter()] - #[System.String[]] - #$IncludeProtectionLevels, - #not exposed yet - #ConditionalAccessUserCondition [Parameter()] [System.String[]] @@ -1698,56 +1650,46 @@ function Test-TargetResource [Parameter()] [ValidateSet('AND', 'OR')] [System.String] - $GrantControl_Operator, + $GrantControlOperator, [Parameter()] [System.String[]] $BuiltInControls, - #[Parameter()] - #[System.String[]] - #$CustomAuthenticationFactors, - #not exposed yet - - #[Parameter()] - #[System.String[]] - #$TermsOfUse, - #not exposed yet - #ConditionalAccessSessionControls [Parameter()] [System.Boolean] - $ApplicationEnforcedRestrictions_IsEnabled, + $ApplicationEnforcedRestrictionsIsEnabled, [Parameter()] [System.Boolean] - $CloudAppSecurity_IsEnabled, + $CloudAppSecurityIsEnabled, [Parameter()] [System.String] - $CloudAppSecurity_Type, + $CloudAppSecurityType, [Parameter()] [System.Int32] - $SignInFrequency_Value, + $SignInFrequencyValue, [Parameter()] [ValidateSet('Days', 'Hours', '')] [System.String] - $SignInFrequency_Type, + $SignInFrequencyType, [Parameter()] [System.Boolean] - $SignInFrequency_IsEnabled, + $SignInFrequencyIsEnabled, [Parameter()] [ValidateSet('Always', 'Never', '')] [System.String] - $PersistentBrowser_Mode, + $PersistentBrowserMode, [Parameter()] [System.Boolean] - $PersistentBrowser_IsEnabled, + $PersistentBrowserIsEnabled, #generic [Parameter()] @@ -1825,34 +1767,60 @@ function Export-TargetResource #endregion $ConnectionMode = New-M365DSCConnection -Platform 'AzureAD' -InboundParameters $PSBoundParameters - - [array] $Policies = Get-AzureADMSConditionalAccessPolicy - $i = 1 - $dscContent = '' - Write-Host "`r`n" -NoNewline - foreach ($Policy in $Policies) + try { - Write-Host " |---[$i/$($Policies.Count)] $($Policy.DisplayName)" -NoNewline - $Params = @{ - GlobalAdminAccount = $GlobalAdminAccount - DisplayName = $Policy.DisplayName - Id = $Policy.Id - ApplicationId = $ApplicationId - TenantId = $TenantId - CertificateThumbprint = $CertificateThumbprint + [array] $Policies = Get-AzureADMSConditionalAccessPolicy + $i = 1 + $dscContent = '' + Write-Host "`r`n" -NoNewline + foreach ($Policy in $Policies) + { + Write-Host " |---[$i/$($Policies.Count)] $($Policy.DisplayName)" -NoNewline + $Params = @{ + GlobalAdminAccount = $GlobalAdminAccount + DisplayName = $Policy.DisplayName + Id = $Policy.Id + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + $dscContent += Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -GlobalAdminAccount $GlobalAdminAccount + Write-Host $Global:M365DSCEmojiGreenCheckMark + $i++ + } + return $dscContent + } + catch + { + try + { + Write-Verbose -Message $_ + $tenantIdValue = "" + if (-not [System.String]::IsNullOrEmpty($TenantId)) + { + $tenantIdValue = $TenantId + } + elseif ($null -ne $GlobalAdminAccount) + { + $tenantIdValue = $GlobalAdminAccount.UserName.Split('@')[1] + } + Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $tenantIdValue + } + catch + { + Write-Verbose -Message $_ } - $Results = Get-TargetResource @Params - $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` - -Results $Results - $dscContent += Get-M365DSCExportContentForResource -ResourceName $ResourceName ` - -ConnectionMode $ConnectionMode ` - -ModulePath $PSScriptRoot ` - -Results $Results ` - -GlobalAdminAccount $GlobalAdminAccount - Write-Host $Global:M365DSCEmojiGreenCheckMark - $i++ + return "" } - return $dscContent } Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof index a1871eaea6..6ecfec08ae 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/MSFT_AADConditionalAccessPolicy.schema.mof @@ -22,16 +22,16 @@ class MSFT_AADConditionalAccessPolicy : OMI_BaseResource [Write, Description("AAD Identity Protection User Risk Levels in scope of the Policy.")] String UserRiskLevels[]; [Write, Description("AAD Identity Protection Sign-in Risk Levels in scope of the Policy.")] String SignInRiskLevels[]; [Write, Description("Client App types in scope of the Policy.")] String ClientAppTypes[]; - [Write, Description("Operator to be used for Grant Controls."), ValueMap{"AND","OR"}, Values{"AND","OR"}] String GrantControl_Operator; + [Write, Description("Operator to be used for Grant Controls."), ValueMap{"AND","OR"}, Values{"AND","OR"}] String GrantControlOperator; [Write, Description("List of built-in Grant Controls to be applied by the Policy.")] String BuiltInControls[]; - [Write, Description("Specifies, whether Application Enforced Restrictions are enabled in the Policy.")] Boolean ApplicationEnforcedRestrictions_IsEnabled; - [Write, Description("Specifies, whether Cloud App Security is enforced by the Policy.")] Boolean CloudAppSecurity_IsEnabled; - [Write, Description("Specifies, what Cloud App Security control is enforced by the Policy.")] String CloudAppSecurity_Type; - [Write, Description("Sign in frequency time in the given unit to be enforced by the policy.")] UInt32 SignInFrequency_Value; - [Write, Description("Sign in frequency unit (days/hours) to be interpreted by the policy."), ValueMap{"Days","Hours",""}, Values{"Days","Hours",""}] String SignInFrequency_Type; - [Write, Description("Specifies, whether sign-in frequency is enforced by the Policy.")] Boolean SignInFrequency_IsEnabled; - [Write, Description("Specifies, whether Browser Persistence is controlled by the Policy.")] Boolean PersistentBrowser_IsEnabled; - [Write, Description("Specifies, what Browser Persistence control is enforced by the Policy."), ValueMap{"Always","Never",""}, Values{"Always","Never",""}] String PersistentBrowser_Mode; + [Write, Description("Specifies, whether Application Enforced Restrictions are enabled in the Policy.")] Boolean ApplicationEnforcedRestrictionsIsEnabled; + [Write, Description("Specifies, whether Cloud App Security is enforced by the Policy.")] Boolean CloudAppSecurityIsEnabled; + [Write, Description("Specifies, what Cloud App Security control is enforced by the Policy.")] String CloudAppSecurityType; + [Write, Description("Sign in frequency time in the given unit to be enforced by the policy.")] UInt32 SignInFrequencyValue; + [Write, Description("Sign in frequency unit (days/hours) to be interpreted by the policy."), ValueMap{"Days","Hours",""}, Values{"Days","Hours",""}] String SignInFrequencyType; + [Write, Description("Specifies, whether sign-in frequency is enforced by the Policy.")] Boolean SignInFrequencyIsEnabled; + [Write, Description("Specifies, whether Browser Persistence is controlled by the Policy.")] Boolean PersistentBrowserIsEnabled; + [Write, Description("Specifies, what Browser Persistence control is enforced by the Policy."), ValueMap{"Always","Never",""}, Values{"Always","Never",""}] String PersistentBrowserMode; [Write, Description("Specify if the Azure AD CA Policy should exist or not."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; [Write, Description("Credentials of the Azure Active Directory Admin"), EmbeddedInstance("MSFT_Credential")] String GlobalAdminAccount; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/Readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/Readme.md index 51536a5659..454ffaac1f 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/Readme.md +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADConditionalAccessPolicy/Readme.md @@ -9,8 +9,26 @@ This resource configures an Azure Active Directory Conditional Access Policy. To authenticate via Azure Active Directory, this resource required the following Application permissions: * **Automate** - * None + * Application.Read.All + * Group.Read.All + * Directory.Read.All + * Policy.Read.All + * Policy.Read.ConditionalAccess + * Policy.ReadWrite.ConditionalAccess + * RoleManagement.Read.All + * RoleManagement.Read.Directory + * User.Read.All + * **Export** - * None + * Application.Read.All + * Group.Read.All + * Directory.Read.All + * Policy.Read.All + * Policy.Read.ConditionalAccess + * RoleManagement.Read.All + * RoleManagement.Read.Directory + * User.Read.All NOTE: All permisions listed above require admin consent. + +Additionally Global Reader Role needs to be assigned, as long as AAD PowerShell is not fully converged to use GRAPH API diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 index 6cb84a044a..0d51e075c1 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 @@ -16,33 +16,33 @@ Configuration Example { AADConditionalAccessPolicy Allin-example { - GlobalAdminAccount = $credsGlobalAdmin; - BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication"); - ClientAppTypes = @("ExchangeActiveSync","Browser","MobileAppsAndDesktopClients","Other"); - CloudAppSecurity_IsEnabled = $True; - CloudAppSecurity_Type = "MonitorOnly"; - DisplayName = "Allin-example"; - Ensure = "Present"; - ExcludeApplications = @("803ee9ca-3f7f-4824-bd6e-0b99d720c35c","00000012-0000-0000-c000-000000000000","00000007-0000-0000-c000-000000000000","Office365"); - ExcludeDeviceStates = @("Compliant","DomainJoined"); - ExcludeLocations = @("Blocked Countries"); - ExcludePlatforms = @("Windows","WindowsPhone","MacOS"); - ExcludeRoles = @("Company Administrator","Application Administrator","Application Developer","Cloud Application Administrator","Cloud Device Administrator"); - ExcludeUsers = @("admin@$OrganizationName","AAdmin@$OrganizationName","CAAdmin@$OrganizationName","AllanD@$OrganizationName","AlexW@$OrganizationName","GuestsOrExternalUsers"); - GrantControl_Operator = "OR"; - IncludeApplications = @("All"); - IncludeDeviceStates = @("All"); - IncludeLocations = @("AllTrusted"); - IncludePlatforms = @("Android","IOS"); - IncludeUserActions = @(); - IncludeUsers = @("All"); - PersistentBrowser_Mode = ""; - SignInFrequency_IsEnabled = $True; - SignInFrequency_Type = "Hours"; - SignInFrequency_Value = 5; - SignInRiskLevels = @("High","Medium"); - State = "disabled"; - UserRiskLevels = @("High","Medium"); + GlobalAdminAccount = $credsGlobalAdmin; + BuiltInControls = @("Mfa", "CompliantDevice", "DomainJoinedDevice", "ApprovedApplication", "CompliantApplication"); + ClientAppTypes = @("ExchangeActiveSync", "Browser", "MobileAppsAndDesktopClients", "Other"); + CloudAppSecurityIsEnabled = $True; + CloudAppSecurityType = "MonitorOnly"; + DisplayName = "Allin-example"; + Ensure = "Present"; + ExcludeApplications = @("803ee9ca-3f7f-4824-bd6e-0b99d720c35c", "00000012-0000-0000-c000-000000000000", "00000007-0000-0000-c000-000000000000", "Office365"); + ExcludeDeviceStates = @("Compliant", "DomainJoined"); + ExcludeLocations = @("Blocked Countries"); + ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS"); + ExcludeRoles = @("Company Administrator", "Application Administrator", "Application Developer", "Cloud Application Administrator", "Cloud Device Administrator"); + ExcludeUsers = @("admin@$OrganizationName", "AAdmin@$OrganizationName", "CAAdmin@$OrganizationName", "AllanD@$OrganizationName", "AlexW@$OrganizationName", "GuestsOrExternalUsers"); + GrantControlOperator = "OR"; + IncludeApplications = @("All"); + IncludeDeviceStates = @("All"); + IncludeLocations = @("AllTrusted"); + IncludePlatforms = @("Android", "IOS"); + IncludeUserActions = @(); + IncludeUsers = @("All"); + PersistentBrowserMode = ""; + SignInFrequencyIsEnabled = $True; + SignInFrequencyType = "Hours"; + SignInFrequencyValue = 5; + SignInRiskLevels = @("High", "Medium"); + State = "disabled"; + UserRiskLevels = @("High", "Medium"); } } } diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADConditionalAccessPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADConditionalAccessPolicy.Tests.ps1 index 21d1e8ce37..afd2e2c5de 100644 --- a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADConditionalAccessPolicy.Tests.ps1 +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADConditionalAccessPolicy.Tests.ps1 @@ -2,14 +2,14 @@ param( ) $M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` - -ChildPath "..\..\Unit" ` - -Resolve + -ChildPath "..\..\Unit" ` + -Resolve $CmdletModule = (Join-Path -Path $M365DSCTestFolder ` - -ChildPath "\Stubs\Microsoft365.psm1" ` - -Resolve) + -ChildPath "\Stubs\Microsoft365.psm1" ` + -Resolve) $GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` - -ChildPath "\Stubs\Generic.psm1" ` - -Resolve) + -ChildPath "\Stubs\Generic.psm1" ` + -Resolve) Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` -ChildPath "\UnitTestHelper.psm1" ` -Resolve) @@ -51,35 +51,35 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Context -Name "When Conditional Access Policy doesn't exist but should" -Fixture { BeforeAll { $testParams = @{ - BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") - ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") - CloudAppSecurity_IsEnabled = $True - CloudAppSecurity_Type = "MonitorOnly" + BuiltInControls = @("Mfa", "CompliantDevice", "DomainJoinedDevice", "ApprovedApplication", "CompliantApplication") + ClientAppTypes = @("Browser", "MobileAppsAndDesktopClients") + CloudAppSecurityIsEnabled = $True + CloudAppSecurityType = "MonitorOnly" DisplayName = "Allin" Ensure = "Present" - ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") - ExcludeDeviceStates = @("Compliant","DomainJoined") + ExcludeApplications = @("00000012-0000-0000-c000-000000000000", "Office365") + ExcludeDeviceStates = @("Compliant", "DomainJoined") ExcludeGroups = @("Group 01") ExcludeLocations = "Contoso LAN" - ExcludePlatforms = @("Windows","WindowsPhone","MacOS") + ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS") ExcludeRoles = @("Compliance Administrator") ExcludeUsers = "alexw@contoso.com" GlobalAdminAccount = $Credsglobaladmin - GrantControl_Operator = "AND" + GrantControlOperator = "AND" Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" IncludeApplications = @("All") IncludeDeviceStates = @("All") IncludeGroups = @("Group 01") IncludeLocations = "AllTrusted" - IncludePlatforms = @("Android","IOS") + IncludePlatforms = @("Android", "IOS") IncludeRoles = @("Compliance Administrator") IncludeUserActions = @("urn:user:registersecurityinfo") IncludeUsers = "All" - PersistentBrowser_IsEnabled = $True - PersistentBrowser_Mode = "Always" - SignInFrequency_IsEnabled = $True - SignInFrequency_Type = "Days" - SignInFrequency_Value = 5 + PersistentBrowserIsEnabled = $True + PersistentBrowserMode = "Always" + SignInFrequencyIsEnabled = $True + SignInFrequencyType = "Days" + SignInFrequencyValue = 5 SignInRiskLevels = @("High") State = "disabled" UserRiskLevels = @("High") @@ -90,25 +90,25 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { } Mock -CommandName Get-AzureADUser -MockWith { return @{ - ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" + ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" UserPrincipalName = "alexw@contoso.com" } } Mock -CommandName Get-AzureADGroup -MockWith { return @{ - ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" + ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" DisplayName = "Group 01" } } Mock -CommandName Get-AzureADDirectoryRoleTemplate -MockWith { return @{ - ObjectId = "17315797-102d-40b4-93e0-432062caca18" + ObjectId = "17315797-102d-40b4-93e0-432062caca18" DisplayName = "Compliance Administrator" } } Mock -CommandName Get-AzureADMSNamedLocationPolicy -MockWith { return @{ - Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" DisplayName = "Contoso LAN" } } @@ -131,121 +131,121 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Context -Name "Policy exists but is not in the Desired State" -Fixture { BeforeAll { $testParams = @{ - ApplicationEnforcedRestrictions_IsEnabled = $True - BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") - ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") - CloudAppSecurity_IsEnabled = $True - CloudAppSecurity_Type = "MonitorOnly" - DisplayName = "Allin" - Ensure = "Present" - ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") - ExcludeDeviceStates = @("Compliant","DomainJoined") - ExcludeGroups = @("Group 01") - ExcludeLocations = "Contoso LAN" - ExcludePlatforms = @("Windows","WindowsPhone","MacOS") - ExcludeRoles = @("Compliance Administrator") - ExcludeUsers = "alexw@contoso.com" - GlobalAdminAccount = $Credsglobaladmin - GrantControl_Operator = "AND" - Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" - IncludeApplications = @("All") - IncludeDeviceStates = @("All") - IncludeGroups = @("Group 01") - IncludeLocations = "AllTrusted" - IncludePlatforms = @("Android","IOS") - IncludeRoles = @("Compliance Administrator") - IncludeUserActions = @("urn:user:registersecurityinfo") - IncludeUsers = "All" - PersistentBrowser_IsEnabled = $True - PersistentBrowser_Mode = "Always" - SignInFrequency_IsEnabled = $True - SignInFrequency_Type = "Days" - SignInFrequency_Value = 5 - SignInRiskLevels = @("High") - State = "disabled" - UserRiskLevels = @("High") + ApplicationEnforcedRestrictionsIsEnabled = $True + BuiltInControls = @("Mfa", "CompliantDevice", "DomainJoinedDevice", "ApprovedApplication", "CompliantApplication") + ClientAppTypes = @("Browser", "MobileAppsAndDesktopClients") + CloudAppSecurityIsEnabled = $True + CloudAppSecurityType = "MonitorOnly" + DisplayName = "Allin" + Ensure = "Present" + ExcludeApplications = @("00000012-0000-0000-c000-000000000000", "Office365") + ExcludeDeviceStates = @("Compliant", "DomainJoined") + ExcludeGroups = @("Group 01") + ExcludeLocations = "Contoso LAN" + ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS") + ExcludeRoles = @("Compliance Administrator") + ExcludeUsers = "alexw@contoso.com" + GlobalAdminAccount = $Credsglobaladmin + GrantControlOperator = "AND" + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + IncludeApplications = @("All") + IncludeDeviceStates = @("All") + IncludeGroups = @("Group 01") + IncludeLocations = "AllTrusted" + IncludePlatforms = @("Android", "IOS") + IncludeRoles = @("Compliance Administrator") + IncludeUserActions = @("urn:user:registersecurityinfo") + IncludeUsers = "All" + PersistentBrowserIsEnabled = $True + PersistentBrowserMode = "Always" + SignInFrequencyIsEnabled = $True + SignInFrequencyType = "Days" + SignInFrequencyValue = 5 + SignInRiskLevels = @("High") + State = "disabled" + UserRiskLevels = @("High") } Mock -CommandName Get-AzureADMSConditionalAccessPolicy -MockWith { return @{ - Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" - DisplayName = "Allin" - State = "enabled" - Conditions = @{ - Applications = @{ - IncludeApplications = @("All") - ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") - IncludeUserActions = @("urn:user:registersecurityinfo") - } - Users = @{ - IncludeUsers = "All" - ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" - IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") - ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") - IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") - ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") - } - Platforms = @{ - IncludePlatforms = @("Android","IOS") - ExcludePlatforms = @("Windows","WindowsPhone","MacOS") - } - Locations = @{ - IncludeLocations = "AllTrusted" - ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" - } - Devices = @{ - IncludeDeviceStates = @("All") - ExcludeDeviceStates = @("Compliant","DomainJoined") - } - ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") - SignInRiskLevels = @("High") - UserRiskLevels = @("High") + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + DisplayName = "Allin" + State = "enabled" + Conditions = @{ + Applications = @{ + IncludeApplications = @("All") + ExcludeApplications = @("00000012-0000-0000-c000-000000000000", "Office365") + IncludeUserActions = @("urn:user:registersecurityinfo") + } + Users = @{ + IncludeUsers = "All" + ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" + IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + } + Platforms = @{ + IncludePlatforms = @("Android", "IOS") + ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS") + } + Locations = @{ + IncludeLocations = "AllTrusted" + ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + } + Devices = @{ + IncludeDeviceStates = @("All") + ExcludeDeviceStates = @("Compliant", "DomainJoined") + } + ClientAppTypes = @("Browser", "MobileAppsAndDesktopClients") + SignInRiskLevels = @("High") + UserRiskLevels = @("High") } - GrantControls = @{ - _Operator = "AND" - BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + GrantControls = @{ + _Operator = "AND" + BuiltInControls = @("Mfa", "CompliantDevice", "DomainJoinedDevice", "ApprovedApplication", "CompliantApplication") } SessionControls = @{ ApplicationEnforcedRestrictions = @{ IsEnabled = $True } - CloudAppSecurity = @{ - IsEnabled = $True - CloudAppSecurityType = "MonitorOnly" + CloudAppSecurity = @{ + IsEnabled = $True + CloudAppSecurityType = "MonitorOnly" } - SignInFrequency = @{ - IsEnabled = $True - Type = "Days" - Value = 5 + SignInFrequency = @{ + IsEnabled = $True + Type = "Days" + Value = 5 } - PersistentBrowser = @{ + PersistentBrowser = @{ IsEnabled = $True - Mode = "Always" + Mode = "Always" } } } } Mock -CommandName Get-AzureADUser -MockWith { return @{ - ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" + ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" UserPrincipalName = "alexw@contoso.com" } } Mock -CommandName Get-AzureADGroup -MockWith { return @{ - ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" + ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" DisplayName = "Group 01" } } Mock -CommandName Get-AzureADDirectoryRoleTemplate -MockWith { return @{ - ObjectId = "17315797-102d-40b4-93e0-432062caca18" + ObjectId = "17315797-102d-40b4-93e0-432062caca18" DisplayName = "Compliance Administrator" } } Mock -CommandName Get-AzureADMSNamedLocationPolicy -MockWith { return @{ - Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" DisplayName = "Contoso LAN" } } @@ -268,121 +268,121 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Context -Name "Policy exists and is already in the Desired State" -Fixture { BeforeAll { $testParams = @{ - ApplicationEnforcedRestrictions_IsEnabled = $True - BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") - ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") - CloudAppSecurity_IsEnabled = $True - CloudAppSecurity_Type = "MonitorOnly" - DisplayName = "Allin" - Ensure = "Present" - ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") - ExcludeDeviceStates = @("Compliant","DomainJoined") - ExcludeGroups = @("Group 01") - ExcludeLocations = "Contoso LAN" - ExcludePlatforms = @("Windows","WindowsPhone","MacOS") - ExcludeRoles = @("Compliance Administrator") - ExcludeUsers = "alexw@contoso.com" - GlobalAdminAccount = $Credsglobaladmin - GrantControl_Operator = "AND" - Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" - IncludeApplications = @("All") - IncludeDeviceStates = @("All") - IncludeGroups = @("Group 01") - IncludeLocations = "AllTrusted" - IncludePlatforms = @("Android","IOS") - IncludeRoles = @("Compliance Administrator") - IncludeUserActions = @("urn:user:registersecurityinfo") - IncludeUsers = "All" - PersistentBrowser_IsEnabled = $True - PersistentBrowser_Mode = "Always" - SignInFrequency_IsEnabled = $True - SignInFrequency_Type = "Days" - SignInFrequency_Value = 5 - SignInRiskLevels = @("High") - State = "disabled" - UserRiskLevels = @("High") + ApplicationEnforcedRestrictionsIsEnabled = $True + BuiltInControls = @("Mfa", "CompliantDevice", "DomainJoinedDevice", "ApprovedApplication", "CompliantApplication") + ClientAppTypes = @("Browser", "MobileAppsAndDesktopClients") + CloudAppSecurityIsEnabled = $True + CloudAppSecurityType = "MonitorOnly" + DisplayName = "Allin" + Ensure = "Present" + ExcludeApplications = @("00000012-0000-0000-c000-000000000000", "Office365") + ExcludeDeviceStates = @("Compliant", "DomainJoined") + ExcludeGroups = @("Group 01") + ExcludeLocations = "Contoso LAN" + ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS") + ExcludeRoles = @("Compliance Administrator") + ExcludeUsers = "alexw@contoso.com" + GlobalAdminAccount = $Credsglobaladmin + GrantControlOperator = "AND" + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + IncludeApplications = @("All") + IncludeDeviceStates = @("All") + IncludeGroups = @("Group 01") + IncludeLocations = "AllTrusted" + IncludePlatforms = @("Android", "IOS") + IncludeRoles = @("Compliance Administrator") + IncludeUserActions = @("urn:user:registersecurityinfo") + IncludeUsers = "All" + PersistentBrowserIsEnabled = $True + PersistentBrowserMode = "Always" + SignInFrequencyIsEnabled = $True + SignInFrequencyType = "Days" + SignInFrequencyValue = 5 + SignInRiskLevels = @("High") + State = "disabled" + UserRiskLevels = @("High") } Mock -CommandName Get-AzureADMSConditionalAccessPolicy -MockWith { return @{ - Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" - DisplayName = "Allin" - State = "disabled" - Conditions = @{ - Applications = @{ - IncludeApplications = @("All") - ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") - IncludeUserActions = @("urn:user:registersecurityinfo") - } - Users = @{ - IncludeUsers = "All" - ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" - IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") - ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") - IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") - ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") - } - Platforms = @{ - IncludePlatforms = @("Android","IOS") - ExcludePlatforms = @("Windows","WindowsPhone","MacOS") - } - Locations = @{ - IncludeLocations = "AllTrusted" - ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" - } - Devices = @{ - IncludeDeviceStates = @("All") - ExcludeDeviceStates = @("Compliant","DomainJoined") - } - ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") - SignInRiskLevels = @("High") - UserRiskLevels = @("High") + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + DisplayName = "Allin" + State = "disabled" + Conditions = @{ + Applications = @{ + IncludeApplications = @("All") + ExcludeApplications = @("00000012-0000-0000-c000-000000000000", "Office365") + IncludeUserActions = @("urn:user:registersecurityinfo") + } + Users = @{ + IncludeUsers = "All" + ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" + IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + } + Platforms = @{ + IncludePlatforms = @("Android", "IOS") + ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS") + } + Locations = @{ + IncludeLocations = "AllTrusted" + ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + } + Devices = @{ + IncludeDeviceStates = @("All") + ExcludeDeviceStates = @("Compliant", "DomainJoined") + } + ClientAppTypes = @("Browser", "MobileAppsAndDesktopClients") + SignInRiskLevels = @("High") + UserRiskLevels = @("High") } - GrantControls = @{ - _Operator = "AND" - BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + GrantControls = @{ + _Operator = "AND" + BuiltInControls = @("Mfa", "CompliantDevice", "DomainJoinedDevice", "ApprovedApplication", "CompliantApplication") } SessionControls = @{ ApplicationEnforcedRestrictions = @{ IsEnabled = $True } - CloudAppSecurity = @{ - IsEnabled = $True - CloudAppSecurityType = "MonitorOnly" + CloudAppSecurity = @{ + IsEnabled = $True + CloudAppSecurityType = "MonitorOnly" } - SignInFrequency = @{ - IsEnabled = $True - Type = "Days" - Value = 5 + SignInFrequency = @{ + IsEnabled = $True + Type = "Days" + Value = 5 } - PersistentBrowser = @{ + PersistentBrowser = @{ IsEnabled = $True - Mode = "Always" + Mode = "Always" } } } } Mock -CommandName Get-AzureADUser -MockWith { return @{ - ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" + ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" UserPrincipalName = "alexw@contoso.com" } } Mock -CommandName Get-AzureADGroup -MockWith { return @{ - ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" + ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" DisplayName = "Group 01" } } Mock -CommandName Get-AzureADDirectoryRoleTemplate -MockWith { return @{ - ObjectId = "17315797-102d-40b4-93e0-432062caca18" + ObjectId = "17315797-102d-40b4-93e0-432062caca18" DisplayName = "Compliance Administrator" } } Mock -CommandName Get-AzureADMSNamedLocationPolicy -MockWith { return @{ - Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" DisplayName = "Contoso LAN" } } @@ -401,121 +401,121 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Context -Name "Policy exists but it should not" -Fixture { BeforeAll { $testParams = @{ - ApplicationEnforcedRestrictions_IsEnabled = $True - BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") - ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") - CloudAppSecurity_IsEnabled = $True - CloudAppSecurity_Type = "MonitorOnly" - DisplayName = "Allin" - Ensure = "Absent" - ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") - ExcludeDeviceStates = @("Compliant","DomainJoined") - ExcludeGroups = @("Group 01") - ExcludeLocations = "Contoso LAN" - ExcludePlatforms = @("Windows","WindowsPhone","MacOS") - ExcludeRoles = @("Compliance Administrator") - ExcludeUsers = "alexw@contoso.com" - GlobalAdminAccount = $Credsglobaladmin - GrantControl_Operator = "AND" - Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" - IncludeApplications = @("All") - IncludeDeviceStates = @("All") - IncludeGroups = @("Group 01") - IncludeLocations = "AllTrusted" - IncludePlatforms = @("Android","IOS") - IncludeRoles = @("Compliance Administrator") - IncludeUserActions = @("urn:user:registersecurityinfo") - IncludeUsers = "All" - PersistentBrowser_IsEnabled = $True - PersistentBrowser_Mode = "Always" - SignInFrequency_IsEnabled = $True - SignInFrequency_Type = "Days" - SignInFrequency_Value = 5 - SignInRiskLevels = @("High") - State = "disabled" - UserRiskLevels = @("High") + ApplicationEnforcedRestrictionsIsEnabled = $True + BuiltInControls = @("Mfa", "CompliantDevice", "DomainJoinedDevice", "ApprovedApplication", "CompliantApplication") + ClientAppTypes = @("Browser", "MobileAppsAndDesktopClients") + CloudAppSecurityIsEnabled = $True + CloudAppSecurityType = "MonitorOnly" + DisplayName = "Allin" + Ensure = "Absent" + ExcludeApplications = @("00000012-0000-0000-c000-000000000000", "Office365") + ExcludeDeviceStates = @("Compliant", "DomainJoined") + ExcludeGroups = @("Group 01") + ExcludeLocations = "Contoso LAN" + ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS") + ExcludeRoles = @("Compliance Administrator") + ExcludeUsers = "alexw@contoso.com" + GlobalAdminAccount = $Credsglobaladmin + GrantControlOperator = "AND" + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + IncludeApplications = @("All") + IncludeDeviceStates = @("All") + IncludeGroups = @("Group 01") + IncludeLocations = "AllTrusted" + IncludePlatforms = @("Android", "IOS") + IncludeRoles = @("Compliance Administrator") + IncludeUserActions = @("urn:user:registersecurityinfo") + IncludeUsers = "All" + PersistentBrowserIsEnabled = $True + PersistentBrowserMode = "Always" + SignInFrequencyIsEnabled = $True + SignInFrequencyType = "Days" + SignInFrequencyValue = 5 + SignInRiskLevels = @("High") + State = "disabled" + UserRiskLevels = @("High") } Mock -CommandName Get-AzureADMSConditionalAccessPolicy -MockWith { return @{ - Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" - DisplayName = "Allin" - State = "disabled" - Conditions = @{ - Applications = @{ - IncludeApplications = @("All") - ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") - IncludeUserActions = @("urn:user:registersecurityinfo") - } - Users = @{ - IncludeUsers = "All" - ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" - IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") - ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") - IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") - ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") - } - Platforms = @{ - IncludePlatforms = @("Android","IOS") - ExcludePlatforms = @("Windows","WindowsPhone","MacOS") - } - Locations = @{ - IncludeLocations = "AllTrusted" - ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" - } - Devices = @{ - IncludeDeviceStates = @("All") - ExcludeDeviceStates = @("Compliant","DomainJoined") - } - ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") - SignInRiskLevels = @("High") - UserRiskLevels = @("High") + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + DisplayName = "Allin" + State = "disabled" + Conditions = @{ + Applications = @{ + IncludeApplications = @("All") + ExcludeApplications = @("00000012-0000-0000-c000-000000000000", "Office365") + IncludeUserActions = @("urn:user:registersecurityinfo") + } + Users = @{ + IncludeUsers = "All" + ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" + IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + } + Platforms = @{ + IncludePlatforms = @("Android", "IOS") + ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS") + } + Locations = @{ + IncludeLocations = "AllTrusted" + ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + } + Devices = @{ + IncludeDeviceStates = @("All") + ExcludeDeviceStates = @("Compliant", "DomainJoined") + } + ClientAppTypes = @("Browser", "MobileAppsAndDesktopClients") + SignInRiskLevels = @("High") + UserRiskLevels = @("High") } - GrantControls = @{ - _Operator = "AND" - BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + GrantControls = @{ + _Operator = "AND" + BuiltInControls = @("Mfa", "CompliantDevice", "DomainJoinedDevice", "ApprovedApplication", "CompliantApplication") } SessionControls = @{ ApplicationEnforcedRestrictions = @{ IsEnabled = $True } - CloudAppSecurity = @{ - IsEnabled = $True - CloudAppSecurityType = "MonitorOnly" + CloudAppSecurity = @{ + IsEnabled = $True + CloudAppSecurityType = "MonitorOnly" } - SignInFrequency = @{ - IsEnabled = $True - Type = "Days" - Value = 5 + SignInFrequency = @{ + IsEnabled = $True + Type = "Days" + Value = 5 } - PersistentBrowser = @{ + PersistentBrowser = @{ IsEnabled = $True - Mode = "Always" + Mode = "Always" } } } } - Mock -CommandName Get-AzureADUser -MockWith { + Mock -CommandName Get-AzureADUser -MockWith { return @{ - ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" + ObjectId = "76d3c3f6-8269-462b-9385-37435cb33f1e" UserPrincipalName = "alexw@contoso.com" } } Mock -CommandName Get-AzureADGroup -MockWith { return @{ - ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" + ObjectId = "f1eb1a09-c0c2-4df4-9e69-fee01f00db31" DisplayName = "Group 01" } } Mock -CommandName Get-AzureADDirectoryRoleTemplate -MockWith { return @{ - ObjectId = "17315797-102d-40b4-93e0-432062caca18" + ObjectId = "17315797-102d-40b4-93e0-432062caca18" DisplayName = "Compliance Administrator" } } Mock -CommandName Get-AzureADMSNamedLocationPolicy -MockWith { return @{ - Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + Id = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" DisplayName = "Contoso LAN" } } @@ -543,59 +543,59 @@ Describe -Name $Global:DscHelper.DescribeHeader -Fixture { Mock -CommandName Get-AzureADMSConditionalAccessPolicy -MockWith { return @{ - Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" - DisplayName = "Allin" - State = "disabled" - Conditions = @{ - Applications = @{ - IncludeApplications = @("All") - ExcludeApplications = @("00000012-0000-0000-c000-000000000000","Office365") - IncludeUserActions = @("urn:user:registersecurityinfo") - } - Users = @{ - IncludeUsers = "All" - ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" - IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") - ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") - IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") - ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") - } - Platforms = @{ - IncludePlatforms = @("Android","IOS") - ExcludePlatforms = @("Windows","WindowsPhone","MacOS") - } - Locations = @{ - IncludeLocations = "AllTrusted" - ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" - } - Devices = @{ - IncludeDeviceStates = @("All") - ExcludeDeviceStates = @("Compliant","DomainJoined") - } - ClientAppTypes = @("Browser","MobileAppsAndDesktopClients") - SignInRiskLevels = @("High") - UserRiskLevels = @("High") + Id = "bcc0cf19-ee89-46f0-8e12-4b89123ee6f9" + DisplayName = "Allin" + State = "disabled" + Conditions = @{ + Applications = @{ + IncludeApplications = @("All") + ExcludeApplications = @("00000012-0000-0000-c000-000000000000", "Office365") + IncludeUserActions = @("urn:user:registersecurityinfo") + } + Users = @{ + IncludeUsers = "All" + ExcludeUsers = "76d3c3f6-8269-462b-9385-37435cb33f1e" + IncludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + ExcludeGroups = @("f1eb1a09-c0c2-4df4-9e69-fee01f00db31") + IncludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + ExcludeRoles = @("17315797-102d-40b4-93e0-432062caca18") + } + Platforms = @{ + IncludePlatforms = @("Android", "IOS") + ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS") + } + Locations = @{ + IncludeLocations = "AllTrusted" + ExcludeLocations = "9e4ca5f3-0ba9-4257-b906-74d3038ac970" + } + Devices = @{ + IncludeDeviceStates = @("All") + ExcludeDeviceStates = @("Compliant", "DomainJoined") + } + ClientAppTypes = @("Browser", "MobileAppsAndDesktopClients") + SignInRiskLevels = @("High") + UserRiskLevels = @("High") } - GrantControls = @{ - _Operator = "AND" - BuiltInControls = @("Mfa","CompliantDevice","DomainJoinedDevice","ApprovedApplication","CompliantApplication") + GrantControls = @{ + _Operator = "AND" + BuiltInControls = @("Mfa", "CompliantDevice", "DomainJoinedDevice", "ApprovedApplication", "CompliantApplication") } SessionControls = @{ ApplicationEnforcedRestrictions = @{ IsEnabled = $True } - CloudAppSecurity = @{ - IsEnabled = $True - CloudAppSecurityType = "MonitorOnly" + CloudAppSecurity = @{ + IsEnabled = $True + CloudAppSecurityType = "MonitorOnly" } - SignInFrequency = @{ - IsEnabled = $True - Type = "Days" - Value = 5 + SignInFrequency = @{ + IsEnabled = $True + Type = "Days" + Value = 5 } - PersistentBrowser = @{ + PersistentBrowser = @{ IsEnabled = $True - Mode = "Always" + Mode = "Always" } } } From c08f7d57adca9ece04b88c5a22ab80055c63170b Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 11 Dec 2020 08:39:12 -0500 Subject: [PATCH 24/33] Update MSFT_TeamsChannelTab.psm1 --- .../MSFT_TeamsChannelTab.psm1 | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index d3007d9445..f4870859b1 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -120,8 +120,9 @@ function Get-TargetResource # Get the Channel Tab Write-Verbose -Message "Getting Tabs for Channel {$ChannelName}" - $tabInstance = Get-MgTeamChannelTab -TeamId $teamInstance.GroupId ` - -ChannelId $channelInstance.Id | Where-Object -FilterScript { $_.DisplayName -eq $DisplayName } + $tabInstance = Get-M365DSCTeamChannelTab -TeamId $teamInstance.GroupId ` + -ChannelId $channelInstance.Id ` + -DisplayName $DisplayName if ($null -eq $tabInstance) { @@ -513,7 +514,7 @@ function New-M365DSCTeamsChannelTab $jsonContent = @" { "displayName": "$($Parameters.DisplayName)", - "teamsApp@odata.bind": "$($Parameters.TeamsApp)", + "teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/$($Parameters.TeamsApp)", "configuration": "{ "websiteUrl": "$($Parameters.WebSiteUrl)", "contentUrl": "$($Parameters.WebSiteUrl)" @@ -529,4 +530,31 @@ function New-M365DSCTeamsChannelTab -Headers @{"Content-Type" = "application/json" } | Out-Null } +function Get-M365DSCTeamChannelTab +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param( + [Parameter(Mandatory = $true)] + [System.String] + $TeamID, + + [Parameter(Mandatory = $true)] + [System.String] + $ChannelId, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName + ) + + $Url = "https://graph.microsoft.com/v1.0/teams/$TeamID/channels/$ChannelId/tabs?`$expand=teamsApp`&`$filter=displayName eq '$($DisplayName.Replace("'","''"))'" + Write-Verbose -Message "Retrieving tab with TeamsID {$TeamID} ChannelID {$ChannelID} DisplayName {$DisplayName}" + Write-Verbose -Message "Get to {$Url}" + $response = Invoke-MgGraphRequest -Method GET ` + -Uri $Url ` + -Headers @{"Content-Type" = "application/json" } + return $response.value +} + Export-ModuleMember -Function *-TargetResource From 59a66ac81c4b467e60e6e938d936ecd1db348a45 Mon Sep 17 00:00:00 2001 From: peterabele <71841133+peterabele@users.noreply.github.com> Date: Fri, 11 Dec 2020 15:11:09 +0100 Subject: [PATCH 25/33] Update 1-ConfigureAADConditionalAccessPolicy.ps1 --- .../1-ConfigureAADConditionalAccessPolicy.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 index 0d51e075c1..8a7effec50 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/AADConditionalAccessPolicy/1-ConfigureAADConditionalAccessPolicy.ps1 @@ -28,7 +28,7 @@ Configuration Example ExcludeLocations = @("Blocked Countries"); ExcludePlatforms = @("Windows", "WindowsPhone", "MacOS"); ExcludeRoles = @("Company Administrator", "Application Administrator", "Application Developer", "Cloud Application Administrator", "Cloud Device Administrator"); - ExcludeUsers = @("admin@$OrganizationName", "AAdmin@$OrganizationName", "CAAdmin@$OrganizationName", "AllanD@$OrganizationName", "AlexW@$OrganizationName", "GuestsOrExternalUsers"); + ExcludeUsers = @("admin@contoso.com", "AAdmin@contoso.com", "CAAdmin@contoso.com", "AllanD@contoso.com", "AlexW@contoso.com", "GuestsOrExternalUsers"); GrantControlOperator = "OR"; IncludeApplications = @("All"); IncludeDeviceStates = @("All"); From a55fcc204675897ce9e7ee417b11708cfc91e0b9 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 11 Dec 2020 11:53:09 -0500 Subject: [PATCH 26/33] Update MSFT_TeamsChannelTab.psm1 --- .../MSFT_TeamsChannelTab.psm1 | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index f4870859b1..ff79afb526 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -35,6 +35,18 @@ function Get-TargetResource [System.String] $WebSiteUrl, + [Parameter()] + [System.String] + $EntityId, + + [Parameter()] + [System.String] + $ContentUrl, + + [Parameter()] + [System.String] + $RemoveUrl, + [Parameter()] [ValidateSet("Present", "Absent")] [System.String] @@ -120,10 +132,15 @@ function Get-TargetResource # Get the Channel Tab Write-Verbose -Message "Getting Tabs for Channel {$ChannelName}" - $tabInstance = Get-M365DSCTeamChannelTab -TeamId $teamInstance.GroupId ` + [array]$tabInstance = Get-M365DSCTeamChannelTab -TeamId $teamInstance.GroupId ` -ChannelId $channelInstance.Id ` -DisplayName $DisplayName + if ($tabInstance.Length -gt 1) + { + throw "More than one instance of a tab with name {$DisplayName} was found." + } + if ($null -eq $tabInstance) { $nullResult = $PSBoundParameters @@ -137,8 +154,11 @@ function Get-TargetResource TeamId = $Team.GroupId ChannelName = $channelInstance.DisplayName SortOrderIndex = $tabInstance.SortOrderIndex - WebSiteUrl = $tabInstance.WebUrl - TeamsApp = $tabInstance.teamApp.id + WebSiteUrl = $tabInstance.configuration.websiteUrl + ContentUrl = $tabInstance.configuration.contentUrl + RemoveUrl = $tabInstance.configuration.removeUrl + EntityId = $tabInstance.configuration.entityId + TeamsApp = $tabInstance.teamsApp.id ApplicationId = $ApplicationId TenantId = $TenantID CertificateThumbprint = $CertificateThumbprint @@ -515,13 +535,15 @@ function New-M365DSCTeamsChannelTab { "displayName": "$($Parameters.DisplayName)", "teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/$($Parameters.TeamsApp)", - "configuration": "{ + "configuration": { "websiteUrl": "$($Parameters.WebSiteUrl)", - "contentUrl": "$($Parameters.WebSiteUrl)" + "contentUrl": "$($Parameters.WebSiteUrl)", + "removeURL": null, + "entityId": null } } "@ - $Url = "https://graph.microsoft.com/v1.0/teams/$($Parameters.TeamId)/channel/$($Parameters.ChannelId)/tabs" + $Url = "https://graph.microsoft.com/v1.0/teams/$($Parameters.TeamId)/channels/$($Parameters.ChannelId)/tabs" Write-Verbose -Message "Creating new Teams Tab with JSON payload: `r`n$JSONContent" Write-Verbose -Message "POST to {$Url}" Invoke-MgGraphRequest -Method POST ` @@ -548,7 +570,7 @@ function Get-M365DSCTeamChannelTab $DisplayName ) - $Url = "https://graph.microsoft.com/v1.0/teams/$TeamID/channels/$ChannelId/tabs?`$expand=teamsApp`&`$filter=displayName eq '$($DisplayName.Replace("'","''"))'" + $Url = "https://graph.microsoft.com/beta/teams/$TeamID/channels/$ChannelId/tabs?Expand=teamsApp&Filter=displayName eq '$($DisplayName.Replace("'","''"))'" Write-Verbose -Message "Retrieving tab with TeamsID {$TeamID} ChannelID {$ChannelID} DisplayName {$DisplayName}" Write-Verbose -Message "Get to {$Url}" $response = Invoke-MgGraphRequest -Method GET ` From 31fae4ae281b409fe03dd1dd9cee0b1d9f46d052 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 11 Dec 2020 12:40:34 -0500 Subject: [PATCH 27/33] Fixes --- .../MSFT_TeamsChannelTab.psm1 | 78 +++++++++++++++++-- .../MSFT_TeamsChannelTab.schema.mof | 3 + 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index ff79afb526..7dad3db9d9 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -151,7 +151,7 @@ function Get-TargetResource return @{ DisplayName = $tabInstance.DisplayName TeamName = $TeamName - TeamId = $Team.GroupId + TeamId = $teamInstance.GroupId ChannelName = $channelInstance.DisplayName SortOrderIndex = $tabInstance.SortOrderIndex WebSiteUrl = $tabInstance.configuration.websiteUrl @@ -227,6 +227,18 @@ function Set-TargetResource [System.String] $WebSiteUrl, + [Parameter()] + [System.String] + $EntityId, + + [Parameter()] + [System.String] + $ContentUrl, + + [Parameter()] + [System.String] + $RemoveUrl, + [Parameter()] [ValidateSet("Present", "Absent")] [System.String] @@ -268,8 +280,11 @@ function Set-TargetResource $CurrentParameters.Remove("TenantId") | Out-Null $CurrentParameters.Remove("CertificateThumbprint") | Out-Null + Write-Verbose -Message "Retrieving Team Channel {$ChannelName} from Team {$($tab.TeamId)}" $ChannelInstance = Get-MgTeamChannel -TeamId $tab.TeamId ` -Filter "DisplayName eq '$ChannelName'" + + Write-Verbose -Message "Retrieving Tab {$DisplayName} from Channel {$($ChannelInstance.Id))} from Team {$($tab.TeamId)}" $tabInstance = Get-MgTeamChannelTab -TeamId $tab.TeamId ` -ChannelId $ChannelInstance.Id ` -Filter "DisplayName eq '$DisplayName'" @@ -277,10 +292,10 @@ function Set-TargetResource { Write-Verbose -Message "Updating current instance of tab {$($tabInstance.DisplayName)}" $CurrentParameters.Add("ChannelId", $ChannelInstance.Id) - $CurrentParameters.Add("TeamsTabId", $tabInstance.Id) $CurrentParameters.Remove("TeamName") | Out-Null $CurrentParameters.Remove("ChannelName") | Out-Null - Update-MgTeamChannelTab @CurrentParameters | Out-Null + Set-M365DSCTeamsChannelTab -Parameters $CurrentParameters ` + -TabId $tabInstance.Id | Out-Null } elseif ($Ensure -eq "Present" -and ($tab.Ensure -eq "Absent")) { @@ -341,6 +356,18 @@ function Test-TargetResource [System.String] $WebSiteUrl, + [Parameter()] + [System.String] + $EntityId, + + [Parameter()] + [System.String] + $ContentUrl, + + [Parameter()] + [System.String] + $RemoveUrl, + [Parameter()] [ValidateSet("Present", "Absent")] [System.String] @@ -535,15 +562,16 @@ function New-M365DSCTeamsChannelTab { "displayName": "$($Parameters.DisplayName)", "teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/$($Parameters.TeamsApp)", + "sortOrderIndex": "$($Parameters.SortOrderIndex)", "configuration": { "websiteUrl": "$($Parameters.WebSiteUrl)", - "contentUrl": "$($Parameters.WebSiteUrl)", - "removeURL": null, - "entityId": null + "contentUrl": "$($Parameters.ContentUrl)", + "removeURL": "$($Parameters.RemoveUrl)", + "entityId": "$($Parameters.EntityId)" } } "@ - $Url = "https://graph.microsoft.com/v1.0/teams/$($Parameters.TeamId)/channels/$($Parameters.ChannelId)/tabs" + $Url = "https://graph.microsoft.com/beta/teams/$($Parameters.TeamId)/channels/$($Parameters.ChannelId)/tabs" Write-Verbose -Message "Creating new Teams Tab with JSON payload: `r`n$JSONContent" Write-Verbose -Message "POST to {$Url}" Invoke-MgGraphRequest -Method POST ` @@ -552,6 +580,40 @@ function New-M365DSCTeamsChannelTab -Headers @{"Content-Type" = "application/json" } | Out-Null } +function Set-M365DSCTeamsChannelTab +{ + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [System.Collections.HashTable] + $Parameters, + + [Parameter(Mandatory = $true)] + [System.String] + $TabID + ) + + $jsonContent = @" + { + "displayName": "$($Parameters.DisplayName)", + "sortOrderIndex": "$($Parameters.SortOrderIndex)", + "configuration": { + "websiteUrl": "$($Parameters.WebSiteUrl)", + "contentUrl": "$($Parameters.ContentUrl)", + "removeURL": "$($Parameters.RemoveUrl)", + "entityId": "$($Parameters.EntityId)" + } + } +"@ + $Url = "https://graph.microsoft.com/beta/teams/$($Parameters.TeamId)/channels/$($Parameters.ChannelId)/tabs/$tabId" + Write-Verbose -Message "Updating Teams Tab with JSON payload: `r`n$JSONContent" + Write-Verbose -Message "PATCH to {$Url}" + Invoke-MgGraphRequest -Method PATCH ` + -Uri $Url ` + -Body $JSONContent ` + -Headers @{"Content-Type" = "application/json" } | Out-Null +} + function Get-M365DSCTeamChannelTab { [CmdletBinding()] @@ -572,7 +634,7 @@ function Get-M365DSCTeamChannelTab $Url = "https://graph.microsoft.com/beta/teams/$TeamID/channels/$ChannelId/tabs?Expand=teamsApp&Filter=displayName eq '$($DisplayName.Replace("'","''"))'" Write-Verbose -Message "Retrieving tab with TeamsID {$TeamID} ChannelID {$ChannelID} DisplayName {$DisplayName}" - Write-Verbose -Message "Get to {$Url}" + Write-Verbose -Message "GET request to {$Url}" $response = Invoke-MgGraphRequest -Method GET ` -Uri $Url ` -Headers @{"Content-Type" = "application/json" } diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof index b54e20a0d4..b4c641db36 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.schema.mof @@ -8,6 +8,9 @@ class MSFT_TeamsChannelTab : OMI_BaseResource [Write, Description("Id of the Teams App associated with the custom tab.")]String TeamsApp; [Write, Description("Index of the sort order for the custom tab.")]UInt32 SortOrderIndex; [Write, Description("Url of the website linked to the Channel Tab.")]String WebSiteUrl; + [Write, Description("Url of the content linked to the Channel Tab.")]String ContentUrl; + [Write, Description("Url of the location used to remove the app.")]String RemoveUrl; + [Write, Description("Id of the Entity linked to the Channel Tab.")]String EntityId; [Write, Description("Present ensures the Tab exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; From b0e841e53166dc45f0d0700a3146d4a252f6522f Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 11 Dec 2020 13:46:57 -0500 Subject: [PATCH 28/33] Ready for PR --- .../MSFT_TeamsChannelTab.psm1 | 21 +- .../TeamsChannelTab/1-CreateNewCustomTab.ps1 | 32 ++ .../Microsoft365DSC.TeamsChannelTab.Tests.ps1 | 336 ++++++++++++++++++ Tests/Unit/Stubs/Generic.psm1 | 2 +- 4 files changed, 381 insertions(+), 10 deletions(-) create mode 100644 Modules/Microsoft365DSC/Examples/Resources/TeamsChannelTab/1-CreateNewCustomTab.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.TeamsChannelTab.Tests.ps1 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index 7dad3db9d9..d38cb354d5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -116,6 +116,8 @@ function Get-TargetResource throw $Message } + $nullReturn.TeamId = $teamInstance.GroupId + $ConnectionMode = New-M365DSCConnection -Platform 'MicrosoftGraph' ` -InboundParameters $PSBoundParameters # Get the Channel ID @@ -124,7 +126,7 @@ function Get-TargetResource if ($null -eq $channelInstance) { - Add-M365DSCEvent -Message $_ -EntryType 'Error' ` + Add-M365DSCEvent -Message "Could not find Channels for Team {$($teamInstance.GroupId)}" -EntryType 'Error' ` -EventID 1 -Source $($MyInvocation.MyCommand.Source) ` -TenantId $TenantID throw "Channel {$ChannelName} was not found." @@ -284,16 +286,13 @@ function Set-TargetResource $ChannelInstance = Get-MgTeamChannel -TeamId $tab.TeamId ` -Filter "DisplayName eq '$ChannelName'" - Write-Verbose -Message "Retrieving Tab {$DisplayName} from Channel {$($ChannelInstance.Id))} from Team {$($tab.TeamId)}" - $tabInstance = Get-MgTeamChannelTab -TeamId $tab.TeamId ` - -ChannelId $ChannelInstance.Id ` - -Filter "DisplayName eq '$DisplayName'" if ($Ensure -eq "Present" -and ($tab.Ensure -eq "Present")) { - Write-Verbose -Message "Updating current instance of tab {$($tabInstance.DisplayName)}" - $CurrentParameters.Add("ChannelId", $ChannelInstance.Id) - $CurrentParameters.Remove("TeamName") | Out-Null - $CurrentParameters.Remove("ChannelName") | Out-Null + Write-Verbose -Message "Retrieving Tab {$DisplayName} from Channel {$($ChannelInstance.Id))} from Team {$($tab.TeamId)}" + $tabInstance = Get-M365DSCTeamChannelTab -TeamId $tab.TeamId ` + -ChannelId $ChannelInstance.Id ` + -DisplayName $DisplayName + Set-M365DSCTeamsChannelTab -Parameters $CurrentParameters ` -TabId $tabInstance.Id | Out-Null } @@ -309,6 +308,10 @@ function Set-TargetResource } elseif ($Ensure -eq "Absent" -and ($tab.Ensure -eq "Present")) { + Write-Verbose -Message "Retrieving Tab {$DisplayName} from Channel {$($ChannelInstance.Id))} from Team {$($tab.TeamId)}" + $tabInstance = Get-M365DSCTeamChannelTab -TeamId $tab.TeamId ` + -ChannelId $ChannelInstance.Id ` + -DisplayName $DisplayName Write-Verbose -Message "Removing existing tab {$DisplayName}" $RemoveParams = @{ ChannelId = $ChannelInstance.Id diff --git a/Modules/Microsoft365DSC/Examples/Resources/TeamsChannelTab/1-CreateNewCustomTab.ps1 b/Modules/Microsoft365DSC/Examples/Resources/TeamsChannelTab/1-CreateNewCustomTab.ps1 new file mode 100644 index 0000000000..c12ea4c1eb --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/TeamsChannelTab/1-CreateNewCustomTab.ps1 @@ -0,0 +1,32 @@ +<# +This example is used to test new resources and showcase the usage of new resources being worked on. +It is not meant to use as a production baseline. +#> + +Configuration Example +{ + param( + [Parameter(Mandatory = $true)] + [PSCredential] + $credsGlobalAdmin + ) + Import-DscResource -ModuleName Microsoft365DSC + + node localhost + { + TeamsChannelTab MyWebTab + { + ApplicationId = "12345"; + CertificateThumbprint = "ABCDEF1234567890"; + ChannelName = "General"; + ContentUrl = "https://contoso.com"; + DisplayName = "TestTab" + Ensure = "Present" + SortOrderIndex = "10100"; + TeamName = "Contoso Team"; + TeamsApp = "com.microsoft.teamspace.tab.web"; + TenantId = "contoso.onmicrosoft.com"; + WebSiteUrl = "https://contoso.com"; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.TeamsChannelTab.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.TeamsChannelTab.Tests.ps1 new file mode 100644 index 0000000000..dac256e9ff --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.TeamsChannelTab.Tests.ps1 @@ -0,0 +1,336 @@ +[CmdletBinding()] +param( +) +$M365DSCTestFolder = Join-Path -Path $PSScriptRoot ` + -ChildPath "..\..\Unit" ` + -Resolve +$CmdletModule = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath "\Stubs\Microsoft365.psm1" ` + -Resolve) +$GenericStubPath = (Join-Path -Path $M365DSCTestFolder ` + -ChildPath "\Stubs\Generic.psm1" ` + -Resolve) +Import-Module -Name (Join-Path -Path $M365DSCTestFolder ` + -ChildPath "\UnitTestHelper.psm1" ` + -Resolve) + +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource "TeamsChannelTab" -GenericStubModule $GenericStubPath + +Describe -Name $Global:DscHelper.DescribeHeader -Fixture { + InModuleScope -ModuleName $Global:DscHelper.ModuleName -ScriptBlock { + Invoke-Command -ScriptBlock $Global:DscHelper.InitializeScript -NoNewScope + + BeforeAll { + $secpasswd = ConvertTo-SecureString "Pass@word1" -AsPlainText -Force + $GlobalAdminAccount = New-Object System.Management.Automation.PSCredential ("tenantadmin", $secpasswd) + + Mock -CommandName Update-M365DSCExportAuthenticationResults -MockWith { + return @{} + } + + Mock -CommandName Get-M365DSCExportContentForResource -MockWith { + + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credential" + } + + Mock -CommandName New-M365DSCTeamsChannelTab -MockWith { + } + + Mock -CommandName Set-M365DSCTeamsChannelTab -MockWith { + } + + Mock -CommandName Remove-MgTeamChannelTab -MockWith { + } + } + + # Test contexts + Context -Name "When the Tab doesn't exist but should" -Fixture { + BeforeAll { + $testParams = @{ + ApplicationId = "12345"; + CertificateThumbprint = "ABCDEF1234567890"; + ChannelName = "General"; + ContentUrl = "https://contoso.com"; + DisplayName = "TestTab" + Ensure = "Present" + SortOrderIndex = "10100"; + TeamName = "Contoso Team"; + TeamsApp = "com.microsoft.teamspace.tab.web"; + TenantId = 'contoso.onmicrosoft.com'; + WebSiteUrl = "https://contoso.com"; + } + + Mock -CommandName Get-Team -MockWith { + return @{ + GroupId = "12345-12345-12345-12345-12345" + DisplayName = "Contoso Team" + } + } + + Mock -CommandName Get-MgTeamChannel -MockWith { + return @{ + Id = "67890-67890-67890-67890-67890" + DisplayName = "General" + } + } + + Mock -CommandName Get-M365DSCTeamChannelTab -MockWith { + return $null + } + } + + It "Should return absent from the Get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + + It "Should return false from the Test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should create the tab in the Set method" { + Set-TargetResource @testParams + Should -Invoke -CommandName New-M365DSCTeamsChannelTab -Exactly 1 + } + } + + Context -Name "The tab exists but is not in the Desired State" -Fixture { + BeforeAll { + $testParams = @{ + ApplicationId = "12345"; + CertificateThumbprint = "ABCDEF1234567890"; + ChannelName = "General"; + ContentUrl = "https://contoso.com"; + DisplayName = "TestTab" + Ensure = "Present" + SortOrderIndex = "10100"; + TeamName = "Contoso Team"; + TeamsApp = "com.microsoft.teamspace.tab.web"; + TenantId = 'contoso.onmicrosoft.com'; + WebSiteUrl = "https://contoso.com"; + } + + Mock -CommandName Get-Team -MockWith { + return @{ + GroupId = "12345-12345-12345-12345-12345" + DisplayName = "Contoso Team" + } + } + + Mock -CommandName Get-MgTeamChannel -MockWith { + return @{ + Id = "67890-67890-67890-67890-67890" + DisplayName = "General" + } + } + + Mock -CommandName Get-MgTeamChannelTab -MockWith { + return @{ + + } + } + + Mock -CommandName Get-M365DSCTeamChannelTab -MockWith { + return @{ + id = "12345-12345-12345-12345-12345" + displayName = "TestTab" + sortOrderIndex = "11100" #Drift + webUrl = "https://contoso.com" + configuration = @{ + entityId = $null + contentUrl = "https://contoso.com" + websiteUrl = "https://contoso.com" + removeUrl = $null + } + teamsApp = @{ + id = "com.microsoft.teamspace.tab.web" + } + } + } + } + + It "Should return Present from the Get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It "Should return false from the Test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should update the settings from the Set method" { + Set-TargetResource @testParams + Should -Invoke -CommandName Set-M365DSCTeamsChannelTab -Exactly 1 + } + } + + Context -Name "The tab exists and is already in the Desired State" -Fixture { + BeforeAll { + $testParams = @{ + ApplicationId = "12345"; + CertificateThumbprint = "ABCDEF1234567890"; + ChannelName = "General"; + ContentUrl = "https://contoso.com"; + DisplayName = "TestTab" + Ensure = "Present" + SortOrderIndex = "10100"; + TeamName = "Contoso Team"; + TeamsApp = "com.microsoft.teamspace.tab.web"; + TenantId = 'contoso.onmicrosoft.com'; + WebSiteUrl = "https://contoso.com"; + } + + Mock -CommandName Get-Team -MockWith { + return @{ + GroupId = "12345-12345-12345-12345-12345" + DisplayName = "Contoso Team" + } + } + + Mock -CommandName Get-MgTeamChannel -MockWith { + return @{ + Id = "67890-67890-67890-67890-67890" + DisplayName = "General" + } + } + + Mock -CommandName Get-M365DSCTeamChannelTab -MockWith { + return @{ + id = "12345-12345-12345-12345-12345" + displayName = "TestTab" + sortOrderIndex = "10100" + webUrl = "https://contoso.com" + configuration = @{ + entityId = $null + contentUrl = "https://contoso.com" + websiteUrl = "https://contoso.com" + removeUrl = $null + } + teamsApp = @{ + id = "com.microsoft.teamspace.tab.web" + } + } + } + } + + It "Should return Present from the Get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It "Should return true from the Test method" { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "Policy exists but it should not" -Fixture { + BeforeAll { + $testParams = @{ + ApplicationId = "12345"; + CertificateThumbprint = "ABCDEF1234567890"; + ChannelName = "General"; + ContentUrl = "https://contoso.com"; + DisplayName = "TestTab" + Ensure = "Absent" + SortOrderIndex = "10100"; + TeamName = "Contoso Team"; + TeamsApp = "com.microsoft.teamspace.tab.web"; + TenantId = 'contoso.onmicrosoft.com'; + WebSiteUrl = "https://contoso.com"; + } + + Mock -CommandName Get-Team -MockWith { + return @{ + GroupId = "12345-12345-12345-12345-12345" + DisplayName = "Contoso Team" + } + } + + Mock -CommandName Get-MgTeamChannel -MockWith { + return @{ + Id = "67890-67890-67890-67890-67890" + DisplayName = "General" + } + } + + Mock -CommandName Get-M365DSCTeamChannelTab -MockWith { + return @{ + id = "12345-12345-12345-12345-12345" + displayName = "TestTab" + sortOrderIndex = "11100" #Drift + webUrl = "https://contoso.com" + configuration = @{ + entityId = $null + contentUrl = "https://contoso.com" + websiteUrl = "https://contoso.com" + removeUrl = $null + } + teamsApp = @{ + id = "com.microsoft.teamspace.tab.web" + } + } + } + } + + It "Should return Present from the Get method" { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It "Should return false from the Test method" { + Test-TargetResource @testParams | Should -Be $false + } + + It "Should remove the policy from the Set method" { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgTeamChannelTab -Exactly 1 + } + } + + Context -Name "ReverseDSC Tests" -Fixture { + BeforeAll { + $testParams = @{ + GlobalAdminAccount = $GlobalAdminAccount + } + + Mock -CommandName Get-Team -MockWith { + return @{ + GroupId = "12345-12345-12345-12345-12345" + DisplayName = "Contoso Team" + } + } + + Mock -CommandName Get-MgTeamChannel -MockWith { + return @{ + Id = "67890-67890-67890-67890-67890" + DisplayName = "General" + } + } + + Mock -CommandName Get-M365DSCTeamChannelTab -MockWith { + return @{ + id = "12345-12345-12345-12345-12345" + displayName = "TestTab" + sortOrderIndex = "11100" #Drift + webUrl = "https://contoso.com" + configuration = @{ + entityId = $null + contentUrl = "https://contoso.com" + websiteUrl = "https://contoso.com" + removeUrl = $null + } + teamsApp = @{ + id = "com.microsoft.teamspace.tab.web" + } + } + } + } + + It "Should Reverse Engineer resource from the Export method" { + Export-TargetResource @testParams + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope diff --git a/Tests/Unit/Stubs/Generic.psm1 b/Tests/Unit/Stubs/Generic.psm1 index 706c0a2364..1ef3f7ef52 100644 --- a/Tests/Unit/Stubs/Generic.psm1 +++ b/Tests/Unit/Stubs/Generic.psm1 @@ -196,7 +196,7 @@ function New-M365DSCConnection [Parameter(Mandatory = $true)] [ValidateSet("Azure", "AzureAD", "SharePointOnline", "ExchangeOnline", 'Intune', ` "SecurityComplianceCenter", "MSOnline", "PnP", "PowerPlatforms", ` - "MicrosoftTeams", "SkypeForBusiness")] + "MicrosoftTeams", "SkypeForBusiness", "MicrosoftGraph")] [System.String] $Platform, From ef3df75e886e37ec67ee071b90016150d82ae0c6 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 11 Dec 2020 13:48:31 -0500 Subject: [PATCH 29/33] Update CHANGELOG.md --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03b4892eab..5a6317484f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change log for Microsoft365DSC +# 1.20.1216.1 + +* AADConditionalAccessPolicy + * Initial Release; +* O365User + * Added support for removing existing users with + Ensure = 'Absent'; +* TeamsChannelTab + * Initial Release; + # 1.20.1209.1 * IntuneAppProtectionPolicyiOS From fcb879e6c35e95bbcf21bd97eff8124fd4b9b4e9 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Fri, 11 Dec 2020 15:16:14 -0500 Subject: [PATCH 30/33] Code Review Fixes --- .../MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 | 6 +++++- .../Resources/TeamsChannelTab/1-CreateNewCustomTab.ps1 | 5 ----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 index d38cb354d5..1b1da34892 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_TeamsChannelTab/MSFT_TeamsChannelTab.psm1 @@ -90,7 +90,11 @@ function Get-TargetResource if ([System.String]::IsNullOrEmpty($TeamId)) { Write-Verbose -Message "Getting team by Name {$TeamName}" - $teamInstance = Get-Team | Where-Object -FilterScript { $_.DisplayName -eq $TeamName } + [array]$teamInstance = Get-Team | Where-Object -FilterScript { $_.DisplayName -eq $TeamName } + if ($teamInstance.Length -gt 1) + { + throw "Multiple Teams with name {$TeamName} were found. Please specify TeamId in your configuration instead." + } } else { diff --git a/Modules/Microsoft365DSC/Examples/Resources/TeamsChannelTab/1-CreateNewCustomTab.ps1 b/Modules/Microsoft365DSC/Examples/Resources/TeamsChannelTab/1-CreateNewCustomTab.ps1 index c12ea4c1eb..bd6dc93cd2 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/TeamsChannelTab/1-CreateNewCustomTab.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/TeamsChannelTab/1-CreateNewCustomTab.ps1 @@ -5,11 +5,6 @@ It is not meant to use as a production baseline. Configuration Example { - param( - [Parameter(Mandatory = $true)] - [PSCredential] - $credsGlobalAdmin - ) Import-DscResource -ModuleName Microsoft365DSC node localhost From 1250465711b6c5403883dada38f437cc7f1e4839 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 14 Dec 2020 06:51:03 -0500 Subject: [PATCH 31/33] EXOSafeLinksRule fix --- .../MSFT_EXOSafeLinksRule/MSFT_EXOSafeLinksRule.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOSafeLinksRule/MSFT_EXOSafeLinksRule.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOSafeLinksRule/MSFT_EXOSafeLinksRule.psm1 index a17c2e0eb1..5cfe424eed 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_EXOSafeLinksRule/MSFT_EXOSafeLinksRule.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_EXOSafeLinksRule/MSFT_EXOSafeLinksRule.psm1 @@ -499,7 +499,7 @@ function Export-TargetResource } catch { - Wtry + try { Write-Verbose -Message $_ $tenantIdValue = "" From 01c8f0a553a07fb0b99c48b34de5d38c659af816 Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Mon, 14 Dec 2020 06:51:45 -0500 Subject: [PATCH 32/33] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a6317484f..d2d3145d4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ * AADConditionalAccessPolicy * Initial Release; +* EXOSafeLinksRule + * Fixed typo in a try/catch clause; * O365User * Added support for removing existing users with Ensure = 'Absent'; From 281eca40676ff05531e67653432d7ebec5f58b8e Mon Sep 17 00:00:00 2001 From: Nik Charlebois Date: Wed, 16 Dec 2020 11:00:50 -0500 Subject: [PATCH 33/33] Release 1.20.1216.1 --- Modules/Microsoft365DSC/Microsoft365DSC.psd1 | 31 ++++++------------- .../Microsoft365DSC/Modules/M365DSCUtil.psm1 | 2 +- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 index aeb8b1684b..7dbedc084b 100644 --- a/Modules/Microsoft365DSC/Microsoft365DSC.psd1 +++ b/Modules/Microsoft365DSC/Microsoft365DSC.psd1 @@ -3,7 +3,7 @@ # # Generated by: Microsoft Corporation # -# Generated on: 2020-12-09 +# Generated on: 2020-12-16 @{ @@ -11,7 +11,7 @@ # RootModule = '' # Version number of this module. - ModuleVersion = '1.20.1209.1' + ModuleVersion = '1.20.1216.1' # Supported PSEditions # CompatiblePSEditions = @() @@ -180,26 +180,15 @@ IconUri = 'https://github.com/microsoft/Microsoft365DSC/blob/Dev/Modules/Microsoft365DSC/Dependencies/Images/Logo.png?raw=true' # ReleaseNotes of this module - ReleaseNotes = "* IntuneAppProtectionPolicyiOS + ReleaseNotes = "* AADConditionalAccessPolicy * Initial Release; - * IntuneDeviceCompliancePolicyiOS - * Initial Release; - * IntuneDeviceConfigurationPolicyiOS - * Initial Release; - * IntuneDeviceEnrollmentPlatformRestriction - * Initial Release; - * IntuneDeviceEnrollmentLimitRestriction - * Initial Release; - * TeamsTenantDialPlan - * Performance Improvements: retrieve all Voice Normalization - Rule at once and then iterated through them instead of - retrieving them for every instance. - * DEPENDENCIES - * Upgraded ExchangeOnlineManagement to version 2.0.3; - * Upgraded Microsoft.Graph.Authentication to version 1.2.0; - * Upgraded Microsoft.Graph.Planner to version 1.2.0; - * Upgraded SharePointPnPPowerShellOnline to version - 3.28.2012.0;" + * EXOSafeLinksRule + * Fixed typo in a try/catch clause; + * O365User + * Added support for removing existing users with + Ensure = 'Absent'; + * TeamsChannelTab + * Initial Release;" # Flag to indicate whether the module requires explicit user acceptance for install/update # RequireLicenseAcceptance = $false diff --git a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 index de580b42e9..b666707d6d 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCUtil.psm1 @@ -8,7 +8,7 @@ $Global:DefaultComponents = @("SPOApp", "SPOSiteDesign") $Global:FullComponents = @("AADMSGroup", "AADServicePrincipal", "EXOMailboxSettings", "EXOManagementRole", "O365Group", "O365User", ` "PlannerPlan", "PlannerBucket", "PlannerTask", "PPPowerAppsEnvironment", ` "SPOSiteAuditSettings", "SPOSiteGroup", "SPOSite", "SPOUserProfileProperty", "SPOPropertyBag", "TeamsTeam", "TeamsChannel", ` - "TeamsUser") + "TeamsUser", "TeamsChannelTab") #endregion function Format-EXOParams