Back to top

FREE eBook: The Most USEFUL PowerShell CmdLets and more…

Grab a copy!

How To Import XML File In PowerShell

To import the XML file in PowerShell we use Import-Clixml CmdLet with the Path argument pointing to the location of the XML file.

IMPORTANTExport-Clixml CmdLet exports XML in the exact format that Import-Clixml CmdLet needs and some sample XML files will not be imported unless in the proper format as I will show you in examples below. For such XML files use Get-Content CmdLet instead.

In my previous article How To Export XML File In PowerShell I have described the export part while in this part I will focus on the Import of XML file using PowerShell.

INFO: If you want to know how to read XML file using Get-Content CmdLet please refer to these sections of the previously mentioned export article. Read XML File Using Get-Content CmdLet and Read XML File And Convert It To XML Object In PowerShell.

Import XML File Example Code

In this example we do several things:

  • Collect properties of all Windows Services on the local machine using Get-Service CmdLet.
  • Pipeline the result from Get-Service CmdLet to the Export-Clixml CmdLet that will save resultset as an XML file.
  • Import XML file into $ImportXML variable using Import-Clixml CmdLet.
  • Show the resultset in the PowerShell Grid.
Get-Service | Export-Clixml -Path 'C:\Temp\XMLExportDemo.xml' -Force

$ImportXML = Import-Clixml -Path 'C:\Temp\XMLExportDemo.xml'

$ImportXML | Out-GridView

Here is the resultset in the PowerShell grid.

Imported XML data presented in PowerShell grid

Let’s quickly check the data type of the XML file using Get-Member CmdLet.

$ImportXML | Get-Member

Each object saved in the XML file is the Service Controller data type which is PowerShell data type for Windows Services. This is completely logical since we have collected the properties of Windows Services using Get-Service CmdLet prior to saving in the XML file and Get-Service CmdLet resultset data type is, of course, Service Controller data type.

Service Controller Data type for collected Windows Services in XML file

If we look into the actual XML file we can see data type of collected objects and which properties are collected (Can Pause and Continue, Can Shutdown, Can Stop, Display Name, Dependencies, etc).

XML file created with Export-Clixml CmdLet

Import Failing For Sample XML File Into PowerShell

But what will happen if we try to import an XML file that was not exported using Export-Clixml CmdLet?

Here I have a sample XML file (XMLdemo.xml) used previously that is a valid XML document but it is not created by using Export-Clixml CmdLet.

Sample XML file (XMLdemo.xml)

Let’s try to import that XML file using Import-Clixml CmdLet.

$ImportXMLFailed = Import-Clixml -Path 'C:\Temp\XMLdemo.xml'

Import fails since our sample XML document is valid XML file but it is not formatted in the way Export-Clixml CmdLet does in PowerShell.

Import of sample XML file fails using Import-Clixml CmdLet

NOTE: Look at the tags of the two XML files and notice that sample XML file (XMLdemo.xml) is missing some tags created by Export-Clixml CmdLet(Objs, Obj, TN, etc.).

How to read such XML files and get the XML document in PowerShell to further manipulate it. Well, one of the solutions is to use Get-Content CmdLet instead of Import-Clixml CmdLet that is failing as we have seen.

Here is the sample code for that solution.

$Geography = Get-Content -Path 'C:\Temp\XMLdemo.xml'

$GeographyXML = [Xml] (Get-Content -Path 'C:\Temp\XMLdemo.xml')

The difference between the two calls is that first will as a result return String data type into PowerShell variable and later uses the [XML] type accelerator and returns XML document data type as a result which is more convenient for working with XML documents since we get XML methods to do so.

To verify the data types of two variables above ($Geography and $GeographyXML) we can always use Get-Member PowerShell CmdLet and run the following lines of the code:

$Geography | Get-Member
$GeographyXML | Get-Member

The outcome and data types of both variables we can see in the links below, so no need to repeat ourselves here.

INFO: Please refer to the article How To Export XML File In PowerShell where I have explained these two examples in more depth in the sections: Read XML File Using Get-Content CmdLet and Read XML File And Convert It To XML Object In PowerShell.

How Did We Implement XML Files In Our Projects

