Author Posts

April 24, 2018 at 4:58 am

Hi, I'm trying to write a function which return XML variable.

function Create-XML()
{
    [xml]$xml = New-Object System.Xml.XmlDocument
    $Dec = $xml.CreateXmlDeclaration("1.0","UTF-8",$null)
    $xml.AppendChild($Dec)
    $Root = $xml.CreateNode("element","Changes",$null)
    $xml.AppendChild($Root)
    return ,$xml
}

If I'm trying to use output of this as xml type I'm getting error "Cannot convert value "System.Object[]" to type "System.Xml.XmlDocument""

April 24, 2018 at 2:56 pm

It's one of those messy things with powershell and functions.
There is a pretty good explanation in this post (a bit further down):
understanding output

To get around your problem either use [void] or pipe the AppendChild statements to Out-Null.
Otherwise the output of those statements will be added to the output of the function.
Which will give you an array instead of an XML document.

E.g.

function Create-XML()
{
    [xml]$xml = New-Object System.Xml.XmlDocument
    $Dec = $xml.CreateXmlDeclaration("1.0","UTF-8",$null)
    [void]$xml.AppendChild($Dec)
    $Root = $xml.CreateNode("element","Changes",$null)
    [void]$xml.AppendChild($Root)
    return ,$xml
}

April 24, 2018 at 3:19 pm

From my prior experimentation with methods of discarding output, I'd recommend a slightly different method.

Methods from slowest to fastest:

$Thing | Out-Null # slowest by an order of magnitude
[void] $Thing
$null = $Thing
$Thing > $null # fastest, but only a few ms ahead of the previous

April 24, 2018 at 3:52 pm

Interesting, at aprox. what amount of statements/iterations did you notice the difference?
Haven't investigated it myself so I guess I haven't run into the problem, that I know of at least.

April 24, 2018 at 4:17 pm

I tested it with some pretty straightforward stuff, at 10,000 iterations:

PS C:\WINDOWS\system32> Measure-Command {1..10000 | % {$_ | Out-Null}}

TotalMilliseconds : 601.827

PS C:\WINDOWS\system32> Measure-Command {1..10000 | % {[void]$_}}

TotalMilliseconds : 91.0079

PS C:\WINDOWS\system32> Measure-Command {1..10000 | % {$null = $_}}

TotalMilliseconds : 92.7215

PS C:\WINDOWS\system32> Measure-Command {1..10000 | % {$_ > $null}}

TotalMilliseconds : 91.0059

So in this particular instance, [void] and > $null worked the same, really. It seems to vary depending on iterations and what kind of things you're discarding, especially with Out-Null. You'll also get slightly different results if you repeat the test a few times, and it tends to average roughly in the order I mentioned, although pretty much any alternative to Out-Null works better than it does.

Interestingly, doing this actually works pretty quickly as well:

Out-Null -InputObject $Stuff

So it's the pipeline that causes the overhead, more than the command. But if you've already got a pipeline spun up, I don't think tacking on Out-Null instead of these other options would really slow things much, in that instance.

April 24, 2018 at 6:18 pm

When I measure commands like that, I do it a little different to time each execution and average them out. Here are my result. The cmdlet is still slower than the others.

Test Code

"Out-Null pipline"
(1..10000 | % {
    Measure-Command {
        "Test Data" | Out-Null
    }
} | Measure-Object -Average TotalMilliseconds).Average

"Out-Null cmdlet"
(1..10000 | % {
    Measure-Command {
        Out-Null -InputObject "Test Data"
    }
} | Measure-Object -Average TotalMilliseconds).Average

"Void"
(1..10000 | % {
    Measure-Command {
        [void]"Test Data"
    }
} | Measure-Object -Average TotalMilliseconds).Average

'$null='
(1..10000 | % {
    Measure-Command {
       $null = "Test Data"
    }
} | Measure-Object -Average TotalMilliseconds).Average

'Redirect null'
(1..10000 | % {
    Measure-Command {
        "Test Data" > $null
    }
} | Measure-Object -Average TotalMilliseconds).Average

Result 1:

Out-Null pipline
0.26157376
Out-Null cmdlet
0.261141030000001
Void
0.0158285399999992
$null=
0.0159924099999991
Redirect null
0.0187904100000002

Result 2:

Out-Null pipline
0.258285110000001
Out-Null cmdlet
0.25256677
Void
0.0159204299999991
$null=
0.0173433099999992
Redirect null
0.0185149200000002

Result 3:

Out-Null pipline
0.27897332
Out-Null cmdlet
0.264224209999999
Void
0.0176090299999993
$null=
0.0162245199999994
Redirect null
0.0187308600000004

April 24, 2018 at 8:00 pm

Very interesting! I guess either my prior test or my memory (or both!) was flawed.

I still personally prefer the > $null method syntactically, but it's nice to know that [void] is on par with $null =, if not better.

$null = Thing doesn't sit super well with me, it's a very odd kind of thing there.