none
Problem with powershell script multithreading - nothing returned RRS feed

  • Question

  •   [cmdletBinding()]
      param(
         [Parameter(
            ParameterSetName='Users',
             Position=0,
             ValueFromPipeLineByPropertyName=$true,
             ValueFromPipeLine=$true,
             Mandatory=$true
         )]
         [string[]]$Users,
    
         [Parameter(
             ParameterSetName='Division',
             Mandatory=$true
         )]
         [string]$Division
     
        
         
     )
        begin{
                $id = "12345"
                $roledefinitions = @{}
                Get-AzureADMSPrivilegedRoleDefinition -ProviderId "aadRoles" -ResourceId $id | ForEach-Object {$roledefinitions[$_.Id] = $_.DisplayName}
                [bool]$isactive | Out-Null
                
                $pimusers=@()
        }
            
         process{
    
                        function GetPimInformation()
                        {
    
                        Param(
                            [Microsoft.Open.AzureAD.Model.User]$user
                            
    
    
                        )
                            $report=@()
                            foreach($user in $users)
                            {
                                
                                $obj = $user.objectId
                                $roleassignments = Get-AzureADMSPrivilegedRoleAssignment -ProviderId "aadRoles" -ResourceId "12345" -Filter "subjectId eq '$obj'" 
                                Write-Host "in the runspace"
                               # Write-Host "$user"
                                
                                foreach($roleassignment in $roleassignments)
                                    {
                                        if($roleassignment.LinkedEligibleRoleAssignmentId)
                                        {
                                        $isactive=$true 
                                        } 
                                        else
                                        {
                                        $isactive=$false
                                        }
    
                                        $rolename =   $roledefinitions[$roleassignment.RoleDefinitionId]
                                        write-host "test"
                                            
                                            $pimobject = New-Object PSCustomObject
                                            $pimobject | Add-Member NoteProperty User $user.DisplayName
                                            $pimobject | Add-Member NoteProperty RoleName $rolename
                                            $pimobject | Add-Member NoteProperty RoleCurrentlyActive $isactive
                                            $pimobject | Add-Member NoteProperty RoleAssignment $roleassignment.AssignmentState
                                            $report += $pimobject
                                    }
                                    
                            }
                           return $report
                           # $report | Export-Csv pimreport.csv -NoTypeInformation
                            
                        }
    
    
                    if($division)
                    {
    
                        $jobs=@()
                        $Sessionstate = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
                        $Sessionstate.Variables.Add((New-object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'roledefinitions', $roledefinitions,$null))
                        $RunspacePool = [RunspaceFactory]::CreateRunspacePool(1,5,$Sessionstate,$Host)
                        $RunspacePool.ApartmentState = "STA"
                        $RunspacePool.Open()
    
    
                        [Microsoft.Open.AzureAD.Model.User[]]$users = Get-AzureADUser -Filter "extension_12345_extensionAttribute14 eq '$division' and AccountEnabled eq true" -Top 7
                        foreach($user in $users){
                        $ScriptBlock = [scriptblock]::Create((Get-ChildItem Function:\GetPimInformation).Definition)
                        $PowershellThread = [powershell]::Create().AddScript($ScriptBlock)
                        $PowershellThread.AddArgument($user)| Out-Null
         
                        $PowershellThread.RunspacePool = $RunspacePool
                        $Handle = $PowershellThread.BeginInvoke()
    
                        $job = "" | Select-Object Handle,Thread,Object
                        $job.Handle = $Handle
                        $job.Thread = $PowershellThread
                        $job.Object = $user
                        $jobs += $job
                        $report=@()
                        While (@($Jobs | Where-Object {$_.Handle -ne $Null}).count -gt 0) {
                        ForEach ($Job in $($Jobs | Where-Object {$_.Handle.IsCompleted -eq $True})){
                      $report += $Job.Thread.EndInvoke($Job.Handle)
                        $Job.Thread.Dispose()
                        $Job.Thread = $Null
                        $Job.Handle = $Null
    
                            }
    
                        }
                   } 
                    $report
                        #$report | Export-Csv pimreport.csv -NoTypeInformation 
                    }
                    elseif($users)
                    {
                        foreach($userobject in $users)
                        {
                            $userinfo = Get-AzureADUser -ObjectId $userobject
                            $pimusers += $userinfo
                        }
                        GetPimInformation($pimusers)
                               
                    }
                   
               
    
                
            }       
    


    • Edited by nickkinn Monday, April 6, 2020 9:36 AM
    Monday, April 6, 2020 8:47 AM

Answers

  • Thanks for your input - I eventually did manage to get it working with the runspaces - there were a lot of syntax errors - thanks
    • Marked as answer by nickkinn Saturday, April 18, 2020 10:56 AM
    Saturday, April 18, 2020 10:56 AM

All replies

  • Before we can help you you will need to edit your post and post the code correctly.


    \_(ツ)_/

    Monday, April 6, 2020 9:01 AM
  • Hi there- I have done that
    Monday, April 6, 2020 9:37 AM
  • Thank you.

    Your code appears to have been written by three different people with three different understandings of PowerShell.  This is usually because someone has copied pieces of code and glued them together with0ou0t understanding the code.

    There are numerous syntax errors and logic errors in the code.  Because of that it is not easy to figure out what you are trying to do.

    When learning PowerShell you should avoid advanced methods like runspaces.  They require a significant technical skill in programming in a multi-threaded system.

    I recommend just using PowerShell "jobs.  They are easier to create and easier to debug.

    Write you code to do one user then add a job for each user in a loop.  This makes testing simple.  Just get one user to work and then create one job using that user and check the results.  Once you have that then just loop through ll users and then wait on all jobs until doen and collect the results.

    $jobs = <loop to create jobs>
    $jobs | Wait-Job | Receive-Job

    help about_jobs

    That is all you need.

    The other method is to use a workflow whi9ch allows a simple setup to create multiple parallel operations with easy syntax.

    help about_workflows


    \_(ツ)_/

    Monday, April 6, 2020 10:27 AM
  • Hi there

    the actual PIM function is written by myself and works fine for a user or an array of users - the multithreading part I have adapted from online blogs etc but they pretty much all use similar sort of syntax - I have a small understanding of how multithreading works - I am thinking that it is to do with the variables and the hashtable I create in the begin block to create the roledefinitions mapping and how they are passed to the runspace


    • Edited by nickkinn Monday, April 6, 2020 10:39 AM
    Monday, April 6, 2020 10:39 AM
  • Again.  You have too many syntax and design errors in the code.  Please use the function with jobs and your issues will go away.  There is no need here for runspaces so why make this harder for your self.

    I will point out a couple os simple issue.

    The "begin" block of a script is where we define all variables, functions and script blocks that are global to the script.  You are defining things all over the place which will cause scope issue.

    To break down a set of parameters set we would use a "switch" statement:

        switch($PSCmdlet.ParameterSetName){
            Division {
                # code
            }
            
            Users {
                # code
            }
        }
    

    There are at least another dozen issues but I am not going to rewrite your code.  Just use jobs and forget about making things more complicated.


    \_(ツ)_/

    Monday, April 6, 2020 11:15 AM
  • Thanks for your input - I eventually did manage to get it working with the runspaces - there were a lot of syntax errors - thanks
    • Marked as answer by nickkinn Saturday, April 18, 2020 10:56 AM
    Saturday, April 18, 2020 10:56 AM