Let me explain to you how we have implemented Import-Clixml CmdLet in one of our CmdLets Compare-Version which is part of the Efficiency Booster PowerShell Project. This project is a library of CmdLets that help us IT personal to accomplish our everyday IT task more efficiently and easily.

Before we dive into the code of Compare-Version CmdLet lets first explain the concept with an example. The idea for this CmdLet came as a part of the change management needs.

Imagine that you have some files and folders that you want to track their change over time (new, updated, deleted files and folders). One of the approaches to solve this would be:

  • Collect all the relevant properties of files and folders (file version, file size, file and folder dates, etc.)
  • Save collected data as an XML file that will represent a snapshot of the current state.
  • The saved XML file is used as a reference point.
  • Collect the files’ and folders’ properties and compare them against the reference snapshot XML data.
  • Analyze the difference between current and reference states.
  • After the analysis phase has been finished, archive the current reference XML file and take a new snapshot XML file as a new reference point.

Compare-Version CmdLet Explained

Of all the tasks named in the previous bulleted list, Compare-Version CmdLet does only the comparison between the baseline XML file and current state of the same properties collected in XML file while Save-Baseline CmdLet does collect of the relevant properties, save of collected data as an XML file using Export-Clixml CmdLet, Archives existing baseline XML file and creates new baseline XML file.

Save-Baseline CmdLet has been explained in my previous article How To Export XML File In PowerShell so please read there more about this CmdLet.

The tricky part with Compare-Version CmdLet is the actual call to the CmdLet that can be very often long and the interpretation of the result set can be confusing at the beginning until you get familiar with the logic but do not worry I will explain everything in small digestible chunks so everyone can hopefully understand it.

Here is first the example call to Compare-Version CmdLet:

Compare-Version -errorlog -Compare { Compare-Object -ReferenceObject ( Import-Clixml "$home\Documents\PSbaselines\Get-AllWindowsServices-OK-FIN.xml" ) -DifferenceObject (Get-AllWindowsServices -client "OK" -solution "FIN" -errorlog) -Property "Service name", Status, "Start mode", Started, "Start name", "Accept pause", "Accept stop" -PassThru | Sort-Object -Property "Service name", Collected | Select-Object SideIndicator, Environment, "Logical Name", "Server name", "Service name", "Process Id", "Path name", Status, Collected, "Start mode", Started, "Start name", "Accept pause", "Accept stop", Description, Caption, "Display name" } | Out-GridView

Compare-Version CmdLet uses in the Compare input parameter call to standard PowerShell CmdLet Compare-Object used for the comparison.

Compare-Object CmdLet has been passed values to three input parameters: ReferenceObject, DifferenceObject, and Property.

ReferenceObject input parameter has its own call to Import-Clixml CmdLet where we read previously saved XML file (baseline) and the XML has been saved using Save-Baseline CmdLet.

DifferenceObject input parameter has its own call to Get-AllWindowsServices (one of my own CmdLets) to read the Windows Service properties of the local machine which will be compared with the properties previously saved in the XML file.

Property input parameter defines a list of columns that we use to compare data between XML file properties and current state properties.

Resultset of Compare-Object CmdLet has been sent further down the PowerShell Pipeline using the PassThrue parameter to the Sort-Object CmdLet to sort the resultset.

Further resultset has been sent to Select-Object CmdLet where we decide which columns we want to show in the resultset.

And finally, for the presentation of the result, we use standard PowerShell Grid implementing Out-GridView CmdLet as the last CmdLet in this long PowerShell Pipeline.

Here are we finished with explaining the call to Compare-Version CmdLet. “Alles Klar!”

So let’s focus now on the resultset of the Compare-Version CmdLet presented in the PowerShell Grid.

Resultset of Compare-Version CmdLet

In order to understand the meaning of the results, we will focus on columns SiteIndicator and Service name.

AOC G-Menu Windows Service (marked green) has Side Indicator of value “<=” (marked orange) and that means it belongs to reference set. The reference set in this example is the values from the XML file which is our baseline.

Since we have only one instance of this Windows Service in the resultset and side indicator is from the XML file that means this Windows Service has been uninstalled from our system since the last save of the baseline.

Uninstalled Windows Service

