Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CimSession created inside Start-ThreadJob is correctly received after Job is over but the object is disposed #21447

Open
5 tasks done
trykert opened this issue Apr 8, 2024 · 0 comments
Labels
Needs-Triage The issue is new and needs to be triaged by a work group.

Comments

@trykert
Copy link

trykert commented Apr 8, 2024

Prerequisites

Steps to reproduce

I searched for similar issues, but since I'm new to PowerShell (and programming in general) I might have missed a result with similar names, so sorry if that's the case.

I'm trying to get some info from computers in my AD Domain (15k computers), and I'm using New-CimSession and Get-Ciminstance to do that. Unfortunately I'm restricted to the DCOM protocol, so I can't use PSSession.

I did some speed tests and found out that New-CimSession is fast, and if I put it inside a Start-ThreadJob it's just as fast, with the added benefit of a throttle. Sometimes it seems New-CimSession creates less sessions than it should, which I believe is a throughput issue, so ThrottleLimit seems to fix that.

Anyway, my code.
First, I get a list of computers from AD with Get-ADComputer (not in the script below), $PCList, then I use Test-Connection in a ForEach-Object parallel to see if they are online, $Results, then I use that list to create the sessions. I reduced the results down to 5 to make it easier to test.

Write-Host "Testing Connection with $($PCList.count) computers"
$PCList | ForEach-Object -parallel {Test-Connection $_ -Count 1 -TimeoutSeconds 1} -AsJob -ThrottleLimit 500
$PCsOn = (Get-Job -IncludeChildJob | Where-Object {$_.Command -match "Test-Connection"}).Name
$Results = Receive-Job -Wait -Name $PCsOn -ErrorAction 'SilentlyContinue' | Where-Object {$_.Status -match "Success"} | Select-Object Destination -ExpandProperty Destination

#Sets up multiple CIM sessions

Write-Host "Creating a CIM session with $($Results.count) computers"
$computername = $Results | Select -First 5
$option = New-CimSessionOption -Protocol Dcom

$test1 = Start-ThreadJob -ScriptBlock {param($computername,$option) New-CimSession -ComputerName $computername -SessionOption $option -OperationTimeoutSec 15 -ErrorAction 'SilentlyContinue' }  -ArgumentList $computername,$option -ThrottleLimit 500 | Wait-Job | Receive-Job

Get-CimInstance -CimSession $test1 -Class Win32_SystemUsers -Property GroupComponent,PartComponent -OperationTimeoutSec 15 -ErrorAction 'SilentlyContinue' | Select-Object @{Name="ComputerName"; Expression={[regex]::Match($_.GroupComponent, '".+?"').Value -replace '"', ''}}, @{Name="UserAccount"; Expression={[regex]::Match($_.PartComponent, '".+?"').Value -replace '"', ''}},@{Name="QueryDate";Expression={Get-Date -Format "yyyy-MM-dd"}} | Where-Object {$_.UserAccount -notmatch "(some_users)"}

That is when I get an error,

Get-CimInstance: Cannot access a disposed object.
Object name: 'CimSession: XXXXX1'.

If I try to get the CimSession, nothing appears.

Edit for clarity: when I type $test1 in the powershell, I get back the list of the CimSessions, but they give the error above when I try to use them.
If I type Get-CimSession, nothing appears.
I believe this is because Start-ThreadJob runs the code in a separate instance, but then shouldn't it return no objects as they are all disposed?

Meanwhile, if I run the above code with $test2:

$test2 = New-CimSession -ComputerName $computername -SessionOption $option -OperationTimeoutSec 15 -ErrorAction 'SilentlyContinue'

Get-CimInstance -CimSession $test2 -Class Win32_SystemUsers -Property GroupComponent,PartComponent -OperationTimeoutSec 15 -ErrorAction 'SilentlyContinue' | Select-Object @{Name="ComputerName"; Expression={[regex]::Match($_.GroupComponent, '".+?"').Value -replace '"', ''}}, @{Name="UserAccount"; Expression={[regex]::Match($_.PartComponent, '".+?"').Value -replace '"', ''}},@{Name="QueryDate";Expression={Get-Date -Format "yyyy-MM-dd"}} | Where-Object {$_.UserAccount -notmatch "(some_users)"}

I get the correct result (Table with ComputerName, UserAccount, QueryDate).

I tested doing the Get-CimInstance query INSIDE the threadjob, and it works. The code looks like this:

