From b34050ea33d46133ea139e83721e989d10f9be2d Mon Sep 17 00:00:00 2001 From: dannyKBjj Date: Wed, 18 Dec 2024 14:16:59 +0000 Subject: [PATCH 1/2] IntuneVPNConfigurationPolicyAndroidWork Added support for Android Work VPN profiles. --- CHANGELOG.md | 2 + ...tuneVPNConfigurationPolicyAndroidWork.psm1 | 1075 +++++++++++++++++ ...NConfigurationPolicyAndroidWork.schema.mof | 74 ++ .../readme.md | 6 + .../settings.json | 44 + .../1-Create.ps1 | 47 + .../2-Update.ps1 | 47 + .../3-Remove.ps1 | 34 + ...PNConfigurationPolicyAndroidWork.Tests.ps1 | 477 ++++++++ 9 files changed, 1806 insertions(+) create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/MSFT_IntuneVPNConfigurationPolicyAndroidWork.psm1 create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/MSFT_IntuneVPNConfigurationPolicyAndroidWork.schema.mof create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/readme.md create mode 100644 Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/settings.json create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/1-Create.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/2-Update.ps1 create mode 100644 Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/3-Remove.ps1 create mode 100644 Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneVPNConfigurationPolicyAndroidWork.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index ec62e49028..373473095e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ * AADApplication * Added support for Oauth2PermissionScopes. * Fixes comparison issue for permissions. +* IntuneVPNConfigurationPolicyAndroidWork + * Initial release * TeamsMeetingPolicy * Adds support for additional Copilot setting value. * FIXES [#5573](https://github.com/microsoft/Microsoft365DSC/issues/5573) diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/MSFT_IntuneVPNConfigurationPolicyAndroidWork.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/MSFT_IntuneVPNConfigurationPolicyAndroidWork.psm1 new file mode 100644 index 0000000000..e379d26cb9 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/MSFT_IntuneVPNConfigurationPolicyAndroidWork.psm1 @@ -0,0 +1,1075 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [ValidateSet('certificate', 'usernameAndPassword', 'sharedSecret', 'derivedCredential', 'azureAD')] + [System.String] + $authenticationMethod, + + [Parameter()] + [System.String] + $connectionName, + + [Parameter()] + [System.String] + $role, + + [Parameter()] + [System.String] + $realm, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $servers, + + [Parameter()] + [ValidateSet('ciscoAnyConnect', 'pulseSecure', 'f5EdgeClient', 'dellSonicWallMobileConnect', 'checkPointCapsuleVpn', 'citrix', 'microsoftTunnel', 'netMotionMobility', 'microsoftProtect')] + [System.String] + $connectionType, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $proxyServer, + + [Parameter()] + [System.string[]] + $targetedPackageIds, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $targetedMobileApps, + + [Parameter()] + [System.Boolean] + $alwaysOn, + + [Parameter()] + [System.Boolean] + $alwaysOnLockdown, + + [Parameter()] + [System.string] + $microsoftTunnelSiteId, + + [Parameter()] + [System.string[]] + $proxyExclusionList, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $customData, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $customKeyValueData, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #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 + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + } + catch + { + Write-Verbose -Message 'Connection to the workload failed.' + } + + #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 + { + if (-not [string]::IsNullOrWhiteSpace($id)) + { + $getValue = Get-MgBetaDeviceManagementDeviceConfiguration -DeviceConfigurationId $id -ErrorAction SilentlyContinue + } + + #region resource generator code + if ($null -eq $getValue) + { + $getValue = Get-MgBetaDeviceManagementDeviceConfiguration -All -Filter "DisplayName eq '$Displayname'" -ErrorAction SilentlyContinue | Where-Object ` + -FilterScript { ` + $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.androidWorkProfileVpnConfiguration' ` + } + } + #endregion + + if ($null -eq $getValue) + { + Write-Verbose -Message "No Intune VPN Policy for Android Work with Id {$id} was found" + return $nullResult + } + + $Id = $getValue.Id + + Write-Verbose -Message "An Intune VPN Policy for Android Work with id {$id} and DisplayName {$DisplayName} was found" + + $complexServers = @() + foreach ($currentservers in $getValue.AdditionalProperties.servers) + { + $myservers = @{} + $myservers.Add('address', $currentservers.address) + $myservers.Add('description', $currentservers.description) + $myservers.Add('isDefaultServer', $currentservers.isDefaultServer) + if ($myservers.values.Where({$null -ne $_}).count -gt 0) + { + $complexServers += $myservers + } + } + + $complexProxyServers = @() + foreach ($currentservers in $getValue.AdditionalProperties.proxyServer) + { + $myservers = @{} + $myservers.Add('automaticConfigurationScriptUrl', $currentservers.automaticConfigurationScriptUrl) + $myservers.Add('address', $currentservers.address) + $myservers.Add('port', $currentservers.port) + if ($myservers.values.Where({$null -ne $_}).count -gt 0) + { + $complexProxyServers += $myservers + } + } + + $complexCustomData = @() + foreach ($value in $getValue.AdditionalProperties.customData) + { + $myCustomdata = @{} + $myCustomdata.Add('key', $value.key) + $myCustomdata.Add('value', $value.value) + if ($myCustomdata.values.Where({$null -ne $_}).count -gt 0) + { + $complexCustomData += $myCustomdata + } + } + + $complexCustomKeyValueData = @() + foreach ($value in $getValue.AdditionalProperties.customKeyValueData) + { + $myCVdata = @{} + $myCVdata.Add('name', $value.name) + $myCVdata.Add('value', $value.value) + if ($myCVdata.values.Where({$null -ne $_}).count -gt 0) + { + $complexCustomKeyValueData += $myCVdata + } + } + + $complexTargetedMobileApps = @() + foreach ($value in $getValue.AdditionalProperties.targetedMobileApps) + { + $myTMAdata = @{} + $myTMAdata.Add('name', $value.name) + $myTMAdata.Add('publisher', $value.publisher) + $myTMAdata.Add('appStoreUrl', $value.appStoreUrl) + $myTMAdata.Add('appId', $value.appId) + if ($myTMAdata.values.Where({$null -ne $_}).count -gt 0) + { + $complexTargetedMobileApps += $myTMAdata + } + } + + $results = @{ + #region resource generator code + Id = $getValue.Id + Description = $getValue.Description + DisplayName = $getValue.DisplayName + authenticationMethod = $getValue.AdditionalProperties.authenticationMethod + connectionName = $getValue.AdditionalProperties.connectionName + role = $getValue.AdditionalProperties.role + realm = $getValue.AdditionalProperties.realm + servers = $complexServers + connectionType = $getValue.AdditionalProperties.connectionType + proxyServer = $complexProxyServers + targetedPackageIds = $getValue.AdditionalProperties.targetedPackageIds + targetedMobileApps = $complexTargetedMobileApps + alwaysOn = $getValue.AdditionalProperties.alwaysOn + alwaysOnLockdown = $getValue.AdditionalProperties.alwaysOnLockdown + microsoftTunnelSiteId = $getValue.AdditionalProperties.microsoftTunnelSiteId + proxyExclusionList = $getValue.AdditionalProperties.proxyExclusionList + customData = $complexCustomData + customKeyValueData = $complexCustomKeyValueData + Ensure = 'Present' + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + ApplicationSecret = $ApplicationSecret + CertificateThumbprint = $CertificateThumbprint + Managedidentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $assignmentsValues = Get-MgBetaDeviceManagementDeviceConfigurationAssignment -DeviceConfigurationId $Results.Id + $assignmentResult = @() + if ($assignmentsValues.Count -gt 0) + { + $assignmentResult += ConvertFrom-IntunePolicyAssignment ` + -IncludeDeviceFilter:$true ` + -Assignments ($assignmentsValues) + } + $results.Add('Assignments', $assignmentResult) + + 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] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [ValidateSet('certificate', 'usernameAndPassword', 'sharedSecret', 'derivedCredential', 'azureAD')] + [System.String] + $authenticationMethod, + + [Parameter()] + [System.String] + $connectionName, + + [Parameter()] + [System.String] + $role, + + [Parameter()] + [System.String] + $realm, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $servers, + + [Parameter()] + [ValidateSet('ciscoAnyConnect', 'pulseSecure', 'f5EdgeClient', 'dellSonicWallMobileConnect', 'checkPointCapsuleVpn', 'citrix', 'microsoftTunnel', 'netMotionMobility', 'microsoftProtect')] + [System.String] + $connectionType, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $proxyServer, + + [Parameter()] + [System.string[]] + $targetedPackageIds, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $targetedMobileApps, + + [Parameter()] + [System.Boolean] + $alwaysOn, + + [Parameter()] + [System.Boolean] + $alwaysOnLockdown, + + [Parameter()] + [System.string] + $microsoftTunnelSiteId, + + [Parameter()] + [System.string[]] + $proxyExclusionList, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $customData, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $customKeyValueData, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #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 + ) + + try + { + $ConnectionMode = New-M365DSCConnection -Workload 'MicrosoftGraph' ` + -InboundParameters $PSBoundParameters + } + catch + { + Write-Verbose -Message $_ + } + + #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 + + #proxy and server values need converting before new- / update- cmdlets will accept parameters + #creating hashtables now for use later in both present/present and present/absent blocks + $allTargetValues = Convert-M365DscHashtableToString -Hashtable $BoundParameters + + if ($allTargetValues -match '\bproxyServer=\(\{([^\)]+)\}\)') + { + $proxyBlock = $matches[1] + } + + $proxyHashtable = @{} + $proxyBlock -split ";" | ForEach-Object { + if ($_ -match '^(.*?)=(.*)$') { + $key = $matches[1].Trim() + $value = $matches[2].Trim() + $proxyHashtable[$key] = $value + } + } + + if ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Absent') + { + Write-Verbose -Message "Creating {$DisplayName}" + $BoundParameters.Remove('Assignments') | Out-Null + $CreateParameters = ([Hashtable]$BoundParameters).clone() + $CreateParameters = Rename-M365DSCCimInstanceParameter -Properties $CreateParameters + $AdditionalProperties = Get-M365DSCAdditionalProperties -Properties ($CreateParameters) + + foreach ($key in $AdditionalProperties.keys) + { + if ($key -ne '@odata.type') + { + $keyName = $key.substring(0, 1).ToUpper() + $key.substring(1, $key.length - 1) + $CreateParameters.remove($keyName) + } + } + + $CreateParameters.Remove('Id') | Out-Null + + foreach ($key in ($CreateParameters.clone()).Keys) + { + if ($CreateParameters[$key].getType().Fullname -like '*CimInstance*') + { + $CreateParameters[$key] = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $CreateParameters[$key] + } + } + + if ($AdditionalProperties.proxyServer) + { + $AdditionalProperties.Remove('proxyServer') #this is not in a format Update-MgBetaDeviceManagementDeviceConfiguration will accept + $AdditionalProperties.add('proxyServer',$proxyHashtable) #replaced with the hashtable we created earlier + } + + $CreateParameters.add('AdditionalProperties', $AdditionalProperties) + + #region resource generator code + $policy = New-MgBetaDeviceManagementDeviceConfiguration @CreateParameters + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + + if ($policy.id) + { + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $policy.id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/deviceConfigurations' + } + #endregion + } + elseif ($Ensure -eq 'Present' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Updating {$DisplayName}" + + $BoundParameters.Remove('Assignments') | Out-Null + $UpdateParameters = ([Hashtable]$BoundParameters).clone() + $UpdateParameters = Rename-M365DSCCimInstanceParameter -Properties $UpdateParameters + $AdditionalProperties = Get-M365DSCAdditionalProperties -Properties ($UpdateParameters) + + foreach ($key in $AdditionalProperties.keys) + { + if ($key -ne '@odata.type') + { + $keyName = $key.substring(0, 1).ToUpper() + $key.substring(1, $key.length - 1) + $UpdateParameters.remove($keyName) + } + } + + $UpdateParameters.Remove('Id') | Out-Null + + foreach ($key in ($UpdateParameters.clone()).Keys) + { + if ($UpdateParameters[$key].getType().Fullname -like '*CimInstance*') + { + $UpdateParameters[$key] = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $UpdateParameters[$key] + } + } + + if ($AdditionalProperties.proxyServer) + { + $AdditionalProperties.Remove('proxyServer') #this is not in a format Update-MgBetaDeviceManagementDeviceConfiguration will accept + $AdditionalProperties.add('proxyServer',$proxyHashtable) #replaced with the hashtable we created earlier + } + + if ($AdditionalProperties) + { + #add the additional properties to the updateparameters + $UpdateParameters.add('AdditionalProperties', $AdditionalProperties) + } + + #region resource generator code + Update-MgBetaDeviceManagementDeviceConfiguration @UpdateParameters ` + -DeviceConfigurationId $currentInstance.Id + $assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:$true -Assignments $Assignments + Update-DeviceConfigurationPolicyAssignment -DeviceConfigurationPolicyId $currentInstance.id ` + -Targets $assignmentsHash ` + -Repository 'deviceManagement/deviceConfigurations' + #endregion + } + elseif ($Ensure -eq 'Absent' -and $currentInstance.Ensure -eq 'Present') + { + Write-Verbose -Message "Removing {$DisplayName}" + #region resource generator code + Remove-MgBetaDeviceManagementDeviceConfiguration -DeviceConfigurationId $currentInstance.Id + #endregion + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + #region resource generator code + [Parameter()] + [System.String] + $Id, + + [Parameter(Mandatory = $true)] + [System.String] + $DisplayName, + + [Parameter()] + [System.String] + $Description, + + [Parameter()] + [ValidateSet('certificate', 'usernameAndPassword', 'sharedSecret', 'derivedCredential', 'azureAD')] + [System.String] + $authenticationMethod, + + [Parameter()] + [System.String] + $connectionName, + + [Parameter()] + [System.String] + $role, + + [Parameter()] + [System.String] + $realm, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $servers, + + [Parameter()] + [ValidateSet('ciscoAnyConnect', 'pulseSecure', 'f5EdgeClient', 'dellSonicWallMobileConnect', 'checkPointCapsuleVpn', 'citrix', 'microsoftTunnel', 'netMotionMobility', 'microsoftProtect')] + [System.String] + $connectionType, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $proxyServer, + + [Parameter()] + [System.string[]] + $targetedPackageIds, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $targetedMobileApps, + + [Parameter()] + [System.Boolean] + $alwaysOn, + + [Parameter()] + [System.Boolean] + $alwaysOnLockdown, + + [Parameter()] + [System.string] + $microsoftTunnelSiteId, + + [Parameter()] + [System.string[]] + $proxyExclusionList, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $customData, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $customKeyValueData, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Assignments, + #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 {$id}" + + $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 ($source.GetType().Name -like '*CimInstance*') + { + $testResult = Compare-M365DSCComplexObject ` + -Source ($source) ` + -Target ($target) + + if (-not $testResult) { break } + + $ValuesToCheck.Remove($key) | Out-Null + } + } + + $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)" + + #Convert any DateTime to String + foreach ($key in $ValuesToCheck.Keys) + { + if (($null -ne $CurrentValues[$key]) ` + -and ($CurrentValues[$key].getType().Name -eq 'DateTime')) + { + $CurrentValues[$key] = $CurrentValues[$key].toString() + } + } + + 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 + [array]$getValue = Get-MgBetaDeviceManagementDeviceConfiguration -Filter $Filter -All ` + -ErrorAction Stop | Where-Object ` + -FilterScript { ` + $_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.androidWorkProfileVpnConfiguration' ` + } + #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++ + } + + Write-Host " |---[$i/$($getValue.Count)] $($config.DisplayName)" -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 + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + if ($Results.Assignments) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject $Results.Assignments -CIMInstanceName DeviceManagementConfigurationPolicyAssignments + if ($complexTypeStringResult) + { + $Results.Assignments = $complexTypeStringResult + } + else + { + $Results.Remove('Assignments') | Out-Null + } + } + + if ($null -ne $Results.servers) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.servers ` + -CIMInstanceName 'MicrosoftGraphvpnServer' #MSFT_MicrosoftGraphVpnServer + if (-Not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.servers = $complexTypeStringResult + } + else + { + $Results.Remove('servers') | Out-Null + } + } + + if ($null -ne $Results.proxyServer) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.proxyServer ` + -CIMInstanceName 'MSFT_MicrosoftvpnProxyServer' + if (-Not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.proxyServer = $complexTypeStringResult + } + else + { + $Results.Remove('proxyServer') | Out-Null + } + } + + if ($null -ne $Results.customData) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.customData ` + -CIMInstanceName 'MSFT_CustomData' + if (-Not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.customData = $complexTypeStringResult + } + else + { + $Results.Remove('customData') | Out-Null + } + } + + if ($null -ne $Results.customKeyValueData) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.customKeyValueData ` + -CIMInstanceName 'MSFT_customKeyValueData' + if (-Not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.customKeyValueData = $complexTypeStringResult + } + else + { + $Results.Remove('customKeyValueData') | Out-Null + } + } + + if ($null -ne $Results.targetedMobileApps) + { + $complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ` + -ComplexObject $Results.targetedMobileApps ` + -CIMInstanceName 'MSFT_targetedMobileApps' + if (-Not [String]::IsNullOrWhiteSpace($complexTypeStringResult)) + { + $Results.targetedMobileApps = $complexTypeStringResult + } + else + { + $Results.Remove('targetedMobileApps') | Out-Null + } + } + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + if ($Results.servers) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "servers" -isCIMArray:$True + } + + if ($Results.proxyServer) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "proxyServer" -isCIMArray:$True + } + + if ($Results.customData) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "customData" -isCIMArray:$True + } + + if ($Results.customKeyValueData) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "customKeyValueData" -isCIMArray:$True + } + + if ($Results.targetedMobileApps) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName "targetedMobileApps" -isCIMArray:$True + } + + if ($Results.Assignments) + { + $isCIMArray = $false + if ($Results.Assignments.getType().Fullname -like '*[[\]]') + { + $isCIMArray = $true + } + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock -ParameterName 'Assignments' -IsCIMArray:$isCIMArray + } + + $dscContent += $currentDSCBlock + Save-M365DSCPartialExport -Content $currentDSCBlock ` + -FileName $Global:PartialExportFileName + $i++ + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + return $dscContent + } + catch + { + if ($_.Exception -like '*401*' -or $_.ErrorDetails.Message -like "*`"ErrorCode`":`"Forbidden`"*" -or ` + $_.Exception -like "*Request not applicable to target tenant*") + { + Write-Host "`r`n $($Global:M365DSCEmojiYellowCircle) The current tenant is not registered for Intune." + } + else + { + Write-Host $Global:M365DSCEmojiRedX + + New-M365DSCLogEntry -Message 'Error during Export:' ` + -Exception $_ ` + -Source $($MyInvocation.MyCommand.Source) ` + -TenantId $TenantId ` + -Credential $Credential + } + + return '' + } +} + +function Get-M365DSCAdditionalProperties +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = 'true')] + [System.Collections.Hashtable] + $Properties + ) + + $additionalProperties = @( + 'authenticationMethod' + 'connectionName' + 'role' + 'realm' + 'servers' + 'connectionType' + 'proxyServer' + 'targetedPackageIds' + 'targetedMobileApps' + 'alwaysOn' + 'alwaysOnLockdown' + 'microsoftTunnelSiteId' + 'proxyExclusionList' + 'customData' + 'customKeyValueData' + ) + + $results = @{'@odata.type' = '#microsoft.graph.androidWorkProfileVpnConfiguration' } + $cloneProperties = $Properties.clone() + foreach ($property in $cloneProperties.Keys) + { + if ($property -in ($additionalProperties) ) + { + $propertyName = $property[0].ToString().ToLower() + $property.Substring(1, $property.Length - 1) + if ($properties.$property -and $properties.$property.getType().FullName -like '*CIMInstance*') + { + if ($properties.$property.getType().FullName -like '*[[\]]') + { + $array = @() + foreach ($item in $properties.$property) + { + $array += Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $item + } + $propertyValue = $array + } + else + { + $propertyValue = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $properties.$property + } + + } + else + { + $propertyValue = $properties.$property + } + + $results.Add($propertyName, $propertyValue) + } + } + if ($results.Count -eq 1) + { + return $null + } + return $results +} + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/MSFT_IntuneVPNConfigurationPolicyAndroidWork.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/MSFT_IntuneVPNConfigurationPolicyAndroidWork.schema.mof new file mode 100644 index 0000000000..8a444d28c5 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/MSFT_IntuneVPNConfigurationPolicyAndroidWork.schema.mof @@ -0,0 +1,74 @@ +[ClassVersion("1.0.0.0")] +class MSFT_DeviceManagementConfigurationPolicyAssignments +{ + [Write, Description("The type of the target assignment."), ValueMap{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}, Values{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}] String dataType; + [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 Id of the filter for the target assignment.")] String deviceAndAppManagementAssignmentFilterId; + [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("The collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId; +}; +[ClassVersion("1.0.0")] +class MSFT_MicrosoftGraphVpnServer +{ + [Write, Description("Address (IP address, FQDN or URL)")] String address; + [Write, Description("Description.")] String description; + [Write, Description("Default server.")] Boolean isDefaultServer; +}; +[ClassVersion("1.0.0")] +class MSFT_MicrosoftvpnProxyServer +{ + [Write, Description("Proxy's automatic configuration script url.")] String automaticConfigurationScriptUrl; + [Write, Description("Address.")] String address; + [Write, Description("Port. Valid values 0 to 65535.")] uint32 port; +}; +[ClassVersion("1.0.0")] +class MSFT_targetedMobileApps +{ + [Write, Description("The application name.")] String name; + [Write, Description("The publisher of the application.")] String publisher; + [Write, Description("The Store URL of the application.")] String appStoreUrl; + [Write, Description("The application or bundle identifier of the application.")] String appId; +}; +class MSFT_CustomData +{ + [Write, Description("Key for the custom data entry.")] String key; + [Write, Description("Value for the custom data entry.")] String value; +}; +class MSFT_customKeyValueData +{ + [Write, Description("Name for the custom data entry.")] String name; + [Write, Description("Value for the custom data entry.")] String value; +}; + +[ClassVersion("1.0.0.0"), FriendlyName("IntuneVPNConfigurationPolicyAndroidWork")] +class MSFT_IntuneVPNConfigurationPolicyAndroidWork : OMI_BaseResource +{ + [Write, Description("Id of the Intune policy.")] String Id; + [Key, Description("Display name of the Intune policy.")] String DisplayName; + [Write, Description("Description of the Intune policy.")] String Description; + [Write, Description("Authentication method. Inherited from vpnConfiguration. Possible values are: certificate, usernameAndPassword, sharedSecret, derivedCredential, azureAD."), ValueMap{"certificate", "usernameAndPassword", "sharedSecret", "derivedCredential", "azureAD"}, Values{"certificate", "usernameAndPassword", "sharedSecret", "derivedCredential", "azureAD"}] String authenticationMethod; + [Write, Description("Connection name displayed to the user.")] String connectionName; + [Write, Description("Role when connection type is set to Pulse Secure. Inherited from vpnConfiguration.")] String role; + [Write, Description("Realm when connection type is set to Pulse Secure. Inherited from vpnConfiguration.")] String realm; + [Write, Description("VPN Server on the network. Make sure end users can access this network location."), EmbeddedInstance("MSFT_MicrosoftGraphvpnServer")] String servers[]; + [Write, Description("Connection type. Possible values are: ciscoAnyConnect, pulseSecure, f5EdgeClient, dellSonicWallMobileConnect, checkPointCapsuleVpn, citrix, microsoftTunnel, netMotionMobility, microsoftProtect."), ValueMap{"ciscoAnyConnect", "pulseSecure", "f5EdgeClient", "dellSonicWallMobileConnect", "checkPointCapsuleVpn", "citrix", "microsoftTunnel", "netMotionMobility", "microsoftProtect"}, Values{"ciscoAnyConnect", "pulseSecure", "f5EdgeClient", "dellSonicWallMobileConnect", "checkPointCapsuleVpn", "citrix", "microsoftTunnel", "netMotionMobility", "microsoftProtect"}] String connectionType; + [Write, Description("Proxy Server."), EmbeddedInstance("MSFT_MicrosoftvpnProxyServer")] String proxyServer[]; + [Write, Description("Targeted App package IDs.")] String targetedPackageIds[]; + [Write, Description("Targeted mobile apps. This collection can contain a maximum of 500 elements."),EmbeddedInstance("MSFT_targetedMobileApps")] String targetedMobileApps[]; + [Write, Description("Whether or not to enable always-on VPN connection.")] Boolean alwaysOn; + [Write, Description("If always-on VPN connection is enabled, whether or not to lock network traffic when that VPN is disconnected.")] Boolean alwaysOnLockdown; + [Write, Description("Microsoft Tunnel site ID.")] String microsoftTunnelSiteId; + [Write, Description("List of hosts to exclude using the proxy on connections for. These hosts can use wildcards such as *.example.com.")] String proxyExclusionList[]; + [Write, Description("Custom data to define key/value pairs specific to a VPN provider. This collection can contain a maximum of 25 elements."), EmbeddedInstance("MSFT_customData")] String customData[]; + [Write, Description("Custom data to define key/value pairs specific to a VPN provider. This collection can contain a maximum of 25 elements."), EmbeddedInstance("MSFT_customKeyValueData")] String customKeyValueData[]; + [Write, Description("Represents the assignment to the Intune policy."), EmbeddedInstance("MSFT_DeviceManagementConfigurationPolicyAssignments")] String Assignments[]; + [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 Intune 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_IntuneVPNConfigurationPolicyAndroidWork/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/readme.md new file mode 100644 index 0000000000..2e578f56d2 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/readme.md @@ -0,0 +1,6 @@ + +# IntuneVPNConfigurationPolicyAndroidWork + +## Description + +This resource configures an Intune VPN Configuration Policy for Android Work Devices. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/settings.json new file mode 100644 index 0000000000..fe10607d46 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_IntuneVPNConfigurationPolicyAndroidWork/settings.json @@ -0,0 +1,44 @@ +{ + "resourceName": "IntuneVPNConfigurationPolicyAndroidWork", + "description": "This resource configures an Intune VPN Configuration Policy for Android Work Devices.", + "permissions": { + "graph": { + "delegated": { + "read": [ + { + "name": "Group.Read.All" + }, + { + "name": "DeviceManagementConfiguration.Read.All" + } + ], + "update": [ + { + "name": "Group.Read.All" + }, + { + "name": "DeviceManagementConfiguration.ReadWrite.All" + } + ] + }, + "application": { + "read": [ + { + "name": "Group.Read.All" + }, + { + "name": "DeviceManagementConfiguration.Read.All" + } + ], + "update": [ + { + "name": "Group.Read.All" + }, + { + "name": "DeviceManagementConfiguration.ReadWrite.All" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/1-Create.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/1-Create.ps1 new file mode 100644 index 0000000000..099cdbd634 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/1-Create.ps1 @@ -0,0 +1,47 @@ +<# +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 + { + IntuneVPNConfigurationPolicyAndroidWork "IntuneVPNConfigurationPolicyAndroidWork-Example" + { + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + Assignments = @(); + authenticationMethod = "usernameAndPassword"; + connectionName = "IntuneVPNConfigurationPolicyAndroidWork ConnectionName"; + connectionType = "ciscoAnyConnect"; + Description = "IntuneVPNConfigurationPolicyAndroidWork Description"; + DisplayName = "IntuneVPNConfigurationPolicyAndroidWork DisplayName"; + Ensure = "Present"; + Id = "12345678-1234-abcd-1234-12345678ABCD"; + servers = @( + MSFT_MicrosoftGraphvpnServer{ + isDefaultServer = $True + description = 'server' + address = 'vpn.test.com' + } + ); + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/2-Update.ps1 new file mode 100644 index 0000000000..4e66cf122f --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/2-Update.ps1 @@ -0,0 +1,47 @@ +<# +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 + { + IntuneVPNConfigurationPolicyAndroidWork "IntuneVPNConfigurationPolicyAndroidWork-Example" + { + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + Assignments = @(); + authenticationMethod = "usernameAndPassword"; + connectionName = "IntuneVPNConfigurationPolicyAndroidWork ConnectionName"; + connectionType = "ciscoAnyConnect"; + Description = "IntuneVPNConfigurationPolicyAndroidWork Description"; + DisplayName = "IntuneVPNConfigurationPolicyAndroidWork DisplayName"; + Ensure = "Present"; + Id = "12345678-1234-abcd-1234-12345678ABCD"; + servers = @( + MSFT_MicrosoftGraphvpnServer{ + isDefaultServer = $True + description = 'server' + address = 'vpn.newAddress.com' #updated VPN address + } + ); + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/3-Remove.ps1 b/Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/3-Remove.ps1 new file mode 100644 index 0000000000..8592b46318 --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/IntuneVPNConfigurationPolicyAndroidWork/3-Remove.ps1 @@ -0,0 +1,34 @@ +<# +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 + { + IntuneVPNConfigurationPolicyAndroidWork "IntuneVPNConfigurationPolicyAndroidWork-Example" + { + ApplicationId = $ApplicationId; + TenantId = $TenantId; + CertificateThumbprint = $CertificateThumbprint; + DisplayName = "IntuneVPNConfigurationPolicyAndroidWork DisplayName"; + Ensure = "Absent"; + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneVPNConfigurationPolicyAndroidWork.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneVPNConfigurationPolicyAndroidWork.Tests.ps1 new file mode 100644 index 0000000000..bd59156355 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.IntuneVPNConfigurationPolicyAndroidWork.Tests.ps1 @@ -0,0 +1,477 @@ +[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 'IntuneVPNConfigurationPolicyAndroidWork' -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).ToString()) -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 Update-MgBetaDeviceManagementDeviceConfiguration -MockWith { + } + + Mock -CommandName New-MgBetaDeviceManagementDeviceConfiguration -MockWith { + } + + Mock -CommandName Remove-MgBetaDeviceManagementDeviceConfiguration -MockWith { + } + + Mock -CommandName Get-MgBetaDeviceManagementDeviceCompliancePolicyAssignment -MockWith { + + return @() + } + Mock -CommandName Update-DeviceConfigurationPolicyAssignment -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 "When the IntuneVPNConfigurationPolicyAndroidWork doesn't already exist" -Fixture { + BeforeAll { + $testParams = @{ + connectionName = 'FakeStringValue' + connectionType = 'ciscoAnyConnect' + Description = 'FakeStringValue' + DisplayName = 'FakeStringValue' + Id = 'FakeStringValue' + proxyServer = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_MicrosoftvpnProxyServer ` + -Property @{ + port = 80 + automaticConfigurationScriptUrl = 'https://www.test.com' + address = 'proxy.test.com' + } -ClientOnly) + ) + servers = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_MicrosoftGraphvpnServer ` + -Property @{ + isDefaultServer = $True + description = 'server' + address = 'vpn.test.com' + } -ClientOnly) + ) + customData = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_CustomData ` + -Property @{ + key = 'FakeStringValue' + value = 'FakeStringValue' + } -ClientOnly) + ) + customKeyValueData = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_CustomData ` + -Property @{ + name = 'FakeStringValue' + value = 'FakeStringValue' + } -ClientOnly) + ) + targetedMobileApps = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_targetedMobileApps ` + -Property @{ + name = 'FakeStringValue' + publisher = 'FakeStringValue' + appStoreUrl = 'FakeStringValue' + appId = 'FakeStringValue' + } -ClientOnly) + ) + Ensure = 'Present' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceManagementDeviceConfiguration -MockWith { + return $null + } + } + + It 'Should return absent from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Absent' + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should create the IntuneVPNConfigurationPolicyAndroidWork from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName 'New-MgBetaDeviceManagementDeviceConfiguration' -Exactly 1 + } + } + + Context -Name 'When the IntuneVPNConfigurationPolicyAndroidWork already exists and is NOT in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + DisplayName = 'FakeStringValue' + Description = 'FakeStringValue' + Id = 'FakeStringValue' + authenticationMethod = 'usernameAndPassword' + connectionName = 'FakeStringValue' + connectionType = 'ciscoAnyConnect' + proxyServer = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_MicrosoftvpnProxyServer ` + -Property @{ + port = 80 + automaticConfigurationScriptUrl = 'https://www.test.com' + address = 'proxy.test.com' + } -ClientOnly) + ) + servers = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_MicrosoftGraphvpnServer ` + -Property @{ + isDefaultServer = $True + description = 'server' + address = 'vpn.test.com' + } -ClientOnly) + ) + customData = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_CustomData ` + -Property @{ + key = 'FakeStringValue' + value = 'FakeStringValue' + } -ClientOnly) + ) + customKeyValueData = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_CustomData ` + -Property @{ + name = 'FakeStringValue' + value = 'FakeStringValue' + } -ClientOnly) + ) + targetedMobileApps = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_targetedMobileApps ` + -Property @{ + name = 'FakeStringValue' + publisher = 'FakeStringValue' + appStoreUrl = 'FakeStringValue' + appId = 'FakeStringValue' + } -ClientOnly) + ) + Ensure = 'Present' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceManagementDeviceConfiguration -MockWith { + return @{ + DisplayName = 'FakeStringValue' + Description = 'FakeStringValue' + Id = 'FakeStringValue' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.androidWorkProfileVpnConfiguration' + authenticationMethod = 'usernameAndPassword' + connectionName = 'FakeStringValue' + connectionType = 'ciscoAnyConnect' + customData = @( + @{ + key = 'FakeStringValue' + value = 'FakeStringValue' + } + ) + customKeyValueData = @( + @{ + name = 'FakeStringValue' + value = 'FakeStringValue' + } + ) + servers = @( + @{ + isDefaultServer = $True + description = 'server' + address = 'vpn.CHANGED.com' #changed value + } + ) + proxyServer = @( + @{ + port = 80 + automaticConfigurationScriptUrl = 'https://www.test.com' + address = 'proxy.test.com' + } + ) + targetedMobileApps = @( + @{ + name = 'FakeStringValue' + publisher = 'FakeStringValue' + appStoreUrl = 'FakeStringValue' + appId = 'FakeStringValue' + } + ) + } + } + } + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' #-Displayname 'FakeStringValue').Ensure | Should -Be 'Present' # + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should update the IntuneVPNConfigurationPolicyAndroidWork from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Update-MgBetaDeviceManagementDeviceConfiguration -Exactly 1 + + } + } + + Context -Name 'When the policy already exists and IS in the Desired State' -Fixture { + BeforeAll { + $testParams = @{ + DisplayName = 'FakeStringValue' + Description = 'FakeStringValue' + authenticationMethod = 'usernameAndPassword' + connectionName = 'FakeStringValue' + connectionType = 'ciscoAnyConnect' + proxyServer = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_MicrosoftvpnProxyServer ` + -Property @{ + port = 80 + automaticConfigurationScriptUrl = 'https://www.test.com' + address = 'proxy.test.com' + } -ClientOnly) + ) + servers = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_MicrosoftGraphvpnServer ` + -Property @{ + isDefaultServer = $True + description = 'server' + address = 'vpn.test.com' + } -ClientOnly) + ) + customData = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_CustomData ` + -Property @{ + key = 'FakeStringValue' + value = 'FakeStringValue' + } -ClientOnly) + ) + customKeyValueData = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_CustomData ` + -Property @{ + name = 'FakeStringValue' + value = 'FakeStringValue' + } -ClientOnly) + ) + targetedMobileApps = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_targetedMobileApps ` + -Property @{ + name = 'FakeStringValue' + publisher = 'FakeStringValue' + appStoreUrl = 'FakeStringValue' + appId = 'FakeStringValue' + } -ClientOnly) + ) + Ensure = 'Present' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceManagementDeviceConfiguration -MockWith { + return @{ + DisplayName = 'FakeStringValue' + Description = 'FakeStringValue' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.androidWorkProfileVpnConfiguration' + authenticationMethod = 'usernameAndPassword' + connectionName = 'FakeStringValue' + connectionType = 'ciscoAnyConnect' + proxyServer = @( + @{ + port = 80 + automaticConfigurationScriptUrl = 'https://www.test.com' + address = 'proxy.test.com' + } + ) + servers = @( + @{ + isDefaultServer = $True + description = 'server' + address = 'vpn.test.com' + } + ) + customData = @( + @{ + key = 'FakeStringValue' + value = 'FakeStringValue' + } + ) + customKeyValueData = @( + @{ + name = 'FakeStringValue' + value = 'FakeStringValue' + } + ) + targetedMobileApps = @( + @{ + name = 'FakeStringValue' + publisher = 'FakeStringValue' + appStoreUrl = 'FakeStringValue' + appId = 'FakeStringValue' + } + ) + } + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name 'When the policy exists and it SHOULD NOT' -Fixture { + BeforeAll { + $testParams = @{ + DisplayName = 'FakeStringValue' + Description = 'FakeStringValue' + authenticationMethod = 'usernameAndPassword' + connectionName = 'FakeStringValue' + connectionType = 'ciscoAnyConnect' + proxyServer = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_MicrosoftvpnProxyServer ` + -Property @{ + port = 80 + automaticConfigurationScriptUrl = 'https://www.test.com' + address = 'proxy.test.com' + } -ClientOnly) + ) + servers = [CimInstance[]]@( + (New-CimInstance ` + -ClassName MSFT_MicrosoftGraphvpnServer ` + -Property @{ + isDefaultServer = $True + description = 'server' + address = 'vpn.test.com' + } -ClientOnly) + ) + Ensure = 'Absent' + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceManagementDeviceConfiguration -MockWith { + return @{ + DisplayName = 'FakeStringValue' + Description = 'FakeStringValue' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.androidWorkProfileVpnConfiguration' + authenticationMethod = 'usernameAndPassword' + connectionName = 'FakeStringValue' + connectionType = 'ciscoAnyConnect' + proxyServer = @( + @{ + port = 80 + automaticConfigurationScriptUrl = 'https://www.test.com' + address = 'proxy.test.com' + } + ) + servers = @( + @{ + isDefaultServer = $True + description = 'server' + address = 'vpn.test.com' + } + ) + } + } + } + } + + It 'Should return Present from the Get method' { + (Get-TargetResource @testParams).Ensure | Should -Be 'Present' + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should remove the IntuneVPNConfigurationPolicyAndroidWork from the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaDeviceManagementDeviceConfiguration -Exactly 1 + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential + } + + Mock -CommandName Get-MgBetaDeviceManagementDeviceConfiguration -MockWith { + return @{ + DisplayName = 'FakeStringValue' + Description = 'FakeStringValue' + AdditionalProperties = @{ + '@odata.type' = '#microsoft.graph.androidWorkProfileVpnConfiguration' + authenticationMethod = 'usernameAndPassword' + connectionName = 'FakeStringValue' + connectionType = 'ciscoAnyConnect' + proxyServer = @( + @{ + port = 80 + automaticConfigurationScriptUrl = 'https://www.test.com' + address = 'proxy.test.com' + } + ) + servers = @( + @{ + isDefaultServer = $True + description = 'server' + address = 'vpn.test.com' + } + ) + } + } + } + } + + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope \ No newline at end of file From 06e3252dc21b5f7f5f228d7f4bef5ce24cdfeef6 Mon Sep 17 00:00:00 2001 From: Yorick Kuijs Date: Tue, 14 Jan 2025 11:18:37 +0100 Subject: [PATCH 2/2] Update CHANGELOG.md with new resource entries --- CHANGELOG.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c171a545f..1b107f47be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,17 @@ # UNRELEASED +* AADGroupEligibilitySchedule + * New resource for Privileged Identity Management (PIM) for Groups +* EXOSmtpDaneInbound + * initial release +* IntuneVPNConfigurationPolicyAndroidWork + * Initial release + # 1.25.108.1 * AADAuthenticationRequirement * Changed Export logic to extract instances from all users. -* AADGroupEligibilitySchedule - * New resource for Privileged Identity Management (PIM) for Groups * AADOrganizationCertificateBasedAuthConfiguration * Fixed the primary key of the resource. FIXES [#5523](https://github.com/microsoft/Microsoft365DSC/issues/5523) @@ -15,10 +20,6 @@ * Fixed error when extracting an entry with a deleted principal. * DefenderDeviceAuthenticatedScanDefinition * Fixed the Data Type export. -* EXOSmtpDaneInbound - * initial release -* IntuneVPNConfigurationPolicyAndroidWork - * Initial release * MISC * Added check to `New-M365DSCReportFromConfiguration` to make sure Windows Remoting is enabled, which is required to convert the DSC config.