-
Documenting a Citrix XenApp 6.5 Farm with Microsoft PowerShell and Word – Version 3
January 28, 2013
The script to document a Citrix XenApp 6.5 farm has proven to be very popular. Recently the script was updated with some significant changes and bug fixes. I have always wanted to take the time to create a version of the script that would output to a Microsoft Word document. Ryan Revord had taken the XenApp 6.0 version of the script and changed it to create a basic Microsoft Word document. Ryan saved me a lot of work but I wanted improve on the document created by adding a cover page, Table of Contents and footer. The basic functionality of the script has not changed since the Version 2 update. This article will explain the changes to the script to create a Word document.
NOTE: This script is continually updated. You can always find the most current version by going to https://carlwebster.com/where-to-get-copies-of-the-documentation-scripts/
Note: If you do not want to use this version of the script to create a Word document, there is functionally no difference with Version 2. Version 2 outputs to a formatted text file and this version creates a Word file with headers and formatting. This script has been tested with Word 2007, 2010 and 2013.
As much as Microsoft pushes PowerShell for their products and on their users, I find it surprising there is no native PowerShell support for any of the Office products. For example there is no New_WordDocument, Get-WordDocument or Save-WordDocument. In order to use Word with PowerShell you must use the Word COM Object model. Finding detailed information on that subject was not easy. Fortunately for me, Jeff Hicks had blogged about a presentation he did in 2012 where he linked to some sample PowerShell script files. One of his sample files gave me the start I needed.
The prerequisites to follow along with this article are:
- A server, physical or virtual, running Microsoft Windows Server 2008 R2 with or without SP1
- Citrix XenApp 6.5 installed with or without HRP01
- Word 2007, 2010 or 2013 installed on the computer running the script
Let’s start at the beginning of the script. There are three pieces of information the script needs for the Cover Page and Footer:
- Company Name
- Cover Page
- User Name
Since a digitally signed version of the script is provided, these three pieces of information need to be passed to the script as parameters. A signed PowerShell script cannot be modified or the script is rendered useless.
[CmdletBinding( SupportsShouldProcess = $False, ConfirmImpact = "None", DefaultParameterSetName = "" ) ] Param( [parameter( Position = 0, Mandatory=$false ) ] [Alias("CN")] [ValidateNotNullOrEmpty()] [string]$CompanyName=(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Office\Common\UserInfo" | select -ExpandProperty Company), [parameter( Position = 1, Mandatory=$false ) ] [Alias("CP")] [ValidateNotNullOrEmpty()] [string]$CoverPage="Motion", [parameter( Position = 2, Mandatory=$false ) ] [Alias("UN")] [ValidateNotNullOrEmpty()] [string]$UserName=$env:username )
These parameters give us $CompanyName, $CoverPage and $UserName. Each has an alias: CN for CompanyName, CP for CoverPage and UN for UserName.
The default for $CompanyName is read from the registry key where Microsoft Office stores user information.
The default for $CoverPage is Motion. Motion is a Word Cover Page that comes with all three versions of Word, looks good but will require a minor tweak of changing the font used by the date field to a smaller font size.
The default for $UserName is taken from the USERNAME environment variable.
The parameter names can be spelled out or the aliases can be used or any combination. All three of these examples are valid:
-CompanyName “XYC, Inc.” –CoverPage “Grid” –UserName “Joe User”
-CN “XYC, Inc.” –CP “Grid” –UN “Joe User”
-CoverPage “Grid” –UN “Joe User”For the third example, the default Company Name will be used.
Citrix added PowerShell remoting support to the XenApp 6.5 cmdlets in the fall of 2011. By issuing the Set-XADefaultComputerName cmdlet, you can set the XenApp collector mode server to run the script against. Unfortunately, the Citrix.GroupPolicy.Commands.psm1 module did not have remoting capability added to it. The script needs to determine if remoting is set so the policy processing section of the script can be bypassed.
$Remoting = $False $tmp = Get-XADefaultComputerName If(![String]::IsNullOrEmpty( $tmp )) { $Remoting = $True } If($Remoting) { write-verbose "Remoting is enabled to XenApp server $tmp" } Else { write-verbose "Remoting is not being used" }
For the Word document to be saved a file name is needed and for the Cover Page, a title is needed.
The filename for the document is the XenApp farm name with the extension DOCX. The document is stored in the folder where the script is run.
# Get farm information write-verbose "Getting Farm data" $farm = Get-XAFarm -EA 0 If( $? ) { #first check to make sure this is a XenApp 6.5 farm If($Farm.ServerVersion.ToString().SubString(0,3) -eq "6.5") { #this is a XenApp 6.5 farm, script can proceed } Else { #this is not a XenApp 6.5 farm, script cannot proceed write-warning "This script is designed for XenApp 6.5 and should not be run on previous versions of XenApp" Return 1 } $FarmName = $farm.FarmName $Title="Inventory Report for the $($FarmName) Farm" $filename="$($pwd.path)\$($farm.FarmName).docx" } Else { $FarmName = "Unable to retrieve" $Title="XenApp 6.5 Farm Inventory Report" $filename="$($pwd.path)\XenApp 6.5 Farm Inventory.docx" write-warning "Farm information could not be retrieved" } $farm = $null
Next, variables specific to Word need to be established. I found two websites that listed the values.
write-verbose "Setting up Word" #these values were attained from #http://groovy.codehaus.org/modules/scriptom/1.6.0/scriptom-office-2K3-tlb/apidocs/ #http://msdn.microsoft.com/en-us/library/office/aa211923(v=office.11).aspx $wdSeekPrimaryFooter = 4 $wdAlignPageNumberRight = 2 $wdStory = 6 $wdMove = 0 $wdSeekMainDocument = 0 $wdColorGray15 = 14277081
Now a Word comObject needs to be created.
$Word = New-Object -comobject "Word.Application"
I will let The Scripting Guy explain the next line.
“We now use the -as operator to turn the string “Microsoft.Office.Interop.Word.WdSaveFormat” into a type. We use [ref] so that we can pass this type by reference, which is a requirement of the Word saveas method. By creating the WdSaveFormat type we gain access WdSaveFormat enumerations, which makes our script easier to write, easier to maintain, and easier to read. This line of code is seen here:”
[ref]$SaveFormat = "microsoft.office.interop.word.WdSaveFormat" -as [type]
Each version of Word comes with Cover Pages and only two are shared across all three versions. The version of Word installed on the computer running the script needs to be determined. If a wrong cover page is passed as $CoverPage and that Cover Page is not in the installed version of Word, the script will run but a lot of errors will be returned. The script needs to validate the $CoverPage against the valid Cover Pages specific to each version of Word.
$WordVersion = [int] $Word.Version If( $WordVersion -eq 15) { write-verbose "Running Microsoft Word 2013" $WordProduct = "Word 2013" } Elseif ( $WordVersion -eq 14) { write-verbose "Running Microsoft Word 2010" $WordProduct = "Word 2010" } Elseif ( $WordVersion -eq 12) { write-verbose "Running Microsoft Word 2007" $WordProduct = "Word 2007" } Elseif ( $WordVersion -eq 11) { write-verbose "Running Microsoft Word 2003" Write-error "This script does not work with Word 2003. Script will end." $word.quit() exit } Else { Write-error "You are running an untested or unsupported version of Microsoft Word. Script will end." $word.quit() exit } write-verbose "Validate cover page" $ValidCP = ValidateCoverPage $WordVersion $CoverPage If(!$ValidCP) { write-error "For $WordProduct, $CoverPage is not a valid Cover Page option. Script cannot continue." $Word.Quit() exit }
The function to validate the Cover Page.
Function ValidateCoverPage { Param( [int]$xWordVersion, [string]$xCP ) $xArray = "" If( $xWordVersion -eq 15) { #word 2013 $xArray = ("Austin", "Banded", "Facet", "Filigree", "Grid", "Integral", "Ion (Dark)", "Ion (Light)", "Motion", "Retrospect", "Semaphore", "Sideline", "Slice (Dark)", "Slice (Light)", "ViewMaster", "Whisp") } ElseIf( $xWordVersion -eq 14) { #word 2010 $xArray = ("Alphabet", "Annual", "Austere", "Austin", "Conservative", "Contrast", "Cubicles", "Exposure", "Grid", "Mod", "Motion", "Newsprint", "Perspective", "Pinstripes", "Puzzle", "Sideline", "Stacks", "Tiles", "Transcend") } ElseIf( $xWordVersion -eq 12) { #word 2007 $xArray = ("Alphabet", "Annual", "Austere", "Conservative", "Contrast", "Cubicles", "Exposure", "Mod", "Motion", "Pinstripes", "Puzzle", "Sideline", "Stacks", "Tiles", "Transcend" ) } If ($xArray -contains $xCP) { Return $True } Else { Return $False } }
If an invalid Cover Page is used, the script gives an error, closes Word and exits.
C:\webster\XA65_Inventory_V3.ps1 : For Word 2013, ABC is not a valid Cover Page option. Script cannot continue. At line:1 char:24 + .\xa65_inventory_v3.ps1 <<<< -CompanyName "The Accidental Citrix Admin" -CoverPage "ABC" -UserName "Amalgamated Consulting Group" -verbose + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,XA65_Inventory_V3.ps1 PS C:\webster>
Word is now hidden so the script runs faster by not having to continually update the screen. Change this to $True to see the Word document as it is built.
$Word.Visible = $False
In trying to find resources to figure out how to use PowerShell to create a complex Word document, I found Jeff Hick’s blog post and sample scripts.
Jeff had a ZIP file with several sample PowerShell scripts. One of them, Demo-WordReport.ps1, was extremely helpful. Jeff’s comments in his code should explain what the script is doing.
write-verbose "Load Word Templates" $word.Templates.LoadBuildingBlocks() If ( $WordVersion -eq 12) { $BuildingBlocks=$word.Templates | Where {$_.name -eq "Building Blocks.dotx"} $part=$BuildingBlocks.BuildingBlockEntries.Item($CoverPage) } Else { $BuildingBlocks=$word.Templates | Where {$_.name -eq "Built-In Building Blocks.dotx"} $part=$BuildingBlocks.BuildingBlockEntries.Item($CoverPage) } write-verbose "Create empty word doc" $Doc = $Word.Documents.Add() $global:Selection = $Word.Selection #insert new page, getting ready for table of contents write-verbose "insert new page, getting ready for table of contents" $part.Insert($selection.Range,$True) | out-null $selection.InsertNewPage() #table of contents write-verbose "table of contents" $toc=$BuildingBlocks.BuildingBlockEntries.Item("Automatic Table 2") $toc.insert($selection.Range,$True) | out-null #set the footer write-verbose "set the footer" [string]$footertext="Report created by $username" #get the footer write-verbose "get the footer and format font" $doc.ActiveWindow.ActivePane.view.SeekView=$wdSeekPrimaryFooter #get the footer and format font $footers=$doc.Sections.Last.Footers foreach ($footer in $footers) { if ($footer.exists) { $footer.range.Font.name="Calibri" $footer.range.Font.size=8 $footer.range.Font.Italic=$True $footer.range.Font.Bold=$True } } #end Foreach write-verbose "Footer text" $selection.HeaderFooter.Range.Text=$footerText #add page numbering write-verbose "add page numbering" $selection.HeaderFooter.PageNumbers.Add($wdAlignPageNumberRight) | Out-Null #return focus to main document write-verbose "return focus to main document" $doc.ActiveWindow.ActivePane.view.SeekView=$wdSeekMainDocument #move to the end of the current document write-verbose "move to the end of the current document" $selection.EndKey($wdStory,$wdMove) | Out-Null #end of Jeff Hicks
The only change I had to make to Jeff’s script was in loading the Word Templates. Word 2007 used the name “Building Blocks.dotx”. I had to add an “If” statement to handle that condition.
write-verbose "Load Word Templates" $word.Templates.LoadBuildingBlocks() If ( $WordVersion -eq 12) { $BuildingBlocks=$word.Templates | Where {$_.name -eq "Building Blocks.dotx"} $part=$BuildingBlocks.BuildingBlockEntries.Item($CoverPage) } Else { $BuildingBlocks=$word.Templates | Where {$_.name -eq "Built-In Building Blocks.dotx"} $part=$BuildingBlocks.BuildingBlockEntries.Item($CoverPage) }
In Version 1 and 2 of this script, in order to write out a line of output, my friend Michael B. Smith wrote a Line function. That function is no longer needed. Ryan took Michael’s function and modified it to write a line to Word.
To write data to Word you first use .TypeText() and then press the Enter key by using .TypeParagraph().
Function WriteWordLine #function created by Ryan Revord #@rsrevord on Twitter #function created to make output to Word easy in this script { Param( [int]$style=0, [int]$tabs = 0, [string]$name = '', [string]$value = '', [string]$newline = "'n", [switch]$nonewline) $output="" #Build output style switch ($style) { 0 {"No Spacing"} 1 {$Selection.Style = "Heading 1"} 2 {$Selection.Style = "Heading 2"} 3 {$Selection.Style = "Heading 3"} Default {"No Spacing"} } #build # of tabs While( $tabs -gt 0 ) { $output += "`t"; $tabs--; } #output the rest of the parameters. $output += $name + $value $Selection.TypeText($output) #test for new WriteWordLine 0. If($nonewline){ # Do nothing. } Else { $Selection.TypeParagraph() } }
In the original scripts, the Line function was used:
Line 1 "Administrator name: "$Administrator.AdministratorName Line 1 "Administrator type: " –nonewline
In this modified script, the WriteWordLine function is used:
WriteWordLine 2 1 "Administrator name: "$Administrator.AdministratorName WriteWordLine 0 1 "Administrator type: " -nonewline
The first parameter tells Word what Style to use. For the first line above, that is Heading 2. For the second line, that is No Spacing. The second parameter is how many tabs to indent.
The next changes in Version 3 come in the Servers section. I added a Word Table to hold information on the Citrix services. I know I can get more data on the services by using WMI Queries but in a large farm with XenApp servers spread geographically; those queries can cause excessive network traffic. I am only using the Get-Service cmdlet because it is native and also supports remoting.
#list citrix services write-verbose "Processing Citrix services for server $($server.ServerName)" $services = get-service -ComputerName $server.ServerName | where-object {$_.DisplayName -like "*Citrix*"} | sort-object DisplayName WriteWordLine 0 2 "Citrix Services" write-verbose "Create Word Table for Citrix services" $TableRange = $doc.Application.Selection.Range $Columns = 2 $Rows = $services.count + 1 $Table = $doc.Tables.Add($TableRange, $Rows, $Columns) $table.AutoFitBehavior(1) $table.Style = "Table Grid" $table.Borders.InsideLineStyle = 1 $table.Borders.OutsideLineStyle = 1 $xRow = 1 $Table.Cell($xRow,1).Shading.BackgroundPatternColor = $wdColorGray15 $Table.Cell($xRow,1).Range.Font.Bold = $True $Table.Cell($xRow,1).Range.Text = "Display Name" $Table.Cell($xRow,2).Shading.BackgroundPatternColor = $wdColorGray15 $Table.Cell($xRow,2).Range.Font.Bold = $True $Table.Cell($xRow,2).Range.Text = "Status" ForEach($Service in $Services) { $xRow++ $Table.Cell($xRow,1).Range.Text = $Service.DisplayName $Table.Cell($xRow,2).Range.Text = $Service.Status } #return focus back to document $doc.ActiveWindow.ActivePane.view.SeekView=$wdSeekMainDocument #move to the end of the current document $selection.EndKey($wdStory,$wdMove) | Out-Null
What I have not been able to figure out how to do is to move the Table to the right three indents. I recorded a Word macro, converted it to PowerShell and it did not work.
The Word Macro:
Selection.Tables(1).Select Selection.Paragraphs.Indent Selection.Paragraphs.Indent Selection.Paragraphs.Indent
My PowerShell code:
$Table.Range.Select() $Selection.Tables.Indent $Selection.Tables.Indent $Selection.Tables.Indent
I can see the Table get selected but it is not moved by three indents. If anyone knows how to do that, please let me know. I will update the script and give you credit.
The next change is to determine if Hotfix Rollup Pack 1 is installed. If not, compare the hotfixes installed to the recommended list from CTX129229 (dated 18-DEC-2012).
$HotfixArray = "" $HRP1Installed = $False WriteWordLine 0 2 "Citrix Hotfixes:" ForEach($hotfix in $hotfixes) { $HotfixArray += $hotfix.HotfixName If( $hotfix.HotfixName -eq "XA650W2K8R2X64R01") { $HRP1Installed = $True } WriteWordLine 0 3 "Hotfix`t`t`t: " $hotfix.HotfixName WriteWordLine 0 3 "Installed by`t`t: " $hotfix.InstalledBy WriteWordLine 0 3 "Installed date`t`t: " $hotfix.InstalledOn WriteWordLine 0 3 "Hotfix type`t`t: " $hotfix.HotfixType WriteWordLine 0 3 "Valid`t`t`t: " $hotfix.Valid WriteWordLine 0 0 "" } #compare Citrix hotfixes to recommended Citrix hotfixes from CTX129229 If( !$HRP1Installed ) { write-verbose "Processing pre HRP01 hotfix list for server $($server.ServerName)" #list is from CTX129229 dated 18-DEC-2012 $RecommendedList = @("XA650W2K8R2X64001","XA650W2K8R2X64011","XA650W2K8R2X64019","XA650W2K8R2X64025") ForEach($element in $RecommendedList) { If(!$HotfixArray -contains $element) { #missing a recommended Citrix hotfix WriteWordLine 0 3 "Recommended Citrix Hotfix $element is not installed" } } }
The same process is followed for the recommended Microsoft hotfixes.
#build list of installed Microsoft hotfixes write-verbose "Processing Microsoft hotfixes for server $($server.ServerName)" $MSInstalledHotfixes = Get-HotFix -computername $Server.ServerName | select-object -Expand HotFixID | sort-object HotFixID If($server.OSServicePack.IndexOf('1') -gt 0) { #Server 2008 R2 SP1 installed $RecommendedList = @("KB2731847","KB2571388","KB2465772", "KB917607", "KB2444328", "KB2551503", "KB2578159", "KB2620656", "KB2617858") } Else { #Server 2008 R2 without SP1 installed $RecommendedList = @("KB2731847","KB2571388","KB2465772", "KB917607", "KB2444328", "KB2551503", "KB2578159", "KB2620656", "KB2617858", "KB979530", "KB975777", "KB980663", "KB2265716", "KB238928", "KB983460", "KB2388142") } $results = @{} $PrintNotice = $False foreach( $hotfix in $RecommendedList ) { If(!($MSInstalledHotfixes -contains $hotfix)) { If(!$PrintNotice) { $PrintNotice = $True WriteWordLine 0 3 "Not all missing Microsoft hotfixes may be needed for this server" } #missing a recommended Citrix hotfix WriteWordLine 0 3 "Recommended Microsoft Hotfix $hotfix is not installed" } }
Since the Citrix.GroupPolicy.commands module does not support remoting, if remoting is being used, the policy section must be skipped.
#if remoting is enabled, the citrix.grouppolicy.commands module does not work with remoting so skip it If($Remoting) { write-warning "Remoting is enabled." write-warning "The Citrix.GroupPolicy.Commands module does not work with Remoting." write-warning "Citrix Policy documentation will not take place." }
Once all data has been gathered and placed into the Word document, the document must be finalized. First the Cover Page properties must be updated. These steps are also from Jeff Hicks.
write-verbose "Finishing up Word document" #end of document processing #Update document properties write-verbose "Set Cover Page Properties" _SetDocumentProperty $doc.BuiltInDocumentProperties "Company" $CompanyName _SetDocumentProperty $doc.BuiltInDocumentProperties "Title" $title _SetDocumentProperty $doc.BuiltInDocumentProperties "Subject" "XenApp 6.5 Farm Inventory" _SetDocumentProperty $doc.BuiltInDocumentProperties "Author" $username #Get the Coverpage XML part $cp=$doc.CustomXMLParts | where {$_.NamespaceURI -match "coverPageProps$"} #get the abstract XML part $ab=$cp.documentelement.ChildNodes | Where {$_.basename -eq "Abstract"} #set the text [string]$abstract="Citrix XenApp 6.5 Inventory for $CompanyName" $ab.Text=$abstract $ab=$cp.documentelement.ChildNodes | Where {$_.basename -eq "PublishDate"} #set the text [string]$abstract=( Get-Date -Format d ).ToString() $ab.Text=$abstract
The (Get-Date -Format d).ToString() will make sure the date on the Cover Page is displayed in the computer’s local date format.
Jeff’s _SetDocumentProperty function.
Function _SetDocumentProperty { #jeff hicks Param([object]$Properties,[string]$Name,[string]$Value) #get the property object $prop=$properties | foreach { $propname=$_.GetType().InvokeMember("Name","GetProperty",$null,$_,$null) if ($propname -eq $Name) { Return $_ } } #foreach #set the value $Prop.GetType().InvokeMember("Value","SetProperty",$null,$prop,$Value) }
The final steps are to:
• Update the Table of Contents,
• Save the document,
• Close the document,
• Quit Word, and
• Perform Garbage Collectionwrite-verbose "Update the Table of Contents" #update the Table of Contents $doc.TablesOfContents.item(1).Update() write-verbose "Save and Close document and Shutdown Word" If ($WordVersion -eq 12) { #Word 2007 $doc.SaveAs($filename, $SaveFormat::wdFormatDocument) } Else { $doc.SaveAs([REF]$filename, [ref]$SaveFormat::wdFormatDocument) } $doc.Close() $Word.Quit() [gc]::collect() [gc]::WaitForPendingFinalizers()
And there you have it, that is “all” there is to creating a really nice document in Microsoft Word using PowerShell.
Since this script has parameters, I wanted to create help text for the script.
<# .SYNOPSIS Creates a complete inventory of a Citrix XenApp 6.5 farm using Microsoft Word. .DESCRIPTION Creates a complete inventory of a Citrix XenApp 6.5 farm using Microsoft Word and PowerShell. Creates a Word document named after the XenApp 6.5 farm. Document includes a Cover Page, Table of Contents and Footer. .PARAMETER CompanyName Company Name to use for the Cover Page. Default value is contained in HKCU:\Software\Microsoft\Office\Common\UserInfo\Company This parameter has an alias of CN. .PARAMETER CoverPage What Microsoft Word Cover Page to use. (default cover pages in Word en-US) Valid input is: Alphabet (Word 2007/2010. Works) Annual (Word 2007/2010. Doesn't really work well for this report) Austere (Word 2007/2010. Works) Austin (Word 2010/2013. Doesn't work in 2013, mostly works in 2007/2010 but Subtitle/Subject & Author fields need to me moved after title box is moved up) Banded (Word 2013. Works) Conservative (Word 2007/2010. Works) Contrast (Word 2007/2010. Works) Cubicles (Word 2007/2010. Works) Exposure (Word 2007/2010. Works if you like looking sideways) Facet (Word 2013. Works) Filigree (Word 2013. Works) Grid (Word 2010/2013.Works in 2010) Integral (Word 2013. Works) Ion (Dark) (Word 2013. Top date doesn't fit, box needs to be manually resized or font changed to 8 point) Ion (Light) (Word 2013. Top date doesn't fit, box needs to be manually resized or font changed to 8 point) Mod (Word 2007/2010. Works) Motion (Word 2007/2010/2013. Works if top date is manually changed to 36 point) Newsprint (Word 2010. Works but date is not populated) Perspective (Word 2010. Works) Pinstripes (Word 2007/2010. Works) Puzzle (Word 2007/2010. Top date doesn't fit, box needs to be manually resized or font changed to 14 point) Retrospect (Word 2013. Works) Semaphore (Word 2013. Works) Sideline (Word 2007/2010/2013. Doesn't work in 2013, works in 2007/2010) Slice (Dark) (Word 2013. Doesn't work) Slice (Light) (Word 2013. Doesn't work) Stacks (Word 2007/2010. Works) Tiles (Word 2007/2010. Date doesn't fit unless changed to 26 point) Transcend (Word 2007/2010. Works) ViewMaster (Word 2013. Works) Whisp (Word 2013. Works) Default value is Motion. This parameter has an alias of CP. .PARAMETER UserName User name to use for the Cover Page and Footer. Default value is contained in $env:username This parameter has an alias of UN. .EXAMPLE PS C:\PSScript > .\XA65_Inventory_v3.ps1 Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Motion for the Cover Page format. Administrator for the User Name. .EXAMPLE PS C:\PSScript > .\XA65_Inventory_v3.ps1 -verbose Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Motion for the Cover Page format. Administrator for the User Name. Will display verbose messages as the script is runnin. .EXAMPLE PS C:\PSScript .\XA65_Inventory_v3.ps1 -CompanyName "Carl Webster Consulting" -CoverPage "Mod" -UserName "Carl Webster" Will use: Carl Webster Consulting for the Company Name. Mod for the Cover Page format. Carl Webster for the User Name. .EXAMPLE PS C:\PSScript .\XA65_Inventory_v3.ps1 -CN "Carl Webster Consulting" -CP "Mod" -UN "Carl Webster" Will use: Carl Webster Consulting for the Company Name (alias CN). Mod for the Cover Page format (alias CP). Carl Webster for the User Name (alias UN). .INPUTS None. You cannot pipe objects to this script. .OUTPUTS No objects are output from this script. This script creates a Word document. .LINK https://carlwebster.com/ documenting-a-citrix-xenapp-6-5-farm-with-microsoft-powershell-and-word-version-3 .NOTES NAME: XA65_Inventory_V3.ps1 VERSION: 3 AUTHOR: Carl Webster (with a lot of help from Michael B. Smith and Jeff Wouters) LASTEDIT: January 27, 2013 #>
Running the following command from the PowerShell prompt will display the full help text.
Get-Help .\XA65_Inventory_v3.ps1 -full
Sample output:
PS C:\webster> Get-Help .\xa65_Inventory_V3.ps1 -full NAME C:\webster\XA65_Inventory_V3.ps1 SYNOPSIS Creates a complete inventory of a Citrix XenApp 6.5 farm using Microsoft Word. SYNTAX C:\webster\XA65_Inventory_V3.ps1 [[-CompanyName] ] [[-CoverPage] ] [[-UserName] ] [] DESCRIPTION Creates a complete inventory of a Citrix XenApp 6.5 farm using Microsoft Word and PowerShell. Creates a Word document named after the XenApp 6.5 farm. Document includes a Cover Page, Table of Contents and Footer. PARAMETERS -CompanyName Company Name to use for the Cover Page. Default value is contained in HKCU:\Software\Microsoft\Office\Common\UserInfo\Company This parameter has an alias of CN. Required? false Position? 1 Default value Accept pipeline input? false Accept wildcard characters? -CoverPage What Microsoft Word Cover Page to use. (default cover pages in Word en-US) Valid input is: Alphabet (Word 2007/2010. Works) Annual (Word 2007/2010. Doesn't really work well for this report) Austere (Word 2007/2010. Works) Austin (Word 2010/2013. Doesn't work in 2013, mostly works in 2007/2010 but Subtitle/Subject & Author fields need to me moved after title box is moved up) Banded (Word 2013. Works) Conservative (Word 2007/2010. Works) Contrast (Word 2007/2010. Works) Cubicles (Word 2007/2010. Works) Exposure (Word 2007/2010. Works if you like looking sideways) Facet (Word 2013. Works) Filigree (Word 2013. Works) Grid (Word 2010/2013.Works in 2010) Integral (Word 2013. Works) Ion (Dark) (Word 2013. Top date doesn't fit, box needs to be manually resized or font changed to 8 point) Ion (Light) (Word 2013. Top date doesn't fit, box needs to be manually resized or font changed to 8 point) Mod (Word 2007/2010. Works) Motion (Word 2007/2010/2013. Works if top date is manually changed to 36 point) Newsprint (Word 2010. Works but date is not populated) Perspective (Word 2010. Works) Pinstripes (Word 2007/2010. Works) Puzzle (Word 2007/2010. Top date doesn't fit, box needs to be manually resized or font changed to 14 point) Retrospect (Word 2013. Works) Semaphore (Word 2013. Works) Sideline (Word 2007/2010/2013. Doesn't work in 2013, works in 2007/2010) Slice (Dark) (Word 2013. Doesn't work) Slice (Light) (Word 2013. Doesn't work) Stacks (Word 2007/2010. Works) Tiles (Word 2007/2010. Date doesn't fit unless changed to 26 point) Transcend (Word 2007/2010. Works) ViewMaster (Word 2013. Works) Whisp (Word 2013. Works) Default value is Motion. This parameter has an alias of CP. Required? false Position? 2 Default value Accept pipeline input? false Accept wildcard characters? -UserName User name to use for the Cover Page and Footer. Default value is contained in $env:username This parameter has an alias of UN. Required? false Position? 3 Default value Accept pipeline input? false Accept wildcard characters? This cmdlet supports the common parameters: Verbose, Debug, ErrorAction, ErrorVariable, WarningAction, WarningVariable, OutBuffer and OutVariable. For more information, type, "get-help about_commonparameters". INPUTS None. You cannot pipe objects to this script. OUTPUTS No objects are output from this script. This script creates a Word document. NOTES NAME: XA65_Inventory_V3.ps1 VERSION: 3 AUTHOR: Carl Webster (with a lot of help from Michael B. Smith and Jeff Wouters) LASTEDIT: January 27, 2013 -------------------------- EXAMPLE 1 -------------------------- PS C:\PSScript >.\XA65_Inventory_v3.ps1 Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Motion for the Cover Page format. Administrator for the User Name. -------------------------- EXAMPLE 2 -------------------------- PS C:\PSScript >.\XA65_Inventory_v3.ps1 -verbose Will use all default values. HKEY_CURRENT_USER\Software\Microsoft\Office\Common\UserInfo\Company="Carl Webster" $env:username = Administrator Carl Webster for the Company Name. Motion for the Cover Page format. Administrator for the User Name. Will display verbose messages as the script is runnin. -------------------------- EXAMPLE 3 -------------------------- C:\PS>PS C:\PSScript .\XA65_Inventory_v3.ps1 -CompanyName "Carl Webster Consulting" -CoverPage "Mod" -UserName "Carl Webster" Will use: Carl Webster Consulting for the Company Name. Mod for the Cover Page format. Carl Webster for the User Name. -------------------------- EXAMPLE 4 -------------------------- C:\PS>PS C:\PSScript .\XA65_Inventory_v3.ps1 -CN "Carl Webster Consulting" -CP "Mod" -UN "Carl Webster" Will use: Carl Webster Consulting for the Company Name (alias CN). Mod for the Cover Page format (alias CP). Carl Webster for the User Name (alias UN). RELATED LINKS
Documenting a Citrix XenApp 6.5 Farm with Microsoft PowerShell and Word – Version 3
PS C:\webster>You can also use –online to get taken to this article.
Get-Help .\XA65_Inventory_V3.ps1 -online
Running the script with –verbose, gives information of the script’s running.
.\xa65_inventory_v3.ps1 -CompanyName "The Accidental Citrix Admin" -CoverPage "Whisp" -UserName "Amalgamated Consulting Group" -verbose
Sample output.
PS C:\webster> .\xa65_inventory_v3.ps1 -CompanyName "The Accidental Citrix Admin" -CoverPage "Whisp" -UserName "Amalgamated Consulting Group" -verbose VERBOSE: Company Name: The Accidental Citrix Admin VERBOSE: Cover Page : Whisp VERBOSE: User Name : Amalgamated Consulting Group VERBOSE: Remoting is not being used VERBOSE: Getting Farm data VERBOSE: Setting up Word VERBOSE: Create Word comObject. If you are not running Word 2007, ignore the next message. VERBOSE: The object written to the pipeline is an instance of the type "Microsoft.Office.Interop.Word.ApplicationClass" from the component's primary interop assembly. If this type exposes different members than the IDispatch members, scripts written to work with this object might not work if the primary interop assembly is not installed. VERBOSE: Running Microsoft Word 2013 VERBOSE: Validate cover page VERBOSE: Load Word Templates VERBOSE: Create empty word doc VERBOSE: insert new page, getting ready for table of contents VERBOSE: table of contents VERBOSE: set the footer VERBOSE: get the footer and format font VERBOSE: Footer text VERBOSE: add page numbering VERBOSE: return focus to main document VERBOSE: move to the end of the current document VERBOSE: Processing Configuration Logging VERBOSE: Processing Administrators VERBOSE: Processing Applications VERBOSE: Processing Configuration Logging/History Report VERBOSE: ParameterSet = ByConnectionString VERBOSE: Processing Load Balancing Policies WARNING: Load balancing policy information could not be retrieved VERBOSE: Processing Load Evaluators VERBOSE: Processing Servers VERBOSE: Processing Citrix services for server XA651 VERBOSE: Create Word Table for Citrix services VERBOSE: Processing Microsoft hotfixes for server XA651 VERBOSE: Processing Citrix services for server XA652 VERBOSE: Create Word Table for Citrix services VERBOSE: Processing Microsoft hotfixes for server XA652 VERBOSE: Processing Citrix services for server XA653 VERBOSE: Create Word Table for Citrix services VERBOSE: Processing Microsoft hotfixes for server XA653 VERBOSE: Processing Citrix services for server XA654 VERBOSE: Create Word Table for Citrix services VERBOSE: Processing Microsoft hotfixes for server XA654 VERBOSE: Processing Worker Groups VERBOSE: Processing Zones VERBOSE: Processing Citrix IMA Policies VERBOSE: Finishing up Word document VERBOSE: Set Cover Page Properties VERBOSE: Update the Table of Contents VERBOSE: Save and Close document and Shutdown Word PS C:\webster>
How to use this script?
I saved the script as XA65_Inventory_V3.ps1 in the C:\PSScripts folder. From the PowerShell prompt, change to the C:\PSScripts folder, or the folder where you saved the script. From the PowerShell prompt, type in:
.\XA65_Inventory_V3.ps1 and press Enter.
If you have any suggestions for the script, please let me know. Send an e-mail to webster@carlwebster.com.
NOTE: This script is continually updated. You can always find the most current version by going to https://carlwebster.com/where-to-get-copies-of-the-documentation-scripts/
Copies of all the Cover Pages can be found here:
12 Responses to “Documenting a Citrix XenApp 6.5 Farm with Microsoft PowerShell and Word – Version 3”
Leave a Reply to Chaitanyakumar G
January 10, 2014 at 10:27 am
The dropbox link site cannot be found. IS the latest script still available somewhere? I would love to try it against our environment.
Thank you.
January 10, 2014 at 10:08 pm
Thanks for reminding me I needed to go through every documentation script related article and update the links. I have updated every article with a new standard link.
Webster
July 29, 2013 at 2:04 pm
Hi Carl,
I have designed powershell script to install xenapp 6(3 versions, added more feasibility in every version), and now I have created posh script for xenapp 6.5. I used your script given in this site. I have got only one thing to say. YOU ARE AWESOME!!! great…
Chaitanya.
March 21, 2013 at 9:06 am
hi,
I have a farm XenApp 6.5 and i want to try your script.
But i don’t know where I can find your “Building Blocks.dotx” ?
I have only : “Built-In Building Blocks.dotx”
My Word 2010 version is in french.
Thank you.
March 21, 2013 at 9:10 am
Unfortunately, the current scripts only support English versions of Microsoft Word. Support for non-English versions of Word is planned for the V4 script.
Sorry
Webster
February 11, 2013 at 10:48 am
I had an issue with the 6.5 V3 documentation script crashing out in a customer environment due to accumulated spell check autocorrect processing. The script would fail half way through the farm and eventually an error dialog from word would appear. I resolved it by explicitly disabling the spell checker and grammar checker in the script. I added the following after line # 524 in the unsigned script.
522 write-verbose “Create empty word doc”
523 $Doc = $Word.Documents.Add()
524 $global:Selection = $Word.Selection
525
526 #Disable Spell and Grammer Check to resolve issue and improve performance
527 $Word.Options.CheckGrammarAsYouType=$false
528 $Word.Options.CheckSpellingAsYouType=$false
February 11, 2013 at 11:55 am
Sweet! Thanks for the tip. I will add this to the next version of the script I will be releasing next week.
Webster
February 4, 2013 at 2:13 pm
If the farm doesn’t have office installed on any of the servers is it possible to run this from a workstation that may have the Appcenter on it?
February 4, 2013 at 4:13 pm
Yes, this should work provided:
On the XenApp Server, Firewall rule created to allow inbound TCP Port 2513 from your Win7 PC
AppCenter is installed on the client
You may need the XenApp PoSH SDK installed on the client (mine did)
Word installed on the client
On the client run Set-XADefaultComputerName XA65ControllerServerName
Except for the Citrix Group Policy stuff, the script should then run just fine.
Thanks
Webster
January 28, 2013 at 4:44 pm
Nice stuff 😉
January 28, 2013 at 3:21 pm
Whenever time permits you could comment upon which cover sheets are included with Word 2010/2013 and where/how to go look at them without running the script 34,445 times 🙂 🙂
Otherwise, totally awesome gift to the Citrix community.
Thank you, Tom
P.S. Put Submit button BELOW the math question, please. 🙂
January 28, 2013 at 3:22 pm
At the end of the article are links to sample cover sheets for all three versions of Word. I already ran the script 34,445 times! 🙂
Webster