Skip to content

Commit

Permalink
Merge pull request d365collaborative#807 from Splaxi/impl-dataverse-t…
Browse files Browse the repository at this point in the history
…ester

Impl dataverse tester
  • Loading branch information
Splaxi authored Feb 6, 2024
2 parents 9ddccd9 + 2dfcf0a commit e4e68e8
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 1 deletion.
36 changes: 35 additions & 1 deletion d365fo.tools/bin/d365fo.tools-index.json
Original file line number Diff line number Diff line change
Expand Up @@ -5876,7 +5876,7 @@
"Name": "Import-D365RsatSelfServiceCertificates",
"Links": null,
"Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eImport-D365RsatSelfServiceCertificates -Path \"C:\\Temp\\UAT\" -Password \"123456789\"\nThis will import the .cer and .pxf files into the correct store, bases on the files located in \"C:\\Temp\\UAT\".\r\nAfter import it will display the thumbprint for both certificates.\nSample output:\r\n[23:43:05][Import-D365RsatSelfServiceCertificates] Pfx Thumbprint: B4D6921321434235463463414312343253523A05\r\n[23:43:05][Import-D365RsatSelfServiceCertificates] Cert Thumbprint: B4D6921321434235463463414312343253523A05",
"Syntax": "Import-D365RsatSelfServiceCertificates [-Path] \u003cObject\u003e [-Password] \u003cObject\u003e [\u003cCommonParameters\u003e]"
"Syntax": "Import-D365RsatSelfServiceCertificates [-Path] \u003cString\u003e [-Password] \u003cString\u003e [\u003cCommonParameters\u003e]"
},
{
"CommandName": "Initialize-D365RsatCertificate",
Expand Down Expand Up @@ -11696,6 +11696,40 @@
"Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eTest-D365Command -CommandText \u0027Import-D365Bacpac -ImportModeTier2 -SqlUser \"sqladmin\" -SqlPwd \"XyzXyz\" -BacpacFile2 \"C:\\temp\\uat.bacpac\"\u0027 -Mode \"Validate\" -IncludeHelp\nThis will validate all the parameters that have been passed to the Import-D365Bacpac cmdlet.\r\nAll supplied parameters that matches a parameter will be marked with an asterisk.\r\nWill print the coloring help.\n-------------------------- EXAMPLE 2 --------------------------\nPS C:\\\u003eTest-D365Command -CommandText \u0027Import-D365Bacpac\u0027 -Mode \"ShowParameters\" -IncludeHelp\nThis will display all the parameter sets and their individual parameters.\r\nWill print the coloring help.\n-------------------------- EXAMPLE 3 --------------------------\nPS C:\\\u003e$params = @{}\nPS C:\\\u003e $params.DatabaseName = \"SAMPLEVALUE\"\r\nPS C:\\\u003e Test-D365Command -CommandText \u0027Import-D365Bacpac -ImportModeTier2\u0027 -SplatInput $params -Mode \"Validate\"\nThis builds a hashtable with a property names \"DatabaseName\".\r\nThe hashtable is passed to the cmdlet to be part of the validation.",
"Syntax": "Test-D365Command [-CommandText] \u003cString\u003e [-Mode] \u003cString\u003e [-SplatInput \u003cHashtable\u003e] [-ShowSplatStyleV1] [-ShowSplatStyleV2] [-IncludeHelp] [\u003cCommonParameters\u003e]"
},
{
"CommandName": "Test-D365DataverseConnection",
"Description": "Invokes the built-in http communication endpount, that validates the connection between the D365FO environment and dataverse",
"Params": [
[
"BinDir",
"The path to the bin directory for the environment\nDefault path is the same as the aos service PackagesLocalDirectory\\bin",
"",
false,
"false",
"\"$Script:BinDir\\bin\""
]
],
"Alias": "",
"Synopsis": "Test the dataverse connection",
"Name": "Test-D365DataverseConnection",
"Links": null,
"Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eTest-D365DataverseConnection\nThis will invoke the http communication component, that validates the basic settings between D365FO and Dataverse.\r\nIt will output the raw details from the call, to make it easier to troubleshoot the connectivity between D365FO and Dataverse.",
"Syntax": "Test-D365DataverseConnection [[-BinDir] \u003cString\u003e] [\u003cCommonParameters\u003e]"
},
{
"CommandName": "Test-D365EntraIntegration",
"Description": "Validates the configuration of the web.config file and the certificate for the environment\n\nIf any of the configuration is missing or in someway incorrect, it will prompt and stating corrective actions needed",
"Params": [

],
"Alias": "",
"Author": "Mötz Jensen (@Splaxi)",
"Synopsis": "Test the Entra Id integration",
"Name": "Test-D365EntraIntegration",
"Links": null,
"Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eTest-D365EntraIntegration\nThis will validate the settings inside the web.config file.\r\nIt will search for Aad.Realm, Infrastructure.S2SCertThumbprint, GraphApi.GraphAPIServicePrincipalCert\r\nIt will search for the certificate that matches the thumbprint.\nA result set example:\nEntraAppId Thumbprint Subject Expiration\r\n---------- ---------- ------- ----------\r\ne068e004-8bec-48c3-a36f-2ab4982ee738 0768175DF3DFDEA3FA78925ADC1E588707649335 CN=CHEAuth 2/5/2026 8:09:28 AM",
"Syntax": "Test-D365EntraIntegration [\u003cCommonParameters\u003e]"
},
{
"CommandName": "Test-D365FlightServiceCatalogId",
"Description": "Test if the FlightingServiceCatalogID element exists in the web.config file used by D365FO",
Expand Down
2 changes: 2 additions & 0 deletions d365fo.tools/d365fo.tools.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@
'Switch-D365ActiveDatabase',

'Test-D365Command',
'Test-D365DataverseConnection',
'Test-D365EntraIntegration',
'Test-D365FlightServiceCatalogId',
'Test-D365LabelIdIsValid',

Expand Down
82 changes: 82 additions & 0 deletions d365fo.tools/functions/test-d365dataverseconnection.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@

<#
.SYNOPSIS
Test the dataverse connection
.DESCRIPTION
Invokes the built-in http communication endpount, that validates the connection between the D365FO environment and dataverse
.PARAMETER BinDir
The path to the bin directory for the environment
Default path is the same as the aos service PackagesLocalDirectory\bin
.EXAMPLE
PS C:\> Test-D365DataverseConnection
This will invoke the http communication component, that validates the basic settings between D365FO and Dataverse.
It will output the raw details from the call, to make it easier to troubleshoot the connectivity between D365FO and Dataverse.
.NOTES
General notes
#>
function Test-D365DataverseConnection {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[string] $BinDir = "$Script:BinDir\bin"
)

begin {
}

process {
$cdsApiPath = "sdkmessages";
$httpCommunicationDllPath = Join-Path -Path $BinDir -ChildPath "Microsoft.Dynamics.HttpCommunication.dll"

if (-not (Test-PathExists -Path $httpCommunicationDllPath -Type Leaf)) {
return
}

Write-PSFMessage -Level Verbose -Message "Loading the 'Microsoft.Dynamics.HttpCommunication.dll' file into the current session."
Add-Type -Path $httpCommunicationDllPath

try {
Write-PSFMessage -Level Verbose -Message "Building the logger object, to handle the output from the test."
$assembly = [System.Reflection.Assembly]::LoadFile($httpCommunicationDllPath)
$loggerType = $assembly.GetType("Microsoft.Dynamics.HttpCommunication.Logging.InMemoryLogger")
$bindingFlags = [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::Public
$loggerConstructor = $loggerType.GetConstructor($bindingFlags, $null, [System.Type]::EmptyTypes, $null)
$logger = $loggerConstructor.Invoke($null)

Write-PSFMessage -Level Verbose -Message "Building the client/request object, to execute the test / validation."
$cdsWebApiClient = New-Object Microsoft.Dynamics.HttpCommunication.Cds.CdsWebApiClient $logger;
$bindingFlags = [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic
$method = [Microsoft.Dynamics.HttpCommunication.Cds.CdsWebApiClient].GetMethod("GetWithStringResponse", $bindingFlags, $null, @([string]), $null)

Write-PSFMessage -Level Verbose -Message "Invoking the test / validation request."
$task = $method.Invoke($cdsWebApiClient, @($cdsApiPath))
$response = $task.GetAwaiter().GetResult()

$response
}
catch {
Write-PSFHostColor -String $logger.LogContent.ToString() -DefaultColor Red

if ($logger.LogContent.ToString() -like '*Cannot Find Thumbprint by Certificatename*') {
Write-PSFMessage -Level Host -Message "The <c='em'>'Cannot Find Thumbprint by Certificatename'</c> indicates that you need to run the <c='em'>'New-D365EntraIntegration'</c> cmdlet."
Write-PSFMessage -Level Host -Message "You should read the following links: <c='em'>https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-tools/secure-developer-vm#external-integrations</c> and <c='em'>https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/business-events/che-be-ve-error</c>."
Stop-PSFFunction -Message "Stopping because the 'Cannot Find Thumbprint by Certificatename' error was encounted"
return
}
elseif ($logger.LogContent.ToString() -like '*Expected aud https://securityservice.operations365.dynamics.com*') {
Write-PSFMessage -Level Host -Message "The <c='em'>'Expected aud https://securityservice.operations365.dynamics.com'</c> indicates that you need to configure Azure Entra (Registered Application) between your <c='em'>D365FO</c> environment and the connected <c='em'>Dataverse</c> environment."
Write-PSFMessage -Level Host -Message "You should read the following link: <c='em'>https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/business-events/che-be-ve-error</c>."
Stop-PSFFunction -Message "Stopping because the 'Cannot Find Thumbprint by Certificatename' error was encounted"
return
}
}
}

end {
}
}
93 changes: 93 additions & 0 deletions d365fo.tools/functions/test-d365entraintegration.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@

<#
.SYNOPSIS
Test the Entra Id integration
.DESCRIPTION
Validates the configuration of the web.config file and the certificate for the environment
If any of the configuration is missing or in someway incorrect, it will prompt and stating corrective actions needed
.EXAMPLE
PS C:\> Test-D365EntraIntegration
This will validate the settings inside the web.config file.
It will search for Aad.Realm, Infrastructure.S2SCertThumbprint, GraphApi.GraphAPIServicePrincipalCert
It will search for the certificate that matches the thumbprint.
A result set example:
EntraAppId Thumbprint Subject Expiration
---------- ---------- ------- ----------
e068e004-8bec-48c3-a36f-2ab4982ee738 0768175DF3DFDEA3FA78925ADC1E588707649335 CN=CHEAuth 2/5/2026 8:09:28 AM
.NOTES
Based on: https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-tools/secure-developer-vm#external-integrations
Author: Mötz Jensen (@Splaxi)
#>
function Test-D365EntraIntegration {
param (
)

if (-not ($Script:IsAdminRuntime)) {
Write-PSFMessage -Level Critical -Message "It seems that you ran this cmdlet <c='em'>non-elevated</c>. Testing the Entra integration requires you to run this cmdlet from an elevated console. Please exit the current console and start a new with `"Run As Administrator`""
Stop-PSFFunction -Message "Stopping because the function is not run elevated"
return
}

$webConfigFile = Join-Path -Path $Script:AOSPath $Script:WebConfig

if (-not (Test-PathExists -Path $webConfigFile -Type Leaf -ErrorAction SilentlyContinue -WarningAction SilentlyContinue)) {
Write-PSFMessage -Level Host -Message "Unable to find the web.config file."
Stop-PSFFunction -Message "Stopping because the web.config file could not be found"
}

$config = @{}

[xml]$xml = Get-Content $webConfigFile
$nodes = ($xml.configuration.appSettings).ChildNodes

$config.AadRealm = $nodes | Where-Object -Property Key -eq "Aad.Realm" | Select-Object -First 1 -ExpandProperty value
$config.S2SCertThumbprint = $nodes | Where-Object -Property Key -eq "Infrastructure.S2SCertThumbprint" | Select-Object -First 1 -ExpandProperty value
$config.GraphAPIServicePrincipalCert = $nodes | Where-Object -Property Key -eq "GraphApi.GraphAPIServicePrincipalCert" | Select-Object -First 1 -ExpandProperty value

if ([System.String]::IsNullOrWhiteSpace($config.AadRealm)) {
Write-PSFMessage -Level Host -Message "The <c='em'>'Aad.Realm'</c> value is empty. This indicates that you need to run the <c='em'>'New-D365EntraIntegration'</c> cmdlet."
Stop-PSFFunction -Message "Stopping because the 'Aad.Realm' value is empty"
}

if ([System.String]::IsNullOrWhiteSpace($config.S2SCertThumbprint)) {
Write-PSFMessage -Level Host -Message "The <c='em'>'Infrastructure.S2SCertThumbprint'</c> value is empty. This indicates that you need to run the <c='em'>'New-D365EntraIntegration'</c> cmdlet."
Stop-PSFFunction -Message "Stopping because the 'Infrastructure.S2SCertThumbprint' value is empty"
}

if ([System.String]::IsNullOrWhiteSpace($config.GraphAPIServicePrincipalCert)) {
Write-PSFMessage -Level Host -Message "The <c='em'>'GraphApi.GraphAPIServicePrincipalCert'</c> value is empty. This indicates that you need to run the <c='em'>'New-D365EntraIntegration'</c> cmdlet."
Stop-PSFFunction -Message "Stopping because the 'GraphApi.GraphAPIServicePrincipalCert' value is empty"
}

if ((-not [System.String]::IsNullOrWhiteSpace($config.S2SCertThumbprint)) -and $config.S2SCertThumbprint -ne $config.GraphAPIServicePrincipalCert) {
Write-PSFMessage -Level Host -Message "The <c='em'>'Infrastructure.S2SCertThumbprint'</c> and the <c='em'>'GraphApi.GraphAPIServicePrincipalCert'</c> value doesn't match each other. This indicates that you a <c='em'>corrupted</c> configuration. Running the <c='em'>'New-D365EntraIntegration'</c> cmdlet could assist with fixing the configuration."
Stop-PSFFunction -Message "Stopping because the 'Infrastructure.S2SCertThumbprint' and 'GraphApi.GraphAPIServicePrincipalCert' values doesn't match"
}

if (Test-PSFFunctionInterrupt) { return }

$certStoreLocation = "Cert:\LocalMachine\My"

$certEntra = Get-ChildItem -Path $certStoreLocation -ErrorAction SilentlyContinue | Where-Object { $_.Thumbprint -eq $config.S2SCertThumbprint } | Select-Object -First 1

if ($null -eq $certEntra) {
Write-PSFMessage -Level Host -Message "Unable to find any certificate in the certificate store <c='em'>'$certStoreLocation'</c> that matches the thumbprint <c='em'>'$($config.S2SCertThumbprint)'</c>."
Stop-PSFFunction -Message "Stopping because no certificate matching the thumbprint was found"
return
}

[PSCustomObject][ordered]@{
EntraAppId = $config.AadRealm.replace("spn:", "")
Thumbprint = $config.S2SCertThumbprint
Subject = $certEntra.Subject
Expiration = $certEntra.NotAfter
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Describe "Test-D365DataverseConnection Unit Tests" -Tag "Unit" {
BeforeAll {
# Place here all things needed to prepare for the tests
}
AfterAll {
# Here is where all the cleanup tasks go
}

Describe "Ensuring unchanged command signature" {
It "should have the expected parameter sets" {
(Get-Command Test-D365DataverseConnection).ParameterSets.Name | Should -Be 'Default'
}

It 'Should have the expected parameter BinDir' {
$parameter = (Get-Command Test-D365DataverseConnection).Parameters['BinDir']
$parameter.Name | Should -Be 'BinDir'
$parameter.ParameterType.ToString() | Should -Be System.String
$parameter.IsDynamic | Should -Be $False
$parameter.ParameterSets.Keys | Should -Be '__AllParameterSets'
$parameter.ParameterSets.Keys | Should -Contain '__AllParameterSets'
$parameter.ParameterSets['__AllParameterSets'].IsMandatory | Should -Be $False
$parameter.ParameterSets['__AllParameterSets'].Position | Should -Be 0
$parameter.ParameterSets['__AllParameterSets'].ValueFromPipeline | Should -Be $False
$parameter.ParameterSets['__AllParameterSets'].ValueFromPipelineByPropertyName | Should -Be $False
$parameter.ParameterSets['__AllParameterSets'].ValueFromRemainingArguments | Should -Be $False
}
}

Describe "Testing parameterset Default" {
<#
Default -
Default -BinDir
#>
}

}
24 changes: 24 additions & 0 deletions d365fo.tools/tests/functions/Test-D365EntraIntegration.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Describe "Test-D365EntraIntegration Unit Tests" -Tag "Unit" {
BeforeAll {
# Place here all things needed to prepare for the tests
}
AfterAll {
# Here is where all the cleanup tasks go
}

Describe "Ensuring unchanged command signature" {
It "should have the expected parameter sets" {
(Get-Command Test-D365EntraIntegration).ParameterSets.Name | Should -Be '__AllParameterSets'
}


}

Describe "Testing parameterset __AllParameterSets" {
<#
__AllParameterSets -
__AllParameterSets -
#>
}

}
61 changes: 61 additions & 0 deletions docs/Test-D365DataverseConnection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
external help file: d365fo.tools-help.xml
Module Name: d365fo.tools
online version:
schema: 2.0.0
---

# Test-D365DataverseConnection

## SYNOPSIS
Test the dataverse connection

## SYNTAX

```
Test-D365DataverseConnection [[-BinDir] <String>] [<CommonParameters>]
```

## DESCRIPTION
Invokes the built-in http communication endpount, that validates the connection between the D365FO environment and dataverse

## EXAMPLES

### EXAMPLE 1
```
Test-D365DataverseConnection
```

This will invoke the http communication component, that validates the basic settings between D365FO and Dataverse.
It will output the raw details from the call, to make it easier to troubleshoot the connectivity between D365FO and Dataverse.

## PARAMETERS

### -BinDir
The path to the bin directory for the environment

Default path is the same as the aos service PackagesLocalDirectory\bin

```yaml
Type: String
Parameter Sets: (All)
Aliases:

Required: False
Position: 1
Default value: "$Script:BinDir\bin"
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
## INPUTS
## OUTPUTS
## NOTES
General notes
## RELATED LINKS
Loading

0 comments on commit e4e68e8

Please sign in to comment.