For some reasons organizations use InfoPath form and there might be attachments within that. This kind of forms are kept in SharePoint list and libraries where is defined by creator of application, as XML format item which you should have InfoPath application installed on your machine in order to see and download content properly.
At my scenario, as mentioned it is not easy to open all of them item by item with InfoPath and retrieve required information once you need. Therefore I’ve developed this script to download InfoPath forms as XML file and play around with it in order to save attachments within InfoPath forms to where ever I want.
Once the case came to me, at the first time I thought the attachments that within InfoPath form might be an item just kept in somewhere in SharePoint library as document but wrong! It exists within XML file as Base64Code format. So I was have to encode it properly and save to somewhere in network. In order to do that I was have to parse XML files first.
Consequently, you are going to see in this script following steps;
Tips and tricks for whom intended to use this script;
You will need to specify only below variables and also be Farm Administrator and also DBOwner of content database.
$webUrl = “http://erdemayyildiz.com/TRAVEL” //Site to connect
$library = “TravelFormArchive” //Library Name to connect
$destFolder = “C:\TEMP\” //Path to download and parse XML files and attachments
$attachments = $xml.myFields.Attachments # Check this field information from XML format this information changes for every InfoPath based on creator decision.
################################ # Author: E.Ayyildiz # Date: 01/07/2021 # Version: 1.0.1 ################################ Add-PSSnapin Microsoft.SharePoint.Powershell #Variables that need to be specified $webUrl = "http://erdemayyildiz.com/TRAVEL" $library = "TravelFormArchive" $destFolder = "C:\TEMP\" $s = new-object Microsoft.SharePoint.SPSite($webUrl) $w = $s.OpenWeb() $l = $w.Lists[$library] foreach ($listItem in $l.Items) { #Download XML files Try { $file = $w.GetFile($listItem.File) $bytes = $file.OpenBinary() $path = $destFolder + $listItem.Name Write "Saving to the loction $path" $fs = new-object System.IO.FileStream($path, "OpenOrCreate") $fs.Write($bytes, 0 , $bytes.Length) $fs.Close() } Catch{} } function ParseInfoPath() { # Enumerate source XML files $files = Get-ChildItem $destFolder "*.xml" foreach ($f in $files) { # XPath parse attachment XML Base64 into Binary $xml = Get-Content $f.FullName $attachments = $xml.myFields.Attachments # Check this field information from XML format foreach($attachment in $attachments){ ParseSingleXML $f.FullName $attachment.Attachment } } } function ParseSingleXML($xmlFileName, $attachBase64) { # Set text encoding $encoding = [System.Text.Encoding]::Unicode; $convert = [Convert]::FromBase64String($attachBase64) $ms = New-Object System.IO.MemoryStream(,$convert) $theReader = New-Object System.IO.BinaryReader($ms) # Parse file attachment [System.Byte[]] $headerData = $theReader.ReadBytes(16); [Int]$fileSize = $theReader.ReadUInt32(); [Int]$attachmentNameLength = $theReader.ReadUInt32() * 2; [System.Byte[]] $fileNameBytes = $theReader.ReadBytes($attachmentNameLength); [string]$fileName = $encoding.GetString($fileNameBytes, 0, $attachmentNameLength-2); # Write file content Write-Host "$xmlFileName attachment $fileName is saving.. " -Fore "Green" # Create folder $xmlFileName = $xmlFileName.Replace(".xml","_xml") mkdir $xmlFileName -ErrorAction SilentlyContinue | Out-Null # Write attachments $destFile = "$xmlFileName\$fileName" [IO.File]::WriteAllBytes($destFile, [Convert]::FromBase64String($attachBase64)) } ParseInfoPath #End
Hope it works for you!
Thanks for reading.
Erdem Ayyildiz