I'm trying to export a csv with FileZillaServer data from XML config.
It works as exepcted, except for the condition Where-Object
due to it stopped on the first block with the same name <Permissions>
.
I'd like to get Permission Dir
value only if it's set to HomeDirectory "IsHome">1
XMl contains:
<FileZillaServer>
<Users>
<User Name="USER1">
<Option Name="Pass">e1923304e508b24dc0</Option>
<Option Name="Salt"></Option>
<Option Name="Group"></Option>
<Option Name="Bypass server userlimit">1</Option>
<Option Name="User Limit">0</Option>
<Option Name="IP Limit">0</Option>
<Option Name="Enabled">0</Option>
<Option Name="Comments">Comment 1</Option>
<Option Name="ForceSsl">0</Option>
<IpFilter>
<Disallowed />
<Allowed />
</IpFilter>
<Permissions>
<Permission Dir="C:\folder1\subfolder1">
<Option Name="FileRead">1</Option>
<Option Name="FileWrite">1</Option>
<Option Name="FileDelete">1</Option>
<Option Name="FileAppend">0</Option>
<Option Name="DirCreate">0</Option>
<Option Name="DirDelete">0</Option>
<Option Name="DirList">1</Option>
<Option Name="DirSubdirs">1</Option>
<Option Name="IsHome">0</Option>
<Option Name="AutoCreate">0</Option>
</Permission>
<Permission Dir="C:\folder1\subfolder2">
<Option Name="FileRead">1</Option>
<Option Name="FileWrite">0</Option>
<Option Name="FileDelete">0</Option>
<Option Name="FileAppend">0</Option>
<Option Name="DirCreate">0</Option>
<Option Name="DirDelete">0</Option>
<Option Name="DirList">1</Option>
<Option Name="DirSubdirs">1</Option>
<Option Name="IsHome">1</Option>
<Option Name="AutoCreate">0</Option>
</Permission>
</Permissions>
<SpeedLimits DlType="0" DlLimit="10" ServerDlLimitBypass="0" UlType="0" UlLimit="10" ServerUlLimitBypass="0">
<Download />
<Upload />
</SpeedLimits>
</User>
</Users>
</FileZillaServer>
I'm using this code:
$xmlFilePath = "C:\FileZilla Server.xml"
$newcsv = "C:\newcsv.csv"
$xml = [xml](Get-Content $xmlFilePath)
$results = foreach ($user in $xml.FileZillaServer.Users.User){
[pscustomobject]@{
User = $user.Name
Comment = $Comments = $user.SelectSingleNode("Option[@Name='Comments']").InnerText = $user.SelectSingleNode("Option[@Name='Comments']").InnerText
ForceSSl = $ForceSSL = $user.SelectSingleNode("Option[@Name='ForceSsl']").InnerText = $user.SelectSingleNode("Option[@Name='ForceSsl']").InnerTex
Enabled = $Enabled = $user.SelectSingleNode("Option[@Name='Enabled']").InnerText = $user.SelectSingleNode("Option[@Name='Enabled']").InnerText
HomeDir = $user.Permissions.SelectSingleNode("Permission[@Dir]").Dir | Where-Object {$user.Permissions.SelectSingleNode("Permission[@Dir]/Option[@Name='IsHome']").InnerText -eq 1}
}
} $results | export-csv $newcsv -NoTypeInformation
You can do the following:
$xmlFilePath = "C:\FileZilla Server.xml"
$xml = [xml](Get-Content $xmlFilePath)
$results = foreach ($user in $xml.FileZillaServer.Users.User){
[pscustomobject]@{
HomeDir = $user.Permissions.SelectSingleNode("Permission[@Dir][./Option[@Name = 'IsHome'] = '1']").Dir
}
}
The XPath predicate [./Option[@Name = 'IsHome'] = '1']
creates a condition where the current node (Permission
) contains a child node Option
with an attribute called Name
. Name
must have a value of IsHome
and the text for that Option
node must be 1
.
The reason the HomeDir
property was not set as expected is because of how the selection conditions are ordered.
$user.Permissions.SelectSingleNode("Permission[@Dir]").Dir
selects the first node that is named Permission
, which contains an attribute named Dir
. When that node is selected, the property Dir
is referenced on that PowerShell object. Ultimately, you are returning the string that represents Dir
and then piping that to Where-Object
. Any piped Where-Object
conditions after that will only filter that string further.
If you wanted to rely on Where-Object
to filter, you can do something like the following:
($user.Permissions.SelectNodes("Permission[@Dir]") | where {
$_.SelectSingleNode("Option[@Name = 'IsHome']").Innertext -eq 1}).Dir
Notice how the Dir
property value is retrieved after the node, attribute, and text conditions are applied. SelectNodes()
is used because we need to send all potential nodes to Where-Object
for it to filter further.