From df5d34c00ebe5c2cee9ab636dd9837d9c6cf323e Mon Sep 17 00:00:00 2001 From: Sai Rohit Date: Wed, 23 Oct 2024 17:57:48 +0530 Subject: [PATCH 1/7] Added new resource device tenant policy. --- CHANGELOG.md | 2 + .../MSFT_SCDeviceTenantPolicy.psm1 | 378 ++++++++++++++++++ .../MSFT_SCDeviceTenantPolicy.schema.mof | 13 + .../MSFT_SCDeviceTenantPolicy/readme.md | 5 + .../MSFT_SCDeviceTenantPolicy/settings.json | 16 + .../SCDeviceTenantPolicy/1-Create.ps1 | 33 ++ .../SCDeviceTenantPolicy/2-Update.ps1 | 33 ++ .../SCDeviceTenantPolicy/3-Remove.ps1 | 31 ++ ...osoft365DSC.SCDeviceTenantPolicy.Tests.ps1 | 265 ++++++++++++ 9 files changed, 776 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/1-Create.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/2-Update.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCDeviceTenantPolicy.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 046e476c01..e228a492f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ * Fixed missing permissions in settings.json * Intune workload * Fixed missing permissions in settings.json +* SCDeviceTenantPolicy + * Initial Release. * SPOTenantSettings * Added support for AllowSelectSGsInODBListInTenant, DenySelectSGsInODBListInTenant, DenySelectSecurityGroupsInSPSitesList, diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.psm1 new file mode 100644 index 0000000000..2b9bb80554 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.psm1 @@ -0,0 +1,378 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter()] + [System.Boolean] + $Enabled, + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.String] + $CertificatePath, + + [Parameter()] + [System.Management.Automation.PSCredential] + $CertificatePassword, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + Write-Verbose -Message "Getting configuration of Device Tenant Policy..." + + if ($Global:CurrentModeIsExport) + { + $ConnectionMode = New-M365DSCConnection -Workload 'SecurityComplianceCenter' ` + -InboundParameters $PSBoundParameters ` + -SkipModuleReload $true + } + else + { + $ConnectionMode = New-M365DSCConnection -Workload 'SecurityComplianceCenter' ` + -InboundParameters $PSBoundParameters + } + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $nullReturn = $PSBoundParameters + $nullReturn.Ensure = 'Absent' + + try + { + $PolicyObject = Get-DeviceTenantPolicy -ErrorAction SilentlyContinue + + if ($null -eq $PolicyObject) + { + Write-Verbose -Message "Device tenant Policy does not exist." + return $nullReturn + } + else + { + Write-Verbose "Found existing Device tenant Policy" + $result = @{ + Ensure = 'Present' + Enabled = $PolicyObject.Enabled + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + CertificatePath = $CertificatePath + CertificatePassword = $CertificatePassword + AccessTokens = $AccessTokens + } + + Write-Verbose -Message "Get-TargetResource Result: `n $(Convert-M365DscHashtableToString -Hashtable $result)" + return $result + } + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullReturn + } +} + +function Set-TargetResource +{ + + [CmdletBinding()] + param + ( + [Parameter()] + [System.Boolean] + $Enabled, + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.String] + $CertificatePath, + + [Parameter()] + [System.Management.Automation.PSCredential] + $CertificatePassword, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + Write-Verbose -Message "Setting configuration of Device tenant Policy." + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + $ConnectionMode = New-M365DSCConnection -Workload 'SecurityComplianceCenter' ` + -InboundParameters $PSBoundParameters + + $policy = Get-DeviceTenantPolicy + + if ($policy.Mode -eq "PendingDeletion") + { + Write-Verbose "The device tenant policy is pending deletion. So no further action to be taken here." + return + } + + $CurrentPolicy = Get-TargetResource @PSBoundParameters + + if (('Present' -eq $Ensure) -and ('Absent' -eq $CurrentPolicy.Ensure)) + { + New-DeviceTenantPolicy -Enabled $Enabled + } + elseif (('Present' -eq $Ensure) -and ('Present' -eq $CurrentPolicy.Ensure)) + { + Write-Verbose "Updating Policy." + Set-DeviceTenantPolicy -Enabled $Enabled + } + elseif (('Absent' -eq $Ensure) -and ('Present' -eq $CurrentPolicy.Ensure)) + { + # If the Policy exists and it shouldn't, simply remove it; + Remove-DeviceTenantPolicy + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter()] + [System.Boolean] + $Enabled, + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.String] + $CertificatePath, + + [Parameter()] + [System.Management.Automation.PSCredential] + $CertificatePassword, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + Write-Verbose -Message "Testing configuration of Device Configuration Policy for $Name" + + $CurrentValues = Get-TargetResource @PSBoundParameters + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + $ValuesToCheck = $PSBoundParameters + + $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.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [System.String] + $CertificatePath, + + [Parameter()] + [System.Management.Automation.PSCredential] + $CertificatePassword, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + $ConnectionMode = New-M365DSCConnection -Workload 'SecurityComplianceCenter' ` + -InboundParameters $PSBoundParameters ` + -SkipModuleReload $true + + #Ensure the proper dependencies are installed in the current environment. + Confirm-M365DSCDependencies + + #region Telemetry + $ResourceName = $MyInvocation.MyCommand.ModuleName -replace 'MSFT_', '' + $CommandName = $MyInvocation.MyCommand + $data = Format-M365DSCTelemetryParameters -ResourceName $ResourceName ` + -CommandName $CommandName ` + -Parameters $PSBoundParameters + Add-M365DSCTelemetryEvent -Data $data + #endregion + + try + { + [array]$policies = Get-DeviceTenantPolicy -ErrorAction Stop | Where-Object -FilterScript { $_.Mode -ne 'PendingDeletion' } + + $i = 1 + $dscContent = '' + if ($policies.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($policy in $policies) + { + if ($null -ne $Global:M365DSCExportResourceInstancesCount) + { + $Global:M365DSCExportResourceInstancesCount++ + } + + Write-Host " |---[$i/$($policies.Length)] $($policy.Name)" -NoNewline + + $Results = Get-TargetResource @PSBoundParameters + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + Write-Host $Global:M365DSCEmojiGreenCheckMark + $i++ + } + return $dscContent + } + catch + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return '' + } +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.schema.mof new file mode 100644 index 0000000000..ac6805996a --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.schema.mof @@ -0,0 +1,13 @@ +[ClassVersion("1.0.0.0"), FriendlyName("SCDeviceTenantPolicy")] +class MSFT_SCDeviceConfigurationPolicy : OMI_BaseResource +{ + [Write, Description("Specify if this policy should be enabled or not.")] Boolean Enabled; + [Write, Description("Present ensures the instance exists, absent ensures it is removed."), ValueMap{"Absent", "Present"}, Values{"Absent", "Present"}] string Ensure; + [Write, Description("Credentials of Security and Compliance Center Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [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; + [Write, Description("Username can be made up to anything but password will be used for CertificatePassword"), EmbeddedInstance("MSFT_Credential")] String CertificatePassword; + [Write, Description("Path to certificate used in service principal usually a PFX file.")] String CertificatePath; + [Write, Description("Access token used for authentication.")] String AccessTokens[]; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/readme.md new file mode 100644 index 0000000000..3d01552af9 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/readme.md @@ -0,0 +1,5 @@ +# SCDeviceTenantPolicy + +## Description + +A policy that defines whether to block or allow mobile device access to Exchange Online email by unsupported devices that use Exchange ActiveSync only. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/settings.json new file mode 100644 index 0000000000..2ea6111849 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/settings.json @@ -0,0 +1,16 @@ +{ + "resourceName": "SCDeviceConfigurationPolicy", + "description": "", + "permissions": { + "graph": { + "delegated": { + "read": [], + "update": [] + }, + "application": { + "read": [], + "update": [] + } + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/1-Create.ps1 new file mode 100644 index 0000000000..3f6fbe18d2 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/1-Create.ps1 @@ -0,0 +1,33 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + SCDeviceTenantPolicy "DeviceTenantPolicy" + { + CertificateThumbprint = $CertificateThumbprint; + Ensure = "Present"; + TenantId = $TenantId; + ApplicationId = $ApplicationId; + Enabled = $true; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/2-Update.ps1 new file mode 100644 index 0000000000..3f6fbe18d2 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/2-Update.ps1 @@ -0,0 +1,33 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + SCDeviceTenantPolicy "DeviceTenantPolicy" + { + CertificateThumbprint = $CertificateThumbprint; + Ensure = "Present"; + TenantId = $TenantId; + ApplicationId = $ApplicationId; + Enabled = $true; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 new file mode 100644 index 0000000000..4e80dbee52 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 @@ -0,0 +1,31 @@ +<# +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()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint + ) + Import-DscResource -ModuleName Microsoft365DSC + node localhost + { + SCDeviceTenantPolicy "DeviceTenantPolicy" + { + CertificateThumbprint = $CertificateThumbprint; + TenantId = $TenantId; + ApplicationId = $ApplicationId; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCDeviceTenantPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCDeviceTenantPolicy.Tests.ps1 new file mode 100644 index 0000000000..f853c4b707 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.SCDeviceTenantPolicy.Tests.ps1 @@ -0,0 +1,265 @@ +[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 'SCDeviceTenantPolicy' -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 (New-Guid | Out-String) -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ('tenantadmin@mydomain.com', $secpasswd) + + + Mock -CommandName Confirm-M365DSCDependencies -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return 'Credentials' + } + + Mock -CommandName Import-PSSession -MockWith { + } + + Mock -CommandName New-PSSession -MockWith { + } + + Mock -CommandName Remove-DeviceTenantPolicy -MockWith { + # This mock should not return anything. Remove-* are normally void methods without any return types + } + + Mock -CommandName Set-DeviceTenantPolicy -MockWith { + } + + Mock -CommandName New-DeviceTenantPolicy -MockWith { + return @{ + # This mock can simply return an empty object for the purpose of these tests. + } + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + } + + # Test contexts + Context -Name "The Device Tenant Policy doesn't already exist" -Fixture { + BeforeAll { + $testParams = @{ + Ensure = 'Present' + Enabled = $true + Credential = $Credential + } + + Mock -CommandName Get-DeviceTenantPolicy -MockWith { + return $null # Policy Not found, therefore return null + } + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should return Absent from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + + It 'Should call the Set method' { + Set-TargetResource @testParams + + # Because the policy was not found, the set method should attempt to create it + # Therefore we want to assess that the New-* method was called exactly once + Should -Invoke -CommandName 'New-DeviceTenantPolicy' -Exactly 1 + } + } + + Context -Name 'The Device tenant Policy already exists and it is already in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Ensure = 'Present' + Enabled = $true + Credential = $Credential + } + + Mock -CommandName Get-DeviceTenantPolicy -MockWith { + return @{ + Enabled = $true + Mode = "Enforce" + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + } + + Context -Name 'The Device tenant Policy already exists and it is NOT in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + Ensure = 'Present' + Enabled = $true + Credential = $Credential + } + + Mock -CommandName Get-DeviceTenantPolicy -MockWith { + return @{ + Enabled = $false + Mode = "Enforce" + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + It 'Should update the policy in the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName 'Set-DeviceTenantPolicy' -Exactly 1 + } + } + + Context -Name 'The Device tenant Policy Exists but it Should NOT' -Fixture { + BeforeAll { + $testParams = @{ + Ensure = 'Absent' + Enabled = $true + Credential = $Credential + } + + Mock -CommandName Get-DeviceTenantPolicy -MockWith { + return @{ + Enabled = $false + Mode = "Enforce" + } + } + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should Delete from the Set method' { + Set-TargetResource @testParams + + # Because the policy was not found, the set method should attempt to delete it + # Therefore we want to assess that the Remove-* method was called exactly once + Should -Invoke -CommandName 'Remove-DeviceTenantPolicy' -Exactly 1 + } + } + + Context -Name 'The Device tenant Policy Exists but it Should NOT and is pending deletion so no action is needed.' -Fixture { + BeforeAll { + $testParams = @{ + Ensure = 'Absent' + Enabled = $true + Credential = $Credential + } + + Mock -CommandName Get-DeviceTenantPolicy -MockWith { + return @{ + Enabled = $false + Mode = "PendingDeletion" + } + } + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should Delete from the Set method' { + Set-TargetResource @testParams + + # Because the policy was not found, the set method should attempt to delete it + # Therefore we want to assess that the Remove-* method was called exactly once + Should -Invoke -CommandName 'Remove-DeviceTenantPolicy' -Exactly 0 + } + } + + Context -Name 'The Device tenant Policy already exists and it is NOT in the Desired State but is pending deletion so no action should be taken.' -Fixture { + BeforeAll { + $testParams = @{ + Ensure = 'Present' + Enabled = $true + Credential = $Credential + } + + Mock -CommandName Get-DeviceTenantPolicy -MockWith { + return @{ + Enabled = $false + Mode = "PendingDeletion" + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + It 'Should not update the policy in the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName 'Set-DeviceTenantPolicy' -Exactly 0 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-DeviceTenantPolicy -MockWith { + return @{ + Enabled = $false + Mode = "Enforce" + } + } + } + + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope From dbfc7b2a9c041ebb77439aeda6a2270e05fd66c2 Mon Sep 17 00:00:00 2001 From: Sai Rohit Date: Wed, 23 Oct 2024 18:11:34 +0530 Subject: [PATCH 2/7] Added ensure field in Remove.ps1 --- .../Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 index 4e80dbee52..6b9085a981 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 @@ -26,6 +26,7 @@ Configuration Example CertificateThumbprint = $CertificateThumbprint; TenantId = $TenantId; ApplicationId = $ApplicationId; + Ensure = "Absent"; } } } From fcc91e62d6f4ceaa5a500b270dc00a1ff6e42ec8 Mon Sep 17 00:00:00 2001 From: Sai Rohit Date: Wed, 23 Oct 2024 18:14:01 +0530 Subject: [PATCH 3/7] Changed resource name. --- .../DSCResources/MSFT_SCDeviceTenantPolicy/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/settings.json index 2ea6111849..cbc91821a5 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/settings.json +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/settings.json @@ -1,5 +1,5 @@ { - "resourceName": "SCDeviceConfigurationPolicy", + "resourceName": "SCDeviceTenantPolicy", "description": "", "permissions": { "graph": { From b141e5252dbba91f0d25b7c38b5c633b9ab7f8e9 Mon Sep 17 00:00:00 2001 From: Sai Rohit Date: Wed, 23 Oct 2024 22:41:31 +0530 Subject: [PATCH 4/7] Added Guid and changed class name. --- .../MSFT_SCDeviceTenantPolicy.psm1 | 17 +++++++++++++++++ .../MSFT_SCDeviceTenantPolicy.schema.mof | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.psm1 index 2b9bb80554..4daba06445 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.psm1 @@ -4,6 +4,10 @@ function Get-TargetResource [OutputType([System.Collections.Hashtable])] param ( + [Parameter()] + [System.String] + $Guid, + [Parameter()] [System.Boolean] $Enabled, @@ -84,6 +88,7 @@ function Get-TargetResource { Write-Verbose "Found existing Device tenant Policy" $result = @{ + Guid = $PolicyObject.Guid Ensure = 'Present' Enabled = $PolicyObject.Enabled Credential = $Credential @@ -117,6 +122,10 @@ function Set-TargetResource [CmdletBinding()] param ( + [Parameter()] + [System.String] + $Guid, + [Parameter()] [System.Boolean] $Enabled, @@ -204,6 +213,10 @@ function Test-TargetResource [OutputType([System.Boolean])] param ( + [Parameter()] + [System.String] + $Guid, + [Parameter()] [System.Boolean] $Enabled, @@ -278,6 +291,10 @@ function Export-TargetResource [OutputType([System.String])] param ( + [Parameter()] + [System.String] + $Guid, + [Parameter()] [System.Management.Automation.PSCredential] $Credential, diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.schema.mof index ac6805996a..61977762f3 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.schema.mof +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_SCDeviceTenantPolicy/MSFT_SCDeviceTenantPolicy.schema.mof @@ -1,6 +1,7 @@ [ClassVersion("1.0.0.0"), FriendlyName("SCDeviceTenantPolicy")] -class MSFT_SCDeviceConfigurationPolicy : OMI_BaseResource +class MSFT_SCDeviceTenantPolicy : OMI_BaseResource { + [Key, Description("Defines the Guid for the policy")] String Guid; [Write, Description("Specify if this policy should be enabled or not.")] Boolean Enabled; [Write, Description("Present ensures the instance exists, absent ensures it is removed."), ValueMap{"Absent", "Present"}, Values{"Absent", "Present"}] string Ensure; [Write, Description("Credentials of Security and Compliance Center Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; From bf24970b19b58bdee4f7509d791bebed758ee735 Mon Sep 17 00:00:00 2001 From: Sai Rohit Date: Wed, 23 Oct 2024 23:13:55 +0530 Subject: [PATCH 5/7] Added guid in the example files. --- .../Examples/Resources/SCDeviceTenantPolicy/1-Create.ps1 | 1 + .../Examples/Resources/SCDeviceTenantPolicy/2-Update.ps1 | 1 + .../Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 | 1 + 3 files changed, 3 insertions(+) diff --git a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/1-Create.ps1 index 3f6fbe18d2..f1fbfa77d0 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/1-Create.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/1-Create.ps1 @@ -23,6 +23,7 @@ Configuration Example { SCDeviceTenantPolicy "DeviceTenantPolicy" { + Guid = "sample guid"; CertificateThumbprint = $CertificateThumbprint; Ensure = "Present"; TenantId = $TenantId; diff --git a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/2-Update.ps1 index 3f6fbe18d2..f1fbfa77d0 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/2-Update.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/2-Update.ps1 @@ -23,6 +23,7 @@ Configuration Example { SCDeviceTenantPolicy "DeviceTenantPolicy" { + Guid = "sample guid"; CertificateThumbprint = $CertificateThumbprint; Ensure = "Present"; TenantId = $TenantId; diff --git a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 index 6b9085a981..352361ff52 100644 --- a/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 +++ b/Modules/Microsoft365DSC/Examples/Resources/SCDeviceTenantPolicy/3-Remove.ps1 @@ -23,6 +23,7 @@ Configuration Example { SCDeviceTenantPolicy "DeviceTenantPolicy" { + Guid = "sample guid"; CertificateThumbprint = $CertificateThumbprint; TenantId = $TenantId; ApplicationId = $ApplicationId; From c6f4c883fe88deae5dad6852b3676a92e6a53175 Mon Sep 17 00:00:00 2001 From: Sai Rohit Date: Thu, 24 Oct 2024 09:20:23 +0530 Subject: [PATCH 6/7] Added stubs. --- Tests/Unit/Stubs/Microsoft365.psm1 | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index f2481bb673..1c5a0e84a0 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -74438,6 +74438,16 @@ function New-DeviceConfigurationPolicy $Enabled ) } +function New-DeviceTenantPolicy +{ + [CmdletBinding()] + param( + + [Parameter()] + [System.Boolean] + $Enabled + ) +} function New-DlpCompliancePolicy { [CmdletBinding()] @@ -76357,6 +76367,14 @@ function Remove-DeviceConfigurationPolicy $Identity ) } + +function Remove-DeviceTenantPolicy +{ + [CmdletBinding()] + param( + ) +} + function Remove-DlpCompliancePolicy { [CmdletBinding()] @@ -77425,6 +77443,17 @@ function Set-DeviceConditionalAccessPolicy $Force ) } + +function Set-DeviceTenantPolicy +{ + [CmdletBinding()] + param( + [Parameter()] + [System.Boolean] + $Enabled + ) +} + function Set-DeviceConfigurationPolicy { [CmdletBinding()] From 47c040e338a9622b7c8350493bdd5e1993701804 Mon Sep 17 00:00:00 2001 From: Sai Rohit Date: Thu, 24 Oct 2024 10:28:16 +0530 Subject: [PATCH 7/7] Added stub for get device tenant policy. --- Tests/Unit/Stubs/Microsoft365.psm1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index 1c5a0e84a0..80e43dae25 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -1984,6 +1984,10 @@ function Get-DataEncryptionPolicy $DomainController ) } +function Get-DeviceTenantPolicy +{ +} + function Get-DeviceConditionalAccessPolicy { [CmdletBinding()]