diff --git a/.editorconfig b/.editorconfig index 6d04bb5..fc01090 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,3 +11,7 @@ end_of_line = crlf [*.md] trim_trailing_whitespace = false + +[*.ps1] +indent_style = tab +tab_width = 2 diff --git a/README.md b/README.md index 069c4b9..f63cbbb 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # generator-nullfactory-xrm -> Dynamics CRM Solution Template +> Scaffolding Template for Dynamics CRM/365 Solutions [![Build status](https://ci.appveyor.com/api/projects/status/4dmqta7pnueqxa11?svg=true)](https://ci.appveyor.com/project/shanec-/generator-nullfactory-xrm) -A yeoman template for managing [Solution Packager](https://msdn.microsoft.com/en-us/library/jj602987.aspx)-compatible Dynamics CRM solutions. +A yeoman tempate for scaffolding [Solution Packager](https://msdn.microsoft.com/en-us/library/jj602987.aspx)-compatible Dynamics CRM (365) solution structure. + +The generated project structure is built around the Solution Packager provided in the official SDK and the [Microsoft.Xrm.Data.PowerShell](https://github.com/seanmcne/Microsoft.Xrm.Data.PowerShell) module. It facilitates the quick creation of team builds and release strategies with minimal effort and enables you to maintain a single source of truth for you CRM solutions. ## Installation @@ -48,7 +50,7 @@ Optionally, install the [`Microsoft.Xrm.Data.PowerShell`](https://github.com/sea Install-Module -Name Microsoft.Xrm.Data.PowerShell -Scope CurrentUser -Force ``` -Even if you skip the above step, the sychrnoization powershell script would attempt to install it automatically. +Even if you skip the above step, the sychrnoization PowerShell script would attempt to install it automatically. The PowerShell scripts require a minimum of PowerShell 5.0 and Microsoft.Xrm.Data.PowerShell 2.5. ## Syncing a Solution to the Project @@ -71,6 +73,7 @@ More information on source control management, setting up continuous integration - [Release Strategy for Dynamics CRM - Part 2 - Setting Up the Build](http://www.nullfactory.net/2016/11/release-strategy-for-dynamics-crm-setting-up-the-build-part-2/) - [Release Strategy for Dynamics CRM - Part 3 - Setting Up the Release](http://www.nullfactory.net/2016/11/release-strategy-for-dynamics-crm-setting-up-the-release-part-3/) - [Release Strategy for Dynamics CRM - Part 4 - Versioning](http://www.nullfactory.net/2017/02/release-strategy-for-dynamics-crm-versioning-part-4/) +- [Release Strategy for Dynamics CRM - Part 5 - Deploy Third-Party Solutions](http://www.nullfactory.net/2017/04/release-strategy-for-dynamics-crm-deploying-third-party-solutions-part-5/) ## Feedback diff --git a/generators/app/index.js b/generators/app/index.js index dd545b6..4468583 100644 --- a/generators/app/index.js +++ b/generators/app/index.js @@ -131,9 +131,13 @@ module.exports = yeoman.Base.extend({ this.destinationPath('Nullfactory.Xrm.Tooling/_Install/Install-Microsoft.Xrm.Data.PowerShell.ps1') ); - this.fs.copy( + this.fs.copyTpl( this.templatePath('Nullfactory.Xrm.Tooling/Mappings/solution-mapping.xml'), - this.destinationPath('Nullfactory.Xrm.Tooling/Mappings/' + this.props.crmSolutionName + '-mapping.xml') + this.destinationPath('Nullfactory.Xrm.Tooling/Mappings/' + this.props.crmSolutionName + '-mapping.xml'), { + visualStudioSolutionProjectPrefix: this.props.visualStudioSolutionProjectPrefix, + isAddPluginProject: this.props.isAddPluginProject, + isAddWorkflowProject: this.props.isAddWorkflowProject + } ); this.fs.copy( diff --git a/generators/app/templates/Nullfactory.Xrm.Tooling/Mappings/solution-mapping.xml b/generators/app/templates/Nullfactory.Xrm.Tooling/Mappings/solution-mapping.xml index d6ec678..090f75a 100644 --- a/generators/app/templates/Nullfactory.Xrm.Tooling/Mappings/solution-mapping.xml +++ b/generators/app/templates/Nullfactory.Xrm.Tooling/Mappings/solution-mapping.xml @@ -3,4 +3,12 @@ + +<% if (isAddPluginProject == true) { %> + +<% } %> +<% if (isAddWorkflowProject == true) { %> + +<% } %> + diff --git a/generators/app/templates/Nullfactory.Xrm.Tooling/Nullfactory.Xrm.Tooling.csproj b/generators/app/templates/Nullfactory.Xrm.Tooling/Nullfactory.Xrm.Tooling.csproj index ace5079..1d29aa3 100644 --- a/generators/app/templates/Nullfactory.Xrm.Tooling/Nullfactory.Xrm.Tooling.csproj +++ b/generators/app/templates/Nullfactory.Xrm.Tooling/Nullfactory.Xrm.Tooling.csproj @@ -1,4 +1,5 @@  + @@ -30,23 +31,17 @@ 4 - - - - - - @@ -56,6 +51,7 @@ + diff --git a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/ApplyVersionToArtifact.ps1 b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/ApplyVersionToArtifact.ps1 index bcda55f..fd500fd 100644 --- a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/ApplyVersionToArtifact.ps1 +++ b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/ApplyVersionToArtifact.ps1 @@ -1,3 +1,27 @@ +<# + .SYNOPSIS + Recursively finds a list of files and uses a pattern to match and replace matches with a specified version number. + .DESCRIPTION + Recursively finds a list of files within a folder and uses a regular expression pattern to match and replace it with a specified version number. + .NOTES + Author: Shane Carvalho + Version: generator-nullfactory-xrm@1.4.0 + .LINK + https://nullfactory.net + .PARAMETER BuildSourcePath + The root folder to search. + .PARAMETER versionFile + The pattern of file to be searched. + .PARAMETER regexPattern + The regex pattern to be searched. + .PARAMETER finalVersion + The new version number. + .PARAMETER encoding + The optional encoding. Common encoding values include ASCII, Unicode, UTF8, Default. Default uses the encoding of the system's current ANSI code page. + .EXAMPLE + ReplaceVersion ".\SourceRootFolder" "*AssemblyInfo.cs" "\d+\.\d+\.\d+\.\d+" "1.3.0" + Gets a list of all files starting with "*AssemblyInfo.cs" within the folder "SourceRootFolder". Within these files it attempts to match all instances of a version number ex. 0.0.0.0 and replace it with the new version number. +#> function ReplaceVersion([string]$BuildSourcePath, [string] $versionFile, [string] $regexPattern, [string]$finalVersion, [string]$encoding='Default') { [bool]$output = $false @@ -19,6 +43,16 @@ function ReplaceVersion([string]$BuildSourcePath, [string] $versionFile, [string return $output } +<# + .SYNOPSIS + Applies a specified version number to a list of file matching a pattern. + .PARAMETER BuildSourcePath + The root folder containing the source files. + .PARAMETER BuildBuildNumber + The new build number. + .EXAMPLE + ApplyVersionToAssemblies ".\RootFolder" "0.1.2" +#> function ApplyVersionToAssemblies { [CmdletBinding()] @@ -40,6 +74,16 @@ function ApplyVersionToAssemblies } } +<# + .SYNOPSIS + Applies a specified version number to a CRM solution. + .PARAMETER BuildSourcePath + The root folder containing the extracted (via solutio packager) CRM Solution. + .PARAMETER BuildBuildNumber + The new build number. + .EXAMPLE + ApplyVersionToCrmSolution ".\RootFolder" "0.1.2" +#> function ApplyVersionToCrmSolution { [CmdletBinding()] diff --git a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/CrmSolution.Common.ps1 b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/CrmSolution.Common.ps1 index 12ac817..a6149a3 100644 --- a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/CrmSolution.Common.ps1 +++ b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/CrmSolution.Common.ps1 @@ -1,4 +1,19 @@ -function GetUsername($solutionName) +<# + .SYNOPSIS + Retrieves the username for the specified CRM solution. + .DESCRIPTION + Retrieves the username for the specified CRM solution which is stored in a user-environmental variable. If one does not exist, the script would prompt the user for a new username, which is then stored in a new environment variable. + .NOTES + Author: Shane Carvalho + Version: generator-nullfactory-xrm@1.4.0 + .LINK + https://nullfactory.net + .PARAMETER solutionName + The name of the CRM solution. + .EXAMPLE + $username = Get-CrmUsername("Nullfactory.Solution1") +#> +function Get-CrmUsername($solutionName) { $variableName = "nfac_" + $solutionName + "_username" $username = [environment]::GetEnvironmentVariable($variableName, "User") @@ -12,7 +27,18 @@ function GetUsername($solutionName) return $username; } -function GetPassword($solutionName) +<# + .SYNOPSIS + Retrieves the password for the specified CRM solution. + .DESCRIPTION + Retrieves the password for the specified CRM solution which is stored in a user-environmental variable. If one does not exist, the script would prompt the user for a new password, which is then stored in a new environment variable. + Note that the password is stored as plain-text. + .PARAMETER solutionName + The name of the CRM solution. + .EXAMPLE + $username = Get-CrmPassword("Nullfactory.Solution1") +#> +function Get-CrmPassword($solutionName) { $variableName = "nfac_" + $solutionName + "_password" $plainTextPassword = [environment]::GetEnvironmentVariable($variableName, "User") diff --git a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Deploy-CrmSolution.Param.ps1 b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Deploy-CrmSolution.Param.ps1 index 139d45b..ed21fa8 100644 --- a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Deploy-CrmSolution.Param.ps1 +++ b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Deploy-CrmSolution.Param.ps1 @@ -1,24 +1,47 @@ +<# + .SYNOPSIS + Manually deploy the CRM Solutions to the remote CRM servers. + .DESCRIPTION + Manually deploy the CRM solution to the configured remote CRM servers. + .NOTES + Author: Shane Carvalho + Version: generator-nullfactory-xrm@1.4.0 + .LINK + https://nullfactory.net +#> + # Importing common functions . .\CrmSolution.Common.ps1 -Write-Host "Attempting to deploy solution(s)..." +# Defaulting to increased verbosity for manual execution +$oldverbose = $VerbosePreference +$VerbosePreference = "continue" -.\Deploy-CrmSolution.ps1 ` - -serverUrl "<%= crmServerUrl %>" ` - -username (GetUsername "<%= crmSolutionName %>") ` - -password (GetPassword "<%= crmSolutionName %>") ` - -solutionName "<%= crmSolutionName %>" ` - -publishChanges ` - -activatePlugins +Write-Host "Attempting to deploy solution(s)..." +try +{ + .\Deploy-CrmSolution.ps1 ` + -serverUrl "<%= crmServerUrl %>" ` + -username (Get-CrmUsername "<%= visualStudioSolutionProjectPrefix %>.<%= crmSolutionName %>") ` + -password (Get-CrmPassword "<%= visualStudioSolutionProjectPrefix %>.<%= crmSolutionName %>") ` + -solutionName "<%= visualStudioSolutionProjectPrefix %>.<%= crmSolutionName %>" ` + -publishChanges ` + -activatePlugins -# Include new entry for each CRM solution to be released manually + # Include new entry for each CRM solution to be released manually -# .\Deploy-CrmSolution.ps1 ` -# -serverUrl "http://servername/secondary" ` -# -username (GetUsername "env_secondary_username_key") ` -# -password (GetPassword "env_secondary_password_key") ` -# -solutionName "secondary" ` -# -publishChanges ` -# -activatePlugins + # .\Deploy-CrmSolution.ps1 ` + # -serverUrl "http://servername/secondary" ` + # -username (GetUsername "env_secondary_username_key") ` + # -password (GetPassword "env_secondary_password_key") ` + # -solutionName "secondary" ` + # -publishChanges ` + # -activatePlugins -Write-Host "Deployment(s) complete." -ForegroundColor Green + Write-Host "Deployment(s) complete." -ForegroundColor Green +} +finally +{ + # Reset the verbosity to original level + $VerbosePreference = $oldverbose +} diff --git a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Deploy-CrmSolution.ps1 b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Deploy-CrmSolution.ps1 index 9032fba..6f7828a 100644 --- a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Deploy-CrmSolution.ps1 +++ b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Deploy-CrmSolution.ps1 @@ -1,6 +1,53 @@ -# -# Deploy-CrmSolution.ps1 -# +<# + + .SYNOPSIS + Deploy a CRM Solution to a remote server. + .DESCRIPTION + This scripts automatically connect to a remote Dynamics CRM instance using the provided credentials and deploys the specified solution. Works with both on-premises and online solutions. + + Pre-requisites: + - PowerShell V5 or greater + - Latest version of Solution Packager tool provided with the CRM SDK. + - Micrsoft.Xrm.Data.Powershell 2.4 or greater + + .NOTES + Author: Shane Carvalho + Version: generator-nullfactory-xrm@1.4.0 + .LINK + https://nullfactory.net + .PARAMETER serverUrl + Mandatory parameter that specifies the server url of the Dynamics CRM instance being deployed to. + .PARAMETER username + Mandatory paramater is the username used to connect to Dynamics CRM. + .PARAMETER password + Mandatory paramerter is the password of the user used to connect to Dynamics CRM. + .PARAMETER solutionName + Required paramter. The name of the solution that needs to be downloaded and extracted. + .PARAMETER isOnPremServer + This optional switch tells the script if the server is an OnPremises server. CRM Online is the default provider. + .PARAMETER deployManagedSolution + This optional switch tells the script that it should deploy the managed version of the solution`. The unmanaged version is selected by default. + .PARAMETER activatePlugIns + This optional switch tells the script that it should attempt to activate plugins that have been included as part of the solution. Defaults to false. + .PARAMETER publishChanges + This optional switch tells the script that it should publish changes once deployed. Defaults to false. + .PARAMETER importAsHoldingSolution + This optional switch tells the script that it should import the solution as a hold solution. + .EXAMPLE + .\Deploy-CrmSolution.ps1 -serverUrl "https://sndbx.crm6.dynamics.com" -username "admin@sndx.onmicrosoft.com" -password "P@ssw0rd!" -solutionName "RemoteSolutionName" + Deploys the unmanaged version of "RemoteSolutionName" to the "https://sndbx.crm6.dynamics.com" dynamics crm online server. + .EXAMPLE + .\Deploy-CrmSolution.ps1 -serverUrl "https://sndbx.crm6.dynamics.com" -username "admin@sndx.onmicrosoft.com" -password "P@ssw0rd!" -solutionName "RemoteSolutionName" -deployManagedSolution -isOnPremServer + Deploys the managed version of "RemoteSolutionName" to the "https://sndbx.crm6.dynamics.com" dynamics crm on premises server and extract it to the "RemoteSolutionRoot" folder using the "RemoteSolutionName-mapping.xml" mapping file. + .EXAMPLE + .\Deploy-CrmSolution.ps1 -serverUrl "https://onpremserver/orgname" -username "admin@sndx.onmicrosoft.com" -password "P@ssw0rd!" -solutionName "RemoteSolutionName" -isOnPremServer -activatePlugIns -publishChanges -importAsHoldingSolution + Deploys the unmanaged version of "RemoteSolutionName" to the "https://onpremserver/orgname" dynamics crm onprem server as an holding solution. Once deployed, activate plugins and publish changes. + .EXAMPLE + .\Deploy-CrmSolution.ps1 -serverUrl "https://sndbx.crm6.dynamics.com" -username "admin@sndx.onmicrosoft.com" -password "P@ssw0rd!" -externalSolutionFileName ".\ThirdPartySolution.zip" -activatePlugIns -publishChanges + Deploys "ThirdPartySolution.zip" solution to the "https://sndbx.crm6.dynamics.com" dynamics crm online. Once deployed, activate plugins and publish changes. + +#> +[CmdletBinding(DefaultParameterSetName="Internal")] param( [Parameter(Mandatory=$true, Position=1)] [string]$serverUrl, @@ -8,18 +55,20 @@ param( [string]$username, [Parameter(Mandatory=$true, Position=3)] [string]$password, - [Parameter(Mandatory=$true, Position=4)] + [Parameter(ParameterSetName='Internal',Mandatory=$true, Position=4)] [string]$solutionName, + [Parameter(ParameterSetName='Internal')] + [switch]$deployManagedSolution, + [Parameter(ParameterSetName='External',Mandatory=$true)] + [string]$externalSolutionFileName, [Parameter(Mandatory=$false)] [switch]$isOnPremServer, [Parameter(Mandatory=$false)] - [switch]$deployManagedSolution, - [Parameter(Mandatory=$false)] - [switch]$activatePlugIns, + [switch]$activatePlugIns, [Parameter(Mandatory=$false)] [switch]$publishChanges, - [Parameter(Mandatory=$false)] - [switch]$importAsHoldingSolution + [Parameter(Mandatory=$false)] + [switch]$importAsHoldingSolution ) if (-Not (Get-Module -ListAvailable -Name Microsoft.Xrm.Data.PowerShell)) @@ -34,23 +83,37 @@ $creds = New-Object System.Management.Automation.PSCredential ($username, $secur if($isOnPremServer) { Write-Verbose "Connecting to OnPrem CRM instance $serverUrl ..." - Connect-CrmOnPremDiscovery -Credential $creds -ServerUrl $serverUrl + $connectionState = Connect-CrmOnPremDiscovery -Credential $creds -ServerUrl $serverUrl } else { Write-Verbose "Connecting to Online CRM instance $serverUrl ..." - Connect-CrmOnline -Credential $creds -ServerUrl $serverUrl + $connectionState = Connect-CrmOnline -Credential $creds -ServerUrl $serverUrl +} + +# Make sure that the connection was successful, else stop the script. +if($connectionState.IsReady -eq $false) +{ + throw $connectionState.LastCrmError } $releaseZipFileName = ""; -if (-Not $deployManagedSolution){ $releaseZipFileName = Resolve-Path("..\..\$solutionName\*\*\$solutionName.zip") } -else { $releaseZipFileName = Resolve-Path("..\..\$solutionName\*\*\$solutionName" + "_managed.zip") } +# if deploying external third party solution +if($externalSolutionFileName) +{ + $releaseZipFileName = Resolve-Path($externalSolutionFileName) +} +else +{ + if (-Not $deployManagedSolution){ $releaseZipFileName = Resolve-Path("..\..\$solutionName\*\*\$solutionName.zip") } + else { $releaseZipFileName = Resolve-Path("..\..\$solutionName\*\*\$solutionName" + "_managed.zip") } +} Write-Verbose "Importing the $releaseZipFileName solution into $serverUrl ..." Import-CrmSolution ` -SolutionFilePath $releaseZipFileName ` -PublishChanges:$publishChanges ` -ActivatePlugIns:$activatePlugIns ` - -ImportAsHoldingSolution:$importAsHoldingSolution ` + -ImportAsHoldingSolution:$importAsHoldingSolution ` -MaxWaitTimeInSeconds 900 diff --git a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Pull-CrmSolution.Param.ps1 b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Pull-CrmSolution.Param.ps1 index d7197dd..ff3f1c2 100644 --- a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Pull-CrmSolution.Param.ps1 +++ b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Pull-CrmSolution.Param.ps1 @@ -1,24 +1,47 @@ -# Importing common functions +<# + .SYNOPSIS + Manually pull and extract CRM Solutions from remote servers. + .DESCRIPTION + Manually pull and extract CRM Solutions from configured remote servers. + .NOTES + Author: Shane Carvalho + Version: generator-nullfactory-xrm@1.4.0 + .LINK + https://nullfactory.net +#> + +# Importing common functions . .\CrmSolution.Common.ps1 -Write-Host "Attempting to synchronize solution(s)..." +# Defaulting to increased verbosity for manual execution +$oldverbose = $VerbosePreference +$VerbosePreference = "continue" -.\Pull-CrmSolution.ps1 ` - -serverUrl "<%= crmServerUrl %>" ` - -username (GetUsername "<%= crmSolutionName %>") ` - -password (GetPassword "<%= crmSolutionName %>") ` - -solutionName "<%= crmSolutionName %>" ` - -solutionRootFolder "..\..\<%= visualStudioSolutionProjectPrefix %>.<%= crmSolutionName %>" ` - -solutionMapFile "..\..\Nullfactory.Xrm.Tooling\Mappings\<%= crmSolutionName %>-mapping.xml" +Write-Host "Attempting to pull solution(s)..." +try +{ + .\Pull-CrmSolution.ps1 ` + -serverUrl "<%= crmServerUrl %>" ` + -username (Get-CrmUsername "<%= visualStudioSolutionProjectPrefix %>.<%= crmSolutionName %>") ` + -password (Get-CrmPassword "<%= visualStudioSolutionProjectPrefix %>.<%= crmSolutionName %>") ` + -solutionName "<%= crmSolutionName %>" ` + -solutionRootFolder "..\..\<%= visualStudioSolutionProjectPrefix %>.<%= crmSolutionName %>" ` + -solutionMapFile "..\..\Nullfactory.Xrm.Tooling\Mappings\<%= crmSolutionName %>-mapping.xml" -# Include a new entry for each CRM solution to be synced against a project folder + # Include a new entry for each CRM solution to be synced against a project folder -# .\Pull-CrmSolution.ps1 ` -# -serverUrl "http://servername/secondary" ` -# -username (GetUsername "env_secondary_username_key") ` -# -password (GetPassword "env_secondary_password_key") ` -# -solutionName "secondary" ` -# -solutionRootFolder "..\..\Demo.Solutions.Secondary" ` -# -solutionMapFile "..\..\Nullfactory.Xrm.Tooling\Mappings\secondary-mapping.xml" + # .\Pull-CrmSolution.ps1 ` + # -serverUrl "http://servername/secondary" ` + # -username (GetUsername "env_secondary_username_key") ` + # -password (GetPassword "env_secondary_password_key") ` + # -solutionName "secondary" ` + # -solutionRootFolder "..\..\Demo.Solutions.Secondary" ` + # -solutionMapFile "..\..\Nullfactory.Xrm.Tooling\Mappings\secondary-mapping.xml" -Write-Host "Synchronization complete." -ForegroundColor Green + Write-Host "Solution pull complete." -ForegroundColor Green +} +finally +{ + # Reset the verbosity to original level + $VerbosePreference = $oldverbose +} diff --git a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Pull-CrmSolution.ps1 b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Pull-CrmSolution.ps1 index f33b2c6..bcbcfdb 100644 --- a/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Pull-CrmSolution.ps1 +++ b/generators/app/templates/Nullfactory.Xrm.Tooling/Scripts/Pull-CrmSolution.ps1 @@ -1,6 +1,45 @@ -# -# Pull-CrmSolution.ps1 -# +<# + + .SYNOPSIS + Download a solution from a remote CRM server and extract to a specified folder location. + .DESCRIPTION + This scripts automatically connect to a remote dynamics CRM instance, downloads a specified CRM solution and unpacks it to the specified folder via the Solution Packager tool. Works with both on-premises and online solutions. + + Pre-requisites: + - PowerShell V5 or greater + - Latest version of Solution Packager tool provided with the CRM SDK. + - Micrsoft.Xrm.Data.Powershell 2.4 or greater + + .NOTES + Author: Shane Carvalho + Version: generator-nullfactory-xrm@1.4.0 + .LINK + https://nullfactory.net + .PARAMETER serverUrl + Required parameter that specifies the server url of the Dynamics CRM instance. + .PARAMETER username + Mandatory paramater is the username used to connect to Dynamics CRM. + .PARAMETER password + Mandatory paramerter is the password of the user used to connect to Dynamics CRM. + .PARAMETER solutionName + Required paramter. The name of the solution that needs to be downloaded and extracted. + .PARAMETER solutionRootFolder + Required Parameter. The folder into which the solution will be extracted to. + .PARAMETER isOnPremServer + This optional switch that tells the script if the server is an OnPremises server. CRM Online is the default provider. + .PARAMETER solutionMapFile + This is an option parameter that specifies the path of the maping file used to be used by SolutionPackager. + .EXAMPLE + .\Pull-CrmSolution.ps1 -serverUrl "https://sndbx.crm6.dynamics.com" -username "admin@sndx.onmicrosoft.com" -password "P@ssw0rd!" -solutionName "RemoteSolutionName" -solutionRootFolder ".\RemoteSolutionRoot" + Download remote solution "RemoteSolutionName" from the "https://sndbx.crm6.dynamics.com" dynamics crm online server and extract it to the "RemoteSolutionRoot" folder. + .EXAMPLE + .\Pull-CrmSolution.ps1 -serverUrl "https://sndbx.crm6.dynamics.com" -username "admin@sndx.onmicrosoft.com" -password "P@ssw0rd!" -solutionName "RemoteSolutionName" -solutionRootFolder ".\RemoteSolutionRoot" -solutionMapFile ".\RemoteSolutionName-mapping.xml" + Download remote solution "RemoteSolutionName" from the "https://sndbx.crm6.dynamics.com" dynamics crm online server and extract it to the "RemoteSolutionRoot" folder using the "RemoteSolutionName-mapping.xml" mapping file. + .EXAMPLE + .\Pull-CrmSolution.ps1 -serverUrl "https://onpremserver.local/orgname" -username "admin@local" -password "P@ssw0rd!" -solutionName "RemoteSolutionName" -solutionRootFolder ".\RemoteSolutionRoot" -isOnPremServer + Download remote solution "RemoteSolutionName" from the "https://onpremserver/orgname" on premises server and extract it to the "RemoteSolutionRoot". + +#> param( [Parameter(Mandatory=$true)] [string]$serverUrl, @@ -30,17 +69,24 @@ $creds = New-Object System.Management.Automation.PSCredential ($username, $secur if($isOnPremServer) { Write-Verbose "Connecting to the OnPrem crm instance $serverUrl ..." - Connect-CrmOnPremDiscovery -Credential $creds -ServerUrl $serverUrl + $connectionState = Connect-CrmOnPremDiscovery -Credential $creds -ServerUrl $serverUrl } else { Write-Verbose "Connecting to the Online crm instance $serverUrl ..." - Connect-CrmOnline -Credential $creds -ServerUrl $serverUrl + $connectionState = Connect-CrmOnline -Credential $creds -ServerUrl $serverUrl +} + +# Make sure that the connection was successful, else stop the script. +if($connectionState.IsReady -eq $false) +{ + throw $connectionState.LastCrmError } $exportZipFileName = $solutionName + "_export.zip" $exportZipFileNameManaged = $solutionName + "_export_Managed.zip" +# Clear previous instances of the exported solution file if (Test-Path $exportZipFileName) { Remove-Item $exportZipFileName } if (Test-Path $exportZipFileNameManaged) { Remove-Item $exportZipFileNameManaged } @@ -53,7 +99,7 @@ Export-CrmSolution -SolutionName $solutionName -Managed -SolutionZipFileName $ex Write-Verbose "Delete the source controlled artifacts while keeping the project file intact..." Remove-Item -Recurse $solutionRootFolder -Force -exclude *.csproj -Write-Verbose "Extracing previous generated solution..." +Write-Verbose "Unpacking exported solution..." if($solutionMapFile -eq "") { .\..\bin\coretools\SolutionPackager.exe ` @@ -65,7 +111,7 @@ if($solutionMapFile -eq "") } else { - Write-Verbose "using mapping file $solutionMapFile for packaging" + Write-Verbose "Using mapping file $solutionMapFile for unpacking" .\..\bin\coretools\SolutionPackager.exe ` /a:extract ` /packagetype:both ` @@ -74,3 +120,13 @@ else /ad:no ` /map:"$solutionMapFile" } + +# Verify that the solution packager ran successfully. +if($?) +{ + Write-Verbose "Unpack successful!" +} +else +{ + throw "SolutionPackager unpack failed." +} diff --git a/generators/app/templates/Nullfactory.Xrm.Tooling/packages.config b/generators/app/templates/Nullfactory.Xrm.Tooling/packages.config index a2fa232..6fe5dda 100644 --- a/generators/app/templates/Nullfactory.Xrm.Tooling/packages.config +++ b/generators/app/templates/Nullfactory.Xrm.Tooling/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/generators/app/templates/Project.Solution.WebResources/Project.Solution.WebResources.csproj b/generators/app/templates/Project.Solution.WebResources/Project.Solution.WebResources.csproj index 6738a70..1933054 100644 --- a/generators/app/templates/Project.Solution.WebResources/Project.Solution.WebResources.csproj +++ b/generators/app/templates/Project.Solution.WebResources/Project.Solution.WebResources.csproj @@ -1,4 +1,5 @@  + @@ -67,4 +68,4 @@ - \ No newline at end of file + diff --git a/generators/app/templates/Project.Xrm.Plugins/Project.Xrm.Plugins.csproj b/generators/app/templates/Project.Xrm.Plugins/Project.Xrm.Plugins.csproj index 3359979..27b4610 100644 --- a/generators/app/templates/Project.Xrm.Plugins/Project.Xrm.Plugins.csproj +++ b/generators/app/templates/Project.Xrm.Plugins/Project.Xrm.Plugins.csproj @@ -1,4 +1,5 @@  + @@ -37,7 +38,7 @@ - ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.1.0.2\lib\net452\Microsoft.Crm.Sdk.Proxy.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.2.0.2\lib\net452\Microsoft.Crm.Sdk.Proxy.dll True @@ -45,7 +46,7 @@ True - ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.1.0.2\lib\net452\Microsoft.Xrm.Sdk.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.2.0.2\lib\net452\Microsoft.Xrm.Sdk.dll True @@ -73,11 +74,11 @@ - - \ No newline at end of file + diff --git a/generators/app/templates/Project.Xrm.Plugins/SimplePlugin.cs b/generators/app/templates/Project.Xrm.Plugins/SimplePlugin.cs index 94d0935..dfc7785 100644 --- a/generators/app/templates/Project.Xrm.Plugins/SimplePlugin.cs +++ b/generators/app/templates/Project.Xrm.Plugins/SimplePlugin.cs @@ -9,15 +9,11 @@ public void Execute(IServiceProvider serviceProvider) { IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); - IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); - IOrganizationService organizationService = (IOrganizationService)serviceProvider.GetService(typeof(IOrganizationService)); - - } } } diff --git a/generators/app/templates/Project.Xrm.Plugins/packages.config b/generators/app/templates/Project.Xrm.Plugins/packages.config index 69eb01b..7d0c2c0 100644 --- a/generators/app/templates/Project.Xrm.Plugins/packages.config +++ b/generators/app/templates/Project.Xrm.Plugins/packages.config @@ -1,5 +1,5 @@  - + - \ No newline at end of file + diff --git a/generators/app/templates/Project.Xrm.Workflows/Project.Xrm.Workflows.csproj b/generators/app/templates/Project.Xrm.Workflows/Project.Xrm.Workflows.csproj index fe21959..e4291be 100644 --- a/generators/app/templates/Project.Xrm.Workflows/Project.Xrm.Workflows.csproj +++ b/generators/app/templates/Project.Xrm.Workflows/Project.Xrm.Workflows.csproj @@ -1,4 +1,5 @@  + @@ -37,7 +38,7 @@ - ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.1.0.2\lib\net452\Microsoft.Crm.Sdk.Proxy.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.2.0.2\lib\net452\Microsoft.Crm.Sdk.Proxy.dll True @@ -45,11 +46,11 @@ True - ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.1.0.2\lib\net452\Microsoft.Xrm.Sdk.dll + ..\packages\Microsoft.CrmSdk.CoreAssemblies.8.2.0.2\lib\net452\Microsoft.Xrm.Sdk.dll True - ..\packages\Microsoft.CrmSdk.Workflow.8.1.0.2\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + ..\packages\Microsoft.CrmSdk.Workflow.8.2.0.2\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll True @@ -83,11 +84,11 @@ - - \ No newline at end of file + diff --git a/generators/app/templates/Project.Xrm.Workflows/packages.config b/generators/app/templates/Project.Xrm.Workflows/packages.config index 09b360b..56ce184 100644 --- a/generators/app/templates/Project.Xrm.Workflows/packages.config +++ b/generators/app/templates/Project.Xrm.Workflows/packages.config @@ -1,6 +1,6 @@  - - + + - \ No newline at end of file + diff --git a/package.json b/package.json index d21e4fd..34f27b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "generator-nullfactory-xrm", - "version": "1.3.6", + "version": "1.4.0", "description": "Dynamics CRM Solution Template", "homepage": "http://www.nullfactory.net", "author": {