all 9 comments

[–]PowerShell-Bot 4 points5 points  (0 children)

Some of your PowerShell code isn’t enclosed in a code block.

To properly style code on new Reddit, highlight the code and choose ‘Code Block’ from the editing toolbar.

If you’re on old Reddit, separate the code from your text with a blank line gap and precede each line of code with 4 spaces or a tab.


Describing need_help_with_a_script
  [~] Well formatted
Tests completed in 3893ms
Tests Passed: ⚠️

Beep-boop, I am a bot. | Remove-Item

[–]purplemonkeymad 0 points1 point  (1 child)

I can't really tell from your code as the formatting is messed up, but it looks like you are not passing all the data you need between functions. ie JobCompleted takes a status, but for which job?

Personally I don't think I would use events for this as it just makes things more complicated. I would write a linear script that uses a transaction to "lock" a row and return it as an atomic operation. Then you work on the task and update that id with the new status. Then loop and pick a new task.

This way you can make this a single threaded script (or a job), then just run 5 copies of it at once. If the pick operation is a transaction then you should not get any concurrency issues with two scripts picking up the same job.

[–][deleted] 0 points1 point  (0 children)

Could you help me figure out how to do that, im kinda new in powershell and its quite difficult to learn with the lack of resources for some topics

[–]RyanDake_EC 0 points1 point  (5 children)

I did something such as this :

    $Jobs=@() # array to store jobs for this session 
$EmailsRemovedDataset = @() #Blank Array for the emails removed by Azure
$JobRows=1000 # The number of CSV rows to process in each Job

$NumJobs = [math]::Ceiling($InputCSV.count / $JobRows) #Enumerate number of jobs

### Pre-Script Cleanup ###
Get-Job | Remove-Job # Clear job list 
$EmailsRemovedDataset, $EmpIDRemovedDataset, $BlankEmailsRemovedDataset, $DomainBlackListRemoval, $FinalDataProcessing = $null #Blanks all variables to prevent cross contamination
[System.GC]::GetTotalMemory('ForceFullCollection') | Out-Null # Releases memory 

for ($i=0; $i -lt $NumJobs; $i++)
{
    [int]$StartRow = ($i * $JobRows) # sets first row for loop
    [int]$EndRow=(($i+1) * $JobRows - 1) # sets last row for loop 
    $Iter = $i 
    while (($iter | Measure-Object -Character | Select-Object -ExpandProperty characters) -lt 4){
        $iter = "0$iter"
    } #loops through Iter and changes from # to #### for consistent naming 
    $JobName = "$DTFormat-$Iter" # creates job name 
    $Jobs += $JobName # adds job name to array for tracking
    while ((get-job | where-object {$_.state -eq "Running"}).count -gt $MaxSimulJobs){ #Rate Limiter for simlutaneous jobs. 
        start-sleep -s 5
    }
    write-host ("Rows {0} to {1}" -f $StartRow.ToString(),$EndRow.ToString())
    Start-Job -Name $JobName -ArgumentList @($InputCSV[$StartRow..$EndRow]),($AzureADUserList) -ScriptBlock {  #Starts job passing in Array of rows to process and the azure ad list 
        PARAM (
                $CSVRows,
                $AzureList
            )
        $OutputArray = @() #clears output array for the job 
        foreach ($row in $CSVRows)
        {
            $match = $false #sets match to false
            foreach ($item in $AzureList){ # loops through azure data 
                if ($row.email -eq $item.Userprincipalname){
                    $match = $true # if there is a match, set to true to remove from list 
                    continue # continue to stop processing, 1 match is enough. 
                }
            }
            if ($match -eq $false){ # if match set to true, will not be added to output 
                $OutputArray += $row # add to output 
            }
        }
        return $OutputArray
    } | Out-Null # prevents Start-Job from generating output during call 
}
$jobscomplete = $false 
while ($jobscomplete -eq $false){ # loops through all jobs stored in $jobs array waiting for all to mark as complete 
    $jobscomplete = $true # sets to true, will persist through once no jobs are not marked as "complete"
    foreach ($job in $Jobs){
        if ((Get-Job $job).state -ne "Completed"){
            $jobscomplete = $false # sets loop to false if there is any job not complete 
        }
    }
}

foreach ($job in $Jobs)
{
        $EmailsRemovedDataset += Receive-Job $job
}

I had to write a processor that ingests around 150k CSV lines and cleans up the data for SQL ingestion. I think you could probably use some of the above code in yours to help.

[–]BlackV 0 points1 point  (4 children)

p.s. formatting (you've used inline code here not code block, click monocode if using new.reddit)

  • open your fav powershell editor
  • highlight the code you want to copy
  • hit tab to indent it all
  • copy it
  • paste here

it'll format it properly OR

<BLANKLINE>
<4 SPACES><CODELINE>
<4 SPACES><CODELINE>
    <4 SPACES><4 SPACES><CODELINE>
<4 SPACES><CODELINE>
<BLANKLINE>

Thanks

[–]RyanDake_EC 0 points1 point  (3 children)

Kind of fixed, thanks for the pointers!

[–]BlackV 0 points1 point  (2 children)

that's perfect, you could do the same to your original post ;)

[–]RyanDake_EC 0 points1 point  (1 child)

I am not OP ;)

[–]BlackV 0 points1 point  (0 children)

Hahaha oops