Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell 如何提高迭代循环性能_Powershell_Loops_Powershell 2.0_Nested Loops_Powershell 3.0 - Fatal编程技术网

Powershell 如何提高迭代循环性能

Powershell 如何提高迭代循环性能,powershell,loops,powershell-2.0,nested-loops,powershell-3.0,Powershell,Loops,Powershell 2.0,Nested Loops,Powershell 3.0,所以我试着循环一组数据,基本上创建一个结果树,显示所有不同的路径,我最终成功了,但运行速度非常慢,从我的测试来看,这是因为循环搜索函数和最后的额外正则表达式匹配,因为该函数无法确定最终结果是否与标准窗口匹配。如何检查根调用以筛选以windows开头的结果:以及如何删除定期搜索功能。我猜我可以创建一个新的哈希表,只包含名称/父值并使用它,但我已经玩了几个小时,没有任何运气 当前工作代码 Function New-CategoryTree { Param ( $Categor

所以我试着循环一组数据,基本上创建一个结果树,显示所有不同的路径,我最终成功了,但运行速度非常慢,从我的测试来看,这是因为循环搜索函数和最后的额外正则表达式匹配,因为该函数无法确定最终结果是否与标准窗口匹配。如何检查根调用以筛选以windows开头的结果:以及如何删除定期搜索功能。我猜我可以创建一个新的哈希表,只包含名称/父值并使用它,但我已经玩了几个小时,没有任何运气

当前工作代码

Function New-CategoryTree {
    Param (
        $Categories
    )

    $GetParentCategory = [ScriptBlock]::Create({
        Param(
            [psobject]$Category
        )
        
        #Examine the parentCategory field and see if it matches certain criteria.
        Switch ($Category.parentCategory.ref) {
            { $_ -match "^windows:([a-zA-Z_\\ 1-9]+)$" } { #if Parent Category matches 'Windows:*'
                Return "$($Category.parentCategory.ref)\$($Category.name)"
            }
            { [String]::IsNullOrWhiteSpace($_) } { #If pareent
                Return
            }
            Default {
                Return ("$(& $GetParentCategory -Category ($Categories.where({$_.name -eq $Category.parentCategory.ref})))\$($Category.name)")
            }
        }
    })

    New-Variable -Name Result -Value (New-Object -TypeName System.Collections.ArrayList)
    New-Variable -Name NewCategories -Value (New-Object -TypeName System.Collections.ArrayList)
    ForEach ($Category in $Categories) {
        [Void]$NewCategories.Add((& $GetParentCategory -Category $Category))
    }

    ForEach ($Category in $NewCategories) {
        ([Regex]::Match($Category,'^windows:([a-zA-Z_\\ 1-9]+)$').groups[1]).where({$_.success -eq $True}).value |ForEach-Object {[Void]$Result.Add($_)}
    }
    Return $Result
}
数据集

<categories>
    <category name="InternetExplorer" displayName="$(string.InternetExplorer)" explainText="$(string.IE_ExplainCat)">
        <parentCategory ref="windows:WindowsComponents" />
    </category>
    <category name="AdvancedPage" displayName="$(string.AdvancedPage)">
        <parentCategory ref="InternetCPL" />
    </category>
    <category name="InternetCPL_Advanced_Accessibility" displayName="$(string.InternetCPL_Advanced_Accessibility)">
        <parentCategory ref="AdvancedPage" />
    </category>
    <category name="InternetCPL_Advanced_International" displayName="$(string.InternetCPL_Advanced_International)">
        <parentCategory ref="AdvancedPage" />
    </category>
    <category name="InternetCPL_Advanced_Security" displayName="$(string.InternetCPL_Advanced_Security)">
        <parentCategory ref="AdvancedPage" />
    </category>
</categories>

首先,正确处理xml数据,以便与之交互:

[xml]$categories
然后您可以轻松地显示它:

[xml]$categories.categories.category | 
    select @{l='ParentCategory';e={$_.ParentCategory.ref}},Name,Displayname

ParentCategory            name                              
--------------            ----                              
windows:WindowsComponents InternetExplorer                  
InternetCPL               AdvancedPage                      
AdvancedPage              InternetCPL_Advanced_Accessibility
AdvancedPage              InternetCPL_Advanced_International
AdvancedPage              InternetCPL_Advanced_Security
根据需要对其进行过滤:

$filtered = [xml]$categories.categories.category | 
    where {$_.ParentCategory.ref -match '^windows:([a-zA-Z_\\ 1-9]+)$'}
$filtered

name             displayName                explainText             parentCategory
----             -----------                -----------             --------------
InternetExplorer $(string.InternetExplorer) $(string.IE_ExplainCat) parentCategory
要将过滤后的xml对象导出回字符串,请添加外部节点:

$xmlout = '<categories>'+$filtered.outerxml+'</categories>'
$xmlout=''+$filtered.outerxml+''

经过几个小时的研究,我偶然发现了“systems.collections.generic.dictionary”属性,它允许我创建一个以PSCustomObject为值的哈希表。这使我能够创建一个具有可引用名称的新对象,从而避免使用搜索功能。再加上新的数据类型+利用Streamreader获取文件,我的脚本以大约3-5s到0.5s的速度运行。忽略代码中的所有注释,我很难理解函数lol

Function New-CategoryTree {
    Param (
        $Categories
    )
        
    #Scriptblock that will be used to check if the currently returned object is the root object.
    $GetParentCategory = [ScriptBlock]::Create({
        Param(
            [Parameter(mandatory=$True)]
            $Category,
            [Parameter(mandatory=$True)]
            $Categories
        )
        Switch -regex ($Category.ParentCategory) {
            "^windows:([a-zA-Z_\\ 1-9]+)$" { #if Category matches 'Windows:*' (a.k.a. we are done with the dive.)
                Return "$($Category.ParentCategory)\$($Category.DisplayName)"
            }
            "/^$|\s+/"  { #Check if whitespace or empty.
                Write-Host "Warning: This shouldn't be possible, best guess is ADMX is missconfigured. CategoryName: '$($Category.Name)'."
                #This means its a root category without a parent so just return.
                Return
            }
            Default {#If not root category, then restart the loop to dive 1 layer deeper then eventually retun with parentCategory.DisplayName\Category.DisplayName.
                #If there is no valid parent category then thow a ignorable warning.
                If ([String]::IsNullOrEmpty($Categories["$($Category.ParentCategory)"])) {
                    Write-Host "Warning: $($Category.name) has no valid parent category."
                } Else {
                    Return ("$(& $GetParentCategory -Category $Categories["$($Category.ParentCategory)"] -Categories $Categories)\$($Category.displayName)")
                }
            }
        }
    })

    New-Variable -Name Results -Value (New-Object -TypeName System.Collections.Generic.List[String]) -Force
    ForEach ($Category in $Categories.GetEnumerator()) {
        $Results.Add((& $GetParentCategory -Category $Category.Value -Categories $Categories))
    }
    Return $Results
}

#Start Looping through every ADMX files.
ForEach ($File in $Script.ADMXFiles) {
    #Get content of ADMX file and store results as XML
    Set-Variable -Name ADMXFile      -Value ([xml]((New-Object -TypeName System.IO.StreamReader -ArgumentList $File.FullName,([Text.Encoding]::Default),$False,"10000").ReadToEnd()))
    New-Variable -Name Categories -Value (New-Object -TypeName 'System.Collections.Generic.Dictionary[[string], [PSCustomObject]]') -Force
    $ADMXFile.policyDefinitions.categories.Category |ForEach-Object {
        $Categories.add($_.name,[PSCustomObject]@{
            Name           = $_.name
            DisplayName    = ConvertFrom-StringTable -String $_.displayName -ADMX ($File.BaseName)
            ParentCategory = $_.ParentCategory.ref
        })
    }
    New-CategoryTree -Categories $Categories
}

使用XML解析器。请添加预期的输出。@zett42已添加,抱歉我忘记了。
Function New-CategoryTree {
    Param (
        $Categories
    )
        
    #Scriptblock that will be used to check if the currently returned object is the root object.
    $GetParentCategory = [ScriptBlock]::Create({
        Param(
            [Parameter(mandatory=$True)]
            $Category,
            [Parameter(mandatory=$True)]
            $Categories
        )
        Switch -regex ($Category.ParentCategory) {
            "^windows:([a-zA-Z_\\ 1-9]+)$" { #if Category matches 'Windows:*' (a.k.a. we are done with the dive.)
                Return "$($Category.ParentCategory)\$($Category.DisplayName)"
            }
            "/^$|\s+/"  { #Check if whitespace or empty.
                Write-Host "Warning: This shouldn't be possible, best guess is ADMX is missconfigured. CategoryName: '$($Category.Name)'."
                #This means its a root category without a parent so just return.
                Return
            }
            Default {#If not root category, then restart the loop to dive 1 layer deeper then eventually retun with parentCategory.DisplayName\Category.DisplayName.
                #If there is no valid parent category then thow a ignorable warning.
                If ([String]::IsNullOrEmpty($Categories["$($Category.ParentCategory)"])) {
                    Write-Host "Warning: $($Category.name) has no valid parent category."
                } Else {
                    Return ("$(& $GetParentCategory -Category $Categories["$($Category.ParentCategory)"] -Categories $Categories)\$($Category.displayName)")
                }
            }
        }
    })

    New-Variable -Name Results -Value (New-Object -TypeName System.Collections.Generic.List[String]) -Force
    ForEach ($Category in $Categories.GetEnumerator()) {
        $Results.Add((& $GetParentCategory -Category $Category.Value -Categories $Categories))
    }
    Return $Results
}

#Start Looping through every ADMX files.
ForEach ($File in $Script.ADMXFiles) {
    #Get content of ADMX file and store results as XML
    Set-Variable -Name ADMXFile      -Value ([xml]((New-Object -TypeName System.IO.StreamReader -ArgumentList $File.FullName,([Text.Encoding]::Default),$False,"10000").ReadToEnd()))
    New-Variable -Name Categories -Value (New-Object -TypeName 'System.Collections.Generic.Dictionary[[string], [PSCustomObject]]') -Force
    $ADMXFile.policyDefinitions.categories.Category |ForEach-Object {
        $Categories.add($_.name,[PSCustomObject]@{
            Name           = $_.name
            DisplayName    = ConvertFrom-StringTable -String $_.displayName -ADMX ($File.BaseName)
            ParentCategory = $_.ParentCategory.ref
        })
    }
    New-CategoryTree -Categories $Categories
}