Microsoft’s “PowerShell” is a command-line shell and scripting language designed for system administration and automation. Its potential benefits to developers and administrators of CRM installations are endless. Since PowerShell can utilize .NET assemblies and web services, it can be used with CRM to automate just about any administration tasks or any other type of routine or tedious tasks.
This blog post provides one example of how PowerShell can make the lives of Microsoft Dynamics CRM 4.0 administrators easier. The script provided below fully automates the process of exporting CRM system customizations to file, which can be scheduled to run at any time interval. It also takes care of creating a unique file name for each export and only keeping customization files that differ from the previous export – thus saving hard drive space.
There are several books and websites dedicated to PowerShell. One site that we’ve found useful is PowerShell.com. Or Bing “powershell” and you’ll find millions of hits. Enjoy!
#######################################################################
##
## PowerShell v1.0 Script: CrmCustomizationExporter.ps1
##
## Purpose: Exports (to an XML file) all CRM 4.0 customizations for the specified organization.
##
## Features:
## 1) Automatically maintains unique customization files. This reduces storage space and makes it easier to
## determine if and when customization were made between exports.
## 2) Reads directly from the CRM WSDL so no local storage of the WSDL (or compiled DLL) is necessary.
##
## Requirements:
## 1) .NET Framework 2.0 SDK
## 2) Run script with an account that has rights to export CRM customizations
## 3) Set the PowerShell execution policy: Set-ExecutionPolicy Unrestricted (change as appropriate)
##
## Creating a scheduled task:
## - Command to run (example): PowerShell "& c:\ps\CrmCustomizationExporter.ps1"
##
#######################################################################
## Modify these variables as needed.
$targetDir = "c:\customizations\"
$filePrefix = "customizations_all_"
$crmOrgName = "altriva"
$crmServiceUrl = "http://localhost:5555/mscrmservices/2007/crmservice.asmx"
$wsdlLocation = "$crmServiceUrl" + "?wsdl&uniquename=$crmOrgName" # This could also be a fixed file name.
$crmServiceUrl = "$crmServiceUrl" + "?uniquename=$crmOrgName"
write-host $wsdlLocation
## Open the WSDL.
[void] [Reflection.Assembly]::LoadWithPartialName("System.Web.Services")
$wc = New-Object System.Net.WebClient
$wc.UseDefaultCredentials = $true
$wsdlStream = $wc.OpenRead($wsdlLocation)
$serviceDescription = [Web.Services.Description.ServiceDescription]::Read($wsdlStream)
$wsdlStream.Close()
## Import the web service into a CodeDom.
$serviceNamespace = New-Object System.CodeDom.CodeNamespace
$codeCompileUnit = New-Object System.CodeDom.CodeCompileUnit
$serviceDescriptionImporter = New-Object Web.Services.Description.ServiceDescriptionImporter
$serviceDescriptionImporter.AddServiceDescription($serviceDescription, $null, $null)
[void] $codeCompileUnit.Namespaces.Add($serviceNamespace)
[void] $serviceDescriptionImporter.Import($serviceNamespace, $codeCompileUnit)
## Generate the code from that CodeDom into a string.
$generatedCode = New-Object Text.StringBuilder
$stringWriter = New-Object IO.StringWriter $generatedCode
$provider = New-Object Microsoft.CSharp.CSharpCodeProvider
$provider.GenerateCodeFromCompileUnit($codeCompileUnit, $stringWriter, $null)
## Compile the source code.
$references = @("System.dll", "System.Web.Services.dll", "System.Xml.dll")
$compilerParameters = New-Object System.CodeDom.Compiler.CompilerParameters
$compilerParameters.ReferencedAssemblies.AddRange($references)
$compilerParameters.GenerateInMemory = $true
$compilerResults = $provider.CompileAssemblyFromSource($compilerParameters, $generatedCode)
## Get the assembly that we just compiled.
$assembly = $compilerResults.CompiledAssembly
## Create an instance of the CrmService type.
$type = "CrmService"
$instance = $assembly.CreateInstance($type)
## Set instance properties.
$instance.UseDefaultCredentials = $true
$token = new-object CrmAuthenticationToken
$tokenAuthenticationType=0
$Token.OrganizationName = $crmOrgName
$instance.Url = $crmServiceUrl
$instance.CrmAuthenticationTokenValue = $token
$CrmCredentials = [System.Net.CredentialCache].DefaultCredentials
## Execute the customization export request
$request = new-object "ExportAllXmlRequest"
$response = $instance.Execute($request) -as [ExportAllXmlResponse]
$responseXml = new-object XML
$responseXml.LoadXml($response.ExportXml)
## Write the exported customizations XML to a date-stamped file.
$date = (get-date).ToString('yyyyMMdd_HHmmss')
$xmlfile = "$targetDir$filePrefix$date.xml"
$responseXml.Save("$xmlfile")
## If the previous export file is the same size as the file just created then delete the previous version.
$XmlFiles = Get-ChildItem "$targetDir*.xml" | Sort-Object -Descending
if ($XmlFiles.count -gt 1)
{
$previousXmlFile = $XmlFiles[1]
$previousXmlFileSize = (Get-Item $previousXmlFile).length
write-host $previousXmlFileSize
if ($previousXmlFileSize -eq (Get-Item $xmlfile).length) { Remove-Item $previousXmlFile }
}
- Tim Dutcher