PowerShell是否可以在Select-Object中获得正确的属性顺序,以便每个对象都有顺序?

时间:2018-08-17 11:10:12

标签: powershell

以下代码列出了所有AD用户。

$Domain.DomainUsersFullList = Get-ADUser -Server $Domain -ResultPageSize 500000 -Filter * -Properties *, "msDS-UserPasswordExpiryTimeComputed" | Select * -ExcludeProperty *Certificate, PropertyNames, *Properties, PropertyCount, Certificates
$($Domain.DomainUsersFullList[0]).PSObject.Properties.Name[12]
$($Domain.DomainUsersFullList[10]).PSObject.Properties.Name[12]

似乎PSObject.Properties.Name返回的顺序可能有所不同。是否可以在不独占告诉Select-Object所需属性的顺序的情况下订购属性?

仅出于我为什么需要这个的目的

  • https://github.com/EvotecIT/PSWriteWord-我编写了一个函数Add-WordTable,该函数接受任何$Object并将其放入Word文档中。无需自己解析对象。只需将其传递给函数,它将被放入Word文档中。

我现在正在为以下项目做同样的事情:

  • https://github.com/EvotecIT/PSWriteExcel-具有功能Add-ExcelWorksheetData的功能与上面的功能完全相同,但有一个例外..因为它是Excel,所以没有列限制。因此,对于100列,我每行的顺序都是错误的。这没有任何意义。

在使用WORD文档的情况下,我没有注意到此问题,因为我从来没有添加超过10列的数据,而使用Excel和100列的数据却出现了错误的顺序。下面是一个示例:

enter image description here

以下是进行转换的方法:

function Format-PSTableConvertType2 {
    [CmdletBinding()]
    param(
        $Object,
        [switch] $SkipTitles,
        [string[]] $ExcludeProperty,
        [switch] $NoAliasOrScriptProperties,
        [switch] $DisplayPropertySet
    )
    [int] $Run = 0
    $Array = New-ArrayList
    $Titles = New-ArrayList
    if ($NoAliasOrScriptProperties) {$PropertyType = 'AliasProperty', 'ScriptProperty'  } else {$PropertyType = ''}
    Write-Verbose "Format-PSTableConvertType2 - Option 2 - NoAliasOrScriptProperties: $NoAliasOrScriptProperties"

    foreach ($O in $Object) {
        $ArrayValues = New-ArrayList
        if ($DisplayPropertySet -and $O.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) {
            $ObjectProperties = $O.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( { $ExcludeProperty -notcontains $_  } ) #.Name
        } else {
            $ObjectProperties = $O.PSObject.Properties.Where( { $PropertyType -notcontains $_.MemberType -and $ExcludeProperty -notcontains $_.Name  } ).Name
        }
        #$ObjectProperties = $O.PSObject.Properties
        foreach ($Name in $ObjectProperties) {
            if ($Run -eq 0 -and -not $SkipTitle) { Add-ToArray -List $Titles -Element $Name }
            Add-ToArray -List $ArrayValues -Element $O.$Name
        }
        if ($Run -eq 0 -and -not $SkipTitle) {Add-ToArray -List ($Array) -Element $Titles }
        Add-ToArray -List $Array -Element $ArrayValues
        $Run++
    }

    return , $Array
}

它实质上将对象转换为数组数组。这样一来,仅遍历行/列就变得微不足道了。

现在重要的是,虽然通常我可以使Get-AdUser仅按正确的顺序显示我想要的值,但是我正在使用通用模块(PSWriteWord / PSWriteExcel),并且希望人们将任何对象传递给它,而不必太在乎它了。

1 个答案:

答案 0 :(得分:0)

除非有人有更好的选择:

$SpecialData = $Domain.DomainUsersFullList | Select-Object $($Domain.DomainUsersFullList[0]).PSObject.Properties.Name

$($Domain.DomainUsersFullList[0]).PSObject.Properties.Name[12]
$($Domain.DomainUsersFullList[10]).PSObject.Properties.Name[12]
$($SpecialData[0] | Select-Object $($Domain.DomainUsersFullList[0]).PSObject.Properties.Name).PSObject.Properties.Name[12]
$($SpecialData[10] | Select-Object $($Domain.DomainUsersFullList[0]).PSObject.Properties.Name).PSObject.Properties.Name[12]

基本上,这是复制第一个元素的顺序并将相同的顺序应用于每一行。这样可以确保每个对象将按与第一个元素相同的顺序返回属性。

最终实现:

function Format-PSTableConvertType2 {
    [CmdletBinding()]
    param(
        $Object,
        [switch] $SkipTitles,
        [string[]] $ExcludeProperty,
        [switch] $NoAliasOrScriptProperties,
        [switch] $DisplayPropertySet,
        $OverwriteHeaders
    )
    #[int] $Run = 0
    $Array = New-ArrayList
    $Titles = New-ArrayList
    if ($NoAliasOrScriptProperties) {$PropertyType = 'AliasProperty', 'ScriptProperty'  } else {$PropertyType = ''}
    Write-Verbose "Format-PSTableConvertType2 - Option 2 - NoAliasOrScriptProperties: $NoAliasOrScriptProperties"

    # Get Titles first (to make sure order is correct for all rows)
    if ($OverwriteHeaders) {
        $Titles = $OverwriteHeaders
    } else {
        foreach ($O in $Object) {
            if ($DisplayPropertySet -and $O.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) {
                $ObjectProperties = $O.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( { $ExcludeProperty -notcontains $_  } ) #.Name
            } else {
                $ObjectProperties = $O.PSObject.Properties.Where( { $PropertyType -notcontains $_.MemberType -and $ExcludeProperty -notcontains $_.Name  } ).Name
            }
            foreach ($Name in $ObjectProperties) {
                Add-ToArray -List $Titles -Element $Name
            }
            break
        }
        # Add Titles to Array (if not -SkipTitles)
        if (-not $SkipTitle) {
            Add-ToArray -List $Array -Element $Titles
        }
    }
    # Extract data (based on Title)
    foreach ($O in $Object) {
        $ArrayValues = New-ArrayList
        foreach ($Name in $Titles) {
            Add-ToArray -List $ArrayValues -Element $O.$Name
        }
        Add-ToArray -List $Array -Element $ArrayValues
    }
    return , $Array
}