Adobe Windows Service (marked green) has Side Indicator of value “=>” (marked orange) and that means it belongs to the difference set. The difference set in our example is the list of Windows Services that are currently on the local machine.

Since we have only one instance of this Windows Service in the resultset and side indicator is from the local machine current Windows Services list that means this Windows Service has been installed on our system since the last save of the baseline.

Newly Installed Windows Service

Finally, in our last result example, we have two lines in the result for the same Service Name (BITS). Side indicator “<=” row represents Windows Service properties from XML baseline file while Side indicator “=>” row represents Windows Service properties from the local machine.

This means that BITS Windows Service has been changed since last taking of the snapshot and in this example, in the column Process Id (marked red) have been different values.

Updated Windows Services

Here is the table just as a quick reminder of Side Indicator explanation and meaning.

Side IndicatorDescriptionNumber of rows
<=Uninstalled, Deleted, Removed1
=>Installed, New1
<= AND =>Edited, Updated2
Compare-Version Result Explained

Now when we understand the resultset we can do the analysis for change management purposes.

For example, we can have separate lists for the installed, uninstalled and updated Windows Service. Further, we can assess whether all installed Windows Services are necessary and according to our change procedures, the same thing for uninstalled and updated Windows Service.

After the assessment of changes has been finished we can archive the previous baseline and create a new baseline (XML file) and repeat the process whenever we need it in the future.

Compare-Version CmdLet – Input Parameters

As input parameters we have:

  • Compare – input parameter with Script Block data type and it holds the syntax for comparing reference data from an XML file with actual data at that moment.
  • errorlog – switch parameter that turns on/off logging of errors in an external text file
Function Compare-Version {
[CmdletBinding()]
param (
    [Parameter(Mandatory=$true,
                HelpMessage="Path to XML baseline file name. Used as Reference object.")] 
    [ScriptBlock]$Compare,
    
    [Parameter(HelpMessage="Write to error log file or not.")]
    [switch]$errorlog
)
}

INFO: To know more about PowerShell Parameters and Parameter Sets with some awesome examples please read the following articles How To Create Parameters In PowerShell and How To Use Parameter Sets In PowerShell Functions.

BEGIN Block

The BEGIN block is empty.

PROCESS Block

The PROCESS block is empty as well.

END Block

END block is the main processing block for this CmdLet and in the END block we:

  • Do the comparison using Invoke-Command CmdLet. Basically, runs the script block passed as input parameter Compare to the CmdLet.
  • Error Handling using try-catch blocks and writing errors in an external text file using Write-ErrorLog CmdLet.
END { 


    try {
        
        Write-Verbose "Begin compare between baseline and objects."
        $obj = Invoke-Command -ScriptBlock $Compare -ErrorAction Stop
        Write-Output $obj        
        Write-Verbose "Objects compared against baseline: $obj"
        
    } catch {
        Write-Warning "Compare-Version function failed"
        Write-Warning "Error message: $_"

        if ( $errorlog ) {

            $errormsg = $_.ToString()
            $exception = $_.Exception
            $stacktrace = $_.ScriptStackTrace
            $failingline = $_.InvocationInfo.Line
            $positionmsg = $_.InvocationInfo.PositionMessage
            $pscommandpath = $_.InvocationInfo.PSCommandPath
            $failinglinenumber = $_.InvocationInfo.ScriptLineNumber
            $scriptname = $_.InvocationInfo.ScriptName

            Write-Verbose "Start writing to Error log."
            Write-ErrorLog -hostname "Compare-Version has failed" -errormsg $errormsg -exception $exception -scriptname $scriptname -failinglinenumber $failinglinenumber -failingline $failingline -pscommandpath $pscommandpath -positionmsg $pscommandpath -stacktrace $stacktrace
            Write-Verbose "Finish writing to Error log."
        } 
    } 
}

INFO: To understand BEGINPROCESS and END blocks in PowerShell please read PowerShell Function Begin Process End Blocks Explained With Examples.

INFO: To learn about PowerShell Error Handling and code debugging please read the following articles: How To Log PowerShell Errors And Much More and How To Debug PowerShell Scripts.

Comment-Based Help Section

For every one of my own CmdLets, I write Comment-Based help as well.

