简体   繁体   English

使用PowerShell将字符串解析为对象时遇到问题

[英]Trouble parsing string to object with PowerShell

I have a string with structured data (see below). 我有一个包含结构化数据的字符串(请参见下文)。 I need to take this string and convert it to an object, so I can export it to .csv (or whatever else is requested of me). 我需要使用此字符串并将其转换为对象,以便可以将其导出到.csv(或其他要求我执行的操作)。 I ran the following code: 我运行了以下代码:

$data = $string -replace "\s*:\s*","="

But my output looks like this: 但是我的输出看起来像这样:

City=Country=Department=DisplayName=John Doe
DistinguishedName=CN=John Doe, CN=Users, DC=domain, DC=com
EmailAddress=jdoe@domain.com
Enabled=False
Fax=GivenName=John
MobilePhone=Name=John Doe
ObjectClass=user
ObjectGUID=cdb9a45c-80f4-4919-bf43-5db8d9ca83da
Office=OfficePhone=PostalCode=SamAccountName=jdoe
SID=S-1-5-21-2025429266-2000478354-1606980848-16934
State=StreetAddress=Surname=Doe
Title=UserPrincipalName=jdoe@domain.com

This is clearly not correct. 这显然是不正确的。 What is a better way to make this conversion? 什么是进行此转换的更好方法? I thought about using ConvertFrom-String with the TemplateContent parameter, but haven't been able to make that work yet. 我曾考虑过将ConvertFrom-String与TemplateContent参数一起使用,但尚未能够使它起作用。

Here are the first two entries in the string (which contains several users worth of data): 这是字符串中的前两个条目(其中包含多个用户数据):

$string = @"
City              :
Country           :
Department        :
DisplayName       : John Doe
DistinguishedName : CN=John Doe,CN=Users,DC=domain,DC=com
EmailAddress      : jdoe@domain.com
Enabled           : False
Fax               :
GivenName         : John
MobilePhone       :
Name              : John Doe
ObjectClass       : user
ObjectGUID        : cdb9a45c-80f4-4919-bf43-5db8d9ca83da
Office            :
OfficePhone       :
PostalCode        :
SamAccountName    : jdoe
SID               : S-1-5-21-2025429266-2000478354-1606980848-16934
State             :
StreetAddress     :
Surname           : Doe
Title             :
UserPrincipalName : jdoe@domain.com

City              :
Country           :
Department        :
DisplayName       : DiscoverySearchMailbox{D919BA15-46A6-415f-80AD-7E09334BB852}
DistinguishedName : CN=DiscoverySearchMailbox {D919BA15-46A6-415f-80AD-7E09334BB852},CN=Users,DC=domain,DC=com
EmailAddress      : DiscoverySearchMailbox{D919BA15-46A6-415f-80AD-7E09334BB852}@domain.com
Enabled           : False
Fax               :
GivenName         :
MobilePhone       :
Name              : DiscoverySearchMailbox{D919BA15-46A6-415f-80AD-7E09334BB852}
ObjectClass       : user
ObjectGUID        : 0f35137a-de93-472f-9114-5488a462d178
Office            :
OfficePhone       :
PostalCode        :
SamAccountName    : SM_2187102a90634829b
SID               : S-1-5-21-2438891277-1009865731-3229889747-3109
State             :
StreetAddress     :
Surname           : MsExchDiscoveryMailbox D919BA15-46A6-415f-80AD-7E09334BB852
Title             :
UserPrincipalName : DiscoverySearchMailbox{D919BA15-46A6-415f-80AD-7E09334BB852}@domain.com
"@

Thanks. 谢谢。

If: 如果:

  • you can rely on values never containing : themselves 您可以依靠永不包含的值:自身
  • you don't mind that the properties of the resulting custom objects don't reflect the input order (though you could easily, but inefficiently, correct that with piping to a Select-Object call enumerating the properties explicitly), 您不必介意所生成的自定义对象的属性不会反映输入顺序(尽管您可以轻松地但效率低下地通过管道传递给Select-Object调用来显式枚举属性),

you can use ConvertFrom-StringData (I suggest avoiding the finicky and poorly documented ConvertFrom-String ): 您可以使用ConvertFrom-StringData (我建议避免使用冗长且记录不完整的ConvertFrom-String ):

$string.Trim() -split '(?m)(?=^City\b)' -ne '' | ForEach-Object { 
  [pscustomobject] ($_ -replace ':', '=' | ConvertFrom-StringData)
}  # | Export-Csv ....

