TL;DR Searching for the error message and looking for the answer? Skip to the bottom!
Introduction to Import/Export-CsUserData
I feel a bit of an introduction is necessary as I wouldn’t encourage anyone to mess with these cmdlets unless there are no other options, but. I’ve recently been building a new Skype for Business 2019 deployment for a customer that’s moving across AD forests as part of an acquisition.
As part of this move, we are trying to preserve user data wherever possible including, user contact lists.
Now as you may or may not know. Skype4B does not support cross-forest migration. So users are being disabled in one forest and enabled in another.
Thankfully they are also getting different SIP domains so we can cut them over in small blocks making testing easy.
As part of the migration steps, I have been exporting the user’s contact data using Export-CsUserData from the old Lync environment and re-importing it into the Skype4B environment with Import-CsUserData
The trick here is though as users have a new SIP domain (and sip address format) a fair bit of manipulation had to go into the zip file that Export-CsUserData generated before it could be imported into the new environment including updating all the contacts stored in someone’s address book from olddomain.com to newdomain.com
Side note: As fellow MVP Greig Sheridan reminded me, a simple “Find and Replace” has the potential to introduce duplicate contacts. So make sure you know what you are doing before you go faffing about in there!
Greig also has a series with his owns struggles with Export/Import-CsUserData over here.
I’m not going to go into the manipulation’s I did or how I’m parsing data as my solution is still very flakey, so I won’t talk about it here as I’d hate to introduce errors in your environment.
But let’s take a quick look into the files. For those unaware, Export-CsUserData creates a zip file dumping user data from the SQL database in 2 XML files inside. (This is important for later)
[Content_Types].xml contains nothing of real importance and is likely just used by whatever XML library the Skype team used to create the file.
DocItemSet.xml is where all the fun stuff happens. We can open it up in XML Notepad and see it’s structured a bit like this.
Looking at the Name field for the DocItem’s we can determine a few things
URN is the User Resource Name
Confs tells us this entry is about the user’s conferences
James.Arber@ucmadscientist.com is the user’s SIP address
Expanding the XML tree downwards we can see that I have one conference on this user with a conference ID of FTALNOZX
We can further drill down into this to see who has been invited with what roles, but that’s not what we are here for.
If we look at the next node we see Confs has been changed for HCD which I assume is Hosted Calendar Data, it contains a bunch of encoded calendar data, which I’m guessing is Free/Busy information. Not what we are here for, but handy to know.
The next set of nodes is LCD which logic suggests is something along the lines of Local Contact Details, it contains your contact list, as well as all your contact and user options in an encoded in Base64 format (online decoder here)
Of important note for us, we have a list of Prompted Subscribers in plain text along with the display name of that contact in Base64 encoding.
And the last one is UPC which appears to be User Personal Certificates, handy to know but not what I was looking for.
So what about that error message then?
Ah yes, well as I alluded to before. Export/Import-CsUserData are a set of cmdlets that honestly can make Sefautil look like a tame circus animal/ Most of which Greig has documented already.
But I did run into probably the most unhelpful error message error which had me scratching my head for a while.
PS C:\UcMadScientist\Scripts\Migrate-CsUsers> Import-CsUserData -PoolFqdn aumlesfb01.ucmadscientist.com -FileName .\ContactsExportModified.zip -UserFilter firstname.lastname@example.org Import-CsUserData : Specified part does not exist in the package.
Here it is in a more copy/paste search engine friendly format too.
So what in blazes is the “Specified Part” that does not exist in the package?
Your first thought like mine might be to start digging through the XML looking for malformed data, but before you do. Make sure you didn’t make the rookie mistake I did.
When I repackaged my XML files for the ZIP import, I had compressed the folder, not the files! so inside the ZIP was a directory and inside that was the XML files. Hence Import-CsUserData couldn’t find the XML files (the specified part) in the package (the zip file) as it wasn’t where it expected it.
Luckily the fix was as simple as extracting the zip and compressing it again selecting the files instead of the directory.
Hope this helps someone, and maybe taught you a bit about CsUserData.