INFO: If you want to learn how to write comment-based Help for your own PowerShell Functions and Scripts please read these articles How To Write PowerShell Help (Step by Step). In this article How To Write PowerShell Function’s Or CmdLet’s Help (Fast), I explain the PowerShell Add-on that helps us be fast with writing help content.

Compare-Version CmdLet Source Code

DISCLAIMER: Compare-Version function is part of the Efficiency Booster PowerShell Project and as such utilize other CmdLets that are part of the same project. So the best option for you in order for this function to work without any additional customization is to download the source code of the whole project from here.

INFO: My best advice to every PowerShell scripter is to learn writing own PowerShell Advanced Functions and CmdLets and I have written several articles explaining this, so please read them. How To Create A Custom PowerShell CmdLet (Step By Step). Here I explain how to use PowerShell Add-on Function to be faster in writing PowerShell Functions How To Write Advanced Functions Or CmdLets With PowerShell (Fast).

Here is the source code of the whole Compare-Version CmdLet:

<#
.SYNOPSIS
Compare between baseline in XML file and current state of objects.
.DESCRIPTION
Compare between baseline in XML file and current state of objects.

The Compare-Version cmdlet compares two sets of objects. One set of objects is the "reference set," and the other set is the "difference set."

reference set is xml file that we have created in ..\Documents\PSbaselines\ folder running Save-Baseline cmdlet and represents snapshot or baseline of objects properties at some point in time.

difference set is current state of objects property values. 

Basically we compare snapshot taken in the past used as our baseline against current status and want to see the differance between them.


The result of the comparison indicates whether a property value appeared only in the object from the reference set (indicated by the <= symbol), only in the object from the difference set (indicated by the
    => symbol) or, if the IncludeEqual parameter is specified, in both objects (indicated by the == symbol).


Explanation - Result of comparation:
===============================================


Deleted objects
<=


New objects
=>


Updated objects

Equal objects


.PARAMETER Compare
Script block that will be passed as parameter and used for comparation.
.PARAMETER errorlog
write to log or not.
.EXAMPLE
Compare-Version -errorlog -Compare { Compare-Object -ReferenceObject ( Import-Clixml "$home\Documents\PSbaselines\Get-AllWindowsServices-OK-FIN.xml" ) -DifferenceObject (Get-AllWindowsServices -client "OK" -solution "FIN" -errorlog) -Property IP, "Service name", Status, "Start mode", Started, "Start name", "Accept pause", "Accept stop" -PassThru | Sort-Object -Property IP, "Service name", Collected | Select-Object SideIndicator, Environment, "Logical Name", "Server name", IP, "Service name", "Process Id", "Path name", Status, Collected, "Start mode", Started, "Start name", "Accept pause", "Accept stop", Description, Caption, "Display name" } | Out-GridView

Description
---------------------------------------
Compare diff of windows services on local server between baseline in XML file and current state of windows services.

.INPUTS
System.Management.Automation.PSCustomObject

InputObject parameter pipeline by value. 
.OUTPUTS
System.Boolen

.NOTES
FunctionName : Compare-Version
Created by   : Dejan Mladenovic
Date Coded   : 10/31/2018 19:06:41
More info    : http://improvescripting.com/

