-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathUserSessionManagement.psm1
More file actions
514 lines (430 loc) · 16.9 KB
/
UserSessionManagement.psm1
File metadata and controls
514 lines (430 loc) · 16.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
# UserSessionManagement Module
# Provides functions for managing user sessions, logins, and related operations
# Supports Windows 10/11 and PowerShell 5.1+
#region Module Requirements
$requiredPSVersion = '5.1'
$requiredOSVersion = '10.0.0.0'
# Check PowerShell version
if ($PSVersionTable.PSVersion.Major -lt [version]$requiredPSVersion.Split('.')[0] -or
$PSVersionTable.PSVersion.Minor -lt [version]$requiredPSVersion.Split('.')[1]) {
throw "This module requires PowerShell version $requiredPSVersion or higher"
}
# Check OS version
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
if ([version]$osInfo.Version -lt [version]$requiredOSVersion) {
throw "This module requires Windows 10 or higher"
}
#endregion
#region Public Functions
<#
.SYNOPSIS
Gets information about active user sessions on a local or remote computer.
.DESCRIPTION
Retrieves detailed information about user sessions, including logon type, start time,
and session ID. Can filter by username and provide basic or detailed output.
.PARAMETER ComputerName
The name of the computer to query. Defaults to the local computer.
.PARAMETER Username
Optional. Filter sessions by username.
.PARAMETER Detailed
Optional. When specified, returns additional session information including
authentication package and logon server.
.EXAMPLE
Get-UserSessions
Gets basic information about all active user sessions on the local computer.
.EXAMPLE
Get-UserSessions -ComputerName "Server01" -Detailed
Gets detailed information about all active user sessions on Server01.
.EXAMPLE
Get-UserSessions -Username "JohnDoe" -Detailed
Gets detailed information about active sessions for user JohnDoe on the local computer.
.OUTPUTS
System.Management.Automation.PSCustomObject
Returns custom objects containing session information.
.NOTES
Requires administrative privileges for remote computer access.
Logon types 2 (Interactive) and 10 (RemoteInteractive) are considered user sessions.
#>
function Get-UserSessions {
[CmdletBinding()]
param(
[Parameter()]
[string]$ComputerName = $env:COMPUTERNAME,
[Parameter()]
[string]$Username,
[Parameter()]
[switch]$Detailed
)
try {
$sessions = Get-CimInstance -ClassName Win32_LogonSession -ComputerName $ComputerName
if ($Username) {
$sessions = $sessions | Where-Object {
$_.LogonType -in @(2, 10) -and
(Get-CimInstance -ClassName Win32_LoggedOnUser -ComputerName $ComputerName |
Where-Object { $_.Antecedent -like "*$Username*" }).Dependent -contains $_.LogonId
}
}
if ($Detailed) {
return $sessions | ForEach-Object {
$session = $_
$user = Get-CimInstance -ClassName Win32_LoggedOnUser -ComputerName $ComputerName |
Where-Object { $_.Dependent -eq $session.LogonId } |
Select-Object -First 1
[PSCustomObject]@{
'LogonId' = $session.LogonId
'Username' = if ($user) { $user.Antecedent -replace '.*Name="([^"]+)".*', '$1' } else { 'Unknown' }
'LogonType' = switch ($session.LogonType) {
2 { 'Interactive' }
3 { 'Network' }
4 { 'Batch' }
5 { 'Service' }
7 { 'Unlock' }
8 { 'NetworkCleartext' }
9 { 'NewCredentials' }
10 { 'RemoteInteractive' }
11 { 'CachedInteractive' }
default { "Unknown ($($session.LogonType))" }
}
'StartTime' = $session.StartTime
'AuthenticationPackage' = $session.AuthenticationPackage
'LogonServer' = $session.LogonServer
'SessionId' = (Get-CimInstance -ClassName Win32_Process -ComputerName $ComputerName |
Where-Object { $_.SessionId -ne 0 } |
Group-Object SessionId |
Where-Object { $_.Group[0].LogonId -eq $session.LogonId }).Name
}
}
}
else {
return $sessions | ForEach-Object {
$session = $_
$user = Get-CimInstance -ClassName Win32_LoggedOnUser -ComputerName $ComputerName |
Where-Object { $_.Dependent -eq $session.LogonId } |
Select-Object -First 1
[PSCustomObject]@{
'Username' = if ($user) { $user.Antecedent -replace '.*Name="([^"]+)".*', '$1' } else { 'Unknown' }
'LogonType' = switch ($session.LogonType) {
2 { 'Interactive' }
10 { 'RemoteInteractive' }
default { "Other" }
}
'StartTime' = $session.StartTime
'SessionId' = (Get-CimInstance -ClassName Win32_Process -ComputerName $ComputerName |
Where-Object { $_.SessionId -ne 0 } |
Group-Object SessionId |
Where-Object { $_.Group[0].LogonId -eq $session.LogonId }).Name
}
}
}
}
catch {
Write-Warning "Error getting user sessions: $($_.Exception.Message)"
return $null
}
}
<#
.SYNOPSIS
Disconnects user sessions from a local or remote computer.
.DESCRIPTION
Allows disconnection of user sessions either by username or session ID.
Can perform forced disconnection if necessary.
.PARAMETER ComputerName
The name of the computer to target. Defaults to the local computer.
.PARAMETER Username
The username whose sessions should be disconnected.
Cannot be used with SessionId parameter.
.PARAMETER SessionId
The specific session ID to disconnect.
Cannot be used with Username parameter.
.PARAMETER Force
Optional. When specified, forces the session disconnection without user confirmation.
.EXAMPLE
Disconnect-UserSession -Username "JohnDoe"
Disconnects all sessions for user JohnDoe on the local computer.
.EXAMPLE
Disconnect-UserSession -ComputerName "Server01" -SessionId 2 -Force
Forces disconnection of session ID 2 on Server01.
.OUTPUTS
System.Management.Automation.PSCustomObject
Returns an object containing the operation result.
.NOTES
Requires administrative privileges.
Use with caution, especially with the Force parameter.
#>
function Disconnect-UserSession {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$ComputerName = $env:COMPUTERNAME,
[Parameter(Mandatory, ParameterSetName = 'ByUsername')]
[string]$Username,
[Parameter(Mandatory, ParameterSetName = 'BySessionId')]
[int]$SessionId,
[Parameter()]
[switch]$Force
)
try {
if ($Username) {
$sessions = Get-UserSessions -ComputerName $ComputerName -Username $Username
if (-not $sessions) {
throw "No active sessions found for user '$Username'"
}
$sessionIds = $sessions.SessionId | Where-Object { $_ -ne $null }
}
else {
$sessionIds = @($SessionId)
}
foreach ($id in $sessionIds) {
if ($Force) {
$result = Invoke-CimMethod -ClassName Win32_OperatingSystem -MethodName Win32Shutdown -Arguments @{
Flags = 4 # Logoff
Reserved = 0
} -ComputerName $ComputerName
if ($result.ReturnValue -ne 0) {
throw "Failed to force logoff session $id. Return code: $($result.ReturnValue)"
}
}
else {
$result = Invoke-CimMethod -ClassName Win32_OperatingSystem -MethodName Win32Shutdown -Arguments @{
Flags = 0 # Logoff
Reserved = 0
} -ComputerName $ComputerName
if ($result.ReturnValue -ne 0) {
throw "Failed to logoff session $id. Return code: $($result.ReturnValue)"
}
}
}
return [PSCustomObject]@{
'Success' = $true
'SessionsDisconnected' = $sessionIds.Count
'ComputerName' = $ComputerName
}
}
catch {
Write-Warning "Error disconnecting user session: $($_.Exception.Message)"
return $null
}
}
<#
.SYNOPSIS
Retrieves successful logon history from the Security event log.
.DESCRIPTION
Gets information about successful user logons, including logon type,
workstation name, and IP address. Can filter by username and time period.
.PARAMETER ComputerName
The name of the computer to query. Defaults to the local computer.
.PARAMETER Username
Optional. Filter logons by username.
.PARAMETER Days
Optional. Number of days to look back for logon events. Defaults to 30 days.
.EXAMPLE
Get-LastLogon
Gets all successful logons in the last 30 days on the local computer.
.EXAMPLE
Get-LastLogon -Username "JohnDoe" -Days 7
Gets successful logons for user JohnDoe in the last 7 days.
.EXAMPLE
Get-LastLogon -ComputerName "Server01" -Days 90
Gets all successful logons in the last 90 days on Server01.
.OUTPUTS
System.Management.Automation.PSCustomObject
Returns custom objects containing logon information.
.NOTES
Requires administrative privileges for remote computer access.
Requires Security event log access.
#>
function Get-LastLogon {
[CmdletBinding()]
param(
[Parameter()]
[string]$ComputerName = $env:COMPUTERNAME,
[Parameter()]
[string]$Username,
[Parameter()]
[int]$Days = 30
)
try {
$cutoffDate = (Get-Date).AddDays(-$Days)
$events = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
ID = 4624 # Successful logon
StartTime = $cutoffDate
} -ComputerName $ComputerName -ErrorAction SilentlyContinue
if ($Username) {
$events = $events | Where-Object {
$_.Properties[5].Value -like "*$Username*" -or
$_.Properties[1].Value -like "*$Username*"
}
}
return $events | ForEach-Object {
[PSCustomObject]@{
'Username' = $_.Properties[5].Value
'Domain' = $_.Properties[6].Value
'LogonType' = switch ($_.Properties[10].Value) {
2 { 'Interactive' }
3 { 'Network' }
4 { 'Batch' }
5 { 'Service' }
7 { 'Unlock' }
8 { 'NetworkCleartext' }
9 { 'NewCredentials' }
10 { 'RemoteInteractive' }
11 { 'CachedInteractive' }
default { "Unknown ($($_.Properties[10].Value))" }
}
'LogonTime' = $_.TimeCreated
'WorkstationName' = $_.Properties[13].Value
'IPAddress' = $_.Properties[18].Value
}
} | Sort-Object -Property LogonTime -Descending
}
catch {
Write-Warning "Error getting last logon information: $($_.Exception.Message)"
return $null
}
}
<#
.SYNOPSIS
Retrieves failed logon attempts from the Security event log.
.DESCRIPTION
Gets information about failed logon attempts, including failure reason,
workstation name, and IP address. Can filter by username and time period.
.PARAMETER ComputerName
The name of the computer to query. Defaults to the local computer.
.PARAMETER Username
Optional. Filter failed logons by username.
.PARAMETER Hours
Optional. Number of hours to look back for failed logon events. Defaults to 24 hours.
.EXAMPLE
Get-FailedLogons
Gets all failed logon attempts in the last 24 hours on the local computer.
.EXAMPLE
Get-FailedLogons -Username "JohnDoe" -Hours 48
Gets failed logon attempts for user JohnDoe in the last 48 hours.
.EXAMPLE
Get-FailedLogons -ComputerName "Server01"
Gets all failed logon attempts in the last 24 hours on Server01.
.OUTPUTS
System.Management.Automation.PSCustomObject
Returns custom objects containing failed logon information.
.NOTES
Requires administrative privileges for remote computer access.
Requires Security event log access.
Failure reasons are translated from Windows error codes to human-readable messages.
#>
function Get-FailedLogons {
[CmdletBinding()]
param(
[Parameter()]
[string]$ComputerName = $env:COMPUTERNAME,
[Parameter()]
[string]$Username,
[Parameter()]
[int]$Hours = 24
)
try {
$cutoffDate = (Get-Date).AddHours(-$Hours)
$events = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
ID = 4625 # Failed logon
StartTime = $cutoffDate
} -ComputerName $ComputerName -ErrorAction SilentlyContinue
if ($Username) {
$events = $events | Where-Object {
$_.Properties[5].Value -like "*$Username*" -or
$_.Properties[1].Value -like "*$Username*"
}
}
return $events | ForEach-Object {
[PSCustomObject]@{
'Username' = $_.Properties[5].Value
'Domain' = $_.Properties[6].Value
'FailureReason' = switch ($_.Properties[8].Value) {
0xC0000064 { 'Unknown username or bad password' }
0xC000006A { 'Bad password' }
0xC000006C { 'Password expired' }
0xC000006D { 'Account disabled' }
0xC000006E { 'Account locked out' }
0xC000006F { 'Account expired' }
0xC0000070 { 'Logon type not granted' }
0xC0000071 { 'Account restricted' }
0xC0000072 { 'Time restriction' }
default { "Unknown ($($_.Properties[8].Value))" }
}
'FailureTime' = $_.TimeCreated
'WorkstationName' = $_.Properties[13].Value
'IPAddress' = $_.Properties[19].Value
}
} | Sort-Object -Property FailureTime -Descending
}
catch {
Write-Warning "Error getting failed logon information: $($_.Exception.Message)"
return $null
}
}
<#
.SYNOPSIS
Retrieves information about locked user accounts.
.DESCRIPTION
Gets detailed information about locked user accounts, including account status,
password settings, and account properties. Can filter by username.
.PARAMETER ComputerName
The name of the computer to query. Defaults to the local computer.
.PARAMETER Username
Optional. Filter locked accounts by username.
.EXAMPLE
Get-LockedAccounts
Gets all locked accounts on the local computer.
.EXAMPLE
Get-LockedAccounts -Username "JohnDoe"
Gets locked account information for user JohnDoe.
.EXAMPLE
Get-LockedAccounts -ComputerName "Server01"
Gets all locked accounts on Server01.
.OUTPUTS
System.Management.Automation.PSCustomObject
Returns custom objects containing account information.
.NOTES
Requires administrative privileges for remote computer access.
Works with both local and domain accounts.
#>
function Get-LockedAccounts {
[CmdletBinding()]
param(
[Parameter()]
[string]$ComputerName = $env:COMPUTERNAME,
[Parameter()]
[string]$Username
)
try {
$accounts = Get-CimInstance -ClassName Win32_UserAccount -ComputerName $ComputerName |
Where-Object { $_.Lockout -eq $true }
if ($Username) {
$accounts = $accounts | Where-Object { $_.Name -like "*$Username*" }
}
return $accounts | ForEach-Object {
[PSCustomObject]@{
'Username' = $_.Name
'Domain' = $_.Domain
'FullName' = $_.FullName
'Description' = $_.Description
'Disabled' = $_.Disabled
'Lockout' = $_.Lockout
'PasswordRequired' = $_.PasswordRequired
'PasswordChangeable' = $_.PasswordChangeable
'PasswordExpires' = $_.PasswordExpires
}
}
}
catch {
Write-Warning "Error getting locked accounts: $($_.Exception.Message)"
return $null
}
}
Export-ModuleMember -Function @(
'Get-UserSessions',
'Disconnect-UserSession',
'Get-LastLogon',
'Get-FailedLogons',
'Get-LockedAccounts'
)