Programatically Convert InfoPath Form to PDF and Upload to SharePoint

June 11th, 2009

I struggled for a while to find a solution to this issue, so I thought I would share.

What I wanted was an InfoPath form that a user could navigate to, fill out some fields, and when they hit Submit it would take that information and shove it in a pre-canned letter, export it to a PDF and then write that PDF to a SharePoint document library. Once it was in that document library we could do all sorts of cool stuff to it with Workflows.

On the InfoPath side the creation of the form was pretty simple. You start with a blank InfoPath form and create two sections. Name one section “sectionInput” and the other “sectionOutput”. Then add a new data source named “hideInput” with a data type of “True/False (boolean)” with a default value of FALSE to the myFields container.

Now open the properties of your “sectionInput” section, click on the Display tab, then click on the “Conditional Formatting…” button. In the Conditional Formatting window, click Add, then create a rule that say if “hideInput” is equal to “TRUE” to “Hide this control”. Do the same thing to the “sectionOutput” section, but make the control hidden when “hideInput” is FALSE.

Now add your fields and a button to the “sectionInput” section. Copy your pre-canned letter or whatever into the “sectionOutput” section. In the areas of the pre-canned letter that you want to be populated by the fields from the “sectionInput” section, you simply have to add an “Expression Box” control and tie that box to the particular field that you want to display.