.LINK 
How To Import XML File In PowerShell
Import-Clixml Export-Clixml Compare-Object #> Function Compare-Version { [CmdletBinding()] param ( [Parameter(Mandatory=$true, HelpMessage="Path to XML baseline file name. Used as Reference object.")] [ScriptBlock]$Compare, [Parameter(HelpMessage="Write to error log file or not.")] [switch]$errorlog ) BEGIN { } PROCESS { } END { try { Write-Verbose "Begin compare between baseline and objects." $obj = Invoke-Command -ScriptBlock $Compare -ErrorAction Stop Write-Output $obj Write-Verbose "Objects compared against baseline: $obj" } catch { Write-Warning "Compare-Version function failed" Write-Warning "Error message: $_" if ( $errorlog ) { $errormsg = $_.ToString() $exception = $_.Exception $stacktrace = $_.ScriptStackTrace $failingline = $_.InvocationInfo.Line $positionmsg = $_.InvocationInfo.PositionMessage $pscommandpath = $_.InvocationInfo.PSCommandPath $failinglinenumber = $_.InvocationInfo.ScriptLineNumber $scriptname = $_.InvocationInfo.ScriptName Write-Verbose "Start writing to Error log." Write-ErrorLog -hostname "Compare-Version has failed" -errormsg $errormsg -exception $exception -scriptname $scriptname -failinglinenumber $failinglinenumber -failingline $failingline -pscommandpath $pscommandpath -positionmsg $pscommandpath -stacktrace $stacktrace Write-Verbose "Finish writing to Error log." } } } } #region Execution examples #Differance from baseline <# Compare-Version -errorlog -Compare { Compare-Object -ReferenceObject ( Import-Clixml "$home\Documents\PSbaselines\Get-AllWindowsServices-OK-FIN.xml" ) -DifferenceObject (Get-AllWindowsServices -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN") -Property IP, "Service name", Status, "Start mode", Started, "Start name", "Accept pause", "Accept stop" -PassThru | Sort-Object -Property IP, "Service name" | Select-Object * } | Save-ToExcel -sendemail -errorlog -ExcelFileName "DFB-GetAllWindowsServices" -title "Diff from baseline Get all windows services info of servers in Financial solution for " -author "DJ PowerScript" -WorkSheetName "DFB - All windows services" -client "OK" -solution "FIN" Compare-Version -errorlog -Compare { Compare-Object -ReferenceObject ( Import-Clixml "$home\Documents\PSbaselines\Get-AllWindowsServices-OK-FIN.xml" ) -DifferenceObject (Get-AllWindowsServices -client "OK" -solution "FIN" -errorlog) -Property IP, "Service name", Status, "Start mode", Started, "Start name", "Accept pause", "Accept stop" -PassThru | Sort-Object -Property IP, "Service name" | Select-Object * } | Save-ToExcel -sendemail -errorlog -ExcelFileName "DFB-GetAllWindowsServices" -title "Diff from baseline Get all windows services info of servers in Financial solution for " -author "DJ PowerScript" -WorkSheetName "DFB - All windows services" -client "OK" -solution "FIN" Compare-Version -errorlog -Compare { Compare-Object -ReferenceObject ( Import-Clixml "$home\Documents\PSbaselines\Get-AllWindowsServices-OK-FIN.xml" ) -DifferenceObject (Get-AllWindowsServices -client "OK" -solution "FIN" -errorlog) -Property IP, "Service name", Status, "Start mode", Started, "Start name", "Accept pause", "Accept stop" -PassThru | Sort-Object -Property IP, "Service name" | Select-Object * } | Out-GridView Compare-Version -errorlog -Compare { Compare-Object -ReferenceObject ( Import-Clixml "$home\Documents\PSbaselines\Get-AllWindowsServices-OK-FIN.xml" ) -DifferenceObject (Get-AllWindowsServices -client "OK" -solution "FIN" -errorlog) -Property IP, "Service name", Status, "Start mode", Started, "Start name", "Accept pause", "Accept stop" -PassThru | Sort-Object -Property IP, "Service name", Collected | Select-Object SideIndicator, Environment, "Logical Name", "Server name", IP, "Service name", "Process Id", "Path name", Status, Collected, "Start mode", Started, "Start name", "Accept pause", "Accept stop", Description, Caption, "Display name" } | Out-GridView Compare-Version -errorlog -Compare { Compare-Object -ReferenceObject ( Import-Clixml "$home\Documents\PSbaselines\Get-AllWindowsServices-OK-FIN.xml" ) -DifferenceObject (Get-AllWindowsServices -client "OK" -solution "FIN" -errorlog) -Property "Service name", Status, "Start mode", Started, "Start name", "Accept pause", "Accept stop" -PassThru | Sort-Object -Property "Service name", Collected | Select-Object SideIndicator, Environment, "Logical Name", "Server name", "Service name", "Process Id", "Path name", Status, Collected, "Start mode", Started, "Start name", "Accept pause", "Accept stop", Description, Caption, "Display name" } | Out-GridView #> #endregion

Useful PowerShell Articles About Import XML Data

Here are some useful articles and resources:

About Dejan Mladenović

Post Author Dejan MladenovicHey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals!
I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials
About Me...

My Posts | Website

Dejan Mladenović

Hey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals! I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials About Me...

Recent Posts