【发布时间】:2019-01-15 03:01:58
【问题描述】:
今天我突然想到,在这么多年习惯性地将-NoTypeInformation 传递给Export-Csv/ConvertTo-Csv 以防止发出不受欢迎的评论行之后,也许Import-Csv/ConvertFrom-Csv 能够如果我没有抑制该类型信息,则使用它们的原始属性类型(而不是所有它们都是 String)重建对象。我试了一下...
PS> Get-Service | ConvertTo-Csv
...而且,很长一段时间没有真正看到省略-NoTypeInformation 会发出什么,提醒它只包括输入对象的类型(实际上只是第一个对象),而不是类型成员...
#TYPE System.ServiceProcess.ServiceController
"Name","RequiredServices","CanPauseAndContinue","CanShutdown","CanStop","DisplayName","DependentServices","MachineName","ServiceName","ServicesDependedOn","ServiceHandle","Status","ServiceType","StartType","Site","Container"
...
比较与类型信息序列化的结果,然后反序列化...
PS> Get-Service | ConvertTo-Csv | ConvertFrom-Csv | Get-Member
TypeName: CSV:System.ServiceProcess.ServiceController
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
CanPauseAndContinue NoteProperty string CanPauseAndContinue=False
CanShutdown NoteProperty string CanShutdown=False
CanStop NoteProperty string CanStop=True
Container NoteProperty object Container=null
DependentServices NoteProperty string DependentServices=System.ServiceProcess.ServiceController[]
DisplayName NoteProperty string DisplayName=Adobe Acrobat Update Service
MachineName NoteProperty string MachineName=.
Name NoteProperty string Name=AdobeARMservice
RequiredServices NoteProperty string RequiredServices=System.ServiceProcess.ServiceController[]
ServiceHandle NoteProperty string ServiceHandle=
ServiceName NoteProperty string ServiceName=AdobeARMservice
ServicesDependedOn NoteProperty string ServicesDependedOn=System.ServiceProcess.ServiceController[]
ServiceType NoteProperty string ServiceType=Win32OwnProcess
Site NoteProperty string Site=
StartType NoteProperty string StartType=Automatic
Status NoteProperty string Status=Running
...到序列化没有类型信息然后反序列化的结果...
PS> Get-Service | ConvertTo-Csv -NoTypeInformation | ConvertFrom-Csv | Get-Member
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
CanPauseAndContinue NoteProperty string CanPauseAndContinue=False
CanShutdown NoteProperty string CanShutdown=False
CanStop NoteProperty string CanStop=True
Container NoteProperty object Container=null
DependentServices NoteProperty string DependentServices=System.ServiceProcess.ServiceController[]
DisplayName NoteProperty string DisplayName=Adobe Acrobat Update Service
MachineName NoteProperty string MachineName=.
Name NoteProperty string Name=AdobeARMservice
RequiredServices NoteProperty string RequiredServices=System.ServiceProcess.ServiceController[]
ServiceHandle NoteProperty string ServiceHandle=
ServiceName NoteProperty string ServiceName=AdobeARMservice
ServicesDependedOn NoteProperty string ServicesDependedOn=System.ServiceProcess.ServiceController[]
ServiceType NoteProperty string ServiceType=Win32OwnProcess
Site NoteProperty string Site=
StartType NoteProperty string StartType=Automatic
Status NoteProperty string Status=Running
...唯一的区别是TypeName 从CSV:System.ServiceProcess.ServiceController(由#TYPE 注释指定的相同类型以CSV: 为前缀)更改为System.Management.Automation.PSCustomObject。所有成员都是相同的,所有属性都是 String 类型,并且在这两种情况下,您都反序列化了不包含原始对象的方法并且不以任何方式连接或代理原始对象的对象。
显然,Microsoft 认为不仅需要在 CSV 输出中包含这种类型的信息,而且应该默认这样做。由于我不能真正问“他们为什么这样做?”,我想知道这些信息如何可能有用?除了设置每个对象的TypeName 之外,*-Csv 序列化 cmdlet 是否将它用于其他任何用途?为什么我会希望这种类型的信息在 CSV 输出中“带内”传达,而不是仅仅...知道这个包含服务信息的文件来自 System.ServiceProcess.ServiceController 实例,甚至不是关心原始类型是什么,只要它具有我期望的属性?
我能想到的仅有的两个用例是,如果您收到由未知 PowerShell 脚本创建的 CSV 文件,那么拥有类型信息可以帮助确定用于生成数据的应用程序/库/模块,或者如果您有一个可笑的通用脚本,它试图根据类型信息刷新任意输入,就像这样......
Import-Csv ... `
| ForEach-Object -Process {
# Original type name of the first record, not necessarily this record!
$firstTypeName = $_.PSObject.TypeNames[0];
if ($firstTypeName -eq 'CSV:System.ServiceProcess.ServiceController')
{
Get-Service ...
}
elseif ('CSV:System.IO.DirectoryInfo', 'CSV:System.IO.FileInfo' -contains $firstTypeName)
{
Get-ChildItem ...
}
elseif ($firstTypeName -eq 'CSV:Microsoft.ActiveDirectory.Management.ADObject')
{
Get-ADObject ...
}
...
}
...但是这些都不是非常有说服力的例子,尤其是考虑到,正如我所指出的,这种类型的信息被认为非常重要,以至于默认包含在内。还有其他我没有想到的用例吗?或者这仅仅是“包含它而不需要它比需要它而不包含它更好(而且便宜)”的情况?
相关: PowerShell GitHub issue 讨论了将 -NoTypeInformation 设为未来版本(根据 cmdlet 文档为 6.0)的默认值,以及一个明显的共识,即没有意义永远忽略-NoTypeInformation。
【问题讨论】:
-
是的...... 10 年前的奇怪设计决定。我怀疑在 6.1 中,默认情况下该开关将关闭(考虑到它在当前环境中始终处于启用状态,并且您只会在他们忘记时诅咒导出 csvs 的系统管理员)
标签: powershell csv serialization typeinfo export-csv