This is the Powershell sample I demoed at the Melbourne Victoria.NET User Group event in June. It's essentially a document generation sample and yup it really works and pretty darn quick. On a Dual Core 1.8gig machine, this Powershell script was generating 60 to 70 Office Open XML Documents a second and it was only running on one thread/core...
And yes you can doc generate Office Open XML documents on the server without requiring Office/Word to be installed and then run the WordML docs through something like http://www.renderx.com to generate PostScript for cheaper offsite printing, PDFs, XSLFOs etc..., all very cool and accessible!!
You'll find the sample at http://projectdistributor.net/Releases/Release.aspx?releaseId=418
For more information on Powershell then check out
http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx
http://blogs.msdn.com/powershell
Cheers and enjoy Dave
BTW, if you think you'll use it or some derivation then let me know via my blog, just interested:)
=================================================================================================
# $psAppDomain = [AppDomain]::CurrentDomain # $psAppDomain.GetAssemblies() d: cd \dgDemo ## Load additional required assemblies ## $dummy = [System.Reflection.Assembly]::Load("Windowsbase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35") ## Initialise global variables ## $documentType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" $customXmlType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml" [uri]$uri = $null; $dummy = [Uri]::TryCreate("/", [UriKind]::Relative, [ref]$uri) $doc = new-object -type system.xml.xmldocument $custRecord = $null [string]$text = "" [hashtable]$stdTexts = @{} function GetCustomXmlPart($customXmlRel) { #Get CustomXML Part $docPart = $Package.GetPart([System.IO.Packaging.PackUriHelper]::ResolvePartUri($uri, $customXmlRel.TargetUri)) $doc.load($docPart.getstream()) #This demo looks one level below the document element for element names to match either customer data or std texts $docElementName = $doc.get_documentelement().get_name() #loop through all the child elements in the customXML doc part looking for matches $doc.$docElementName.get_childnodes() | &{process{ $docElementName = $_.get_name() if ($stdTexts.Containskey($docElementName)) {$text = $stdtexts[$docElementName]} else {$text = $custRecord.$docElementName} $_.Set_InnerText($text) } } #Save the data inserted in to the customXML doc part $doc.save($docpart.getstream()) } function GetDocumentPart($OfficeDocRel) { #get ref to word document part find all relationships that are of type CustomXML $documentPart = $Package.GetPart([System.IO.Packaging.PackUriHelper]::ResolvePartUri($uri, $OfficeDocRel.TargetUri)) foreach ($customXmlRel in $documentPart.GetRelationshipsByType($customXmlType)) { GetCustomXmlPart($customXmlRel) } } function ProcessDocs([int]$docNumber) { #create new doc from the template $newFile = (get-location).path + "\processedDocs\LatePayment" + $docNumber + ".docx" $sourceFile = (get-location).path + "\Template.docx" copy -path $sourceFile -destination $newFile #loop through the root relationships in the doc looking for word document part - there will only be one $Package = [System.IO.Packaging.Package]::Open($newFile) foreach ($rel in $Package.GetRelationshipsByType($documentType)) { GetDocumentPart($rel) } $Package.Close() } function Initialise() { if(test-path -path processedDocs) {remove-item -path Processeddocs -recurse} $dummy = mkdir ProcessedDocs #load customers.xml in to a global cust oject [xml]$global:cust = get-content .\customers.xml #load standard letter parts from standardtexts.xml in to a hash table [xml]$stdTextsXml = get-content standardtext.xml $stdTextsXml.texts.text | &{process{$stdTexts[$_.key] = $_.value}} } Initialise ## Main ## $start = [datetime]::now #loop through all customer childnodes in the customers.xml doc $cust.Customers.Customer | &{begin{$records=0} process{$records++; $custRecord = $_; ProcessDocs($records)} end{$global:totRecords = $records} } $end = [datetime]::now "============================================================" "Total Documents Generated: " + $totRecords "Total processing time (seconds): " + ($end.subtract($start)).totalseconds "Office Open XML documents generated/sec: " + $totRecords / ($end.subtract($start)).totalseconds "============================================================"