Import-CliXml is a rather convenient way to import (configuration) data from serialized XML files which then can be easily processed as hashtables. But unfortunately, there seem to be some subtle bugs in the implementation of the Cmdlet (remember the implicit type conversion I wrote about before). This time it hit me when I was debugging a strange behaviour when using Enter-Infoblox which is part of our biz.dfch.PS.Ipam.Infoblox.Api PowerShell module. Strangely this had been working for months and all of a sudden it refused to perform a login.

Unfortunately, I had not been using Pester when I first created the module so I had to manually debug the problem and could not rely on unit tests to isolate the problem. After some investigation I saw that the serialised hashtable that I imported from the XML configuration file contained duplicate key names – something you would think is impossible for a hashtable … However, It was actually true and fully reproducible as you can see here:

PS > $ht = Import-Clixml .\HashtableDuplicateKey.xml
PS > $ht.GetType()

IsPublic IsSerial Name      BaseType
-------- -------- ----      --------
True     True     Hashtable System.Object
PS > $ht

Name          Value
----          -----
DuplicateKey  some other arbitrary value
DuplicateKey  arbitrary value

But even stranger than a hashtable with duplicate keys was the fact that it still did not behave consistently:

  • I could still Clone() the hashtable (effectively getting another broken hashtable)
  • I could not access either of the duplicate keys with ContainsKey() though it was shown to me in the Keys collection.
  • but I could still find all of its values via ContainsValue()

… very weird! After some investigation it turned out that someone modified the XML file on disk manually and accidently duplicated one of the keys, which then led to this incident. I created some Pester tests to demonstrate the behaviour (you can simply clone the repo and run Invoke-Pester in that directory).


#Requires -Module Pester
#Requires -Version 3.0
# see https://d-fens.ch/2015/06/28/bug-powershell-import-clixml-incorrectly-creates-hashtables-with-duplicate-keys/ for further explanation
$here = Split-Path Parent $MyInvocation.MyCommand.Path
$ImportCliXmlDuplicateKeys = "{0}.xml" -f $MyInvocation.MyCommand.Name.Replace('.Tests.ps1', '');
Describe Tags "Test-ImportCliXml" "Test-ImportCliXml" {
$ImportCliXmlDuplicateKeysPathAndFileName = Join-Path Path $here ChildPath $ImportCliXmlDuplicateKeys;
Context "Test-ImportCliXmlWithDuplicateKeys" {
It 'ShouldThrow-OnImportWithDuplicateKeys' {
{ Import-CliXml $ImportCliXmlDuplicateKeysPathAndFileName } | Should Throw;
}
It 'ShouldNotBe-TypeHashtable' {
$hashtable = Import-CliXml $ImportCliXmlDuplicateKeysPathAndFileName;
$hashtable -is [hashtable] | Should Not Be $True;
}
It 'ShouldNot-Contain2Keys' {
$hashtable = Import-CliXml $ImportCliXmlDuplicateKeysPathAndFileName;
$hashtable.Count | Should Not Be 2;
}
It 'ShouldNotThrow-ExceptionWhenAdding' {
$hashtable = Import-CliXml $ImportCliXmlDuplicateKeysPathAndFileName;
$hashtableTemp = @{};
{
foreach($i in $hashtable.GetEnumerator())
{
$hashtableTemp.Add($i.Name, $i.Value);
}
} | Should Not Throw;
}
It 'ShouldBe-TrueAndFindKey' {
$hashtable = Import-CliXml $ImportCliXmlDuplicateKeysPathAndFileName;
foreach($i in $hashtable.Keys)
{
$keyName = '{0}' -f $i;
break;
}
$hashtable.ContainsKey($keyName) | Should Be $true;
}
It 'ShouldBe-TrueAndFindValues' {
$hashtable = Import-CliXml $ImportCliXmlDuplicateKeysPathAndFileName;
$hashtable.ContainsValue('some other arbitrary value') | Should Be $true;
$hashtable.ContainsValue('arbitrary value') | Should Be $true;
}
}
}
#
# Copyright 2015 Ronald Rink, d-fens GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>System.Collections.Hashtable</T>
<T>System.Object</T>
</TN>
<DCT>
<En>
<S N="Key">DuplicateKey</S>
<S N="Value">arbitrary value</S>
</En>
<En>
<S N="Key">DuplicateKey</S>
<S N="Value">some other arbitrary value</S>
</En>
</DCT>
</Obj>
</Objs>

In addition I opened an issue at Microsoft Connect. Maybe this once gets fixed.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.