$test1 = Start-ThreadJob -ScriptBlock {param($computername,$option) New-CimSession -ComputerName $computername -SessionOption $option -OperationTimeoutSec 15 -ErrorAction 'SilentlyContinue' | Get-CimInstance -Class Win32_SystemUsers -Property GroupComponent,PartComponent -OperationTimeoutSec 15 -ErrorAction 'SilentlyContinue' | Select-Object @{Name="ComputerName"; Expression={[regex]::Match($_.GroupComponent, '".+?"').Value -replace '"', ''}}, @{Name="UserAccount"; Expression={[regex]::Match($_.PartComponent, '".+?"').Value -replace '"', ''}},@{Name="QueryDate";Expression={Get-Date -Format "yyyy-MM-dd"}} | Where-Object {$_.UserAccount -notmatch "(some_users)"}}  -ArgumentList $computername,$option -ThrottleLimit 500 | Wait-Job | Receive-Job | Select -First 5

However, since I'm reusing the CimSessions for other Win32 Class queries, this would not be ideal.
For now, I'm sticking with using $test2 method, but I figured it might be niche enough to mention.

Expected behavior

ComputerName    UserAccount QueryDate
------------    ----------- ---------
XXXXX1             UUUUUU     2024-04-08
XXXXX2             UUUUUU     2024-04-08
XXXXX3             UUUUUU     2024-04-08
XXXXX4             UUUUUU     2024-04-08

Actual behavior

Get-CimInstance: Cannot access a disposed object.
Object name: 'CimSession: XXXXX1'.

Error details

Exception             :
    Type       : System.ObjectDisposedException
    Message    : Cannot access a disposed object.
                 Object name: 'CimSession: XXXXX1'.
    ObjectName : CimSession: XXXXX1
    TargetSite :
        Name          : AssertNotDisposed
        DeclaringType : CimSession
        MemberType    : Method
        Module        : Microsoft.Management.Infrastructure.dll
    Source     : Microsoft.Management.Infrastructure
    HResult    : -2146232798
    StackTrace :
   at Microsoft.Management.Infrastructure.CimSession.AssertNotDisposed()
   at Microsoft.Management.Infrastructure.CimSession.QueryInstancesAsync(String namespaceName, String queryDialect, String queryExpression, CimOperationOptions options)
   at Microsoft.Management.Infrastructure.CimCmdlets.CimSessionProxy.QueryInstancesAsync(String namespaceName, String queryDialect, String queryExpression)
   at Microsoft.Management.Infrastructure.CimCmdlets.CimGetInstance.GetCimInstanceInternal(CimBaseCommand cmdlet)
   at Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand.ProcessRecord()
   at System.Management.Automation.CommandProcessor.ProcessRecord()
CategoryInfo          : NotSpecified: (:) [Get-CimInstance], ObjectDisposedException
FullyQualifiedErrorId : System.ObjectDisposedException,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
InvocationInfo        :
    MyCommand        : Get-CimInstance
    ScriptLineNumber : 1
    OffsetInLine     : 1
    HistoryId        : 121
    Line             : Get-CimInstance -CimSession $test1 -Class Win32_SystemUsers -Property GroupComponent,PartComponent -OperationTimeoutSec 15 -ErrorAction
'SilentlyContinue' | Select-Object @{Name="ComputerName"; Expression={[regex]::Match($_.GroupComponent, '".+?"').Value -replace '"', ''}}, @{Name="UserAccount";
Expression={[regex]::Match($_.PartComponent, '".+?"').Value -replace '"', ''}},@{Name="QueryDate";Expression={Get-Date -Format "yyyy-MM-dd"}} | Where-Object
{$_.UserAccount -notmatch "(some_users)"}
    Statement        : Get-CimInstance -CimSession $test1 -Class Win32_SystemUsers -Property GroupComponent,PartComponent -OperationTimeoutSec 15 -ErrorAction
'SilentlyContinue'
    PositionMessage  : At line:1 char:1
                       + Get-CimInstance -CimSession $test1 -Class Win32_SystemUsers -Property …
                       + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    InvocationName   : Get-CimInstance
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1

Environment data

Name                           Value
----                           -----
PSVersion                      7.4.1
PSEdition                      Core
GitCommitId                    7.4.1
OS                             Microsoft Windows 10.0.19045
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

@trykert trykert added the Needs-Triage The issue is new and needs to be triaged by a work group. label Apr 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs-Triage The issue is new and needs to be triaged by a work group.
Projects
None yet
Development

No branches or pull requests

1 participant