Script causes ISE to crash

I downloaded the Get-NetSession.ps1 script from the TechNet Script Center Gallery, (Browse code samples | Microsoft Docs) but I needed the number of open files, so I substituted SESSION_INFO_10 for SESSION_INFO_1 and defined the two extra fields. It runs and returns the open files, but it crashes ISE right after that.

I added code to get the user DisplayName, Telephone and Extension. Also added code to format the SessionTime and IdleTime. Still need to add code to display the OpenFiles correctly.

Does anyone have any ideas why its crashing ISE?

Running on a Windows 10 Enterprise Edition workstation.

Thanks.

Function Get-NetSession {
<#
.SYNOPSIS
Queries the remote system for all net sessions

.DESCRIPTION
Queries the remote system for all net sessions

.PARAMETER Computername
Computer to query for net sessions

.PARAMETER Username
Specifies a user to look for in the net sessions

.PARAMETER IncludeSelf
Includes the current user session used to run this command

.NOTES
Name: Get-NetSession
Author: Boe Prox
Version History:
1.1 //Boe Prox - 1 August 2016
- Added IncludeSelf parameter to include displaying the session created from command otherwise
this data is not presented
- Bug fixes

1.0 //Boe Prox - 28 July 2016
- Initial build

.EXAMPLE
Get-NetSession -Computername Server1

Computername : Server1
SourceComputer : Workstation1
SourceIPAddress : 192.168.2.56
Username : bobsmith
SessionTime : 0
IdleTime : 0

Computername : Server1
SourceComputer : Workstation2
SourceIPAddress : 192.168.2.110
Username : joeuser
SessionTime : 348607
IdleTime : 345850

Description
-----------
Returns all net sessions on Server1
#>
[cmdletbinding()]
Param (
[parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[string[]]$Computername,
[parameter()]
[string]$Username = '',
[parameter()]
[switch]$IncludeSelf
)
Begin {
If ($PSBoundParameters.ContainsKey('Debug')) {
$DebugPreference = 'Continue'
}
If (-NOT $PSBoundParameters.ContainsKey('IncludeSelf')) {
$Hostname = "$($env:COMPUTERNAME).$($env:USERDNSDOMAIN)"
Write-Verbose "Excluding $Hostname and $($env:USERNAME)"
}
#region Reflection
Try {
[void][Net.Session]
} 
Catch {
Write-Verbose "Building pinvoke via reflection"
#region Module Builder
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('NetSession')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) # Only run in memory
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('NetSessionModule', $False)
#endregion Module Builder

#region Custom Attribute Builder
$ctor = [System.Runtime.InteropServices.MarshalAsAttribute].GetConstructor(@([System.Runtime.InteropServices.UnmanagedType]))
$CustomAttribute = [System.Runtime.InteropServices.UnmanagedType]::LPWStr
$CustomAttributeBuilder = New-Object System.Reflection.Emit.CustomAttributeBuilder -ArgumentList $ctor, $CustomAttribute
#endregion Custom Attribute Builder

#region Struct
#region SESSION_INFO_1
$Attributes = 'AutoLayout, AnsiClass, Class, Public, SequentialLayout, Sealed, BeforeFieldInit'
$STRUCT_TypeBuilder = $ModuleBuilder.DefineType('SESSION_INFO_1', $Attributes, [System.ValueType], 8, 0x0)
$Field = $STRUCT_TypeBuilder.DefineField('OriginatingHost', [string], 'Public')
$Field.SetCustomAttribute($CustomAttributeBuilder)
$Field = $STRUCT_TypeBuilder.DefineField('DomainUser', [string], 'Public')
$Field.SetCustomAttribute($CustomAttributeBuilder)
[void]$STRUCT_TypeBuilder.DefineField('OpenFiles', [uint32], 'Public')
[void]$STRUCT_TypeBuilder.DefineField('SessionTime', [uint32], 'Public')
[void]$STRUCT_TypeBuilder.DefineField('IdleTime', [uint32], 'Public')
[void]$STRUCT_TypeBuilder.DefineField('UserFlags', [uint32], 'Public')
[void]$STRUCT_TypeBuilder.CreateType()
#endregion SESSION_INFO_1
#endregion Struct

$TypeBuilder = $ModuleBuilder.DefineType('Net.Session', 'Public, Class')

#region Methods
#region NetSessionEnum Method
$PInvokeMethod = $TypeBuilder.DefineMethod(
'NetSessionEnum', #Method Name
[Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes
[int32], #Method Return Type
[Type[]] @(
[string],
[string],
[string],
[int32],
[intptr].MakeByRefType(),
[int],
[int32].MakeByRefType(),
[int32].MakeByRefType(),
[int32].MakeByRefType()
) #Method Parameters
)

#Define first three parameters with custom attributes
1..3 | ForEach {
$Parameter = $PInvokeMethod.DefineParameter(
$_,
[System.Reflection.ParameterAttributes]::In,
$Null
)
$Parameter.SetCustomAttribute(
$CustomAttributeBuilder
)
}

$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
$FieldArray = [Reflection.FieldInfo[]] @(
[Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
[Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
[Runtime.InteropServices.DllImportAttribute].GetField('ExactSpelling')
[Runtime.InteropServices.DllImportAttribute].GetField('PreserveSig')
)

$FieldValueArray = [Object[]] @(
'NetSessionEnum', #CASE SENSITIVE!!
$True,
$True,
$True
)

$CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
$DllImportConstructor,
@('Netapi32.dll'),
$FieldArray,
$FieldValueArray
)

$PInvokeMethod.SetCustomAttribute($CustomAttribute)
#endregion NetSessionEnum Method
#region NetApiBufferFree Method
$PInvokeMethod = $TypeBuilder.DefineMethod(
'NetApiBufferFree', #Method Name
[Reflection.MethodAttributes] 'PrivateScope, Public, Static, HideBySig, PinvokeImpl', #Method Attributes
[int], #Method Return Type
[Type[]] @(
[intptr]
) #Method Parameters
)

$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
$FieldArray = [Reflection.FieldInfo[]] @(
[Runtime.InteropServices.DllImportAttribute].GetField('EntryPoint'),
[Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
[Runtime.InteropServices.DllImportAttribute].GetField('ExactSpelling')
[Runtime.InteropServices.DllImportAttribute].GetField('PreserveSig')
)

$FieldValueArray = [Object[]] @(
'NetApiBufferFree', #CASE SENSITIVE!!
$True,
$True,
$True
)

$CustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
$DllImportConstructor,
@('Netapi32.dll'),
$FieldArray,
$FieldValueArray
)

$PInvokeMethod.SetCustomAttribute($CustomAttribute)
#endregion NetApiBufferFree Method
#endregion Methods

[void]$TypeBuilder.CreateType()
}
#endregion Reflection

}
Process {
ForEach ($Computer in $Computername) {
Write-Verbose "Scanning $Computer"
$SessionInfo1 = New-Object -TypeName SESSION_INFO_1
$SessionInfo1Size = [System.Runtime.InteropServices.Marshal]::SizeOf($SessionInfo1)
$Buffer = [IntPtr]::Zero
[int32]$EntriesRead = 0
[int32]$TotalEntries = 0
[int32]$ResumeHandle = 0
$Return = [Net.Session]::NetSessionEnum(
$Computer, 
"", 
$Username, 
10, 
[ref]$Buffer, 
-1, 
[ref]$EntriesRead, 
[ref]$TotalEntries, 
[ref]$ResumeHandle
)
$LastError = [ComponentModel.Win32Exception][Runtime.InteropServices.Marshal]::GetLastWin32Error()

If ([System.IntPtr]::Size -eq 4) {
$BufferOffset = $Buffer.ToInt32()
}
Else {
$BufferOffset = $Buffer.ToInt64()
}

For ($Count = 0; ($Count -lt $EntriesRead); $Count++){
$NewBuffer = New-Object System.Intptr -ArgumentList $BufferOffset
$Info = [System.Runtime.Interopservices.Marshal]::PtrToStructure($NewBuffer,[type]$SessionInfo1.GetType())
$Info | ForEach { 
$IP = $_.OriginatingHost.Trim('\\')
Try {
$ResolvedName = [Net.DNS]::GetHostByAddress($IP).HostName
}
Catch {
$ResolvedName = 'N/A'
}
$Object = [pscustomobject]@{
Computername = $Computer
SourceComputer = $ResolvedName
SourceIPAddress = $IP
Username = $_.DomainUser
DisplayName = (Get-ADUser -Identity $_.DomainUser -Properties displayname).displayname
Telephone = (Get-ADUser -Identity $_.DomainUser -Properties telephoneNumber).telephoneNumber
Extension = (Get-ADUser -Identity $_.DomainUser -Properties extensionAttribute3).extensionAttribute3
OpenFiles = "$($_.OpenFiles)" ## Added to script ##
SessionTime = [TimeSpan]::FromSeconds($_.SessionTime).ToString('hh\:mm\:ss')
IdleTime = [TimeSpan]::FromSeconds($_.IdleTime).ToString('hh\:mm\:ss')
}
$Object.pstypenames.insert(0,'Net.SessionInformation')
If (($PSBoundParameters.ContainsKey('IncludeSelf'))) { 
$Object

} 
ElseIf (-NOT ((($ResolvedName -eq $Hostname) -OR ($IP -eq $env:COMPUTERNAME)) -AND ($_.DomainUser -eq $env:USERNAME))) {
$Object
}
}
$BufferOffset = $BufferOffset + $SessionInfo1Size
}

[void][Net.Session]::NetApiBufferFree($Buffer)
}
}
End {}
}

PowerShell ISE is deprecated. Development of the ISE ended along with development of Windows PowerShell (v5.1), which was dropped in favor of the open-source PowerShell Core in 2017. No one is working on it; the problems with it won’t be fixed.

Additionally, the PowerShell ISE console is not a ‘real’ console, but is effectively an emulation of a console running inside a Win32 application (it’s fake). There are significant execution differences between the ISE console and actual PowerShell, which are now amplified by the differences between Windows PowerShell and PowerShell Core, and three more years of development.

So, ISE is not a valid test environment. You should test your scripts against the version of PowerShell that you have installed on your system, in a development environment. VSCode is the recommended development tool.

I do have VSCode installed on my workstation, but since I started with ISE and don’t code as often as I wish, it’s my fallback.

Let me try to run the script in VSCode.

Also, like I said I don’t code often enough, I still haven’t figured out how to display the OpenFiles correctly. It reports 37434 files open, when the user only has 2 files open. Any help would be appreciated.

Thanks,