How to remove nested element from xml file - powershell

I need help removing removing multiple element with the same name and also remove multiple element with the same name with nested element
$file = [xml]#'
<?xml version="1.0"?>
<data>
<title>Name</title>
<date>2019 Jan 01</date>
<actor>
<name>Actor Name 1</name>
<type>Actor</type>
<thumb>image.jpg</thumb>
</actor>
<actor>
<name>Actor Name 2</name>
<type>Actor</type>
<thumb>image.jpg</thumb>
</actor>
<genre>genre1</genre>
<genre>genre2</genre>
</data>
'#
I want to remove acotr element and genre element from the xml
I try following but it didnt work.
foreach($actor in $file.data.actor)
{
$actor.RemoveAll()
}
cls
$file.SelectNodes("//actor") | foreach
{
$file.ParentNode.RemoveChild($_)
}

When the node is a complex type (it has sub elements or attributes), then you can use the following because PowerShell maps this to the node:
$file.data.actor| % { $_.ParentNode.RemoveChild($_) | OUT-NULL }
However, this won't work for things like genre because PowerShell maps it as a string. Instead you can use the following (which will work in either case):
$file.data.SelectNodes('genre') | % { $_.ParentNode.RemoveChild($_) }

Related

Convert Single Line to Multiple Lines

I am new to this Powershell.
I am trying to learn how to modified output.
When I run "Write-output $result | format-list" I have the following output
userDetails : #{id=AA:BB:CC:DD:11:22; connectionStatus=CONNECTED; hostType=WIRELESS;
authType=WPA2/WPA3+802.1x/FT-802.1x}
connectedDevice : {#{deviceDetails=}}
How do I rewrite this output to below using powershell 7.2 ? I would like to have
userDetails :
connectionStatus= CONNECTED
hostType = WIRELESS
authType = WPA2/WPA3+802.1x/FT-802.1x
connectedDevice :
Thank you for your help.
Note: I'm assuming that you're looking for a friendlier display representation of your data. For programmatic processing, Format-* cmdlets should be avoided, for the reasons explained in this answer.
What you're looking for is for Format-List to work recursively, i.e. to not only list the individual properties and their values for each input object itself, but also for nested objects contained in property values.
Format-List does not support this:
Nested objects are represented by their single-line .ToString() representations.
If they're part of a collection (enumerable), the individual elements' representations are joined with , on a single line, and are enclosed in {...}(!) as a whole. How many elements are shown at most is controlled by the $FormatEnumerationLimit preference variable, which defaults to 4.
However, you can approximate recursive listing behavior with Format-Custom; using a simplified example:
# Nested sample object to format.
[pscustomobject]#{
userDetails = [pscustomobject] #{
id = 'AA:BB:CC:DD:11:22'
connectionStatus= 'CONNECTED'
hostType = 'WIRELESS'
authType = 'WPA2/WPA3+802.1x/FT-802.1x'
}
connectedDevice = '...'
} |
Format-Custom -Depth 1 # use higher -Depth levels for multi-level expansion
Output:
class PSCustomObject
{
userDetails =
[
class PSCustomObject
{
id = AA:BB:CC:DD:11:22
connectionStatus = CONNECTED
hostType = WIRELESS
authType = WPA2/WPA3+802.1x/FT-802.1x
}
]
connectedDevice = ...
}
Note:
Caveat: If a custom view happens to be defined for a given input object's type via associated formatting data, it is that custom view that Format-Custom will invoke, not the structural representation shown above; however, this is rare ([datetime] is a rare example).
Apart from the output showing the structure recursively, the format differs from that of Format-List as follows:
Complex objects are enclosed in class <typeName> { ... }
Elements of collections (enumerables) each render on their own (group of) line(s), enclosed in [ ... ] overall. However, as with Format-List, the number of elements that are shown at most is limited by $FormatEnumerationLimit.
To prevent excessively nested output, Format-Custom stops recursing at a depth of 5 by default; you can control the recursion depth via the -Depth parameter, 1 meaning that only objects in immediate child properties are expanded.
When the recursion depth limit is reached, non-collection objects are represented by their .ToString() representations, as with Format-List.
Here is some code that produces output close to your desired output:
# Create sample data
$result = [pscustomobject] #{
userDetails = [pscustomobject]#{ id="AA:BB:CC:DD:11:22"; connectionStatus="CONNECTED"; hostType="WIRELESS"; authType="WPA2/WPA3+802.1x/FT-802.1x"}
connectedDevice = [pscustomobject]#{ deviceDetails=$null }
}
# Produce output
"userDetails :"
($result.userDetails |
Format-List -Property connectionStatus, hostType, authType |
Out-String).Trim() -replace '(?m)(?<=^[^:]+):', '='
"`nconnectedDevice :"
# TODO: add similar code as for .userDetails
Output:
userDetails :
connectionStatus = CONNECTED
hostType = WIRELESS
authType = WPA2/WPA3+802.1x/FT-802.1x
connectedDevice :
Using member access .userDetails to select a child object (similar to Select-Object -ExpandProperty userDetails).
Using Format-List -Property to output a list of the given properties
Using Out-String to create a string from the formatting data that is produced by Format-List. This string looks exactly like the output you normally see on the console.
Use String method .Trim() to remove whitespace (in this case newlines) from the beginning and end.
Use the -replace operator to replace the first : of each line by =. See this regex101 demo for more information.

