function Get-UserProfile{
<#
.SYNOPSIS
Use WMI to query a computer about local profiles on the machine
.Description
This Fucntion is used to get information about local profiles on a computer. This will return information about any local profile, including the local cache of the domain accounts. By default returns the SID, Local path, and Last Use Time of the account; the -verbose flag can be used to return additional information.
.PARAMETER UserID
UserID to search for. If left blank will default to all users. By default UserID must match exactly, but you can use the wildcard '%' to perform more general seraches
.PARAMETER Computer
Computer to query for user accounts. Leaving Blank will default to 'localhost'.
.PARAMETER ExcludeSystemAccounts
Filters out System accounts (e.g. System, Network Service). This is done by looking at the 'special' property, which does not filter out users non-windows programs may create.
.PARAMETER OnlyLoaded
Setting this parameter shows only profiles that are currently in Use -- Combine with -ExcludeSystemAccounts and you can get a pretty good idea of who is currently logged into a machine.
.PARAMETER ExcludeLoaded
Returns only user profiles that are not currently in use. This is useful if you need to clear out profiles.
.PARAMETER Verbose
Returns Full user porfile data, rather than the default SID,LocalPath,LastUseTime
.PARAMETER OlderThan
Filter Results based on datetime. This requires a datetime object
.Example
Get-UserProfile -UserID MyUser
Basic usage to see if the user "MyUser" exists on the local machine.
.Example
Get-UserProfile -Computer RDSServ1.mydomain.com
Lists all user Profiles from remote computer "RDSServ1.mydomain.com"
.Example
Get-UserProfile -Computer RDSServ1.mydomain.com -ExcludeSystemAccounts -OnlyLoaded
Lists non-system user profiles from remote computer currently marked as loaded. This gives a pretty good idea of who is currently logged into a remote machine.
.Example
Get-UserProfile -OlderThan $((get-date).adddays(-14))
Lists user profiles that have not been used on the localhost in 14 days.
.Notes
Author: Keith Ballou
Date: Oct 15, 2014
This Script Relies on Convert-UTCtoDateTime -- A function for converting UTC strings to DateTime Objects
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$False)][string]$UserID="%",
[Parameter(Mandatory=$False)][string]$Computer="LocalHost",
[Parameter(Mandatory=$False)][switch]$ExcludeSystemAccounts,
[Parameter(Mandatory=$False)][switch]$OnlyLoaded,
[Parameter(Mandatory=$False)][switch]$ExcludeLoaded,
[Parameter(Mandatory=$False)][datetime]$OlderThan
)
if(!(Get-Command Convert-UTCtoDateTime -ErrorAction SilentlyContinue)){
write-host -BackgroundColor "Black" -ForegroundColor "Red" "################################################################################"
write-host -BackgroundColor "Black" -ForegroundColor "Red" "# "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "This Program Requires cmdlet ""Convert-UTCtoDateTime"" "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "Find it here: "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "http://pastebin.com/SSKJ4bwt "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "# "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "################################################################################"
break;
}
if($Computer.ToLower() -eq "localhost"){
$Return = Get-WmiObject -Query "Select * from win32_userprofile where LocalPath like '%\\$UserID'"
}
else{
$Return = get-wmiobject -ComputerName $Computer -Query "Select * from win32_userprofile where LocalPath like '%\\$UserID'"
}
#Filter System Accounts
if($ExcludeSystemAccounts){
$Return = $Return | Where-Object -Property Special -eq $False
}
#Filter out Loaded Accounts
if($ExcludeLoaded){
$Return = $Return | Where-Object -Property Loaded -eq $False
}
#Filter otherthan loaded accounts
if($OnlyLoaded){
$Return = $Return | Where-Object -Property Loaded -eq $True
}
#Filter on lastusetime
if([bool]$OlderThan){
$Return | Where-Object -property LastUseTime -eq $Null | % {Write-Host -BackgroundColor "Black" -ForegroundColor "Yellow" $_.LocalPath " Has no 'LastUseTime', omitting" }
$Return = $Return | Where-Object -property LastUseTime -ne $Null
$Return = $Return | Where-Object {$(Convert-UTCtoDateTime $_.LastUseTime -ToLocal) -lt $OlderThan }
}
if($PSBoundParameters['Verbose'])
{
Write-Output $Return
}
else{
Write-Output $Return | Select SID,LocalPath,@{Label="Last Use Time";Expression={Convert-UTCtoDateTime $_.LastUseTime -ToLocal}}
}
}
Function Remove-UserProfile{
<#
.SYNOPSIS
Removes User Profiles from a machine via WMI
.Description
This Cmdlet is used to remove user profiles from a machine when it is inconveinient to do so from the System menu. The script relies on Cmdlet Get-UserProfile. It is especially userful on Terminal Server/RDS machines where opening the system menu to delete user profiles can take hours (because reasons, I suppose).
.PARAMETER UserID
UserID to search for. Unlike Get-UserProfile, this cannot be left blank. If you intentionally want to remove all user profiles, or need to select multiple, you can use WMIs limited regex. Check this Link for more information: http://blogs.technet.com/b/heyscriptingguy/archive/2012/07/13/use-the-like-operator-to-simplify-your-wql-queries.aspx
.PARAMETER Computer
Computer to delete user accounts from. Leaving Blank will default to 'localhost'.
.PARAMETER Batch
This Flag will suppress confirmation dialogs, as well change console output to the more redirect friendly Write-Output, rather than the Write-Host it otherwise uses.
.PARAMETER OlderThan
Filter user accounts based on last use time. Remember that this Cmdlet does not assume 'all users', so you must specify -UserID %.
.Example
Remove-UserProfile myuser remotemachine.mydomain.com
Remove Users using positional parameters
.Example
Remove-UserProfile -UserID myuser -Computer remotemachine.mydomain.com
remove users specifying with flags
.Example
Get-Content machinelist.txt | % {Remove-UserProfile -User myuser -Computer $_ -Batch} >> C:\Temp\UserRemoval.log
Remove a user from a list of machines using the batch mode, seding output to a log file
.Example
Remove-UserProfile -OlderThan $((get-date).adddays(-14)) -UserID %
Remove all user accounts that haven't been used in 14 days
The '%' here is the WMI regex for anything (analogous to '*' (or '.*') in most regex) -- it is necessary because this Cmdlet never assumes all users
.Notes
Author: Keith Ballou
Date: Oct 16, 2014
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string]$UserID,
[Parameter(Mandatory=$False)][string]$Computer="LocalHost",
[Parameter(Mandatory=$False)][datetime]$OlderThan=(get-date).adddays(1),
[Parameter(Mandatory=$False)][switch]$Batch
)
#Make Sure Necessary Cmdlets Exist
if(!(Get-Command Get-UserProfile -ErrorAction SilentlyContinue)){
write-host -BackgroundColor "Black" -ForegroundColor "Red" "################################################################################"
write-host -BackgroundColor "Black" -ForegroundColor "Red" "# "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "This Program Requires cmdlet ""Get-UserProfile"" "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "Find it here: "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "http://pastebin.com/wvUDki7p "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "# "
write-host -BackgroundColor "Black" -ForegroundColor "Red" "################################################################################"
break;
}
#to simplify query, if OlderThan was not specified, assume anything earlier than right now (plus a day to account for timezones, rounding, etc)
#if(![bool]$OlderThan){
# $OlderThan = (get-date).adddays(1)
#}
#This Part relies on another of my Cmdlets "get-UserPorfile" to simplify the code a bit
#This Could be substituted with: $ProfileList = Get-WmiObject -Computer $Computer -Query "Select * From Win32_UserProfile where LocalPath like \\$UserID"
#..............................: $ProfileList = $ProfileList | Where-Object -Property Special -eq $False
#Additional logic may have to be added if WMI doesn't like 'localhost' as a ComputerName. Seems to work ok for me, but I wouldn't count on it.
#Get_UserProfile includes this logic
$ProfileList = Get-UserProfile -Verbose -UserID $UserID -Computer $Computer -ExcludeSystemAccounts -OlderThan $OlderThan
#If no Users were found, exit
if(!$ProfileList){
Write-Warning "NO USER PROFILES WERE FOUND"
RETURN;
}
#Confirmation Dialog if -Batch is not set
if(!$Batch){
Write-Warning "ABOUT TO REMOVE THE FOLLOWING USER ACCOUNTS"
Foreach($User in $ProfileList){
$User | Select SID,LocalPath,@{Label="Last Use Time";Expression={Convert-UTCtoDateTime $_.LastUseTime -ToLocal}}
}
$Title = "PROCEED?"
$Message = "ARE YOU SURE YOU WANT TO REMOVE THE LISTED USER ACCOUNTS?"
$Yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes","Removes User Accounts"
$No = New-Object System.Management.Automation.Host.ChoiceDescription "&No","Exits Script, No Changes Will be Made"
$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
$result = $host.ui.PromptForChoice($title, $message, $options, 1)
switch ($result)
{
0 {}
1 {return;}
}
}
#Remove Users provided they are not currently Loaded
Foreach($User in $ProfileList){
if($User.Loaded){
if(!$Batch){
Write-Host -BackgroundColor "Black" -ForegroundColor "Red" "User Account " $User.LocalPath "is Currently in user on" $Computer ":`tSkipping"
}
else{
Write-Output "User $($User.LocalPath) on $($Computer) was in use and could not be removed"
}
continue;
}
if(!$Batch){
Write-Host -BackgroundColor "Blue" -ForegroundColor "Green" "Removing User $($UserID.LocalPath) from $($Computer)"
}
else{
Echo "Deleting $($User.LocalPath) from $($Computer)"
}
$User.delete()
}
}
function Get-SNMPWalk{
[CmdletBinding()]
param(
[Parameter(Mandatory=$True)][string]$IP,
[Parameter(Mandatory=$False)][int]$SNMPVersion=2,
[Parameter(Mandatory=$False)][int]$Port=161,
[Parameter(Mandatory=$False)][int]$TimeOut=3000,
[Parameter(Mandatory=$False)][string]$Community="public",
[Parameter(Mandatory=$False)][string]$OIDStart=".1.3.6.1.2.1.1.1"
)
[reflection.assembly]::LoadFrom( (Resolve-Path ".\SharpSnmpLib.dll")) | Out-Null
if($SNMPVersion -gt 2 -or $SNMPVersion -lt 1)
{
Write-Error "Invalid SNMP Version Number, This script supports Versions 1 and 2"
return;
}
$OIDObject = New-Object Lextm.SharpSnmpLib.ObjectIdentifier ($OIDStart)
#if($SNMPVersion < 3)
#{
# $results = New-GenericObject System.Collections.Generic.List Lextm.SharpSnmpLib.Variable
#else
#{
$results = New-Object 'System.Collections.Generic.List[Lextm.SharpSnmpLib.Variable]'
#}
$IPObject=[System.Net.IPAddress]::Parse($IP)
$Server=New-Object System.Net.IpEndPoint($IPObject,$Port)
switch($SNMPVersion)
{
1
{
$SNMPVersionObject = [Lextm.SharpSnmpLib.VersionCode]::V1
}
2
{
$SNMPVersionObject = [Lextm.SharpSnmpLib.VersionCode]::V2
}
#3
#{
# $SNMPVersionObject = [Lextm.SharpSnmpLib.VersionCode]::V3
#}
}
$WalkMode = [Lextm.SharpSnmpLib.Messaging.WalkMode]::WithinSubtree
#try
#{
[Lextm.SharpSnmpLib.Messaging.Messenger]::Walk($SNMPVersionObject,$Server,$Community,$OIDObject,$results,$TimeOut,$WalkMode) | Out-Null
#}
#catch
#{
#Write-Host "SNMP Walk error: $_"
# return;
#}
$res = @()
foreach ($var in $results) {
$line = "" | Select IP,OID, Data
$line.IP = $IP
$line.OID = $var.Id.ToString()
$line.Data = $var.Data.ToString()
$res += $line
}
$res
}
function Convert-UTCtoDateTime{
#Parameter Binding
[CmdletBinding()]
param(
[Parameter(Mandatory=$True,Position=1)][string]$UTC,
[Parameter(Mandatory=$false)][switch]$ToLocal
)
#Breakout the various portions of the time with substring
#This is very inelegant, and UTC
$yyyy = $UTC.substring(0,4)
$M = $UTC.substring(4,2)
$dd = $UTC.substring(6,2)
$hh = $UTC.substring(8,2)
$mm = $UTC.substring(10,2)
$ss = $UTC.substring(12,2)
$fff = $UTC.substring(15,3)
$zzz = $UTC.substring(22,3)
#If local, add the UTC offset returned by get-date
if($ToLocal){
(get-date -Year $yyyy -Month $M -Day $dd -Hour $hh -Minute $mm -Second $ss -Millisecond $fff) + (get-date -format "zzz")
}
#else just return the UTC time
else{
get-date -Year $yyyy -Month $M -Day $dd -Hour $hh -Minute $mm -Second $ss -Millisecond $fff
}
}