diff --git a/d365fo.tools/bin/d365fo.tools-index.json b/d365fo.tools/bin/d365fo.tools-index.json
index 445115f7..5e1f0819 100644
--- a/d365fo.tools/bin/d365fo.tools-index.json
+++ b/d365fo.tools/bin/d365fo.tools-index.json
@@ -8980,7 +8980,7 @@
},
{
"CommandName": "Invoke-D365SDPInstall",
- "Description": "A cmdlet that wraps some of the cumbersome work into a streamlined process.\nThe process are detailed in the Microsoft documentation here:\nhttps://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/deployment/install-deployable-package",
+ "Description": "A cmdlet that wraps some of the cumbersome work into a streamlined process.\nThe process for a legacy (i.e. non unified) environment are detailed in the Microsoft documentation here:\nhttps://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/deployment/install-deployable-package",
"Params": [
[
"Path",
@@ -9077,15 +9077,60 @@
false,
"false",
"False"
+ ],
+ [
+ "UnifiedDevelopmentEnvironment",
+ "Use this switch to install the package in a Unified Development Environment (UDE).",
+ "",
+ false,
+ "false",
+ "False"
]
],
"Alias": "",
"Author": "Tommy Skaue (@skaue)",
- "Synopsis": "Invoke the AxUpdateInstaller.exe file from Software Deployable Package (SDP)",
+ "Synopsis": "Install a Software Deployable Package (SDP)",
"Name": "Invoke-D365SDPInstall",
"Links": null,
- "Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\package.zip\" -QuickInstallAll\nThis will install the package contained in the c:\\temp\\package.zip file using a runbook in memory while executing.\n-------------------------- EXAMPLE 2 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -DevInstall\nThis will install the extracted package in c:\\temp\\ using a runbook in memory while executing.\nThis command is to be used on Microsoft Hosted Tier1 development environment, where you don\u0027t have access to the administrator user account on the vm.\n-------------------------- EXAMPLE 3 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command SetTopology\nPS C:\\\u003e Invoke-D365SDPInstall -Path \"c:\\temp\\\" -Command Generate -RunbookId \u0027MyRunbook\u0027\r\nPS C:\\\u003e Invoke-D365SDPInstall -Path \"c:\\temp\\\" -Command Import -RunbookId \u0027MyRunbook\u0027\r\nPS C:\\\u003e Invoke-D365SDPInstall -Path \"c:\\temp\\\" -Command Execute -RunbookId \u0027MyRunbook\u0027\nManual operations that first create Topology XML from current environment, then generate runbook with id \u0027MyRunbook\u0027, then import it and finally execute it.\n-------------------------- EXAMPLE 4 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command RunAll\nCreate Topology XML from current environment. Using default runbook id \u0027Runbook\u0027 and run all the operations from generate, to import to execute.\n-------------------------- EXAMPLE 5 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command RerunStep -Step 18 -RunbookId \u0027MyRunbook\u0027\nRerun runbook with id \u0027MyRunbook\u0027 from step 18.\n-------------------------- EXAMPLE 6 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command SetStepComplete -Step 24 -RunbookId \u0027MyRunbook\u0027\nMark step 24 complete in runbook with id \u0027MyRunbook\u0027 and continue the runbook from the next step.\n-------------------------- EXAMPLE 7 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command SetTopology -TopologyFile \"c:\\temp\\MyTopology.xml\"\nUpdate the MyTopology.xml file with all the installed services on the machine.\n-------------------------- EXAMPLE 8 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command RunAll -TopologyFile \"c:\\temp\\MyTopology.xml\" -UseExistingTopologyFile\nRun all manual steps in one single operation using the MyTopology.xml file. The topology file is not updated.",
- "Syntax": "Invoke-D365SDPInstall [-Path] \u003cString\u003e [[-MetaDataDir] \u003cString\u003e] [[-QuickInstallAll]] [[-Step] \u003cInt32\u003e] [[-RunbookId] \u003cString\u003e] [-LogPath \u003cString\u003e] [-ShowOriginalProgress] [-OutputCommandOnly] [-TopologyFile \u003cString\u003e] [-UseExistingTopologyFile] [\u003cCommonParameters\u003e]\nInvoke-D365SDPInstall [-Path] \u003cString\u003e [[-MetaDataDir] \u003cString\u003e] [[-DevInstall]] [[-Step] \u003cInt32\u003e] [[-RunbookId] \u003cString\u003e] [-LogPath \u003cString\u003e] [-ShowOriginalProgress] [-OutputCommandOnly] [-TopologyFile \u003cString\u003e] [-UseExistingTopologyFile] [\u003cCommonParameters\u003e]\nInvoke-D365SDPInstall [-Path] \u003cString\u003e [[-MetaDataDir] \u003cString\u003e] [-Command] \u003cString\u003e [[-Step] \u003cInt32\u003e] [[-RunbookId] \u003cString\u003e] [-LogPath \u003cString\u003e] [-ShowOriginalProgress] [-OutputCommandOnly] [-TopologyFile \u003cString\u003e] [-UseExistingTopologyFile] [\u003cCommonParameters\u003e]"
+ "Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\package.zip\" -QuickInstallAll\nThis will install the package contained in the c:\\temp\\package.zip file using a runbook in memory while executing.\n-------------------------- EXAMPLE 2 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -DevInstall\nThis will install the extracted package in c:\\temp\\ using a runbook in memory while executing.\nThis command is to be used on Microsoft Hosted Tier1 development environment, where you don\u0027t have access to the administrator user account on the vm.\n-------------------------- EXAMPLE 3 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command SetTopology\nPS C:\\\u003e Invoke-D365SDPInstall -Path \"c:\\temp\\\" -Command Generate -RunbookId \u0027MyRunbook\u0027\r\nPS C:\\\u003e Invoke-D365SDPInstall -Path \"c:\\temp\\\" -Command Import -RunbookId \u0027MyRunbook\u0027\r\nPS C:\\\u003e Invoke-D365SDPInstall -Path \"c:\\temp\\\" -Command Execute -RunbookId \u0027MyRunbook\u0027\nManual operations that first create Topology XML from current environment, then generate runbook with id \u0027MyRunbook\u0027, then import it and finally execute it.\n-------------------------- EXAMPLE 4 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command RunAll\nCreate Topology XML from current environment. Using default runbook id \u0027Runbook\u0027 and run all the operations from generate, to import to execute.\n-------------------------- EXAMPLE 5 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command RerunStep -Step 18 -RunbookId \u0027MyRunbook\u0027\nRerun runbook with id \u0027MyRunbook\u0027 from step 18.\n-------------------------- EXAMPLE 6 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command SetStepComplete -Step 24 -RunbookId \u0027MyRunbook\u0027\nMark step 24 complete in runbook with id \u0027MyRunbook\u0027 and continue the runbook from the next step.\n-------------------------- EXAMPLE 7 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command SetTopology -TopologyFile \"c:\\temp\\MyTopology.xml\"\nUpdate the MyTopology.xml file with all the installed services on the machine.\n-------------------------- EXAMPLE 8 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -Command RunAll -TopologyFile \"c:\\temp\\MyTopology.xml\" -UseExistingTopologyFile\nRun all manual steps in one single operation using the MyTopology.xml file. The topology file is not updated.\n-------------------------- EXAMPLE 9 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstall -Path \"c:\\temp\\\" -MetaDataDir \"c:\\MyRepository\\Metadata\" -UnifiedDevelopmentEnvironment\nInstall the modules contained in the c:\\temp\\ directory into the c:\\MyRepository\\Metadata directory.",
+ "Syntax": "Invoke-D365SDPInstall [-Path] \u003cString\u003e [[-MetaDataDir] \u003cString\u003e] [[-QuickInstallAll]] [[-Step] \u003cInt32\u003e] [[-RunbookId] \u003cString\u003e] [-LogPath \u003cString\u003e] [-ShowOriginalProgress] [-OutputCommandOnly] [-TopologyFile \u003cString\u003e] [-UseExistingTopologyFile] [\u003cCommonParameters\u003e]\nInvoke-D365SDPInstall [-Path] \u003cString\u003e [[-MetaDataDir] \u003cString\u003e] [[-DevInstall]] [[-Step] \u003cInt32\u003e] [[-RunbookId] \u003cString\u003e] [-LogPath \u003cString\u003e] [-ShowOriginalProgress] [-OutputCommandOnly] [-TopologyFile \u003cString\u003e] [-UseExistingTopologyFile] [\u003cCommonParameters\u003e]\nInvoke-D365SDPInstall [-Path] \u003cString\u003e [[-MetaDataDir] \u003cString\u003e] [-Command] \u003cString\u003e [[-Step] \u003cInt32\u003e] [[-RunbookId] \u003cString\u003e] [-LogPath \u003cString\u003e] [-ShowOriginalProgress] [-OutputCommandOnly] [-TopologyFile \u003cString\u003e] [-UseExistingTopologyFile] [\u003cCommonParameters\u003e]\nInvoke-D365SDPInstall [-Path] \u003cString\u003e [[-MetaDataDir] \u003cString\u003e] [[-Step] \u003cInt32\u003e] [[-RunbookId] \u003cString\u003e] [-LogPath \u003cString\u003e] [-ShowOriginalProgress] [-OutputCommandOnly] [-TopologyFile \u003cString\u003e] [-UseExistingTopologyFile] [-UnifiedDevelopmentEnvironment] [\u003cCommonParameters\u003e]"
+ },
+ {
+ "CommandName": "Invoke-D365SDPInstallUDE",
+ "Description": "A cmdlet that wraps some of the cumbersome work into a streamlined process.\nIt first checks if the package is a zip file and extracts it if necessary.\nThen it checks if the package contains the necessary files and modules.\nFinally, it extracts the module zip files into the metadata directory.",
+ "Params": [
+ [
+ "Path",
+ "Path to the package that you want to install into the environment\nThe cmdlet supports a path to a zip-file or directory with the unpacked contents.",
+ "File,Hotfix",
+ true,
+ "false",
+ ""
+ ],
+ [
+ "MetaDataDir",
+ "The path to the meta data directory for the environment",
+ "",
+ true,
+ "false",
+ ""
+ ],
+ [
+ "LogPath",
+ "The path where the log file(s) will be saved",
+ "LogDir",
+ false,
+ "false",
+ "$(Join-Path -Path $Script:DefaultTempPath -ChildPath \"Logs\\SdpInstall\")"
+ ]
+ ],
+ "Alias": "",
+ "Author": "Florian Hopfner (@FH-Inway)",
+ "Synopsis": "Install a Software Deployable Package (SDP) in a unified development environment",
+ "Name": "Invoke-D365SDPInstallUDE",
+ "Links": null,
+ "Examples": "-------------------------- EXAMPLE 1 --------------------------\nPS C:\\\u003eInvoke-D365SDPInstallUDE -Path \"c:\\temp\\package.zip\" -MetaDataDir \"c:\\MyRepository\\Metadata\"\nThis will install the modules contained in the c:\\temp\\package.zip file into the c:\\MyRepository\\Metadata directory.",
+ "Syntax": "Invoke-D365SDPInstallUDE [-Path] \u003cString\u003e [-MetaDataDir] \u003cString\u003e [-LogPath \u003cString\u003e] [\u003cCommonParameters\u003e]"
},
{
"CommandName": "Invoke-D365SeleniumDownload",
diff --git a/d365fo.tools/d365fo.tools.psd1 b/d365fo.tools/d365fo.tools.psd1
index 3563d5e7..42054bbb 100644
--- a/d365fo.tools/d365fo.tools.psd1
+++ b/d365fo.tools/d365fo.tools.psd1
@@ -241,6 +241,7 @@
'Invoke-D365RunbookAnalyzer',
'Invoke-D365SDPInstall',
+ 'Invoke-D365SDPInstallUDE',
'Invoke-D365SCDPBundleInstall',
'Invoke-D365SeleniumDownload',
'Invoke-D365SysFlushAodCache',
diff --git a/d365fo.tools/functions/get-d365sdpdetails.ps1 b/d365fo.tools/functions/get-d365sdpdetails.ps1
index 425c1a63..f325b1c4 100644
--- a/d365fo.tools/functions/get-d365sdpdetails.ps1
+++ b/d365fo.tools/functions/get-d365sdpdetails.ps1
@@ -91,7 +91,7 @@ function Get-D365SDPDetails {
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($zipEntry, $pathHotfix, $true)
- foreach ($nuget in $($zipArch.Entries | Where-Object Fullname -like "AOSService\Packages\*.nupkg")) {
+ foreach ($nuget in $($zipArch.Entries | Where-Object Fullname -like "AOSService[\/]Packages[\/]*.nupkg")) {
$pathNuget = "$pathWorkDirectory\$($nuget.name).zip"
# The nuget file contains module name in correct casing
@@ -144,16 +144,16 @@ function Get-D365SDPDetails {
Version = $moduleSpec.package.metadata.version
}
)
- }
- # Clear out any inner zip archive objects from memory
- if ($zipNuget) {
- $zipArch.Dispose()
- }
-
- if ($fileNuget) {
- $file.Close()
- $file.Dispose()
+ # Clear out any inner zip archive objects from memory
+ if ($zipNuget) {
+ $zipNuget.Dispose()
+ }
+
+ if ($fileNuget) {
+ $fileNuget.Close()
+ $fileNuget.Dispose()
+ }
}
[xml] $hotfix = Get-Content -Path "$pathWorkDirectory\HotfixInstallationInfo.xml" -Raw
diff --git a/d365fo.tools/functions/invoke-d365sdpinstall.ps1 b/d365fo.tools/functions/invoke-d365sdpinstall.ps1
index 9b3f28d1..18afa5ea 100644
--- a/d365fo.tools/functions/invoke-d365sdpinstall.ps1
+++ b/d365fo.tools/functions/invoke-d365sdpinstall.ps1
@@ -1,11 +1,11 @@
<#
.SYNOPSIS
- Invoke the AxUpdateInstaller.exe file from Software Deployable Package (SDP)
+ Install a Software Deployable Package (SDP)
.DESCRIPTION
A cmdlet that wraps some of the cumbersome work into a streamlined process.
- The process are detailed in the Microsoft documentation here:
+ The process for a legacy (i.e. non unified) environment are detailed in the Microsoft documentation here:
https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/deployment/install-deployable-package
.PARAMETER Path
@@ -69,6 +69,9 @@
.PARAMETER UseExistingTopologyFile
Use this switch to indicate that the topology file is already updated and should not be updated again.
+ .PARAMETER UnifiedDevelopmentEnvironment
+ Use this switch to install the package in a Unified Development Environment (UDE).
+
.EXAMPLE
PS C:\> Invoke-D365SDPInstall -Path "c:\temp\package.zip" -QuickInstallAll
@@ -114,12 +117,20 @@
Run all manual steps in one single operation using the MyTopology.xml file. The topology file is not updated.
+ .EXAMPLE
+ PS C:\> Invoke-D365SDPInstall -Path "c:\temp\" -MetaDataDir "c:\MyRepository\Metadata" -UnifiedDevelopmentEnvironment
+
+ Install the modules contained in the c:\temp\ directory into the c:\MyRepository\Metadata directory.
+
.NOTES
Author: Tommy Skaue (@skaue)
Author: Mötz Jensen (@Splaxi)
Inspired by blogpost http://dev.goshoom.net/en/2016/11/installing-deployable-packages-with-powershell/
+ .LINK
+ Invoke-D365SDPInstallUDE
+
#>
function Invoke-D365SDPInstall {
[CmdletBinding(DefaultParameterSetName = 'QuickInstall')]
@@ -157,8 +168,16 @@ function Invoke-D365SDPInstall {
[string] $TopologyFile = "DefaultTopologyData.xml",
- [switch] $UseExistingTopologyFile
+ [switch] $UseExistingTopologyFile,
+
+ [Parameter(ParameterSetName = 'UDEInstall')]
+ [switch] $UnifiedDevelopmentEnvironment
)
+
+ if ($UnifiedDevelopmentEnvironment) {
+ Invoke-D365SDPInstallUDE -Path $Path -MetaDataDir $MetaDataDir -LogPath $LogPath
+ return
+ }
if ((Get-Process -Name "devenv" -ErrorAction SilentlyContinue).Count -gt 0) {
Write-PSFMessage -Level Host -Message "It seems that you have a Visual Studio running. Please ensure exit Visual Studio and run the cmdlet again."
diff --git a/d365fo.tools/functions/invoke-d365sdpinstallude.ps1 b/d365fo.tools/functions/invoke-d365sdpinstallude.ps1
new file mode 100644
index 00000000..8417052f
--- /dev/null
+++ b/d365fo.tools/functions/invoke-d365sdpinstallude.ps1
@@ -0,0 +1,117 @@
+
+<#
+ .SYNOPSIS
+ Install a Software Deployable Package (SDP) in a unified development environment
+
+ .DESCRIPTION
+ A cmdlet that wraps some of the cumbersome work into a streamlined process.
+ It first checks if the package is a zip file and extracts it if necessary.
+ Then it checks if the package contains the necessary files and modules.
+ Finally, it extracts the module zip files into the metadata directory.
+
+ .PARAMETER Path
+ Path to the package that you want to install into the environment
+
+ The cmdlet supports a path to a zip-file or directory with the unpacked contents.
+
+ .PARAMETER MetaDataDir
+ The path to the meta data directory for the environment
+
+ .PARAMETER LogPath
+ The path where the log file(s) will be saved
+
+ .EXAMPLE
+ PS C:\> Invoke-D365SDPInstallUDE -Path "c:\temp\package.zip" -MetaDataDir "c:\MyRepository\Metadata"
+
+ This will install the modules contained in the c:\temp\package.zip file into the c:\MyRepository\Metadata directory.
+
+ .NOTES
+ Author: Florian Hopfner (@FH-Inway)
+
+#>
+function Invoke-D365SDPInstallUDE {
+ param (
+ [Parameter(Mandatory = $True, Position = 1 )]
+ [Alias('Hotfix')]
+ [Alias('File')]
+ [string] $Path,
+
+ [Parameter(Mandatory = $true, Position = 2 )]
+ [string] $MetaDataDir,
+
+ [Alias('LogDir')]
+ [string] $LogPath = $(Join-Path -Path $Script:DefaultTempPath -ChildPath "Logs\SdpInstall")
+ )
+
+ if ((Get-Process -Name "devenv" -ErrorAction SilentlyContinue).Count -gt 0) {
+ Write-PSFMessage -Level Host -Message "It seems that you have a Visual Studio running. Please ensure exit Visual Studio and run the cmdlet again."
+ Stop-PSFFunction -Message "Stopping because of running Visual Studio."
+ return
+ }
+
+ Invoke-TimeSignal -Start
+
+
+ #Test if input is a zipFile that needs to be extracted first
+ if ($Path.EndsWith(".zip")) {
+ Unblock-File -Path $Path
+
+ $extractedPath = $path.Remove($path.Length - 4)
+ if (!(Test-Path $extractedPath)) {
+ Expand-Archive -Path $Path -DestinationPath $extractedPath
+
+ #lets work with the extracted directory from now on
+ $Path = $extractedPath
+ }
+ }
+
+ # Input is a relative path which needs to be converted to an absolute path.
+ # see https://powershellmagazine.com/2013/01/16/pstip-check-if-the-path-is-relative-or-absolute/
+ if (-not ([System.IO.Path]::IsPathRooted($Path) -or (Split-Path -Path $Path -IsAbsolute))) {
+ $currentPath = Get-Location
+ # https://stackoverflow.com/a/13847304/2720554
+ $absolutePath = Join-Path -Path $currentPath -ChildPath $Path
+ $absolutePath = [System.IO.Path]::GetFullPath($absolutePath)
+ Write-PSFMessage -Level Verbose "Updating path to '$absolutePath' as relative paths are not supported"
+ $Path = $absolutePath
+ }
+
+ Get-ChildItem -Path $Path -Recurse | Unblock-File
+ $packageDetails = Get-D365SDPDetails -Path $Path
+
+ $packagesFolder = "$Path\AOSService\Packages"
+ $filesFolder = Get-ChildItem -Path $packagesFolder -Directory -Filter "files"
+ if ($filesFolder.Count -eq 0) {
+ Write-PSFMessage -Level Host -Message "No /AOSService/Packages/files folder found in the package. Please ensure that the package is extracted correctly."
+ Stop-PSFFunction -Message "Stopping because of missing files folder."
+ return
+ }
+
+ $zipFiles = Get-ChildItem -Path $filesFolder.FullName -File -Filter "*.zip"
+ if ($zipFiles.Count -eq 0) {
+ Write-PSFMessage -Level Host -Message "No module zip files found in the package. Please ensure that the package is extracted correctly."
+ Stop-PSFFunction -Message "Stopping because of missing zip files."
+ return
+ }
+
+ $numberOfInstalledModules = 0
+ $packageDetails.Modules | ForEach-Object {
+ $moduleZip = $zipFiles | Where-Object Name -eq "dynamicsax-$($_.Name).$($_.Version).zip"
+ if (-not $moduleZip) {
+ Write-PSFMessage -Level Host -Message "No module zip file found for module $($_.Name). Please ensure that the package is extracted correctly."
+ Stop-PSFFunction -Message "Stopping because of missing module zip file."
+ return
+ }
+
+ # Unzip to $MetaDataDir
+ $moduleZipPath = Join-Path -Path $MetaDataDir -ChildPath $($_.Name)
+ Expand-Archive -Path $moduleZip.FullName -DestinationPath $moduleZipPath
+ Write-PSFMessage -Level Verbose -Message "Unzipped module $($_.Name) to $moduleZipPath"
+ $numberOfInstalledModules++
+ }
+
+ Write-PSFMessage -Level Host -Message "Installed $numberOfInstalledModules module(s) into $MetaDataDir"
+
+ Invoke-TimeSignal -End
+
+}
\ No newline at end of file
diff --git a/d365fo.tools/tests/functions/Invoke-D365SDPInstall.Tests.ps1 b/d365fo.tools/tests/functions/Invoke-D365SDPInstall.Tests.ps1
index d36341f9..5e0e1e3b 100644
--- a/d365fo.tools/tests/functions/Invoke-D365SDPInstall.Tests.ps1
+++ b/d365fo.tools/tests/functions/Invoke-D365SDPInstall.Tests.ps1
@@ -8,7 +8,7 @@
Describe "Ensuring unchanged command signature" {
It "should have the expected parameter sets" {
- (Get-Command Invoke-D365SDPInstall).ParameterSets.Name | Should -Be 'QuickInstall', 'DevInstall', 'Manual'
+ (Get-Command Invoke-D365SDPInstall).ParameterSets.Name | Should -Be 'QuickInstall', 'DevInstall', 'Manual', 'UDEInstall'
}
It 'Should have the expected parameter Path' {
@@ -167,6 +167,19 @@
$parameter.ParameterSets['__AllParameterSets'].ValueFromPipelineByPropertyName | Should -Be $False
$parameter.ParameterSets['__AllParameterSets'].ValueFromRemainingArguments | Should -Be $False
}
+ It 'Should have the expected parameter UnifiedDevelopmentEnvironment' {
+ $parameter = (Get-Command Invoke-D365SDPInstall).Parameters['UnifiedDevelopmentEnvironment']
+ $parameter.Name | Should -Be 'UnifiedDevelopmentEnvironment'
+ $parameter.ParameterType.ToString() | Should -Be System.Management.Automation.SwitchParameter
+ $parameter.IsDynamic | Should -Be $False
+ $parameter.ParameterSets.Keys | Should -Be 'UDEInstall'
+ $parameter.ParameterSets.Keys | Should -Contain 'UDEInstall'
+ $parameter.ParameterSets['UDEInstall'].IsMandatory | Should -Be $False
+ $parameter.ParameterSets['UDEInstall'].Position | Should -Be -2147483648
+ $parameter.ParameterSets['UDEInstall'].ValueFromPipeline | Should -Be $False
+ $parameter.ParameterSets['UDEInstall'].ValueFromPipelineByPropertyName | Should -Be $False
+ $parameter.ParameterSets['UDEInstall'].ValueFromRemainingArguments | Should -Be $False
+ }
}
Describe "Testing parameterset QuickInstall" {
@@ -187,5 +200,11 @@
Manual -Path -MetaDataDir -Command -Step -RunbookId -LogPath -ShowOriginalProgress -OutputCommandOnly -TopologyFile -UseExistingTopologyFile
#>
}
+ Describe "Testing parameterset UDEInstall" {
+ <#
+ UDEInstall -Path
+ UDEInstall -Path -MetaDataDir -Step -RunbookId -LogPath -ShowOriginalProgress -OutputCommandOnly -TopologyFile -UseExistingTopologyFile -UnifiedDevelopmentEnvironment
+ #>
+ }
}
\ No newline at end of file
diff --git a/d365fo.tools/tests/functions/Invoke-D365SDPInstallUDE.Tests.ps1 b/d365fo.tools/tests/functions/Invoke-D365SDPInstallUDE.Tests.ps1
new file mode 100644
index 00000000..105d3d16
--- /dev/null
+++ b/d365fo.tools/tests/functions/Invoke-D365SDPInstallUDE.Tests.ps1
@@ -0,0 +1,62 @@
+Describe "Invoke-D365SDPInstallUDE 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 Invoke-D365SDPInstallUDE).ParameterSets.Name | Should -Be '__AllParameterSets'
+ }
+
+ It 'Should have the expected parameter Path' {
+ $parameter = (Get-Command Invoke-D365SDPInstallUDE).Parameters['Path']
+ $parameter.Name | Should -Be 'Path'
+ $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 $True
+ $parameter.ParameterSets['__AllParameterSets'].Position | Should -Be 1
+ $parameter.ParameterSets['__AllParameterSets'].ValueFromPipeline | Should -Be $False
+ $parameter.ParameterSets['__AllParameterSets'].ValueFromPipelineByPropertyName | Should -Be $False
+ $parameter.ParameterSets['__AllParameterSets'].ValueFromRemainingArguments | Should -Be $False
+ }
+ It 'Should have the expected parameter MetaDataDir' {
+ $parameter = (Get-Command Invoke-D365SDPInstallUDE).Parameters['MetaDataDir']
+ $parameter.Name | Should -Be 'MetaDataDir'
+ $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 $True
+ $parameter.ParameterSets['__AllParameterSets'].Position | Should -Be 2
+ $parameter.ParameterSets['__AllParameterSets'].ValueFromPipeline | Should -Be $False
+ $parameter.ParameterSets['__AllParameterSets'].ValueFromPipelineByPropertyName | Should -Be $False
+ $parameter.ParameterSets['__AllParameterSets'].ValueFromRemainingArguments | Should -Be $False
+ }
+ It 'Should have the expected parameter LogPath' {
+ $parameter = (Get-Command Invoke-D365SDPInstallUDE).Parameters['LogPath']
+ $parameter.Name | Should -Be 'LogPath'
+ $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 -2147483648
+ $parameter.ParameterSets['__AllParameterSets'].ValueFromPipeline | Should -Be $False
+ $parameter.ParameterSets['__AllParameterSets'].ValueFromPipelineByPropertyName | Should -Be $False
+ $parameter.ParameterSets['__AllParameterSets'].ValueFromRemainingArguments | Should -Be $False
+ }
+ }
+
+ Describe "Testing parameterset __AllParameterSets" {
+ <#
+ __AllParameterSets -Path -MetaDataDir
+ __AllParameterSets -Path -MetaDataDir -LogPath
+ #>
+ }
+
+}
\ No newline at end of file
diff --git a/docs/Invoke-D365SDPInstall.md b/docs/Invoke-D365SDPInstall.md
index d7f14ebc..ce3158f4 100644
--- a/docs/Invoke-D365SDPInstall.md
+++ b/docs/Invoke-D365SDPInstall.md
@@ -8,7 +8,7 @@ schema: 2.0.0
# Invoke-D365SDPInstall
## SYNOPSIS
-Invoke the AxUpdateInstaller.exe file from Software Deployable Package (SDP)
+Install a Software Deployable Package (SDP)
## SYNTAX
@@ -33,9 +33,17 @@ Invoke-D365SDPInstall [-Path] [[-MetaDataDir] ] [-Command] ] [-UseExistingTopologyFile] []
```
+### UDEInstall
+```
+Invoke-D365SDPInstall [-Path] [[-MetaDataDir] ] [[-Step] ] [[-RunbookId] ]
+ [-LogPath ] [-ShowOriginalProgress] [-OutputCommandOnly] [-TopologyFile ]
+ [-UseExistingTopologyFile] [-UnifiedDevelopmentEnvironment] []
+```
+
## DESCRIPTION
A cmdlet that wraps some of the cumbersome work into a streamlined process.
-The process are detailed in the Microsoft documentation here:
+The process for a legacy (i.e.
+non unified) environment are detailed in the Microsoft documentation here:
https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/deployment/install-deployable-package
## EXAMPLES
@@ -104,6 +112,13 @@ Invoke-D365SDPInstall -Path "c:\temp\" -Command RunAll -TopologyFile "c:\temp\My
Run all manual steps in one single operation using the MyTopology.xml file.
The topology file is not updated.
+### EXAMPLE 9
+```
+Invoke-D365SDPInstall -Path "c:\temp\" -MetaDataDir "c:\MyRepository\Metadata" -UnifiedDevelopmentEnvironment
+```
+
+Install the modules contained in the c:\temp\ directory into the c:\MyRepository\Metadata directory.
+
## PARAMETERS
### -Path
@@ -313,6 +328,21 @@ Accept pipeline input: False
Accept wildcard characters: False
```
+### -UnifiedDevelopmentEnvironment
+Use this switch to install the package in a Unified Development Environment (UDE).
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: UDEInstall
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+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).
@@ -327,3 +357,6 @@ Author: Mötz Jensen (@Splaxi)
Inspired by blogpost http://dev.goshoom.net/en/2016/11/installing-deployable-packages-with-powershell/
## RELATED LINKS
+
+[Invoke-D365SDPInstallUDE]()
+
diff --git a/docs/Invoke-D365SDPInstallUDE.md b/docs/Invoke-D365SDPInstallUDE.md
new file mode 100644
index 00000000..5be0796e
--- /dev/null
+++ b/docs/Invoke-D365SDPInstallUDE.md
@@ -0,0 +1,93 @@
+---
+external help file: d365fo.tools-help.xml
+Module Name: d365fo.tools
+online version:
+schema: 2.0.0
+---
+
+# Invoke-D365SDPInstallUDE
+
+## SYNOPSIS
+Install a Software Deployable Package (SDP) in a unified development environment
+
+## SYNTAX
+
+```
+Invoke-D365SDPInstallUDE [-Path] [-MetaDataDir] [-LogPath ] []
+```
+
+## DESCRIPTION
+A cmdlet that wraps some of the cumbersome work into a streamlined process.
+It first checks if the package is a zip file and extracts it if necessary.
+Then it checks if the package contains the necessary files and modules.
+Finally, it extracts the module zip files into the metadata directory.
+
+## EXAMPLES
+
+### EXAMPLE 1
+```
+Invoke-D365SDPInstallUDE -Path "c:\temp\package.zip" -MetaDataDir "c:\MyRepository\Metadata"
+```
+
+This will install the modules contained in the c:\temp\package.zip file into the c:\MyRepository\Metadata directory.
+
+## PARAMETERS
+
+### -Path
+Path to the package that you want to install into the environment
+
+The cmdlet supports a path to a zip-file or directory with the unpacked contents.
+
+```yaml
+Type: String
+Parameter Sets: (All)
+Aliases: File, Hotfix
+
+Required: True
+Position: 2
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -MetaDataDir
+The path to the meta data directory for the environment
+
+```yaml
+Type: String
+Parameter Sets: (All)
+Aliases:
+
+Required: True
+Position: 3
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -LogPath
+The path where the log file(s) will be saved
+
+```yaml
+Type: String
+Parameter Sets: (All)
+Aliases: LogDir
+
+Required: False
+Position: Named
+Default value: $(Join-Path -Path $Script:DefaultTempPath -ChildPath "Logs\SdpInstall")
+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
+Author: Florian Hopfner (@FH-Inway)
+
+## RELATED LINKS