Getting data out of structure not working

I'm trying to get the data out of the data structure, and I can see it's in there, but the variable the info is assigned to is null.
Let me know if you need more info for the method that assigns $SizeBasedVideoStringDevice, but it looks like this:
$SizeBasedVideoStringDevice:
[Object[7]]:
[0]:#{Key=LOAD_MEDIA;VALUE=SYSTEM.OBJECT[]}
[1]:#{KEY=LOAD_MEDIAB;VALUE=}
[2]:#{KEY=LOAD_MEDIAC;VALUE=}
[3]:#{KEY=LOAD_MEDIAD;VALUE=SYSTEM.OBJECT[]}
...
So some of them have a Value, which is fine.
When I look closer at that first value, it looks like this:
Value: [Object[5]]
[0]: "LoadDialog.MediaA"
[1]: "LoadDialog.MediaB"
[2]: "LoadDialog.MediaC"
...
I have the following code, and for some reason it's not finding that first one. Once I get the data out, I will loop thru and process each Value.
$tmp = "LOAD_MEDIA" #this will match first in data structure
$sizeBasedVideoString = $SizeBasedVideoStringDevice.where{$_Key -eq $tmp}.Value ###this is null
if($null -ne $sizeBasedVideoString)
{
$resultDPS_sized = New-Object System.Collections.Generic.List[string]
foreach($vid in $sizeBasedVideoString)
{
#get vid location
$temp = ProcessDPSMDB -mdbLookupString $vid -mdbFilePath $dpsMdbPathFull
$resultDPS_sized.Add($temp)
}
}
This is using PowerShell 5.1 and VSCode.

How to bind an array to an HTML tag in powershell?

