PoshCode Logo PowerShell Code Repository

Xml Module 6.5 by Joel Bennett 28 months ago (modification of post by Joel Bennett view diff)
View followups from Jaykul | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/3556"></script>download | new post

A complete set of XML functionality (especially if you don’t have PSCX), including reading and writing xml files (import-xml, export-xml), selecting (via xpath), updating, transforming and creating new xml documents.

In particular:

A DSL for creating XML documents.

Convert-Xml which supports parameters so you can use XSLT which require parameters

Select-XML which leverages Remove-XmlNamespace to simplify simple xml queries by allowing you to leave out the namespaces. It is important to note that this means that the returned results will not have namespaces in them, even if the input XML did.

ALSO NOTE: only raw XmlNodes are returned from Select-Xml, so the output isn’t compatible with the built in Select-Xml — instead, it’s equivalent to using it the way I usually do: Select-Xml ... | Select-Object -Expand Node

Update-Xml which allows you to append, insert, remove, and replace values in XML Documents

Remove-XmlElement which can remove nodes or attributes by namespace to clean-up designer-generated XML

In this Version: I added Remove-XmlElement, added a Parameters parameter to New-XmlDocument, and fixed a bug in New-XElement which prevented using attribute values with dashes in them.

  1. #requires -version 2.0
  2.  
  3. # Improves over the built-in Select-XML by leveraging Remove-XmlNamespace http`://poshcode.org/1492
  4. # to provide a -RemoveNamespace parameter -- if it's supplied, all of the namespace declarations
  5. # and prefixes are removed from all XML nodes (by an XSL transform) before searching.
  6. # IMPORTANT: returned results *will not* have namespaces in them, even if the input XML did.
  7.  
  8. # Also, only raw XmlNodes are returned from this function, so the output isn't completely compatible
  9. # with the built in Select-Xml. It's equivalent to using Select-Xml ... | Select-Object -Expand Node
  10.  
  11. # Version History:
  12. # Select-Xml 2.0 This was the first script version I wrote.
  13. #                it didn't function identically to the built-in Select-Xml with regards to parameter parsing
  14. # Select-Xml 2.1 Matched the built-in Select-Xml parameter sets, it's now a drop-in replacement
  15. #                BUT only if you were using the original with: Select-Xml ... | Select-Object -Expand Node
  16. # Select-Xml 2.2 Fixes a bug in the -Content parameterset where -RemoveNamespace was *presumed*
  17. # Version    3.0 Added New-XDocument and associated generation functions for my XML DSL
  18. # Version    3.1 Fixed a really ugly bug in New-XDocument in 3.0 which I should not have released
  19. # Version    4.0 Never content to leave well enough alone, I've completely reworked New-XDocument
  20. # Version    4.1 Tweaked namespaces again so they don't cascade down when they shouldn't. Got rid of the unnecessary stack.
  21. # Version    4.2 Tightened xml: only cmdlet, function, and external scripts, with "-" in their names are exempted from being converted into xml tags.
  22. #                Fixed some alias error messages caused when PSCX is already loaded (we overwrite their aliases for cvxml and fxml)
  23. # Version    4.3 Added a Path parameter set to Format-Xml so you can specify xml files for prety printing
  24. # Version    4.5 Fixed possible [Array]::Reverse call on a non-array in New-XElement (used by New-XDocument)
  25. #                Work around possible variable slipping on null values by:
  26. #                1) allowing -param:$value syntax (which doesn't fail when $value is null)
  27. #                2) testing for -name syntax on the value and using it as an attribute instead
  28. # Version    4.6 Added -Arguments to Convert-Xml so that you can pass arguments to XSLT transforms!
  29. #                Note: when using strings for xslt, make sure you single quote them or escape the $ signs.
  30. # Version    4.7 Fixed a typo in the namespace parameter of Select-Xml
  31. # Version    4.8 Fixed up some uses of Select-Xml -RemoveNamespace
  32. # Version    5.0 Added Update-Xml to allow setting xml attributes or node content
  33. # Version    6.0 Major cleanup, breaking changes.
  34. #       - Added Get-XmlContent and Set-XmlContent for loading/saving XML from files or strings
  35. #       - Removed Path and Content parameters from the other functions (it greatly simplifies thost functions, and makes the whole thing more maintainable)
  36. #       - Updated Update-Xml to support adding nodes "before" and "after" other nodes, and to support "remove"ing nodes
  37. # Version    6.1 Update for PowerShell 3.0
  38. # Version    6.2 Minor tweak in exception handling for CliXml
  39. # Version    6.3 Added Remove-XmlElement to allow removing nodes or attributes
  40. #                This is something I specifically needed to remove "ignorable" namespaces
  41. #                Specifically, the ones created by the Visual Studio Workflow designer (and perhaps other visual designers like Blend)
  42. #                Which I don't want to check into source control, because it makes diffing nearly impossible
  43. # Version    6.4 Fixed a bug on New-XElement for Rudy Shockaert (nice bug report, thanks!)
  44. # Version    6.5 Added -Parameters @{} parameter to New-XDocument to allow local variables to be passed into the module scope. *grumble*
  45.  
  46. function Add-Accelerator {
  47. <#
  48.    .Synopsis
  49.       Add a type accelerator to the current session
  50.    .Description
  51.       The Add-Accelerator function allows you to add a simple type accelerator (like [regex]) for a longer type (like [System.Text.RegularExpressions.Regex]).
  52.    .Example
  53.       Add-Accelerator list System.Collections.Generic.List``1
  54.       $list = New-Object list[string]
  55.      
  56.       Creates an accelerator for the generic List[T] collection type, and then creates a list of strings.
  57.    .Example
  58.       Add-Accelerator "List T", "GList" System.Collections.Generic.List``1
  59.       $list = New-Object "list t[string]"
  60.      
  61.       Creates two accelerators for the Generic List[T] collection type.
  62.    .Parameter Accelerator
  63.       The short form accelerator should be just the name you want to use (without square brackets).
  64.    .Parameter Type
  65.       The type you want the accelerator to accelerate (without square brackets)
  66.    .Notes
  67.       When specifying multiple values for a parameter, use commas to separate the values.
  68.       For example, "-Accelerator string, regex".
  69.      
  70.       PowerShell requires arguments that are "types" to NOT have the square bracket type notation, because of the way the parsing engine works.  You can either just type in the type as System.Int64, or you can put parentheses around it to help the parser out: ([System.Int64])
  71.  
  72.       Also see the help for Get-Accelerator and Remove-Accelerator
  73.    .Link
  74.       http://huddledmasses.org/powershell-2-ctp3-custom-accelerators-finally/
  75. #>
  76. [CmdletBinding()]
  77. param(
  78.    [Parameter(Position=0,ValueFromPipelineByPropertyName=$true)]
  79.    [Alias("Key","Name")]
  80.    [string[]]$Accelerator
  81. ,
  82.    [Parameter(Position=1,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  83.    [Alias("Value","FullName")]
  84.    [type]$Type
  85. )
  86. process {
  87.    # add a user-defined accelerator  
  88.    foreach($a in $Accelerator) {
  89.       if($xlr8r::AddReplace) {
  90.          $xlr8r::AddReplace( $a, $Type)
  91.       } else {
  92.          $null = $xlr8r::Remove( $a )
  93.          $xlr8r::Add( $a, $Type)
  94.       }
  95.       trap [System.Management.Automation.MethodInvocationException] {
  96.          if($xlr8r::get.keys -contains $a) {
  97.             if($xlr8r::get[$a] -ne $Type) {
  98.                Write-Error "Cannot add accelerator [$a] for [$($Type.FullName)]`n                  [$a] is already defined as [$($xlr8r::get[$a].FullName)]"
  99.             }
  100.             Continue;
  101.          }
  102.          throw
  103.       }
  104.    }
  105. }
  106. }
  107.  
  108. &{
  109. $local:xlr8r = [psobject].assembly.gettype("System.Management.Automation.TypeAccelerators")
  110. $local:xlinq = [Reflection.Assembly]::Load("System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
  111. $xlinq.GetTypes() | ? { $_.IsPublic -and !$_.IsSerializable -and $_.Name -ne "Extensions" -and !$xlr8r::Get[$_.Name] } | Add-Accelerator
  112.  
  113. Add-Accelerator "Dictionary" "System.Collections.Generic.Dictionary``2, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
  114. Add-Accelerator "PSParser" "System.Management.Automation.PSParser, System.Management.Automation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  115. }
  116.  
  117.  
  118. function Get-XmlContent {
  119. #.Synopsis
  120. #   Load an XML file as an XmlDocument
  121. param(
  122.     # Specifies a string that contains the XML to load, or a path to a file which has the XML to load (wildcards are permitted).
  123.     [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  124.     [ValidateNotNullOrEmpty()]
  125.     [Alias("PSPath","Path")]
  126.     [String[]]$Content
  127. ,
  128.     # If set, loads XML with all namespace qualifiers removed, and all entities expanded.
  129.     [Alias("Rn","Rm")]
  130.     [Switch]$RemoveNamespace
  131. )
  132. begin {
  133.     [Text.StringBuilder]$XmlContent = [String]::Empty
  134.     [bool]$Path = $true
  135. }
  136. process {
  137.     if($Path -and ($Path = Test-Path @($Content)[0] -EA 0)) {
  138.         foreach($file in Resolve-Path $Content) {
  139.             $xml = New-Object System.Xml.XmlDocument;
  140.             if($file.Provider.Name -eq "FileSystem") {
  141.                 Write-Verbose $file.ProviderPath
  142.                 $xml.Load( $file.ProviderPath )
  143.             } else {
  144.                 $ofs = "`n"
  145.                 $xml.LoadXml( ([String](Get-Content $file)) )
  146.             }
  147.             if($RemoveNamespace) {
  148.                 [System.Xml.XmlNode[]]$Xml = @(Remove-XmlNamespace -Xml $node)
  149.             }
  150.             Write-Output $xml
  151.         }
  152.     } else {
  153.         # If the "path" parameter isn't actually a path, assume that it's actually content
  154.         foreach($line in $content) {
  155.             $null = $XmlContent.AppendLine( $line )
  156.         }
  157.     }
  158. }
  159. end {
  160.     if(!$Path) {
  161.         $xml = New-Object System.Xml.XmlDocument;
  162.         $xml.LoadXml( $XmlContent.ToString() )
  163.         if($RemoveNamespace) {
  164.             $Xml = @(Remove-XmlNamespace -Xml $xml)
  165.         }
  166.         Write-Output $xml
  167.     }
  168. }}
  169.  
  170.  
  171. Set-Alias Import-Xml Get-XmlContent
  172. Set-Alias ipxml Get-XmlContent
  173. Set-Alias ipx Get-XmlContent
  174. Set-Alias Get-Xml Get-XmlContent
  175. Set-Alias gxml Get-XmlContent
  176. Set-Alias gx Get-XmlContent
  177.  
  178. function Set-XmlContent {
  179. param(
  180.     [Parameter(Mandatory=$true, Position=1)]
  181.     [Alias("PSPath")]
  182.     [String]$Path
  183. ,
  184.     # Specifies one or more XML nodes to search.
  185.     [Parameter(Position=5,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  186.     [ValidateNotNullOrEmpty()]
  187.     [Alias("Node")]
  188.     [Xml]$Xml
  189. )
  190. process {
  191.     $xml.Save( $Path )
  192. }
  193. }
  194.  
  195. Set-Alias Export-Xml Set-XmlContent
  196. Set-Alias epxml Set-XmlContent
  197. Set-Alias epx Set-XmlContent
  198. Set-Alias Set-Xml Set-XmlContent
  199. Set-Alias sxml Set-XmlContent
  200. Set-Alias sx Set-XmlContent
  201.  
  202. function Format-Xml {
  203. #.Synopsis
  204. #   Pretty-print formatted XML source
  205. #.Description
  206. #   Runs an XmlDocument through an auto-indenting XmlWriter
  207. #.Parameter Xml
  208. #   The Xml Document
  209. #.Parameter Path
  210. #   The path to an xml document (on disc or any other content provider).
  211. #.Parameter Indent
  212. #   The indent level (defaults to 2 spaces)
  213. #.Example
  214. #   [xml]$xml = get-content Data.xml
  215. #   C:\PS>Format-Xml $xml
  216. #.Example
  217. #   get-content Data.xml | Format-Xml
  218. #.Example
  219. #   Format-Xml C:\PS\Data.xml
  220. #.Example
  221. #   ls *.xml | Format-Xml
  222. #
  223. [CmdletBinding()]
  224. param(
  225.    [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="Document")]
  226.    [xml]$Xml
  227. ,
  228.    [Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName="File")]
  229.    [Alias("PsPath")]
  230.    [string]$Path
  231. ,
  232.    [Parameter(Mandatory=$false)]
  233.    $Indent=2
  234. )
  235. process {
  236.    ## Load from file, if necessary
  237.    if($Path) { [xml]$xml = Get-Content $Path }
  238.    
  239.    $StringWriter = New-Object System.IO.StringWriter
  240.    $XmlWriter = New-Object System.Xml.XmlTextWriter $StringWriter
  241.    $xmlWriter.Formatting = "indented"
  242.    $xmlWriter.Indentation = $Indent
  243.    $xml.WriteContentTo($XmlWriter)
  244.    $XmlWriter.Flush()
  245.    $StringWriter.Flush()
  246.    Write-Output $StringWriter.ToString()
  247. }}
  248. Set-Alias fxml Format-Xml -EA 0
  249. Set-Alias fx   Format-Xml -EA 0
  250.  
  251. function Select-XmlNodeInternal {
  252. [CmdletBinding()]
  253. param([Xml.XmlNode[]]$Xml, [String[]]$XPath, [Hashtable]$NamespaceManager)
  254. begin {
  255.     Write-Verbose "XPath = $($XPath -join ',')"
  256.     foreach($node in $xml) {
  257.         if($NamespaceManager) {
  258.             $nsManager = new-object System.Xml.XmlNamespaceManager $node.NameTable
  259.             foreach($ns in $NamespaceManager.GetEnumerator()) {
  260.                 $nsManager.AddNamespace( $ns.Key, $ns.Value )
  261.             }
  262.             Write-Verbose "Names = $($nsManager | % { @{ $_ = $nsManager.LookupNamespace($_) } } | Out-String)"
  263.         }
  264.         foreach($path in $xpath) {
  265.             $node.SelectNodes($path, $nsManager)
  266.         }
  267.     }
  268. }}
  269.  
  270. function Select-Xml {
  271. #.Synopsis
  272. #  The Select-XML cmdlet lets you use XPath queries to search for text in XML strings and documents. Enter an XPath query, and use the Content, Path, or Xml parameter to specify the XML to be searched.
  273. #.Description
  274. #  Improves over the built-in Select-XML by leveraging Remove-XmlNamespace to provide a -RemoveNamespace parameter -- if it's supplied, all of the namespace declarations and prefixes are removed from all XML nodes (by an XSL transform) before searching.  
  275. #  
  276. #  However, only raw XmlNodes are returned from this function, so the output isn't currently compatible with the built in Select-Xml, but is equivalent to using Select-Xml ... | Select-Object -Expand Node
  277. #
  278. #  Also note that if the -RemoveNamespace switch is supplied the returned results *will not* have namespaces in them, even if the input XML did, and entities get expanded automatically.
  279. [CmdletBinding(DefaultParameterSetName="Xml")]
  280. param(
  281.     # Specifies an XPath search query. The query language is case-sensitive. This parameter is required.
  282.     [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
  283.     [ValidateNotNullOrEmpty()]
  284.     [Alias("Query")]
  285.     [String[]]$XPath
  286. ,
  287.     # Specifies a string that contains the XML to search. You can also pipe strings to Select-XML.
  288.     [Parameter(ParameterSetName="Content",Mandatory=$true)]
  289.     [ValidateNotNullOrEmpty()]
  290.     [String[]]$Content
  291. ,
  292.     # Specifies the path and file names of the XML files to search.  Wildcards are permitted.
  293.     [Parameter(Position=5,ParameterSetName="Path",Mandatory=$true,ValueFromPipelineByPropertyName=$true)]
  294.     [ValidateNotNullOrEmpty()]
  295.     [Alias("PSPath")]
  296.     [String[]]$Path
  297. ,
  298.     # Specifies one or more XML nodes to search.
  299.     [Parameter(Position=5,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  300.     [ValidateNotNullOrEmpty()]
  301.     [Alias("Node")]
  302.     [System.Xml.XmlNode[]]$Xml
  303. ,
  304.     # Specifies a hash table of the namespaces used in the XML. Use the format @{<namespaceName> = <namespaceUri>}.
  305.     [Parameter(Position=10,Mandatory=$false)]
  306.     [ValidateNotNullOrEmpty()]
  307.     [Alias("Ns")]
  308.     [Hashtable]$Namespace
  309. ,
  310.     # Allows the execution of XPath queries without namespace qualifiers.
  311.     #
  312.     # If you specify the -RemoveNamespace switch, all namespace declarations and prefixes are actually removed from the Xml before the XPath search query is evaluated, and your XPath query should therefore NOT contain any namespace prefixes.
  313.     #
  314.     # Note that this means that the returned results *will not* have namespaces in them, even if the input XML did, and entities get expanded automatically.
  315.     [Alias("Rn","Rm")]
  316.     [Switch]$RemoveNamespace
  317. )
  318. begin {
  319.     $NSM = $Null; if($PSBoundParameters.ContainsKey("Namespace")) { $NSM = $Namespace }
  320.     $XmlNodes = New-Object System.Xml.XmlNode[] 1
  321.     if($PSCmdlet.ParameterSetName -eq "Content") {
  322.         $XmlNodes = ConvertTo-Xml $Content -RemoveNamespace:$RemoveNamespace
  323.         Select-XmlNodeInternal $XmlNodes $XPath $NSM
  324.     }
  325. }
  326. process {
  327.     switch($PSCmdlet.ParameterSetName) {
  328.         "Path" {
  329.             $node = ConvertTo-Xml $Path -RemoveNamespace:$RemoveNamespace
  330.             Select-XmlNodeInternal $node $XPath $NSM
  331.         }
  332.         "Xml" {
  333.             foreach($node in $Xml) {
  334.                 if($RemoveNamespace) {
  335.                    [Xml]$node = Remove-XmlNamespace -Xml $node
  336.                 }
  337.                 Select-XmlNodeInternal $node $XPath $NSM
  338.             }
  339.         }
  340.     }
  341. }}
  342. Set-Alias slxml Select-Xml -EA 0
  343. Set-Alias slx Select-Xml -EA 0
  344.  
  345.  
  346. function Update-Xml {
  347. #.Synopsis
  348. #  The Update-XML cmdlet lets you use XPath queries to replace text in nodes in XML documents. Enter an XPath query, and use the Content, Path, or Xml parameter to specify the XML to be searched.
  349. #.Description
  350. #  Allows you to update an attribute value, xml node contents, etc.
  351. #
  352. #.Notes
  353. #  We still need to implement RemoveNode and RemoveAttribute and even ReplaceNode
  354. [CmdletBinding(DefaultParameterSetName="Set")]
  355. param(
  356.     # Specifies an XPath for an element where you want to insert the new node.
  357.     [Parameter(ParameterSetName="Before",Mandatory=$true)]
  358.     [ValidateNotNullOrEmpty()]
  359.     [Switch]$Before
  360. ,
  361.     # Specifies an XPath for an element where you want to insert the new node.
  362.     [Parameter(ParameterSetName="After",Mandatory=$true)]
  363.     [ValidateNotNullOrEmpty()]
  364.     [Switch]$After
  365. ,
  366.     # If set, the new value will be added as a new child of the node identified by the XPath
  367.     [Parameter(ParameterSetName="Append",Mandatory=$true)]
  368.     [Switch]$Append
  369. ,
  370.     # If set, the node identified by the XPath will be removed instead of set
  371.     [Parameter(ParameterSetName="Remove",Mandatory=$true)]
  372.     [Switch]$Remove
  373. ,
  374.     # If set, the node identified by the XPath will be Replace instead of set
  375.     [Parameter(ParameterSetName="Replace",Mandatory=$true)]
  376.     [Switch]$Replace
  377. ,
  378.     # Specifies an XPath for the node to update. This could be an element node *or* an attribute node (remember: //element/@attribute )
  379.     [Parameter(Position=1,Mandatory=$true)]
  380.     [ValidateNotNullOrEmpty()]
  381.     [String[]]$XPath
  382. ,
  383.     # The new value to place in the xml
  384.     [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$false)]
  385.     [ValidateNotNullOrEmpty()]
  386.     [String]$Value
  387. ,
  388.     # Specifies one or more XML nodes to search.
  389.     [Parameter(Position=5,Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  390.     [ValidateNotNullOrEmpty()]
  391.     [Alias("Node")]
  392.     [System.Xml.XmlNode[]]$Xml
  393. ,  
  394.     # Specifies a hash table of the namespaces used in the XML. Use the format @{<namespaceName> = <namespaceUri>}.
  395.     [Parameter(Position=10,Mandatory=$false)]
  396.     [ValidateNotNullOrEmpty()]
  397.     [Alias("Ns")]
  398.     [Hashtable]$Namespace
  399. ,  
  400.     # Output the XML documents after adding updating them
  401.     [Switch]$Passthru
  402. )
  403. process
  404. {
  405.     foreach($XmlNode in $Xml) {
  406.         $select = @{}
  407.         $select.Xml = $XmlNode
  408.         $select.XPath = $XPath
  409.         if($Namespace) {  
  410.             $select.Namespace = $Namespace
  411.         }
  412.         $document =
  413.             if($XmlNode -is [System.Xml.XmlDocument]) {
  414.                 $XmlNode
  415.             } else {
  416.                 $XmlNode.get_OwnerDocument()
  417.             }
  418.         if($xValue = $Value -as [Xml]) {
  419.             $xValue = $document.ImportNode($xValue.SelectSingleNode("/*"), $true)
  420.         }
  421.         $nodes = Select-Xml @Select | Where-Object { $_ }
  422.  
  423.         if(@($nodes).Count -eq 0) { Write-Warning "No nodes matched your XPath, nothing will be updated" }
  424.        
  425.         foreach($node in $nodes) {
  426.             $select.XPath = "$XPath/parent::*"
  427.             $parent = Select-Xml @Select
  428.             if(!$xValue) {
  429.                 if($node -is [System.Xml.XmlAttribute] -and $Value.Contains("=")) {
  430.                     $aName, $aValue = $Value.Split("=",2)
  431.                     if($aName.Contains(":")){
  432.                         $ns,$name = $aName.Split(":",2)
  433.                         $xValue = $document.CreateAttribute( $name, $Namespace[$ns] )
  434.                     } else {
  435.                         $xValue = $document.CreateAttribute( $aName )
  436.                     }
  437.                     $xValue.Value = $aValue
  438.                 }
  439.             }
  440.            
  441.             switch($PSCmdlet.ParameterSetName) {
  442.                 "Before" {
  443.                     $null = $parent.InsertBefore( $xValue, $node )
  444.                 }
  445.                 "After" {
  446.                     $null = $parent.InsertAfter( $xValue, $node )
  447.                 }
  448.                 "Append" {
  449.                     $null = $parent.AppendChild( $xValue )
  450.                 }
  451.                 "Remove" {
  452.                     $null = $parent.RemoveChild( $node )
  453.                 }
  454.                 "Replace" {
  455.                     if(!$xValue) {
  456.                         $xValue = $document.CreateTextNode( $Value )
  457.                     }
  458.                     $null = $parent.ReplaceChild( $xValue, $node )
  459.                 }
  460.                 "Set" {
  461.                     if(!$xValue -and $node."#text") {
  462.                         $node."#text" = $Value
  463.                     } else {
  464.                         if($node -is [System.Xml.XmlElement]) {
  465.                             if(!$xValue) {
  466.                                 $xValue = $document.CreateTextNode( $Value )
  467.                             }
  468.                             $null = $node.set_innerXml("")
  469.                             $null = $node.AppendChild($xValue)
  470.                         }
  471.                         elseif($node -is [System.Xml.XmlAttribute]) {
  472.                             $node.Value = $Value
  473.                         } else {
  474.                             Write-Warning "$XPath selects a node of type $($node.GetType()), which we haven't handled. Please add that handler!"
  475.                         }
  476.                     }
  477.                 }
  478.             }
  479.         }
  480.         if($Passthru) {
  481.             Write-Output $XmlNode
  482.         }
  483.     }
  484. }}
  485. Set-Alias uxml Update-Xml -EA 0
  486. Set-Alias ux Update-Xml -EA 0
  487.  
  488. function Convert-Node {
  489. #.Synopsis
  490. # Convert a single XML Node via XSL stylesheets
  491. [CmdletBinding(DefaultParameterSetName="Reader")]
  492. param(
  493.    [Parameter(ParameterSetName="ByNode",Mandatory=$true,ValueFromPipeline=$true)]
  494.    [System.Xml.XmlNode]$Node
  495. ,
  496.    [Parameter(ParameterSetName="Reader",Mandatory=$true,ValueFromPipeline=$true)]
  497.    [System.Xml.XmlReader]$XmlReader
  498. ,
  499.    [Parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false)]
  500.    [System.Xml.Xsl.XslCompiledTransform]$StyleSheet
  501. ,
  502.    [Parameter(Position=2,Mandatory=$false)]
  503.    [Alias("Parameters")]
  504.    [hashtable]$Arguments
  505. )
  506. PROCESS {
  507.    if($PSCmdlet.ParameterSetName -eq "ByNode") {
  508.       $XmlReader = New-Object Xml.XmlNodeReader $node
  509.    }
  510.  
  511.    $output = New-Object IO.StringWriter
  512.    $argList = $null
  513.    
  514.    if($Arguments) {
  515.       $argList = New-Object System.Xml.Xsl.XsltArgumentList
  516.       foreach($arg in $Arguments.GetEnumerator()) {
  517.          $namespace, $name = $arg.Key -split ":"
  518.          ## Fix namespace
  519.          if(!$name) {
  520.             $name = $Namespace
  521.             $namespace = ""
  522.          }
  523.          
  524.          Write-Verbose "ns:$namespace name:$name value:$($arg.Value)"
  525.          $argList.AddParam($name,"$namespace",$arg.Value)
  526.       }
  527.    }
  528.    
  529.    $StyleSheet.Transform( $XmlReader, $argList, $output )
  530.    Write-Output $output.ToString()
  531. }
  532. }
  533.  
  534. function Convert-Xml {
  535. #.Synopsis
  536. #   The Convert-XML function lets you use Xslt to transform XML strings and documents.
  537. #.Description
  538. #   Documentation TODO
  539. [CmdletBinding(DefaultParameterSetName="Xml")]
  540. param(
  541.     # Specifies one or more XML nodes to process.
  542.     [Parameter(Position=1,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  543.     [ValidateNotNullOrEmpty()]
  544.     [Alias("Node")]
  545.     [System.Xml.XmlNode[]]$Xml
  546. ,  
  547.     # Specifies an Xml StyleSheet to transform with...
  548.     [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false)]
  549.     [ValidateNotNullOrEmpty()]
  550.     [Alias("StyleSheet")]
  551.     [String]$Xslt
  552. ,
  553.     # Specify arguments to the XSL Transformation
  554.     [Alias("Parameters")]
  555.     [hashtable]$Arguments
  556. )
  557. begin {
  558.    $StyleSheet = New-Object System.Xml.Xsl.XslCompiledTransform
  559.    if(Test-Path $Xslt -EA 0) {
  560.       Write-Verbose "Loading Stylesheet from $(Resolve-Path $Xslt)"
  561.       $StyleSheet.Load( (Resolve-Path $Xslt) )
  562.    } else {
  563.       $OFS = "`n"
  564.       Write-Verbose "$Xslt"
  565.       $StyleSheet.Load(([System.Xml.XmlReader]::Create((New-Object System.IO.StringReader $Xslt))))
  566.    }
  567. }
  568. process {
  569.    foreach($node in $Xml) {
  570.       Convert-Node -Xml (New-Object Xml.XmlNodeReader $node) $StyleSheet $Arguments
  571.    }
  572. }
  573. }
  574. Set-Alias cvxml Convert-Xml -EA 0
  575.  
  576. function Remove-XmlNamespace {
  577. #.Synopsis
  578. #  Removes namespace definitions and prefixes from xml documents
  579. #.Description
  580. #  Runs an xml document through an XSL Transformation to remove namespaces from it if they exist.
  581. #  Entities are also naturally expanded
  582. #.Parameter Content
  583. #  Specifies a string that contains the XML to transform.
  584. #.Parameter Path
  585. #  Specifies the path and file names of the XML files to transform. Wildcards are permitted.
  586. #
  587. #  There will be one output document for each matching input file.
  588. #.Parameter Xml
  589. #  Specifies one or more XML documents to transform
  590. [CmdletBinding(DefaultParameterSetName="Xml")]
  591. PARAM(
  592.    [Parameter(Position=1,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  593.    [ValidateNotNullOrEmpty()]
  594.    [Alias("Node")]
  595.    [System.Xml.XmlNode[]]$Xml
  596. )
  597. BEGIN {
  598.    $StyleSheet = New-Object System.Xml.Xsl.XslCompiledTransform
  599.    $StyleSheet.Load(([System.Xml.XmlReader]::Create((New-Object System.IO.StringReader @"
  600. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  601.   <xsl:output method="xml" indent="yes"/>
  602.   <xsl:template match="/|comment()|processing-instruction()">
  603.      <xsl:copy>
  604.         <xsl:apply-templates/>
  605.      </xsl:copy>
  606.   </xsl:template>
  607.  
  608.   <xsl:template match="*">
  609.      <xsl:element name="{local-name()}">
  610.         <xsl:apply-templates select="@*|node()"/>
  611.      </xsl:element>
  612.   </xsl:template>
  613.  
  614.   <xsl:template match="@*">
  615.      <xsl:attribute name="{local-name()}">
  616.         <xsl:value-of select="."/>
  617.      </xsl:attribute>
  618.   </xsl:template>
  619. </xsl:stylesheet>
  620. "@))))
  621.    [Text.StringBuilder]$XmlContent = [String]::Empty
  622. }
  623. PROCESS {
  624.    $Xml | Convert-Node $StyleSheet
  625. }
  626. }
  627. Set-Alias rmns Remove-XmlNamespace -EA 0
  628. Set-Alias rmxns Remove-XmlNamespace -EA 0
  629.  
  630.  
  631.  
  632.  
  633.  
  634. function Remove-XmlElement {
  635. #.Synopsis
  636. #  Removes specified elements (tags or attributes) or all elements from a specified namespace from an Xml document
  637. #.Description
  638. #  Runs an xml document through an XSL Transformation to remove tag namespaces from it if they exist.
  639. #  Entities are also naturally expanded
  640. #.Parameter Content
  641. #  Specifies a string that contains the XML to transform.
  642. #.Parameter Path
  643. #  Specifies the path and file names of the XML files to transform. Wildcards are permitted.
  644. #
  645. #  There will be one output document for each matching input file.
  646. #.Parameter Xml
  647. #  Specifies one or more XML documents to transform
  648. [CmdletBinding(DefaultParameterSetName="Xml")]
  649. PARAM(
  650.    [Parameter(Position=0,ParameterSetName="Xml")] #,Mandatory=$true
  651.    #[ValidateNotNullOrEmpty()]
  652.    [XNamespace[]]$Namespace
  653. ,
  654.    [Parameter(Position=1,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  655.    [ValidateNotNullOrEmpty()]
  656.    [Alias("Node")]
  657.    [System.Xml.XmlNode[]]$Xml
  658. )
  659. BEGIN {
  660.    foreach($Node in @($Xml)) {
  661.       $Allspaces += Get-Namespace -Xml $Node
  662.  
  663.       $nsManager = new-object System.Xml.XmlNamespaceManager $node.NameTable
  664.       foreach($ns in $Allspaces.GetEnumerator()) {
  665.           $nsManager.AddNamespace( $ns.Key, $ns.Value )
  666.       }
  667.  
  668.       # If no namespaces are passed in, use the "ignorable" ones from XAML if there are any
  669.       if(!$Namespace) {
  670.          $root = $Node.DocumentElement
  671.          # $nsManager = new-object System.Xml.XmlNamespaceManager $Node.NameTable                      
  672.          $nsManager.AddNamespace("compat", "http://schemas.openxmlformats.org/markup-compatibility/2006")
  673.          if($ignorable = $root.SelectSingleNode("@compat:Ignorable",$nsManager)) {
  674.             foreach($prefix in $ignorable.get_InnerText().Split(" ")) {
  675.                $Namespace += $root.GetNamespaceOfPrefix($prefix)
  676.             }
  677.          }
  678.       }
  679.    }
  680.  
  681.    
  682.    Write-Verbose "$Namespace"
  683.    $i = 0
  684.    $NSString = $(foreach($n in $Namespace) { "xmlns:n$i='$n'"; $i+=1 }) -Join " "
  685.    $EmptyTransforms = $(for($i =0; $i -lt $Namespace.Count;$i++) {
  686.       "<xsl:template match='n${i}:*'>
  687.      </xsl:template>
  688.      <xsl:template match='@n${i}:*'>
  689.      </xsl:template>"
  690.    })
  691.    
  692.    $XSLT = @"
  693. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" $NSString>
  694.   <xsl:output method="xml" indent="yes"/>
  695.   <xsl:template match="@*|node()">
  696.      <xsl:copy>
  697.         <xsl:apply-templates select="@*|node()"/>
  698.      </xsl:copy>
  699.   </xsl:template>
  700.   $EmptyTransforms
  701. </xsl:stylesheet>
  702. "@
  703.    Write-Verbose $XSLT
  704.  
  705.    $StyleSheet = New-Object System.Xml.Xsl.XslCompiledTransform
  706.    $StyleSheet.Load(([System.Xml.XmlReader]::Create((New-Object System.IO.StringReader $XSLT))))
  707.    [Text.StringBuilder]$XmlContent = [String]::Empty
  708. }
  709. PROCESS {
  710.    $Xml | Convert-Node $StyleSheet
  711. }
  712. }
  713. #Set-Alias rmns Remove-XmlNamespace -EA 0
  714. #Set-Alias rmxns Remove-XmlNamespace -EA 0
  715.  
  716. function Get-Namespace {
  717. param(
  718.    [Parameter(Position=0)]
  719.    [String[]]$Prefix = "*"
  720. ,
  721.    [Parameter(Position=1,ParameterSetName="Xml",Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  722.    [ValidateNotNullOrEmpty()]
  723.    [Alias("Node")]
  724.    [System.Xml.XmlNode[]]$Xml
  725. )
  726.    foreach($Node in @($Xml)) {
  727.       $results = @{}
  728.       if($Node -is [Xml.XmlDocument]) {
  729.          $Node = $Node.DocumentElement
  730.       }
  731.       foreach($ns in $Node.CreateNavigator().GetNamespacesInScope("All").GetEnumerator()) {
  732.          foreach($p in $Prefix) {
  733.             if($ns.Key -like $p) {
  734.                $results.Add($ns.Key, $ns.Value)
  735.                break;
  736.             }
  737.          }
  738.       }
  739.       $results
  740.    }
  741. }
  742.  
  743.  
  744.  
  745. ######## Helper functions for working with CliXml
  746.  
  747. function ConvertFrom-CliXml {
  748.    param(
  749.       [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
  750.       [ValidateNotNullOrEmpty()]
  751.       [String[]]$InputObject
  752.    )
  753.    begin
  754.    {
  755.       $OFS = "`n"
  756.       [String]$xmlString = ""
  757.    }
  758.    process
  759.    {
  760.       $xmlString += $InputObject
  761.    }
  762.    end
  763.    {
  764.       $type = [psobject].assembly.gettype("System.Management.Automation.Deserializer")
  765.       $ctor = $type.getconstructor("instance,nonpublic", $null, @([xml.xmlreader]), $null)
  766.       $sr = new-object System.IO.StringReader $xmlString
  767.       $xr = new-object System.Xml.XmlTextReader $sr
  768.       $deserializer = $ctor.invoke($xr)
  769.       $method = @($type.getmethods("nonpublic,instance") | where-object {$_.name -like "Deserialize"})[1]
  770.       $done = $type.getmethod("Done", [System.Reflection.BindingFlags]"nonpublic,instance")
  771.       while (!$done.invoke($deserializer, @()))
  772.       {
  773.          try {
  774.             $method.invoke($deserializer, "")
  775.          } catch {
  776.             write-warning "Could not deserialize $xmlString"
  777.          }
  778.       }
  779.       $xr.Close()
  780.       $sr.Dispose()
  781.    }
  782. }
  783.  
  784. function ConvertTo-CliXml {
  785.    param(
  786.       [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
  787.       [ValidateNotNullOrEmpty()]
  788.       [PSObject[]]$InputObject
  789.    )
  790.    begin {
  791.       $type = [psobject].assembly.gettype("System.Management.Automation.Serializer")
  792.       $ctor = $type.getconstructor("instance,nonpublic", $null, @([System.Xml.XmlWriter]), $null)
  793.       $sw = new-object System.IO.StringWriter
  794.       $xw = new-object System.Xml.XmlTextWriter $sw
  795.       $serializer = $ctor.invoke($xw)
  796.       $method = $type.getmethod("Serialize", "nonpublic,instance", $null, [type[]]@([object]), $null)
  797.       $done = $type.getmethod("Done", [System.Reflection.BindingFlags]"nonpublic,instance")
  798.    }
  799.    process {
  800.       try {
  801.          [void]$method.invoke($serializer, $InputObject)
  802.       } catch {
  803.          write-warning "Could not serialize $($InputObject.gettype()): $InputObject"
  804.       }
  805.    }
  806.    end {    
  807.       [void]$done.invoke($serializer, @())
  808.       $sw.ToString()
  809.       $xw.Close()
  810.       $sw.Dispose()
  811.    }
  812. }
  813.  
  814.  
  815. ######## From here down is all the code related to my XML DSL:
  816.  
  817. function New-XDocument {
  818. #.Synopsis
  819. #   Creates a new XDocument (the new xml document type)
  820. #.Description
  821. #  This is the root for a new XML mini-dsl, akin to New-BootsWindow for XAML
  822. #  It creates a new XDocument, and takes scritpblock(s) to define it's contents
  823. #.Example
  824. # [string]$xml = New-XDocument rss -version "2.0" {
  825. #    channel {
  826. #       title {"Test RSS Feed"}
  827. #       link {"http`://HuddledMasses.org"}
  828. #       description {"An RSS Feed generated simply to demonstrate my XML DSL"}
  829. #       item {
  830. #          title {"The First Item"}
  831. #          link {"http`://huddledmasses.org/new-site-new-layout-lost-posts/"}
  832. #          guid -isPermaLink true {"http`://huddledmasses.org/new-site-new-layout-lost-posts/"}
  833. #          description {"Ema Lazarus' Poem"}
  834. #          pubDate {(Get-Date 10/31/2003 -f u) -replace " ","T"}
  835. #       }
  836. #    }
  837. # }
  838. #
  839. # C:\PS>$xml.Declaration.ToString()  ## I can't find a way to have this included in the $xml.ToString()
  840. # C:\PS>$xml.ToString()
  841. #
  842. # <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  843. # <rss version="2.0">
  844. #   <channel>
  845. #     <title>Test RSS Feed</title>
  846. #     <link>http ://HuddledMasses.org</link>
  847. #     <description>An RSS Feed generated simply to demonstrate my XML DSL</description>
  848. #     <item>
  849. #       <title>The First Item</title>
  850. #       <link>http ://huddledmasses.org/new-site-new-layout-lost-posts/</link>
  851. #       <guid isPermaLink="true">http ://huddledmasses.org/new-site-new-layout-lost-posts/</guid>
  852. #       <description>Ema Lazarus' Poem</description>
  853. #       <pubDate>2003-10-31T00:00:00Z</pubDate>
  854. #     </item>
  855. #   </channel>
  856. # </rss>
  857. #
  858. #
  859. # Description
  860. # -----------
  861. # This example shows the creation of a complete RSS feed with a single item in it.
  862. #
  863. # NOTE that the backtick in the http`: in the URLs in the input is unecessary, and I added the space after the http: in the URLs  in the output -- these are accomodations to PoshCode's spam filter. Backticks are not need in the input, and spaces do not appear in the actual output.
  864. #
  865. #
  866. #.Example
  867. # [XNamespace]$atom="http`://www.w3.org/2005/Atom"
  868. # C:\PS>[XNamespace]$dc = "http`://purl.org/dc/elements/1.1"
  869. #
  870. # C:\PS>New-XDocument ($atom + "feed") -Encoding "UTF-16" -$([XNamespace]::Xml +'lang') "en-US" -dc $dc {
  871. #    title {"Test First Entry"}
  872. #    link {"http`://HuddledMasses.org"}
  873. #    updated {(Get-Date -f u) -replace " ","T"}
  874. #    author {
  875. #       name {"Joel Bennett"}
  876. #       uri {"http`://HuddledMasses.org"}
  877. #    }
  878. #    id {"http`://huddledmasses.org/" }
  879. #
  880. #    entry {
  881. #       title {"Test First Entry"}
  882. #       link {"http`://HuddledMasses.org/new-site-new-layout-lost-posts/" }
  883. #       id {"http`://huddledmasses.org/new-site-new-layout-lost-posts/" }
  884. #       updated {(Get-Date 10/31/2003 -f u) -replace " ","T"}
  885. #       summary {"Ema Lazarus' Poem"}
  886. #       link -rel license -href "http`://creativecommons.org/licenses/by/3.0/" -title "CC By-Attribution"
  887. #       dc:rights { "Copyright 2009, Some rights reserved (licensed under the Creative Commons Attribution 3.0 Unported license)" }
  888. #       category -scheme "http`://huddledmasses.org/tag/" -term "huddled-masses"
  889. #    }
  890. # } | % { $_.Declaration.ToString(); $_.ToString() }
  891. #
  892. # <?xml version="1.0" encoding="UTF-16" standalone="yes"?>
  893. # <feed xml:lang="en-US" xmlns="http ://www.w3.org/2005/Atom">
  894. #   <title>Test First Entry</title>
  895. #   <link>http ://HuddledMasses.org</link>
  896. #   <updated>2009-07-29T17:25:49Z</updated>
  897. #   <author>
  898. #      <name>Joel Bennett</name>
  899. #      <uri>http ://HuddledMasses.org</uri>
  900. #   </author>
  901. #   <id>http ://huddledmasses.org/</id>
  902. #   <entry>
  903. #     <title>Test First Entry</title>
  904. #     <link>http ://HuddledMasses.org/new-site-new-layout-lost-posts/</link>
  905. #     <id>http ://huddledmasses.org/new-site-new-layout-lost-posts/</id>
  906. #     <updated>2003-10-31T00:00:00Z</updated>
  907. #     <summary>Ema Lazarus' Poem</summary>
  908. #     <link rel="license" href="http ://creativecommons.org/licenses/by/3.0/" title="CC By-Attribution" />
  909. #     <dc:rights>Copyright 2009, Some rights reserved (licensed under the Creative Commons Attribution 3.0 Unported license)</dc:rights>
  910. #     <category scheme="http ://huddledmasses.org/tag/" term="huddled-masses" />
  911. #   </entry>
  912. # </feed>
  913. #
  914. #
  915. # Description
  916. # -----------
  917. # This example shows the use of a default namespace, as well as additional specific namespaces for the "dc" namespace. It also demonstrates how you can get the <?xml?> declaration which does not appear in a simple .ToString().
  918. #
  919. # NOTE that the backtick in the http`: in the URLs in the input is unecessary, and I added the space after the http: in the URLs  in the output -- these are accomodations to PoshCode's spam filter. Backticks are not need in the input, and spaces do not appear in the actual output.#
  920. #
  921. [CmdletBinding()]
  922. Param(
  923.    # The root node name
  924.    [Parameter(Mandatory = $true, Position = 0)]
  925.    [System.Xml.Linq.XName]$root
  926. ,
  927.    # Optional: the XML version. Defaults to 1.0
  928.    [Parameter(Mandatory = $false)]
  929.    [string]$Version = "1.0"
  930. ,
  931.    # Optional: the Encoding. Defaults to UTF-8
  932.    [Parameter(Mandatory = $false)]
  933.    [string]$Encoding = "UTF-8"
  934. ,
  935.    # Optional: whether to specify standalone in the xml declaration. Defaults to "yes"
  936.    [Parameter(Mandatory = $false)]
  937.    [string]$Standalone = "yes"
  938. ,
  939.    # A Hashtable of parameters which should be available as local variables to the scriptblock in args
  940.    [Parameter(Mandatory = $false)]
  941.    [hashtable]$Parameters
  942. ,
  943.    # this is where all the dsl magic happens. Please see the Examples. :)
  944.    [AllowNull()][AllowEmptyString()][AllowEmptyCollection()]
  945.    [Parameter(Position=99, Mandatory = $false, ValueFromRemainingArguments=$true)]
  946.    [PSObject[]]$args
  947. )
  948. BEGIN {
  949.    $script:NameSpaceHash = New-Object 'Dictionary[String,XNamespace]'
  950.    if($root.NamespaceName) {
  951.       $script:NameSpaceHash.Add("", $root.Namespace)
  952.    }
  953. }
  954. PROCESS {
  955.    if($Parameters) {
  956.       foreach($key in $Parameters.Keys) {
  957.          Set-Variable $key $Parameters.$key -Scope Script
  958.       }
  959.    }
  960.    New-Object XDocument (New-Object XDeclaration $Version, $Encoding, $standalone),(
  961.       New-Object XElement $(
  962.          $root
  963.          while($args) {
  964.             $attrib, $value, $args = $args
  965.             if($attrib -is [ScriptBlock]) {
  966.                # Write-Verbose "Preparsed DSL: $attrib"
  967.                $attrib = ConvertFrom-XmlDsl $attrib
  968.                Write-Verbose "Reparsed DSL: $attrib"
  969.                & $attrib
  970.             } elseif ( $value -is [ScriptBlock] -and "-CONTENT".StartsWith($attrib.TrimEnd(':').ToUpper())) {
  971.                $value = ConvertFrom-XmlDsl $value
  972.                Write-Verbose "Reparsed DSL: $value"
  973.                & $value
  974.             } elseif ( $value -is [XNamespace]) {
  975.                New-Object XAttribute ([XNamespace]::Xmlns + $attrib.TrimStart("-").TrimEnd(':')), $value
  976.                $script:NameSpaceHash.Add($attrib.TrimStart("-").TrimEnd(':'), $value)
  977.             } else {
  978.                Write-Verbose "XAttribute $attrib = $value"
  979.                New-Object XAttribute $attrib.TrimStart("-").TrimEnd(':'), $value
  980.             }
  981.          }
  982.       ))
  983. }
  984. }
  985.  
  986. Set-Alias xml New-XDocument -EA 0
  987. Set-Alias New-Xml New-XDocument -EA 0
  988.  
  989. function New-XAttribute {
  990. #.Synopsys
  991. #   Creates a new XAttribute (an xml attribute on an XElement for XDocument)
  992. #.Description
  993. #  This is the work-horse for the XML mini-dsl
  994. #.Parameter name
  995. #   The attribute name
  996. #.Parameter value
  997. #  The attribute value
  998. [CmdletBinding()]
  999. Param([Parameter(Mandatory=$true)]$name,[Parameter(Mandatory=$true)]$value)
  1000.    New-Object XAttribute $name, $value
  1001. }
  1002. Set-Alias xa New-XAttribute -EA 0
  1003. Set-Alias New-XmlAttribute New-XAttribute -EA 0
  1004.  
  1005.  
  1006. function New-XElement {
  1007. #.Synopsys
  1008. #   Creates a new XElement (an xml tag for XDocument)
  1009. #.Description
  1010. #  This is the work-horse for the XML mini-dsl
  1011. #.Parameter tag
  1012. #   The name of the xml tag
  1013. #.Parameter args
  1014. #   this is where all the dsl magic happens. Please see the Examples. :)
  1015. [CmdletBinding()]
  1016. Param(
  1017.    [Parameter(Mandatory = $true, Position = 0)]
  1018.    [System.Xml.Linq.XName]$tag
  1019. ,
  1020.    [AllowNull()][AllowEmptyString()][AllowEmptyCollection()]
  1021.    [Parameter(Position=99, Mandatory = $false, ValueFromRemainingArguments=$true)]
  1022.    [PSObject[]]$args
  1023. )
  1024. PROCESS {
  1025.   New-Object XElement $(
  1026.      $tag
  1027.      Write-Verbose "New-XElement $tag $($args -join ',')"
  1028.      while($args) {
  1029.         $attrib, $value, $args = $args
  1030.         if($attrib -is [ScriptBlock]) { # then it's content
  1031.            & $attrib
  1032.         } elseif ( $value -is [ScriptBlock] -and "-CONTENT".StartsWith($attrib.TrimEnd(':').ToUpper())) { # then it's content
  1033.            & $value
  1034.         } elseif ( $value -is [XNamespace]) {
  1035.            Write-Verbose "New XAttribute xmlns: $($attrib.TrimStart("-").TrimEnd(':')) = $value"
  1036.            New-Object XAttribute ([XNamespace]::Xmlns + $attrib.TrimStart("-").TrimEnd(':')), $value
  1037.            $script:NameSpaceHash.Add($attrib.TrimStart("-").TrimEnd(':'), $value)
  1038.         } elseif($value -match "^-(?!\d)\w") {
  1039.             $args = @($value)+@($args)
  1040.         } elseif($value -ne $null) {
  1041.            Write-Verbose "New XAttribute $($attrib.TrimStart("-").TrimEnd(':')) = $value"
  1042.            New-Object XAttribute $attrib.TrimStart("-").TrimEnd(':'), $value
  1043.         }        
  1044.      }
  1045.    )
  1046. }
  1047. }
  1048. Set-Alias xe New-XElement
  1049. Set-Alias New-XmlElement New-XElement
  1050.  
  1051. function ConvertFrom-XmlDsl {
  1052. Param([ScriptBlock]$script)
  1053.    $parserrors = $null
  1054.    $global:tokens = [PSParser]::Tokenize( $script, [ref]$parserrors )
  1055.    [Array]$duds = $global:tokens | Where-Object { $_.Type -eq "Command" -and !$_.Content.Contains('-') -and ($(Get-Command $_.Content -Type Cmdlet,Function,ExternalScript -EA 0) -eq $Null) }
  1056.    if($duds) {
  1057.            [Array]::Reverse( $duds )
  1058.    }
  1059.    [string[]]$ScriptText = "$script" -split "`n"
  1060.  
  1061.    ForEach($token in $duds ) {
  1062.           # replace : notation with namespace notation
  1063.           if( $token.Content.Contains(":") ) {
  1064.                  $key, $localname = $token.Content -split ":"
  1065.                  $ScriptText[($token.StartLine - 1)] = $ScriptText[($token.StartLine - 1)].Remove( $token.StartColumn -1, $token.Length ).Insert( $token.StartColumn -1, "'" + $($script:NameSpaceHash[$key] + $localname) + "'" )
  1066.           } else {
  1067.                  $ScriptText[($token.StartLine - 1)] = $ScriptText[($token.StartLine - 1)].Remove( $token.StartColumn -1, $token.Length ).Insert( $token.StartColumn -1, "'" + $($script:NameSpaceHash[''] + $token.Content) + "'" )
  1068.           }
  1069.           # insert 'xe' before everything (unless it's a valid command)
  1070.           $ScriptText[($token.StartLine - 1)] = $ScriptText[($token.StartLine - 1)].Insert( $token.StartColumn -1, "xe " )
  1071.    }
  1072.    Write-Output ([ScriptBlock]::Create( ($ScriptText -join "`n") ))
  1073. }
  1074.  
  1075.  
  1076.  
  1077. ######## Xaml
  1078. #  if($PSVersionTable.CLRVersion -ge "4.0"){
  1079. #     trap { continue }
  1080. #     [Reflection.Assembly]::LoadWithPartialName("System.Xaml") | Out-Null
  1081. #     if("System.Xaml.XamlServices" -as [type]) {
  1082.    
  1083.    #  }
  1084. #  }
  1085.    
  1086. Export-ModuleMember -alias * -function New-XDocument, New-XAttribute, New-XElement, Remove-XmlNamespace, Remove-XmlElement, Get-Namespace, Get-XmlContent, Set-XmlContent, ConvertTo-Xml, Select-Xml, Update-Xml, Format-Xml, ConvertTo-CliXml, ConvertFrom-CliXml
  1087.  
  1088. # SIG # Begin signature block
  1089. # MIIZEwYJKoZIhvcNAQcCoIIZBDCCGQACAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
  1090. # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
  1091. # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUSzpk+TjIGQhlVoEBJG9eVnhA
  1092. # vr+gghTRMIIDnzCCAoegAwIBAgIQeaKlhfnRFUIT2bg+9raN7TANBgkqhkiG9w0B
  1093. # AQUFADBTMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xKzAp
  1094. # BgNVBAMTIlZlcmlTaWduIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EwHhcNMTIw
  1095. # NTAxMDAwMDAwWhcNMTIxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJVUzEdMBsGA1UE
  1096. # ChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xNDAyBgNVBAMTK1N5bWFudGVjIFRpbWUg
  1097. # U3RhbXBpbmcgU2VydmljZXMgU2lnbmVyIC0gRzMwgZ8wDQYJKoZIhvcNAQEBBQAD
  1098. # gY0AMIGJAoGBAKlZZnTaPYp9etj89YBEe/5HahRVTlBHC+zT7c72OPdPabmx8LZ4
  1099. # ggqMdhZn4gKttw2livYD/GbT/AgtzLVzWXuJ3DNuZlpeUje0YtGSWTUUi0WsWbJN
  1100. # JKKYlGhCcp86aOJri54iLfSYTprGr7PkoKs8KL8j4ddypPIQU2eud69RAgMBAAGj
  1101. # geMwgeAwDAYDVR0TAQH/BAIwADAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js
  1102. # LnZlcmlzaWduLmNvbS90c3MtY2EuY3JsMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMI
  1103. # MDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AudmVyaXNp
  1104. # Z24uY29tMA4GA1UdDwEB/wQEAwIHgDAeBgNVHREEFzAVpBMwETEPMA0GA1UEAxMG
  1105. # VFNBMS0zMB0GA1UdDgQWBBS0t/GJSSZg52Xqc67c0zjNv1eSbzANBgkqhkiG9w0B
  1106. # AQUFAAOCAQEAHpiqJ7d4tQi1yXJtt9/ADpimNcSIydL2bfFLGvvV+S2ZAJ7R55uL
  1107. # 4T+9OYAMZs0HvFyYVKaUuhDRTour9W9lzGcJooB8UugOA9ZresYFGOzIrEJ8Byyn
  1108. # PQhm3ADt/ZQdc/JymJOxEdaP747qrPSWUQzQjd8xUk9er32nSnXmTs4rnykr589d
  1109. # nwN+bid7I61iKWavkugszr2cf9zNFzxDwgk/dUXHnuTXYH+XxuSqx2n1/M10rCyw
  1110. # SMFQTnBWHrU1046+se2svf4M7IV91buFZkQZXZ+T64K6Y57TfGH/yBvZI1h/MKNm
  1111. # oTkmXpLDPMs3Mvr1o43c1bCj6SU2VdeB+jCCA8QwggMtoAMCAQICEEe/GZXfjVJG
  1112. # Q/fbbUgNMaQwDQYJKoZIhvcNAQEFBQAwgYsxCzAJBgNVBAYTAlpBMRUwEwYDVQQI
  1113. # EwxXZXN0ZXJuIENhcGUxFDASBgNVBAcTC0R1cmJhbnZpbGxlMQ8wDQYDVQQKEwZU
  1114. # aGF3dGUxHTAbBgNVBAsTFFRoYXd0ZSBDZXJ0aWZpY2F0aW9uMR8wHQYDVQQDExZU
  1115. # aGF3dGUgVGltZXN0YW1waW5nIENBMB4XDTAzMTIwNDAwMDAwMFoXDTEzMTIwMzIz
  1116. # NTk1OVowUzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMSsw
  1117. # KQYDVQQDEyJWZXJpU2lnbiBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIENBMIIBIjAN
  1118. # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqcqypMzNIK8KfYmsh3XwtE7x38EP
  1119. # v2dhvaNkHNq7+cozq4QwiVh+jNtr3TaeD7/R7Hjyd6Z+bzy/k68Numj0bJTKvVIt
  1120. # q0g99bbVXV8bAp/6L2sepPejmqYayALhf0xS4w5g7EAcfrkN3j/HtN+HvV96ajEu
  1121. # A5mBE6hHIM4xcw1XLc14NDOVEpkSud5oL6rm48KKjCrDiyGHZr2DWFdvdb88qiaH
  1122. # XcoQFTyfhOpUwQpuxP7FSt25BxGXInzbPifRHnjsnzHJ8eYiGdvEs0dDmhpfoB6Q
  1123. # 5F717nzxfatiAY/1TQve0CJWqJXNroh2ru66DfPkTdmg+2igrhQ7s4fBuwIDAQAB
  1124. # o4HbMIHYMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
  1125. # dmVyaXNpZ24uY29tMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYDVR0fBDowODA2oDSg
  1126. # MoYwaHR0cDovL2NybC52ZXJpc2lnbi5jb20vVGhhd3RlVGltZXN0YW1waW5nQ0Eu
  1127. # Y3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIBBjAkBgNVHREE
  1128. # HTAbpBkwFzEVMBMGA1UEAxMMVFNBMjA0OC0xLTUzMA0GCSqGSIb3DQEBBQUAA4GB
  1129. # AEpr+epYwkQcMYl5mSuWv4KsAdYcTM2wilhu3wgpo17IypMT5wRSDe9HJy8AOLDk
  1130. # yZNOmtQiYhX3PzchT3AxgPGLOIez6OiXAP7PVZZOJNKpJ056rrdhQfMqzufJ2V7d
  1131. # uyuFPrWdtdnhV/++tMV+9c8MnvCX/ivTO1IbGzgn9z9KMIIGnzCCBYegAwIBAgIQ
  1132. # DmkGmMIUyHq1tgS5FjzRkDANBgkqhkiG9w0BAQUFADBzMQswCQYDVQQGEwJVUzEV
  1133. # MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t
  1134. # MTIwMAYDVQQDEylEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBDb2RlIFNpZ25pbmcg
  1135. # Q0EtMTAeFw0xMjAzMjAwMDAwMDBaFw0xMzAzMjIxMjAwMDBaMG0xCzAJBgNVBAYT
  1136. # AlVTMREwDwYDVQQIEwhOZXcgWW9yazEXMBUGA1UEBxMOV2VzdCBIZW5yaWV0dGEx
  1137. # GDAWBgNVBAoTD0pvZWwgSC4gQmVubmV0dDEYMBYGA1UEAxMPSm9lbCBILiBCZW5u
  1138. # ZXR0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2ogGAG89d1jMfRJv
  1139. # 2d3U1lCsW8ok7GkjnLYDn0zC1ALq11rWN5NVwVbn133i+KV0O8kM5vd2M7xE8CnV
  1140. # AgybjkrvRD2IqMtp4SrwQuiGiVGsNVWO3vSLHcWsS/I7N0UIpS5PhTuFB4PcOy/M
  1141. # HR4F2g6JLMrAtkpYWxauAFZfFwuEfm6vqWobHTDt5wG+zqOTxMSi1UvL5fEMDoej
  1142. # GqqriIx5mKDzrvUb/ALNKZ1rGPWlT7O0/UHrV5VuOfgij4XVKBAdcg9JLxkyAEIJ
  1143. # +VvVQ2Jn3lVONCCHbfu5IVhddMru81U/v5Wrj80Zrwh2TH25qlclUKr6eXRLtP+x
  1144. # Fm23CwIDAQABo4IDMzCCAy8wHwYDVR0jBBgwFoAUl0gD6xUIa7myWCPMlC7xxmXS
  1145. # ZI4wHQYDVR0OBBYEFJicRKq/XsBWRuKzU6eTUCBCCU65MA4GA1UdDwEB/wQEAwIH
  1146. # gDATBgNVHSUEDDAKBggrBgEFBQcDAzBpBgNVHR8EYjBgMC6gLKAqhihodHRwOi8v
  1147. # Y3JsMy5kaWdpY2VydC5jb20vaGEtY3MtMjAxMWEuY3JsMC6gLKAqhihodHRwOi8v
  1148. # Y3JsNC5kaWdpY2VydC5jb20vaGEtY3MtMjAxMWEuY3JsMIIBxAYDVR0gBIIBuzCC
  1149. # AbcwggGzBglghkgBhv1sAwEwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3LmRp
  1150. # Z2ljZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUHAgIw
  1151. # ggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQA
  1152. # aQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUA
  1153. # cAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMA
  1154. # UAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEA
  1155. # cgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkA
  1156. # dAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8A
  1157. # cgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIA
  1158. # ZQBuAGMAZQAuMIGGBggrBgEFBQcBAQR6MHgwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
  1159. # Y3NwLmRpZ2ljZXJ0LmNvbTBQBggrBgEFBQcwAoZEaHR0cDovL2NhY2VydHMuZGln
  1160. # aWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUNvZGVTaWduaW5nQ0EtMS5j
  1161. # cnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQUFAAOCAQEAHIfeYpO0Jtdi/Tpc
  1162. # I6eWQIYU2ALO847Q91jLE6WiU6u8wN6tkHqgeOls070SDUK+C1rVoXKKZ0Jec2k1
  1163. # dYukKPkyf3qURPyh/aC3hJ0Wwbje7fK79Lt9ZHwJORpesJrwa8T63l3qLLLlPaIY
  1164. # o/bqiMpNZRfOclukKg2hO67yMaQl8DEL/D5UP1XZShF2zbauH627zEC5KXGZY2yU
  1165. # bmWG2N0oHxr+q4Gyfd0MPtU5avWOILB0ZsN+br+SCVVK6nKzauXMk4HXmKHaX7cy
  1166. # sqpmQiFb7/J7tPQ037KQKHCY/Z+fl0arRCiHih/Q/5owv51WSKPiaUrkBvdJ0mKV
  1167. # K+McHzCCBr8wggWnoAMCAQICEAgcV+5dcOuboLFSDHKcGwkwDQYJKoZIhvcNAQEF
  1168. # BQAwbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE
  1169. # CxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1
  1170. # cmFuY2UgRVYgUm9vdCBDQTAeFw0xMTAyMTAxMjAwMDBaFw0yNjAyMTAxMjAwMDBa
  1171. # MHMxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT
  1172. # EHd3dy5kaWdpY2VydC5jb20xMjAwBgNVBAMTKURpZ2lDZXJ0IEhpZ2ggQXNzdXJh
  1173. # bmNlIENvZGUgU2lnbmluZyBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
  1174. # CgKCAQEAxfkj5pQnxIAUpIAyX0CjjW9wwOU2cXE6daSqGpKUiV6sI3HLTmd9QT+q
  1175. # 40u3e76dwag4j2kvOiTpd1kSx2YEQ8INJoKJQBnyLOrnTOd8BRq4/4gJTyY37zqk
  1176. # +iJsiMlKG2HyrhBeb7zReZtZGGDl7im1AyqkzvGDGU9pBXMoCfsiEJMioJAZGkwx
  1177. # 8tMr2IRDrzxj/5jbINIJK1TB6v1qg+cQoxJx9dbX4RJ61eBWWs7qAVtoZVvBP1hS
  1178. # M6k1YU4iy4HKNqMSywbWzxtNGH65krkSz0Am2Jo2hbMVqkeThGsHu7zVs94lABGJ
  1179. # AGjBKTzqPi3uUKvXHDAGeDylECNnkQIDAQABo4IDVDCCA1AwDgYDVR0PAQH/BAQD
  1180. # AgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMIIBwwYDVR0gBIIBujCCAbYwggGyBghg
  1181. # hkgBhv1sAzCCAaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29t
  1182. # L3NzbC1jcHMtcmVwb3NpdG9yeS5odG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEA
  1183. # bgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEA
  1184. # dABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMA
  1185. # ZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAARQBWACAAQwBQAFMA
  1186. # IABhAG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEA
  1187. # ZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEA
  1188. # YgBpAGwAaQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEA
  1189. # dABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4w
  1190. # DwYDVR0TAQH/BAUwAwEB/zB/BggrBgEFBQcBAQRzMHEwJAYIKwYBBQUHMAGGGGh0
  1191. # dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcwAoY9aHR0cDovL2NhY2Vy
  1192. # dHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNy
  1193. # dDCBjwYDVR0fBIGHMIGEMECgPqA8hjpodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v
  1194. # RGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMECgPqA8hjpodHRwOi8v
  1195. # Y3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0Eu
  1196. # Y3JsMB0GA1UdDgQWBBSXSAPrFQhrubJYI8yULvHGZdJkjjAfBgNVHSMEGDAWgBSx
  1197. # PsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQUFAAOCAQEAggXpha+nTL+v
  1198. # zj2y6mCxaN5nwtLLJuDDL5u1aw5TkIX2m+A1Av/6aYOqtHQyFDwuEEwomwqtCAn5
  1199. # 84QRk4/LYEBW6XcvabKDmVWrRySWy39LsBC0l7/EpZkG/o7sFFAeXleXy0e5NNn8
  1200. # OqL/UCnCCmIE7t6WOm+gwoUPb/wI5DJ704SuaWAJRiac6PD//4bZyAk6ZsOnNo8Y
  1201. # T+ixlpIuTr4LpzOQrrxuT/F+jbRGDmT5WQYiIWQAS+J6CAPnvImQnkJPAcC2Fn91
  1202. # 6kaypVQvjJPNETY0aihXzJQ/6XzIGAMDBH5D2vmXoVlH2hKq4G04AF01K8UihssG
  1203. # yrx6TT0mRjGCA6wwggOoAgEBMIGHMHMxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxE
  1204. # aWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMjAwBgNVBAMT
  1205. # KURpZ2lDZXJ0IEhpZ2ggQXNzdXJhbmNlIENvZGUgU2lnbmluZyBDQS0xAhAOaQaY
  1206. # whTIerW2BLkWPNGQMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh
  1207. # AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM
  1208. # BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRl7Z8Ka4sa/4B0YuthUiWk0DOI
  1209. # hTANBgkqhkiG9w0BAQEFAASCAQCb7PNuJWsmOxRPLG4o70iH1/kheuSC45XIj9Rj
  1210. # 3QHKqH7UReswMWNnpEBwM3w0kXMSHeLvuztx4hHtCDXVaf8sugtvZz/i7xjEdU3Q
  1211. # QF1DSDEPYcth/zk1qeGP2FpBnR/hGF/wup53XR93yIyXgJfxJjYFBsUL7A6b9Vdg
  1212. # 4/h14aOTv4IQPe8LLsr14QXaXRrcBScAFVqcVCoR5zu003A++RNaiv4yrI6chp2A
  1213. # ImKWwa9wBtny0WFaltAnlAAnh+yccn/a77GEVNZgTNzmdOQv6Fh+ZNqCSTfAQRd6
  1214. # bC7FDlIqvt1DWl8hADWmswz6RR8CR2dijPg27yWNm6HLmM/doYIBfzCCAXsGCSqG
  1215. # SIb3DQEJBjGCAWwwggFoAgEBMGcwUzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZl
  1216. # cmlTaWduLCBJbmMuMSswKQYDVQQDEyJWZXJpU2lnbiBUaW1lIFN0YW1waW5nIFNl
  1217. # cnZpY2VzIENBAhB5oqWF+dEVQhPZuD72to3tMAkGBSsOAwIaBQCgXTAYBgkqhkiG
  1218. # 9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xMjA4MDIxNTA3MjRa
  1219. # MCMGCSqGSIb3DQEJBDEWBBRPzjZ9FFQI4JywxRW/O/s/eWMzPjANBgkqhkiG9w0B
  1220. # AQEFAASBgJkIUKOPt7BfL9hooks1U6ZY1ft9lNnIB1/iOYsD4QqWK+FSv6w4oM0T
  1221. # 4S7mwPnbTB3WuWXxnt55+JpSkshiGyKmBJ9biwh0a4h4ZqA+VfTLmbY+szaloWCx
  1222. # 9ordICKOsJ1S+7SpXNImGxvR7mOcNCpxVcn6OYzfBr8aNR4y+iJN
  1223. # SIG # End signature block

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me