Public/Solution.ps1
|
#ImportSolutionToCrmAsync function Import-CrmSolutionAsync { # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$true, Position=1)] [string]$SolutionFilePath, [parameter(Mandatory=$false, Position=2)] [switch]$ActivateWorkflows, [parameter(Mandatory=$false, Position=3)] [switch]$OverwriteUnManagedCustomizations, [parameter(Mandatory=$false, Position=4)] [switch]$SkipDependancyOnProductUpdateCheckOnInstall, [parameter(Mandatory=$false, Position=5)] [switch]$PublishChanges, [parameter(Mandatory=$false, Position=6)] [int64]$MaxWaitTimeInSeconds, [parameter(Mandatory=$false, Position=7)] [switch]$ImportAsHoldingSolution, [parameter(Mandatory=$false, Position=8)] [switch]$BlockUntilImportComplete, [parameter(Mandatory=$false, Position=9)] [int64]$PollingDelayInSeconds = 5 ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) $importId = [guid]::Empty $asyncResponse = $null try { if (!(Test-Path $SolutionFilePath)) { throw [System.IO.FileNotFoundException] "$SolutionFilePath not found." } Write-Verbose "Importing solution file $SolutionFilePath into: $($conn.CrmConnectOrgUriActual)" Write-Verbose "OverwriteCustomizations: $OverwriteUnManagedCustomizations" Write-Verbose "SkipDependancyCheck: $SkipDependancyOnProductUpdateCheckOnInstall" Write-Verbose "ImportAsHoldingSolution: $ImportAsHoldingSolution" Write-Verbose "Maximum seconds to poll: $MaxWaitTimeInSeconds" Write-Verbose "Block and wait? $BlockUntilImportComplete" if($BlockUntilImportComplete -eq $false -and ($MaxWaitTimeInSeconds -gt 0 -or $MaxWaitTimeInSeconds -eq -1)){ Write-Warning "MaxWaitTimeInSeconds is $MaxWaitTimeInSeconds, we assume the user wants to block until complete." Write-Warning "To avoid this warning in the future please specify the switch: -BlockUntilImportComplete" $BlockUntilImportComplete = $true } if($BlockUntilImportComplete -eq $false -and $PublishChanges -eq $true){ Write-Warning "PublishChanges will be ignored because BlockUntilImportComplete is $BlockUntilImportComplete" $PublishChanges = $false; } $data = [System.IO.File]::ReadAllBytes($SolutionFilePath) $request = New-Object Microsoft.Crm.Sdk.Messages.ImportSolutionRequest $request.CustomizationFile = $data $request.PublishWorkflows = $ActivateWorkflows $request.OverwriteUnmanagedCustomizations = $OverwriteUnManagedCustomizations $request.SkipProductUpdateDependencies = $SkipDependancyOnProductUpdateCheckOnInstall $request.HoldingSolution = $ImportAsHoldingSolution $asyncRequest = New-Object Microsoft.Xrm.Sdk.Messages.ExecuteAsyncRequest $asyncRequest.Request = $request; Write-Verbose "Importing solution. This process can take a while..." try { $asyncResponse = ($conn.Execute($asyncRequest, "AsyncImportRequest") -as [Microsoft.Xrm.Sdk.Messages.ExecuteAsyncResponse]) $importId = $asyncResponse.AsyncJobId Write-Verbose "Async Operation ID (asyncoperationid): $importId" if($importId -eq $null -or $importId -eq [Guid]::Empty) { throw "Import request failed for Async Operation {$importId}" } #if the caller wants to get the ID and does NOT want to wait if($BlockUntilImportComplete -eq $false){ return $asyncResponse; } } catch { throw $_.Exception } $pollingStart = Get-Date $isProcessing = $true $secondsSpentPolling = 0 $transientFailureCount = 0; Write-Verbose "Solution import requested, waiting on completion of Async Operation {$importId}..." try{ while(($isProcessing -and $secondsSpentPolling -lt $MaxWaitTimeInSeconds) -or ($isProcessing -and $MaxWaitTimeInSeconds -eq -1)){ #delay Start-Sleep -Seconds $PollingDelayInSeconds #check the import job for success/fail/inProgress try{ $import = Get-CrmRecord -conn $conn -EntityLogicalName asyncoperation -Id $importId -Fields statuscode,completedon,friendlymessage } catch { $transientFailureCount++; Write-Verbose "Import Job status check did not succeed: $($_.Exception)" } $statuscode = $import.statuscode_Property.value.Value; #Check for import completion - https://msdn.microsoft.com/en-us/library/gg309288.aspx if($statuscode -lt 30){ $secondsSpentPolling = ([Int]((Get-Date) - $pollingStart).TotalSeconds) Write-Verbose "Executing for $($secondsSPentPolling.ToString())/$MaxWaitTimeInSeconds seconds | Status: $($import.statuscode) ($statuscode)" } elseif($statuscode -eq 31 -or $statuscode -eq 32 ){ $isProcessing = $false throw "Status: $($import.statuscode) ($statuscode) | Operation has been either cancelled or has failed for Async Operation {$importId}.`n$($import.friendlymessage)" break; } elseif($statuscode -eq 30){ $isProcessing = $false Write-Verbose "Processing Completed at: $($import.completedon)" if($PublishChanges){ Write-Verbose "SUCCESS: PublishChanges set, executing: Publish-CrmAllCustomization using the same connection." Publish-CrmAllCustomization -conn $conn return $import } else{ Write-Verbose "SUCCESS: Import Complete, don't forget to publish customizations." return $import } break; } } #User provided timeout and exit function with an error if($secondsSpentPolling -gt $MaxWaitTimeInSeconds){ Write-Warning "Import-CrmSolutionAsync exited due to exceeding the maximum timeout of $MaxWaitTimeInSeconds. The import will continue in CRM async until it either succeeds or fails." } #at this point we appear to have imported successfully return $asyncResponse; } Catch { throw "AsyncOperation with ID: $importId has encountered an exception: $_" } } catch { throw $_.Exception } } #ImportSolutionToCrm function Import-CrmSolution{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$true, Position=1)] [string]$SolutionFilePath, [parameter(Mandatory=$false, Position=2)] [switch]$ActivatePlugIns, [parameter(Mandatory=$false, Position=3)] [switch]$OverwriteUnManagedCustomizations, [parameter(Mandatory=$false, Position=4)] [switch]$SkipDependancyOnProductUpdateCheckOnInstall, [parameter(Mandatory=$false, Position=5)] [switch]$PublishChanges, [parameter(Mandatory=$false, Position=6)] [int64]$MaxWaitTimeInSeconds = 900, [parameter(Mandatory=$false, Position=7)] [switch]$ImportAsHoldingSolution, [parameter(Mandatory=$false, Position=8)] [switch]$AsyncOperationImportMethod ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) $importId = [guid]::Empty try { if (!(Test-Path $SolutionFilePath)) { throw [System.IO.FileNotFoundException] "$SolutionFilePath not found." } Write-Verbose "Importing solution file $SolutionFilePath into: $($conn.CrmConnectOrgUriActual)" Write-Verbose "OverwriteCustomizations: $OverwriteUnManagedCustomizations" Write-Verbose "SkipDependancyCheck: $SkipDependancyOnProductUpdateCheckOnInstall" Write-Verbose "ImportAsHoldingSolution: $ImportAsHoldingSolution" Write-Verbose "Maximum seconds to poll for successful completion: $MaxWaitTimeInSeconds" if($AsyncOperationImportMethod){ Write-Warning "Option to import using Aync method flagged! With this option you may not be able to debug problems easily." Write-Warning "To import async going forward use the Import-CrmSolutionAsync cmdlet instead." $result = Import-CrmSolutionAsync ` -Conn $conn ` -SolutionFilePath $SolutionFilePath ` -OverwriteUnManagedCustomizations:$OverwriteUnManagedCustomizations ` -SkipDependancyOnProductUpdateCheckOnInstall:$SkipDependancyOnProductUpdateCheckOnInstall ` -MaxWaitTimeInSeconds $MaxWaitTimeInSeconds ` -ImportAsHoldingSolution:$ImportAsHoldingSolution ` -BlockUntilImportComplete:$true; Write-Verbose "Solution import using async completed - asyncoperationid = $($result.AsyncJobId)"; return $result; } Write-Verbose "Calling .ImportSolutionToCrm() this process can take minutes..." $result = $conn.ImportSolutionToCrm($SolutionFilePath, [ref]$importId, $ActivatePlugIns, $OverwriteUnManagedCustomizations, $SkipDependancyOnProductUpdateCheckOnInstall,$ImportAsHoldingSolution) Write-Verbose "ImportId: $result" if ($result -eq [guid]::Empty) { throw $_.Exception } $pollingStart = Get-Date $isProcessing = $true $secondsSpentPolling = 0 $pollingDelaySeconds = 5 $TopPrevProcPercent = [double]0 $isProcPercentReduced = $false #this is for a bug where the service will throw a 401 on retrieve of importjob during an import under certain conditions $transientFailureCount = 0; Write-Host "Import of file completed, waiting on completion of importId: $importId" try{ while($isProcessing -and $secondsSpentPolling -lt $MaxWaitTimeInSeconds){ #delay Start-Sleep -Seconds $pollingDelaySeconds #check the import job for success/fail/inProgress try{ $import = Get-CrmRecord -conn $conn -EntityLogicalName importjob -Id $importId -Fields solutionname,data,completedon,startedon,progress } catch { if($transientFailureCount > 5){ Write-Error "Import Job status check FAILED 5 times this could be due to a bug where the service returns a 401. Throwing lastException:"; throw $conn.LastCrmException } Write-Verbose "Import Job status check FAILED this could be due to a bug where the service returns a 401. We'll allow up to 5 failures before aborting."; $transientFailureCount++; } #Option to use Get-CrmRecords so we can force a no-lock to prevent hangs in the retrieve #$import = (Get-CrmRecords -conn $conn -EntityLogicalName importjob -FilterAttribute importjobid -FilterOperator eq -FilterValue $importId -Fields data,completedon,startedon,progress).CrmRecords[0] $importManifest = ([xml]($import).data).importexportxml.solutionManifests.solutionManifest $ProcPercent = [double](Coalesce $import.progress "0") #check if processing percentage reduced at any given time if($TopPrevProcPercent -gt $ProcPercent) { $isProcPercentReduced = $true Write-Verbose "Processing is reversing... import will fail." } else { $TopPrevProcPercent = $ProcPercent } #Check for import completion if($import.completedon -eq $null -and $importManifest.result.result -ne "success"){ $isProcessing = $true $secondsSpentPolling = ([Int]((Get-Date) - $pollingStart).TotalSeconds) Write-Host "$($secondsSPentPolling.ToString()) seconds of max: $MaxWaitTimeInSeconds ... ImportJob%: $ProcPercent" } else { Write-Verbose "Processing Completed at: $($import.completedon) with ImportJob%: $ProcPercent" Write-Verbose "Import Manifest Result: $($importManifest.result.result) with ImportJob%: $ProcPercent" $solutionImportResults = Select-Xml -Xml ([xml]$import.data) -XPath "//result" $anyFailuresInImport = $false; $allErrorText = ""; foreach($solutionImportResult in $solutionImportResults) { try{ $resultParent = "" $itemResult = "" $resultParent = $($solutionImportResult.Node.ParentNode.ParentNode.Name) $itemResult = $($solutionImportResult.Node.result) }catch{} Write-Verbose "Item:$resultParent result: $itemResult" # write each item result in result data if ($solutionImportResult.Node.result -ne "success") { # if any error in result print more error details try{ $errorCode = "" $errorText = "" $moreErrorDetails = "" $errorCode = $($solutionImportResult.Node.errorcode) $errorText = $($solutionImportResult.Node.errortext) $moreErrorDetails = $solutionImportResult.Node.parameters.InnerXml }catch{} Write-Verbose "errorcode: $errorCode errortext: $errorText more details: $moreErrorDetails" if ($solutionImportResult.Node.result -eq "failure") # Fail only on errors, not on warnings { $anyFailuresInImport = $true; # mark if any failures in solution import $allErrorText = $allErrorText + ";" + $errorText; } } } if(-not $isProcPercentReduced -and $importManifest.result.result -eq "success" -and (-not $anyFailuresInImport)) { Write-Verbose "Setting to 100% since all results are success" $ProcPercent = 100.0 } $isProcessing = $false break } } } Catch { Write-Error "ImportJob with ID: $importId has encountered an exception: $_ " } Finally{ $ProcPercent = ([double](Coalesce $ProcPercent 0)) } #User provided timeout and exit function with an error if($secondsSpentPolling -gt $MaxWaitTimeInSeconds){ throw "Import-CrmSolution halted due to exceeding the maximum timeout of $MaxWaitTimeInSeconds." } #detect a failure by a failure result OR the percent being less than 100% if(($importManifest.result.result -eq "failure") -or ($ProcPercent -lt 100) -or $anyFailuresInImport) #Must look at %age instead of this result as the result is usually wrong! { Write-Verbose "Import result: failed - job with ID: $importId failed at $ProcPercent complete." throw $allErrorText } else { #at this point we appear to have imported successfully $managedsolution = $importManifest.Managed if($managedsolution -ne 1) { if($PublishChanges){ Write-Verbose "PublishChanges set, executing: Publish-CrmAllCustomization using the same connection." Publish-CrmAllCustomization -conn $conn } else{ Write-Output "Import Complete, don't forget to publish customizations." } } else{ #managed Write-Output "Import of managed solution complete." } } } catch { Write-Error $_.Exception } } #MergeHoldingSolution function Merge-CrmHoldingSolutionAsync { [CmdletBinding()] PARAM( [parameter(Mandatory=$true)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$true, Position=1)] [string]$CrmSolutionName, [parameter(Mandatory=$false, Position=2)] [int64]$MaxWaitTimeInSeconds, [parameter(Mandatory=$false, Position=3)] [switch]$BlockUntilImportComplete, [parameter(Mandatory=$false, Position=4)] [int64]$PollingDelayInSeconds = 5 ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) $request = New-Object Microsoft.Crm.Sdk.Messages.DeleteAndPromoteRequest $request.UniqueName = $CrmSolutionName $asyncRequest = New-Object Microsoft.Xrm.Sdk.Messages.ExecuteAsyncRequest $asyncRequest.Request = $request try { Write-Verbose "Applying async solution upgrade for solution '$CrmSolutionName'" $asyncResponse = ($conn.Execute($asyncRequest, "AsyncImportRequest") -as [Microsoft.Xrm.Sdk.Messages.ExecuteAsyncResponse]) $asyncOperationId = $asyncResponse.AsyncJobId Write-Verbose "Async Operation ID (asyncoperationid): $asyncOperationId" if(($asyncOperationId -eq $null) -or ($asyncOperationId -eq [Guid]::Empty)) { throw "Async request failed!" } #if the caller wants to get the ID and does NOT want to wait if($BlockUntilImportComplete -eq $false){ return $asyncResponse } } catch { throw $_.Exception } $pollingStart = Get-Date $isProcessing = $true $secondsSpentPolling = 0 $transientFailureCount = 0 Write-Verbose "Async Delete and Promote requested, waiting on completion..." try{ while(($isProcessing -and $secondsSpentPolling -lt $MaxWaitTimeInSeconds) -or ($isProcessing -and $MaxWaitTimeInSeconds -eq -1)) { #delay Start-Sleep -Seconds $PollingDelayInSeconds #check the async job for success/fail/inProgress try{ $asyncOperation = Get-CrmRecord -conn $conn -EntityLogicalName asyncoperation -Id $asyncOperationId -Fields statuscode,completedon,friendlymessage } catch { $transientFailureCount++; Write-Verbose "Async job status check did not succeed: $($_.Exception)" } $statuscode = $asyncOperation.statuscode_Property.value.Value; #Check for import completion - https://msdn.microsoft.com/en-us/library/gg309288.aspx if($statuscode -lt 30){ $secondsSpentPolling = ([Int]((Get-Date) - $pollingStart).TotalSeconds) Write-Verbose "Executing for $($secondsSPentPolling.ToString())/$TimeoutInSeconds seconds | Status: $($asyncOperation.statuscode) ($statuscode)" } elseif($statuscode -eq 31 -or $statuscode -eq 32 ){ $isProcessing = $false throw "Status: $($asyncOperation.statuscode) ($statuscode) | Operation has been either cancelled or has failed.`n$($asyncOperation.friendlymessage)" break; } elseif($statuscode -eq 30){ $isProcessing = $false Write-Verbose "Processing Completed at: $($asyncOperation.completedon)" Write-Verbose "SUCCESS: Delete and Promote successfully completed." return $asyncOperation } } #User provided timeout and exit function with an error if($secondsSpentPolling -gt $MaxWaitTimeInSeconds){ Write-Warning "Delete and Promote request exited due to exceeding the maximum timeout of $MaxWaitTimeInSeconds. The import will continue in CRM asynchronously until it either succeeds or fails." } #at this point request appears to have succeeded return $asyncResponse; } catch { throw "AsyncOperation with ID: $asyncOperationId has encountered an exception: $_" } } #InstallSampleDataToCrm function Add-CrmSampleData{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false, Position=0)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) try { $result = $conn.InstallSampleDataToCrm() if($result -eq $null) { throw "Could not add sample data" } } catch { throw } return $result } #IsSampleDataInstalled function Test-CrmSampleDataInstalled{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) try { $result = $conn.IsSampleDataInstalled() } catch { throw } return $result } #PublishEntity function Publish-CrmEntity{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$true, Position=1)] [string]$EntityLogicalName ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) try { $result = $conn.PublishEntity($EntityLogicalName) if(!$result) { throw "Could not publish entity" } } catch { throw } return $result } #PublishTheme function Publish-CrmTheme{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$true, Position=1, ParameterSetName="ThemeName")] [string]$ThemeName, [parameter(Mandatory=$true, Position=1, ParameterSetName="ThemeId")] [guid]$ThemeId ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) try { if($ThemeName -ne "") { $themes = Get-CrmRecords -conn $conn -EntityLogicalName theme -FilterAttribute name -FilterOperator eq -FilterValue $ThemeName -WarningAction SilentlyContinue if($themes.CrmRecords.Count -eq 0) { Write-Warning "No Theme found" return } else { $ThemeId = $themes.CrmRecords[0].themeid } } $req = New-Object Microsoft.Crm.Sdk.Messages.PublishThemeRequest $req.target = New-CrmEntityReference -EntityLogicalName "theme" -Id $ThemeId $result = $conn.Execute($req, $null) if(!$result) { throw "Could not publish theme" } } catch { throw } return $result } #ResetLocalMetadataCache function Remove-CrmEntityMetadataCache{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$false, Position=1)] [string]$EntityLogicalName ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) if($EntityLogicalName -eq "") { $EntityLogicalName = $null } try { $result = $conn.ResetLocalMetadataCache($EntityLogicalName) if($result -eq $null) { throw "Could not remove metadata cache" } } catch { throw } } #UninstallSampleDataFromCrm function Remove-CrmSampleData{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) try { $result = $conn.UninstallSampleDataFromCrm() } catch { throw } return $result } function Export-CrmApplicationRibbonXml { # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$false, Position=1)][alias("Path")] [string]$RibbonFilePath ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) $exportPath = if($RibbonFilePath -ne ""){Get-Item $RibbonFilePath} else {Get-Location} $exportFileName = "applicationRibbon.xml" $path = Join-Path $exportPath $exportFileName # Instantiate RetrieveEntityRibbonRequest $request = New-Object Microsoft.Crm.Sdk.Messages.RetrieveApplicationRibbonRequest try { $response = $conn.Execute($request) if ($response.CompressedApplicationRibbonXml -ne $null) { $ribbonXml = UnzipCrmRibbon -Data $response.CompressedApplicationRibbonXml Write-Verbose 'Saving ribbon file to path: $path' $ribbonXml.Save($path) Write-Verbose "Successfully wrote file" $result = New-Object PSObject Add-Member -InputObject $result -MemberType NoteProperty -Name "RetrieveApplicationRibbonRequest" -Value $response Add-Member -InputObject $result -MemberType NoteProperty -Name "RibbonFilePath" -Value $path return $result } #Should only get here if there was nothing returned. throw "Could not export application ribbon xml" } catch { throw $_.Exception } } function Export-CrmEntityRibbonXml { # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$true, Position=1)] [string]$EntityLogicalName, [parameter(Mandatory=$false, Position=2)][alias("Path")] [string]$RibbonFilePath ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) $exportPath = if($RibbonFilePath -ne ""){Get-Item $RibbonFilePath} else {Get-Location} $exportFileName = $EntityLogicalName + "Ribbon.xml" $path = Join-Path $exportPath $exportFileName # Instantiate RetrieveEntityRibbonRequest $request = New-Object Microsoft.Crm.Sdk.Messages.RetrieveEntityRibbonRequest $request.EntityName = $EntityLogicalName $request.RibbonLocationFilter = [Microsoft.Crm.Sdk.Messages.RibbonLocationFilters]::All try { $response = $conn.Execute($request) if ($response.CompressedEntityXml -ne $null) { $ribbonXml = UnzipCrmRibbon -Data $response.CompressedEntityXml Write-Verbose 'Saving ribbon file to path: $path' $ribbonXml.Save($path) Write-Verbose "Successfully wrote file" $result = New-Object PSObject Add-Member -InputObject $result -MemberType NoteProperty -Name "RetrieveEntityRibbonResponse" -Value $response Add-Member -InputObject $result -MemberType NoteProperty -Name "RibbonFilePath" -Value $path return $result } #Should only get here if there was nothing returned. throw "Could not export entity ribbon xml" } catch { throw } } function Export-CrmSolution{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$true, Position=1)] [string]$SolutionName, [parameter(Mandatory=$false, Position=2)] [string]$SolutionFilePath, [parameter(Mandatory=$false)] [string]$SolutionZipFileName, [parameter(Mandatory=$false)] [switch]$Managed, [parameter(Mandatory=$false)] [string]$TargetVersion, [parameter(Mandatory=$false)] [switch]$ExportAutoNumberingSettings, [parameter(Mandatory=$false)] [switch]$ExportCalendarSettings, [parameter(Mandatory=$false)] [switch]$ExportCustomizationSettings, [parameter(Mandatory=$false)] [switch]$ExportEmailTrackingSettings, [parameter(Mandatory=$false)] [switch]$ExportGeneralSettings, [parameter(Mandatory=$false)] [switch]$ExportMarketingSettings, [parameter(Mandatory=$false)] [switch]$ExportOutlookSynchronizationSettings, [parameter(Mandatory=$false)] [switch]$ExportRelationshipRoles, [parameter(Mandatory=$false)] [switch]$ExportIsvConfig, [parameter(Mandatory=$false)] [switch]$ExportSales ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) try { $solutionRecords = (Get-CrmRecords -conn $conn -EntityLogicalName solution -FilterAttribute uniquename -FilterOperator "like" -FilterValue $SolutionName -Fields uniquename,publisherid,version ) #if we can't find just one solution matching then ERROR if($solutionRecords.CrmRecords.Count -ne 1) { $friendlyName = $conn.ConnectedOrgFriendlyName.ToString() Write-Error "Solution with name `"$SolutionName`" in CRM Instance: `"$friendlyName`" not found!" break } #else PROCEED $crmSolutionRecord = $solutionRecords.CrmRecords[0] $version = $crmSolutionRecord.version $solutionUniqueName = $crmSolutionRecord.uniquename write-verbose "Solution found with version# $version" $exportPath = if($SolutionFilePath -ne ""){Get-Item $SolutionFilePath} else {Get-Location} #if a filename is not given, then we'll default one to [solutionname]_[managed]_[version].zip if($SolutionZipFileName.Length -eq 0) { $version = $version.Replace('.','_') $managedFileName = if($Managed) {"_managed_"} else {"_unmanaged_"} $solutionZipFileName = "$solutionUniqueName$managedFileName$version.zip" } #now we should have the final path $path = Join-Path $exportPath $solutionZipFileName Write-Verbose "Solution path: $path" #create the export request then set all the properties $exportRequest = New-Object Microsoft.Crm.Sdk.Messages.ExportSolutionRequest $exportRequest.ExportAutoNumberingSettings =$ExportAutoNumberingSettings $exportRequest.ExportCalendarSettings =$ExportCalendarSettings $exportRequest.ExportCustomizationSettings =$ExportCustomizationSettings $exportRequest.ExportEmailTrackingSettings =$ExportEmailTrackingSettings $exportRequest.ExportGeneralSettings =$ExportGeneralSettings $exportRequest.ExportIsvConfig =$ExportIsvConfig $exportRequest.ExportMarketingSettings =$ExportMarketingSettings $exportRequest.ExportOutlookSynchronizationSettings =$ExportOutlookSynchronizationSettings $exportRequest.ExportRelationshipRoles =$ExportRelationshipRoles $exportRequest.Managed =$Managed $exportRequest.SolutionName =$solutionUniqueName $exportRequest.TargetVersion =$TargetVersion if($conn.ConnectedOrgVersion.Major -ge 7) { $exportRequest.ExportSales = $ExportSales } Write-Verbose 'ExportSolutionRequests may take several minutes to complete execution.' $response = [Microsoft.Crm.Sdk.Messages.ExportSolutionResponse]($conn.Execute($exportRequest)) if($response -eq $null){ if($conn.LastCrmException -eq ""){ throw "The result was null, please double check the command" } else{ throw $_.Exception } } Write-Verbose 'Using solution file to path: $path' [System.IO.File]::WriteAllBytes($path,$response.ExportSolutionFile) Write-Verbose "Successfully wrote file" $result = New-Object psObject Add-Member -InputObject $result -MemberType NoteProperty -Name "ExportSolutionResponse" -Value $response Add-Member -InputObject $result -MemberType NoteProperty -Name "SolutionPath" -Value $path return $result } catch { Write-Error $_.Exception } return $result } function Publish-CrmCustomization{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$false)] [switch]$Entity, [parameter(Mandatory=$false)] [string[]]$EntityLogicalNames, [parameter(Mandatory=$false)] [switch]$Ribbon, [parameter(Mandatory=$false)] [switch]$SiteMap, [parameter(Mandatory=$false)] [switch]$Dashbord, [parameter(Mandatory=$false)] [guid[]]$DashbordIds, [parameter(Mandatory=$false)] [switch]$OptionSet, [parameter(Mandatory=$false)] [string[]]$OptionSetNames, [parameter(Mandatory=$false)] [switch]$WebResource, [parameter(Mandatory=$false)] [guid[]]$WebResourceIds ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) $parameterXml = "<importexportxml>" if($Entity -and $EntityLogicalNames.Count -ne 0) { $parameterXml += "<entities>" foreach($entityLogicalName in $EntityLogicalNames) { $parameterXml += "<entity>" + $entityLogicalName + "</entity>" } $parameterXml += "</entities>" } if($Ribbon) { $parameterXml += "<ribbons><ribbon></ribbon></ribbons>" } if($Dashbord -and $DashbordIds.Count -ne 0) { $parameterXml += "<dashboards>" foreach($dashbordId in $DashbordIds) { $parameterXml += "<dashboard>{" + $dashbordId + "}</dashboard>" } $parameterXml += "</dashboards>" } if($OptionSet -and $OptionSetNames.Count -ne 0) { $parameterXml += "<optionsets>" foreach($optionSetName in $OptionSetNames) { $parameterXml += "<optionset>{" + $optionSetName + "}</optionset>" } $parameterXml += "</optionsets>" } if($SiteMap) { $parameterXml += "<sitemaps><sitemap></sitemap></sitemaps>" } if($WebResource -and $WebResourceIds.Count -ne 0) { $parameterXml += "<webresources>" foreach($webResourceId in $WebResourceIds) { $parameterXml += "<webresource>{" + $webResourceId + "}</webresource>" } $parameterXml += "</webresources>" } $parameterXml += "</importexportxml>" $request = New-Object Microsoft.Crm.Sdk.Messages.PublishXmlRequest $request.ParameterXml = $parameterXml try { $response = $conn.Execute($request) if($response.ResponseName -eq $null) { throw "Could not publish" } } catch { throw $_.Exception } } function Publish-CrmAllCustomization{ # .ExternalHelp Campgemini.Xrm.Data.PowerShell.Help.xml [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) $request = New-Object Microsoft.Crm.Sdk.Messages.PublishAllXmlRequest try { $response = $conn.Execute($request) } catch { throw $_.Exception } #return $response } function Set-CrmSolutionVersionNumber { [CmdletBinding()] PARAM( [parameter(Mandatory=$false)] [Microsoft.Xrm.Sdk.IOrganizationService]$conn, [parameter(Mandatory=$true, Position=1)] [string]$SolutionName, [parameter(Mandatory=$true, Position=2)] [ValidatePattern('^(?:[\d]{1,}\.){1,3}[\d]{1,}$')] [string]$VersionNumber ) $conn = VerifyCrmConnectionParam -conn $conn -pipelineValue ($PSBoundParameters.ContainsKey('conn')) $solutionRecords = (Get-CrmRecords -conn $conn -EntityLogicalName solution -FilterAttribute uniquename -FilterOperator eq -FilterValue $devops_SolutionName -Fields uniquename,version ) #if we can't find just one solution matching then ERROR if($solutionRecords.CrmRecords.Count -eq 0) { #$friendlyName = $conn.ConnectedOrgFriendlyName.ToString() throw "Solution with name `"$SolutionName`" not found!" } #else PROCEED $crmSolutionRecord = $solutionRecords.CrmRecords[0] $oldVersion = $crmSolutionRecord.version $crmSolutionRecord.version = $VersionNumber try { Write-Verbose "Updating $($crmSolutionRecord.uniquename) version to $VersionNumber" Set-CrmRecord -conn $conn -CrmRecord $crmSolutionRecord Write-Verbose "Successfully updated solution record" $result = New-Object psObject Add-Member -InputObject $result -MemberType NoteProperty -Name "PreviousVersionNumber" -Value $oldVersion Add-Member -InputObject $result -MemberType NoteProperty -Name "NewVersionNumber" -Value $VersionNumber } catch { throw $_.Exception } $result } |