Below is a snip of my powershell code where my response or my variable($witrevisions) is of type array. I am looking to bind this in a html tag which i have defined in the power shell. As I am very new to coding stuff , I am looking the ways how can I bind array to html tag in best possible way
...continuing my line of code
$response4s = (Invoke-RestMethod -Uri $uriAccount -Method get -Headers $AzureDevOpsAuthenicationHeader).values
$wits = $response4s | where({$_.fields.'System.WorkItemType' -eq 'Task'}) # Only retrieve Tasks
$witrevisions = #()
foreach($wit in $response4s){
$customObject = new-object PSObject -property #{
"Title" = $wit.fields.'System.Title'
"AssignedTo" = $wit.fields.'System.AssignedTo'
}
$witrevisions += $customObject
}
$witrevisions | Select-Object `
Title,
AssignedTo
}
and this the sample response i am getting in $witrevisions which i have exported in text file. its a table with two column one having emails and other having a title name.i have tried to show by giving it a table view for better understanding
Assigned To Title
xyz#outlook.com testingpro
drdr#outlook.com resttesting
and here is the html tag where I trying to bind the $witrevisions.
$DOWNLOAD_PAGE_BODY_CONTENT = "<!DOCTYPE html>
`n<html>
`n<head>
`n <title>Validation</title>
`n</head>
`n<body>
`n
`n<p>Please click the link to download the release.</p>
`n<p></p>
`n<p></p>
`n<p>$witrevisions</p>
`n</body>
`n</html>
`n"
Can someone please tell me how should I do this??
Here is an example of some code that would take your array and emit a table, with an explanation to help you tweak to your specific needs:
"<table><body>$($witrevisions|% {"<tr><td>$($_.Title)</td><td>$($_.AssignedTo)</td></tr>"} )</body></table>"
The double quotes are important because they allow string interpolation (it will replace variables with this value, versus being read a plain text. E.g. '[' + $test + ']' => "[$test]"
If you need to do more complex logic in string interpolation, you can use $(...), the ellipses being regular code.
You can iterate through an array by piping to the ForEach-Object, or it's alias %. All the code in the braces will be executed for each item in the array. The current items is represented by $_.
We're then back to string interpolation and using $(...), which is needed to access the members of the current item.
Note: There are several other ways to accomplish (functionally) the same thing. E.g. foreach(...){} vs |%{...}, so feel free to use a different technique if you are more comfortable with doing something a different way.

Import in a CSV and Exporting to a Text File

I been ting to research this and I'm trying to do something that I'm not sure is possible in Powershell. I have a CSV like this with the header included:
Field1,Field2,Field3
Field1aaa,abc,rst
Field2bbb,ghi,xyz
In the end, I'm looking to take the CSV and export to a text file in a specific format. And it needs to be formatted this way for the program that I'm working with. It's kind of like a JSON file, but not quite. I'm trying to create essential a block of text for each CSV row. Here is what I'm literally trying to get on the output text file
Fieldaaa {
field2<abc>
field3<rst>
}
Field2bbb {
field2<ghi>
field3<xyz>
Think of field1 like the title for each group as I listed above. I have accomplished loading in the csv:
$userobjects = Import-CSV C:\temp\testcsv2.csv.
But then I don't know how to do it from here. And to add, that text output I'm trying to add in are tab keys. I imagine I could do this by inserting in \t once I figure out how to parse this CSV and export to text. And I can use Powershell 5.1 as I'm working with Server 2016 and Windows 10 environment with that version. Please let me know if I can clarify anything else.
You just need to follow these steps:
get the content (you already did this, and its already in a nice object for you to use)
Iterate around each row and append some formatted value to an output string
write that output string to your file
Here is one way you can do this:
$outString = ""
$userobjects = Import-CSV C:\test\test.csv
foreach ($object in $userobjects) {
$outString = #"
$outString
$($object.Field1) {
field2<$($object.Field2)>
field3<$($object.Field3)>
}
"#
}
Set-Content C:\test\out.txt $outString
Or maybe a more PowerShelly way is
Import-Csv C:\test\test.csv | ForEach-Object {
Write-Output #"
$($_.Field1) {
field2<$($_.Field2)>
field3<$($_.Field3)>
}
"# } > c:\test\out.txt
If you don't know it already, I can recommend checking ss64 for powershell examples

PowerShell Variable

I am looking up data and then want to add that to some kind of list which I can reference, for example if my data looked like this:
Name - John
Last Name - Doe
Age - 55
I would want to store that in a list and be able to do foreach $member in $myList and be able to print $member.Name
Hope that makes sense, not sure what the best way to do this is, would it be creating an object? or using a hashtable?
You can use a PowerShell Hashtable for this:
$NameObject= #{
'Name'='John'
'LastName'='Doe'
'Age'='55'
}
You can do this inside of a loop to add your data like so, to create a PowerShell Object.
$NameObjectCollection = foreach($Object in $MyData)
{
#Add Data to Object
[PSCustomObject] $NameObject= #{
'Name'=$Object.Property1
'LastName'=$Object.Property2
'Age'=$Object.Property3
}
#Output object
$NameObject
}
#Now you can loop over this data
foreach($NameObject in $NameObjectCollection)
{
#Access the properties of the NameObject`
$NameObject.Name
$NameObject.LastName
$NameObject.Age
}