Note: Casting to [pscustomobject] requires PSv3+; 注意: [pscustomobject]转换为[pscustomobject]需要PSv3 +; on PSv2, use New-Object PSCustomObject -Property (...) 在PSv2上,使用New-Object PSCustomObject -Property (...)

  • $string.Trim() -split '(?m)(?=^City\\b)' -ne '' splits the input lines into blocks of lines each representing one object ; $string.Trim() -split '(?m)(?=^City\\b)' -ne ''将输入行拆分为每行代表一个对象的行块 ; splitting is performed by lines that start with City ; 分割由以City开头的线进行; -ne '' filters out the empty block that results from parsing the start of the input. -ne ''过滤掉解析输入开始时产生的空白块。

    • .Trim() is needed to ignore empty lines at the start of the string. 需要.Trim()来忽略字符串开头的空行。
  • $_ -replace ':', '=' | ConvertFrom-StringData $_ -replace ':', '=' | ConvertFrom-StringData converts each block into $_ -replace ':', '=' | ConvertFrom-StringData将每个块转换为
    <key>=<value> lines that ConvertFrom-StringData converts as a group to a [hashtable] instance; <key>=<value> ConvertFrom-StringData <key>=<value>行, ConvertFrom-StringData作为组转换为[hashtable]实例; because hash tables inherently enumerate their entries in no guaranteed order, this is where the input ordering of properties is lost. 因为哈希表固有地以没有保证的顺序枚举其条目,所以这是属性输入顺序丢失的地方。

  • Cast [pscustomobject] converts each hashtable to a custom object, which is implicitly output; Cast [pscustomobject]将每个哈希表转换为隐式输出的自定义对象; the output can be piped to Export-Csv . 输出可以通过管道传递到Export-Csv

The escape sequence \\s matches all whitespace, including newlines. 转义序列\\s匹配所有空格,包括换行符。 Because of that lines without a value are actually merged with the next line. 因此,没有值的行实际上与下一行合并。 Split the string at newlines, do the replacement, then merge the string array back to a single string. 在换行符处分割字符串,进行替换,然后将字符串数组合并回单个字符串。

$data = $string -split '\r?\n' -replace '\s*:\s*','=' | Out-String

or make sure you don't replace line break characters: 或确保您不替换换行符:

$data = $string -replace '[\t ]*:[\t ]*', '='

Edit: 编辑:

Since your input data seems to consist of multiple records, not just one, you need to split the resulting string by record, so that you have individual strings per data set. 由于输入数据似乎由多个记录组成,而不仅仅是一个记录,因此您需要按记录分割结果字符串,以便每个数据集具有单独的字符串。 Convert each data set to a hashtable with ConvertFrom-StringData , then convert those hashtables to custom objects. 使用ConvertFrom-StringData将每个数据集转换为哈希表,然后将这些哈希表转换为自定义对象。

$data = $string -split '(?<=\r?\n)\r?\n' | ForEach-Object {
    $prop = $_.Trim() -split '\r?\n' -replace '\s*:\s*','=' |
            Out-String |
            ConvertFrom-StringData
    New-Object -Type PSObject -Property $prop
}

In PowerShell v3 and newer you can use the [PSCustomObject] type accelerator instead of New-Object : 在PowerShell v3和更高版本中,可以使用[PSCustomObject]类型的加速器代替New-Object

$data = $string -split '(?<=\r?\n)\r?\n' | ForEach-Object {
    $prop = $_.Trim() -split '\r?\n' -replace '\s*:\s*','=' |
            Out-String |
            ConvertFrom-StringData
    [PSCustomObject]$prop
}

The resulting list of objects can then be exported to a CSV. 然后可以将对象的结果列表导出为CSV。

Here You go:) 干得好:)

    $a=@"
City              :
Country           :
Department        :
DisplayName       : John Doe
DistinguishedName : CN=John Doe,CN=Users,DC=domain,DC=com
EmailAddress      : jdoe@domain.com
Enabled           : False
Fax               :
GivenName         : John
MobilePhone       :
Name              : John Doe
ObjectClass       : user
ObjectGUID        : cdb9a45c-80f4-4919-bf43-5db8d9ca83da
Office            :
OfficePhone       :
PostalCode        :
SamAccountName    : jdoe
SID               : S-1-5-21-2025429266-2000478354-1606980848-16934
State             :
StreetAddress     :
Surname           : Doe
Title             :
UserPrincipalName : jdoe@domain.com
"@
$b=ConvertFrom-Csv -InputObject $a -Delimiter ':' -Header "key","value"
$c=New-Object -TypeName System.Management.Automation.PSObject 
$b|%{ $c|Add-Member -NotePropertyName $_.key -NotePropertyValue "$($_.value)"}

Resulting object looks like this 结果对象看起来像这样

PS C:\Users\Tomasz> $c|gm




  S C:\Users\Tomasz> $c


City               : 
Country            : 
Department         : 
DisplayName        : John Doe
DistinguishedName  : CN=John Doe,CN=Users,DC=domain,DC=com
EmailAddress       : jdoe@domain.com
Enabled            : False
Fax                : 
GivenName          : John
MobilePhone        : 
Name               : John Doe
ObjectClass        : user
ObjectGUID         : cdb9a45c-80f4-4919-bf43-5db8d9ca83da
Office             : 
OfficePhone        : 
PostalCode         : 
SamAccountName     : jdoe
SID                : S-1-5-21-2025429266-2000478354-1606980848-16934
State              : 
StreetAddress      : 
Surname            : Doe
Title              : 
UserPrincipalName  : jdoe@domain.com

If this kind of solution seems like a good Idea I'll work on my answer more. 如果这种解决方案似乎是一个好主意,我将继续研究我的答案。
It obviously needs white spaces removal and some nicer variable names, but I trust You can get that done Yourself :) 它显然需要去除空格和一些更好的变量名,但是我相信您可以自己完成:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM