HelpDesk.psm1
#Region $HelpDeskADComputernameArgCompleter $HelpDeskADComputernameArgCompleter = { param ($CommandName, $ParameterName, $StringMatch) if ($null -eq $StringMatch) { $Filter = "*" } else { $Filter = "*$StringMatch*" } (Get-ADComputer -filter { Name -like $Filter }).Name } Register-ArgumentCompleter -CommandName Get-Computer, Add-LocalAdmin, Remove-LocalAdmin, Get-LocalAdmin, Get-DellTags, Get-UserProfile, Remove-UserProfile -ParameterName ComputerName -ScriptBlock $HelpDeskADComputernameArgCompleter #EndRegion $HelpDeskADComputernameArgCompleter #Region $HelpDeskADFirstNameArgCompleter $HelpDeskADFirstNameArgCompleter = { param ($CommandName, $ParameterName, $StringMatch) if ($null -eq $StringMatch) { $Filter = "*" } else { $Filter = "*$StringMatch*" } $GivenNames = (Get-ADUser -Filter { GivenName -like $Filter }).GivenName $QuotedNames = foreach ($Name in $GivenNames) { if ($Name.Contains(" ")) { "`"$Name`"" } else { $Name } } return $QuotedNames } Register-ArgumentCompleter -CommandName Get-UsersWithFirstName -ParameterName FirstName -ScriptBlock $HelpDeskADFirstNameArgCompleter #EndRegion $HelpDeskADFirstNameArgCompleter #Region $HelpDeskADLastNameArgCompleter $HelpDeskADLastNameArgCompleter = { param ($CommandName, $ParameterName, $StringMatch) if ($null -eq $StringMatch) { $Filter = "*" } else { $Filter = "*$StringMatch*" } $SurNames = (Get-ADUser -Filter { SurName -like $Filter }).SurName $QuotedNames = foreach ($Name in $SurNames) { if ($Name.Contains(" ")) { "`"$Name`"" } else { $Name } } return $QuotedNames } Register-ArgumentCompleter -CommandName Get-UsersWithLastName -ParameterName LastName -ScriptBlock $HelpDeskADLastNameArgCompleter #EndRegion $HelpDeskADLastNameArgCompleter #Region $HelpDeskADUsernameArgCompleter $HelpDeskADUsernameArgCompleter = { param ($CommandName, $ParameterName, $StringMatch) if ($null -eq $StringMatch) { $Filter = "*" } else { $Filter = "*$StringMatch*" } $Users = (Get-ADUser -Filter { SamAccountName -like $Filter }).SamAccountName $QuotedUsers = foreach ($User in $Users) { if ($User[0] -eq "-") { "`"$User`"" } else { $User } } return $QuotedUsers } Register-ArgumentCompleter -CommandName Get-User, Get-OtherADUserAccounts, Reset-Password, Add-LocalAdmin, Remove-LocalAdmin, Get-LocalAdmin, Get-ADGroupsManagedByUser -ParameterName Username -ScriptBlock $HelpDeskADUsernameArgCompleter #EndRegion $HelpDeskADUsernameArgCompleter #Region ConvertExpressServiceCodeTo-ServiceTag Function ConvertExpressServiceCodeTo-ServiceTag() { [CmdletBinding()] param ([parameter(valuefrompipeline=$true, HelpMessage="Integer number to convert")][int64]$ExpressServiceCode="") $alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" do { $remainder = ($ExpressServiceCode % 36) $char = $alphabet.substring($remainder,1) $ServiceTag = "$char$ServiceTag" $ExpressServiceCode = ($ExpressServiceCode - $remainder) / 36 } while ($ExpressServiceCode -gt 0) $ServiceTag } #EndRegion ConvertExpressServiceCodeTo-ServiceTag #Region ConvertServiceTagTo-ExpressServiceCode Function ConvertServiceTagTo-ExpressServiceCode{ [CmdletBinding(DefaultParameterSetName='ServiceTag')] param( [Parameter(Mandatory,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName,ParameterSetName="ServiceTag")] [System.String] $ServiceTag ) begin{} process{ try { $Range = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" $ServiceTag_CharacterArray = $ServiceTag.ToUpper().ToCharArray() [System.Array]::Reverse($ServiceTag_CharacterArray) [System.Int64]$ExpressServiceCode=0 $i = 0 foreach($Character in $ServiceTag_CharacterArray) { $ExpressServiceCode += $Range.IndexOf($Character) * [System.Int64][System.Math]::Pow(36,$i) $i+=1 } $ExpressServiceCode } catch { Write-Error "$($_.Exception.Message)" } } end{} } #EndRegion ConvertServiceTagTo-ExpressServiceCode\ #Region Get-PlainText <# .SYNOPSIS Retrieve the Plain text string from a SecureString object. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus #> Function Get-PlainText() { [CmdletBinding()] param ( [parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [System.Security.SecureString[]]$SecureString ) begin { } process { foreach ($String in $SecureString) { $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($String); try { [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr); } finally { [Runtime.InteropServices.Marshal]::FreeBSTR($bstr); } } } end { } } #EndRegion Get-PlainText #Region Set-Password <# .SYNOPSIS Reset domain password for an ActiveDirectory user. .DESCRIPTION Sets a Active Directory Password and provides an option to require a password change on login. .EXAMPLE Specifies the username being set and then prompts for a password. Set-Password -username domain\username .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus #> Function Set-Password { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)]$Username, [Parameter()][SecureString]$Password = (Read-Host -Prompt "Password" -AsSecureString), [Switch]$RequireReset ) Set-ADAccountPassword -Identity $username -Reset -NewPassword $Password if ($RequireReset.IsPresent) { Set-ADUser -Identity $Username -ChangePasswordAtLogon $true } } #EndRegion Set-Password #Region Add-LocalAdmin <# .SYNOPSIS Adds user to local admin group. .DESCRIPTION This function adds a local admin to the computer or server it is run from. .PARAMETER Username Specify the SAMAccountName of the user to add. .PARAMETER ComputerName Specify the remote computer to run against. .PARAMETER Domain Specify the domain that the user belongs to. .EXAMPLE PS> Add-LocalAdmin -Username username Description ----------- Adds specified domain user to the local administrators group .EXAMPLE PS> Add-LocalAdmin -ComputerName Some-Remote-Computer -Username username Description ----------- This will attempt to add the specified user to the local admin group of the specified remote computer. You must be an admin on the remote computer for this to work. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk Azure AD Joined machines will require the user to first login to a computer with their domain account before adding their domain account as a local admin. The user logging in registers their SID so that the command is successful. #> Function Add-LocalAdmin() { [CmdletBinding()] Param ( [Parameter(Mandatory, Position = 0)] [string] $Username, [Parameter(Position = 1)] [string] $ComputerName = $env:COMPUTERNAME, [Parameter()] [string] $Domain = $env:USERDOMAIN ) begin { function Get-UsernameDomainFormat($Username, $Domain) { return ("$Domain\$Username") } } process { try { $FullUsername = Get-UsernameDomainFormat $Username $Domain if ($PSBoundParameters.ContainsKey('ComputerName')) { Invoke-Command -ComputerName $ComputerName -ScriptBlock { Add-LocalGroupMember -Group 'Administrators' -Member $using:FullUsername } #Invoke-Command -ComputerName $ComputerName -ScriptBlock { net.exe Localgroup Administrators $using:FullUsername /add } } else { Add-LocalGroupMember -Group 'Administrators' -Member $FullUsername #net.exe Localgroup Administrators $FullUsername /add } } catch { Write-Error "$($_.Exception.Message)" } } end {} } #EndRegion Add-LocalAdmin #Region Aliases Set-Alias FName FirstName Set-Alias FirstName Get-UsersWithFirstName Set-Alias LName LastName Set-Alias LastName Get-UsersWithLastName Set-Alias GLO Get-LockedOutADUsers Set-Alias LU Lookup Set-Alias Lookup Get-User Set-Alias UL Unlock-LockedOutADUsers Set-Alias PC PCLookup Set-Alias PCLookup Get-Computer Set-Alias RPW Reset-Password #EndRegion Aliases #Region Disable-Account <# .SYNOPSIS Disable an enabled AD Account. .DESCRIPTION Disables a specified Active Directory Account .PARAMETER Username Specify the SAMAccountName or DistinguishedName of the user to disable. .EXAMPLE PS> Disable-ADAccount -Username JohnDoe Description ----------- Use the Samaccountname of the account being disabled .EXAMPLE PS> Disable-ADAccount -Username "CN=Matt Degar,OU=AI,OU=UserAccounts,DC=FAKE,DC=COM" Description ----------- Use the DistinguishedName of the account being disabled .EXAMPLE PS> Disable-ADAccount -Username JohnD@Company.com Description ----------- Use the UserPrincipalName of the account being disabled .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Disable-Account() { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)]$Username ) Disable-ADAccount -Identity $Username -Confirm } #EndRegion Disable-Account #Region Enable-Account <# .SYNOPSIS Quickly enable a disabled ActiveDirectory user account .DESCRIPTION Enables a specified Active Directory Account .PARAMETER Username Specify the SAMAccountName or DistinguishedName of the user to enable. .EXAMPLE PS> Enable-ADAccount -Username JohnD Description ----------- Use the Samaccountname of the account being disabled .EXAMPLE PS> Enable-ADAccount -Username "CN=Matt Degar,OU=AI,OU=UserAccounts,DC=FAKE,DC=COM" Description ----------- Use the DistinguishedName of the account being disabled .EXAMPLE PS> Enable-ADAccount -Username PJohnD@Company.com Description ----------- Use the UserPrincipalName of the account being disabled .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Enable-Account() { [CmdletBinding()] Param ( [Parameter(Mandatory)] [string] $Username ) Enable-ADAccount -Identity $Username -Confirm } #EndRegion Enable-Account #Region Get-ADGroupsManagedByUser <# .SYNOPSIS Generate a list of group names owned by a specified. .DESCRIPTION This will look up groups owned by the specified user. .PARAMETER Username This is the Identity used by `Get-ADUser` to look up the Distinguished name used by `Get-ADGroup`. .EXAMPLE PS>Get-ADGroupsManagedByUser mjdegar Description ----------- This will generate all groups (Security or Distribution) Managed by `mjdegar`. .NOTES Author: Matthew J. DeGarmo Handle: @TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Get-ADGroupsManagedByUser() { [CmdletBinding()] param( [Parameter(Mandatory, Position = 0)] [string] $Username ) try { $User_DN = (Get-ADUser -Identity $Username).DistinguishedName Get-ADGroup -Properties ManagedBy -Filter * | ` Where-Object { $_.ManagedBy -eq $User_DN } | ` Select-Object Name } catch { Write-Error "$($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" } } #EndRegion Get-ADGroupsManagedByUser #Region Get-Computer <# .SYNOPSIS This function performs a quick lookup of an ActiveDirectory computer. .DESCRIPTION This function is a simple Get-ADComputer with certain fields to display. .PARAMETER ComputerName This parameter should specify the ActiveDirectory ComputerName. This parameter can accept multiple values, separated by commas. .PARAMETER FilePath This parameter should specify a .CSV or a .TXT file containing only computername values. NOTE: The CSV must have a value title at the top, aka the first line should say ComputerName or something similar. CSV files - first row should be column headers - The first row should be ComputerName EXAMPLE: ComputerName computer1 computer2 TXT files - just input data, no headers necessary. EXAMPLE: computer1 computer2 .INPUTS System.String[] This function does not accept pipeline data. The values for all parameters must be specified. .OUTPUTS None This function does not produce output except for write-host data .EXAMPLE PS>Get-Computer -ComputerName Computer1 Name : Computer1 Description : Some description of this computer OperatingSystem : Windows 10 Enterprise CanonicalName : some.domain.com/ou/path/to/computer Description ----------- This will display information about the computer. .EXAMPLE PS>PCLookup -ComputerName Fake-Computer PCLookup : The PC named 'Fake-Computer' does not exist. At line:1 char:1 + PCLookup -ComputerName Fake-Computer + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,PCLookup Description ----------- This will write an error to the screen that 'Fake-Computer' is not a computer that exists in ActiveDirectory. This also shows the usage of the alias `PCLookup` which points to `Get-Computer`. .EXAMPLE PS>PC -ComputerName Computer1,Fake-Computer,Computer2 Name : Computer1 Description : Some description of this computer OperatingSystem : Windows 10 Enterprise CanonicalName : some.domain.com/ou/path/to/computer PCLookup : The PC named 'Fake-Computer' does not exist. At line:1 char:1 + PCLookup -ComputerName Computer1,Fake-Computer,Computer2 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,PCLookup Name : Computer2 Description : Some description of this computer OperatingSystem : Windows 10 Enterprise CanonicalName : some.domain.com/ou/path/to/computer Description ----------- This will generate results for all three specified ComputerName's, and will generate an error in place of the Fake-Computer, and continue generating results. This also shows the usage of the alias `PC`, which points to the alias `PCLookup`, which points to the command `Get-Computer`. .EXAMPLE PS>Get-Computer -FilePath .\Computers.txt .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk Change Log: Version: 2.0 - Added the FilePath parameter, and loads error-checking to detect if computername is used or filepath used without having to specify -Computername or -FilePath Example: You can use PCLookup test-pc AND PCLookup C:\temp\file.txt AND PCLookup C:\temp\nonexistentfile.csv This script will now generate results, OR display the correct error message for all these scenarios. Version: 1.0 - Function Creation. #> Function Get-Computer() { [CmdletBinding(DefaultParameterSetName = "Named")] param( [parameter(Mandatory = $true, Position = 0, ParameterSetName = "Named", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true)] [ALias("Name")] [string[]]$ComputerName, [parameter(Mandatory = $true, Position = 0, ParameterSetName = "File")] [string]$FilePath ) begin { if ($ComputerName.Count -le 1) { if (([System.IO.File]::Exists($ComputerName)) -or (Test-Path $ComputerName)) { $FilePath = (Get-ChildItem $ComputerName).Fullname $Computername = $null } else { if (($ComputerName -match "\\") -and (-Not(Test-Path $ComputerName))) { Write-Error "File $ComputerName does not exist. Please provide a correct file path for -FilePath." break } } } if ($FilePath) { $ImportFileInfo = Get-Item $FilePath -ErrorAction SilentlyContinue $ImportFileData = Get-Content $FilePath -ErrorAction SilentlyContinue if (!$ImportFileData) { Write-Error "$FilePath is null or empty." break } switch ($ImportFileInfo.Extension) { '.csv' { $FileData = Import-Csv $FilePath } '.txt' { $FileData = $ImportFileData } #End '.txt' Default { Write-Error "Please use an approved file format for the -FilePath parameter." break } }# End switch ($ImportFile.Extension) $ComputerName = $FileData } } process { try { foreach ($Computer in $ComputerName) { try { Get-ADComputer $Computer -Property "Name", "Description", "OperatingSystem", "OperatingSystemVersion", "CanonicalName" -ErrorAction Stop | Select-Object Name, Description, OperatingSystem, OperatingSystemVersion, CanonicalName } catch { try { $regex = "*$Computer*" $Filter = "Name -like `"$regex`"" Get-ADComputer -Filter $Filter -Properties "Name", "Description", "OperatingSystem", "OperatingSystemVersion", "CanonicalName" -ErrorAction Stop -OutVariable ComputerExists | Select-Object Name, Description, OperatingSystem, OperatingSystemVersion, CanonicalName if (!$ComputerExists) { Throw } } catch { Write-Error "The PC named '$Computer' does not exist." } } } } catch { Write-Error "$($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" } } end {} } #EndRegion Get-Computer #Region Get-DaysUntil <# .SYNOPSIS Calculate the number of days between today and any future (or past) date. .DESCRIPTION This function provides the quantity of days between today and any given date. .PARAMETER Date Specifies a date. Enter the date in a format that is standard for the system locale. Example Date Formats: 06/06/2020 6/6 june6 june6/2020 aug12 october18 .EXAMPLE Let's say today is January 1st, 2020. PS> Get-DaysUntil 10/18 291 Description ----------- This will generate the number of days between today (jan1/2020) and October 18th, 2020. See `Get-Help Get-DaysUntil -Parameter Date` for example date formats. .EXAMPLE Let's say today is January 1st, 2020. PS> Get-DaysUntil 10/18/2000 -7014 Description ----------- This will generate a negative number, for the number of days in the past the specified date is. See `Get-Help Get-DaysUntil -Parameter Date` for example date formats. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Get-DaysUntil() { [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Date ) $TimeSpan = (New-TimeSpan -Start (Get-Date -Hour 0 -Minute 0 -Second 0) -End (Get-Date -Date $Date)) if ([math]::Round($TimeSpan.Hours / 24) -eq 1) { if ($TimeSpan.Days -ge 0) {$Days = $TimeSpan.Days + 1} elseif ($TimeSpan.Days -lt 0) {$Days = $TimeSpan.Days - 1} } else { $Days = $TimeSpan.Days } $Days } #EndRegion Get-DaysUntil #Region Get-DellTags <# .SYNOPSIS Gather Dell Tag information. .DESCRIPTION Generate the ServiceTag and ExpressServiceCode of a dell computer. .PARAMETER ServiceTag Providing the ServiceTag (SerialNumber) will generate the accompanying ExpressServiceCode. .PARAMETER ExpressServiceCode Providing the ExpressServiceCode will generate the accompanying ServiceTag (SerialNumber). .PARAMETER ComputerName Providing the ComputerName will attempt to generate the ServiceTag and ExpressServiceCode. The computer specified must be turned on, online, and your account must have remote access rights to it. If the Get-CimInstance query finds that the specified computer is not a Dell, your query will fail. .EXAMPLE PS> Get-DellTags -ServiceTag M11P21T ServiceTag ExpressServiceCode ---------- ------------------ M11P21T 47952526241 Description ----------- Providing the -ServiceTag will generate the ExpressServiceCode .EXAMPLE PS> Get-DellTags -ExpressServiceCode 47952526241 ServiceTag ExpressServiceCode ---------- ------------------ M11P21T 47952526241 Description ----------- Providing the -ExpressServiceCode will generate the ServiceTag. .EXAMPLE PS> Get-DellTags -ComputerName some-domain-computer ServiceTag ExpressServiceCode ---------- ------------------ M11P21T 47952526241 Description ----------- Providing the -ComputerName will attempt to generate this information if the computer is online, and it is a Dell computer. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Get-DellTags() { [cmdletBinding(DefaultParameterSetName='ComputerName')] param ( [Parameter(Mandatory,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName,ParameterSetName="ServiceTag")] [System.String] $ServiceTag, [Parameter(Mandatory,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName,ParameterSetName="ExpressServiceCode")] [System.Int64] $ExpressServiceCode, [Parameter(Mandatory,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName,ParameterSetName="ComputerName")] [System.String] $ComputerName ) begin {} process { try { switch($PSBoundParameters.Keys) { 'ServiceTag' { $ExpressServiceCode = ConvertServiceTagTo-ExpressServiceCode -ServiceTag $ServiceTag } 'ExpressServiceCode' { $ServiceTag = ConvertExpressServiceCodeTo-ServiceTag -ExpressServiceCode $ExpressServiceCode } 'ComputerName' { $params = @{ ClassName = 'Win32_BIOS' ComputerName = $ComputerName } $ComputerInfo = Get-CimInstance @params if ($ComputerInfo.Manufacturer -like "*DELL*") { $ServiceTag = $ComputerInfo.SerialNumber } else { Throw("Computer: $($ComputerName.ToUpper()) is not a Dell computer. Manufacturer is $($ComputerInfo.Manufacturer)") } $ExpressServiceCode = ConvertServiceTagTo-ExpressServiceCode -ServiceTag $ServiceTag } DEFAULT {} } [PSCustomObject]@{ ServiceTag = $ServiceTag ExpressServiceCode = $ExpressServiceCode } } catch { Write-Error "$($_.Exception.Message)" } } end {} } #EndRegion Get-DellTags #Region Get-LocalAdmin <# .SYNOPSIS Retrieves a list of users in the local Administrators group. .DESCRIPTION This function identifies local admins from the computer or server it is run from. .PARAMETER ComputerName Specify the remote computer to query. .EXAMPLE PS> Get-LocalAdmin Description ----------- Generates a list of local admins .EXAMPLE PS> Get-LocalAdmin -ComputerName SomeRemoteComputer-PC Description ----------- Generate a list of local admins on a remote PC. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> #Requires -Assembly C:\Windows\system32\net.exe Function Get-LocalAdmin() { [CmdletBinding()] param( [Parameter()] [string] $ComputerName = $env:COMPUTERNAME ) if ($PSBoundParameters.ContainsKey('ComputerName')) { $NetAdminObject = Invoke-Command -ComputerName $ComputerName -ScriptBlock { (net.exe localgroup Administrators) -split '\r?\n' } } else { $NetAdminObject = (net.exe localgroup Administrators) -split '\r?\n' } $NetAdminObject[6..(($NetAdminObject.count) - 3)] } #EndRegion Get-LocalAdmin #Region Get-LockedOutADUsers <# .SYNOPSIS This function performs a search of users in ActiveDirectory who are currently locked out. .DESCRIPTION This function is a simple Search-ADAccount -Lockedout to generate a list of users who are currently locked out. This function provides the Name, SAMAccountName, and LockoutTime for each user that is locked out. .PARAMETER Properties This parameter should specify any AD properties to be returned for each user. This parameter is optional. If not specified, the default is to return the following properties: - Name - SAMAccountName - LockoutTime - [CONDITIONAL] LockoutSource (See Parameter -IncludeLockoutSource) .PARAMETER IncludeLockoutSource This parameter is optional. If specified, the LockoutSource will be returned for each user. This parameter requires you have rights to query your domain controller for these logs. Specifying this parameter will first make a test query to your domain controller to confirm you have rights to query these logs. If you do not have rights to query these logs, this parameter will be ignored. So far, the SIMPLEST way to grant a domain user rights to read these logs from the correct Domain Controller (that I know of) involves the following: - Add the user (or group) to the 'Event Log Readers' group on the domain controller. - Grant the user (or group) READ rights to the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Security on the domain controller. Both of the above are required to have rights to the DC's Security logs. Membership to the 'Event Log Readers' group only will NOT grant read rights to the Security logs. See: https://social.technet.microsoft.com/Forums/lync/en-US/b72162d1-2c86-4d1a-9727-ec7269814cc4/getwinevent-with-nonadministrative-user?forum=winserverpowershell This will grant the user (or group) rights to read the Event Logs on the domain controller, including the Security logs. This is the only registry key that is required to read the Security Event Logs. If you do not have these rights, you will not be able to read the Lockout (4740) logs. .INPUTS System.String This function does not accept pipeline data. The values for all parameters must be specified. .OUTPUTS None This function does not produce output except for write-host data .EXAMPLE PS>Get-LockedOutADUsers Name SamAccountName LockoutTime ---- -------------- ----------- DeGarmo, Matthew J. matthewjd 6/26/2019 13:32:15 Description ----------- This will show all users who are currently locked out. .EXAMPLE PS>Get-LockedOutADUsers No users are currently locked out. Description ----------- This will display the results of the query, in this case there were no results to display. .EXAMPLE PS>GLO -IncludeLockoutSource Name SamAccountName LockoutTime LockoutSource ---- -------------- ----------- ------------- DeGarmo, Matthew J. matthewjd 6/26/2019 13:32:15 Some-Computer Description ----------- This will show all users who are currently locked out and the source computername of the lockout event. .EXAMPLE PS>Get-LockedOutADUsers -IncludeLockoutSource You do not have rights to execute remote queries to this Domain Controller: Some-DC-Here Please see 'Get-Help Get-LockedOutADUsers -Parameter IncludeLockoutSource' for more information. Name SamAccountName LockoutTime ---- -------------- ----------- DeGarmo, Matthew J. matthewjd 6/26/2019 13:32:15 Description ----------- This will show all users who are currently locked out, while displaying a message letting you know you do not have rights to read these events from the Domain Controller. .NOTES Author: Matthew.DeGarmo Github: https://github.com/TechDufus Sponsor: https://github.com/sponsors/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Get-LockedOutADUsers() { [CmdletBinding()] param( [Switch] $IncludeLockoutSource, [System.String[]] $Properties ) Begin { If ($IncludeLockoutSource.IsPresent) { $ComputerName = "$((Get-ADDomain).PDCEmulator)" $params = @{ FilterHashTable = @{ LogName = 'Security' ID = '4740' } MaxEvents = 1 ComputerName = $ComputerName ErrorAction = 'Stop' } Try { $null = Get-WinEvent @params } Catch { [Switch]$IncludeLockoutSource = $false Write-Warning "You do not have rights to execute remote queries to this Domain Controller: $ComputerName" Write-Warning "Please see 'Get-Help $($MyInvocation.MyCommand) -Parameter IncludeLockoutSource' for more information." } } } Process { If ($Properties -ne '*') { $Properties = @('Name', 'SAMAccountName', 'LockoutTime') + @($Properties) | Select-Object -Unique } If ($IncludeLockoutSource.IsPresent) { $LockoutEvents = @{} Get-LockoutSource -ComputerName $ComputerName | Foreach-Object { If (-Not([bool]$LockoutEvents["$($_.Identity)"])) { $LockoutEvents["$($_.Identity)"] = $_.LockoutSource } } } Search-ADAccount -LockedOut | Foreach-Object { Get-ADUser $_.SamAccountName -Properties LockoutTime | Where-Object { $_.Name -ne 'Guest' } | Select-Object $Properties | Foreach-Object { $Date = [DateTime]$_.LockoutTime $_.LockoutTime = $Date.AddYears(1600).ToLocalTime() If ($IncludeLockoutSource.IsPresent) { If ([bool]$LockoutEvents["$($_.SamAccountName)"]) { $_ | Add-Member -MemberType NoteProperty -Name 'LockoutSource' -Value $LockoutEvents["$($_.SamAccountName)"] } Else { $_ | Add-Member -MemberType NoteProperty -Name 'LockoutSource' -Value 'UNKNOWN' } } $_ } } } } #EndRegion Get-LockedOutADUsers #Region Get-LockoutSource <# .SYNOPSIS Get the lockout (4740) parsed event log from your domain controller. .DESCRIPTION This command will get the lockout (4740) event log from your domain controller. .PARAMETER Identity The Identity of a specific AD User to query. .PARAMETER ComputerName The name of the computer to query. This defaults to the correct domain controller. .EXAMPLE Get-LockoutSource -ComputerName DC1 Description ----------- This will get the lockout (4740) events log from DC1 for any user. .EXAMPLE Get-LockoutSource -Identity "Administrator" -ComputerName DC1 Description ----------- This will get the lockout (4740) events log from DC1 for the Administrator user. .EXAMPLE Get-LockoutSource -Identity "Administrator" Description ----------- This will get the lockout (4740) events log from the current domain controller for the Administrator user. .NOTES Author: TechDufus GitHub: https://github.com/TechDufus #> Function Get-LockoutSource() { [CmdletBinding()] Param( [Parameter( ValueFromPipelineByPropertyName )] [Alias('SAMAccountName')] [System.String] $Identity, [Parameter()] [System.String] $ComputerName = "$((Get-ADDomain).PDCEmulator)" ) Process { Try { # If object is from the pipe, need to set $User.SAMAccountName value If ($_ -is [System.Object]) { $User = @{ SAMAccountName = $_.SamAccountName } } Else { If ($Identity) { $User = Get-ADUser $Identity -Properties LockedOut If (-Not ($User.LockedOut)) { Throw [System.DirectoryServices.ActiveDirectory.ActiveDirectoryObjectNotFoundException]::new("The user $($User.SamAccountName) is not currently locked out.") } } } $params = @{ FilterHashTable = @{ LogName = 'Security' ID = '4740' } ComputerName = $ComputerName ErrorAction = 'SilentlyContinue' } If ($ComputerName -ne $env:COMPUTERNAME -or 'localhost') { $params['ComputerName'] = $ComputerName } If ($Identity) { Get-WinEvent @params | Where-Object { (($_.Message) -split '\t')[-3].split([System.Environment]::NewLine)[0] -eq $($User.SamAccountName) } | Foreach-Object { [PSCustomObject] @{ Identity = $($User.SamAccountName) LockoutSource = (($_.Message) -split '\t')[-1] TimeCreated = $_.TimeCreated } } } Else { Get-WinEvent @params | Foreach-Object { [PSCustomObject] @{ Identity = (($_.Message) -split '\t')[-3].split([System.Environment]::NewLine)[0] LockoutSource = (($_.Message) -split '\t')[-1] TimeCreated = $_.TimeCreated } } } } Catch { Throw $_ } } } #EndRegion Get-LockoutSource #Region Get-User <# .SYNOPSIS This function performs a quick lookup of an ActiveDirectory user, group membership, and possible computers belonging to that user. .DESCRIPTION This function is a simple Get-ADUser with certain fields to display. This function also uses the user Surname against ActiveDirectory Computer Descriptions to generate a list of possible PC's used by the user. This assumes that the AD Computer Descriptions are being used and that full last names are used. This function also generates a list (if the parameter -Groups is used) of groups that a user is a member of using Get-ADPrincipalGroupMembership. .PARAMETER Username This parameter should specify the ActiveDirectory account name or SamAccountName. .PARAMETER Groups This is a switch that will have the function include a listing of user group membership. .PARAMETER Computers Specifying this switch will check the desired user's last name (SurName) against all AD Computer Descriptions for a possible match. If your organization used the ManagedBy value to tie an AD Computer to an AD User, then you can change the script. I will look into how to do both in the future. .INPUTS System.String This function does not accept pipeline data. The values for all parameters must be specified. .OUTPUTS None This function does not produce output except for write-host data .EXAMPLE PS>Get-User matthewjd DisplayName : DeGarmo, Matthew J. Manager : Elon Musk Department : AI Relations Title : AI Architect Office : Jupiter-K12-A Mail : jpytr_MailMe@AICorp.com OfficePhone : 90acedb3-afb1-4986-99de-378fa797fa58 IPPhone : a66f0778 SamAccountName : matthewjd Description : Head of AI Relations PassLastSet : DATE HERE Possible Computers... Name : Some-Computer Description : Matthew DeGarmo, AI Relations Description ----------- This will display generic information about the user as well as attempt to locate AD Computers that may belong to them. .EXAMPLE PS>Lookup -Username user1 -Groups Description ----------- Additionally, this will add the group names from `Get-ADPrincipalGroupMembership` to the beginning of the output. This also shows the usage of the previous command `Lookup`. This is an alias. .EXAMPLE PS>lu user1 Description ----------- This shows the usage of the alias `LU`, which points to the old command name `Lookup`, which now points to `Get-User` .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk Change Log: Version: 1.2 - Added Password Last Set date to the end of data. This is useful to help troubleshoot lockout issues. Version: 1.1 - Added Description to the user data section. Version: 1.0 - Function Creation. #> Function Get-User() { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('SAMAccountName')] [String]$Username, [switch]$Groups, [switch]$Computers ) begin { $Username = $Username.ToUpper() } process { try { if ($Groups.IsPresent) { Write-Verbose "Groups switch is on. Gathering groups." try { Write-Verbose "Generating groups list for Username: $Username" $GroupMembership = Get-ADPrincipalGroupMembership $Username -ErrorAction Stop | Select-Object Name | Sort-Object Name } catch { Write-Verbose "Failed to generate groups list." Write-Error "Could not retrieve groups for user $($Username.ToUpper())" } } try { Write-Verbose "Checking for Username: $Username details." $AllUserInfo = Get-ADUser -Identity $Username -Properties "DisplayName", "Department", "Title", "Office", "Mail", "OfficePhone", "IPPhone", "Manager", "Description", "EmployeeID", "pwdLastSet" -ErrorAction Stop $User = $AllUserInfo | ` Select-Object DisplayName, @{Name = 'Manager'; Expression = { $(Get-ADUser $_.Manager).Name } }, Department, Title, Office, Mail, OfficePhone, IPPhone, EmployeeID, SamAccountName, Description, @{Name = 'PassLastSet'; Expression = { [DateTime]::FromFileTime($_.pwdLastSet) } } } catch { Write-Verbose "Failed to lookup User attributes" Throw("The user '$Username' does not exist.") } if (!$User) { Write-Error "The user '$Username' does not exist." } else { if ($Groups.IsPresent) { Write-Verbose "Groups switch is on. Displaying Groups." $GroupMembership.Name } Write-Verbose "Displaying user attributes." $User if ($Computers.IsPresent) { $UserDistinguishedName = $AllUserInfo.DistinguishedName $ComputerManagedBy = Get-ADComputer -Filter { ManagedBy -eq $UserDistinguishedName } if ($ComputerManagedBy) { Write-Verbose "Found possible computers. Displaying results." Write-Output "Possible Computers..." $ComputerManagedBy.Name | ForEach-Object { Get-ADComputer -Identity $_ -Properties Description -ErrorAction Stop | Select-Object Name, Description } } else { $Surname = "*$((Get-ADUser -Identity $Username -Properties SurName).SurName)*" Write-Verbose "Checking for possible computers based on last name: $Surname" try { $Filter = "Description -like `"$Surname`" -and Enabled -eq `"$true`"" $PossibleComputers = Get-ADComputer -filter $Filter -Properties Description -ErrorAction Stop | Select-Object Name, Description } catch {} if ($PossibleComputers) { Write-Verbose "Found possible computers. Displaying results." Write-Output "Possible Computers..." $PossibleComputers } else { Write-Verbose "No possible PCs were found." Write-Output "Unable to locate possible Computers for this user..." } } } } } catch { Write-Error "$($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" } } } #EndRegion Get-User #Region Get-UserProfile <# .SYNOPSIS Quickly generate a list of user profiles for a computer. .DESCRIPTION This will generate a local or a remote list of non-special (SYSTEM, Administrator, etc.) profiles on a computer. .PARAMETER ComputerName Specify the remote machine to query. You must have rights to connect to this computer. .EXAMPLE PS> Get-UserProfile Description ----------- This will display CIM Objects for each profile on the local system. .EXAMPLE PS> Get-UserProfile -ComputerName Some-Remote-PC1 Description ----------- This will retrieve User Profile CIM Objects from the remote PC. .NOTES Author: Matthew J. DeGarmo Handle: @TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Get-UserProfile() { [CmdletBinding()] Param ( [System.String] $ComputerName ) Begin {} Process { Try { $Params = @{ ClassName = 'Win32_UserProfile' } if ($PSBoundParameters.ContainsKey('ComputerName')) { $Params += @{ComputerName = $ComputerName.ToUpper()} } $Profiles = Get-CimInstance @Params | Where-Object {$_.Special -ne "Special" -and $_.LocalPath -ne "C:\Users\Administrator"} if ($Profiles) { $Profiles } else { Throw("There are no user profiles to display.") } } Catch { Write-Error "$($_.Exception.Message)" } } End {} } #EndRegion Get-UserProfile #Region Get-UsersWithFirstName <# .SYNOPSIS This function performs a search of users in ActiveDirectory for a first name. .DESCRIPTION This function is a simple Get-ADUser with a filter for GivenName to generate a list of users with the provided first name. This function provides the Name, SAMAccountName, and Office for each user with the specified first name. These are sorted by office first, and then name second. .PARAMETER FirstName This parameter should specify the ActiveDirectory account GivenName (first name). This parameter will only accept alpha characters and will halt the function if it detects numeric characters. .PARAMETER Properties This parameter will declare additional properties to include with the default values generated. To see what other properties can be included, fun this function against a name that is successful and add "| Get-Member" to get a list. The items with a MemberType of NoteProperty can be named in this -Properties parameter separated by commas. Example ------- FirstName Matthew | Get-Member .INPUTS System.String This function does not accept pipeline data. The values for all parameters must be specified. .OUTPUTS System.Object[] Objects generated from the AD query. .EXAMPLE PS>Get-UsersWithFirstName Matt -Properties Title Name SamAccountName Office Title ---- -------------- ------ ----- JoeBobJenkins, Matt mjoebob Chicago Position Jackson, Matt mjackso Chicago Position Williamson-bob, Matt mwillia Boston-North Position Zachery, Matt mzacher Boston-East Position Zebras, Matt mzebras Chicago Position Description ----------- This will find all ActiveDirectory users with the first name of 'Matt' and display the results. .EXAMPLE PS>Get-FirstName FakeName FName : There is no user with 'FakeName' as their first name. Description ----------- This will display an error indicating there were no users who matched the first name provided. .EXAMPLE PS>fname michael Desctiption ----------- This example shows using the alias for this function. The alias is FName. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Get-UsersWithFirstName() { [CmdletBinding()] param ( [string[]] $Properties, [Parameter(Mandatory = $true, Position = 0)] [ValidateLength(1, 33)] [ValidateScript( { if ($_ -match '\d') { throw('Parameter -FirstName should only contain alpha characters.') } else { return $true } })] [string]$FirstName ) $Filter = "GivenName -eq `"$FirstName`"" $Users = Get-ADUser -Filter $Filter -Properties GivenName, Surname, Manager, Office, OfficePhone, Title $i = 0 $Users | ForEach-Object { $i++ } if ($i -eq 1) { Lookup -Username $Users.SamAccountName } else { ##Set up the default display set and create the member set object for use later on #Configure a default display set if ($Properties -eq '*') { $DefaultDisplaySet = 'Name', 'FirstName', 'LastName', 'Manager', 'Office', 'Phone', 'Gender', 'Title', 'SamAccountName' } elseif ($Properties -and $Properties -ne '*') { $DefaultDisplaySet = 'Name', 'SamAccountName', 'Office' $DefaultDisplaySet += $Properties } else { $DefaultDisplaySet = 'Name', 'SamAccountName', 'Office' } #Create the default property display set $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet', [string[]]$DefaultDisplaySet) $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) $Results = $Users | ForEach-Object { try { $Manager = $(Get-ADUser $_.Manager -ErrorAction Stop ).Name } catch { $Manager = "Unavailable" } $object = [pscustomobject]@{ Name = $_.Name FirstName = $_.GivenName LastName = $_.Surname Manager = $Manager Office = $_.Office Phone = $_.OfficePhone Title = $_.Title SamAccountName = $_.SamAccountName } #Give this object a unique typename $object.PSObject.TypeNames.Insert(0, 'User.Information') $object | Add-Member MemberSet PSStandardMembers $PSStandardMembers $Object } if ($Results) { $Results } else { Write-Error "There is no user with '$FirstName' as their first name." } } } #EndRegion Get-UsersWithFirstName #Region Get-UsersWithLastName <# .SYNOPSIS This function performs a search of users in ActiveDirectory for a last name. .DESCRIPTION This function is a simple Get-ADUser with a filter for SurName to generate a list of users with the provided last name. This function provides the Name, SAMAccountName, and Office for each user with the specified last name. These are sorted by office first, and then name second. .PARAMETER LastName This parameter should specify the ActiveDirectory account SurName (last name). This parameter will only accept alpha characters and will halt the function if it detects numeric characters. .PARAMETER Properties This parameter will declare additional properties to include with the default values generated. To see what other properties can be included, fun this function against a name that is successful and add "| Get-Member" to get a list. The items with a MemberType of NoteProperty can be named in this -Properties parameter separated by commas. Example ------- Get-UsersWithLastName Matthew | Get-Member .INPUTS System.String This function does not accept pipeline data. The values for all parameters must be specified. .OUTPUTS System.Object[] Objects generated from the AD query. .EXAMPLE PS>Get-UsersWithLastName Smith -Property Title Name SamAccountName Office Title ---- -------------- ------ ----- Smith, Deborah dsmith Chicago Position Smith, Kent ksmith Boston-South Position Smith, Matthew msmith Chicago Position Smith, Trent tsmith Boston-North Position Description ----------- This will find all ActiveDirectory users with the last name of 'Smith' and display the results. .EXAMPLE PS>LastName FakeName LastName : There is no user with 'FakeName' as their last name. Description ----------- This will display an error indicating there were no users who matched the last name provided. .EXAMPLE PS>Lname degarmo Desctiption ----------- This example shows using the alias for this function. The alias is LName. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Get-UsersWithLastName() { [CmdletBinding()] param ( [string[]]$Properties, [Parameter(Mandatory = $true, Position = 0)] [ValidateLength(1, 35)] [ValidateScript( { if ($_ -match '\d') { throw('Paremeter -LastName should only contain alpha characters.') } else { return $true } })] [string]$LastName ) $Filter = "Surname -eq `"$LastName`"" $Users = Get-ADUser -Filter $Filter -Properties GivenName, Surname, Manager, Office, OfficePhone, Title $i = 0 $Users | ForEach-Object { $i++ } if ($i -eq 1) { Lookup -Username $Users.SamAccountName } else { ##Set up the default display set and create the member set object for use later on #Configure a default display set if ($Properties -eq '*') { $DefaultDisplaySet = 'Name', 'FirstName', 'LastName', 'Manager', 'Office', 'Phone', 'Gender', 'Title', 'SamAccountName' } elseif ($Properties -and $Properties -ne '*') { $DefaultDisplaySet = 'Name', 'SamAccountName', 'Office' $DefaultDisplaySet += $Properties } else { $DefaultDisplaySet = 'Name', 'SamAccountName', 'Office' } #Create the default property display set $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet', [string[]]$DefaultDisplaySet) $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) #$Users = Get-ADUser -Filter {Surname -eq $LastName} -Properties GivenName,Surname,Manager,Office,OfficePhone,Title $Results = $Users | ForEach-Object { try { $Manager = $(Get-ADUser $_.Manager -ErrorAction Stop).Name } catch { $Manager = "Unavailable" } $object = [pscustomobject]@{ Name = $_.Name FirstName = $_.GivenName LastName = $_.Surname Manager = $Manager Office = $_.Office Phone = $_.OfficePhone Title = $_.Title SamAccountName = $_.SamAccountName } #Give this object a unique typename $object.PSObject.TypeNames.Insert(0, 'User.Information') $object | Add-Member MemberSet PSStandardMembers $PSStandardMembers return $Object } if ($Results) { $Results } else { Write-Error "There is no user with '$LastName' as their last name." } } } #EndRegion Get-UsersWithLastName #Region New-Password <# .SYNOPSIS Create a random password .DESCRIPTION The function creates a random password using a given set of available characters. The password is generated with fixed or random length. Passwords will never end with a number, and never start with a special character. .PARAMETER Admin This switch will change all of the password requirements to be a 24-character password with all character types. .PARAMETER Size Specify the fixed length of the password. .PARAMETER Count Number of passwords to generate, default = 1 .PARAMETER CharSets Specify the character-type requirements. U=Upper, L=Lower, N=Number, S=Special. .PARAMETER Exclude Specify any characters to exclude from the new password generated. .EXAMPLE PS> New-RandomPassword -Admin Description ----------- This generates a random password of 24-character length, and includes all character types. .EXAMPLE PS> New-RandomPassword -Size 20 Description ----------- Generates a password of 20 characters .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function New-Password() { [CmdletBinding()] param ( [Int]$Size = 12, [Char[]]$CharSets = "ULNS", [Char[]]$Exclude, [int]$Count = 1, [switch]$Admin ) if ($Admin.IsPresent) { $Size = 24 } for ($i = 0; $i -lt $Count; $i++) { $Chars = @(); $TokenSets = @() #Creates a disctionary of character arrays for each character set If (!$TokenSets) { $TokenSets = @{ U = [Char[]]'ABCDEFGHJKLMNPQRTUVWXYZ' #Upper case L = [Char[]]'abcdefghijkmnrstuvwxyz' #Lower case N = [Char[]]'2346789' #Numerals S = [Char[]]'_!@#%&' #Symbols } } #Cycles through each character set for a random character from each. $CharSets | ForEach-Object { #Creates a single array from all character and token sets. $Tokens = $TokenSets."$_" | ForEach-Object { If ($Exclude -cNotContains $_) { $_ } } If ($Tokens) { $TokensSet += $Tokens If ($_ -cle [Char]"Z") { $Chars += $Tokens | Get-Random } #Character sets defined in upper case are mandatory } } #Loops through each character and grabs a random one. While ($Chars.Count -lt $Size) { $Chars += $TokensSet | Get-Random } #Further randomizes the ending password. $PW = ($Chars | Sort-Object { Get-Random }) -Join "" #Mix the (mandatory) characters and output string #Password must not end with a number, must start with an alpha character, and must have at least 1 of each character type. #If password doesn't meet the below regexs, it adds 1 to the amount of password needed, and skips that password. if (($PW[-1] -match '\d') -or (-Not ($PW[0] -match '[a-zA-Z]')) -or (-Not($PW -match "^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[_!@#%&]).*$"))) { $Count++ continue } else { $PW } } } #EndRegion New-Password #Region Remove-LocalAdmin <# .SYNOPSIS Removes user from local admin group. .DESCRIPTION This function removes a local admin from the computer or server it is run from. .PARAMETER Username Specify the SAMAccountName of the user to remove. .PARAMETER ComputerName Specify a remote computer to run against. .PARAMETER Domain Specify the domain that the user belongs to. .EXAMPLE PS> Remove-LocalAdmin -Username someuser Description ----------- Removes specified domain user from the local administrators group .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk Azure AD Joined machines will require the user to first login to a computer with their domain account before adding their domain account as a local admin. The user logging in registers their SID so that the command is successful. #> Function Remove-LocalAdmin() { [CmdletBinding()] Param ( [Parameter(Mandatory, Position = 0)] [string] $Username, [Parameter(Position = 1, ValueFromPipelineByPropertyName)] [string] $ComputerName = $env:COMPUTERNAME, [Parameter()] [string] $Domain = $env:USERDOMAIN ) begin { function Get-UsernameDomainFormat($Username, $Domain) { return ("$Domain\$Username") } } process { try { $FullUsername = Get-UsernameDomainFormat $Username $Domain if ($PSBoundParameters.ContainsKey('ComputerName')) { #Invoke-Command -ComputerName $ComputerName -ScriptBlock { Remove-LocalGroupMember -Group Administrators -Member $using:FullUsername } Invoke-Command -ComputerName $ComputerName -ScriptBlock { net.exe Localgroup Administrators $using:FullUsername /delete } } else { #Remove-LocalGroupMember -Group Administrators -Member $FullUsername net.exe Localgroup Administrators $FullUsername /delete } } catch { Write-Error "$($_.Exception.Message)" } } end {} } #EndRegion Remove-LocalAdmin #Region Remove-UserProfile <# .SYNOPSIS Quickly delete a user profile from a computer .DESCRIPTION This command will delete user profiles for the local or remote computer. .PARAMETER Username Specify the specific username(s) for the profile(s) to be deleted. .PARAMETER ComputerName Specify a remote computer name to remove user profiles from. .PARAMETER All This switch will query all non-special profiles for deletion. .PARAMETER Except This switch is used to exclude profiles when specifying the `-All` switch. .EXAMPLE PS> Remove-UserProfile test123 Description ----------- This will delete the local `test123` account on the local computer. If this account / profile does not exist, you will get an error. .EXAMPLE PS> Remove-UserProfile -All -ComputerName Some-Remote-PC1 Description ----------- This will delete all non-special profiles on the remote computer. .EXAMPLE PS> Remove-UserProfile user1,user2,user3 -ComputerName Some-Remote-PC1 -Verbose Description ----------- This will attempt to remove all named user accounts (comma-seperated) from the remote computer and display verbose output. .EXAMPLE PS> Remove-UserProfile -ComputerName Some-Remote-PC1 -All -Except user1,specialuser,user4 Description ----------- This will remove all user profiles EXCEPT for the ones listed in the `-Except` parameter. .NOTES Author: Matthew J. DeGarmo Handle: @TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Remove-UserProfile() { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High', DefaultParameterSetName = 'Named')] Param ( [Parameter(Mandatory, ParameterSetName = 'Named')] [System.String[]] $UserName, [Parameter(ParameterSetName = 'Named')] [Parameter(ParameterSetName = 'All')] [System.String] $ComputerName, [Parameter(Mandatory, ParameterSetName = 'All')] [Switch] $All, [Parameter(ParameterSetName = 'All')] [System.String[]] $Except ) Begin {} Process { Try { if ($PSBoundParameters.ContainsKey('All')) { $Params = @{} $Confirm = $true if ($PSBoundParameters.ContainsKey('ComputerName')) { $Params += @{ ComputerName = $ComputerName.ToUpper() } } else { $ComputerName = $env:COMPUTERNAME } $AllProfiles = Get-UserProfile @Params if ($PSBoundParameters.ContainsKey('Except')) { $Except | ForEach-Object { $ExceptUser = $_ Write-Output "Removing $ExceptUser from the deletion list. Will not delete user: $ExceptUser" $AllProfiles = $AllProfiles | Where-Object { $_.LocalPath -notlike "*$ExceptUser*" } } } if ($null -ne $AllProfiles) { if ($PSCmdlet.ShouldProcess($AllProfiles, "Delete all profiles from this computer except for any exceptions listed.")) { Write-Verbose "Removing all user profiles from computer: $ComputerName" $Total = $AllProfiles.Count $Position = 0 Write-Progress -Activity "Deleting Profiles from Computer: $ComputerName" $AllProfiles | ForEach-Object { $Percent = [int]$(($Position / $Total) * 100) $Progress = @{ Activity = "Removing profile for user: $(Split-Path $_.LocalPath -Leaf)" Status = "Removing profile $Position of $Total" PercentComplete = (($Position / $Total) * 100) CurrentOperation = "$Percent%" } Write-Progress @Progress Remove-CimInstance -InputObject $_ $Position++ } } } else { Write-Error "There are no user profiles to remove with the specified criteria. Username: $User Computername: $ComputerName" } } else { $Params = @{ } if ($PSBoundParameters.ContainsKey('ComputerName')) { $Params += @{ ComputerName = $ComputerName.ToUpper() } } else { $ComputerName = $env:COMPUTERNAME } $Username | ForEach-Object { $User = $_ $UserProfile = Get-UserProfile @Params | Where-Object { $_.LocalPath -match $User } if ($UserProfile) { Write-Verbose "Removing user profile $User on $ComputerName" $UserProfile | Remove-CimInstance -Whatif:$Whatif -Confirm:$Confirm } else { Write-Error "There are no user profiles to remove with the specified criteria. Username: $User Computername: $ComputerName" } } } } Catch { Write-Error "$($_.Exception.Message)" } } End {} } #EndRegion Remove-UserProfile #Region Reset-Password <# .SYNOPSIS Reset domain password for an ActiveDirectory user. .DESCRIPTION Sets a Active Directory Password and provides an option to require a password change on login. .PARAMETER Username Specify the username to reset the password for. .PARAMETER Password Specify the password to set. By default, a strong, random password is generated, unless a password is provided. .PARAMETER ComputerName Specify the computer name that the user would be sitting at. This will attempt to display a popup on their screen displaying the new password. .PARAMETER RequireReset With this switch present, the user will be forced to reset their password immediately after signing in. .PARAMETER Admin With this switch present, a stronger random password will be auto-generated. #Security .EXAMPLE PS> Reset-Password someuser1 Username Password -------- -------- someuser1 xh9GKKtN!64v Description ----------- Calls `New-Password` .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Reset-Password() { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] [string] $Username, [Parameter()][SecureString] [string] $Password, [string] $ComputerName, [Switch] $RequireReset = $false, [Switch] $Admin ) if ([String]::IsNullOrEmpty($Password)) { #Many domain admin accounts do not start with an alpha character. Edit this for your needs. if ($Username[0] -notmatch '[a-zA-Z]' -or $Admin.IsPresent) { $NewPasswordArgs = @{Admin = $True } } else { $NewPasswordArgs = @{} } $SecurePassword = New-Password @NewPasswordArgs | ConvertTo-SecureString -AsPlainText -Force } else { $SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force } $ResetPasswordArgs = @{ Username = $Username RequireReset = $RequireReset } try { Set-Password @ResetPasswordArgs -Password $SecurePassword [pscustomobject] @{ Username = $Username NewPassword = ($SecurePassword | Get-PlainText) } #Copies $SecurePassword | Get-PlainText | Clip if ($PSBoundParameters.ContainsKey('ComputerName')) { Send-DesktopPopupMessage -ComputerName $ComputerName -Message "Password: $($SecurePassword | Get-PlainText)" } } catch { Write-Error "$($_.Exception.Message)" } } #EndRegion Reset-Password #Region Send-DesktopPopupMessage <# .SYNOPSIS Send individual Pop-up message to remote host. .DESCRIPTION This script sends a custom pop-up message to desired server/host with no options or required action. This script must be run as an Administrator. .PARAMETER ComputerName This parameter is to specify the remote PC to attempt to send a message popup to. This parameter needs to pass a Test-Connection to attempt to send the message. .PARAMETER Message This parameter should be inside quotation marks. This will be the text to be displayed in the popup. .PARAMETER Seconds This parameter specifies the number of seconds that the popup will remain on the screen before auto-closing. This has a default value of 120. .EXAMPLE PS> Send-DesktopPopupMessage -ComputerName computer1,FakeServer -Message "This is a test message. Get back to work!" [06/05/2019 09:46:36] : Message to computer1 sent successfully. [06/05/2019 09:46:36] : Unable to establish a connection with FAKESERVER. ___________________________________ | Message from 6/5/2019 9:46 AM |X| |_________________________________| | This is a test message. Get back| | to work! | | From: Matthew J. DeGarmo | | ComputerName: SourceServer __ | | |OK|| |_________________________________| Description ----------- This will create a small popup window on the target computer with the message text, and the From: and ComputerName: information at the bottom. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Send-DesktopPopupMessage() { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [string[]] $ComputerName, [Parameter(Mandatory = $true, Position = 1)] [string] $Message, [Parameter(Position=2)] [int] $Seconds = 120 ) begin { $ComputerName = $ComputerName.ToUpper() $Username = (Get-ADUser -Identity $Env:Username | Select-Object Name).Name $LocalComputer = $Env:COMPUTERNAME } process { try { foreach ($Computer in $ComputerName) { if (Test-Connection $Computer -Count 1 -Quiet -ErrorAction Stop) { try { Write-Output "Sending message to Computer: $Computer..." Invoke-Command -ComputerName $Computer -ScriptBlock { C:\windows\system32\msg.exe * /time:$using:Seconds "$using:Message From: $using:Username Source: $using:LocalComputer" } } catch { Write-Error "Failed to send message to $ComputerName." } } else { Write-Error "Unable to establish a connection with $Computer." } } "" } catch { Write-Error "$($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" } } } #EndRegion Send-DesktopPopupMessage #Region Start-MSRA <# .SYNOPSIS Starts Microsoft Remote Assistance .DESCRIPTION This function is set to work with the helpdesk mode of Windows Remote Assistance. You can either enter a computer name and the function will attempt to start a connection to the remote computer. If no computer name is specified Windows Remote Assistance will open to the Advanced Help Desk Mode, which is where you can enter a computer name to connect to. .PARAMETER ComputerName This parameter is for the remote computer you wish to connect to. By default if you don’t specify a remote computer Windows Remote Assistant will open up to the helpdesk screen. .EXAMPLE PS C:\> Start-MSRA computer1 Description ----------- This example shows how to call the Start-MSRA function and automatically connect to the remote computer. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Start-MSRA() { [CmdletBinding()] param ( [Parameter(Mandatory = $false, HelpMessage = 'This is the remote computer you wish to connect to.')] [Alias('CN')] [string] $ComputerName = "" ) If ($ComputerName -eq "") { Start-Process -FilePath "C:\Windows\System32\msra.exe" -Args "/Offerra" } Else { If (Test-Connection -ComputerName $ComputerName -Count 2 -Quiet) { Start-Process -FilePath "C:\Windows\System32\msra.exe" -Args "/Offerra \\$ComputerName" } Else { Return "Failed to Connect to $ComputerName" } } } #EndRegion Start-MSRA #Region Test-Administrator <# .SYNOPSIS Test to see if the current user / process is being run as an Administrator. .DESCRIPTION Test if the credentials running this function are elevated on the local system. .PARAMETER User Specify the windows identity to test. This defaults to the current signed-in user running the command. .EXAMPLE PS> Test-Administrator Description ----------- This will return a boolean based on if the user is an admin or not. .NOTES Author: Matthew J. DeGarmo Handle: @TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Test-Administrator() { [CmdletBinding()] param ( $User = [Security.Principal.WindowsIdentity]::GetCurrent() ) (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) } #EndRegion Test-Administrator #Region Unlock-LockedOutADUsers <# .SYNOPSIS This function performs an unlock of users in ActiveDirectory who are currently locked out. .DESCRIPTION This function is a simple wrapper for Unlock-ADAccount. .OUTPUTS None This function does not produce output except for write-output data .PARAMETER SAMAccountName Specify the SAMAccountName or username of the AD User you want to unlock. .EXAMPLE PS>Unlock-LockedOutADUsers -SAMAccountName matthewjd Unlocking: matthewjd Description ----------- This will unlock the AD Account for user 'matthewjd'. .EXAMPLE PS>Get-LockedOutADUsers | Unlock-LockedOutADUsers Unlocking: User1 Unlocking: User2 Description ----------- This gets a list of all current locked out users from Get-LockedOutADUsers and forwards each user to Unlock-LockedOutADUsers, which effectively unlocked all currently locked AD Users A short-handed command for this using aliases: PS> glo | ul .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Unlock-LockedOutADUsers() { [CmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('Username')] [string[]]$SAMAccountName ) begin {} process { try { foreach ($Username in $SAMAccountName) { Write-Output "Unlocking: $Username" Unlock-ADAccount -Identity $Username -ErrorAction Stop } } catch { Write-Error "$($_.Exception.Message)" } } } #EndRegion Unlock-LockedOutADUsers #Region Watch-Connection <# .SYNOPSIS Loops through a test-connection and sends email when connection is made. .DESCRIPTION This script simply is a test-connection that loops until a connection is made. .PARAMETER ComputerName This parameter should specify the computer name you are testing a connections with. .PARAMETER Message This parameter will include text to be included in the success email. .PARAMETER Recipients This parameter specifies additional recipients to receive the successful connection email. These values should be separated by commas and wrapped in quotation marks. .PARAMETER Email This switch allows the function to send an email when a successful connection is made. If this switch is present, an email will be sent. .PARAMETER From This is the email address that this alert will originate from. .PARAMETER SmtpServer This is the SMTP server that you will be using to send the email. .EXAMPLE PS>Watch-Connection -ComputerName SomeServer -Message "A connection to SomeServer has been made. Please remove admin access from user 'SomeUser'" -Recipients "myself@me.com","someoneelse@them.com","OtherEmailsSeperatedByCommas@site.com" Connecting to SOMESERVER.... Sending email to the following recipients: "myself@me.com","someoneelse@them.com","OtherEmailsSeperatedByCommas@site.com" Connection Successful. Message: A connection to SomeServer has been made. Please remove admin access from user 'SomeUser' Description ----------- This will loop through a Test-Connection -Count 1 command against 'SomeServer' until a connection is made. Once it is made, an email is sent to the user running the script and to the additional users specified in the -Recipients Parameter. .EXAMPLE PS>Watch-Connection SomeComputer -Notification "Finally connected to user 'SomeUser' PC." Connecting to SOMECOMPUTER.... Connection Successful. Message: Finally connected to user 'SomeUser' PC. Description ----------- This will loop through a `Test-Connection -Count 1` command against 'SomeComputer'. .NOTES Author: Matthew J. DeGarmo GitHub: https://github.com/TechDufus You can either submit a [PR](https://github.com/TechDufus/HelpDesk/pulls) or create an [Issue](https://github.com/TechDufus/HelpDesk/issues/new) on this GitHub project at https://github.com/TechDufus/HelpDesk #> Function Watch-Connection() { [cmdletbinding()] param( [parameter(Mandatory = $true, Position = 1)] [ValidateNotNullOrEmpty()] [string] $ComputerName, [string ]$Message, [string[]] $Recipients, [switch] $Email, [String] $From, [String] $SmtpServer ) begin { $ComputerName = $ComputerName.ToUpper() } process { try { DO { Clear-Host Write-Host "Connecting to $ComputerName." -ForegroundColor Yellow Start-Sleep -Milliseconds 500 Clear-Host Write-Host "Connecting to $ComputerName.." -ForegroundColor Yellow Start-Sleep -Milliseconds 500 Clear-Host Write-Host "Connecting to $ComputerName..." -ForegroundColor Yellow Start-Sleep -Milliseconds 500 Clear-Host Write-Host "Connecting to $ComputerName...." -ForegroundColor Yellow } while (-not(Test-Connection $ComputerName -count 1 -ErrorAction SilentlyContinue)) if (Test-Connection $ComputerName -count 1 -ErrorAction SilentlyContinue) { if ($Email.IsPresent) { $MessageArgs = @{ To = $Recipients From = $From Subject = "$ComputerName Online" SmtpServer = $SmtpServer Priority = 'High' Body = "$ComputerName is now online. <p>$Message</p> <p></p><n>From: $env:USERNAME</n> <p></p><n>Source: $env:COMPUTERNAME</n>" } Write-Output "Sending email to the following recipients: $Recipients" Send-MailMessage @MessageArgs -BodyAsHtml } Write-Host 'Connection Successful.' -ForegroundColor Green if ($Message) { Write-Output "Message: $Message" } } } catch { Write-Error "$($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" } } end {} } #EndRegion Watch-Connection |