AdminToolkit.psm1
#Region $AdminToolkitADComputernameArgCompleter $AdminToolkitADComputernameArgCompleter = { param ($CommandName, $ParameterName, $StringMatch) if ($null -eq $StringMatch) { $Filter = "*" } else { $Filter = "*$StringMatch*" } (Get-ADComputer -filter { Name -like $Filter }).Name } Register-ArgumentCompleter -CommandName Push-LocalScheduledTask,Get-RebootLogs,Clear-CCMCache -ParameterName ComputerName -ScriptBlock $AdminToolkitADComputernameArgCompleter #EndRegion $AdminToolkitADComputernameArgCompleter #Region $AdminToolkitScheduledTaskNameArgCompleter $AdminToolkitScheduledTaskNameArgCompleter = { param ($CommandName, $ParameterName, $StringMatch) $Tasks = (Get-ScheduledTask | Where-Object { $_.TaskName -match "$StringMatch" }).TaskName $QuotedTasks = foreach ($Task in $Tasks) { $QuotedTask = "`"$Task`"" $QuotedTask } return $QuotedTasks } Register-ArgumentCompleter -CommandName Push-LocalScheduledTask -ParameterName TaskName -ScriptBlock $AdminToolkitScheduledTaskNameArgCompleter #EndRegion $AdminToolkitScheduledTaskNameArgCompleter #Region Test-IsIpAddressInRange <# .SYNOPSIS Test to see if a given IP is between a given start and end address. .DESCRIPTION Provide the IP Range (Start and End Address) and the IP to check. This function will return True or False. .PARAMETER IpAddress Specify the IP to test if it is in a specific range. .PARAMETER StartAddress Specify the start IP Address for the range you want to test. .PARAMETER EndAddress Specify the end IP Address for the range you want to test. .EXAMPLE Test-IsIpAddressInRange -IpAddress 10.10.0.235 -StartAddress 10.10.0.0 -EndAddress 10.10.120.0 Description ----------- This will return True, since 10.10.0.235 is within the given Start and End addresses. .NOTES Author: Matthew DeGarmo GitHub: https://github.com/matthewjdegarmo #> Function Test-IsIpAddressInRange() { [CmdletBinding()] Param( [Parameter(Mandatory)] [System.String] $IpAddress, [Parameter(Mandatory)] [System.String] $StartAddress, [Parameter(Mandatory)] [System.String] $EndAddress ) $ip = [System.Net.IPAddress]::Parse($IpAddress).GetAddressBytes() [array]::Reverse($ip) $ip = [System.BitConverter]::ToUInt32($ip, 0) $Start = [System.Net.IPAddress]::Parse($StartAddress).GetAddressBytes() [array]::Reverse($Start) $Start = [System.BitConverter]::ToUInt32($Start, 0) $End = [System.Net.IPAddress]::Parse($EndAddress).GetAddressBytes() [array]::Reverse($End) $End = [System.BitConverter]::ToUInt32($End, 0) $Start -le $ip -and $ip -le $End } #EndRegion Test-IsIpAddressInRange #Region Aliases Set-Alias -Name GD -Value Get-Definition Set-Alias -Name Watch -Value Watch-Command #EndRegion Aliases #Region Clear-Arp <# .SYNOPSIS Use Netsh to clear ArpCache .DESCRIPTION Clears the local arp table .EXAMPLE PS> Clear-Arp Description ----------- This will clear the arpcache on the local machine. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Clear-Arp() { [CmdletBinding()] param() netsh.exe interface ip delete arpcache } #EndRegion Clear-Arp #Region Clear-CCMCache <# .SYNOPSIS Clear local CCM Cache. .DESCRIPTION This command will clear the local or remote ccm cache. .PARAMETER ComputerName Specify the remote system to connect to and clear. .EXAMPLE PS> Clear-CCMCache Description ----------- Clear the CCM Cache on the local system. .EXAMPLE PS> Clear-CCMCache -ComputerName Some-Remote-PC Description ----------- This will attempt to connect and clear the CCM Cache from the computer specified. .EXAMPLE PS> Clear-CCMCache -ComputerName pc1,pc2,pc3,pc4,pc5 Description ----------- This will attempt to connect to each computer listed to clear the local CCM Cache. .NOTES Author: Matthew J. DeGarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Clear-CCMCache() { [CmdletBinding()] param( [Parameter()] [System.String[]] $ComputerName = $env:COMPUTERNAME ) begin {} process { try { Invoke-Command -ComputerName $ComputerName -ScriptBlock { Write-Output "Clearing CCM Cache on $($env:COMPUTERNAME)" ## Initialize the CCM resource manager com object [__comobject]$CCMComObject = New-Object -ComObject 'UIResource.UIResourceMgr' ## Get the CacheElementIDs to delete $CacheInfo = $CCMComObject.GetCacheInfo().GetCacheElements() ## Remove cache items ForEach ($CacheItem in $CacheInfo) { $null = $CCMComObject.GetCacheInfo().DeleteCacheElement([string]$($CacheItem.CacheElementID)) } } } catch { Write-Error "$($_.Exception.Message)" } } end {} } #EndRegion Clear-CCMCache #Region Copy-WithProgress <# .SYNOPSIS This function performs a copy of a specified object recursively to a specified location. .DESCRIPTION This function is a glorified Copy-Item in that it will show progress data. If moving 10,000 files that equal 2GB in size, it will show you what file you are currently on as well as how much data has been moved / what is left using Write-Progress. .PARAMETER Path Source should specify the object to be copied by name. This value must be the FullPath and cannot be shortened. An example would be if you were in the C:\Scripts directory, you could not specify '.\TestFile.ps1' as the source location, you must specify 'C:\Scripts\TestFile.ps1' in this case. .PARAMETER Destination Destination should specify the target location of the specified Source by name. This value must be the FullPath and cannot be shortened. An example would be if you were in the C:\Scripts directory, you could not specify '.\TestFile.ps1' as the Destination location, you must specify 'C:\Scripts\TestFile.ps1' in this case .PARAMETER IncludeACL With this present, this will copy the ACL from each source file and apply it to the destination file. .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 the Write-Progress data. .EXAMPLE PS>Copy-WithProgress -Source "C:\Scripts\TestFile.ps1" -Destination "C:\Temp\TestFile.ps1" Description ----------- This will copy the source file to the file specified in Destination. Note that the filename for Destination can be anything and does not have to match the original. .EXAMPLE PS>Copy-WithProgress -Source .\Folder -Destination .\Folder1 -IncludeACL Description ----------- This will copy all contents of .\Folder to .\Folder1 and include the Acl / NTFS permissions. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Copy-WithProgress() { [CmdletBinding()] Param ( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [Alias('Source')] $Path, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] $Destination, [Parameter()] [Switch] $IncludeACL ) Write-Progress -Activity "Gathering data from $Path" $Source = (Resolve-Path -Path $Path).Path.Replace('Microsoft.PowerShell.Core\FileSystem::', '').ToLower() $Destination = $Destination.Replace('Microsoft.PowerShell.Core\FileSystem::', '').ToLower() $Filelist = Get-Childitem $Source -Recurse $Total = $Filelist.count $Position = 0 $Size = ($Filelist | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum Write-Progress -Activity "Gathering data from $Source" -Completed foreach ($File in $Filelist) { switch ($Size) { { $_ -ge '1000000000' } { $TotalSize = "{0:N2} GB" -f ($_ / 1GB) } { ($_ -lt '1000000000') -and ($_ -ge '10000000') } { $TotalSize = "{0:N2} MB" -f ($_ / 1MB) } { $_ -lt '1000000' } { $TotalSize = "{0:N2} KB" -f ($_ / 1KB) } } $FileSize = ($File | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum $Filename = $File.Fullname.ToLower().Replace($Source, '').Replace('Microsoft.PowerShell.Core\FileSystem::', '') $DestinationFile = Join-Path $Destination $FileName $Position++ $Percent = [int]$(($Position / $Total) * 100) Write-Progress -Activity "Copying data from '$Source' to '$Destination'" -Status "Copying File $Position of $total - $TotalSize remaining..." -PercentComplete (($Position / $total) * 100) -CurrentOperation "$Percent% complete" #$null = New-Item -Name $File.FullName -Path $DestinationFile -ItemType File -Force $null = Copy-Item $File.FullName -Destination $DestinationFile -Force -ErrorAction SilentlyContinue -Container If ($IncludeACL.IsPresent) { $SourceFileACL = Get-Acl -Path $File.FullName Set-Acl -Path $DestinationFile -AclObject $SourceFileACL } $Size = ($Size - $FileSize) } Write-Progress -Activity "Moving data from '$Source' to '$Destination'" -Completed } #EndRegion Copy-WithProgress #Region DateStamp <# This is to pass the cmdlet exporting pester tests since this is a filter Function DateStamp() { #> <# .SYNOPSIS This is a filter used to place timestamps on any output messages. .DESCRIPTION The function `TimeStamp` is a colorized version of this command `DateStamp`, but `TimeStamp` output cannot be written to a file. You will want to use `DateStamp` if you are going to output your messages into a log or txt file. .EXAMPLE "ERROR: Something bad happened on this line of the script" | DateStamp [08/04/2020 11:34:35]: ERROR: Something bad happened on this line of the script Description ----------- This line will place a time stamp at the beginning of the line that can be written to a file. .NOTES Author: Matthew J. DeGarmo Site: https://matthewjdegarmo.github.io You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Filter DateStamp() { [CmdletBinding()] param() process { Write-Output "[$(Get-Date -Format "MM/dd/yyyy HH:mm:ss")]: $_" } } #EndRegion DateStamp #Region Enable-Remoting <# .Synopsis Enable PSRemoting via PSEXEC remotely. .Description This Command will enable PowerShell Remoting on a remote PC. .PARAMETER ComputerName Specify a remote computer to run against. .PARAMETER Username Specify a username to use to make the remote connection. .PARAMETER Password Specify the respective password to match the Username provided. .EXAMPLE PS> Enable-PSRemoting -computer PCName -username domain\username Description ----------- This will enable remoting and then prompt for credentials .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit Change Log: Version: 1.0 - Function Creation. This Function requires psexec. If you do not, download it with the sysinternals suite. Add psexec to one of your enviroment variable paths. #> Function Enable-Remoting() { [CmdletBinding()] Param ( [Parameter(Position = 0, Mandatory)] [string] $ComputerName, [Parameter(Position = 1, Mandatory)] [string] $Username, [Parameter(Position = 2)] [SecureString] $Password ) #Enabling PSRemoting PsExec.exe \\$ComputerName -s winrm.cmd quickconfig -q PsExec.exe \\$ComputerName -u $Username -p $Password powershell.exe cmd /c "enable-psremoting -force" try { Test-WSMan $Computer } catch { Write-Error "Failed to enable PSRemoting via PSEXEC" } } #EndRegion Enable-Remoting #Region Get-Applications <# .SYNOPSIS List locally installed applications .DESCRIPTION Query local registry for installed applications. .EXAMPLE PS> Get-Applications Description ----------- This will generate all installed applications on the local system. .NOTES Author: Matthew J. DeGarmo Site: https://matthewjdegarmo.github.io You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-Applications() { [CmdletBinding()] param() $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" Get-ChildItem -Path $RegPath | Get-ItemProperty | Sort-Object DisplayName } #EndRegion Get-Applications #Region Get-CIDRNotationBySubnetMask <# .SYNOPSIS Quickly generate the CIDR "slash" notation for a given subnet mask. .DESCRIPTION This will provide the CIDR value for a subnet mask. This function will also error if the subnet mask is not valid. .PARAMETER SubnetMask Specify the subnet mask to generate the CIDR Notation for. .EXAMPLE PS> Get-CIDRNotationBySubnetMask 255.255.255.0 24 Description ----------- Providing the SubnetMask, this returns the correct CIDR abreviation. CIDR is used like this: 192.168.1.0/24 .NOTES Author: Matthew J. DeGarmo Site: https://matthewjdegarmo.github.io You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-CIDRNotationBySubnetMask() { [CmdletBinding()] param ( [Parameter(Mandatory, Position = 0)] [String] $SubnetMask ) $cidr = 0 $octet = 0 $SubnetMask.split(".") | Foreach-Object { switch ($_) { 255 { $cidr += 8 ; $CorrectSubnet += "$_." } 254 { $cidr += 7 ; $CorrectSubnet += "$_." } 252 { $cidr += 6 ; $CorrectSubnet += "$_." } 248 { $cidr += 5 ; $CorrectSubnet += "$_." } 240 { $cidr += 4 ; $CorrectSubnet += "$_." } 224 { $cidr += 3 ; $CorrectSubnet += "$_." } 192 { $cidr += 2 ; $CorrectSubnet += "$_." } 128 { $cidr += 1 ; $CorrectSubnet += "$_." } 0 { $cidr += 0 ; $CorrectSubnet += "$_." } default { $SplitSubnet = $SubnetMask.Split('.') $SplitSubnet[$octet] = "[$($SplitSubnet[$octet])]" $ErrorSubnet = $SplitSubnet -join '.' Write-Error -Message "Invalid Subnet Mask value: `'$_`' in $ErrorSubnet" ` -Category InvalidArgument ` -RecommendedAction "Provide a proper SubnetMask" ` -ErrorAction Stop $BadMask = $true } } $octet++ } if (-Not ($BadMask)) { $cidr } } #EndRegion Get-CIDRNotationBySubnetMask #Region Get-ContentWithLineNumbers <# .Synopsis Mimic Unix / Linux tool nl number lines .Description Print file content with numbered lines no original nl options supported .PARAMETER FileName Specify a file to extract and prefix with line numbers. .PARAMETER InputObject Specify an object of text to prefix with line numbers. .Example PS> Get-ContentWithLineNumbers -FileName C:\Foo.txt Description ----------- This will append line numbers to the begninning of each line in the Foo.txt file. .NOTES Author: Matthew J. DeGarmo Site: https://matthewjdegarmo.github.io You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-ContentWithLineNumbers() { [CmdletBinding()] param ( [parameter(mandatory = $true, Position = 0, ValueFromPipeline, ParameterSetName = 'File')] [String]$FileName, [Parameter(ParameterSetName = 'Input')] $InputObject ) process { if ($PSBoundParameters.ContainsKey('FileName')) { If (Test-Path $FileName) { $Data = Get-Content $FileName | ForEach-Object { "{0,5} {1}" -f $_.ReadCount, $_ } } $Data } elseif ($PSBoundParameters.ContainsKey('Input')) { $inData = New-Object -TypeName System.IO.StringReader -ArgumentList $InputObject $Data = While ($Line = $InData.ReadLine()) { $Line } $Data | ForEach-Object { "{0,5} {1}" -f $_.ReadCount, $_ } } } } #EndRegion Get-ContentWithLineNumbers #Region Get-Definition <# .SYNOPSIS Gets the back-end definition of a function. .DESCRIPTION This function will export a string of the code that defines a function. .PARAMETER Function This parameter takes a function name, or an alias name, to generate the function definition. .EXAMPLE PS> Get-Definition Get-Definition Description ----------- This will get the function definitnion for the `Get-Definition` command itself. .EXAMPLE PS> Get-Definition glo | Clip Description ----------- This will get the definition for the `glo` aliased command, and pipe it into your clipboard using the clip.exe file. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-Definition() { [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Function ) $null = Get-Command -Name $Function -ErrorAction SilentlyContinue $Alias = (Get-Alias -Name $Function -ErrorAction SilentlyContinue).ResolvedCommand.Name if ($Alias) { Write-Warning "'$Function' is an alias for '$Alias'. Running 'Get-Definition -Function $Alias'." $Function = $Alias } $FunctionDefinition = (Get-Command -name $Function | Select-Object -ExpandProperty Definition) $returnDefinition = [System.Text.StringBuilder]::New() $null = $returnDefinition.Append("function $Function`() {") $null = $returnDefinition.Append($FunctionDefinition) $null = $returnDefinition.Append('}') $returnDefinition.ToString() } #EndRegion Get-Definition #Region Get-FileOwner <# .Synopsis Display the owner of an item(s) .Description This Function lists file owners within a given path .PARAMETER Path Specify the file / directory path to query. .PARAMETER Recursive Search recursively. .Example PS> Get-FileOwner C:\Users Description ----------- This will list file owners recursively for this directory. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-FileOwner() { [CmdletBinding()] param( [Parameter(Mandatory, Position = 0)] [string] $Path, [switch]$Recursive ) $LastWrite = @{ Name = 'Last Write Time' Expression = { $_.LastWriteTime.ToString('u') } } $Owner = @{ Name = 'File Owner' Expression = { (Get-Acl $_.FullName).Owner } } $HostName = @{ Name = 'Host Name' Expression = { $env:COMPUTERNAME } } Get-ChildItem @PSBoundParameters | Select-Object $HostName, $Owner, Name, Directory, $LastWrite, Length } #EndRegion Get-FileOwner #Region Get-FolderSize <# .SYNOPSIS Quickly calculate the size of a directory. .DESCRIPTION This function will calculate the disk space used by a specified directory. This uses the current directory by default. .PARAMETER Folder Specify the folder to query. This defaults to the current directory. .PARAMETER ComputerName Specify a remote computer to get the folder size of. NOTE: The `-Folder` path will still need to be the local path for the remote computer Example: Get-FolderSize -ComputerName Some-Remote-PC -Folder C:\Windows\System .EXAMPLE PS> Get-FolderSize Description ----------- This will display the folder size of the current folder location `Get-Location` .EXAMPLE PS> Get-FolderSize -ComputerName Some-Remote-PC -Folder C:\Windows\System Description ----------- This will get the folder size of the C:\Windows\System folder on the remote pc specified. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-FolderSize() { [CmdletBinding()] Param ( [Parameter( Position = 0, ValueFromPipeline )] [System.String] $Folder = (Get-Location), [Parameter()] [System.String] $ComputerName ) Begin { } Process { If ($ComputerName) { $Size = Invoke-Command -ComputerName $ComputerName -ScriptBlock { (Get-ChildItem $using:Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum } } Else { $Size = (Get-ChildItem $Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum } switch ($Size) { { ($_ -lt '1000000000000000') -and ($_ -ge '1000000000000') } { $TotalSize = "{0:N2} TB" -f ($_ / 1TB) } { ($_ -lt '1000000000000') -and ($_ -ge '1000000000') } { $TotalSize = "{0:N2} GB" -f ($_ / 1GB) } { ($_ -lt '1000000000') -and ($_ -ge '1000000') } { $TotalSize = "{0:N2} MB" -f ($_ / 1MB) } { $_ -lt '1000000' } { $TotalSize = "{0:N2} KB" -f ($_ / 1KB) } } $TotalSize } } #EndRegion Get-FolderSize #Region Get-IPv4NetworkInfo <# .SYNOPSIS Gets extended information about an IPv4 network. .DESCRIPTION Gets Network Address, Broadcast Address, Wildcard Mask. and usable host range for a network given the IP address and Subnet Mask. .PARAMETER IPAddress IP Address of any ip within the network Note: Exclusive from @CIDRAddress .PARAMETER SubnetMask Subnet Mask of the network. Note: Exclusive from @CIDRAddress .PARAMETER CIDRAddress CIDR Notation of IP/Subnet Mask (x.x.x.x/y) Note: Exclusive from @IPAddress and @SubnetMask .PARAMETER IncludeIPRange Switch parameter that defines whether or not the script will return an array of usable host IP addresses within the defined network. Note: This parameter can cause delays in script completion for larger subnets. .EXAMPLE Get-IPv4NetworkInfo -IPAddress 192.168.1.23 -SubnetMask 255.255.255.0 Get network information with IP Address and Subnet Mask .EXAMPLE Get-IPv4NetworkInfo -CIDRAddress 192.168.1.23/24 Get network information with CIDR Notation .NOTES File Name : Get-IPv4NetworkInfo.ps1 Author : Ryan Drane Date : 5/10/16 Requires : PowerShell v3 .LINK www.ryandrane.com #> Function Get-IPv4NetworkInfo() { [CmdletBinding()] Param( [Parameter(ParameterSetName = "IPandMask", Mandatory = $true)] [ValidateScript( { $_ -match [ipaddress]$_ })] [System.String]$IPAddress, [Parameter(ParameterSetName = "IPandMask", Mandatory = $true)] [ValidateScript( { $_ -match [ipaddress]$_ })] [System.String]$SubnetMask, [Parameter(ParameterSetName = "CIDR", Mandatory = $true)] [ValidateScript( { $_ -match '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/([0-9]|[0-2][0-9]|3[0-2])$' })] [System.String]$CIDRAddress, [Switch]$IncludeIPRange ) # If @CIDRAddress is set if ($CIDRAddress) { # Separate our IP address, from subnet bit count $IPAddress, [int32]$MaskBits = $CIDRAddress.Split('/') # Create array to hold our output mask $CIDRMask = @() # For loop to run through each octet, for ($j = 0; $j -lt 4; $j++) { # If there are 8 or more bits left if ($MaskBits -gt 7) { # Add 255 to mask array, and subtract 8 bits $CIDRMask += [byte]255 $MaskBits -= 8 } else { # bits are less than 8, calculate octet bits and # zero out our $MaskBits variable. $CIDRMask += [byte]255 -shl (8 - $MaskBits) $MaskBits = 0 } } # Assign our newly created mask to the SubnetMask variable $SubnetMask = $CIDRMask -join '.' } # Get Arrays of [Byte] objects, one for each octet in our IP and Mask $IPAddressBytes = ([ipaddress]::Parse($IPAddress)).GetAddressBytes() $SubnetMaskBytes = ([ipaddress]::Parse($SubnetMask)).GetAddressBytes() # Declare empty arrays to hold output $NetworkAddressBytes = @() $BroadcastAddressBytes = @() $WildcardMaskBytes = @() # Determine Broadcast / Network Addresses, as well as Wildcard Mask for ($i = 0; $i -lt 4; $i++) { # Compare each Octet in the host IP to the Mask using bitwise # to obtain our Network Address $NetworkAddressBytes += $IPAddressBytes[$i] -band $SubnetMaskBytes[$i] # Compare each Octet in the subnet mask to 255 to get our wildcard mask $WildcardMaskBytes += $SubnetMaskBytes[$i] -bxor 255 # Compare each octet in network address to wildcard mask to get broadcast. $BroadcastAddressBytes += $NetworkAddressBytes[$i] -bxor $WildcardMaskBytes[$i] } # Create variables to hold our NetworkAddress, WildcardMask, BroadcastAddress $NetworkAddress = $NetworkAddressBytes -join '.' $BroadcastAddress = $BroadcastAddressBytes -join '.' $WildcardMask = $WildcardMaskBytes -join '.' # Now that we have our Network, Widcard, and broadcast information, # We need to reverse the byte order in our Network and Broadcast addresses [array]::Reverse($NetworkAddressBytes) [array]::Reverse($BroadcastAddressBytes) # We also need to reverse the array of our IP address in order to get its # integer representation [array]::Reverse($IPAddressBytes) # Next we convert them both to 32-bit integers $NetworkAddressInt = [System.BitConverter]::ToUInt32($NetworkAddressBytes, 0) $BroadcastAddressInt = [System.BitConverter]::ToUInt32($BroadcastAddressBytes, 0) #Calculate the number of hosts in our subnet, subtracting one to account for network address. $NumberOfHosts = ($BroadcastAddressInt - $NetworkAddressInt) - 1 # Declare an empty array to hold our range of usable IPs. $IPRange = @() # If -IncludeIPRange specified, calculate it if ($IncludeIPRange) { # Now run through our IP range and figure out the IP address for each. For ($j = 1; $j -le $NumberOfHosts; $j++) { # Increment Network Address by our counter variable, then convert back # lto an IP address and extract as string, add to IPRange output array. $IPRange += [ipaddress]([convert]::ToDouble($NetworkAddressInt + $j)) | Select-Object -ExpandProperty IPAddressToString } } # Create our output object $obj = New-Object -TypeName psobject # Add our properties to it Add-Member -InputObject $obj -MemberType NoteProperty -Name "IPAddress" -Value $IPAddress Add-Member -InputObject $obj -MemberType NoteProperty -Name "SubnetMask" -Value $SubnetMask Add-Member -InputObject $obj -MemberType NoteProperty -Name "NetworkAddress" -Value $NetworkAddress Add-Member -InputObject $obj -MemberType NoteProperty -Name "BroadcastAddress" -Value $BroadcastAddress Add-Member -InputObject $obj -MemberType NoteProperty -Name "WildcardMask" -Value $WildcardMask Add-Member -InputObject $obj -MemberType NoteProperty -Name "NumberOfHostIPs" -Value $NumberOfHosts Add-Member -InputObject $obj -MemberType NoteProperty -Name "IPRange" -Value $IPRange # Return the object return $obj } #EndRegion Get-IPv4NetworkInfo #Region Get-Management <# .SYNOPSIS Open Computer management .DESCRIPTION Opens Computer management connected for a PC, local or remote. Default is local. .PARAMETER ComputerName Specify a remote computer to run against. .Example PS> Get-Management Test-999999-H Description ----------- This will open computer management for this remote PC, if you are an admin on that PC. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-Management() { [CmdletBinding()] Param ( [Parameter(Position = 0)]$ComputerName = $env:ComputerName ) compmgmt.msc /computer:$ComputerName } #EndRegion Get-Management #Region Get-PasswordExpired <# .SYNOPSIS Generates list of ActiveDirectory users who have expired passwords .DESCRIPTION Returns a list of Active Directory Accounts with expired passwords .EXAMPLE PS> Get-PasswordExpired Description ----------- This will get all of the current accounts with expired passwords. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-PasswordExpired() { [CmdletBinding()] param () Search-ADAccount -PasswordExpired } #EndRegion Get-PasswordExpired #Region Get-PCInfo <# .Synopsis Gather useful information from a remote PC. .Description Returns useful informaion on the local endpoint or another. .PARAMETER ComputerName Specify a remote computer to generate information for. .EXAMPLE PS> Get-PCInfo -ComputerName Computer1 Description ----------- This will generate information from the remote computer using CIM Instances. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-PCInfo() { [CmdletBinding()] Param ( [string]$ComputerName = $env:ComputerName ) try { $SystemEnclosure = Get-CimInstance win32_systemenclosure -computername $ComputerName -ErrorAction Stop $OS = Get-CimInstance Win32_OperatingSystem -Computername $ComputerName -ErrorAction Stop } catch { Write-Error "$($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" break } #Creating Hash table from variables $PCInfo = @{ Manufacturer = $SystemEnclosure.Manufacturer PCName = $OS.CSName OS = $OS.Caption Architecture = $OS.OSArchitecture AssetTag = $systemenclosure.serialnumber; OSVersion = $OS.Version InstallDate = $OS.InstallDate LastBootUpTime = $OS.LastBootUpTime } #Writing to Host Write-Host " " Write-Host "Computer Info" -Foregroundcolor Cyan Write-Host "If not run on a Dell machine AssetTag is the Serial Number" -Foregroundcolor Yellow #Display Hash Table $PCInfo.getenumerator() | Sort-Object -property name | Format-Table -autosize #Writing to Host Write-Host "Computer Disk Info" -Foregroundcolor Cyan #Display Drives Get-CimInstance win32_logicaldisk -filter "drivetype=3" -computer $ComputerName | Format-Table -Property DeviceID, Volumename, ` @{Name = "SizeGB"; Expression = { [math]::Round($_.Size / 1GB) } }, ` @{Name = "FreeGB"; Expression = { [math]::Round($_.Freespace / 1GB, 2) } }, ` @{Name = "PercentFree"; Expression = { [math]::Round(($_.Freespace / $_.size) * 100, 2) } } #Writing to Host Write-Host "Network Information" -Foregroundcolor Cyan Get-CimInstance win32_networkadapterconfiguration -computer $ComputerName | Where-Object { $null -ne $_.IPAddress } | Select-Object IPAddress, DefaultIPGateway, DNSServerSearchOrder, IPSubnet, MACAddress, Caption, DHCPEnabled, DHCPServer, DNSDomainSuffixSearchOrder | Format-List } #EndRegion Get-PCInfo #Region Get-PCUpTime <# .SYNOPSIS Get the amount of time since the last boot-up sequence for a computer. .DESCRIPTION This cmdlet uses Get-CimInstance to gather the .LastBootUpTime for the local or remote computer. PowerShell 7 comes with a `Get-Uptime` cmdlet, so if called from PowerShell, it will simply call or invoke that cmdlet. otherwise when called from Windows Powershell, it will invoke a CimInstance. .PARAMETER ComputerName Specify the remote computer to query using CIM. .EXAMPLE PS> Get-PCUpTime Description ----------- This will return the current UpTime value for the local computer. .EXAMPLE PS> Get-PCUpTime Remote-Server Description ----------- This will query `Remote-Server` for it's uptime data. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-PCUpTime() { [CmdletBinding()] param( [Parameter(ValueFromPipeline)] $ComputerName ) begin { $Version = $PSVersionTable.PSEdition } process { try { switch($Version) { 'Desktop' { if ($null -ne $ComputerName) { $SplatMe = @{ ClassName = 'Win32_OperatingSystem' ComputerName = $ComputerName} } else { $SplatMe = @{ ClassName = 'Win32_OperatingSystem' } } $Now = Get-Date $LastBootUpTime = (Get-CimInstance @SplatMe -ErrorAction Stop).LastBootUpTime $Return = $Now - $LastBootUpTime return $Return } 'Core' { if ($null -ne $ComputerName) { $PCFunctionDefinition = Get-Definition Get-PCUpTime $Script = @" $PCFunctionDefinition Get-PCUpTime "@ $ScriptBlock = { param ($Script) . ([ScriptBlock]::Create($Script)) } $params = @{ ComputerName = $ComputerName ScriptBlock = $ScriptBlock ArgumentList = $Script } Invoke-Command @params } else { Get-Uptime } } DEFAULT {} } } catch { Write-Error "$($_.Exception.Message)" } } } #EndRegion Get-PCUpTime #Region Get-Printers <# .SYNOPSIS Get printers for local or remote PC .Description This function will attempt to gather printer information for a local or remote PC. .PARAMETER ComputerName Specify the remote computer to query. .EXAMPLE PS> Get-Printers Description ----------- This will generate local printer information. .EXAMPLE PS> Get-Printers -ComputerName Some-Remote-Computer1 Description ----------- This will generate printer information for the remote computer `Some-Remote-Computer1' via a Cim Instance. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-Printers() { [CmdletBinding()] Param ( [Parameter(Mandatory = $false)] [String] $ComputerName ) $Params = @{ ClassName = 'CIM_Printer' } if ($ComputerName) { $Params += @{ComputerName = $ComputerName } } Get-CimInstance @Params | Select-Object Name, Drivername, Portname, Status, SystemName, local, shared, CapabilityDescriptions } #EndRegion Get-Printers #Region Get-PrintManagement <# .SYNOPSIS Quickly launch Print Management MSC Snap-in .DESCRIPTION Opens Print Management for the local PC and one remote PC using -ComputerName .PARAMETER ComputerName Specify the remote computer to open Print Management against. .EXAMPLE PS> Get-PrintManagement -ComputerName Computer1 Description ----------- This will open PrintManagement on the local machine and connect to the remote `Computer1` .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-PrintManagement() { [CmdletBinding()] param ( [string[]]$ComputerName = $env:COMPUTERNAME ) printmanagement.msc /computer:$ComputerName } #EndRegion Get-PrintManagement #Region Get-PublicIP <# .SYNOPSIS Generates your current Public IP Information .DESCRIPTION Returns WhoIS public IP info for your location or any specified public IP. By Default, returns your current public IP info. .PARAMETER IP Specify the IP Address to look up information for. This uses your current public IP by default. .EXAMPLE PS> Get-PublicIP Description ----------- Returns local Public IP Info Get-PublicIP .Example PS> Get-PublicIP -IP 8.8.8.8 Description ----------- Returns Public IP Info for 8.8.8.8 Get-PublicIP -IP 8.8.8.8 .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Get-PublicIP() { [CmdletBinding()] Param ( [Parameter(Position = 0)]$IP ) try { if ($IP) { $ipinfo = Invoke-RestMethod http://ipinfo.io/$IP/json } else { $ipinfo = Invoke-RestMethod http://ipinfo.io/json } [PSCustomObject]@{ IP = $ipinfo.ip City = $ipinfo.city Region = $ipinfo.region Country = $ipinfo.country Coord = $ipinfo.loc Organization = $ipinfo.org Postal = $ipinfo.Postal TimeZone = $ipinfo.timezone } } catch { Write-Error "$($_.Exception.Message)" } } #EndRegion Get-PublicIP #Region Get-RebootLogs <# .SYNOPSIS Get the System Event logs for reboot ID 1074. .DESCRIPTION This will pull system event logs for the local or remote computer. .PARAMETER ComputerName Specify a remote computer to pull logs from. .EXAMPLE PS> Get-RebootLogs Description ----------- This will generate a list of all System Reboot log events with ID 1074 on the local system. .EXAMPLE PS> Get-RebootLogs -ComputerName Some-Remote-Computer | Select -First 5 Description ----------- This will get the System Reboot logs from `Some-Remote-Computer` and only show the first 5 results. .NOTES Author: Matthew J. DeGarmo Site: https://matthewjdegarmo.com You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> function Get-RebootLogs() { [CmdletBinding()] param ( [Parameter()] [string] $ComputerName = $env:COMPUTERNAME ) begin {} process { try { $params = @{ LogName = 'System' ComputerName = $ComputerName.ToUpper() ErrorAction = 'SilentlyContinue' Verbose = $Verbose } Write-Verbose "Gathering $($params.LogName) logs from $($params.ComputerName) with ID 1074." Get-WinEvent @params | Where-Object { $_.ID -eq '1074' } } catch { Write-Error "$($_.Exception.Message)" } } end {} } #EndRegion Get-RebootLogs #Region Get-WindowsBuild <# .SYNOPSIS Gets Windows Build information. .DESCRIPTION This will query the local PC OR an array of remote PC's .PARAMETER ComputerName Specify the remote computer to query. .INPUTS System.String[] You must specify the value for Credential. You cannot pipe a value to this function. .OUTPUTS None There are no outputs. .EXAMPLE PS> ConnectTeams Description ----------- This will attempt a connection to portal.office.com. This will prompt you for account information like what password to use. .EXAMPLE PS> ConnectTeams -Credential 'SomeAccount@Email.com' Description ----------- This will attempt a connection to portal.office.com. This will prompt you for account information like what password to use. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> function Get-WindowsBuild() { [CmdletBinding()] param ( [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true )] [string[]]$ComputerName = $env:COMPUTERNAME ) begin { $Table = New-Object System.Data.DataTable $Table.Columns.AddRange(@("ComputerName", "Windows Edition", "Version", "OSBuild")) } process { Foreach ($Computer in $ComputerName) { $Code = { $ProductName = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ProductName).ProductName try { $Version = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ReleaseID -ErrorAction Stop).ReleaseID } catch { $Version = "N/A" } $CurrentBuild = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name CurrentBuild).CurrentBuild $UBR = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name UBR).UBR $OSVersion = $CurrentBuild + "." + $UBR $TempTable = New-Object System.Data.DataTable $TempTable.Columns.AddRange(@("ComputerName", "Windows Edition", "Version", "OSBuild")) [void]$TempTable.Rows.Add($env:COMPUTERNAME, $ProductName, $Version, $OSVersion) return $TempTable } if ($Computer -eq $env:COMPUTERNAME) { $Result = Invoke-Command -ScriptBlock $Code [void]$Table.Rows.Add($Result.Computername, $Result.'Windows Edition', $Result.Version, $Result.'OSBuild') } else { if (Test-Connection $Computer -count 1 -ErrorAction SilentlyContinue) { try { $Result = Invoke-Command -ComputerName $Computer -ScriptBlock $Code -ErrorAction Stop [void]$Table.Rows.Add($Result.Computername, $Result.'Windows Edition', $Result.Version, $Result.'OSBuild') } catch { $_ } } else { [void]$Table.Rows.Add($Computer, "OFFLINE", "OFFLINE", "OFFLINE") } } } } end { Return $Table } } #EndRegion Get-WindowsBuild #Region grep $DetectedOS = switch($true) { $IsWindows {'Windows'} $IsLinux {'Linux'} $IsMacOS {'MacOS'} DEFAULT {'Windows'} } If ($DetectedOS -eq 'Windows') { <# .SYNOPSIS Basic version of the linux command `grep` on Windows. .DESCRIPTION This is a windows version of the linux `grep` command. I still need to figure out how to NOT import this command when on a linux system. This is basically a shorter `Select-String`, and does not support other grep flags as on a Linux system. .PARAMETER Regex Specify the regex pattern to filter for. .EXAMPLE Get-Process | grep powershell Description ----------- This will filter the `Get-Process` output with the regex 'powershell'. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function grep() { # [CmdletBinding()] # This is to pass the advanced function pester tests. param( $regex ) process { $_ | Where-Object { $_ -match $regex } } } } #EndRegion grep #Region Invoke-Speech <# .SYNOPSIS Translate a string into an audible message. .DESCRIPTION This function calls the SAPI.SPVoice class to invoke audio given a string. This is useful when running long processes, you can audibly be alerted that a task is finished. .PARAMETER Message Specify the message to have voiced. .EXAMPLE PS> Get-SomeDataThatTakesAnHour;Invoke-Speech -Message "Your data is ready, sir." Description ----------- This will generated audio for the string 'Your data is ready, sir." depending on your volume level. .NOTES Author: Matthew J. DeGarmo Site: https://matthewjdegarmo.github.io You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Invoke-Speech() { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [string]$Message ) begin { #Set Variables for the Invoke-Speech Function $voice = New-Object -ComObject SAPI.SPVoice $voice.Rate = -2 } process { $voice.Speak($Message) | out-null; } } #EndRegion Invoke-Speech #Region LL <# .SYNOPSIS This is a colorized version of Get-ChildItem (dir, ls). .DESCRIPTION This function will change the color of object names using Get-ChildItem based on the object type or extension. You can define more extensions and their associated colors if you wish. .PARAMETER Directory Specify the directory to get items for. Default is '.' or current directory. .PARAMETER All Essentially this is a `-Force` switch on Get-ChildItem. By default this is set to $false. .EXAMPLE PS> LL C:\Temp Description ----------- Display a colorized output for `Get-ChildItem` at C:\Temp. .EXAMPLE PS> ll Description ----------- Display a colorized output for `Get-ChildItem` at the current working directory. .NOTES Author: Matthew J. DeGarmo Site: https://matthewjdegarmo.github.io You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function LL() { [CmdletBinding()] param ( [String] $Directory = ".", $All = $false ) $originalForeground = $host.ui.rawui.foregroundColor if ( $All ) { $toList = Get-ChildItem -force $Directory } else { $toList = Get-ChildItem $Directory } foreach ($Item in $toList) { Switch ($Item.Extension) { ".Exe" { $host.ui.rawui.foregroundColor = "Yellow" } ".cmd" { $host.ui.rawui.foregroundColor = "Red" } ".lnk" { $host.ui.rawui.foregroundColor = "Red" } ".msh" { $host.ui.rawui.foregroundColor = "Red" } ".vbs" { $host.ui.rawui.foregroundColor = "Red" } ".ps1" { $host.ui.rawui.foregroundColor = "Cyan" } ".psm1" { $host.ui.rawui.foregroundColor = "Cyan" } ".psd1" { $host.ui.rawui.foregroundColor = "Cyan" } ".ps1xml" { $host.ui.rawui.foregroundColor = "Cyan" } ".txt" { $host.ui.rawui.foregroundColor = "DarkCyan" } ".xml" { $host.ui.rawui.foregroundColor = "Magenta" } ".cvs" { $host.ui.rawui.foregroundColor = "Magenta" } ".doc" { $host.ui.rawui.foregroundColor = "Magenta" } ".csv" { $host.ui.rawui.foregroundColor = "Magenta" } ".bat" { $host.ui.rawui.foregroundColor = "Yellow" } ".docx" { $host.ui.rawui.foregroundColor = "Magenta" } ".pdf" { $host.ui.rawui.foregroundColor = "Magenta" } ".xls" { $host.ui.rawui.foregroundColor = "Magenta" } ".xlsx" { $host.ui.rawui.foregroundColor = "Magenta" } ".log" { $host.ui.rawui.foregroundColor = "DarkCyan" } Default { $host.ui.rawui.foregroundColor = $originalForeground } } if ($item.Mode.StartsWith("d")) { $host.ui.rawui.foregroundColor = "Green" } $item } $host.ui.rawui.foregroundColor = $originalForeground } #EndRegion LL #Region LLM <# .SYNOPSIS This is a quick way to lock your workstation. .DESCRIPTION LLM is to stand for 'Lock Local Machine'. This will lock the current session on a windows workstation. Will need to add functionality to lock a linux or mac. .EXAMPLE PS> llm Description ----------- This will quickly lock the current workstation. .NOTES Author: Matthew J. DeGarmo Site: https://matthewjdegarmo.github.io You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function llm() { [CmdletBinding()] param () $signature = @" [DllImport("user32.dll", SetLastError = true)] public static extern bool LockWorkStation(); "@ Write-Host "Locking local machine: $Env:COMPUTERNAME" -ForegroundColor Yellow $LockWorkStation = Add-Type -memberDefinition $signature -name "Win32LockWorkStation" -namespace Win32Functions -passthru $LockWorkStation::LockWorkStation() | Out-Null } #EndRegion LLM #Region Locate <# .SYNOPSIS Quickly search a location for a file, folder, hidden file, etc... This should return the same object that Get-ChildItem returns. .DESCRIPTION This function takes a -Filter and applies dual-wildcards for maximum search results. By default this will search recursively in the local directory, but you can specify any custom location. .PARAMETER Directory [<SwitchParameter>] Gets directories (folders). To get only directories, use the Directory parameter and omit the File parameter. To exclude directories, use the File parameter and omit the Directory parameter. To get directories, use the Directory parameter. .PARAMETER File [<SwitchParameter>] Gets files. To get only files, use the File parameter and omit the Directory parameter. To exclude files, use the Directory parameter and omit the File parameter. To get files, use the File parameter. .PARAMETER Hidden [<SwitchParameter>] Gets only hidden files and directories (folders). By default, Get-ChildItem gets only non-hidden items, but you can use the Force parameter to include hidden items in the results. To get only hidden items, use the Hidden parameter. To exclude hidden items, omit the Hidden parameter. .PARAMETER ReadOnly [<SwitchParameter>] Gets only read-only files and directories (folders). To get only read-only items, use the ReadOnly parameter, its "ar" alias, or the ReadOnly value of the Attributes parameter. To exclude read-only items, use the Attributes parameter. .PARAMETER System [<SwitchParameter>] Gets only system files and directories (folders). To get only system files and folders, use the System parameter. .PARAMETER Force [<SwitchParameter>] Gets hidden files and folders. By default, hidden files and folder are excluded. You can also get hidden files and folders by using the Hidden parameter or the Hidden value of the Attributes parameter. .PARAMETER Exclude <String[]> Specifies, as a string array, an item or items that this cmdlet excludes in the operation. The value of this parameter qualifies the Path parameter. Enter a path element or pattern, such as *.txt. Wildcards are permitted. .PARAMETER Include <String[]> Specifies, as a string array, an item or items that this cmdlet includes in the operation. The value of this parameter qualifies the Path parameter. Enter a path element or pattern, such as *.txt. Wildcards are permitted. The Include parameter is effective only when the command includes the Recurse parameter or the path leads to the contents of a directory, such as C:\Windows\*, where the wildcard character specifies the contents of the C:\Windows directory. .PARAMETER Filter <String> Specifies a filter in the provider's format or language. The value of this parameter qualifies the Path parameter. The syntax of the filter, including the use of wildcards, depends on the provider. Filters are more efficient than other parameters, because the provider applies them when retrieving the objects, rather than having Windows PowerShell filter the objects after they are retrieved. .PARAMETER Path <String[]> Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.). .PARAMETER Recurse [<SwitchParameter>] Indicates that this cmdlet gets the items in the specified locations and in all child items of the locations. In Windows PowerShell 2.0 and earlier versions of Windows PowerShell, the Recurse parameter works only when the value of the Path parameter is a container that has child items, such as C:\Windows or C:\Windows\ , and not when it is an item does not have child items, such as C:\Windows\ .exe. By Default, this is set to True. Use -Recurse:$false to turn off recursive results. .EXAMPLE PS> Locate AdminToolkit.psd1 -Recurse Description ----------- This will search from the current working directory for files or folders mathing the filter 'AdminToolkit.psd1' .EXAMPLE PS> locate foo.txt C:\temp Description ----------- This will search for the file foo.txt in the directory C:\temp. .EXAMPLE PS> locate test -Recurse -Exclude *.tests.* Directory: C:\Temp\HelpDesk\Functions\Public Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 8/5/2020 11:51 AM 6985 Test-Administrator.ps1 Directory: C:\Temp\HelpDesk Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 8/5/2020 2:07 PM Tests Description ----------- This will search recursively using the filter 'test' and exclude files/folders that match '*.tests.*' .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit Change Log: Version: 1.0 - Function Creation. #> Function Locate() { [CmdletBinding()] param ( [Parameter(Position = 0)] [string]$Filter, [Parameter(Position = 1)] [string]$Path = (Get-Location), [string[]]$Include, [string[]]$Exclude, [switch]$Force, [switch]$Recurse, [switch]$Directory, [switch]$File, [switch]$System, [switch]$Hidden, [switch]$ReadOnly ) if (-Not($PSBoundParameters.Filter)) { $PSBoundParameters.Filter = '*' } else { $PSBoundParameters.Filter = "*$Filter*" } Get-ChildItem @PSBoundParameters -ErrorAction SilentlyContinue } #EndRegion Locate #Region Merge-CIDRIpRanges <# .SYNOPSIS Reduces a list of CIDR IP Ranges to a single list of ranges that do not overlap. .DESCRIPTION Given a list of CIDR IP Ranges, this will remove CIDR IP Ranges that overlap / are nested within other ranges in the list. When an overlap is found, the CIDR Range that survives the filter is the larger range. EXAMPLE: If the provided list contains 3.134.215.0/24 and 3.132.0.0/14 ranges, the range that will be kept is 3.132.0.0/14 since it is the larger range and contains the other. .PARAMETER CIDRAddresses Provide an array of CIDR IP Ranges (IP.Add.Re.SS/## format). .EXAMPLE Merge-CIDRIpRanges -CIDRAddresses $TotalCIDRIps Description ----------- This will remove any overlapping IP Ranges from your provided array of CIDR ranges in $TotalCIDRIps .EXAMPLE Merge-CIDRIpRanges -CIDRAddresses (Get-AWSPublicIpAddressRange -Region us-east-2 | ? IpAddressFormat -eq 'Ipv4').IpPrefix Description ----------- This AWS Function will return the entire AWS IpRange set for us-east-2. This function will remove any duplicate and overlapping ranges from this provided list. .NOTES Author: Matthew DeGarmo GitHub: https://github.com/matthewjdegarmo .LINK https://matthewjdegarmo.com #> Function Merge-CIDRIpRanges() { [CmdletBinding()] Param( [Parameter(Mandatory)] [ValidateScript( { $_ -match '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/([0-9]|[0-2][0-9]|3[0-2])$' })] [System.String[]] $CIDRAddresses ) Begin { #Region Get-Ipv4SubnetInfo Function Get-Ipv4SubnetInfo() { [CmdletBinding()] Param( [Parameter(ParameterSetName = "CIDR", Mandatory = $true)] [ValidateScript( { $_ -match '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/([0-9]|[0-2][0-9]|3[0-2])$' })] [System.String]$CIDRAddress ) # Separate our IP address, from subnet bit count $IPAddress, [int32]$MaskBits = $CIDRAddress.Split('/') # Create array to hold our output mask $CIDRMask = @() # For loop to run through each octet, for ($j = 0; $j -lt 4; $j++) { # If there are 8 or more bits left if ($MaskBits -gt 7) { # Add 255 to mask array, and subtract 8 bits $CIDRMask += [byte]255 $MaskBits -= 8 } else { # bits are less than 8, calculate octet bits and # zero out our $MaskBits variable. $CIDRMask += [byte]255 -shl (8 - $MaskBits) $MaskBits = 0 } } # Assign our newly created mask to the SubnetMask variable $SubnetMask = $CIDRMask -join '.' # Get Arrays of [Byte] objects, one for each octet in our IP and Mask $IPAddressBytes = ([ipaddress]::Parse($IPAddress)).GetAddressBytes() $SubnetMaskBytes = ([ipaddress]::Parse($SubnetMask)).GetAddressBytes() # Declare empty arrays to hold output $NetworkAddressBytes = @() $BroadcastAddressBytes = @() $WildcardMaskBytes = @() # Determine Broadcast / Network Addresses, as well as Wildcard Mask for ($i = 0; $i -lt 4; $i++) { # Compare each Octet in the host IP to the Mask using bitwise # to obtain our Network Address $NetworkAddressBytes += $IPAddressBytes[$i] -band $SubnetMaskBytes[$i] # Compare each Octet in the subnet mask to 255 to get our wildcard mask $WildcardMaskBytes += $SubnetMaskBytes[$i] -bxor 255 # Compare each octet in network address to wildcard mask to get broadcast. $BroadcastAddressBytes += $NetworkAddressBytes[$i] -bxor $WildcardMaskBytes[$i] } # Create variables to hold our NetworkAddress, WildcardMask, BroadcastAddress $NetworkAddress = $NetworkAddressBytes -join '.' $BroadcastAddress = $BroadcastAddressBytes -join '.' [pscustomobject]@{ IPAddress = $IPAddress NetworkAddress = $NetworkAddress BroadcastAddress = $BroadcastAddress } } #EndRegion Get-Ipv4SubnetInfo $CIDRAddresses = $CIDRAddresses | Select-Object -Unique } Process { [System.Collections.ArrayList]$RejectedIPs = @() $Index = 0 $CIDRAddresses | ForEach-Object { $Index++ $RootIP = $_ #When we reach the last entry of the list, there is no nested loop to run, so we can simply end here. #Otherwise the nested compare will compare to itself, add to the reject list, and will NEVER survive, even its is a non-overlapping IP. If ($Index -eq ($CIDRAddresses.Count)) { If ($RootIP -notin $RejectedIPs) { $RootIP break } } $IpInfo = Get-Ipv4SubnetInfo -CIDRAddress $RootIP $ProgressPercent = ($Index / ($CIDRAddresses.count) * 100) $Percent = "$([math]::round($ProgressPercent,2))%" $Progress = @{ Activity = "Filtering Overlapping CIDR IP Ranges" Status = "Examining IP: [$RootIP] - $Percent" CurrentOperation = "IP: $Index of $($CIDRAddresses.Count)" Id = 1 PercentComplete = $ProgressPercent } Write-Progress @Progress Write-Debug "Beginning compare of: [$RootIP]" [System.Collections.ArrayList]$Reject = @() [System.Collections.ArrayList]$Survivor = @() $NestedIndex = 0 $CIDRAddresses[$Index..$($CIDRAddresses.Count - 1)] | ForEach-Object { $NestedIndex++ $CompareIP = $_ Write-Debug "Comparing [$RootIP] to [$CompareIP]" $CompareIPInfo = Get-Ipv4SubnetInfo -CIDRAddress $CompareIP $NestedProgressPercent = ($NestedIndex / $($CIDRAddresses.Count - 1) * 100) $Progress = @{ Activity = "Comparing [$RootIP] to full array of CIDR Ranges" Status = "Comparing: [$RootIP] to [$CompareIP]" CurrentOperation = "IP: $NestedIndex of $($CIDRAddresses.Count - $Index)" ParentId = 1 PercentComplete = $NestedProgressPercent } Write-Progress @Progress $RangeCompareRootToNested = @{ IPAddress = $CompareIPInfo.IpAddress StartAddress = $IPInfo.NetworkAddress EndAddress = $IPInfo.BroadcastAddress } If (Test-IsIpAddressInRange @RangeCompareRootToNested) { Write-Verbose "$($CompareIP) is inside range $($RootIP)" $null = $Survivor.Add($RootIP) $null = $Reject.Add($CompareIP) } $RangeCompareNestedToRoot = @{ IPAddress = $IPInfo.IpAddress StartAddress = $CompareIPInfo.NetworkAddress EndAddress = $CompareIPInfo.BroadcastAddress } If (Test-IsIpAddressInRange @RangeCompareNestedToRoot) { Write-Verbose "$($RootIP) is inside range $($CompareIP)" $null = $Survivor.Add($CompareIP) $null = $Reject.Add($RootIP) } } If ($Reject) { Foreach ($Ip in @($Reject | Select-Object -Unique)) { Write-Verbose "Adding Reject: $Ip" $null = $RejectedIPs.Add($Ip) } } If ($Survivor) { Foreach ($Ip in ($Survivor | Select-Object -Unique)) { If ($IP -notin $RejectedIPs) { Write-Debug "[$IP] not in [$RejectedIPs]" $IP } } } Else { If ($RootIP -notin $RejectedIPs) { $RootIP } } } } End {} } #EndRegion Merge-CIDRRanges #Region New-Folder <# .SYNOPSIS Easily create a new folder in the current working directory. .DESCRIPTION This will create a new directory in the current working directory. .PARAMETER Name Spedify the name for the new folder. .EXAMPLE PS> New-Folder Foobar Description ----------- This will create a new folder 'Foobar' if there currently is not a folder of the same name. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function New-Folder() { [CmdletBinding()] param ( [Parameter(Mandatory, Position = 0)] [string] $Name ) process { New-Item $Name -ItemType Directory } } #EndRegion New-Folder #Region PSRemote <# .SYNOPSIS Starts an Enter-PSSession with the specified Server. .DESCRIPTION PSRemote will attempt to enter a PSSession with a specified host with a specified account. If no Credential is specified, it will use the currently signed in account to connect. .PARAMETER ComputerName This parameter specifies what host to attempt an Enter-PSSession with. .PARAMETER Credential This parameter is used to change the current account for the PSSession. .PARAMETER IncludeModule This parameter specifies any local installed / imported modules to be defined in the remote scope. Essentially bringing any local modules with you without installing them on the remote machine. .PARAMETER IncludeProfile Specify a local profile to load in the remote session. .INPUTS System.String[] You must specify the value for Computername. You cannot pipe a value to this function. .OUTPUTS None There are no outputs except for Write-Host messages. .EXAMPLE PS> PSRemote -ComputerName Computer1 -Credential matthewjd Description ----------- This will attempt to start a PSSession with Computer1 as matthewjd. This will prompt for a password for matthewjd. .EXAMPLE PS> PSRemote Computer1 -IncludeModule AdminToolkit Description ----------- This will use the currently signed in account to connect to attempt a connection with Computer1 and import the module Helpdesk. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit Change Log: Version: 2.0 - Added -IncludeModule parameter. This will allow you to import a local module into your remote session. Version: 1.0 - Function Creation. #> Function PSRemote() { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [string]$ComputerName, [Parameter(Mandatory = $false, Position = 1)] [PSCredential]$Credential, [Parameter(Mandatory = $false)] [string[]]$IncludeModule, [Parameter(Mandatory = $false)] [string]$IncludeProfile ) begin { function Import-ModuleRemotely { Param ( [string] $moduleName, [System.Management.Automation.Runspaces.PSSession] $session ) Import-Module $moduleName -ErrorAction SilentlyContinue $Script = @" if (get-module $moduleName) { remove-module $moduleName; } New-Module -Name $moduleName { $($(Get-Module $moduleName).Definition) } | Import-Module "@ Invoke-Command -Session $Session -ScriptBlock { Param($Script) . ([ScriptBlock]::Create($Script)) #Get-Module } -ArgumentList $Script } } process { try { if ($Credential) { $Session = New-PSSession -ComputerName $ComputerName -Credential $credential -ErrorAction Stop } else { $Session = New-PSSession -ComputerName $ComputerName -ErrorAction Stop } if ($PSBoundParameters.ContainsKey('IncludeProfile')) { Invoke-Command -FilePath $IncludeProfile -Session $Session -ErrorAction Stop } if ($IncludeModule) { foreach ($Module in $IncludeModule) { Import-ModuleRemotely -moduleName $Module -session $Session } } Enter-PSSession -Session $Session -ErrorAction Stop } catch { Write-Error "$($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" } } } #EndRegion PSRemote #Region Push-LocalScheduledTask <# .SYNOPSIS Deploy a local scheduled task to a remote machine .DESCRIPTION This function exports the XML for a local scheduled task and creates that task on a remote machine. .PARAMETER ComputerName This parameter specifies the remote host(s) to create the task(s) on. This parameter supports tab-completion based on the current domain. I can type '-ComputerName cgo-2' and this will tab-complete computer objects in the current domain that match the string 'cgo-2' .PARAMETER TaskName This parameter specifies the local task name to export and create on a remote machine. I have not tested how to export nested tasks (See Register-ScheduledTask '-TaskPath' parameter) You can specify multiple task names, separated by comma please. .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. This credential is used for a task against the local pc, and the remote PC. because of this, the account used must have rights to do the required tasks on all computers involved. Type a user name, such as User01 or Domain01\User01 , or enter a PSCredential object generated by the `Get-Credential` cmdlet. If you type a user name, you're prompted to enter the password. Credentials are stored in a PSCredential (/dotnet/api/system.management.automation.pscredential)object and the password is stored as a SecureString (/dotnet/api/system.security.securestring). > [!NOTE] > For more information about SecureString data protection, see > How secure is SecureString? (/dotnet/api/system.security.securestring#how-secure-is-securestring). .PARAMETER Force Instructs the cmdlet to perform the operation without prompting for confirmation. Additionally this will overwrite any remote tasks with the same name. If you attempt to deploy a local task on a remote machine without using -Force, the export will fail. .PARAMETER PassThru I haven't gotten this switch to be accurate. Currently this function will ALWAYS spit out Scheduled Task objects that it creates whether -PassThru is present or not. The goal is to have the function not return objects if -PassThru is not present... like every other advanced function. .EXAMPLE PS>Deploy-LocalScheduledTask -ComputerName Computer1,Computer2 -TaskName "Task1","Task2" Description ----------- This will export both Task1 and Task2 scheduled tasks to both Computer1 and Computer2. .EXAMPLE PS>Deploy-LocalScheduledTask -ComputerName Computer1 -TaskName "Task1" -Credential (Get-Credential) -Force Description ----------- This will export the task Task1 to Computer1 using the provided credentials. You can also save the results of Get-Credential to a variable and use the '-Credential $cred' method. This will also overwrite a possible existing task named Task1 since -Force is used. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Push-LocalScheduledTask() { [CmdletBinding()] param( [Parameter(Mandatory)] [string[]] $ComputerName, [Parameter(Mandatory)] [string[]] $TaskName, [PSCredential] $Credential, [switch] $Force, #? Should this switch just be tossed? #TODO This switch doesn't do anything. Need to figure out how to supress Invoke-Command output for Register-ScheduledTask command. [switch] $PassThru ) begin { $ComputerName = foreach ($Computer in $ComputerName) { if (Test-Connection -ComputerName $Computer -Count 1 -ErrorAction SilentlyContinue) { $Computer } else { Write-Warning "Test-Connection to '$ComputerName' failed." } } } process { try { foreach ($Computer in $ComputerName) { $InvokeParams = @{ ComputerName = $Computer } if ($PSBoundParameters.ContainsKey('Credential')) { $InvokeParams += @{Credential = $Credential } } foreach ($Task in $TaskName) { if ($PSBoundParameters.ContainsKey('Credential')) { $TaskXML = Invoke-Command -ComputerName $env:COMPUTERNAME -Credential $Credential -Command { Export-ScheduledTask $using:Task | Out-String } } else { $TaskXML = Export-ScheduledTask $Task | Out-String } $TaskParams = @{ Xml = $TaskXML TaskName = $Task } if ($PSBoundParameters.ContainsKey('Force')) { $TaskParams += @{Force = $true } } if (-Not($PSBoundParameters.ContainsKey('PassThru'))) { $TaskParams += @{InformationAction = 'Ignore' } } Invoke-Command @InvokeParams -ScriptBlock { Register-ScheduledTask @using:TaskParams } } } } catch { Write-Error "$($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" } } end {} } #EndRegion Push-LocalScheduledTask #Region Remove-AllTempFiles <# .Synopsis Generic Cleanup of temp files on a computer. .Description This Command removes log files, temp files, and empties the recycle bin. Access denied errors do not indicate a failure of the script. Run for the local or a remote PC. .PARAMETER ComputerName Specify a remote computer to run against. .EXAMPLE PS> Remove-All Description ----------- Free up space on the local computer .EXAMPLE PS> Remove-All -Computer Test-PC-01 Description ----------- Free up space on a remote PC. May be more effective if run locally depending on in place security. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Remove-AllTempFiles() { [CmdletBinding(SupportsShouldProcess)] param ( [Parameter()]$ComputerName ) #Statement of Free Space before Cleaning Write-Host " " Write-Host "Free Space Before Cleaning" -ForegroundColor Yellow Get-CimInstance win32_logicaldisk -filter "drivetype=3" -computer $ComputerName | Format-Table -Property DeviceID, Volumename, ` @{Name = "SizeGB"; Expression = { [math]::Round($_.Size / 1GB) } }, ` @{Name = "FreeGB"; Expression = { [math]::Round($_.Freespace / 1GB, 2) } }, ` @{Name = "PercentFree"; Expression = { [math]::Round(($_.Freespace / $_.size) * 100, 2) } } #Statement that the function is freeing up space Write-Host "Freeing up space. Enjoy your Coffee!" -BackgroundColor Black -ForegroundColor Green #Free up space on the local or remote computer if ($null -ne $ComputerName) { $ErrorActionPreference = 'SilentlyContinue' Get-Service -ComputerName $ComputerName TrustedInstaller | Stop-Service -Force Get-ChildItem -path "\\$ComputerName\C$\windows\logs" -Include '*.log' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "\\$ComputerName\C$\windows\logs" -Include '*.cab' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "\\$ComputerName\C$\ProgramData\Microsoft\Windows\WER" -Include '*.*' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "\\$ComputerName\C$\`$recycle.bin" -Include '*' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "\\$ComputerName\C$\Users\*\AppData\Local\Google\Chrome\User Data\Default\Cache\" -include '*.*' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "\\$ComputerName\C$\Users\*\AppData\Local\Microsoft\Terminal Server Client\" -include '*.*' -Recurse -force | Remove-Item -force -Recurse $tempfolders = @("\\$ComputerName\C$\Windows\Temp\*", "\\$ComputerName\C$\Windows\Prefetch\*", "\\$ComputerName\C$\Documents and Settings\*\Local Settings\temp\*", "\\$ComputerName\C$\Users\*\Appdata\Local\Temp\*") Remove-Item $tempfolders -force -recurse -errorAction SilentlyContinue $tempinternetfolders = @("\\$ComputerName\C$\Users\*\Appdata\Local\Microsoft\Windows\INetCache\*", "\\$ComputerName\C$\Users\*\Appdata\Local\Microsoft\Windows\Cookies\*", "\\$ComputerName\C$\Users\*\AppData\Local\Microsoft\Windows\Temporary Internet Files\*.*") Remove-Item $tempinternetfolders -force -recurse -errorAction SilentlyContinue Get-Service -ComputerName $ComputerName -Name TrustedInstaller | Start-Service $ErrorActionPreference = 'Continue' Write-Host " " Write-Host "Free Space After Cleaning" -ForegroundColor Yellow Get-CimInstance win32_logicaldisk -filter "drivetype=3" -computer $ComputerName | Format-Table -Property DeviceID, Volumename, ` @{Name = "SizeGB"; Expression = { [math]::Round($_.Size / 1GB) } }, ` @{Name = "FreeGB"; Expression = { [math]::Round($_.Freespace / 1GB, 2) } }, ` @{Name = "PercentFree"; Expression = { [math]::Round(($_.Freespace / $_.size) * 100, 2) } } } else { $ErrorActionPreference = 'SilentlyContinue' Stop-Service TrustedInstaller -Force Get-ChildItem -path "C:\windows\" -Include '*.log' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "C:\windows\logs" -Include '*.cab' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "C:\ProgramData\Microsoft\Windows\WER" -Include '*.*' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "c:\`$recycle.bin" -Include '*' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "C:\Users\*\AppData\Local\Google\Chrome\User Data\Default\Cache\" -include '*.*' -Recurse -force | Remove-Item -force -Recurse Get-ChildItem -path "C:\Users\*\AppData\Local\Microsoft\Terminal Server Client\" -include '*.*' -Recurse -force | Remove-Item -force -Recurse $tempfolders = @("C:\Windows\Temp\*", "C:\Windows\Prefetch\*", "C:\Documents and Settings\*\Local Settings\temp\*", "C:\Users\*\Appdata\Local\Temp\*") Remove-Item $tempfolders -force -recurse -errorAction SilentlyContinue $tempinternetfolders = @("C:\Users\*\Appdata\Local\Microsoft\Windows\INetCache\*", "C:\Users\*\Appdata\Local\Microsoft\Windows\Cookies\*", "C:\Users\*\AppData\Local\Microsoft\Windows\Temporary Internet Files\*.*") Remove-Item $tempinternetfolders -force -recurse -errorAction SilentlyContinue powercfg.exe /hibernate off Remove-Item c:\hiberfil.sys -force -ErrorAction SilentlyContinue Start-Service TrustedInstaller $ErrorActionPreference = 'Continue' Write-Host " " Write-Host "Free Space After Cleaning" -ForegroundColor Yellow Get-CimInstance win32_logicaldisk -filter "drivetype=3" -computer $ComputerName | Format-Table -Property DeviceID, Volumename, ` @{Name = "SizeGB"; Expression = { [math]::Round($_.Size / 1GB) } }, ` @{Name = "FreeGB"; Expression = { [math]::Round($_.Freespace / 1GB, 2) } }, ` @{Name = "PercentFree"; Expression = { [math]::Round(($_.Freespace / $_.size) * 100, 2) } } } } #EndRegion Remove-AllTempFiles #Region Remove-Application <# .Synopsis Attempt to Uninstall an application. .DESCRIPTION This command uninstalls an application. Good for when elevated privileges are needed from a user session. .PARAMETER Application Specify the application name to delete. .EXAMPLE Specify the installed application being uninstalled. The full application name must be used. Remove-AppName -Application 'App Name has spaces' .EXAMPLE Find application using Get-Applications and pipe the correct item into Remove-Application. Get-Applications | Where-Object { $_.DisplayName -match 'vim' } | Remove-Application .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit Change Log: Version: 1.0 - Function Creation. #> Function Remove-Application() { [CmdletBinding()] Param ( [Parameter(Mandatory, ValueFromPipeline)] $Application ) Begin {} Process { if ($_ -is [PSCustomObject]) { $AppToRemove = $_ } else { $AppToRemove = Get-Applications | Where-Object { $_.DisplayName -match $Application } } switch ($true) { { $AppToRemove.QuietUninstallString } { Write-Output "Running Quiet Uninstall String: $($AppToRemove.QuietUninstallString)" & $AppToRemove.QuietUninstallString } { $AppToRemove.UninstallString } { Write-Output "Running Uninstall String: $($AppToRemove.UninstallString)" & $AppToRemove.UninstallString } DEFAULT { Write-Error "No Uninstall String is provided for this application." } } } } #EndRegion Remove-Application #Region Remove-OlderThan <# .Synopsis Remove files in a directory recursively based on how many days since the files was changed. Use negative values for -DaysBack. .Description This scripts function is to delete files and folders older than x days recursively. .PARAMETER Path Specify the root path to delete items from. .PARAMETER DaysBack Specify the amount of days old since a file was edited to delete. .PARAMETER Recurse Search recursively for files. .Example Delete-OlderThan -Path "C:\Folder" -DaysBack 90 .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit Change Log: Version: 1.0 - Function Creation. #> Function Remove-OlderThan() { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)]$Path, [Parameter(Mandatory = $true)][ValidateScript( { $_ -gt 0 })][int]$DaysBack, [Parameter(Mandatory = $false)][Switch]$Recurse ) $CurrentDate = Get-Date $DatetoDelete = $CurrentDate.AddDays("-$Daysback") Get-ChildItem $Path | Where-Object { $_.LastWriteTime -lt $DatetoDelete } | Remove-Item -Force } #EndRegion Remove-OlderThan #Region Remove-Path <# .Synopsis Deletes folder recursively, so be careful. If -Include is empty, it will delete all files, otherwise it will delete only the ones you -Include. .DESCRIPTION This command deletes all files recursively in a path that match the included filename. .PARAMETER Path Specify the path to recursively delete. .PARAMETER Include Restrict the deletion to specific file names, types, etc.. by specifying them in this parameter. See `Get-Help Get-ChildItem -Parameter Include` for more information. .EXAMPLE PS>Remove-Path C:\temp Description ----------- Specify the parent folder from which the command runs and specify file names to include. Wildcards are supported. Remove-Path -path c:\Folder -include "*.logs" .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Remove-Path() { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)]$Path, [Parameter(Mandatory = $true)]$Include ) Get-ChildItem -path "$Path" -Include "$Include" -Recurse -force | Remove-Item -force -Recurse } #EndRegion Remove-Path #Region Remove-PrintQueue <# .Synopsis Quickly clear print que from all installed printers. .DESCRIPTION This command clears print queues for all printers, including network printers. If you specify a single printer using -Printer, you will NOT clear all installed printers. .PARAMETER Printer Specify the printer name to clear. .EXAMPLE PS> Remove-PrintQueue -Printer Some_printer_name1 Description ----------- This will delete all of the current print jobs on the network printer 'Some_printer_name1' .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit Change Log: Version: 1.0 - Function Creation. #> Function Remove-PrintQueue() { [CmdletBinding()] param ( [string]$Printer ) if ($Printer) { $Printers = Get-Printer -Name *$Printer* } else { $Printers = Get-Printer } foreach ($printer in $printers) { $printjobs = Get-PrintJob -PrinterObject $printer foreach ($printjob in $printjobs) { Remove-PrintJob -InputObject $printjob } } } #EndRegion Remove-PrintQueue #Region Reset-NetworkAdapter <# .SYNOPSIS Reset a network interface. .DESCRIPTION Reset a specified interface with -Interface. .PARAMETER Interface Specify the name of the network interface name to reset. .EXAMPLE Reset-NetworkAdapter -Interface "Local Area Connection" .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit Change Log: Version: 1.0 - Function Creation. #> Function Reset-NetworkAdapter() { [CmdletBinding()] param ( [Parameter(Mandatory = $true)]$Interface ) netsh.exe interface set interface $Interface admin=disable netsh.exe interface set interface $Interface admin=enable } #EndRegion Reset-NetworkAdapter #Region Reset-NetworkStack <# .SYNOPSIS Reset Network Stack. Will require a reboot. .DESCRIPTION Resets the TCP/IP and Winsock Stacks .EXAMPLE PS> Reset-NetworkStack Description ----------- This will reset the winsock and ip, ipv4, and ipv6 interfaces. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit Change Log: Version: 1.0 - Function Creation. #> Function Reset-NetworkStack() { [CmdletBinding()] param ( ) netsh.exe winsock reset netsh.exe int ip reset netsh.exe int ipv4 reset reset.log netsh.exe int ipv6 reset reset.log Write-Output "[-] You will need to restart this computer." } #EndRegion Reset-NetworkStack #Region SU $DetectedOS = switch($true) { $IsWindows {'Windows'} $IsLinux {'Linux'} $IsMacOS {'MacOS'} DEFAULT {'Windows'} } If ($DetectedOS -eq 'Windows') { <# .SYNOPSIS Windows version of the linux command `SU` .DESCRIPTION Immitate SU on Linux. This creates new PoSH Session as an admin. .PARAMETER NoExit Default `su` will close the current session and launch a new one as admin Specify `-NoExit` to keep the non-admin shell running. .EXAMPLE PS> su Description ----------- Depending on what edition of powershell is running, this will start an elevated process and close the original process. .EXAMPLE PS> su -NoExit Description ----------- This will keep the non-admin shell running and you will have two processes open. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> function su() { [CmdletBinding()] param ( [Switch] $NoExit ) switch ($($PSVersionTable.PSEdition)) { "Desktop" { $Parent = (Get-Process -Id $PID) Switch($Parent.ProcessName) { 'powershell_ise' { Start-Process $Parent.Path -Verb RunAs } 'Code' { #TODO: Detect VSCode running powershell.exe somehow } DEFAULT { Start-Process Powershell -Verb RunAs } } } "Core" { $Parent = (Get-Process -Id $PID).Parent Switch($Parent.ProcessName) { 'WindowsTerminal' { Start-Process wt.exe -Verb RunAs If (-Not($NoExit.IsPresent)) { exit } } 'Code' { Start-Process $Parent.Path -Verb RunAs } DEFAULT { Start-Process Pwsh -Verb RunAs } } } } } } #EndRegion SU #Region TimeStamp <# This is to pass the cmdlet exporting pester tests since this is a filter Function TimeStamp() { #> <# .SYNOPSIS This is a filter used to place colorized timestamps on any output messages. .DESCRIPTION The function `TimeStamp` is a colorized version of this command `DateStamp`, but `TimeStamp` output cannot be written to a file. You will want to use `DateStamp` if you are going to output your messages into a log or txt file. .PARAMETER Color Specify the color to display the message text. See `[System.ConsoleColor].GetEnumNames()` for full list of colors. .PARAMETER NoNewLine Specify this to change the color of the first segment of text, and not the rest. See Example #3. .EXAMPLE "ERROR: Something bad happened on this line of the script" | TimeStamp [08/04/2020 11:55:39] : ERROR: Something bad happened on this line of the script Description ----------- This line will place a time stamp at the beginning of the line that can only be written to the console and not to a file. .EXAMPLE "ERROR: Something bad happened on this line of the script" | TimeStamp Red [08/04/2020 11:56:40] : ERROR: Something bad happened on this line of the script Description ----------- This will colorize the timestamp, and turn the provided string red. You can provide any color usable by Write-Host -ForegroundColor. .EXAMPLE "ERROR: " | TimeStamp Red NoNewLine;"Something bad happened on this line fo the script" [08/04/2020 11:58:54] : ERROR: Something bad happened on this line fo the script Description ----------- This will colorize the TimeStamp, and make "ERROR: " Red, and with `NoNewLine` provided, you can add additional non-colorized text to the same line. .NOTES Author: Matthew J. DeGarmo Site: https://matthewjdegarmo.github.io You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Filter TimeStamp($color, $NoNewLine) { # [CmdletBinding()] # This is to pass the advanced function pester tests. # param () # This is to pass the advanced function pester tests. # Function # This is to pass the advanced function pester tests. if ($color -eq 'NoNewLine') { $color = 'White' $NoNewLine = 'NoNewLine' } Write-Host "[" -ForegroundColor Yellow -NoNewLine Write-Host $(Get-Date -Format "MM/dd/yyyy HH:mm:ss") -ForegroundColor Green -NoNewLine Write-Host "] " -ForegroundColor Yellow -NoNewLine Write-Host ": " -ForegroundColor Red -NoNewLine if ($NoNewLine) { Write-Host "$_" -ForegroundColor $color -NoNewline } elseif (!$Color) { Write-Host "$_" } else { Write-Host "$_" -ForegroundColor $color } } #EndRegion TimeStamp #Region Update-PowerShell <# .SYNOPSIS This will both Install the latest release of PowerShell or update your current PowerShell. .DESCRIPTION This one-liner is provided by [Tyler Leonhardt](https://github.com/TylerLeonhardt). I have added some parameters to help customize the install of the .MSI .PARAMETER Preview Specifying this switch will install the latest preview version of PowerShell. Otherwise this will install / update the latest stable release. .PARAMETER Quiet Specifying this switch will install or update quietly with no gui popup, taking all defaults of the install. You need to run as admin to use this switch. .EXAMPLE PS> Update-Powershell -Preview Description ----------- This will update or install PowerShell with the latest Preview release. .EXAMPLE PS> Update-Powershell -Quiet Description ----------- This will update or install the latest General Release version of PowerShell. .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Update-PowerShell() { [CmdletBinding()] param( [switch] $Preview, [switch] $Quiet ) if ($PSBoundParameters.ContainsKey('Preview')) { $PreviewOption = '-Preview' } if ($PSBoundParameters.ContainsKey('Quiet')) { $QuietOption = '-Quiet' } Invoke-Expression -Command "& {$(Invoke-RestMethod https://aka.ms/install-powershell.ps1)} -UseMSI $PreviewOption $QuietOption" } #EndRegion Update-PowerShell #Region Watch-Command <# .SYNOPSIS Loop through a command forever until canceled (Ctrl + C) .DESCRIPTION This is meant to be a powershell equivalent to the linux `watch` command. .PARAMETER Command This parameter takes in a command to evaluate. This parameter takes in a string, and uses Invoke-Expression to run the command. This means that complex commands must be wrapped within quotation marks. .PARAMETER WaitSeconds This parameter takes in an Int (number) which equates to the number of seconds to wait after the completion of the command before executing again. .PARAMETER Differences This switch will not overwrite the original text displayed if something in the output has changed. It will place a timestamp in between the previous output and the current (changed) output. This also breaks out what items were `Added` or `Removed` from the previous output to assist with monitoring visually. .EXAMPLE PS> Watch-Command -Command Get-Process Description ----------- This will run Get-Process, wait 5 seconds (the default amount of time) and run it again. .EXAMPLE PS> Watch-Command "Get-Process | Select-Object -First 12" -Differences -WaitSeconds 3 Description ----------- This will run the Get-Process command through the pipeline, and monitor for differences every 3 seconds. Notice this command is treated as a string and `"wrapped in quotes"` .NOTES Author: Matthew J. DeGarmo Handle: @matthewjdegarmo You can either submit a [PR](https://github.com/matthewjdegarmo/AdminToolkit/pulls) or create an [Issue](https://github.com/matthewjdegarmo/AdminToolkit/issues/new) on this GitHub project at https://github.com/matthewjdegarmo/AdminToolkit #> Function Watch-Command() { [CmdletBinding()] param( [Parameter(Mandatory, Position = 0)] [string] $Command, [Parameter(Position = 1)] [int] $WaitSeconds = 5, [switch] $Differences ) begin { $Output = $null $PreviousOutput = $null $Difference = $null $SaveX = [console]::CursorLeft $SaveY = [console]::CursorTop + 1 } process { try { Write-Output "Watching command: '$Command' | Interval: $WaitSeconds`s | Time: $([datetime]::Now)" While ($true) { [console]::SetCursorPosition($SaveX, $SaveY) $Output = (Invoke-Expression -Command $Command -ErrorAction SilentlyContinue) if ($PreviousOutput -and $Output -and $Differences.IsPresent) { # $Properties = $PreviousOutput | Get-Member -MemberType "*Property*" $Difference = (Compare-Object $PreviousOutput $Output -PassThru) if ($Difference) { ($PreviousOutput | Out-String).Trim() "|-------------------------------| |-----------------|" "There was a change in the output: $([datetime]::Now)" "|-------------------------------| |-----------------|" $AddedDifferences = $Difference | Where-Object { $_.SideIndicator -eq "=>" } $RemovedDifferences = $Difference | Where-Object { $_.SideIndicator -eq "<=" } if ($AddedDifferences) { "Added:"; ($AddedDifferences | Out-String).Trim(); "" } if ($RemovedDifferences) { "Removed:"; ($RemovedDifferences | Out-String).Trim(); "" } # ($Difference | Out-String).Trim() # $Difference = $null # $AddedDifferences = $null # $RemovedDifferences = $null ""; Write-Output "Watching command: '$Command' | Interval: $WaitSeconds`s | Time: $([datetime]::Now)" $SaveX = [console]::CursorLeft $SaveY = [console]::CursorTop } } if ($Differences.IsPresent) { $PreviousOutput = $Output } ($Output | Out-String).Trim() Start-Sleep -Seconds $WaitSeconds } } finally { $SaveX = $null $SaveY = $null $Output = $null $PreviousOutput = $null # $Difference = $null } } end {} } #EndRegion Watch-Command |