Сокращение потребления памяти скриптом PowerShell - PullRequest
0 голосов
/ 12 апреля 2020

Я знаю, что это тянет довольно много данных, но в настоящее время это ограничивает потребление памяти, когда я запускаю его на своей локальной машине. Хорошая новость в том, что он возвращает результат, который мне нужен. Может кто-нибудь помочь мне с оптимизацией производительности? До сих пор я мало что сделал, опасаясь испортить скрипт, который возвращает желаемый результат. Заранее спасибо за любые предложения.

#// Start of script 
#// Get year and month for csv export file 
$DateTime = Get-Date -f "yyyy-MM" 

#// Set CSV file name 
$CSVFile = "C:\Temp\AD_Groups"+$DateTime+".csv" 

#// Create emy array for CSV data 
$CSVOutput = @() 

Measure-Command {

    #// Get all AD groups in the domain 
    $ADGroups = Get-ADGroup -Filter "GroupScope -ne 'DomainLocal' -AND GroupCategory -eq 'Security' -AND Member -like '*'" -SearchBase "OU=SHS, DC=shs, DC=net" -Properties Member #-ResultSetSize 1000 Name -like '*''s*' -AND 

    #// Set progress bar variables 
    $i=0 
    $tot = $ADGroups.count 

    foreach ($ADGroup in $ADGroups) {
        #// Set up progress bar 
        $i++ 
        $status = "{0:N0}" -f ($i / $tot * 100) 
        Write-Progress -Activity "Exporting AD Groups" -status "Processing Group $i of $tot : $status% Completed" -PercentComplete ($i / $tot * 100) 

        #// Ensure Members variable is empty 
        $Members = ""

        #// Get group members which are also groups and add to string 
        $MembersArr = Get-ADGroup $ADGroup.DistinguishedName -Properties Member | Select-Object -ExpandProperty Member

        if ($MembersArr) {

            foreach ($Member in $MembersArr) {

                $ADObj = Get-ADObject -filter {DistinguishedName -eq $Member}
                #// Initialize regex variable
                $matches = "" 

                if ($ADObj.ObjectClass -eq "user") {
                    $UserObj = Get-ADObject -filter {DistinguishedName -eq $Member}

                    $match = $UserObj -match '\([a-zA-Z0-9]+\)'
                    $empid=$matches[0] -replace ".*\(","" -replace "\)",""

                    if ($UserObj.Enabled -eq $False) { 
                        continue
                    }

                    $Members = $empid

                }

                # Check for null members to avoid error for empty groups 
                if ([string]::IsNullOrEmpty($Members)) { 
                    continue        
                }

                $HashTab = [ordered]@{ 
                        "GroupName" = $ADGroup.Name -replace "'s", "''s"
                        "GroupCategory" = $ADGroup.GroupCategory 
                        "GroupScope" = $ADGroup.GroupScope 
                        "MemberID" = if([string]::IsNullOrEmpty($empid)){""}
                                        else{$empid}
                }

                #// Add hash table to CSV data array 
                $CSVOutput += New-Object PSObject -Property $HashTab
            }
        }

        #// Export to CSV files 
        $CSVOutput | Sort-Object Name, Member | Export-Csv $CSVFile -NoTypeInformation
    }
}

1 Ответ

1 голос
/ 12 апреля 2020

Я тоже испытал это с кодом, который перебирает тысячи учетных записей. Проблема в том, что у сборщика мусора нет времени на очистку в l oop, поскольку ваш код постоянно что-то делает. В. NET, я бы вызвал .Dispose() вручную, чтобы убедиться, что вещи очищены, но здесь вы не можете.

Вы можете попробовать вызвать [System.GC]::Collect() после назначения каждой переменной в l oop. Например, после $MembersArr = и после $ADObj = (надеюсь) заставить его освободить память, использованную для предыдущего значения.

Кроме того, я думаю, что строка $UserObj = Get-ADObject... должна вызывать Get-ADUser, а не Get-ADObject. Таким образом, $UserObj.Enabled никогда не будет иметь значения, и ваш continue никогда не будет поражен.

Но вы можете полностью сэкономить на использовании Get-ADUser, запросив userAccountControl значение в Get-ADObject и использование его для определения, отключен ли пользователь. Например:

$ADObj = Get-ADObject -filter {DistinguishedName -eq $Member} -Properties userAccountControl

# Clean up the old $ADObj value
[System.GC]::Collect()

#// Initialize regex variable
$matches = "" 

if ($ADObj.ObjectClass -eq "user") {
    $match = $ADObj -match '\([a-zA-Z0-9]+\)'
    $empid=$matches[0] -replace ".*\(","" -replace "\)",""

    if ($ADObj.userAccountControl -band 2) { 
        continue
    }

    $Members = $empid
}

Проверка состояния $ADObj.userAccountControl -band 2 является побитовым И сравнение для проверки, установлен ли второй бит значения userAccountControl, что означает, что учетная запись отключена.

...