1
votes

I am running a PowerShell script that gets some information from a csv file, stores it in an object array and then does some action depending on what's on the file. It actually only does one thing:

If one column has a AD group it copies the row for every member of that group.

The thing is I am really new at scripting and at the beginning the files were small, so everything went ok. Now I have huge files and the script is taking hours to execute.

$file = "c:\Report.csv" 
$fileContent = Import-csv $file | select *, UserName

foreach($item in $fileContent)
{
    $LoginName = $item.LoginName
    $LoginNameClean = $LoginName.split("\")
    $LoginNameClean = $LoginNameClean[1].trimstart("_")
    $ObjectClass = (Get-ADObject -filter {SamAccountName -eq $LoginNameClean}).ObjectClass
    $UserName = $null

    if($ObjectClass -eq "user")
    {
        $UserName = Get-ADUser -identity $LoginNameClean -properties DisplayName

        if($UserName)
        {
            $item.UserName = $UserName.DisplayName
        }
    }

    elseif($ObjectClass -eq "group")
    {   
        $GroupUsers = Get-ADGroupMember -identity $LoginNameClean -Recursive

        foreach($user in $GroupUsers)
        {
            $UserInsideGroup = Get-ADUser -identity $user -properties DisplayName 
            $UserInsideGroupName =  $UserInsideGroup.DisplayName
            $newRow = New-Object PsObject -Property @{"URL" = $item.URL; "SiteListFolderItem" = $item.SiteListFolderItem; "TitleName" = $item.TitleName; "PermissionType" = $item.PermissionType;  "LoginName" = $item.LoginName; "Permissions" = $Item.Permissions; "UserName" = $UserInsideGroup.DisplayName;}
            $fileContent += $newRow
        }
    }
}   


$fileContent | Export-Csv -NoTypeInformation -Path "c:\ReportUpgraded.csv" 

Any tips on how to improve the performance of this is much appreciated

Thanks in advance.

edit: I am using PS 2.0

As commentaries suggested, I am trying to replace the fileContent += newRow.

I am trying to use add member but it's giving me this error:

Add-Member : Cannot add a member with the name "URL" because a member with that name already exists. If you wan t to overwrite the member anyway, use the Force parameter to overwrite it. At line:1 char:26 + $fileContent | Add-Member <<<< -MemberType NoteProperty -Name "URL"-Value "teste" + CategoryInfo : InvalidOperation: (@{SiteListFolde...me=; URL=teste}:PSObject) [Add-Member], Inv
alidOperationException + FullyQualifiedErrorId : MemberAlreadyExists,Microsoft.PowerShell.Commands.AddMemberCommand

How I can I use this properly? Add-member is not adding but replacing members

1
well, split the data in pieces and process them in parallel - 4c74356b41
I am already doing that, but yes, I could do more splitting but it would get confusing. Is that the only way of speeding the execution time? Thanks - ranbo
where are you doing that? as for the other options, looking at this, most of the time it is probably doing requests to AD, you can't really speed that up, unless you process data in parallel - 4c74356b41
Actually on my computer. I see, I thought my loop trough all items wasn't really good. And I also read that when I do object += item I create a whole object again and that takes long, just don't know how to do it in a other way - ranbo
no i mean, where are you doing something in parallel? is $fileContent += $newRow supposed to be $fileContent1 += $newRow - 4c74356b41

1 Answers

2
votes

I manage to reduce 30 times the execution time with a couple of things.

First, I switched array to a array list so that I could use theArray.Add() method. Then, in order to stop making requests to the AD all the time, I am saving the information in excel sheets with the name of the group, so that it will only request AD once per group.

Here is the script:

$file = "ReportBefore.csv" 
$fileContent = Import-csv $file | select *, UserName
[System.Collections.ArrayList]$ArrayList = $fileContent


foreach($item in $fileContent)
{
    $LoginName = $item.LoginName
    $LoginNameClean = $LoginName.split("\")
    $LoginNameClean = $LoginNameClean[1].trimstart("_")
    $ObjectClass = (Get-ADObject -filter {SamAccountName -eq $LoginNameClean}).ObjectClass
    $UserName = $null

    if($ObjectClass -eq "user")
    {
        $UserName = Get-ADUser -identity $LoginNameClean -properties DisplayName

        if($UserName)
            {
            $item.UserName = $UserName.DisplayName
            }
    }

    elseif($ObjectClass -eq "group")
    {   
        $exportString = "\\folder\username$\Desktop\ADGroups\" + $LoginNameClean + ".csv" 

        if([System.IO.File]::Exists($exportString))
        {
          $GroupUsers = Import-csv $exportString | select *            
        }
        else
        {
        $GroupUsers = Get-ADGroupMember -identity $LoginNameClean -Recursive | Select samAccountName,Name, @{Name="DisplayName";Expression={(Get-ADUser $_.distinguishedName -Properties Displayname).Displayname}}
        $GroupUsers | Export-Csv -NoTypeInformation -Path $exportString
        }
        foreach($user in $GroupUsers)
        {

            $UserInsideGroupName =  $user.DisplayName
            $newRow = New-Object PsObject -Property @{"URL" = $item.URL; "SiteListFolderItem" = $item.SiteListFolderItem; "TitleName" = $item.TitleName; "PermissionType" = $item.PermissionType;  "LoginName" = $item.LoginName; "Permissions" = $Item.Permissions; "UserName" = $UserInsideGroupName;}
            #$filecontent += $newRow
            $ArrayList.Add($newRow)
        }
     }
}   
$ArrayList | Export-Csv -NoTypeInformation -Path "\ReportAfter.csv"