Now, right click on the button you created in the sectionInput section and choose “Button Properties…” then click on the “Edit Form Code…” button (make sure you have set up InfoPath to use C# code).

In the new code window, click on Project -> Add Reference and add the Microsoft.Office.Interop.Word 12.0 reference.

Here is a sample of what the full code for the button should look like.

using Microsoft.Office.InfoPath; using Word = Microsoft.Office.Interop.Word; using System; using System.Collections.Generic; using System.Net; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Xml; using System.Xml.XPath; using mshtml; namespace NDA___WM3 { public partial class FormCode { // Member variables are not supported in browser-enabled forms. // Instead, write and read these values from the FormState // dictionary using code such as the following: // // private object _memberVariable // { // get // { // return FormState["_memberVariable"]; // } // set // { // FormState["_memberVariable"] = value; // } // } // NOTE: The following procedure is required by Microsoft Office InfoPath. // It can be modified using Microsoft Office InfoPath. public void InternalStartup() { ((ButtonEvent)EventManager.ControlEvents["buttonSubmit"]).Clicked += new ClickedEventHandler(buttonSubmit_Clicked); } /// 
        /// Declare all variables and assign values to "paramUploadLocation" related variables.
        /// string paramTempLocation = System.IO.Path.GetTempPath(); string paramUploadLocation = "http://SharePoint/DocumentLibrary/"; string paramFilename; string paramDocFilename; string paramPdfFilename; // string paramExportFilePath; string[] paramMailRecipients = null; XPathNavigator paramHideInputShowOutput; /// /// Create "functionExtractData" function. /// /// This function extracts data from the infopath form and assings to to variables. /// void functionExtractData() { paramHideInputShowOutput = MainDataSource.CreateNavigator().SelectSingleNode("/my:myFields/my:hideInput-showOutput", NamespaceManager); } /// 
        /// Create "functionHideInputShowOutput" function.
        ///
        /// This function hides the input section and shows the output section.
        /// void functionHideInputShowOutput() { if (paramHideInputShowOutput != null && paramHideInputShowOutput.ValueAsBoolean == false) { paramHideInputShowOutput.SetValue("true"); } else { MessageBox.Show("There has been an error.", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// 
        /// Create "functionExportToDoc" function.
        ///
        /// This function exports the current view and creates a DOC file.
        /// void functionExportToDoc() { /// /// Assign a value to the "paramDocFilename" variable. /// paramFilename = "InfoPathToPDF" + "_" + DateTime.Now.Ticks; paramDocFilename = paramTempLocation + paramFilename + ".doc"; /// 
            /// Export the current view to a DOC file.
            /// this.CurrentView.Export(paramDocFilename, ExportFormat.Mht); } /// /// Create "functionConvertDocToPDF" function. /// /// This function coverts the DOC file created in the "functionExportToDoc" function to PDF. /// 
        void functionConvertDocToPDF()
        {
 
            /// 
            /// Declare variables
            /// Word.Application wordApplication = null; Word.Documents wordDocuments = null; Word.Document wordDocument = null; Word.WdExportCreateBookmarks paramCreateBookmarks; Word.WdExportFormat paramExportFormat; Word.WdExportItem paramExportItem; Word.WdExportOptimizeFor paramExportOptimizeFor; Word.WdExportRange paramExportRange; bool paramBitmapMissingFonts; bool paramDocStructureTags; bool paramIncludeDocProps; bool paramKeepIRM; bool paramOpenAfterExport; bool paramUseISO19005_1; int paramStartPage; int paramEndPage; object paramSourceDocPath = null; object paramMissing = null; try { /// 
                /// Assign values to variables.
                /// wordApplication = new Word.Application(); paramSourceDocPath = paramDocFilename; paramMissing = Type.Missing; paramPdfFilename = paramTempLocation + paramFilename + ".pdf"; paramExportFormat = Word.WdExportFormat.wdExportFormatPDF; paramOpenAfterExport = false; paramExportOptimizeFor = Word.WdExportOptimizeFor.wdExportOptimizeForPrint; paramExportRange = Word.WdExportRange.wdExportAllDocument; paramStartPage = 0; paramEndPage = 0; paramExportItem = Word.WdExportItem.wdExportDocumentContent; paramIncludeDocProps = true; paramKeepIRM = true; paramCreateBookmarks = Word.WdExportCreateBookmarks.wdExportCreateWordBookmarks; paramDocStructureTags = true; paramBitmapMissingFonts = true; paramUseISO19005_1 = false; /// 
                /// Invoke new Word application.
                /// wordApplication = new Word.Application(); wordDocuments = wordApplication.Documents; /// 
                /// Open source DOC file.
                /// wordDocument = wordDocuments.Open(ref paramSourceDocPath, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing); /// 
                /// Export DOC file to PDF Format.
                /// if (wordDocument != null) wordDocument.ExportAsFixedFormat(paramPdfFilename, paramExportFormat, paramOpenAfterExport, paramExportOptimizeFor, paramExportRange, paramStartPage, paramEndPage, paramExportItem, paramIncludeDocProps, paramKeepIRM, paramCreateBookmarks, paramDocStructureTags, paramBitmapMissingFonts, paramUseISO19005_1, ref paramMissing); } /// 
            /// Display message if exception occurs.
            /// catch (Exception ex) { MessageBox.Show("An error has occured, please try the operation again. If the error persists, please contact your system administrator.\n" + ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { /// 
                /// Close and release the Document object
                /// if (wordDocument != null) { wordDocument.Close(ref paramMissing, ref paramMissing, ref paramMissing); wordDocument = null; } /// /// Quite word and release the ApplicationClass oject /// if (wordApplication != null) { wordApplication.Quit(ref paramMissing, ref paramMissing, ref paramMissing); wordApplication = null; } /// 
                /// Release the wordApplication.
                /// Release(wordDocument); Release(wordDocuments); Release(wordApplication); } } /// /// Create "functionFileUpload" function. /// /// This function uploads the specified file to the specified SharePoint site. /// void functionFileUpload(string paramUploadSource, string paramUploadDestination) { WebClient WC = new WebClient(); WC.UseDefaultCredentials = true; byte[] response = WC.UploadFile(paramUploadDestination, "PUT", paramUploadSource); } /// 
        /// Clean up
        /// public static void Release(object o) { if (o != null && Marshal.IsComObject(o)) { int refCount = 0; do { try { refCount = Marshal.FinalReleaseComObject(o); } catch { } } while (refCount > 0); o = null; } } /// 
        /// Execute Code
        /// public void buttonSubmit_Clicked(object sender, ClickedEventArgs e) { functionExtractData(); functionHideInputShowOutput(); functionExportToDoc(); functionConvertDocToPDF(); functionFileUpload(paramPdfFilename, paramUploadLocation + paramFilename + ".pdf"); MessageBox.Show("Your form has been successfully submitted.", "Success!", MessageBoxButtons.OK, MessageBoxIcon.Information); this.Application.ActiveWindow.Close(false); } } }

That should pretty much do it, if you can successfully impliment the code above you will now have an InfoPath form that will convert to PDF and upload itself to a SharePoint document library.

It would be very easy to add additional functionality to the script, like sending an e-mail with the file attached, etc.

Richard C#, Microsoft Office, Programming, SharePoint, System Administration

Information Gathering via PowerShell Script Pt. 2

May 13th, 2009

Here is another script that I created while trying to hone my PowerShell skills. It prompts you for the FQDN of the computer that you want to gather information on, asks you whether you want to see the output on the screen or dump it into a text file, and then runs a bunch of WMI queries to get a good general overview of the machine in question.

# Function Definition: fnCompInfoGatherExecute
Function fnCompInfoGatherExecute
{
	# Prompt for FQDN of Computer to be Queried
	"Enter the FQDN of the computer you wish to query."
	$CompName = Read-Host " "
 
    # Prompt for Output Method
	" "
	"How would you like the output to be handled?"
	$MenuTopLevel = 
'
[1] Display on Screen
[2] Output to File
[3] Exit 
 
Choice'
 
	# Define Logic for Top Level Menu
	switch (Read-Host $MenuTopLevel)
	{
		1 {
			# Define WMI Information to be Retrieved
			Get-WmiObject Win32_BIOS -ComputerName "$CompName"
			Get-WmiObject Win32_ComputerSystem -ComputerName "$CompName"
			Get-WmiObject Win32_DiskDrive -ComputerName "$CompName"
			Get-WmiObject Win32_DiskPartition -ComputerName "$CompName"
			Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName "$CompName"
			Get-WmiObject Win32_Processor -ComputerName "$CompName"
		  }
		2 {
			# Prompt for Output Path
			" "
			"Enter the path to the output file (i.e. C:\Output.txt)."
			$OutputPath = Read-Host " "
 
			# Define WMI Information to be Retrieved
			Get-WmiObject Win32_BIOS -ComputerName "$CompName" >> "$OutputPath"
			Get-WmiObject Win32_ComputerSystem -ComputerName "$CompName" >> "$OutputPath"
			Get-WmiObject Win32_DiskDrive -ComputerName "$CompName" >> "$OutputPath"
			Get-WmiObject Win32_DiskPartition -ComputerName "$CompName" >> "$OutputPath"
			Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName "$CompName" >> "$OutputPath"
			Get-WmiObject Win32_Processor -ComputerName "$CompName" >> "$OutputPath"
 
			# Open Output File
			C:\Windows\notepad.exe "$OutputPath"
		  }
		3 {Exit}
		default {"You have chosen an invalid option"; fnPause; fnADSearchMenu}
	}
}
 
# Call fnCompInfoGatherExecute Function
fnCompInfoGatherExecute

Richard PowerShell, System Administration

Information Gathering via PowerShell Script Pt. 1

May 13th, 2009

Here is a simple PowerShell script I wrote to gather either computer, group, or user information depending on your choices. This could easily be done with much simpler scripts, but I wanted to use it as more of a learning process in order to better understand AD queries, variable expansion, functions, and other PowerShell features.

# Function Definition: fnPause
Function fnPause ($message="Press any key to continue...")
	{
		Write-Host -NoNewLine $Message
		$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
		Write-Host ""
		Main_Menu
	}
 
# Function Definition: fnADSearchMenu 
Function fnADSearchMenu
{
	# Display Welcome Message
	Clear-Host
	"Active Directory Search Script v1.0"
	"Created By: Richard Raseley (Richard@Raseley.com)"
	" "
 
	# Display Top Level Menu Question
	"What type of Active Directory object would you like to search for?"
 
	# Display Top Level Menu
	$MenuTopLevel = 
	'
	[1] User(s)
	[2] Group(s)
	[3] Computer(s)
	[4] Exit 
 
	Choice'
 
	# Define Logic for Top Level Menu
	switch (Read-Host $MenuTopLevel)
	{
		1 {fnUserSearchMenu}
		2 {fnGroupSearchMenu}
		3 {fnComputerSearchMenu}
		4 {Exit}
		default {"You have chosen an invalid option"; fnPause; fnADSearchMenu}
	}
}
 
# Function Definition: fnUserSearchMenu
Function fnUserSearchMenu
{
	# Display User Search Menu Question
	" "
	"What type of user information would you like?"
 
	# Display User Search Menu
	$MenuUserSearch =
	'
	[1] Summary of all users in the current domain
	[2] Return to the main menu
 
	Choice'
 
	# Define Logic for User Search Menu
	switch (Read-Host $MenuUserSearch)
	{
		1 {
		  	#Define LDAP Filter
			$LDAPFilter = "(objectCategory=User)"
 
		  	#Call fnADSearchExecute
		  	fnADSearchExecute
		  }
		2 {
	    	fnADSearchMenu
		  }
		default {"You have chosen an invalid option"; fnPause; fnADSearchMenu}
	}
}
 
# Function Definition: fnGroupSearchMenu
Function fnGroupSearchMenu
{
	# Display Group Search Menu Question
	" "
	"What type of group information would you like?"
 
	# Display Group Search Menu
	$MenuGoupSearch =
	'
	[1] Summary of all groups in the current domain
	[2] Return to main menu
 
	Choice'
 
	# Define Logic for Group Search Menu
	switch (Read-Host $MenuGoupSearch)
	{
		1 {
			# Define LDAP Filter
			$LDAPFilter = "(objectCategory=Group)"
 
			#Call fnADSearchExecute
			fnADSearchExecute
		  }
		2 {
			fnADSearchMenu
		  }
		default {"You have chosen an invalid option"; fnPause; fnADSearchMenu}
	}
}
 
# Function Definition: fnComputerSearchMenu
Function fnComputerSearchMenu
{
	# Display Computer Search Menu Question
	" "
	"What type of computer information would you like?"
 
	# Display Group Search Menu
	$MenuComputerSearch =
	'
	[1] Summary of all computers in the current domain
	[2] Return to main menu
 
	Choice'
 
	# Define Logic for Group Search Menu
	switch (Read-Host $MenuComputerSearch)
	{
		1 {
			# Define LDAP Filter
			$LDAPFilter = "(objectCategory=Computer)"
 
			#Call fnADSearchExecute
			fnADSearchExecute
		  }
		2 {
			fnADSearchMenu
		  }
		default {"You have chosen an invalid option"; fnPause; fnADSearchMenu}
	}
}
 
# Function Definition: fnADSearchExecute
Function fnADSearchExecute
{
	# Define AD Search Filter
	$strFilter = "$LDAPFilter"
 
	# Define AD Location for Search
	$objDomain = New-Object System.DirectoryServices.DirectoryEntry
 
	# Define AD Search Parameters
	$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
	$objSearcher.SearchRoot = $objDomain
	$objSearcher.PageSize = 1000
	$objSearcher.Filter = $strFilter
	$objSearcher.SearchScope = "Subtree"
 
	# Define AD Properties Returned by Search
	$colProplist = "name"
	foreach ($i in $colProplist){$objSearcher.PropertiesToLoad.Add($i)}
 
	# Execute AD Search
	$colResults = $objSearcher.FindAll()
 
	# Format AD Search Results
	foreach ($objResult in $colResults)
	{
		$objItem = $objResult.Properties
		"Name: " + $objItem.name
		" "
	}
}
 
# Call ADSearch Menu Function
fnADSearchMenu

Richard Active Directory, PowerShell , ,

Left4Dead – Survival – No Mercy, Gas Station

April 30th, 2009

Me playing Left 4 Dead Survival mode on the No Mercy – Gas Station level.

Richard Uncategorized , , , , ,

Deny Logoff of an Administrator Logged in to the Console Session

April 21st, 2009

Here is a Group Policy setting you can apply in Active Directory to prevent an administrator or other user from logging you off from a machine that you have remotely logged into via the console session.

Policy Path: Administrative Templates\Windows Components\Terminal Services

Supported On: At least Microsoft Windows Server 2003

Help/Explain Text: Specifies whether to allow an administrator attempting to connect to the console of a server to log off an administrator currently logged on to the console. The console session is also known as Session 0. Console access can be obtained by using the /console switch from Remote Desktop Connection in the computer field name or from the command line. If the status is set to Enabled, logging off the connected administrator is not allowed. If the status is set to Disabled, logging off the connected administrator is allowed. If the status is set to Not Configured, logging off the connected administrator is allowed but can be changed at the local computer policy level. This policy is useful when the currently connected administrator does not want to be logged off by another administrator. If the connected administrator is logged off, any data not previously saved is lost.

Registry Settings: HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services!fDisableForcibleLogoff

Richard Active Directory, System Administration ,

Run IE6, IE7 and IE8 Side by Side

April 21st, 2009

IE6-IE7-IE8

There is an interesting post over @ AARFing.dk with instructions on how to get IE6, IE7, and IE8 running side by side for testing purposes.

Link: http://aarfing.dk/?p=120

Richard Computer Hardware and Software, Consumer Hardware and Software, Windows

Exchange 2010

April 15th, 2009

Exchange 2010

Exchange 2010 Beta is now available!

You can go to https://www.microsoft.com/exchange/2010/en/us/trial-software.aspx and download a 360 day trial. The RTM and public launch will probably coincide with the launch of Office 2010 and SharePoint Server 2010.

Richard Enterprise Hardware and Software, Exchange Server

Are Violent Video Games Adequately Preparing Children For The Apocalypse?

February 26th, 2009

The G1

February 25th, 2009
T-Mobile G1

T-Mobile G1

I got a new phone today, the Google G1. All I have to say is =]

Richard Consumer Hardware and Software, Personal , ,

Physical to Virtual Conversion Methods with Hyper-V

February 19th, 2009

A lot of people seem to wonder what the best, FREE,  way to do a Physical to Virtual (P2V) conversion of their Windows servers is. If your VM host is going to be a Hyper-V server, then there are two good methods (that I know of) to perform the operation.

Method 1:

Use the System Center Virtual Machine Manager’s (SCVMM) integrated P2V conversion utility to perform the operation. This supports doing a live migration, meaning that the target system can remain online and available for user’s requests during the migration period.

SCVMM 180 Day Evaluation: http://technet.microsoft.com/en-us/evalcenter/cc793138.aspx

Method 2:

If you don’t want to use the SCVMM method or it isn’t working properly for you, you can use the free VMWare converter tool. The VMWare converter tool also supports live migrations. After you perform the live P2V conversion with the VMWare converter tool you will end up with a VMDK file (VMWare’s virtual hard disk format), so that will have to be converted to a Hyper-V usable file with the VMDK to VHD converter.

VMWare Converter: http://www.vmware.com/products/converter/

VMDK to VHD Converter: http://vmtoolkit.com/files/folders/converters/entry8.aspx

Good luck!

Richard Hyper-V, System Administration, Windows , , ,