|
$GLOBAL_USER_NAME = "PII\Administrator" # Not case sensitive |
|
$GLOBAL_REMOVE_DIR = "C:\temp" |
|
|
|
<# |
|
.SYNOPSIS |
|
|
|
Get's a full list of users that are currently logged |
|
into a system. |
|
.DESCRIPTION |
|
|
|
Leverages WMI calls to extract user and session details |
|
|
|
.PARAMETER UserName |
|
|
|
(Optional) The name of the user account 'COMPUTER\USERNAME' to filter for. |
|
|
|
.EXAMPLE |
|
|
|
PS> Get-LoggedOnUser |
|
|
|
Session : 4039626 |
|
User : PII\lukem |
|
Type : Interactive |
|
Auth : NTLM |
|
StartTime : 3/30/2016 6:04:00 PM |
|
|
|
Session : 4039597 |
|
User : PII\GeorgeT |
|
Type : Interactive |
|
Auth : NTLM |
|
StartTime : 3/30/2016 6:20:00 PM |
|
|
|
.EXAMPLE |
|
|
|
PS> Get-LoggedOnUser -UserName "PII\lukem" |
|
|
|
Session : 4039626 |
|
User : PII\lukem |
|
Type : Interactive |
|
Auth : NTLM |
|
StartTime : 3/30/2016 6:04:00 PM |
|
|
|
.NOTES |
|
Function Name : Get-LoggedOnUser |
|
Author : Luke Muccillo luke@lukemuccillo.com |
|
Requires : PowerShell V2 |
|
|
|
Call this function whenever you need to pull a list of users from a windows machine. |
|
NB// I never tested this script in a domain environment so YMMV. |
|
#> |
|
function Get-LoggedOnUser { |
|
|
|
param ( |
|
[string]$UserName |
|
) |
|
|
|
$regExAntecent = '.+Domain="(.+)",Name="(.+)"$' |
|
$regExDependent = '.+LogonId="(\d+)"$' |
|
|
|
$logontypes = @{ |
|
"0"="Local System" |
|
"2"="Interactive" #(Local logon) |
|
"3"="Network" # (Remote logon) |
|
"4"="Batch" # (Scheduled task) |
|
"5"="Service" # (Service account logon) |
|
"7"="Unlock" #(Screen saver) |
|
"8"="NetworkCleartext" # (Cleartext network logon) |
|
"9"="NewCredentials" #(RunAs using alternate credentials) |
|
"10"="RemoteInteractive" #(RDP\TS\RemoteAssistance) |
|
"11"="CachedInteractive" #(Local w\cached credentials) |
|
} |
|
|
|
$loggedOnUsers = @(Get-WmiObject -Class Win32_LoggedOnUser) |
|
$logonSessions = @(Get-WmiObject -Class Win32_LogonSession) |
|
|
|
$sessionUserMap = @{} |
|
|
|
foreach ($loggedOnUser in $loggedOnUsers) { |
|
|
|
$loggedOnUser.antecedent -match $regExAntecent > $nul |
|
# Name Value |
|
# ---- ----- |
|
# 2 lukem |
|
# 1 PII |
|
# 0 \\.\root\cimv2:Win32_Account.Domain="PII",Name="lukem" |
|
$loggedOnUserName = $matches[1] + "\" + $matches[2] |
|
|
|
$loggedOnUser.dependent -match $regExDependent > $nul |
|
# Name Value |
|
# ---- ----- |
|
# 1 4039626 |
|
# 0 \\.\root\cimv2:Win32_LogonSession.LogonId="4039626" |
|
$session = $matches[1] |
|
|
|
$sessionUserMap[$session] += $loggedOnUserName |
|
|
|
} |
|
|
|
$allSessionObjects = @() |
|
foreach ($logonSession in $logonSessions) { |
|
|
|
$loggedOnUserName = $sessionUserMap[$logonSession.LogonId] |
|
$logonType = $logonTypes[$logonSession.LogonType.ToString()] |
|
$authPackage = $logonSession.Authenticationpackage |
|
$startTime = [Management.ManagementDateTimeConverter]::ToDateTime($logonSession.StartTime) |
|
|
|
$o = New-Object -TypeName PSObject |
|
$o | Add-Member -MemberType NoteProperty -Name "Session" -Value $logonSession.LogonId |
|
$o | Add-Member -MemberType NoteProperty -Name "UserName" -Value $loggedOnUserName |
|
$o | Add-Member -MemberType NoteProperty -Name "Type" -Value $logonType |
|
$o | Add-Member -MemberType NoteProperty -Name "Auth" -Value $authPackage |
|
$o | Add-Member -MemberType NoteProperty -Name "StartTime" -Value $startTime |
|
|
|
$allSessionObjects += $o |
|
} |
|
|
|
if (-not [string]::IsNullOrEmpty($UserName)) { |
|
|
|
return $allSessionObjects | Where { $_.UserName -ieq $UserName } |
|
} |
|
|
|
return $allSessionObjects |
|
} |
|
|
|
<# |
|
.SYNOPSIS |
|
|
|
Checks to see if a user (COMPUTER\USERNAME) is logged in and, if the user is not logged |
|
in, executes a script block. |
|
|
|
.DESCRIPTION |
|
|
|
This function is designed with the same idea as the Invoke-Command cmdlet. Except |
|
in this function we also check to see if the user (COMPUTER\USERNAME) is currently |
|
logged into the system prior to execution. |
|
|
|
.PARAMETER UserName |
|
|
|
[string] |
|
The name of the user account 'COMPUTER\USERNAME' to filter for. |
|
|
|
.PARAMETER ScriptBlock |
|
|
|
[ScriptBlock] |
|
The block of powershell code that needs to be executed. |
|
|
|
.PARAMETER IgnoreAccountCheck |
|
|
|
[switch] |
|
If this value is **not** provided, the function will check to see if a local account exists with the UserName value provided. |
|
|
|
If this value is provided, the function will skip the check to see if a local account exists with the UserName value provided. |
|
|
|
.EXAMPLE |
|
|
|
PS> $theScriptBlock = { Remove-Item -Recurse -Force -Path 'C:\Users\lukem' -WhatIf } |
|
PS> Invoke-CommandIfOffline -Username "PII\lukem" -ScriptBlock $theScriptBlock |
|
|
|
|
|
.EXAMPLE |
|
|
|
# This example illustrates what happens when the user is online. |
|
|
|
PS>Invoke-CommandIfOffline -UserName "Pii\lukem" -ScriptBlock { Write-Host "Hello World!" } |
|
[!] The user is currently online. We cannot invoke the command at this time. |
|
|
|
.EXAMPLE |
|
|
|
# This example illustrates what happens when the user name provided is not a local account. |
|
|
|
PS>Invoke-CommandIfOffline -UserName "BLAH" -ScriptBlock { Write-Host "Hello World!" } |
|
|
|
Invoke-CommandIfOffline : [!] The user name provided does not exist. |
|
At line:1 char:1 |
|
+ Invoke-CommandIfOffline -UserName "BLAH" -ScriptBlock { Write-Host "H ... |
|
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
|
|
.EXAMPLE |
|
|
|
# This example illustrates a successful execution |
|
|
|
PS>Invoke-CommandIfOffline -UserName "Pii\Administrator" -ScriptBlock { Write-Host "Hello World!" } |
|
Hello World! |
|
|
|
.NOTES |
|
Function Name : Invoke-CommandIfOffline |
|
Author : Luke Muccillo luke@lukemuccillo.com |
|
Requires : PowerShell V3 |
|
|
|
Call this function whenever |
|
1. You need to run a command (and) |
|
2. You first want to ensure that a user is not online |
|
|
|
NB// I never tested this script in a domain environment so YMMV. |
|
#> |
|
function Invoke-CommandIfOffline { |
|
param( |
|
[Parameter(Mandatory=$true)] |
|
[string]$UserName, |
|
[Parameter(Mandatory=$true)] |
|
[ScriptBlock]$ScriptBlock, |
|
[Switch]$IgnoreAccountCheck |
|
) |
|
|
|
if (-not $IgnoreAccountCheck) { |
|
# Error detection that checks to see if a local account |
|
# exists with the username provided. |
|
$allUserAccounts = Get-WmiObject -Class Win32_UserAccount |
|
$allUserCaptionNames = $allUserAccounts | |
|
Select -ExpandProperty Caption |
|
|
|
if ($allUserCaptionNames -inotcontains $UserName) { |
|
|
|
$validUserNames = [string]::Join(",", $allUserCaptionNames) |
|
Write-Error "[!] The user name provided does not exist." |
|
Write-Error "[i] Valid local accounts: ", $allUserCaptionNames |
|
} |
|
} |
|
|
|
$currentUserSessions = @(Get-LoggedOnUser -UserName $UserName) |
|
|
|
if ($currentUserSessions.Count -ine 0) { |
|
Write-Output "[!] The user is currently online. We cannot invoke the command at this time." |
|
return |
|
} |
|
|
|
Invoke-Command -ScriptBlock $ScriptBlock |
|
} |
|
|
|
# Begin Script |
|
if (Test-Path $GLOBAL_REMOVE_DIR) { |
|
|
|
$scriptBlock = { Remove-Item -Recurse -Force -Path $GLOBAL_REMOVE_DIR } |
|
Invoke-CommandIfOffline -UserName $GLOBAL_USER_NAME -ScriptBlock $scriptBlock |
|
} |
|
# End Script |