From 56013c03641c5226b81798568952eb58f96c407d Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Fri, 21 Feb 2025 15:01:48 +0100 Subject: [PATCH] Add Intune Device Compliance Script for Windows10 resource --- CHANGELOG.md | 5 + ...IntuneDeviceComplianceScriptWindows10.psm1 | 547 ++++++++++++++++++ ...DeviceComplianceScriptWindows10.schema.mof | 21 + .../readme.md | 6 + .../settings.json | 16 + .../1-Create.ps1 | 40 ++ .../2-Update.ps1 | 40 ++ .../3-Remove.ps1 | 35 ++ ...eDeviceComplianceScriptWindows10.Tests.ps1 | 249 ++++++++ 9 files changed, 959 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/MSFT_IntuneDeviceComplianceScriptWindows10.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/MSFT_IntuneDeviceComplianceScriptWindows10.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/1-Create.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/2-Update.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/3-Remove.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceComplianceScriptWindows10.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 59a80ebf3e..a08464db67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* IntuneDeviceComplianceScriptWindows10 + * Initial release. + # 1.25.219.1 * AADAccessReviewPolicy diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/MSFT_IntuneDeviceComplianceScriptWindows10.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/MSFT_IntuneDeviceComplianceScriptWindows10.psm1 new file mode 100644 index 0000000000..058e24d281 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/MSFT_IntuneDeviceComplianceScriptWindows10.psm1 @@ -0,0 +1,547 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.Boolean] + $EnforceSignatureCheck, + + [Parameter()] + [System.String] + $Publisher, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.Boolean] + $RunAs32Bit, + + [Parameter()] + [ValidateSet('system', 'user')] + [System.String] + $RunAsAccount, + + [Parameter()] + [System.String] + $DetectionScriptContent, + + [Parameter()] + [System.String] + $Id, + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + Write-Verbose -Message "Getting configuration of the Intune Device Compliance Script for Windows10 with Id {$Id} and DisplayName {$DisplayName}" + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -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 + + $nullResult = $PSBoundParameters + $nullResult.Ensure = 'Absent' + + $getValue = $null + #region resource generator code + $getValue = Invoke-MgGraphRequest -Method GET -Uri "/beta/deviceManagement/deviceComplianceScripts/$Id" -SkipHttpErrorCheck + + if ($null -eq $getValue -or $null -ne $getValue.error) + { + Write-Verbose -Message "Could not find an Intune Device Compliance Script for Windows10 with Id {$Id}" + + if (-not [string]::IsNullOrEmpty($DisplayName)) + { + $getValue = (Invoke-MgGraphRequest -Method GET ` + -Uri "/beta/deviceManagement/deviceComplianceScripts?`$filter=displayName eq '$DisplayName'").value + if ($getValue.Count -gt 0) + { + $getValue = Invoke-MgGraphRequest -Method GET -Uri "/beta/deviceManagement/deviceComplianceScripts/$($getValue.id)" + } + } + } + #endregion + if ($getValue.Count -eq 0) + { + Write-Verbose -Message "Could not find an Intune Device Compliance Script for Windows10 with DisplayName {$DisplayName}" + return $nullResult + } + $Id = $getValue.Id + + Write-Verbose -Message "An Intune Device Compliance Script for Windows10 with Id {$Id} and DisplayName {$DisplayName} was found." + + #region resource generator code + $enumRunAsAccount = $null + if ($null -ne $getValue.RunAsAccount) + { + $enumRunAsAccount = $getValue.RunAsAccount.ToString() + } + #endregion + + $results = @{ + #region resource generator code + Description = $getValue.Description + DisplayName = $getValue.DisplayName + EnforceSignatureCheck = $getValue.EnforceSignatureCheck + RoleScopeTagIds = $getValue.RoleScopeTagIds + RunAs32Bit = $getValue.RunAs32Bit + RunAsAccount = $enumRunAsAccount + DetectionScriptContent = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($getValue.DetectionScriptContent)) + Publisher = $getValue.Publisher + Id = $getValue.Id + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + #endregion + } + + return [System.Collections.Hashtable] $results + } + catch + { + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.Boolean] + $EnforceSignatureCheck, + + [Parameter()] + [System.String] + $Publisher, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.Boolean] + $RunAs32Bit, + + [Parameter()] + [ValidateSet('system', 'user')] + [System.String] + $RunAsAccount, + + [Parameter()] + [System.String] + $DetectionScriptContent, + + [Parameter()] + [System.String] + $Id, + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [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 + + $currentInstance = Get-TargetResource @PSBoundParameters + + $BoundParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + $BoundParameters.DetectionScriptContent = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($BoundParameters.DetectionScriptContent)) + + # Convert all keys to camelCase + $scriptBody = @{} + foreach ($key in $BoundParameters.Keys) + { + $camelCaseKey = $key.Substring(0, 1).ToLower() + $key.Substring(1) + $scriptBody[$camelCaseKey] = $BoundParameters[$key] + } + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating an Intune Device Compliance Script for Windows10 with DisplayName {$DisplayName}" + $scriptBody.Remove('Id') | Out-Null + Invoke-MgGraphRequest -Method POST -Uri '/beta/deviceManagement/deviceComplianceScripts' -Body $($scriptBody | ConvertTo-Json) + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating the Intune Device Compliance Script for Windows10 with Id {$($currentInstance.Id)}" + Invoke-MgGraphRequest -Method PATCH -Uri "/beta/deviceManagement/deviceComplianceScripts/$($currentInstance.Id)" -Body $($scriptBody | ConvertTo-Json) + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing the Intune Device Compliance Script for Windows10 with Id {$($currentInstance.Id)}" + try + { + Invoke-MgGraphRequest -Method DELETE -Uri "/beta/deviceManagement/deviceComplianceScripts/$($currentInstance.Id)" -ErrorAction Stop + } + catch + { + throw "Failed to delete Intune Device Compliance Script for Windows10 with Id $($currentInstance.Id). Error: $($_.ErrorDetails.Message)" + } + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Description, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.Boolean] + $EnforceSignatureCheck, + + [Parameter()] + [System.String] + $Publisher, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.Boolean] + $RunAs32Bit, + + [Parameter()] + [ValidateSet('system', 'user')] + [System.String] + $RunAsAccount, + + [Parameter()] + [System.String] + $DetectionScriptContent, + + [Parameter()] + [System.String] + $Id, + #endregion + + [Parameter()] + [System.String] + [ValidateSet('Absent', 'Present')] + $Ensure = 'Present', + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [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 the Intune Device Compliance Script for Windows10 with Id {$Id} and DisplayName {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).Clone() + $testResult = $true + + $ValuesToCheck.Remove('Id') | Out-Null + $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)" + + if ($testResult) + { + $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] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -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 + + try + { + #region resource generator code + $uri = if ([string]::IsNullOrEmpty($Filter)) { '/beta/deviceManagement/deviceComplianceScripts' } else { "/beta/deviceManagement/deviceComplianceScripts?`$filter=$Filter" } + [array]$getValue = (Invoke-MgGraphRequest ` + -Method GET ` + -Uri $uri ` + -ErrorAction Stop).value + #endregion + + $i = 1 + $dscContent = '' + if ($getValue.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($config in $getValue) + { + if ($null -ne $Global:M365DSCExportResourceInstancesCount) + { + $Global:M365DSCExportResourceInstancesCount++ + } + + $displayedKey = $config.Id + if (-not [String]::IsNullOrEmpty($config.displayName)) + { + $displayedKey = $config.displayName + } + Write-Host " |---[$i/$($getValue.Count)] $displayedKey" -NoNewline + $params = @{ + Id = $config.Id + DisplayName = $config.DisplayName + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + 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_IntuneDeviceComplianceScriptWindows10/MSFT_IntuneDeviceComplianceScriptWindows10.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/MSFT_IntuneDeviceComplianceScriptWindows10.schema.mof new file mode 100644 index 0000000000..bd27c0a468 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/MSFT_IntuneDeviceComplianceScriptWindows10.schema.mof @@ -0,0 +1,21 @@ +[ClassVersion("1.0.0.0"), FriendlyName("IntuneDeviceComplianceScriptWindows10")] +class MSFT_IntuneDeviceComplianceScriptWindows10 : OMI_BaseResource +{ + [Write, Description("Optional description for the device compliance script.")] String Description; + [Key, Description("Name of the device compliance script.")] String DisplayName; + [Write, Description("Indicate whether the script signature needs be checked.")] Boolean EnforceSignatureCheck; + [Write, Description("Publisher of the script.")] String Publisher; + [Write, Description("List of Scope Tag IDs for this PowerShellScript instance.")] String RoleScopeTagIds[]; + [Write, Description("A value indicating whether the PowerShell script should run as 32-bit")] Boolean RunAs32Bit; + [Write, Description("Indicates the type of execution context. Possible values are: system, user."), ValueMap{"system","user"}, Values{"system","user"}] String RunAsAccount; + [Write, Description("The script content in Base64.")] String DetectionScriptContent; + [Write, Description("The unique identifier for an entity. Read-only.")] String Id; + [Write, Description("Present ensures the policy exists, absent ensures it is removed."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Write, Description("Credentials of the 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("Secret of the Azure Active Directory tenant used for authentication."), EmbeddedInstance("MSFT_Credential")] String ApplicationSecret; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; + [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; + [Write, Description("Access token used for authentication.")] String AccessTokens[]; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/readme.md new file mode 100644 index 0000000000..1b3598bfcd --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/readme.md @@ -0,0 +1,6 @@ + +# IntuneDeviceComplianceScriptWindows10 + +## Description + +Intune Device Compliance Script for Windows10 diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/settings.json new file mode 100644 index 0000000000..dda8b8cc29 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneDeviceComplianceScriptWindows10/settings.json @@ -0,0 +1,16 @@ +{ + "resourceName": "IntuneDeviceComplianceScriptWindows10", + "description": "This resource configures an Intune Device Compliance Script for Windows10.", + "permissions": { + "graph": { + "delegated": { + "read": [], + "update": [] + }, + "application": { + "read": [], + "update": [] + } + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/1-Create.ps1 new file mode 100644 index 0000000000..d0a5b0f13f --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/1-Create.ps1 @@ -0,0 +1,40 @@ +<# +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 + { + IntuneDeviceComplianceScriptWindows10 'Example' + { + DisplayName = "custom"; + Ensure = "Present"; + EnforceSignatureCheck = $False; + Id = "00000000-0000-0000-0000-000000000000"; + RunAs32Bit = $True; + RunAsAccount = "system"; + DetectionScriptContent = "Write-Output `$true"; + Publisher = ""; + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/2-Update.ps1 new file mode 100644 index 0000000000..a0f64d10a0 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/2-Update.ps1 @@ -0,0 +1,40 @@ +<# +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 + { + IntuneDeviceComplianceScriptWindows10 'Example' + { + DisplayName = "custom"; + Ensure = "Present"; + EnforceSignatureCheck = $False; + Id = "00000000-0000-0000-0000-000000000000"; + RunAs32Bit = $False; # Updated property + RunAsAccount = "system"; + DetectionScriptContent = "Write-Output `$true"; + Publisher = ""; + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/3-Remove.ps1 new file mode 100644 index 0000000000..3d3ac06708 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneDeviceComplianceScriptWindows10/3-Remove.ps1 @@ -0,0 +1,35 @@ +<# +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 + { + IntuneDeviceComplianceScriptWindows10 'Example' + { + DisplayName = "custom"; + Ensure = "Absent"; + Id = "00000000-0000-0000-0000-000000000000"; + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceComplianceScriptWindows10.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceComplianceScriptWindows10.Tests.ps1 new file mode 100644 index 0000000000..f47fb0d5dc --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneDeviceComplianceScriptWindows10.Tests.ps1 @@ -0,0 +1,249 @@ +[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 "IntuneDeviceComplianceScriptWindows10" -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 Get-PSSession -MockWith { + } + + Mock -CommandName Remove-PSSession -MockWith { + } + + Mock -CommandName Invoke-MgGraphRequest -MockWith { + } + + Mock -CommandName New-M365DSCConnection -MockWith { + return "Credentials" + } + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + $Script:exportedInstances =$null + $Script:ExportMode = $false + + $allComplianceScripts = @{ + value = @( + @{ + Description = "FakeStringValue" + DisplayName = "DeviceComplianceScript" + EnforceSignatureCheck = $true + Id = "12345-12345-12345-12345-12345" + Publisher = "FakeStringValue" + RoleScopeTagIds = @("FakeStringValue") + RunAsAccount = "system" + RunAs32Bit = $true + DetectionScriptContent = "" + } + ) + } + + $specificComplianceScript = @{ + Description = "FakeStringValue" + DisplayName = "DeviceComplianceScript" + EnforceSignatureCheck = $true + Id = "12345-12345-12345-12345-12345" + Publisher = "FakeStringValue" + RoleScopeTagIds = @("FakeStringValue") + RunAsAccount = "system" + RunAs32Bit = $true + DetectionScriptContent = "V3JpdGUtT3V0cHV0ICR0cnVl" + } + + $noComplianceScripts = @{ + value = @() + } + } + # Test contexts + Context -Name "The IntuneDeviceComplianceScriptWindows10 should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "DeviceComplianceScript" + EnforceSignatureCheck = $True + Id = "12345-12345-12345-12345-12345" + Publisher = "FakeStringValue" + RoleScopeTagIds = @("FakeStringValue") + RunAs32Bit = $True + RunAsAccount = "system" + DetectionScriptContent = "Write-Output `$true" + Ensure = "Present" + Credential = $Credential + } + + Mock -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'GET' -and $Uri -eq '/beta/deviceManagement/deviceComplianceScripts' } -MockWith { + return $noComplianceScripts + } + } + + It 'Should return Values 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 Intune Device Compliance Script for Windows10 from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'POST' } -Exactly 1 + } + } + + Context -Name "The IntuneDeviceComplianceScriptWindows10 exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "DeviceComplianceScript" + EnforceSignatureCheck = $True + Id = "12345-12345-12345-12345-12345" + Publisher = "FakeStringValue" + RoleScopeTagIds = @("FakeStringValue") + RunAs32Bit = $True + RunAsAccount = "system" + DetectionScriptContent = "Write-Output `$true" + Ensure = "Absent" + Credential = $Credential + } + + Mock -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'GET' -and $Uri -eq '/beta/deviceManagement/deviceComplianceScripts' } -MockWith { + return $allComplianceScripts + } + + Mock -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'GET' -and $Uri -eq '/beta/deviceManagement/deviceComplianceScripts/12345-12345-12345-12345-12345' } -MockWith { + return $specificComplianceScript + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should Remove the group from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'DELETE' } -Exactly 1 + } + } + Context -Name "The IntuneDeviceComplianceScriptWindows10 Exists and Values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "DeviceComplianceScript" + EnforceSignatureCheck = $True + Id = "12345-12345-12345-12345-12345" + Publisher = "FakeStringValue" + RoleScopeTagIds = @("FakeStringValue") + RunAs32Bit = $True + RunAsAccount = "system" + DetectionScriptContent = "Write-Output `$true" + Ensure = "Present" + Credential = $Credential + } + + Mock -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'GET' -and $Uri -eq '/beta/deviceManagement/deviceComplianceScripts' } -MockWith { + return $allComplianceScripts + } + + Mock -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'GET' -and $Uri -eq '/beta/deviceManagement/deviceComplianceScripts/12345-12345-12345-12345-12345' } -MockWith { + return $specificComplianceScript + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The IntuneDeviceComplianceScriptWindows10 exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Description = "FakeStringValue" + DisplayName = "DeviceComplianceScript" + EnforceSignatureCheck = $True + Id = "12345-12345-12345-12345-12345" + Publisher = "FakeStringValue" + RoleScopeTagIds = @("FakeStringValue") + RunAs32Bit = $False #Drift + RunAsAccount = "system" + DetectionScriptContent = "Write-Output `$false" #Drift + Ensure = "Present" + Credential = $Credential + } + + Mock -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'GET' -and $Uri -eq '/beta/deviceManagement/deviceComplianceScripts' } -MockWith { + return $allComplianceScripts + } + + Mock -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'GET' -and $Uri -eq '/beta/deviceManagement/deviceComplianceScripts/12345-12345-12345-12345-12345' } -MockWith { + return $specificComplianceScript + } + } + + It 'Should return Values 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 call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'PATCH' } -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'GET' -and $Uri -eq '/beta/deviceManagement/deviceComplianceScripts' } -MockWith { + return $allComplianceScripts + } + + Mock -CommandName Invoke-MgGraphRequest -ParameterFilter { $Method -eq 'GET' -and $Uri -eq '/beta/deviceManagement/deviceComplianceScripts/12345-12345-12345-12345-12345' } -MockWith { + return $specificComplianceScript + } + } + + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope