diff --git a/CHANGELOG.md b/CHANGELOG.md index e3a64fe812..0b479d5275 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ * Migrate to new Settings Catalog cmdlets. * IntuneMobileAppsMacOSLobApp * Initial release +* IntuneMobileAppsWindowsOfficeSuiteApp + * Initial release * IntuneSecurityBaselineMicrosoft365AppsForEnterprise * Initial release * IntuneSecurityBaselineMicrosoftEdge diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsMacOSLobApp/MSFT_IntuneMobileAppsMacOSLobApp.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsMacOSLobApp/MSFT_IntuneMobileAppsMacOSLobApp.psm1 index f0e7cd245e..739c2c80d7 100644 --- a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsMacOSLobApp/MSFT_IntuneMobileAppsMacOSLobApp.psm1 +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsMacOSLobApp/MSFT_IntuneMobileAppsMacOSLobApp.psm1 @@ -450,7 +450,7 @@ function Set-TargetResource throw "Mobile App Category with DisplayName $($category.DisplayName) not found." } - Invoke-MgBetaGraphRequest -Uri "/beta/deviceAppManagement/mobileApps/$($app.Id)/categories/`$ref" -Method 'POST' -Body @{ + Invoke-MgGraphRequest -Uri "/beta/deviceAppManagement/mobileApps/$($app.Id)/categories/`$ref" -Method 'POST' -Body @{ '@odata.id' = "https://graph.microsoft.com/beta/deviceAppManagement/mobileAppCategories/$($currentCategory.Id)" } } diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp.psm1 new file mode 100644 index 0000000000..f10634ed10 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp.psm1 @@ -0,0 +1,1002 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region Intune resource parameters + + [Parameter()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Boolean] + $IsFeatured, + + [Parameter()] + [System.String] + $PrivacyInformationUrl, + + [Parameter()] + [System.String] + $InformationUrl, + + [Parameter()] + [System.String] + $Notes, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.Boolean] + $AutoAcceptEula, + + [Parameter()] + [System.String[]] + [ValidateSet('O365ProPlusRetail', 'O365BusinessRetail', 'VisioProRetail', 'ProjectProRetail')] + $ProductIds, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $ExcludedApps, + + [Parameter()] + [System.Boolean] + $UseSharedComputerActivation, + + [Parameter()] + [System.String] + [ValidateSet('None', 'Current', 'Deferred', 'FirstReleaseCurrent', 'FirstReleaseDeferred', 'MonthlyEnterprise')] + $UpdateChannel, + + [Parameter()] + [System.String] + [ValidateSet('NotConfigured', 'OfficeOpenXMLFormat', 'OfficeOpenDocumentFormat', 'UnknownFutureValue')] + $OfficeSuiteAppDefaultFileFormat, + + [Parameter()] + [System.String] + [ValidateSet('None', 'X86', 'X64', 'Arm', 'Neutral', 'Arm64')] + $OfficePlatformArchitecture, + + [Parameter()] + [System.String[]] + $LocalesToInstall, + + [Parameter()] + [System.String] + [ValidateSet('None', 'Full')] + $InstallProgressDisplayLevel, + + [Parameter()] + [System.Boolean] + $ShouldUninstallOlderVersionsOfOffice, + + [Parameter()] + [System.String] + $TargetVersion, + + [Parameter()] + [System.String] + $UpdateVersion, + + [Parameter()] + [System.Byte[]] + $OfficeConfigurationXml, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Categories, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + # [Parameter()] + # [Microsoft.Management.Infrastructure.CimInstance] + # $LargeIcon, + + #endregion + + [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.Management.Automation.PSCredential] + $ApplicationSecret, + + [Parameter()] + [Switch] + $ManagedIdentity, + + [Parameter()] + [System.String[]] + $AccessTokens + ) + + New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters | Out-Null + + #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' + try + { + $instance = Get-MgBetaDeviceAppManagementMobileApp -MobileAppId $Id ` + -ExpandProperty "categories" ` + -ErrorAction SilentlyContinue + + if ($null -eq $instance) + { + Write-Verbose -Message "Could not find an Intune Windows Office Suite App with Id {$Id}." + + if (-not [System.String]::IsNullOrEmpty($DisplayName)) + { + $instance = Get-MgBetaDeviceAppManagementMobileApp ` + -Filter "(isof('microsoft.graph.officeSuiteApp') and displayName eq '$DisplayName')" ` + -ErrorAction SilentlyContinue + } + + if ($null -ne $instance) + { + $instance = Get-MgBetaDeviceAppManagementMobileApp -MobileAppId $instance.Id ` + -ExpandProperty "categories" ` + -ErrorAction SilentlyContinue + $Id = $instance.Id + } + } + + if ($null -eq $instance) + { + Write-Verbose -Message "Could not find an Intune Windows Office Suite App with DisplayName {$DisplayName} was found." + return $nullResult + } + + Write-Verbose "An Intune Windows Office Suite App with Id {$Id} and DisplayName {$DisplayName} was found." + + #region complex types + $complexCategories = @() + foreach ($category in $instance.Categories) + { + $myCategory = @{} + $myCategory.Add('Id', $category.id) + $myCategory.Add('DisplayName', $category.displayName) + $complexCategories += $myCategory + } + + $complexExcludedApps = @{} + if ($null -ne $instance.AdditionalProperties.excludedApps) + { + $instance.AdditionalProperties.excludedApps.GetEnumerator() | Foreach-Object { + $complexExcludedApps.Add($_.Key, $_.Value) + } + } + + # $complexLargeIcon = @{} + # if ($null -ne $instance.LargeIcon.Value) + # { + # $complexLargeIcon.Add('Value', [System.Convert]::ToBase64String($instance.LargeIcon.Value)) + # $complexLargeIcon.Add('Type', $instance.LargeIcon.Type) + # } + + $results = @{ + Id = $instance.Id + DisplayName = $instance.DisplayName + Description = $instance.Description + IsFeatured = $instance.IsFeatured + PrivacyInformationUrl = $instance.PrivacyInformationUrl + InformationUrl = $instance.InformationUrl + Notes = $instance.Notes + RoleScopeTagIds = $instance.RoleScopeTagIds + AutoAcceptEula = $instance.AdditionalProperties.autoAcceptEula + ProductIds = $instance.AdditionalProperties.productIds + UseSharedComputerActivation = $instance.AdditionalProperties.useSharedComputerActivation + UpdateChannel = $instance.AdditionalProperties.updateChannel + OfficeSuiteAppDefaultFileFormat = $instance.AdditionalProperties.officeSuiteAppDefaultFileFormat + OfficePlatformArchitecture = $instance.AdditionalProperties.officePlatformArchitecture + LocalesToInstall = $instance.AdditionalProperties.localesToInstall + InstallProgressDisplayLevel = $instance.AdditionalProperties.installProgressDisplayLevel + ShouldUninstallOlderVersionsOfOffice = $instance.AdditionalProperties.shouldUninstallOlderVersionsOfOffice + TargetVersion = $instance.AdditionalProperties.targetVersion + UpdateVersion = $instance.AdditionalProperties.updateVersion + OfficeConfigurationXml = $instance.AdditionalProperties.officeConfigurationXml + # LargeIcon = $complexLargeIcon + ExcludedApps = $complexExcludedApps + Categories = $complexCategories + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + ApplicationSecret = $ApplicationSecret + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + #Assignments + $resultAssignments = @() + $appAssignments = Get-MgBetaDeviceAppManagementMobileAppAssignment -MobileAppId $instance.Id + if ($null -ne $appAssignments -and $appAssignments.count -gt 0) + { + $convertedAssignments = ConvertFrom-IntuneMobileAppAssignment ` + -IncludeDeviceFilter:$true ` + -Assignments ($appAssignments) + + # Filter out 'source' from the assignment objects + foreach ($assignment in $convertedAssignments) { + if ($assignment.ContainsKey('source')) { + $assignment.Remove('source') + } + } + + $resultAssignments += $convertedAssignments + } + $results.Add('Assignments', $resultAssignments) + return [System.Collections.Hashtable] $results + } + catch + { + Write-Verbose -Message $_ + New-M365DSCLogEntry -Message 'Error retrieving data:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + + return $nullResult + } +} + +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + #region Intune resource parameters + + [Parameter()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Boolean] + $IsFeatured, + + [Parameter()] + [System.String] + $PrivacyInformationUrl, + + [Parameter()] + [System.String] + $InformationUrl, + + [Parameter()] + [System.String] + $Notes, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.Boolean] + $AutoAcceptEula, + + [Parameter()] + [System.String[]] + [ValidateSet('O365ProPlusRetail', 'O365BusinessRetail', 'VisioProRetail', 'ProjectProRetail')] + $ProductIds, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $ExcludedApps, + + [Parameter()] + [System.Boolean] + $UseSharedComputerActivation, + + [Parameter()] + [System.String] + [ValidateSet('None', 'Current', 'Deferred', 'FirstReleaseCurrent', 'FirstReleaseDeferred', 'MonthlyEnterprise')] + $UpdateChannel, + + [Parameter()] + [System.String] + [ValidateSet('NotConfigured', 'OfficeOpenXMLFormat', 'OfficeOpenDocumentFormat', 'UnknownFutureValue')] + $OfficeSuiteAppDefaultFileFormat, + + [Parameter()] + [System.String] + [ValidateSet('None', 'X86', 'X64', 'Arm', 'Neutral', 'Arm64')] + $OfficePlatformArchitecture, + + [Parameter()] + [System.String[]] + $LocalesToInstall, + + [Parameter()] + [System.String] + [ValidateSet('None', 'Full')] + $InstallProgressDisplayLevel, + + [Parameter()] + [System.Boolean] + $ShouldUninstallOlderVersionsOfOffice, + + [Parameter()] + [System.String] + $TargetVersion, + + [Parameter()] + [System.String] + $UpdateVersion, + + [Parameter()] + [System.Byte[]] + $OfficeConfigurationXml, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Categories, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + # [Parameter()] + # [Microsoft.Management.Infrastructure.CimInstance] + # $LargeIcon, + + #endregion + + [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.Management.Automation.PSCredential] + $ApplicationSecret, + + [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 + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating an Intune Windows Office Suite App with DisplayName {$DisplayName}" + $BoundParameters.Remove('Assignments') | Out-Null + + $CreateParameters = ([Hashtable]$BoundParameters).Clone() + $CreateParameters = Rename-M365DSCCimInstanceParameter -Properties $CreateParameters + $CreateParameters.Remove('Id') | Out-Null + $CreateParameters.Remove('Categories') | Out-Null + $CreateParameters.Add('Publisher', 'Microsoft') + $CreateParameters.Add('Developer', 'Microsoft') + $CreateParameters.Add('Owner', 'Microsoft') + + foreach ($key in ($CreateParameters.Clone()).Keys) + { + if ($null -ne $CreateParameters.$key -and $CreateParameters.$key.GetType().Name -like '*CimInstance*') + { + $CreateParameters.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $CreateParameters.$key + } + } + + $CreateParameters.Add('@odata.type', '#microsoft.graph.officeSuiteApp') + $app = New-MgBetaDeviceAppManagementMobileApp -BodyParameter $CreateParameters + + foreach ($category in $Categories) + { + if ($category.Id) + { + $currentCategory = Get-MgBetaDeviceAppManagementMobileAppCategory -MobileAppCategoryId $category.Id + } + else + { + $currentCategory = Get-MgBetaDeviceAppManagementMobileAppCategory -Filter "displayName eq '$($category.DisplayName)'" + } + + if ($null -eq $currentCategory) + { + throw "Mobile App Category with DisplayName $($category.DisplayName) not found." + } + + Invoke-MgGraphRequest -Uri "/beta/deviceAppManagement/mobileApps/$($app.Id)/categories/`$ref" -Method 'POST' -Body @{ + '@odata.id' = "https://graph.microsoft.com/beta/deviceAppManagement/mobileAppCategories/$($currentCategory.Id)" + } + } + + #Assignments + if ($app.Id) + { + $assignmentsHash = ConvertTo-IntuneMobileAppAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceAppManagementPolicyAssignment -AppManagementPolicyId $app.Id ` + -Assignments $assignmentsHash + } + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Host "Updating the Intune Windows Office Suite App with DisplayName {$DisplayName}" + $BoundParameters.Remove('Assignments') | Out-Null + + $UpdateParameters = ([Hashtable]$BoundParameters).Clone() + $UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $UpdateParameters + $UpdateParameters.Remove('Id') | Out-Null + $UpdateParameters.Remove('Categories') | Out-Null + $UpdateParameters.Remove('OfficePlatformArchitecture') | Out-Null + + foreach ($key in ($UpdateParameters.Clone()).Keys) + { + if ($null -ne $UpdateParameters.$key -and $UpdateParameters.$key.GetType().Name -like '*CimInstance*') + { + $UpdateParameters.$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters.$key + } + } + + $UpdateParameters.Add('@odata.type', '#microsoft.graph.officeSuiteApp') + Update-MgBetaDeviceAppManagementMobileApp -MobileAppId $currentInstance.Id -BodyParameter $UpdateParameters + + [array]$referenceObject = if ($null -ne $currentInstance.Categories.DisplayName) { $currentInstance.Categories.DisplayName } else { ,@() } + [array]$differenceObject = if ($null -ne $Categories.DisplayName) { $Categories.DisplayName } else { ,@() } + $delta = Compare-Object -ReferenceObject $referenceObject -DifferenceObject $differenceObject -PassThru + foreach ($diff in $delta) + { + if ($diff.SideIndicator -eq '=>') + { + $category = $Categories | Where-Object { $_.DisplayName -eq $diff } + if ($category.Id) + { + $currentCategory = Get-MgBetaDeviceAppManagementMobileAppCategory -MobileAppCategoryId $category.Id + } + else + { + $currentCategory = Get-MgBetaDeviceAppManagementMobileAppCategory -Filter "displayName eq '$($category.DisplayName)'" + } + + if ($null -eq $currentCategory) + { + throw "Mobile App Category with DisplayName $($category.DisplayName) not found." + } + + Invoke-MgGraphRequest -Uri "/beta/deviceAppManagement/mobileApps/$($currentInstance.Id)/categories/`$ref" -Method 'POST' -Body @{ + '@odata.id' = "https://graph.microsoft.com/beta/deviceAppManagement/mobileAppCategories/$($currentCategory.Id)" + } + } + else + { + $category = $currentInstance.Categories | Where-Object { $_.DisplayName -eq $diff } + Invoke-MgGraphRequest -Uri "/beta/deviceAppManagement/mobileApps/$($currentInstance.Id)/categories/$($category.Id)/`$ref" -Method 'DELETE' + } + } + + #Assignments + $assignmentsHash = ConvertTo-IntuneMobileAppAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceAppManagementPolicyAssignment -AppManagementPolicyId $currentInstance.Id ` + -Assignments $assignmentsHash + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Host "Remove the Intune Windows Office Suite App with Id {$($currentInstance.Id)}" + Remove-MgBetaDeviceAppManagementMobileApp -MobileAppId $currentInstance.Id -Confirm:$false + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region Intune resource parameters + + [Parameter()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [System.Boolean] + $IsFeatured, + + [Parameter()] + [System.String] + $PrivacyInformationUrl, + + [Parameter()] + [System.String] + $InformationUrl, + + [Parameter()] + [System.String] + $Notes, + + [Parameter()] + [System.String[]] + $RoleScopeTagIds, + + [Parameter()] + [System.Boolean] + $AutoAcceptEula, + + [Parameter()] + [System.String[]] + [ValidateSet('O365ProPlusRetail', 'O365BusinessRetail', 'VisioProRetail', 'ProjectProRetail')] + $ProductIds, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance] + $ExcludedApps, + + [Parameter()] + [System.Boolean] + $UseSharedComputerActivation, + + [Parameter()] + [System.String] + [ValidateSet('None', 'Current', 'Deferred', 'FirstReleaseCurrent', 'FirstReleaseDeferred', 'MonthlyEnterprise')] + $UpdateChannel, + + [Parameter()] + [System.String] + [ValidateSet('NotConfigured', 'OfficeOpenXMLFormat', 'OfficeOpenDocumentFormat', 'UnknownFutureValue')] + $OfficeSuiteAppDefaultFileFormat, + + [Parameter()] + [System.String] + [ValidateSet('None', 'X86', 'X64', 'Arm', 'Neutral', 'Arm64')] + $OfficePlatformArchitecture, + + [Parameter()] + [System.String[]] + $LocalesToInstall, + + [Parameter()] + [System.String] + [ValidateSet('None', 'Full')] + $InstallProgressDisplayLevel, + + [Parameter()] + [System.Boolean] + $ShouldUninstallOlderVersionsOfOffice, + + [Parameter()] + [System.String] + $TargetVersion, + + [Parameter()] + [System.String] + $UpdateVersion, + + [Parameter()] + [System.Byte[]] + $OfficeConfigurationXml, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Categories, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + + # [Parameter()] + # [Microsoft.Management.Infrastructure.CimInstance] + # $LargeIcon, + + #endregion + + [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.Management.Automation.PSCredential] + $ApplicationSecret, + + [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 Windows Suite App with Id {$Id} and DisplayName {$DisplayName}" + + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).Clone() + + if ($CurrentValues.Ensure -ne $Ensure) + { + Write-Verbose -Message "Test-TargetResource returned $false" + return $false + } + $testResult = $true + + #Compare Cim instances + foreach ($key in $PSBoundParameters.Keys) + { + $source = $PSBoundParameters.$key + $target = $CurrentValues.$key + if ($null -ne $source -and $source.GetType().Name -like '*CimInstance*') + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-not $testResult) + { + break + } + + $ValuesToCheck.Remove($key) | Out-Null + } + } + + # Prevent screen from filling up with the LargeIcon value + # Comparison will already be done because it's a CimInstance + # $CurrentValues.Remove('LargeIcon') | Out-Null + # $PSBoundParameters.Remove('LargeIcon') | Out-Null + + $ValuesToCheck.Remove('Id') | Out-Null + $ValuesToCheck.Remove('OfficePlatformArchitecture') | Out-Null # Cannot be changed after creation + $ValuesToCheck = Remove-M365DSCAuthenticationParameter -BoundParameters $ValuesToCheck + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + 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.String] + $CertificateThumbprint, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ApplicationSecret, + + [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 + { + $Script:ExportMode = $true + [array] $Script:getInstances = Get-MgBetaDeviceAppManagementMobileApp ` + -Filter "isof('microsoft.graph.officeSuiteApp')" ` + -ErrorAction Stop + + $i = 1 + $dscContent = '' + if ($Script:getInstances.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + + foreach ($config in $Script:getInstances) + { + if ($null -ne $Global:M365DSCExportResourceInstancesCount) + { + $Global:M365DSCExportResourceInstancesCount++ + } + + $displayedKey = $config.Id + Write-Host " |---[$i/$($Script:getInstances.Count)] $displayedKey" -NoNewline + + $params = @{ + Id = $config.Id + DisplayName = $config.DisplayName + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + ApplicationSecret = $ApplicationSecret + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + #region complex types + if ($null -ne $Results.Categories) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.Categories ` + -CIMInstanceName 'DeviceManagementMobileAppCategory' + + if (-not [System.String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.Categories = $complexTypeStringResult + } + else + { + $Results.Remove('Categories') | Out-Null + } + } + + if ($null -ne $Results.ExcludedApps) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.ExcludedApps ` + -CIMInstanceName 'DeviceManagementMobileAppExcludedApp' + + if (-not [System.String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.ExcludedApps = $complexTypeStringResult + } + else + { + $Results.Remove('ExcludedApps') | Out-Null + } + } + + # if ($null -ne $Results.LargeIcon) + # { + # $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + # -ComplexObject $Results.LargeIcon ` + # -CIMInstanceName 'DeviceManagementMimeContent' + + # if (-not [System.String]::IsNullOrWhiteSpace($complexTypeStringResult)) + # { + # $Results.LargeIcon = $complexTypeStringResult + # } + # else + # { + # $Results.Remove('LargeIcon') | Out-Null + # } + # } + + if ($null -ne $Results.Assignments) + { + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.Assignments ` + -CIMInstanceName DeviceManagementMobileAppAssignment + + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + } + #endregion complex types + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + #region complex types + if ($null -ne $Results.Categories) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Categories' -IsCIMArray:$true + } + + if ($null -ne $Results.ExcludedApps) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'ExcludedApps' -IsCIMArray:$false + } + + # if ($null -ne $Results.LargeIcon) + # { + # $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'LargeIcon' -IsCIMArray:$false + # } + + if ($null -ne $Results.Assignments) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Assignments' -IsCIMArray:$true + } + #endregion complex types + + $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_IntuneMobileAppsWindowsOfficeSuiteApp/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp.schema.mof new file mode 100644 index 0000000000..9d07d216db --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp.schema.mof @@ -0,0 +1,78 @@ +class MSFT_DeviceManagementMobileAppAssignment +{ + [Write, Description("The type of the target assignment."), ValueMap{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget", "#microsoft.graph.mobileAppAssignment"}, Values{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget", "#microsoft.graph.mobileAppAssignment"}] String dataType; + [Write, Description("The Id of the filter for the target assignment.")] String deviceAndAppManagementAssignmentFilterId; + [Write, Description("The type of filter of the target assignment i.e. Exclude or Include. Possible values are: none, include, exclude."), ValueMap{"none", "include", "exclude"}, Values{"none", "include", "exclude"}] String deviceAndAppManagementAssignmentFilterType; + [Write, Description("The group Id that is the target of the assignment.")] String groupId; + [Write, Description("The group Display Name that is the target of the assignment.")] String groupDisplayName; + [Write, Description("Possible values for the install intent chosen by the admin."), ValueMap{"available", "required", "uninstall", "availableWithoutEnrollment"}, Values{"available", "required", "uninstall", "availableWithoutEnrollment"}] String intent; +}; + +class MSFT_DeviceManagementMimeContent +{ + [Write, Description("Indicates the type of content mime.")] String Type; + [Write, Description("The Base64 encoded string content.")] String Value; +}; + +class MSFT_DeviceManagementMobileAppCategory +{ + [Key, Description("The name of the app category.")] String DisplayName; + [Write, Description("The unique identifier for an entity. Read-only.")] String Id; +}; + +class MSFT_DeviceManagementMobileAppExcludedApp +{ + [Write, Description("Specifies whether to exclude Microsoft Office Access from the installation.")] Boolean Access; + [Write, Description("Specifies whether to exclude Microsoft Search (Bing) as the default from the installation.")] Boolean Bing; + [Write, Description("Specifies whether to exclude Microsoft Office Excel from the installation.")] Boolean Excel; + [Write, Description("Specifies whether to exclude Microsoft Office OneDrive for Business (Groove) from the installation.")] Boolean Groove; + [Write, Description("Specifies whether to exclude Microsoft Office InfoPath from the installation.")] Boolean InfoPath; + [Write, Description("Specifies whether to exclude Microsoft Office Skype for Business (Lync) from the installation.")] Boolean Lync; + [Write, Description("Specifies whether to exclude Microsoft Office OneDrive from the installation.")] Boolean OneDrive; + [Write, Description("Specifies whether to exclude Microsoft Office OneNote from the installation.")] Boolean OneNote; + [Write, Description("Specifies whether to exclude Microsoft Office Outlook from the installation.")] Boolean Outlook; + [Write, Description("Specifies whether to exclude Microsoft Office PowerPoint from the installation.")] Boolean PowerPoint; + [Write, Description("Specifies whether to exclude Microsoft Office Publisher from the installation.")] Boolean Publisher; + [Write, Description("Specifies whether to exclude Microsoft Office SharePoint Designer from the installation.")] Boolean SharePointDesigner; + [Write, Description("Specifies whether to exclude Microsoft Office Teams from the installation.")] Boolean Teams; + [Write, Description("Specifies whether to exclude Microsoft Office Visio from the installation.")] Boolean Visio; + [Write, Description("Specifies whether to exclude Microsoft Office Word from the installation.")] Boolean Word; +}; + +[ClassVersion("1.0.0"), FriendlyName("IntuneMobileAppsWindowsOfficeSuiteApp")] +class MSFT_IntuneMobileAppsWindowsOfficeSuiteApp : OMI_BaseResource +{ + [Key, Description("The admin provided or imported title of the app. Inherited from mobileApp.")] String DisplayName; + [Write, Description("The unique identifier for an entity. Read-only. Inherited from mobileApp object.")] String Id; + + [Write, Description("The description of the app. Inherited from mobileApp.")] String Description; + [Write, Description("The value indicating whether the app is marked as featured by the admin. Inherited from mobileApp.")] Boolean IsFeatured; + [Write, Description("The privacy statement Url. Inherited from mobileApp.")] String PrivacyInformationUrl; + [Write, Description("The InformationUrl of the app. Inherited from mobileApp.")] String InformationUrl; + [Write, Description("Notes for the app. Inherited from mobileApp.")] String Notes; + [Write, Description("List of Scope Tag IDs for mobile app.")] String RoleScopeTagIds[]; + [Write, Description("Specifies if the EULA is accepted automatically on the end user's device.")] Boolean AutoAcceptEula; + [Write, Description("The Product IDs that represent the Office 365 Suite SKU, such as 'O365ProPlusRetail' or 'VisioProRetail'.")] String ProductIds[]; + [Write, Description("Indicates whether shared computer activation is used for Office installations.")] Boolean UseSharedComputerActivation; + [Write, Description("Specifies the update channel for the Office 365 app suite, such as 'Current' or 'Deferred'.")] String UpdateChannel; + [Write, Description("Specifies the default file format type for Office apps, such as 'OfficeOpenXMLFormat' or 'OfficeOpenDocumentFormat'.")] String OfficeSuiteAppDefaultFileFormat; + [Write, Description("The architecture of the Office installation (e.g., 'X86', 'X64', or 'Arm64'). Cannot be changed after creation.")] String OfficePlatformArchitecture; + [Write, Description("Specifies the locales to be installed when the Office 365 apps are deployed. Uses the standard RFC 5646 format (e.g., 'en-US', 'fr-FR').")] String LocalesToInstall[]; + [Write, Description("Specifies the display level of the installation progress for Office apps. Use 'Full' to display the installation UI, or 'None' for a silent installation.")] String InstallProgressDisplayLevel; + [Write, Description("Indicates whether older versions of Office should be uninstalled when deploying the Office 365 app suite.")] Boolean ShouldUninstallOlderVersionsOfOffice; + [Write, Description("The specific target version of the Office 365 app suite to be deployed.")] String TargetVersion; + [Write, Description("The update version in which the target version is available for the Office 365 app suite.")] String UpdateVersion; + [Write, Description("A base64-encoded XML configuration file that specifies Office ProPlus installation settings. Takes precedence over all other properties. When present, this XML file will be used to create the app.")] String OfficeConfigurationXml; + [Write, Description("The list of categories for this app."), EmbeddedInstance("MSFT_DeviceManagementMobileAppCategory")] String Categories[]; + [Write, Description("The list of assignments for this app."), EmbeddedInstance("MSFT_DeviceManagementMobileAppAssignment")] String Assignments[]; + [Write, Description("The property that represents the apps excluded from the selected Office 365 Product ID."), EmbeddedInstance("MSFT_DeviceManagementMobileAppExcludedApp")] String ExcludedApps; + + [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_IntuneMobileAppsWindowsOfficeSuiteApp/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/readme.md new file mode 100644 index 0000000000..f35ec06360 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/readme.md @@ -0,0 +1,6 @@ + +# IntuneMobileAppsWindowsOfficeSuiteApp + +## Description + +This resource configures an Intune mobile app of OfficeSuiteApp type for Windows devices. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/settings.json new file mode 100644 index 0000000000..a9bd04b5fa --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneMobileAppsWindowsOfficeSuiteApp/settings.json @@ -0,0 +1,32 @@ +{ + "resourceName": "IntuneMobileAppsWindowsOfficeSuiteApp", + "description": "This resource configures an Intune mobile app.", + "permissions": { + "graph": { + "delegated": { + "read": [ + { + "name": "DeviceManagementApps.Read.All" + } + ], + "update": [ + { + "name": "DeviceManagementApps.ReadWrite.All" + } + ] + }, + "application": { + "read": [ + { + "name": "DeviceManagementApps.Read.All" + } + ], + "update": [ + { + "name": "DeviceManagementApps.ReadWrite.All" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppsWindowsOfficeSuiteApp/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppsWindowsOfficeSuiteApp/1-Create.ps1 new file mode 100644 index 0000000000..1eb9c2d9fb --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppsWindowsOfficeSuiteApp/1-Create.ps1 @@ -0,0 +1,54 @@ +<# +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 + { + IntuneMobileAppsWindowsOfficeSuiteApp "IntuneMobileAppsWindowsOfficeSuiteApp-Microsoft 365 Apps for Windows 10 and later" + { + Id = "8e683524-4ec1-4813-bb3e-6256b2f293d" + Description = "Microsoft 365 Apps for Windows 10 and laterr" + DisplayName = "Microsoft 365 Apps for Windows 10 and later" + Ensure = "Present"; + InformationUrl = ""; + IsFeatured = $False; + Notes = "" + PrivacyInformationUrl = "" + RoleScopeTagIds = @() + Assignments = @( + MSFT_DeviceManagementMobileAppAssignment{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '42c02b60-f28c-4eef-b3e1-973184cc4a6c' + intent = 'required' + } + ); + Categories = @( + MSFT_DeviceManagementMobileAppCategory { + Id = '8e683524-4ec1-4813-bb3e-6256b2f293d8' + DisplayName = 'Productivity' + }); + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppsWindowsOfficeSuiteApp/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppsWindowsOfficeSuiteApp/2-Update.ps1 new file mode 100644 index 0000000000..1eb9c2d9fb --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppsWindowsOfficeSuiteApp/2-Update.ps1 @@ -0,0 +1,54 @@ +<# +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 + { + IntuneMobileAppsWindowsOfficeSuiteApp "IntuneMobileAppsWindowsOfficeSuiteApp-Microsoft 365 Apps for Windows 10 and later" + { + Id = "8e683524-4ec1-4813-bb3e-6256b2f293d" + Description = "Microsoft 365 Apps for Windows 10 and laterr" + DisplayName = "Microsoft 365 Apps for Windows 10 and later" + Ensure = "Present"; + InformationUrl = ""; + IsFeatured = $False; + Notes = "" + PrivacyInformationUrl = "" + RoleScopeTagIds = @() + Assignments = @( + MSFT_DeviceManagementMobileAppAssignment{ + deviceAndAppManagementAssignmentFilterType = 'none' + dataType = '#microsoft.graph.groupAssignmentTarget' + groupId = '42c02b60-f28c-4eef-b3e1-973184cc4a6c' + intent = 'required' + } + ); + Categories = @( + MSFT_DeviceManagementMobileAppCategory { + Id = '8e683524-4ec1-4813-bb3e-6256b2f293d8' + DisplayName = 'Productivity' + }); + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppsWindowsOfficeSuiteApp/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppsWindowsOfficeSuiteApp/3-Remove.ps1 new file mode 100644 index 0000000000..8b731ff4ac --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneMobileAppsWindowsOfficeSuiteApp/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 + { + IntuneMobileAppsWindowsOfficeSuiteApp "IntuneMobileAppsWindowsOfficeSuiteApp-Microsoft 365 Apps for Windows 10 and later" + { + Id = "8e683524-4ec1-4813-bb3e-6256b2f293d8"; + DisplayName = "Microsoft 365 Apps for Windows 10 and later"; + Ensure = "Absent"; + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneMobileAppsWindowsOfficeSuiteApp.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneMobileAppsWindowsOfficeSuiteApp.Tests.ps1 new file mode 100644 index 0000000000..ff169134f0 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneMobileAppsWindowsOfficeSuiteApp.Tests.ps1 @@ -0,0 +1,386 @@ +[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) + +$CurrentScriptPath = $PSCommandPath.Split('\') +$CurrentScriptName = $CurrentScriptPath[$CurrentScriptPath.Length -1] +$ResourceName = $CurrentScriptName.Split('.')[1] +$Global:DscHelper = New-M365DscUnitTestHelper -StubModule $CmdletModule ` + -DscResource $ResourceName -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 New-M365DSCConnection -MockWith { + return "Credentials" + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + } + Mock -CommandName New-MgBetaDeviceAppManagementMobileApp -MockWith { + } + Mock -CommandName Update-MgBetaDeviceAppManagementMobileApp -MockWith { + } + Mock -CommandName Remove-MgBetaDeviceAppManagementMobileApp -MockWith { + } + + Mock -CommandName Update-MgBetaDeviceAppManagementMobileAppAssignment -MockWith{} + + # Mock Write-Host to hide output during the tests + Mock -CommandName Write-Host -MockWith { + } + + $Script:exportedInstances =$null + $Script:ExportMode = $false + } + + # Test contexts + Context -Name "1. The instance should exist but it DOES NOT" -Fixture { + BeforeAll { + $testParams = @{ + Id = "8d027f94-0682-431e-97c1-827d1879fa79" + Categories = @() + Description = "Microsoft 365 Apps for Windows 10 and later" + DisplayName = "Microsoft 365 Apps for Windows 10 and later" + InformationUrl = "" + IsFeatured = $False + PrivacyInformationUrl = "" + ExcludedApps = (New-CimInstance -ClassName MSFT_DeviceManagementMobileAppExcludedApp -Property @{ + teams = $false + sharePointDesigner = $true + powerPoint = $false + outlook = $false + groove = $true + word = $false + lync = $true + oneNote = $false + oneDrive = $false + publisher = $false + bing = $false + visio = $false + access = $false + infoPath = $true + excel = $false + } -ClientOnly) + RoleScopeTagIds = @() + Notes = "" + Ensure = 'Present' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + return $null + } + } + + It '1.1 Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + It '1.2 Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + It '1.3 Should create a new instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName New-MgBetaDeviceAppManagementMobileApp -Exactly 1 + } + } + + Context -Name "2. The instance exists but it SHOULD NOT" -Fixture { + BeforeAll { + $testParams = @{ + Id = "ad027f94-0682-431e-97c1-827d1879fa79" + Categories = @() + Description = "Microsoft 365 Apps for Windows 10 and later" + DisplayName = "Microsoft 365 Apps for Windows 10 and later" + InformationUrl = "" + IsFeatured = $False + ExcludedApps = (New-CimInstance -ClassName MSFT_DeviceManagementMobileAppExcludedApp -Property @{ + teams = $false + sharePointDesigner = $true + powerPoint = $false + outlook = $false + groove = $true + word = $false + lync = $true + oneNote = $false + oneDrive = $false + publisher = $false + bing = $false + visio = $false + access = $false + infoPath = $true + excel = $false + } -ClientOnly) + Notes = "" + PrivacyInformationUrl = "" + RoleScopeTagIds = @() + Ensure = 'Absent' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + return @{ + Id = "ad027f94-0682-431e-97c1-827d1879fa79" + Categories = @() + Description = "Microsoft 365 Apps for Windows 10 and laterr" + DisplayName = "Microsoft 365 Apps for Windows 10 and later" + InformationUrl = "" + IsFeatured = $False + Notes = "" + PrivacyInformationUrl = "" + RoleScopeTagIds = @() + ExcludedApps = (New-CimInstance -ClassName MSFT_DeviceManagementMobileAppExcludedApp -Property @{ + teams = $false + sharePointDesigner = $true + powerPoint = $false + outlook = $false + groove = $true + word = $false + lync = $true + oneNote = $false + oneDrive = $false + publisher = $false + bing = $false + visio = $false + access = $false + infoPath = $true + excel = $false + } -ClientOnly) + Ensure = 'Present' + } + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppAssignment -MockWith{ + return $null + } + } + + It '2.1 Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + It '2.2 Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + It '2.3 Should remove the instance from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaDeviceAppManagementMobileApp -Exactly 1 + } + } + + Context -Name "3. The instance exists and values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Id = "8d027f94-0682-431e-97c1-827d1879fa79" + Categories = @() + Description = "Microsoft 365 Apps for Windows 10 and later" + DisplayName = "Microsoft 365 Apps for Windows 10 and later" + InformationUrl = "" + IsFeatured = $False + Notes = "" + PrivacyInformationUrl = "" + RoleScopeTagIds = @() + Ensure = 'Present' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + return @{ + Id = "8d027f94-0682-431e-97c1-827d1879fa79" + Categories = @() + Description = "Microsoft 365 Apps for Windows 10 and later" + DisplayName = "Microsoft 365 Apps for Windows 10 and later" + InformationUrl = "" + IsFeatured = $False + Notes = "" + PrivacyInformationUrl = "" + RoleScopeTagIds = @() + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.officeSuiteApp' + minimumSupportedOperatingSystem = @{ + v11_0 = $true + } + } + Ensure = 'Present' + } + } + + # Remove Assignments logic for now as we debug this part + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppAssignment -MockWith{ + return $null + } + } + + It '3.0 Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "4. The instance exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Id = "8d027f94-0682-431e-97c1-827d1879fa79" + Categories = @() + Description = "Microsoft 365 Apps for Windows 10 and later" + DisplayName = "Microsoft 365 Apps for Windows 10 and later" + InformationUrl = "" + IsFeatured = $False + ExcludedApps = (New-CimInstance -ClassName MSFT_DeviceManagementMobileAppExcludedApp -Property @{ + teams = $false + sharePointDesigner = $true + powerPoint = $false + outlook = $false + groove = $true + word = $false + lync = $true + oneNote = $false + oneDrive = $false + publisher = $false + bing = $false + visio = $false + access = $false + infoPath = $true + excel = $false + } -ClientOnly) + Notes = "" + PrivacyInformationUrl = "" + RoleScopeTagIds = @() + Ensure = 'Present' + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + return @{ + Id = "8d027f94-0682-431e-97c1-827d1879fa79" + Categories = @() + Description = "Microsoft 365 Apps for Windows 10 and later" + DisplayName = "Microsoft 365 Apps for Windows 10 and later drift" + InformationUrl = "" + IsFeatured = $False + Notes = "" + PrivacyInformationUrl = "" + ExcludedApps = (New-CimInstance -ClassName MSFT_DeviceManagementMobileAppExcludedApp -Property @{ + teams = $false + sharePointDesigner = $true + powerPoint = $false + outlook = $false + groove = $true + word = $false + lync = $true + oneNote = $false + oneDrive = $false + publisher = $false + bing = $false + visio = $false + access = $false + infoPath = $true + excel = $false + } -ClientOnly) + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.officeSuiteApp' + minimumSupportedOperatingSystem = @{ + v11_0 = $true + } + } + } + } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppAssignment -MockWith{ + return $null + } + } + + It '4.1 Should return Values from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + It '4.2 Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + It '4.3 Should call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgBetaDeviceAppManagementMobileApp -Exactly 1 + } + } + + Context -Name '5. ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaDeviceAppManagementMobileApp -MockWith { + return @{ + Id = "8d027f94-0682-431e-97c1-827d1879fa79" + Categories = @() + Description = "Microsoft 365 Apps for Windows 10 and later" + DisplayName = "Microsoft 365 Apps for Windows 10 and later drift" + InformationUrl = "" + IsFeatured = $False + Notes = "" + PrivacyInformationUrl = "" + RoleScopeTagIds = @() + ExcludedApps = (New-CimInstance -ClassName MSFT_DeviceManagementMobileAppExcludedApp -Property @{ + teams = $false + sharePointDesigner = $true + powerPoint = $false + outlook = $false + groove = $true + word = $false + lync = $true + oneNote = $false + oneDrive = $false + publisher = $false + bing = $false + visio = $false + access = $false + infoPath = $true + excel = $false + } -ClientOnly) + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.officeSuiteApp' + minimumSupportedOperatingSystem = @{ + v11_0 = $true + } + } + } + } + Mock -CommandName Get-MgBetaDeviceAppManagementMobileAppAssignment -MockWith{ + return $null + } + } + + It '5.0 Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope