1

我有一个处理我们所有 SQL Server 的脚本。该脚本有几个函数,我有一个错误例程,它将服务器名称、函数名称和错误消息记录到一个 500 行 x 3 列的数组中。在脚本结束时,我想将此数组排序为服务器名称序列。有几篇文章建议我只需将数组通过管道传输到sort-objectcmdlet,但是当我这样做时,数组的每个元素都将替换为system.Object[]. 注意。函数之前的数组填充只是我的数组的一个例子

$global:ErrorCount = 0
$global:ErrArray = new-object 'object[,]' 500,3

$global:ErrArray[1,00]= "SV000004"
$global:ErrArray[1,01]= "ProcessServers"
$global:ErrArray[1,02]= "The server was not found or was not accessible."

$global:ErrArray[2,00]= "BOSWEB02"
$global:ErrArray[2,01]= "GetDatabases"
$global:ErrArray[2,02]= "Database Status = Shutdown"

$global:ErrArray[3,00]= "SATURN"
$global:ErrArray[3,01]= "GetDatabases"
$global:ErrArray[3,02]= "Database Status = Shutdown"

$global:ErrArray[4,00]= "BOSWEB02"
$global:ErrArray[4,01]= "GetSystemInfo"
$global:ErrArray[4,02]= "Access is denied"

$global:ErrorCount = 4

Function DisplayErrors
{
    Write-Host "`nBefore:-`n"

    for ( $iLoop=1; $iLoop -le $global:ErrorCount; $iLoop++)
    {
        "{0,-14}  {1,-18}  {2,-80}" -f 
          $global:ErrArray[$iLoop,0], $global:ErrArray[$iLoop,1], 
          $global:ErrArray[$iLoop,2]
    }

    $Sorted = $global:ErrArray | Sort-Object @{Expression={$_[0]}}

    Write-Host "`nAfter:-`n"    

    for ( $iLoop=1; $iLoop -le $global:ErrorCount; $iLoop++)
    {
        "{0,-14}  {1,-18}  {2,-80}" -f 
          $Sorted[$iLoop,0], $Sorted[$iLoop,1], $Sorted[$iLoop,2]
    }
}  

DisplayErrors

输出如下所示:-

前:-

SV000004        ProcessServers      The server was not found or was not accessible.                                 
BOSWEB02        GetDatabases        Database Status = Shutdown                                                      
SATURN          GetDatabases        Database Status = Shutdown                                                      
BOSWEB02        GetSystemInfo       Access is denied                                                                

后:-

System.Object[]  System.Object[]     System.Object[]                                                                 
System.Object[]  System.Object[]     System.Object[]                                                                 
System.Object[]  System.Object[]     System.Object[]                                                                 
System.Object[]  System.Object[]     System.Object[]  

谁能告诉我我在这里做错了什么?

非常感谢 :-)

4

3 回答 3

1

以这种方式创建数组(锯齿状数组:array[][])你sort-object可以工作:

$global:ErrArray += ,@("SV000004","ProcessServers","The server was not found or was not accessible.")
$global:ErrArray += ,@("BOSWEB02","GetDatabases","Database Status = Shutdown")
$global:ErrArray += ,@("SATURN","GetDatabases","Database Status = Shutdown")
$global:ErrArray += ,@("BOSWEB02","GetSystemInfo","Access is denied" )

Function DisplayErrors
{
    Write-Host "`nBefore:-`n"

    foreach ( $server in $global:Errarray)
    {
    write-host $server 
    }

    $sorted = $global:ErrArray | Sort-Object @{Expression={$_[0]}}

    Write-Host "`nAfter:-`n"    

   foreach ( $server in $sorted)
    {
        write-host $server    
    }
}  

DisplayErrors

或者更像你的代码:

$global:ErrArray += ,@("SV000004","ProcessServers","The server was not found or was not accessible.")
$global:ErrArray += ,@("BOSWEB02","GetDatabases","Database Status = Shutdown")
$global:ErrArray += ,@("SATURN","GetDatabases","Database Status = Shutdown")
$global:ErrArray += ,@("BOSWEB02","GetSystemInfo","Access is denied" )



Function DisplayErrors
{
    Write-Host "`nBefore:-`n"

for ( $iLoop=0; $iLoop -lt $global:errarray.count; $iLoop++)
{
    "{0,-14}  {1,-18}  {2,-80}" -f   $global:ErrArray[$iLoop][0], $global:ErrArray[$iLoop][1], $global:ErrArray[$iLoop][2]
}

$sorted = $global:ErrArray | Sort-Object @{Expression={$_[0]}}

Write-Host "`nAfter:-`n"    

for ( $iLoop=0; $iLoop -lt $sorted.count; $iLoop++)
    {
        "{0,-14}  {1,-18}  {2,-80}" -f   $Sorted[$iLoop][0], $Sorted[$iLoop][1], $Sorted[$iLoop][2]
    }
}  

DisplayErrors
于 2012-06-26T12:18:02.140 回答
0

只是代码,女士

警告:快速排序确实存在

我在实现中将 ErrArray 更改为从 0 开始——

$global:ErrArray[ 0 ,00]= "SV000004"

...但否则插入以下功能,交易线...

$Sorted = $global:ErrArray | Sort-Object @{Expression={$_[0]}}

... 为了...

$Sorted = Order-2dArray $global:ErrArray;

# Naming sorts stinks: http://stackoverflow.com/questions/27173621/
# NOTE: **EVERY** array entry in [0,x] must be non-null if -ColCount not set.
# NOTE: **EVERY** array entry in [y,0] must be non-null. Thanks.
Function Order-2dArray
{
    param
    (
        [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
        $ArrayToSort,
        [int]$ColCount = -1,  # I hate multi-dim PS arrays.
        [int]$SortColumn = 0, # Would be a touch faster if this were a constant.
        [switch][alias("desc")]$Descending # Ascend by default.
    )

    $fullCount = $ArrayToSort.Length;
    if ($ColCount -le 0) # if not given, guess by checking for $nulls.
    {
        $ColCount=0;while ($ArrayToSort[0,$ColCount] -ne $null) {
            $ColCount++;
        }
    }

    $RowCount = $fullCount / $ColCount;
    $nullRowCap = $RowCount-1;  # 1-based to 0-based
    while ($ArrayToSort[$nullRowCap,0] -eq $null) { $nullRowCap--; }

    $itemToPlace = $nullRowCap;
    for ($i=0;$i -lt $nullRowCap;$i++)
    {
        for ($j=0;$j -lt $itemToPlace;$j++)
        {
            # This dual-check method for optionally descending is not efficient.
            if (($ArrayToSort[$j,$SortColumn] -gt $ArrayToSort[($j+1),$SortColumn] -and !$Descending) -or
                ($ArrayToSort[$j,$SortColumn] -lt $ArrayToSort[($j+1),$SortColumn] -and $Descending))
            {
                for($k=0;$k -lt $ColCount;$k++) {
                    $hold = $ArrayToSort[$j,$k];
                    $ArrayToSort[$j,$k] = $ArrayToSort[($j+1),$k];
                    $ArrayToSort[($j+1),$k] = $hold;
                }
            }
        }
        $itemToPlace--;
    }
    Write-Host -BackgroundColor Magenta $ArrayToSort.GetType();
    , $ArrayToSort; # see http://stackoverflow.com/questions/7833317/ for comma use
}

原作怎么没了?

[意识到这是一个僵尸问题——]这对于评论来说有点太大了,所以我将创建一个答案来解释为什么你需要使用 @CB 。或@vonPryz 建议。

首先,看最后的评论。OP 的方法在 PowerShell 1.0 中可以正常工作。显然不是现在。

简而言之,您不能再在 PowerShell 中访问“二维数组第一行中的值”。如果要将每个“行”条目分组到一个对象中并将该数组传递Sort-Object. 因此,您可以选择数组数组,如 CB. 的答案,或对象数组New-Object,如 vonPryz - 或任何感觉最好的东西。但它必须是 X 的数组,而不是二维数组。

要显示发生了什么,请尝试

PS> $global:ErrArray[0]

...在任何时候。你会得到...

You cannot index into a 2 dimensional array with index [0].
At line:1 char:1
+ $global:ErrArray[0]
+ ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NeedMultidimensionalIndex

也就是说,没有返回三个值的 $global:ErrArray[0] ,至少不是您想象的那样。数组的第一个维度不会对第二个维度中的三个对象进行分组。它更像是 1500 个地址,而不是 500 个楼层,每个楼层有 3 个地址。


好的,那为什么代码没有出错呢?

在您的代码中尝试此操作以确认它不会引发错误的原因:

$Sorted = $global:ErrArray | Sort-Object @{
    Expression={
        $_[0];
        Write-Host $_[0];
    }
}

结果可能会让您大吃一惊——它是每个字符串的第一个字符。

S
P
T
B
G
D
S
G
D
B
G
A

由于没有“多维数组的单行”的概念,PowerShell 正在将二维数组中的所有条目解包到字符串的单维数组中,并且使用$_[0],您将获取字符串中的第一个字符-作为数组。!!(如果你在每个位置都有整数而不是字符串,我相信代码会在这里出错。)

这意味着您不只是对二维数组中任何位置的所有非空值进行排序,您只是按每个值的第一个字母排序!

$Sorted[$iLoop,0]之所以有效,是因为(我同意这非常违反直觉)PowerShell 为您提供了现在单维数组中的$iLoop-th 和-th 值。它认为您正在为新的扁平数组传递两个索引,并且返回的值是一个包含这两个值的数组。0$Sorted

试试这两行来代替你的-f

"{0} {1}" -f $Sorted[$iLoop,0]
"{0} {1}" -f $Sorted[$iLoop,0], $Sorted[$iLoop,1], $Sorted[$iLoop,2]

第一个“有效”——它为您提供了for的$iLoop第 th 值和第 0 的 for,因为您实际上传入了两个字符串。它们可能已作为数组传入,但 PowerShell “有用地”将其解压缩为两个字符串。完美,有点。$Sorted{0}{1}

第二行回到System.Object[]您所看到的,因为它是...一个由三个数组组成的数组(因为它认为您正在使用数组逗号表示法:)X,Y,Z,每个数组的长度为 2(来自两个索引它认为它从$iLoop, 0等)。在这种情况下,数组中的前两个元素被推入{0}and {1}ToString()隐式调用并成为System.Object[]

当我们有类似的东西时,让我们确认它正在返回数组$Sorted[$iLoop,0]。在这里,我使用 PowerGUI 并在排序后放入断点以进行调试:

[DBG]: PS> $t2 = $Sorted[$iLoop,0], $Sorted[$iLoop,1], $Sorted[$iLoop,2]
[DBG]: PS> $t2.Length
3
[DBG]: PS> $t2[0]
BOSWEB02
BOSWEB02
[DBG]: PS> $t2[0][0]
BOSWEB02

因此,您要Object[]在格式调用中发送三个带有两个字符串的数组。调用ToString()anObject[]会给你带来讨厌的 System.Object[]。

如果您想按每个第一维的第二维的第 0 个元素中的内容对二维数组进行排序 [原文如此,我认为],您可能必须将其写出旧式、Bubble 或 Quicksort 或你有什么,就像我在这个答案的第一部分所做的那样。(如果可以的话,最好使用 CB. 的建议。)

所以这一切都说得通。对于 PowerShell,您有 1500 个地址,但没有按它们的 " x" 值对它们进行真正的分组。别担心,这对我来说也没有立即意义(因此我在这个问题上磕磕绊绊)。

编辑:只是为了让事情更有趣,看起来数组在 PowerShell v1.0 中确实像您期望的那样工作: http ://arstechnica.com/civis/viewtopic.php?t=52603但看看脚本专家是如何做数组的2011 年的多维数组。

于 2015-01-02T17:16:26.603 回答
0

虽然我不知道为什么 Powershell 搞砸了阵列,但我可能有更多的 Powershellish 解决方法。让我们创建一个包含数据和这些数据的一维数组的自定义对象。排序很简单。

# Custom error object
function CreateErrorObject {
    param ([string]$server, [string]$proc, [string]$message)
    $objError = New-Object System.Object
    $objError | Add-Member -type NoteProperty -name Server -value $server
    $objError | Add-Member -type NoteProperty -name Proc -value $proc
    $objError | Add-Member -type NoteProperty -name Message -value $message
    $objError
}

$errors = @() # Empty array

# Populate error objects some way
$errors += CreateErrorObject "SV000004" "ProcessServers" "The server was not found or was not accessible"
$errors += CreateErrorObject "BOSWEB02" "GetDatabases" "Database Status = Shutdown"
$errors += CreateErrorObject "SATURN" "GetDatabases" "Database Status = Shutdown"
$errors += CreateErrorObject "BOSWEB02" "GetSystemInfo" "Access is denied"


$errors # Unsorted list
$errors | sort -Property server # sort by server property
$errors | sort -Property proc # sort by proc property
$errors | sort -Property message # sort by message property
于 2012-06-26T11:56:02.213 回答