diff --git a/CHANGELOG.md b/CHANGELOG.md index 231ce3150f..07be125484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,8 @@ * Fixed issue where duplicate names were not detected correctly. * AADNetworkAccessForwardingProfile * Initial release. +* AADNetworkAccessForwardingPolicy + * Initial release. * AADNetworkAccessSettingCrossTenantAccess * Initial release. * AADOrganizationCertificateBasedAuthConfiguration diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/MSFT_AADNetworkAccessForwardingPolicy.psm1 b/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/MSFT_AADNetworkAccessForwardingPolicy.psm1 new file mode 100644 index 0000000000..47acfe16dd --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/MSFT_AADNetworkAccessForwardingPolicy.psm1 @@ -0,0 +1,493 @@ +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $PolicyRules, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [Parameter()] + [System.String] + $CertificateThumbprint, + + [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 + try + { + if ($null -ne $Script:exportedInstances -and $Script:ExportMode) + { + $instance = $Script:exportedInstances | Where-Object -FilterScript {$_.Name -eq $Name} + } + else + { + $instance = Get-MgBetaNetworkAccessForwardingPolicy -Expand * -ErrorAction SilentlyContinue | Where-Object { $_.Name -eq $Name } + } + if ($null -eq $instance) + { + throw "Could not retrieve the Forwarding Policy with name: $Name" + } + + $complexPolicyRules = Get-MicrosoftGraphNetworkAccessForwardingPolicyRules -PolicyRules $instance.PolicyRules + + $results = @{ + Name = $instance.name + PolicyRules = $complexPolicyRules + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + 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 + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $PolicyRules, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [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 + + $setParameters = Remove-M365DSCAuthenticationParameter -BoundParameters $PSBoundParameters + + $currentPolicy = Get-MgBetaNetworkAccessForwardingPolicy -Expand * -ErrorAction SilentlyContinue | Where-Object { $_.Name -eq $setParameters.Name } + if ($Name -eq "Custom Bypass") { + foreach ($rule in $currentPolicy.PolicyRules) { + Remove-MgBetaNetworkAccessForwardingPolicyRule -ForwardingPolicyId $currentPolicy.Id -PolicyRuleId $rule.Id + } + + foreach ($rule in $setParameters.PolicyRules) { + $complexDestinations = @() + foreach ($destination in $rule.Destinations) { + $complexDestinations += @{ + "@odata.type" = "#microsoft.graph.networkaccess." + $rule.RuleType + value = $destination + } + } + $params = @{ + "@odata.type" = "#microsoft.graph.networkaccess.internetAccessForwardingRule" + name = $rule.Name + action = $rule.ActionValue + ruleType = $rule.RuleType + ports = ($rule.Ports | ForEach-Object { $_.ToString() }) + protocol = $rule.Protocol + destinations = $complexDestinations + } + + New-MgBetaNetworkAccessForwardingPolicyRule -ForwardingPolicyId $currentPolicy.Id -BodyParameter $params + } + } elseif ($currentPolicy.TrafficForwardingType -eq "m365") { + $rulesParam = @() + foreach ($desiredRule in $setParameters.PolicyRules) { + $desiredRuleHashtable = Convert-M365DSCDRGComplexTypeToHashtable $desiredRule + $desiredRuleHashtable.Remove('actionValue') + $testResult = $false + foreach ($currentRule in $currentPolicy.PolicyRules) { + $currentRuleHashtable = Get-MicrosoftGraphNetworkAccessForwardingPolicyRules -PolicyRules @($currentRule) + $currentRuleHashtable.Remove('ActionValue'); + $testResult = Compare-M365DSCComplexObject ` + -Source ($currentRuleHashtable) ` + -Target ($desiredRuleHashtable) + if ($testResult) { + Write-Verbose "Updating: $($currentRule.Name), $($currentRule.Id)" + $rulesParam += @{ + ruleId = $currentRule.Id + action = $desiredRule.ActionValue + } + break + } + } + if($testResult -eq $false){ + Write-Verbose "Could not find rule with the given specification: $(Convert-M365DscHashtableToString -Hashtable $desiredRuleHashtable), skipping set for this." + } + } + $updateParams = @{ + rules = $rulesParam + } + + Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/beta/networkAccess/forwardingPolicies/$($currentPolicy.ID)/updatePolicyRules" -Method Post -Body $updateParams + } + else { + Write-Verbose "Can not modify the list of poilicy rules for the forwarding policy with name: $($setParameters.Name)" + } +} + +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name, + + [Parameter()] + [Microsoft.Management.Infrastructure.CimInstance[]] + $PolicyRules, + + [Parameter()] + [System.Management.Automation.PSCredential] + $Credential, + + [Parameter()] + [System.String] + $ApplicationId, + + [Parameter()] + [System.String] + $TenantId, + + [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 + + $testTargetResource = $true + $CurrentValues = Get-TargetResource @PSBoundParameters + $ValuesToCheck = ([Hashtable]$PSBoundParameters).Clone() + + #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) + { + $testTargetResource = $false + } + else { + $ValuesToCheck.Remove($key) | Out-Null + } + } + } + + Write-Verbose -Message "Current Values: $(Convert-M365DscHashtableToString -Hashtable $CurrentValues)" + Write-Verbose -Message "Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)" + + $TestResult = Test-M365DSCParameterState -CurrentValues $CurrentValues ` + -Source $($MyInvocation.MyCommand.Source) ` + -DesiredValues $PSBoundParameters ` + -ValuesToCheck $ValuesToCheck.Keys ` + -IncludedDrifts $driftedParams + + if(-not $TestResult) + { + $testTargetResource = $false + } + + Write-Verbose -Message "Test-TargetResource returned $testTargetResource" + + return $testTargetResource +} + +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [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 + { + $Script:ExportMode = $true + [array] $Script:exportedInstances = Get-MgBetaNetworkAccessForwardingPolicy -Expand * -ErrorAction Stop + + $i = 1 + $dscContent = '' + if ($Script:exportedInstances.Length -eq 0) + { + Write-Host $Global:M365DSCEmojiGreenCheckMark + } + else + { + Write-Host "`r`n" -NoNewline + } + foreach ($config in $Script:exportedInstances) + { + if ($null -ne $Global:M365DSCExportResourceInstancesCount) + { + $Global:M365DSCExportResourceInstancesCount++ + } + + $displayedKey = $config.Name + Write-Host " |---[$i/$($Script:exportedInstances.Count)] $displayedKey" -NoNewline + $params = @{ + Name = $config.Name + Credential = $Credential + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + ManagedIdentity = $ManagedIdentity.IsPresent + AccessTokens = $AccessTokens + } + + $Results = Get-TargetResource @Params + $Results = Update-M365DSCExportAuthenticationResults -ConnectionMode $ConnectionMode ` + -Results $Results + + if ($null -ne $Results.PolicyRules) + { + $Results.PolicyRules = Get-MicrosoftGraphNetworkAccessForwardingPolicyRulesAsString -PolicyRules $Results.PolicyRules + } + + $currentDSCBlock = Get-M365DSCExportContentForResource -ResourceName $ResourceName ` + -ConnectionMode $ConnectionMode ` + -ModulePath $PSScriptRoot ` + -Results $Results ` + -Credential $Credential + + if ($null -ne $Results.PolicyRules) + { + $currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock $currentDSCBlock ` + -ParameterName 'PolicyRules' + } + + $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 '' + } +} + +function Get-MicrosoftGraphNetworkAccessForwardingPolicyRules +{ + [CmdletBinding()] + [OutputType([System.Collections.ArrayList])] + param( + [Parameter(Mandatory = $true)] + [System.Collections.ArrayList] + $PolicyRules + ) + + $newPolicyRules = @() + foreach ($rule in $PolicyRules) { + $destinations = @() + foreach ($destination in $rule.AdditionalProperties.destinations) { + $destinations += $destination.value + } + $newPolicyRules += @{ + Name = $rule.Name + ActionValue = $rule.AdditionalProperties.action + RuleType = $rule.AdditionalProperties.ruleType + Ports = $rule.AdditionalProperties.ports + Protocol = $rule.AdditionalProperties.protocol + Destinations = $destinations + } + } + + return $newPolicyRules +} + +function Get-MicrosoftGraphNetworkAccessForwardingPolicyRulesAsString +{ + [CmdletBinding()] + [OutputType([System.String])] + param( + [Parameter(Mandatory = $true)] + [System.Collections.ArrayList] + $PolicyRules + ) + + $StringContent = [System.Text.StringBuilder]::new() + $StringContent.Append('@(') | Out-Null + + foreach ($rule in $PolicyRules) + { + $StringContent.Append("`n MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule {`r`n") | Out-Null + $StringContent.Append(" Name = '" + $rule.Name + "'`r`n") | Out-Null + $StringContent.Append(" ActionValue = '" + $rule.ActionValue + "'`r`n") | Out-Null + $StringContent.Append(" RuleType = '" + $rule.RuleType + "'`r`n") | Out-Null + $StringContent.Append(" Protocol = '" + $rule.Protocol + "'`r`n") | Out-Null + $StringContent.Append(" Ports = @(" + $($rule.Ports -join ", ") + ")`r`n") | Out-Null + $StringContent.Append(" Destinations = @(" + $(($rule.Destinations | ForEach-Object { "'$_'" }) -join ", ") + ")`r`n") | Out-Null + $StringContent.Append(" }`r`n") | Out-Null + } + + $StringContent.Append(' )') | Out-Null + return $StringContent.ToString() +} + + +Export-ModuleMember -Function *-TargetResource diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/MSFT_AADNetworkAccessForwardingPolicy.schema.mof b/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/MSFT_AADNetworkAccessForwardingPolicy.schema.mof new file mode 100644 index 0000000000..78c92d1747 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/MSFT_AADNetworkAccessForwardingPolicy.schema.mof @@ -0,0 +1,24 @@ +[ClassVersion("1.0.0")] +class MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule +{ + [Write, Description("Policy Rule Name. Required")] String Name; + [Write, Description("Action value.")] String ActionValue; + [Write, Description("Type of Rule")] String RuleType; + [Write, Description("List of Ports.")] UInt32 Ports[]; + [Write, Description("Protocol Value")] String Protocol; + [Write, Description("List of destinations.")] String Destinations[]; +}; + +[ClassVersion("1.0.0.0"), FriendlyName("AADNetworkAccessForwardingPolicy")] +class MSFT_AADNetworkAccessForwardingPolicy : OMI_BaseResource +{ + [Key, Description("Name of the forwarding policy")] String Name; + [Write, Description("List of rules associated to this forwarding policy."), EmbeddedInstance("MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule")] String PolicyRules[]; + + [Write, Description("Credentials of the workload's Admin"), EmbeddedInstance("MSFT_Credential")] string Credential; + [Write, Description("Id of the Azure Active Directory application to authenticate with.")] String ApplicationId; + [Write, Description("Id of the Azure Active Directory tenant used for authentication.")] String TenantId; + [Write, Description("Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.")] String CertificateThumbprint; + [Write, Description("Managed ID being used for authentication.")] Boolean ManagedIdentity; + [Write, Description("Access token used for authentication.")] String AccessTokens[]; +}; diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/readme.md b/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/readme.md new file mode 100644 index 0000000000..0eb3e52feb --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/readme.md @@ -0,0 +1,6 @@ + +# AADNetworkAccessForwardingPolicy + +## Description + +Use this resource to monitor the forwarding policy rules associated with the forwarding policies. diff --git a/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/settings.json b/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/settings.json new file mode 100644 index 0000000000..1c3b2ce323 --- /dev/null +++ b/Modules/Microsoft365DSC/DSCResources/MSFT_AADNetworkAccessForwardingPolicy/settings.json @@ -0,0 +1,32 @@ +{ + "resourceName": "AADNetworkAccessForwardingPolicy", + "description": "Use this resource to monitor the forwarding policy rules associated with the forwarding policies.", + "permissions": { + "graph": { + "delegated": { + "read": [ + { + "name": "NetworkAccessPolicy.Read.All" + } + ], + "update": [ + { + "name": "NetworkAccessPolicy.ReadWrite.All" + } + ] + }, + "application": { + "read": [ + { + "name": "NetworkAccessPolicy.Read.All" + } + ], + "update": [ + { + "name": "NetworkAccessPolicy.ReadWrite.All" + } + ] + } + } + } +} diff --git a/Modules/Microsoft365DSC/Examples/Resources/AADNetworkAccessForwardingPolicy/2-Update.ps1 b/Modules/Microsoft365DSC/Examples/Resources/AADNetworkAccessForwardingPolicy/2-Update.ps1 new file mode 100644 index 0000000000..87f8e1578a --- /dev/null +++ b/Modules/Microsoft365DSC/Examples/Resources/AADNetworkAccessForwardingPolicy/2-Update.ps1 @@ -0,0 +1,60 @@ +<# +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 + { + AADNetworkAccessForwardingPolicy "AADNetworkAccessForwardingPolicy-Custom Bypass" + { + Name = "Custom Bypass"; + PolicyRules = @( + MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule { + Name = 'Custom policy internet rule' + ActionValue = 'bypass' + RuleType = 'fqdn' + Protocol = 'tcp' + Ports = @(80, 443) + Destinations = @('www.microsoft.com') + } + + MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule { + Name = 'Custom policy internet rule' + ActionValue = 'bypass' + RuleType = 'ipAddress' + Protocol = 'tcp' + Ports = @(80, 443) + Destinations = @('192.168.1.1') + } + + MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule { + Name = 'Custom policy internet rule' + ActionValue = 'bypass' + RuleType = 'ipSubnet' + Protocol = 'tcp' + Ports = @(80, 443) + Destinations = @('192.164.0.0/24') + } + ); + ApplicationId = $ApplicationId + TenantId = $TenantId + CertificateThumbprint = $CertificateThumbprint + } + } +} diff --git a/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADNetworkAccessForwardingPolicy.Tests.ps1 b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADNetworkAccessForwardingPolicy.Tests.ps1 new file mode 100644 index 0000000000..45562b9072 --- /dev/null +++ b/Tests/Unit/Microsoft365DSC/Microsoft365DSC.AADNetworkAccessForwardingPolicy.Tests.ps1 @@ -0,0 +1,253 @@ +[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 New-M365DSCConnection -MockWith { + return "Credentials" + } + + Mock -CommandName Get-MgBetaNetworkAccessForwardingPolicy -MockWith { + } + + Mock -CommandName New-MgBetaNetworkAccessForwardingPolicyrule -MockWith { + } + + Mock -CommandName Remove-MgBetaNetworkAccessForwardingPolicyRule -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 "The instance exists and values are already in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Name = "Custom Bypass"; + PolicyRules = [CimInstance[]]@( + New-CimInstance -ClassName MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule -Property @{ + Name = 'Custom policy internet rule' + ActionValue = 'bypass' + RuleType = 'fqdn' + Protocol = 'tcp' + Ports = @(80, 443) + Destinations = @('www.google.com') + } -ClientOnly + + New-CimInstance -ClassName MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule -Property @{ + Name = 'Custom policy internet rule' + ActionValue = 'bypass' + RuleType = 'ipSubnet' + Protocol = 'tcp' + Ports = @(80, 443) + Destinations = @('192.164.0.0/24') + } -ClientOnly + ) + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaNetworkAccessForwardingPolicy -MockWith { + return @{ + Name = "Custom Bypass" + PolicyRules = @( + @{ + Name = "Custom policy internet rule" + AdditionalProperties = @{ + ruleType = "fqdn" + action = "bypass" + ports = @(80,443) + protocol = "tcp" + destinations = @( + @{ + value = "www.google.com" + } + ) + } + }, + @{ + Name = "Custom policy internet rule" + AdditionalProperties = @{ + ruleType = "ipSubnet" + action = "bypass" + ports = @(80,443) + protocol = "tcp" + destinations = @( + @{ + value = "192.164.0.0/24" + } + ) + } + } + ) + } + } + } + + It 'Should return true from the Test method' { + Test-TargetResource @testParams | Should -Be $true + } + } + + Context -Name "The instance exists and values are NOT in the desired state" -Fixture { + BeforeAll { + $testParams = @{ + Name = "Custom Bypass"; + PolicyRules = [CimInstance[]]@( + New-CimInstance -ClassName MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule -Property @{ + Name = 'Custom policy internet rule' + ActionValue = 'bypass' + RuleType = 'fqdn' + Protocol = 'tcp' + Ports = @(80, 443) + Destinations = @('www.google.com') + } -ClientOnly + + New-CimInstance -ClassName MSFT_MicrosoftGraphNetworkAccessForwardingPolicyRule -Property @{ + Name = 'Custom policy internet rule' + ActionValue = 'bypass' + RuleType = 'ipSubnet' + Protocol = 'tcp' + Ports = @(80, 443) + Destinations = @('192.164.0.0/24') + } -ClientOnly + ) + Credential = $Credential; + } + + Mock -CommandName Get-MgBetaNetworkAccessForwardingPolicy -MockWith { + return @{ + Name = "Custom Bypass" + PolicyRules = @( + @{ + Name = "Custom policy internet rule" + AdditionalProperties = @{ + ruleType = "fqdn" + action = "bypass" + ports = @(80,443) + protocol = "tcp" + destinations = @( + @{ + value = "www.google.com" + } + ) + } + }, + @{ + Name = "Custom policy internet rule" + AdditionalProperties = @{ + ruleType = "ipSubnet" + action = "bypass" + ports = @(80,443) + protocol = "tcp" + destinations = @( + @{ + value = "192.164.0.0/28" # created drift here + } + ) + } + } + ) + } + } + } + + It 'Should return Values from the Get method' { + (Get-TargetResource @testParams).Name | Should -Be "Custom Bypass" + } + + It 'Should return false from the Test method' { + Test-TargetResource @testParams | Should -Be $false + } + + It 'Should call the Set method' { + Set-TargetResource @testParams + Should -Invoke -CommandName Remove-MgBetaNetworkAccessForwardingPolicyRule + Should -Invoke -CommandName New-MgBetaNetworkAccessForwardingPolicyRule + } + } + + Context -Name 'ReverseDSC Tests' -Fixture { + BeforeAll { + $Global:CurrentModeIsExport = $true + $Global:PartialExportFileName = "$(New-Guid).partial.ps1" + $testParams = @{ + Credential = $Credential; + } + + ##TODO - Mock the Get-MgBetaNetworkAccessForwardingPolicy to return an instance + Mock -CommandName Get-MgBetaNetworkAccessForwardingPolicy -MockWith { + return @{ + Name = "Custom Bypass" + PolicyRules = @( + @{ + Name = "Custom policy internet rule" + AdditionalProperties = @{ + ruleType = "fqdn" + action = "bypass" + ports = @(80,443) + protocol = "tcp" + destinations = @( + @{ + value = "www.google.com" + } + ) + } + }, + @{ + Name = "Custom policy internet rule" + AdditionalProperties = @{ + ruleType = "ipSubnet" + action = "bypass" + ports = @(80,443) + protocol = "tcp" + destinations = @( + @{ + value = "192.164.0.0/28" # created drift here + } + ) + } + } + ) + } + } + } + It 'Should Reverse Engineer resource from the Export method' { + $result = Export-TargetResource @testParams + $result | Should -Not -BeNullOrEmpty + } + } + } +} + +Invoke-Command -ScriptBlock $Global:DscHelper.CleanupScript -NoNewScope diff --git a/Tests/Unit/Stubs/Microsoft365.psm1 b/Tests/Unit/Stubs/Microsoft365.psm1 index 521191304f..1a35591bdb 100644 --- a/Tests/Unit/Stubs/Microsoft365.psm1 +++ b/Tests/Unit/Stubs/Microsoft365.psm1 @@ -98726,6 +98726,220 @@ function Update-MgBetaNetworkAccessForwardingProfile #endregion +#region MgBetaNetworkAccessForwardingPolicy +function Get-MgBetaNetworkAccessForwardingPolicy +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $ForwardingPolicyId, + + [Parameter()] + [System.String[]] + $Property, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Int32] + $PageSize, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Int32] + $Skip, + + [Parameter()] + [System.Int32] + $Top, + + [Parameter()] + [System.String] + $CountVariable, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.String[]] + $Sort, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $All, + + [Parameter()] + [System.String] + $Filter, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $Search, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.String[]] + $ExpandProperty, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} +function New-MgBetaNetworkAccessForwardingPolicyRule +{ + [CmdletBinding()] + param( + [Parameter()] + [System.String] + $ForwardingPolicyId, + + [Parameter()] + [System.String] + $Name, + + [Parameter()] + [System.Collections.Hashtable] + $AdditionalProperties, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [PSObject] + $BodyParameter, + + [Parameter()] + [System.String] + $Id, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [PSObject] + $HttpPipelineAppend + ) +} +function Remove-MgBetaNetworkAccessForwardingPolicyRule +{ + [CmdletBinding()] + param( + [Parameter()] + [PSObject] + $InputObject, + + [Parameter()] + [PSObject] + $HttpPipelinePrepend, + + [Parameter()] + [System.Management.Automation.PSCredential] + $ProxyCredential, + + [Parameter()] + [System.Uri] + $Proxy, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $PassThru, + + [Parameter()] + [System.String] + $ForwardingPolicyId, + + [Parameter()] + [System.String] + $IfMatch, + + [Parameter()] + [System.String] + $ResponseHeadersVariable, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Confirm, + + [Parameter()] + [PSObject] + $HttpPipelineAppend, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $ProxyUseDefaultCredentials, + + [Parameter()] + [System.Collections.IDictionary] + $Headers, + + [Parameter()] + [System.String] + $PolicyRuleId, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Break + ) +} +#endregion + #region MgBetaNetworkAccessForwardingProfilePolicy function Get-MgBetaNetworkAccessForwardingProfilePolicy {