├── ThreatHunting.psd1 ├── ThreatHunting.psm1 ├── README.md ├── Utilities ├── PoshRSJob-Wrapper.ps1 └── Generate-ModuleManifest.ps1 └── Functions ├── Hunt-BitLockerDetails.ps1 ├── Invoke-Portscan.ps1 ├── Test-SharePermissions.ps1 ├── Hunt-Hotfixes2.ps1 ├── Hunt-WinEvents.ps1 ├── Hunt-InstalledHardware.ps1 ├── Hunt-InstalledSoftware.ps1 ├── Hunt-EnvironmentVariables.ps1 ├── Hunt-AutoRuns.ps1 ├── Hunt-Drivers.ps1 ├── Hunt-ProcessDLLs.ps1 ├── Hunt-Hotfixes.ps1 ├── Hunt-HostsEntries.ps1 ├── Hunt-ArpCache.ps1 ├── Hunt-LoginSessions.ps1 ├── Add-WinEventXMLData.ps1 ├── Hunt-ActivePorts.ps1 ├── Hunt-IPv4Route.ps1 ├── Hunt-RecycleBin.ps1 ├── Hunt-DnsCache.ps1 ├── Hunt-ScheduledTasks.ps1 ├── Hunt-InterfaceDetails.ps1 ├── Hunt-Services.ps1 ├── Hunt-LocalGroupMembers.ps1 ├── Hunt-SCCMLocalGroupMembers.ps1 ├── Hunt-SCCMConsoleUsers.ps1 ├── Hunt-SCCMBrowserHelperObjects.ps1 ├── Hunt-ADS.ps1 ├── Hunt-ProcessHandles.ps1 ├── Hunt-SharePermissions.ps1 ├── Hunt-SCCMUSBDevices.ps1 ├── Hunt-SCCMEnvironments.ps1 ├── Hunt-TPM.ps1 ├── Hunt-SCCMLogicalDisks.ps1 ├── Hunt-SCCMAutostarts.ps1 ├── Hunt-SCCMInstalledSoftware.ps1 ├── Hunt-SCCMServices.ps1 └── Hunt-Processes.ps1 /ThreatHunting.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/securycore/ThreatHunting/HEAD/ThreatHunting.psd1 -------------------------------------------------------------------------------- /ThreatHunting.psm1: -------------------------------------------------------------------------------- 1 | # Make scripts available for use. 2 | 3 | Get-ChildItem -Path $PSScriptRoot\Functions -Filter *.ps1 | 4 | ForEach-Object -Process { . $PSItem.FullName }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ThreatHunting 2 | 3 | ## Installation 4 | 5 | Before installation, unblocking the downloaded files may be required. 6 | 7 | `Get-ChildItem *.ps* -Recurse | Unblock-File` 8 | 9 | ### Option 1: Install at the System Level 10 | Copy the project folder to `%Windir%\System32\WindowsPowerShell\v1.0\Modules\` 11 | 12 | ### Option 2: Install at the Profile Level 13 | Copy the project folder to `$home\Documents\WindowsPowerShell\Modules\` 14 | 15 | ### Option 3: Import Module at each Powershell Prompt 16 | To only use the scripts during the current powershell session, use 17 | 18 | `Import-Module .\ThreatHunting.psm1` 19 | 20 | ### Contact 21 | CERTAnalysisMitigation@dla.mil 22 | 23 | CERT@dla.mil 24 | 25 | http://seclist.us/threathunting-powershell-collection-designed-to-assist-in-threat-hunting-windows-systems.html 26 | -------------------------------------------------------------------------------- /Utilities/PoshRSJob-Wrapper.ps1: -------------------------------------------------------------------------------- 1 | $RunDate = Get-Date -Format 'yyyy-MM-dd'; 2 | 3 | $InputList = "C:\Temp\Scope.csv"; 4 | $OutputPath = "C:\Temp\Hunt-Environmentvariables_{0}.csv" -f $RunDate; 5 | 6 | $jobArguments = @{ 7 | Name = "$_" 8 | Throttle = 20 9 | InputObject = (Get-Content $InputList -totalcount 10) 10 | FunctionsToLoad = "Hunt-Environmentvariables" 11 | ScriptBlock = [scriptblock]::Create('Hunt-Environmentvariables $_') 12 | }; 13 | 14 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 15 | $stopwatch.Start(); 16 | 17 | Start-RSJob @JobArguments | Select-Object ID, Name, Command | Format-Table -Autosize; 18 | 19 | # Job management 20 | While (Get-RSJob) { # So long as there is a job remaining 21 | $CompletedJobs = Get-RSJob -State Completed; 22 | $RunningJobs = Get-RSJob -State Running; 23 | $NotStartedJobs = Get-RSJob -State NotStarted; 24 | $TimeStamp = Get-Date -Format 'yyyy/MM/dd hh:mm:ss'; 25 | 26 | Write-Host -Object ("$TimeStamp - Saving $($CompletedJobs.Count) completed jobs. There are $($RunningJobs.Count)/$($NotStartedJobs.Count) jobs still running."); 27 | 28 | ForEach ($DoneJob in $CompletedJobs) { 29 | 30 | Receive-RSJob -Id $DoneJob.ID | Export-Csv $OutputPath -NoTypeInformation -Append; 31 | Stop-RSJob -Id $DoneJob.ID; 32 | Remove-RSJob -Id $DoneJob.ID; 33 | }; 34 | 35 | Start-Sleep -Seconds 10; 36 | }; 37 | 38 | $elapsed = $stopwatch.Elapsed; 39 | Write-Host $elapsed; 40 | -------------------------------------------------------------------------------- /Utilities/Generate-ModuleManifest.ps1: -------------------------------------------------------------------------------- 1 | $FileList = @('ThreatHunting.psd1', 'ThreatHunting.psm1'); 2 | $FunctionsToExport = @(); 3 | 4 | Get-ChildItem "e:\scripts\threathunting\functions" -Filter *.ps1 | Select-Object -ExpandProperty FullName | ForEach-Object { 5 | $File = Split-Path $_ -Leaf 6 | $Function = $File.Split(".")[0]; 7 | $FileList += "Functions\" + $File; 8 | $FunctionsToExport += $Function; 9 | }; 10 | 11 | $RunDate = Get-Date -Format 'yyyy-MM-dd'; 12 | 13 | $manifest = @{ 14 | RootModule = 'ThreatHunting.psm1' 15 | Path = 'E:\scripts\ThreatHunting\ThreatHunting.psd1' 16 | ModuleVersion = '1.0' 17 | CompatiblePSEditions = @('Core') 18 | Author = 'Various Authors' 19 | CompanyName = 'DLA CERT' 20 | Copyright = 'Copyright (C) 2017 DLA CERT 21 | This program is free software: you can redistribute it and/or modify 22 | it under the terms of the GNU General Public License as published by 23 | the Free Software Foundation, either version 3 of the License, or 24 | (at your option) any later version. 25 | 26 | This program is distributed in the hope that it will be useful, 27 | but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | GNU General Public License for more details. 30 | 31 | You should have received a copy of the GNU General Public License 32 | along with this program. If not, see ','','' | Hunt-BitLockerDetails 18 | Hunt-BitLockerDetails SomeHostName.domain.com 19 | Get-Content C:\hosts.csv | Hunt-BitLockerDetails 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-BitLockerDetails 21 | 22 | .Notes 23 | Updated: 2017-10-10 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | Anthony Phipps 28 | 29 | LEGAL: Copyright (C) 2017 30 | This program is free software: you can redistribute it and/or modify 31 | it under the terms of the GNU General Public License as published by 32 | the Free Software Foundation, either version 3 of the License, or 33 | (at your option) any later version. 34 | 35 | This program is distributed in the hope that it will be useful, 36 | but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 | GNU General Public License for more details. 39 | 40 | You should have received a copy of the GNU General Public License 41 | along with this program. If not, see . 42 | #> 43 | 44 | PARAM( 45 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 46 | $Computer = $env:COMPUTERNAME, 47 | [Parameter()] 48 | $Fails 49 | ) 50 | 51 | BEGIN{ 52 | 53 | $datetime = Get-Date -Format u; 54 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 55 | 56 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 57 | $stopwatch.Start(); 58 | $total = 0; 59 | }; 60 | 61 | PROCESS{ 62 | 63 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 64 | 65 | $Volumes = Invoke-Command -ComputerName $Computer -ScriptBlock {Get-BitLockerVolume} -ErrorAction SilentlyContinue; 66 | 67 | $Volumes | 68 | ForEach-Object { 69 | 70 | $Key = Invoke-Command -ComputerName $Computer -ScriptBlock {(Get-BitLockerVolume).KeyProtector.RecoveryPassword[1]} -ErrorAction SilentlyContinue; 71 | 72 | $_ | Add-Member -MemberType NoteProperty -Name RecoveryPassword -Value $Key; 73 | $_ | Add-Member –MemberType NoteProperty –Name Computer -Value $Computer; 74 | $_ | Add-Member –MemberType NoteProperty –Name DateScanned -Value (Get-Date -Format u); 75 | 76 | Return $_ | Select-Object *; 77 | }; 78 | }; 79 | 80 | END{ 81 | $elapsed = $stopwatch.Elapsed; 82 | 83 | Write-Information -MessageData "Total Systems: $total `t Total time elapsed: $elapsed" -InformationAction Continue; 84 | }; 85 | }; 86 | -------------------------------------------------------------------------------- /Functions/Invoke-Portscan.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Invoke-PortScan { 2 | <# 3 | .Synopsis 4 | Utilizes Test-NetConnection to perform rudimentary port scanning. 5 | 6 | .Description 7 | Utilizes Test-NetConnection to perform rudimentary port scanning. 8 | Note that this is much slower due than things like nmap due to lack 9 | of multithreading. However tools like PoshRSJob will certainly 10 | speed things up. 11 | 12 | .Parameter Computer 13 | Computer can be a single hostname, FQDN, or IP address. 14 | 15 | .Parameter Fails 16 | Provide a path to save failed systems to. 17 | 18 | .Example 19 | Invoke-PortScan SomeHostName.domain.com 20 | Get-Content C:\hosts.txt | Invoke-PortScan 21 | Get-ADComputer -filter * | Select -ExpandProperty Name | Invoke-PortScan 22 | 23 | .Notes 24 | Updated: 2017-10-10 25 | 26 | Contributing Authors: 27 | Anthony Phipps 28 | 29 | LEGAL: Copyright (C) 2017 30 | This program is free software: you can redistribute it and/or modify 31 | it under the terms of the GNU General Public License as published by 32 | the Free Software Foundation, either version 3 of the License, or 33 | (at your option) any later version. 34 | 35 | This program is distributed in the hope that it will be useful, 36 | but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 | GNU General Public License for more details. 39 | 40 | You should have received a copy of the GNU General Public License 41 | along with this program. If not, see . 42 | #> 43 | 44 | [CmdletBinding()] 45 | PARAM( 46 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 47 | $Computer = $env:COMPUTERNAME, 48 | [Parameter()] 49 | [array] 50 | $Ports = (80, 443, 593, 135, 139, 445, 3389, 5988, 5989), 51 | [Parameter()] 52 | $Fails 53 | ); 54 | 55 | BEGIN{ 56 | 57 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 58 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 59 | 60 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 61 | $stopwatch.Start(); 62 | }; 63 | 64 | PROCESS{ 65 | 66 | class Port { 67 | [String] $Computer 68 | [DateTime] $DateScanned 69 | 70 | [String] $RemoteAddress 71 | [String] $RemotePort 72 | [String] $TCPTestSucceeded 73 | }; 74 | 75 | $OutputArray = $null; 76 | $OutputArray = @(); 77 | 78 | Foreach ($Port in $Ports) { 79 | 80 | $Scan = Test-NetConnection -ComputerName $Computer -Port $Port | Select-Object ComputerName, RemoteAddress, RemotePort, TCPTestSucceeded; 81 | 82 | $output = $null; 83 | $output = [Port]::new(); 84 | 85 | $output.Computer = $Computer; 86 | $output.DateScanned = Get-Date -Format u; 87 | 88 | $output.ComputerName = $Scan.ComputerName; 89 | $output.RemoteAddress = $Scan.RemoteAddress; 90 | $output.RemotePort = $Scan.RemotePort; 91 | $output.TcpTestSucceeded = $Scan.TcpTestSucceeded; 92 | 93 | $OutputArray += $output; 94 | }; 95 | 96 | Return $OutputArray; 97 | }; 98 | }; -------------------------------------------------------------------------------- /Functions/Test-SharePermissions.ps1: -------------------------------------------------------------------------------- 1 | Function Test-SharePermissions { 2 | <# 3 | .Synopsis 4 | Tests the current user's ability to read, write, and delete a file in a given share. 5 | 6 | .Description 7 | Tests the current user's ability to read, write, and delete a file in a given share. Supports piping in share paths. 8 | 9 | .Parameter SharePath 10 | A complete share path (e.g. \\Hostname\ShareName\). 11 | 12 | .Example 13 | Test-SharePermissions "\\servername\share\" 14 | Import-Csv c:\temp\shares.csv | ForEach-Object {"\\{0}\{1}\" -f $_.ComputerName, $_.Name} | Test-SharePermissions 15 | 16 | .Notes 17 | Updated: 2017-10-10 18 | 19 | Contributing Authors: 20 | Anthony Phipps 21 | 22 | LEGAL: Copyright (C) 2017 23 | This program is free software: you can redistribute it and/or modify 24 | it under the terms of the GNU General Public License as published by 25 | the Free Software Foundation, either version 3 of the License, or 26 | (at your option) any later version. 27 | 28 | This program is distributed in the hope that it will be useful, 29 | but WITHOUT ANY WARRANTY; without even the implied warranty of 30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 | GNU General Public License for more details. 32 | 33 | You should have received a copy of the GNU General Public License 34 | along with this program. If not, see . 35 | #> 36 | 37 | [CmdletBinding()] 38 | PARAM( 39 | [Parameter(ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] 40 | $SharePath 41 | ); 42 | 43 | BEGIN{ 44 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 45 | Write-Verbose "Started at $datetime"; 46 | 47 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 48 | $stopwatch.Start(); 49 | 50 | $total = 0; 51 | 52 | class Share { 53 | [String] $SharePath 54 | [DateTime] $DateScanned 55 | [String] $UserTested 56 | [String] $FileTested 57 | [String] $Read 58 | [String] $Write 59 | [String] $Delete 60 | 61 | }; 62 | 63 | $RandomString = -join ((65..90) + (97..122) | Get-Random -Count 10 | Foreach-Object {[char]$_}); 64 | }; 65 | 66 | PROCESS{ 67 | 68 | $output = $null; 69 | $output = [Share]::new(); 70 | 71 | $output.SharePath = $SharePath; 72 | $output.UserTested = whoami; 73 | $output.FileTested = "$RandomString.txt"; 74 | $output.DateScanned = Get-Date -Format u; 75 | $output.Read = $False; 76 | $output.Write = $False; 77 | $output.Delete = $False; 78 | 79 | Write-Verbose "Testing Read Permission"; 80 | 81 | if (Get-ChildItem $SharePath -Name -ErrorAction SilentlyContinue) { 82 | 83 | $output.Read = $True; 84 | }; 85 | 86 | Write-Verbose "Testing Write Permission"; 87 | if (($output.Read) -eq $True) { 88 | 89 | New-Item -Path $SharePath -Name "$RandomString.txt" -ItemType "file" -Force -ErrorAction SilentlyContinue | Out-Null; 90 | 91 | if (Test-Path $SharePath\$RandomString.txt -PathType Leaf -ErrorAction SilentlyContinue) { 92 | 93 | $output.Write = $True; 94 | }; 95 | }; 96 | 97 | Write-Verbose "Testing Delete Permission"; 98 | if (($output.Write) -eq $True) { 99 | 100 | Remove-Item -path $SharePath\$RandomString.txt -ErrorAction SilentlyContinue | Out-Null; 101 | 102 | if (-NOT (Test-Path $SharePath\$RandomString.txt -ErrorAction SilentlyContinue)) { 103 | 104 | $output.Delete = $True; 105 | }; 106 | }; 107 | 108 | $elapsed = $stopwatch.Elapsed; 109 | $total = $total + 1; 110 | 111 | Write-Verbose "System $total `t $ThisComputer `t Total Time Elapsed: $elapsed"; 112 | 113 | return $output; 114 | }; 115 | 116 | END{ 117 | 118 | $elapsed = $stopwatch.Elapsed; 119 | 120 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 121 | }; 122 | }; 123 | -------------------------------------------------------------------------------- /Functions/Hunt-Hotfixes2.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-HotFixes2 { 2 | <# 3 | .Synopsis 4 | Gets the installed Hotfixes for the given computer(s). 5 | 6 | .Description 7 | Gets the installed Hotfixes for the given computer(s). 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-HotFixes 17 | Hunt-HotFixes SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-HotFixes 19 | Hunt-HotFixes -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-HotFixes 21 | 22 | .Notes 23 | Updated: 2017-10-10 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | #> 42 | 43 | PARAM( 44 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 45 | $Computer = $env:COMPUTERNAME, 46 | [Parameter()] 47 | $Fails 48 | ); 49 | 50 | BEGIN{ 51 | 52 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 53 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 54 | 55 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 56 | $stopwatch.Start(); 57 | $total = 0; 58 | 59 | class Hotfix 60 | { 61 | 62 | [datetime]$datescanned 63 | [string]$Computer 64 | 65 | }; 66 | 67 | }; 68 | 69 | PROCESS{ 70 | 71 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 72 | $Hotfixes = $null; 73 | $Hotfixes = Invoke-Command -Computer $Computer -ScriptBlock {Get-HotFix -ErrorAction SilentlyContinue}; # get current installed hotfixes 74 | 75 | 76 | if ($Hotfixes) { 77 | 78 | foreach ($hotfix in $Hotfixes) {#loop through each hotfix 79 | 80 | $hotfix | Add-Member -NotePropertyName DateScanned -NotePropertyValue $(Get-Date -Format u); 81 | $hotfix | Add-Member -NotePropertyName Computer -NotePropertyValue $($Computer); 82 | 83 | }; 84 | 85 | $Hotfixes = $Hotfixes | select DateScanned, Computer, Description, HotfixID, InstalledBy, InstalledOn; 86 | 87 | Return $Hotfixes; 88 | 89 | }Else{# System not reachable 90 | 91 | if ($Fails) { 92 | 93 | # -Fails switch was used 94 | Add-Content -Path $Fails -Value ("$Computer"); 95 | 96 | }else{ 97 | 98 | # -Fails switch not used 99 | $output = $null; 100 | $output = [Hotfix]::new(); 101 | $output.Computer = $Computer; 102 | $output.DateScanned = Get-Date -Format u; 103 | 104 | return $output; 105 | 106 | }; 107 | 108 | }; 109 | 110 | }; 111 | 112 | END{ 113 | $elapsed = $stopwatch.Elapsed; 114 | $total = $total+1; 115 | 116 | Write-Information -MessageData "Total Systems: $total `t Total time elapsed: $elapsed" -InformationAction Continue; 117 | 118 | }; 119 | 120 | }; 121 | -------------------------------------------------------------------------------- /Functions/Hunt-WinEvents.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-WinEvents { 2 | <# 3 | .Synopsis 4 | Gets Windows events from one or more systems. 5 | 6 | .Description 7 | Gets Windows events from one or more systems. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-WinEvents -FilterHashTable @{LogName="Microsoft-Windows-AppLocker/EXE and DLL"; ID="8002","8003","8004"} 17 | Hunt-WinEvents -FilterHashTable @{LogName="Windows PowerShell"; StartTime=(Get-Date).AddDays(-8); EndTime=(Get-Date)} 18 | Hunt-WinEvents SomeHostName.domain.com 19 | Get-Content C:\hosts.txt | Hunt-WinEvents 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-WinEvents 21 | 22 | .Example 23 | Pull AppLocker Events from a Windows Event Collector: 24 | Hunt-WinEvents -FilterHashTable @{LogName="ForwardedEvents"; ID="8002","8003","8004"} 25 | 26 | .Notes 27 | To extract XML data, use another script like Get-WinEventXMLData 28 | https://github.com/DLACERT/ThreatHunting/blob/master/Add-WinEventXMLData.ps1 29 | 30 | Updated: 2017-10-10 31 | 32 | Contributing Authors: 33 | Anthony Phipps 34 | 35 | LEGAL: Copyright (C) 2017 36 | This program is free software: you can redistribute it and/or modify 37 | it under the terms of the GNU General Public License as published by 38 | the Free Software Foundation, either version 3 of the License, or 39 | (at your option) any later version. 40 | 41 | This program is distributed in the hope that it will be useful, 42 | but WITHOUT ANY WARRANTY; without even the implied warranty of 43 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 44 | GNU General Public License for more details. 45 | 46 | You should have received a copy of the GNU General Public License 47 | along with this program. If not, see . 48 | #> 49 | 50 | [CmdletBinding()] 51 | PARAM( 52 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 53 | $Computer = $env:COMPUTERNAME, 54 | [Parameter()] 55 | [array] 56 | $FilterHashTable = @{LogName="Windows PowerShell"; StartTime=(Get-Date).AddDays(-8);}, 57 | [Parameter()] 58 | $Fails 59 | ); 60 | 61 | BEGIN{ 62 | 63 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 64 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 65 | 66 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 67 | $stopwatch.Start(); 68 | 69 | $total = 0; 70 | }; 71 | 72 | PROCESS{ 73 | 74 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 75 | 76 | $Events = Get-WinEvent -ComputerName $Computer -FilterHashTable $FilterHashTable; 77 | 78 | if ($Events) { 79 | 80 | $Events | 81 | Foreach-Object { 82 | 83 | $output = $_; 84 | $output | Add-Member -MemberType NoteProperty -Name Computer -Value $Computer; 85 | $output | Add-Member -MemberType NoteProperty -Name DateScanned -Value (Get-Date -Format u); 86 | 87 | Return $output; 88 | }; 89 | } 90 | else { 91 | 92 | Write-Verbose ("{0}: System failed." -f $Computer); 93 | if ($Fails) { 94 | 95 | $total++; 96 | Add-Content -Path $Fails -Value ("$Computer"); 97 | } 98 | else { 99 | 100 | $output = $null; 101 | $output = [PSCustomObject]@{ 102 | Computer = $Computer 103 | DateScanned = Get-Date -Format u 104 | }; 105 | 106 | $total++; 107 | return $output; 108 | }; 109 | }; 110 | }; 111 | 112 | end { 113 | 114 | $elapsed = $stopwatch.Elapsed; 115 | 116 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 117 | }; 118 | }; -------------------------------------------------------------------------------- /Functions/Hunt-InstalledHardware.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-InstalledHardware { 2 | <# 3 | .Synopsis 4 | Gets a list of installed devices for the given computer(s). 5 | 6 | .Description 7 | Gets a list of installed devices for the given computer(s). 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-InstalledHardware 17 | Hunt-InstalledHardware SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-InstalledHardware 19 | Hunt-InstalledHardware -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-InstalledHardware 21 | 22 | .Notes 23 | Updated: 2017-10-12 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | #> 42 | 43 | PARAM( 44 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 45 | $Computer = $env:COMPUTERNAME, 46 | [Parameter()] 47 | $Fails 48 | ); 49 | 50 | BEGIN{ 51 | 52 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 53 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 54 | 55 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 56 | $stopwatch.Start(); 57 | $total = 0; 58 | 59 | class Device 60 | { 61 | [Datetime] $DateScanned 62 | [string] $Computer 63 | [String] $Class 64 | [string] $Caption 65 | [string] $Description 66 | [String] $DeviceID 67 | 68 | }; 69 | 70 | }; 71 | 72 | PROCESS{ 73 | 74 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 75 | $OutputArray = @(); 76 | $drivers = $null; 77 | Write-Verbose "Getting a list of installed devices..." 78 | $devices = Invoke-Command -Computer $Computer -ScriptBlock {Get-CimInstance Win32_PnPEntity -ErrorAction SilentlyContinue}; 79 | 80 | if ($devices) { 81 | $deviceClassArray = $devices | Group-Object pnpclass | Select-Object Name, Count | Sort-Object name; 82 | foreach ($device in $devices) { 83 | 84 | $output = $null; 85 | $output = [Device]::new(); 86 | 87 | $output.DateScanned = Get-Date -Format u; 88 | $output.Computer = $Computer; 89 | $output.Class = $device.pnpclass; 90 | $output.caption = $device.caption; 91 | $output.description = $device.description; 92 | $output.deviceID = $device.deviceID; 93 | 94 | $OutputArray += $output; 95 | 96 | }; 97 | 98 | Return $OutputArray; 99 | 100 | } 101 | else { 102 | 103 | Write-Verbose ("{0}: System failed." -f $Computer); 104 | if ($Fails) { 105 | 106 | $total++; 107 | Add-Content -Path $Fails -Value ("$Computer"); 108 | } 109 | else { 110 | 111 | $output = $null; 112 | $output = [Device]::new(); 113 | 114 | $output.Computer = $Computer; 115 | $output.DateScanned = Get-Date -Format u; 116 | 117 | $total++; 118 | return $output; 119 | }; 120 | }; 121 | }; 122 | 123 | end { 124 | 125 | $elapsed = $stopwatch.Elapsed; 126 | 127 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 128 | }; 129 | }; -------------------------------------------------------------------------------- /Functions/Hunt-InstalledSoftware.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-InstalledSoftware { 2 | <# 3 | .Synopsis 4 | Gets the installed Software for the given computer(s). 5 | 6 | .Description 7 | Gets the installed Software for the given computer(s). 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-InstalledSoftware 17 | Hunt-InstalledSoftware SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-InstalledSoftware 19 | Hunt-InstalledSoftware -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-InstalledSoftware 21 | 22 | .Notes 23 | Updated: 2017-10-10 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | #> 42 | 43 | PARAM( 44 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 45 | $Computer = $env:COMPUTERNAME, 46 | [Parameter()] 47 | $Fails 48 | ); 49 | 50 | BEGIN{ 51 | 52 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 53 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 54 | $UninstallKey="SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall", 55 | "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; 56 | 57 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 58 | $stopwatch.Start(); 59 | $total = 0; 60 | 61 | class InstalledSoftware 62 | { 63 | [datetime]$datescanned 64 | [string]$Computer 65 | }; 66 | 67 | }; 68 | 69 | PROCESS{ 70 | 71 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 72 | 73 | $installedSoft = $null; 74 | 75 | foreach ($key in $UninstallKey){ 76 | 77 | $installedSoft += $installedSoft = Invoke-Command -Computer $Computer -ScriptBlock {Get-ItemProperty ('HKLM:\' + "$key" + '\*') -ErrorAction SilentlyContinue}; # get current uninstallkey properties 78 | 79 | } 80 | 81 | if ($installedSoft) { 82 | 83 | foreach ($item in $installedSoft) {#loop through each record 84 | 85 | $item | Add-Member -NotePropertyName DateScanned -NotePropertyValue $(Get-Date -Format u); 86 | $item | Add-Member -NotePropertyName Computer -NotePropertyValue $($Computer); 87 | 88 | }; 89 | 90 | $installedSoft = $installedSoft | Select-Object -Property Publisher, DisplayName, DisplayVersion, InstallDate, 91 | InstallSource, InstallLocation, pschildname, HelpLink | 92 | Sort-Object -Property Displayname; 93 | 94 | 95 | Return $installedSoft; 96 | 97 | } 98 | else { 99 | 100 | Write-Verbose ("{0}: System failed." -f $Computer); 101 | if ($Fails) { 102 | 103 | $total++; 104 | Add-Content -Path $Fails -Value ("$Computer"); 105 | } 106 | else { 107 | 108 | $output = $null; 109 | $output = [InstalledSoftware]::new(); 110 | 111 | $output.Computer = $Computer; 112 | $output.DateScanned = Get-Date -Format u; 113 | 114 | $total++; 115 | return $output; 116 | }; 117 | }; 118 | }; 119 | 120 | end { 121 | 122 | $elapsed = $stopwatch.Elapsed; 123 | 124 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 125 | }; 126 | }; -------------------------------------------------------------------------------- /Functions/Hunt-EnvironmentVariables.ps1: -------------------------------------------------------------------------------- 1 | Function Hunt-EnvironmentVariables { 2 | <# 3 | .Synopsis 4 | Retreives the values of all environment variables from one or more systems. 5 | 6 | .Description 7 | Retreives the values of all environment variables from one or more systems. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Example 13 | get-content .\hosts.txt | Hunt-EnvironmentVariables $env:computername | export-csv envVars.csv -NoTypeInformation 14 | 15 | .Notes 16 | Updated: 2017-10-10 17 | 18 | Contributing Authors: 19 | Anthony Phipps 20 | 21 | LEGAL: Copyright (C) 2017 22 | This program is free software: you can redistribute it and/or modify 23 | it under the terms of the GNU General Public License as published by 24 | the Free Software Foundation, either version 3 of the License, or 25 | (at your option) any later version. 26 | 27 | This program is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | GNU General Public License for more details. 31 | 32 | You should have received a copy of the GNU General Public License 33 | along with this program. If not, see . 34 | #> 35 | 36 | 37 | [cmdletbinding()] 38 | 39 | 40 | PARAM( 41 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 42 | $Computer = $env:COMPUTERNAME, 43 | [Parameter()] 44 | $Fails 45 | ); 46 | 47 | BEGIN{ 48 | 49 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 50 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 51 | 52 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 53 | $stopwatch.Start(); 54 | 55 | $total = 0; 56 | 57 | class EnvVariable { 58 | [String] $Computer 59 | [DateTime] $DateScanned 60 | 61 | [String] $Name 62 | [String] $UserName 63 | [String] $VariableValue 64 | }; 65 | }; 66 | 67 | 68 | PROCESS{ 69 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 70 | 71 | $AllVariables = $null; 72 | $AllVariables = Get-CimInstance -Class Win32_Environment -ComputerName $Computer -ErrorAction SilentlyContinue; 73 | 74 | if ($AllVariables) { 75 | 76 | $OutputArray = $null; 77 | $OutputArray = @(); 78 | 79 | ForEach ($Variable in $AllVariables) { 80 | $VariableValues = $Variable.VariableValue.Split(";") | Where-Object {$_ -ne ""} 81 | 82 | Foreach ($VariableValue in $VariableValues) { 83 | $VariableValueSplit = $Variable; 84 | $VariableValueSplit.VariableValue = $VariableValue; 85 | 86 | $output = $null; 87 | $output = [EnvVariable]::new(); 88 | 89 | $output.Computer = $Computer; 90 | $output.DateScanned = Get-Date -Format u; 91 | 92 | $output.Name = $VariableValueSplit.Name; 93 | $output.UserName = $VariableValueSplit.UserName; 94 | $output.VariableValue = $VariableValueSplit.VariableValue; 95 | 96 | $OutputArray += $output; 97 | 98 | }; 99 | }; 100 | 101 | $elapsed = $stopwatch.Elapsed; 102 | $total = $total+1; 103 | 104 | return $OutputArray; 105 | } 106 | else { 107 | 108 | Write-Verbose ("{0}: System failed." -f $Computer); 109 | if ($Fails) { 110 | 111 | $total++; 112 | Add-Content -Path $Fails -Value ("$Computer"); 113 | } 114 | else { 115 | 116 | $output = $null; 117 | $output = [EnvVariable]::new(); 118 | 119 | $output.Computer = $Computer; 120 | $output.DateScanned = Get-Date -Format u; 121 | 122 | $total++; 123 | return $output; 124 | }; 125 | }; 126 | }; 127 | 128 | end { 129 | 130 | $elapsed = $stopwatch.Elapsed; 131 | 132 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 133 | }; 134 | }; -------------------------------------------------------------------------------- /Functions/Hunt-AutoRuns.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-Autoruns { 2 | <# 3 | .Synopsis 4 | Gets a list of programs that auto start for the given computer(s). 5 | 6 | .Description 7 | Gets a list of programs that auto start for the given computer(s). 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-Autoruns 17 | Hunt-Autoruns SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-Autoruns 19 | Hunt-Autoruns -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-Autoruns 21 | 22 | .Notes 23 | Updated: 2017-10-24 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | Anthony Phipps 28 | 29 | LEGAL: Copyright (C) 2017 30 | This program is free software: you can redistribute it and/or modify 31 | it under the terms of the GNU General Public License as published by 32 | the Free Software Foundation, either version 3 of the License, or 33 | (at your option) any later version. 34 | 35 | This program is distributed in the hope that it will be useful, 36 | but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 | GNU General Public License for more details. 39 | 40 | You should have received a copy of the GNU General Public License 41 | along with this program. If not, see . 42 | 43 | .LINK 44 | https://github.com/DLACERT/ThreatHunting 45 | #> 46 | 47 | param( 48 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 49 | $Computer = $env:COMPUTERNAME, 50 | [Parameter()] 51 | $Fails 52 | ); 53 | 54 | begin{ 55 | 56 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 57 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 58 | 59 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 60 | $stopwatch.Start(); 61 | $total = 0; 62 | 63 | class Autorun 64 | { 65 | [Datetime] $DateScanned 66 | [string] $Computer 67 | [String] $User 68 | [string] $Caption 69 | [string] $Command 70 | [String] $Location 71 | 72 | }; 73 | 74 | }; 75 | 76 | process{ 77 | 78 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 79 | 80 | Write-Verbose ("{0}: Querying remote system" -f $Computer); 81 | $autoruns = $null; 82 | $autoruns = Invoke-Command -Computer $Computer -ErrorAction SilentlyContinue -ScriptBlock { 83 | Get-CimInstance Win32_StartupCommand -ErrorAction SilentlyContinue; 84 | }; 85 | 86 | if ($autoruns) { 87 | 88 | $outputArray = @(); 89 | 90 | foreach ($autorun in $autoruns) { 91 | 92 | $output = $null; 93 | $output = [Autorun]::new(); 94 | 95 | $output.Computer = $Computer; 96 | $output.DateScanned = Get-Date -Format u; 97 | 98 | $output.User = $autorun.User; 99 | $output.Caption = $autorun.Caption; 100 | $output.Command = $autorun.Command; 101 | $output.Location = $autorun.Location; 102 | 103 | $outputArray += $output; 104 | 105 | }; 106 | 107 | $total++; 108 | return $OutputArray; 109 | 110 | } 111 | else { 112 | 113 | Write-Verbose ("{0}: System failed." -f $Computer); 114 | if ($Fails) { 115 | 116 | $total++; 117 | Add-Content -Path $Fails -Value ("$Computer"); 118 | } 119 | else { 120 | 121 | $output = $null; 122 | $output = [Autorun]::new(); 123 | 124 | $output.Computer = $Computer; 125 | $output.DateScanned = Get-Date -Format u; 126 | 127 | $total++; 128 | return $output; 129 | }; 130 | }; 131 | }; 132 | 133 | end { 134 | 135 | $elapsed = $stopwatch.Elapsed; 136 | 137 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 138 | }; 139 | }; -------------------------------------------------------------------------------- /Functions/Hunt-Drivers.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-Drivers { 2 | <# 3 | .Synopsis 4 | Gets a list of drivers for the given computer(s). 5 | 6 | .Description 7 | Gets a list of drivers for the given computer(s). 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-Drivers 17 | Hunt-Drivers SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-Drivers 19 | Hunt-Drivers -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-Drivers 21 | 22 | .Notes 23 | Updated: 2017-10-10 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | Anthony Phipps 28 | 29 | LEGAL: Copyright (C) 2017 30 | This program is free software: you can redistribute it and/or modify 31 | it under the terms of the GNU General Public License as published by 32 | the Free Software Foundation, either version 3 of the License, or 33 | (at your option) any later version. 34 | 35 | This program is distributed in the hope that it will be useful, 36 | but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 | GNU General Public License for more details. 39 | 40 | You should have received a copy of the GNU General Public License 41 | along with this program. If not, see . 42 | #> 43 | 44 | PARAM( 45 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 46 | $Computer = $env:COMPUTERNAME, 47 | [Parameter()] 48 | $Fails 49 | ); 50 | 51 | BEGIN{ 52 | 53 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 54 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 55 | 56 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 57 | $stopwatch.Start(); 58 | $total = 0; 59 | 60 | class Driver 61 | { 62 | [Datetime] $DateScanned 63 | [string] $Computer 64 | [string] $Provider 65 | [string] $Driver 66 | [String] $Version 67 | [datetime] $Date 68 | [String] $Class 69 | [string] $DriverSigned 70 | [string] $OrginalFileName 71 | }; 72 | 73 | }; 74 | 75 | PROCESS{ 76 | 77 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 78 | $OutputArray = @(); 79 | $drivers = $null; 80 | $drivers = Invoke-Command -ComputerName $Computer -ScriptBlock {Get-WindowsDriver -Online -ErrorAction SilentlyContinue}; # get list of drivers 81 | 82 | if ($drivers) { 83 | 84 | foreach ($driver in $drivers) { 85 | 86 | $output = $null; 87 | $output = [Driver]::new(); 88 | 89 | $output.DateScanned = Get-Date -Format u; 90 | $output.Computer = $Computer; 91 | $output.Provider = $driver.ProviderName; 92 | $output.Driver = $driver.Driver; 93 | $output.Version = $driver.Version; 94 | $output.date = $driver.Date; 95 | $output.Class = $driver.ClassDescription; 96 | $output.DriverSigned = $driver.DriverSignature; 97 | $output.OrginalFileName = $driver.OriginalFileName; 98 | 99 | $OutputArray += $output; 100 | 101 | }; 102 | 103 | Return $OutputArray | Sort-Object -Property date -Descending; 104 | 105 | } 106 | else { 107 | 108 | Write-Verbose ("{0}: System failed." -f $Computer); 109 | if ($Fails) { 110 | 111 | $total++; 112 | Add-Content -Path $Fails -Value ("$Computer"); 113 | } 114 | else { 115 | 116 | $output = $null; 117 | $output = [Driver]::new(); 118 | 119 | $output.Computer = $Computer; 120 | $output.DateScanned = Get-Date -Format u; 121 | 122 | $total++; 123 | return $output; 124 | }; 125 | }; 126 | }; 127 | 128 | end { 129 | 130 | $elapsed = $stopwatch.Elapsed; 131 | 132 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 133 | }; 134 | }; -------------------------------------------------------------------------------- /Functions/Hunt-ProcessDLLs.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-ProcessDLLs { 2 | <# 3 | .Synopsis 4 | Gets a list of DLLs loaded by all process on a given system. 5 | 6 | .Description 7 | Gets a list of DLLs loaded by all process on a given system. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-ProcessDLLs 17 | Hunt-ProcessDLLs SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-ProcessDLLs 19 | Hunt-ProcessDLLs $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-ProcessDLLs 21 | 22 | .Notes 23 | Updated: 2017-11-4 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | 42 | .LINK 43 | https://github.com/DLACERT/ThreatHunting 44 | #> 45 | 46 | param( 47 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 48 | $Computer = $env:COMPUTERNAME, 49 | [Parameter()] 50 | $Fails 51 | ); 52 | 53 | begin{ 54 | 55 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 56 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 57 | 58 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 59 | $stopwatch.Start(); 60 | 61 | $total = 0; 62 | 63 | class DLLs 64 | { 65 | [String] $Computer 66 | [dateTime] $DateScanned 67 | 68 | [string] $ProcessID 69 | [string] $Process 70 | [String] $DLLName 71 | [String] $DLLCompany 72 | [String] $DLLProduct 73 | 74 | }; 75 | }; 76 | 77 | process{ 78 | 79 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 80 | 81 | $processes = $null; 82 | $processes = Invoke-Command -ComputerName $Computer -ErrorAction SilentlyContinue -ScriptBlock { 83 | 84 | $processes = Get-Process | Select-Object Id, ProcessName, Company, Product, Modules ; 85 | 86 | return $processes; 87 | 88 | }; 89 | 90 | if ($processes) { 91 | 92 | $outputArray = @(); 93 | 94 | Foreach ($process in $processes) { 95 | 96 | Foreach ($module in $process.modules){ 97 | 98 | $output = $null; 99 | $output = [DLLs]::new(); 100 | 101 | $output.Computer = $Computer; 102 | $output.DateScanned = Get-Date -Format u; 103 | 104 | $output.ProcessID = $process.id; 105 | $output.Process = $process.processname; 106 | $output.DLLCompany = $module.company; 107 | $output.DLLProduct = $module.Product; 108 | $output.DLLName = $module.modulename; 109 | 110 | $outputArray += $output; 111 | }; 112 | }; 113 | 114 | return $outputArray; 115 | 116 | } 117 | else { 118 | 119 | Write-Verbose ("{0}: System failed." -f $Computer); 120 | if ($Fails) { 121 | 122 | $total++; 123 | Add-Content -Path $Fails -Value ("$Computer"); 124 | } 125 | else { 126 | 127 | $output = $null; 128 | $output = [DLLs]::new(); 129 | 130 | $output.Computer = $Computer; 131 | $output.DateScanned = Get-Date -Format u; 132 | 133 | $total++; 134 | return $output; 135 | }; 136 | }; 137 | }; 138 | 139 | end { 140 | 141 | $elapsed = $stopwatch.Elapsed; 142 | 143 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 144 | }; 145 | }; -------------------------------------------------------------------------------- /Functions/Hunt-Hotfixes.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-Hotfixes { 2 | <# 3 | .Synopsis 4 | Gets the hotfixes applied to a given system. 5 | 6 | .Description 7 | Gets the hotfixes applied to a given system. Get-Hotfix returns only OS-level hotfixes, this one grabs em all. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Example 13 | Hunt-Hotfixes 14 | Hunt-Hotfixes SomeHostName.domain.com 15 | Get-Content C:\hosts.csv | Hunt-Hotfixes 16 | Hunt-Hotfixes $env:computername 17 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-Hotfixes 18 | 19 | .Notes 20 | Updated: 2017-10-10 21 | 22 | Contributing Authors: 23 | Anthony Phipps 24 | 25 | LEGAL: Copyright (C) 2017 26 | This program is free software: you can redistribute it and/or modify 27 | it under the terms of the GNU General Public License as published by 28 | the Free Software Foundation, either version 3 of the License, or 29 | (at your option) any later version. 30 | 31 | This program is distributed in the hope that it will be useful, 32 | but WITHOUT ANY WARRANTY; without even the implied warranty of 33 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 34 | GNU General Public License for more details. 35 | 36 | You should have received a copy of the GNU General Public License 37 | along with this program. If not, see . 38 | #> 39 | 40 | PARAM( 41 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 42 | $Computer 43 | ); 44 | 45 | BEGIN{ 46 | 47 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 48 | Write-Verbose "Started at $datetime" 49 | 50 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 51 | $stopwatch.Start(); 52 | 53 | $total = 0; 54 | } 55 | 56 | PROCESS{ 57 | 58 | $output = [PSCustomObject]@{ 59 | Name = $Computer 60 | PSComputerName = "" 61 | Operation = "" 62 | ResultCode = "" 63 | HResult = "" 64 | Date = "" 65 | Title = "" 66 | Description = "" 67 | UnmappedResultCode = "" 68 | ClientApplicationID = "" 69 | ServerSelection = "" 70 | ServiceID = "" 71 | UninstallationNotes = "" 72 | SupportUrl = "" 73 | }; 74 | 75 | $Hotfixes = invoke-command -Computer $Computer -scriptblock { 76 | 77 | $Session = New-Object -ComObject "Microsoft.Update.Session"; 78 | $Searcher = $Session.CreateUpdateSearcher(); 79 | $historyCount = $Searcher.GetTotalHistoryCount(); 80 | $Searcher.QueryHistory(0, $historyCount) | Select-Object PSComputerName, Operation, ResultCode, HResult, Date, Title, Description, UnmappedResultCode, ClientApplicationID, ServerSelection, ServiceID, UninstallationNotes, SupportUrl | Where-Object Title -ne $null; 81 | }; 82 | 83 | if ($Hotfixes){ 84 | 85 | $Hotfixes | ForEach-Object { 86 | 87 | $output.PSComputerName = $_.PSComputerName; 88 | $output.Operation = $_.Operation; 89 | $output.ResultCode = $_.ResultCode; 90 | $output.HResult = $_.HResult; 91 | $output.Date = $_.Date; 92 | $output.Title = $_.Title; 93 | $output.Description = $_.Description; 94 | $output.UnmappedResultCode = $_.UnmappedResultCode; 95 | $output.ClientApplicationID = $_.ClientApplicationID; 96 | $output.ServerSelection = $_.ServerSelection; 97 | $output.ServiceID = $_.ServiceID; 98 | $output.UninstallationNotes = $_.UninstallationNotes; 99 | $output.SupportUrl = $_.SupportUrl; 100 | 101 | $output.PsObject.Members | ForEach-Object {$output.PsObject.Members.Remove($_.Name)}; 102 | return $output; 103 | }; 104 | } 105 | else { 106 | 107 | Write-Verbose ("{0}: System failed." -f $Computer); 108 | if ($Fails) { 109 | 110 | $total++; 111 | Add-Content -Path $Fails -Value ("$Computer"); 112 | } 113 | else { 114 | 115 | $output = $null; 116 | $output = [ArpCache]::new(); 117 | 118 | $output.Computer = $Computer; 119 | $output.DateScanned = Get-Date -Format u; 120 | 121 | $total++; 122 | return $output; 123 | }; 124 | }; 125 | }; 126 | 127 | end { 128 | 129 | $elapsed = $stopwatch.Elapsed; 130 | 131 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 132 | }; 133 | }; -------------------------------------------------------------------------------- /Functions/Hunt-HostsEntries.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-HostsEntries { 2 | <# 3 | .Synopsis 4 | Gets the arp cache for the given computer(s). 5 | 6 | .Description 7 | Gets the arp cache from all connected interfaces for the given computer(s). 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-HostsEntries 17 | Hunt-HostsEntries SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-HostsEntries 19 | Hunt-HostsEntries -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-HostsEntries 21 | 22 | .Notes 23 | Updated: 2017-10-19 24 | 25 | Contributing Authors: 26 | Anthony Phipps 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | #> 42 | 43 | param( 44 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 45 | $Computer = $env:COMPUTERNAME, 46 | 47 | [Parameter()] 48 | $Fails 49 | ); 50 | 51 | begin{ 52 | 53 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 54 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 55 | 56 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 57 | $stopwatch.Start(); 58 | $total = 0; 59 | 60 | class Entry 61 | { 62 | [string] $Computer 63 | [Datetime] $DateScanned 64 | 65 | [String] $HostsIP 66 | [string] $HostsName 67 | [String] $HostsComment 68 | }; 69 | }; 70 | 71 | process{ 72 | 73 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 74 | 75 | $HostsData = Invoke-Command -ComputerName $Computer -ErrorAction SilentlyContinue -ScriptBlock { 76 | $Hosts = Join-Path -Path $($env:windir) -ChildPath "system32\drivers\etc\hosts"; 77 | 78 | [regex]$nonwhitespace = "\S"; 79 | 80 | Get-Content $Hosts | Where-Object { 81 | (($nonwhitespace.Match($_)).value -ne "#") -and ($_ -notmatch "^\s+$") -and ($_.Length -gt 0); # exlcude full-line comments and blank lines 82 | }; 83 | }; 84 | 85 | if ($HostsData){ 86 | 87 | $OutputArray = @(); 88 | 89 | Write-Verbose ("{0}: Parsing results." -f $Computer); 90 | $HostsData | ForEach-Object { 91 | 92 | $ip = $null; 93 | $hostname = $null; 94 | $comment = $null; 95 | 96 | $_ -match "(?\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+(?\S+)" | Out-Null; 97 | 98 | $ip = $matches.ip; 99 | $hostname = $matches.hostname; 100 | 101 | if ($_.contains("#")) { 102 | 103 | $comment = $_.substring($_.indexof("#")+1); 104 | }; 105 | 106 | $output = $null; 107 | $output = [Entry]::new(); 108 | 109 | $output.Computer = $Computer; 110 | $output.DateScanned = Get-Date -Format u; 111 | 112 | $output.HostsIP = $ip; 113 | $output.HostsName = $hostname; 114 | $output.HostsComment = $comment; 115 | 116 | $OutputArray += $output; 117 | } 118 | 119 | $total++; 120 | return $OutputArray; 121 | } 122 | else { 123 | 124 | Write-Verbose ("{0}: System failed." -f $Computer); 125 | if ($Fails) { 126 | 127 | $total++; 128 | Add-Content -Path $Fails -Value ("$Computer"); 129 | } 130 | else { 131 | 132 | $output = $null; 133 | $output = [Entry]::new(); 134 | 135 | $output.Computer = $Computer; 136 | $output.DateScanned = Get-Date -Format u; 137 | 138 | $total++; 139 | return $output; 140 | }; 141 | }; 142 | }; 143 | 144 | end { 145 | 146 | $elapsed = $stopwatch.Elapsed; 147 | 148 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 149 | }; 150 | }; -------------------------------------------------------------------------------- /Functions/Hunt-ArpCache.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-ArpCache { 2 | <# 3 | .Synopsis 4 | Gets the arp cache for the given computer(s). 5 | 6 | .Description 7 | Gets the arp cache from all connected interfaces for the given computer(s). 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-ArpCache 17 | Hunt-ArpCache SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-ArpCache 19 | Hunt-ArpCache -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-ArpCache 21 | 22 | .Notes 23 | Updated: 2017-10-19 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | Anthony Phipps 28 | 29 | LEGAL: Copyright (C) 2017 30 | This program is free software: you can redistribute it and/or modify 31 | it under the terms of the GNU General Public License as published by 32 | the Free Software Foundation, either version 3 of the License, or 33 | (at your option) any later version. 34 | 35 | This program is distributed in the hope that it will be useful, 36 | but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 | GNU General Public License for more details. 39 | 40 | You should have received a copy of the GNU General Public License 41 | along with this program. If not, see . 42 | #> 43 | 44 | param( 45 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 46 | $Computer = $env:COMPUTERNAME, 47 | [Parameter()] 48 | $Fails 49 | ); 50 | 51 | begin{ 52 | 53 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 54 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 55 | 56 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 57 | $stopwatch.Start(); 58 | $total = 0; 59 | 60 | class ArpCache 61 | { 62 | [string] $Computer 63 | [Datetime] $DateScanned 64 | 65 | [String] $IfIndex 66 | [string] $InterfaceAlias 67 | [String] $IPAdress 68 | [String] $LinkLayerAddress 69 | [String] $State 70 | [String] $PolicyStore 71 | }; 72 | }; 73 | 74 | process{ 75 | 76 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 77 | 78 | 79 | $arpCache = Invoke-Command -ComputerName $Computer -ErrorAction SilentlyContinue -ScriptBlock { 80 | Get-NetNeighbor | 81 | Where-Object {($_.LinkLayerAddress -ne "") -and 82 | ($_.LinkLayerAddress -ne "FF-FF-FF-FF-FF-FF") -and # Broadcast. Filtered by LinkLayerAddress rather than "$_.State -ne "permanent" to maintain manual entries 83 | ($_.LinkLayerAddress -notlike "01-00-5E-*") -and # IPv4 multicast 84 | ($_.LinkLayerAddress -notlike "33-33-*") # IPv6 multicast 85 | }; 86 | }; 87 | 88 | 89 | if ($arpCache) { 90 | 91 | Write-Verbose ("{0}: Parsing results." -f $Computer); 92 | $OutputArray = @(); 93 | 94 | foreach ($record in $arpCache) { 95 | 96 | $output = $null; 97 | $output = [ArpCache]::new(); 98 | 99 | $output.Computer = $Computer; 100 | $output.DateScanned = Get-Date -Format u; 101 | 102 | $output.IfIndex = $record.ifIndex; 103 | $output.InterfaceAlias = $record.InterfaceAlias; 104 | $output.IPAdress = $record.IPAddress; 105 | $output.LinkLayerAddress = $record.LinkLayerAddress; 106 | $output.State = $record.State; 107 | $output.PolicyStore = $record.Store; 108 | 109 | $OutputArray += $output; 110 | }; 111 | 112 | $total = $total+1; 113 | return $OutputArray; 114 | 115 | } 116 | else { 117 | 118 | Write-Verbose ("{0}: System failed." -f $Computer); 119 | if ($Fails) { 120 | 121 | $total++; 122 | Add-Content -Path $Fails -Value ("$Computer"); 123 | } 124 | else { 125 | 126 | $output = $null; 127 | $output = [ArpCache]::new(); 128 | 129 | $output.Computer = $Computer; 130 | $output.DateScanned = Get-Date -Format u; 131 | 132 | $total++; 133 | return $output; 134 | }; 135 | }; 136 | }; 137 | 138 | end { 139 | 140 | $elapsed = $stopwatch.Elapsed; 141 | 142 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 143 | }; 144 | }; -------------------------------------------------------------------------------- /Functions/Hunt-LoginSessions.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-LoginSessions { 2 | <# 3 | .Synopsis 4 | Gets the login sessions for the given computer(s). 5 | 6 | .Description 7 | Gets the login sessions for the given computer(s) utizling the builtin "qwinsta.exe" tool. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-LoginSessions 17 | Hunt-LoginSessions SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-LoginSessions 19 | Hunt-LoginSessions -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-LoginSessions 21 | 22 | .Notes 23 | Updated: 2017-10-17 24 | 25 | Contributing Authors: 26 | Anthony Phipps 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | #> 42 | 43 | param( 44 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 45 | $Computer = $env:COMPUTERNAME, 46 | 47 | [Parameter()] 48 | $Fails 49 | ); 50 | 51 | begin{ 52 | 53 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 54 | Write-Verbose ("Started at {0}" -f $datetime); 55 | 56 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 57 | $stopwatch.Start(); 58 | $total = 0; 59 | 60 | class LoginSession { 61 | [string] $Computer 62 | [Datetime] $DateScanned 63 | 64 | [String] $SessionName 65 | [String] $UserName 66 | [String] $Id 67 | [String] $State 68 | [String] $Type 69 | [String] $Device 70 | }; 71 | }; 72 | 73 | process{ 74 | 75 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 76 | 77 | Write-Verbose ("{0}: Querying remote system" -f $Computer); 78 | $sessions = $null; 79 | $sessions = (qwinsta /server:$Computer 2> $null | Foreach-Object { (($_.trim() -replace "\s+",","))} | ConvertFrom-Csv); 80 | 81 | if ($sessions) { 82 | 83 | $OutputArray = @(); 84 | 85 | Write-Verbose ("{0}: Looping through retrived results" -f $Computer); 86 | foreach ($session in $sessions) { 87 | 88 | $output = $null; 89 | $output = [LoginSession]::new(); 90 | 91 | $output.Computer = $Computer; 92 | $output.DateScanned = Get-Date -Format u; 93 | 94 | $output.SessionName = $session.SESSIONNAME; 95 | 96 | if ($session.STATE -eq $null) { 97 | $output.Id = $session.USERNAME; 98 | $output.State = $session.ID; 99 | $output.Type = $session.STATE; 100 | } 101 | else { 102 | $output.UserName = $session.USERNAME; 103 | $output.Id = $session.ID; 104 | $output.State = $session.STATE; 105 | $output.Type = $session.TYPE; 106 | $output.Device = $session.DEVICE; 107 | } 108 | 109 | $OutputArray += $output; 110 | }; 111 | 112 | $elapsed = $stopwatch.Elapsed; 113 | $total = $total + 1; 114 | 115 | Write-Verbose ("System {0} complete: `t {1} `t Total Time Elapsed: {2}" -f $total, $Computer, $elapsed); 116 | 117 | $total = $total+1; 118 | Return $OutputArray; 119 | } 120 | else { 121 | 122 | Write-Verbose ("{0}: System failed." -f $Computer); 123 | if ($Fails) { 124 | 125 | $total++; 126 | Add-Content -Path $Fails -Value ("$Computer"); 127 | } 128 | else { 129 | 130 | $output = $null; 131 | $output = [LoginSession]::new(); 132 | 133 | $output.Computer = $Computer; 134 | $output.DateScanned = Get-Date -Format u; 135 | 136 | $total++; 137 | return $output; 138 | }; 139 | }; 140 | }; 141 | 142 | end { 143 | 144 | $elapsed = $stopwatch.Elapsed; 145 | 146 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 147 | }; 148 | }; -------------------------------------------------------------------------------- /Functions/Add-WinEventXMLData.ps1: -------------------------------------------------------------------------------- 1 | Function Add-WinEventXMLData { 2 | <# 3 | .SYNOPSIS 4 | Add XML fields to an event log record. 5 | 6 | .DESCRIPTION 7 | Add XML fields to an event log record. 8 | Takes in Event Log entries from Get-WinEvent, converts each to XML, extracts all properties and adds them to the event object. 9 | 10 | .PARAMETER Event 11 | One or more events. 12 | Accepts data from Get-WinEvent or any System.Diagnostics.Eventing.Reader.EventLogRecord object 13 | 14 | .INPUTS 15 | System.Diagnostics.Eventing.Reader.EventLogRecord 16 | 17 | .OUTPUTS 18 | System.Diagnostics.Eventing.Reader.EventLogRecord 19 | 20 | .EXAMPLE 21 | Get Windows Applocker events and XML fields. 22 | Get-WinEvent -FilterhashTable @{ LogName="Microsoft-Windows-AppLocker/EXE and DLL"; ID="8002","8003","8004" } -MaxEvents 10 | 23 | Add-WinEventXMLData | 24 | Select-Object *; 25 | 26 | .EXAMPLE 27 | Get Windows Sysmon events and XML fields. 28 | Get-WinEvent -filterhashtable @{ LogName="Microsoft-Windows-Sysmon/Operational" } | 29 | Add-WinEventXMLData | 30 | Select-Object *; 31 | 32 | Or from a WEF/WEC: 33 | Get-WinEvent -ComputerName WEFSERVER -FilterHashtable @{ LogName="ForwardedEvents"; Id=1; StartTime=(Get-Date).AddDays(-2) } -MaxEvents 10 | 34 | Where-Object { $_.LogName -eq "Microsoft-Windows-Sysmon/Operational" } | 35 | Add-WinEventXMLData | 36 | Select-Object *; 37 | 38 | .EXAMPLE 39 | Get Windows System logs and XML fields. 40 | Get-WinEvent -FilterHashtable @{ LogName="System" } -MaxEvents 10 | 41 | Add-WinEventXMLData | 42 | Select-Object *; 43 | 44 | .EXAMPLE 45 | Get-WinEvent -FilterHashtable @{ LogName="ForwardedEvents" } -MaxEvents 10 | 46 | Add-WinEventXMLData | 47 | Select-Object *; 48 | 49 | .NOTES 50 | Updated: 2017-10-10 51 | 52 | Contributing Authors: 53 | Anthony Phipps 54 | 55 | LEGAL: Copyright (C) 2017 56 | This program is free software: you can redistribute it and/or modify 57 | it under the terms of the GNU General Public License as published by 58 | the Free Software Foundation, either version 3 of the License, or 59 | (at your option) any later version. 60 | 61 | This program is distributed in the hope that it will be useful, 62 | but WITHOUT ANY WARRANTY; without even the implied warranty of 63 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 64 | GNU General Public License for more details. 65 | 66 | You should have received a copy of the GNU General Public License 67 | along with this program. If not, see . 68 | 69 | .FUNCTIONALITY 70 | Computers 71 | #> 72 | 73 | [CmdletBinding()] 74 | Param( 75 | [Parameter(Mandatory = $true, 76 | ValueFromPipeline = $true, 77 | ValueFromPipelineByPropertyName = $true, 78 | ValueFromRemainingArguments = $false, 79 | Position = 0 )] 80 | [System.Diagnostics.Eventing.Reader.EventLogRecord[]] 81 | $Event 82 | ); 83 | 84 | Process { 85 | 86 | $output = $_; 87 | 88 | $EventXML = [xml]$_.ToXml(); 89 | 90 | if ($EventXML.Event.UserData.RuleAndFileData) { 91 | 92 | Write-Verbose "Event Type: AppLocker"; 93 | $EventXMLFields = $EventXML.Event.UserData.RuleAndFileData | Get-Member | Where-Object {$_.Membertype -eq "Property"} | Select-Object Name; 94 | 95 | $EventXMLFields | ForEach-Object { 96 | $output | Add-Member -MemberType NoteProperty -Name $_.Name -Value $EventXML.Event.UserData.RuleAndFileData.($_.Name); 97 | }; 98 | } 99 | elseif ($EventXML.Event.UserData.CbsPackageInitiateChanges) { 100 | 101 | Write-Verbose "Event Type: Setup"; 102 | $EventXMLFields = $EventXML.Event.UserData.CbsPackageInitiateChanges | Get-Member | Where-Object {$_.Membertype -eq "Property"} | Select-Object Name; ; 103 | 104 | $EventXMLFields | ForEach-Object { 105 | $output | Add-Member -MemberType NoteProperty -Name $_.Name -Value $EventXML.Event.UserData.CbsPackageInitiateChanges.($_.Name); 106 | }; 107 | } 108 | elseif ($EventXML.Event.UserData.CbsPackageChangeState) { 109 | 110 | Write-Verbose "Event Type: Setup"; 111 | $EventXMLFields = $EventXML.Event.UserData.CbsPackageChangeState | Get-Member | Where-Object {$_.Membertype -eq "Property"} | Select-Object Name; 112 | 113 | $EventXMLFields | ForEach-Object { 114 | $output | Add-Member -MemberType NoteProperty -Name $_.Name -Value $EventXML.Event.UserData.CbsPackageChangeState.($_.Name); 115 | }; 116 | } 117 | elseif ($EventXML.Event.EventData.Data[0].Name) { 118 | 119 | Write-Verbose "Event Type: Generic"; 120 | $EventXMLFields = $EventXML.Event.EventData.Data; 121 | 122 | For ( $i = 0; $i -lt $EventXMLFields.count; $i++ ) { 123 | $output | Add-Member -MemberType NoteProperty -Name $EventXMLFields[$i].Name -Value $EventXMLFields[$i].'#text' -Force; 124 | }; 125 | }; 126 | 127 | Return $output; 128 | }; 129 | }; 130 | -------------------------------------------------------------------------------- /Functions/Hunt-ActivePorts.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-ActivePorts { 2 | <# 3 | .Synopsis 4 | Gets the active ports for the given computer(s). 5 | 6 | .Description 7 | Gets the active ports for the given computer(s) and returns a PS Object. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Path 13 | Resolve owning PID to process path. Increases hunt time per system. 14 | 15 | .Parameter Fails 16 | Provide a path to save failed systems to. 17 | 18 | .Example 19 | Hunt-ActivePorts 20 | Hunt-ActivePorts SomeHostName.domain.com 21 | Get-Content C:\hosts.csv | Hunt-ActivePorts 22 | Hunt-ActivePorts -Computer $env:computername 23 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-ActivePorts 24 | 25 | .Notes 26 | Updated: 2017-10-17 27 | 28 | Contributing Authors: 29 | Jeremy Arnold 30 | Anthony Phipps 31 | 32 | LEGAL: Copyright (C) 2017 33 | This program is free software: you can redistribute it and/or modify 34 | it under the terms of the GNU General Public License as published by 35 | the Free Software Foundation, either version 3 of the License, or 36 | (at your option) any later version. 37 | 38 | This program is distributed in the hope that it will be useful, 39 | but WITHOUT ANY WARRANTY; without even the implied warranty of 40 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 41 | GNU General Public License for more details. 42 | You should have received a copy of the GNU General Public License 43 | along with this program. If not, see . 44 | #> 45 | 46 | param( 47 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 48 | $Computer = $env:COMPUTERNAME, 49 | 50 | [Parameter()] 51 | [switch] $Path, 52 | 53 | [Parameter()] 54 | $Fails 55 | ); 56 | 57 | begin{ 58 | 59 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 60 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 61 | 62 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 63 | $stopwatch.Start(); 64 | $total = 0; 65 | 66 | class TCPConnection 67 | { 68 | [String] $Computer 69 | [DateTime] $DateScanned 70 | 71 | [String] $LocalAddress 72 | [String] $LocalPort 73 | [String] $RemoteAddress 74 | [String] $RemotePort 75 | [String] $State 76 | [String] $AppliedSetting 77 | [String] $OwningProcessID 78 | [String] $OwningProcessPath 79 | }; 80 | }; 81 | 82 | process{ 83 | 84 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 85 | 86 | $TCPConnections = $null; 87 | $TCPConnections = Invoke-Command -ComputerName $Computer -ScriptBlock { 88 | $TCPConnections = Get-NetTCPConnection -State Listen, Established; 89 | 90 | if ($using:Path) { 91 | $TCPConnections | ForEach-Object { 92 | $_ | Add-Member -MemberType NoteProperty -Name Path -Value ((Get-Process -Id $_.OwningProcess).Path); 93 | }; 94 | }; 95 | 96 | return $TCPConnections; 97 | }; 98 | 99 | if ($TCPConnections) { 100 | 101 | Write-Verbose ("{0}: Parsing results." -f $Computer); 102 | $OutputArray = @(); 103 | 104 | foreach ($TCPConnection in $TCPConnections) { 105 | 106 | $output = $null; 107 | $output = [TCPConnection]::new(); 108 | 109 | $output.Computer = $Computer; 110 | $output.DateScanned = Get-Date -Format u; 111 | 112 | $output.LocalAddress = $TCPConnection.LocalAddress; 113 | $output.LocalPort = $TCPConnection.LocalPort; 114 | $output.RemoteAddress = $TCPConnection.RemoteAddress; 115 | $output.RemotePort = $TCPConnection.RemotePort; 116 | $output.State = $TCPConnection.State; 117 | $output.AppliedSetting = $TCPConnection.AppliedSetting; 118 | $output.OwningProcessID = $TCPConnection.OwningProcess; 119 | $output.OwningProcessPath = $TCPConnection.Path; 120 | 121 | $OutputArray += $output; 122 | }; 123 | 124 | $total++; 125 | return $OutputArray; 126 | } 127 | else { 128 | 129 | Write-Verbose ("{0}: System failed." -f $Computer); 130 | if ($Fails) { 131 | 132 | $total++; 133 | Add-Content -Path $Fails -Value ("$Computer"); 134 | } 135 | else { 136 | 137 | $output = $null; 138 | $output = [TCPConnection]::new(); 139 | 140 | $output.Computer = $Computer; 141 | $output.DateScanned = Get-Date -Format u; 142 | 143 | $total++; 144 | return $output; 145 | }; 146 | }; 147 | }; 148 | 149 | end { 150 | 151 | $elapsed = $stopwatch.Elapsed; 152 | 153 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 154 | }; 155 | }; -------------------------------------------------------------------------------- /Functions/Hunt-IPv4Route.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-IPv4Route { 2 | <# 3 | .Synopsis 4 | Gets a list of IPv4 Routes on a given system. 5 | 6 | .Description 7 | Gets a list of IPv4 Routes on a given system. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-IPv4Route 17 | Hunt-IPv4Route SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-IPv4Route 19 | Hunt-Hunt-IPv4Route $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-Hunt-IPv4Route 21 | 22 | .Notes 23 | Updated: 2017-10-26 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | 42 | .LINK 43 | https://github.com/DLACERT/ThreatHunting 44 | #> 45 | 46 | param( 47 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 48 | $Computer = $env:COMPUTERNAME, 49 | [Parameter()] 50 | $Fails 51 | ); 52 | 53 | begin{ 54 | 55 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 56 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 57 | 58 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 59 | $stopwatch.Start(); 60 | 61 | $total = 0; 62 | 63 | Enum RouteType 64 | { 65 | AdminDefinedRoute = 2 66 | ComputedRoute = 3 67 | ActualRoute = 4 68 | } 69 | 70 | class RouteTable 71 | { 72 | [String] $Computer 73 | [dateTime] $DateScanned 74 | 75 | [String] $InterfaceIndex 76 | [String] $InterfaceName 77 | [String] $DestinationPrefix 78 | [String] $NextHop 79 | [String] $Metric 80 | [String] $Protocol 81 | [String] $Store 82 | [String] $PublishedRoute 83 | [RouteType] $TypeOfRoute 84 | }; 85 | }; 86 | 87 | process{ 88 | 89 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 90 | 91 | $routes = $null; 92 | $routes = Invoke-Command -ComputerName $Computer -ErrorAction SilentlyContinue -ScriptBlock { 93 | 94 | $interfaces = $null; 95 | $interfaces = Get-NetAdapter | Where-Object {$_.MediaConnectionState -eq "Connected"}; 96 | $routeTable = $null; 97 | 98 | Foreach ($interface in $interfaces) { # loop through each interface 99 | 100 | $routeTable += Get-NetRoute -AddressFamily IPv4 -InterfaceIndex $interface.ifIndex -IncludeAllCompartments; 101 | 102 | }; 103 | 104 | return $routeTable; 105 | 106 | }; 107 | 108 | if ($routes) { 109 | 110 | $outputArray = @(); 111 | 112 | Foreach ($route in $routes) { 113 | 114 | $output = $null; 115 | $output = [RouteTable]::new(); 116 | 117 | $output.Computer = $Computer; 118 | $output.DateScanned = Get-Date -Format u; 119 | 120 | $output.InterfaceIndex = $route.ifIndex; 121 | $output.InterfaceName= $route.interfaceAlias; 122 | $output.DestinationPrefix = $route.DestinationPrefix; 123 | $output.NextHop = $route.NextHop; 124 | $output.Metric = $route.RouteMetric; 125 | $output.Protocol = $route.Protocol; 126 | $output.Store = $route.Store 127 | $output.PublishedRoute = $route.Publish; 128 | $output.TypeOfRoute = $route.TypeOfRoute; 129 | 130 | $outputArray += $output; 131 | }; 132 | 133 | return $outputArray; 134 | 135 | } 136 | else { 137 | 138 | Write-Verbose ("{0}: System failed." -f $Computer); 139 | if ($Fails) { 140 | 141 | $total++; 142 | Add-Content -Path $Fails -Value ("$Computer"); 143 | } 144 | else { 145 | 146 | $output = $null; 147 | $output = [RouteTable]::new(); 148 | 149 | $output.Computer = $Computer; 150 | $output.DateScanned = Get-Date -Format u; 151 | 152 | $total++; 153 | return $output; 154 | }; 155 | }; 156 | }; 157 | 158 | end { 159 | 160 | $elapsed = $stopwatch.Elapsed; 161 | 162 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 163 | }; 164 | }; -------------------------------------------------------------------------------- /Functions/Hunt-RecycleBin.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-RecycleBin { 2 | <# 3 | .Synopsis 4 | Gets the login sessions for the given computer(s). 5 | 6 | .Description 7 | Gets the login sessions for the given computer(s) utizling the builtin "qwinsta.exe" tool. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-RecycleBin 17 | Hunt-RecycleBin SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-RecycleBin 19 | Hunt-RecycleBin -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-RecycleBin 21 | 22 | .Notes 23 | Updated: 2017-10-17 24 | 25 | Contributing Authors: 26 | Anthony Phipps 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | #> 42 | 43 | param( 44 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 45 | $Computer = $env:COMPUTERNAME, 46 | 47 | [Parameter()] 48 | $Fails 49 | ); 50 | 51 | begin{ 52 | 53 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 54 | Write-Verbose ("Started at {0}" -f $datetime); 55 | 56 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 57 | $stopwatch.Start(); 58 | $total = 0; 59 | 60 | class DeletedItem { 61 | [string] $Computer 62 | [Datetime] $DateScanned 63 | 64 | [String] $LinkType 65 | [String] $Name 66 | [String] $Length 67 | [String] $Directory 68 | [String] $IsReadOnly 69 | [String] $Exists 70 | [String] $FullName 71 | [String] $CreationTimeUtc 72 | [String] $LastAccessTimeUtc 73 | [String] $LastWriteTimeUtc 74 | [String] $IsContainer 75 | [String] $Mode 76 | }; 77 | }; 78 | 79 | process{ 80 | 81 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 82 | 83 | Write-Verbose ("{0}: Querying remote system" -f $Computer); 84 | $recycleBin = $null; 85 | $recycleBin = Invoke-Command -ComputerName $Computer -ErrorAction SilentlyContinue -ScriptBlock { 86 | Get-ChildItem ("{0}\`$Recycle.Bin" -f $env:SystemDrive) -Force -Recurse; 87 | }; 88 | 89 | if ($recycleBin) { 90 | 91 | $OutputArray = @(); 92 | 93 | Write-Verbose ("{0}: Looping through retrived results" -f $Computer); 94 | foreach ($recycled in $recycleBin) { 95 | 96 | $output = $null; 97 | $output = [DeletedItem]::new(); 98 | 99 | $output.Computer = $Computer; 100 | $output.DateScanned = Get-Date -Format u; 101 | 102 | $output.LinkType = $recycled.LinkType 103 | $output.Name = $recycled.Name 104 | $output.Length = $recycled.Length 105 | $output.Directory = $recycled.Directory 106 | $output.IsReadOnly = $recycled.IsReadOnly 107 | $output.Exists = $recycled.Exists 108 | $output.FullName = $recycled.FullName 109 | $output.CreationTimeUtc = $recycled.CreationTimeUtc 110 | $output.LastAccessTimeUtc = $recycled.LastAccessTimeUtc 111 | $output.LastWriteTimeUtc = $recycled.LastWriteTimeUtc 112 | $output.IsContainer = $recycled.PSIsContainer 113 | $output.Mode = $recycled.Mode 114 | 115 | $OutputArray += $output; 116 | }; 117 | 118 | $elapsed = $stopwatch.Elapsed; 119 | $total = $total + 1; 120 | 121 | Write-Verbose ("System {0} complete: `t {1} `t Total Time Elapsed: {2}" -f $total, $Computer, $elapsed); 122 | 123 | $total = $total+1; 124 | return $OutputArray; 125 | } 126 | else { 127 | 128 | Write-Verbose ("{0}: System failed." -f $Computer); 129 | if ($Fails) { 130 | 131 | $total++; 132 | Add-Content -Path $Fails -Value ("$Computer"); 133 | } 134 | else { 135 | 136 | $output = $null; 137 | $output = [DeletedItem]::new(); 138 | 139 | $output.Computer = $Computer; 140 | $output.DateScanned = Get-Date -Format u; 141 | 142 | $total++; 143 | return $output; 144 | }; 145 | }; 146 | }; 147 | 148 | end { 149 | 150 | $elapsed = $stopwatch.Elapsed; 151 | 152 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 153 | }; 154 | }; -------------------------------------------------------------------------------- /Functions/Hunt-DnsCache.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-DNSCache { 2 | <# 3 | .Synopsis 4 | Gets the DNS cache for the given computer(s). 5 | 6 | .Description 7 | Gets the DNS cache from all connected interfaces for the given computer(s). 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-DNSCache 17 | Hunt-DNSCache SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-DNSCache 19 | Hunt-DNSCache -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-DNSCache 21 | 22 | .Notes 23 | Updated: 2017-10-17 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | Anthony Phipps 28 | 29 | LEGAL: Copyright (C) 2017 30 | This program is free software: you can redistribute it and/or modify 31 | it under the terms of the GNU General Public License as published by 32 | the Free Software Foundation, either version 3 of the License, or 33 | (at your option) any later version. 34 | 35 | This program is distributed in the hope that it will be useful, 36 | but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 | GNU General Public License for more details. 39 | 40 | You should have received a copy of the GNU General Public License 41 | along with this program. If not, see . 42 | #> 43 | 44 | param( 45 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 46 | $Computer = $env:COMPUTERNAME, 47 | [Parameter()] 48 | $Fails 49 | ); 50 | 51 | begin{ 52 | 53 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 54 | Write-Verbose ("Started at {0}" -f $datetime); 55 | 56 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 57 | $stopwatch.Start(); 58 | $total = 0; 59 | 60 | enum recordType { 61 | A = 1 62 | NS = 2 63 | CNAME = 5 64 | SOA = 6 65 | WKS = 11 66 | PTR = 12 67 | HINFO = 13 68 | MINFO = 14 69 | MX = 15 70 | TXT = 16 71 | AAAA = 28 72 | SRV = 33 73 | ALL = 255 74 | }; 75 | 76 | enum recordStatus { 77 | Success = 0 78 | NotExist = 9003 79 | NoRecords = 9501 80 | }; 81 | 82 | enum recordResponse { 83 | Question = 0 84 | Answer = 1 85 | Authority = 2 86 | Additional = 3 87 | }; 88 | 89 | class DNSCache { 90 | [string] $Computer 91 | [Datetime] $DateScanned 92 | 93 | [recordStatus] $Status 94 | [String] $DataLength 95 | [recordresponse] $RecordResponse 96 | [String] $TTL 97 | [RecordType] $RecordType 98 | [String] $Record 99 | [string] $Entry 100 | [string] $RecordName 101 | }; 102 | }; 103 | 104 | process{ 105 | 106 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 107 | 108 | Write-Verbose ("{0}: Querying remote system" -f $Computer); 109 | $dnsCache = $null; 110 | $dnsCache = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-DnsClientCache } -ErrorAction SilentlyContinue; 111 | 112 | if ($dnsCache) { 113 | 114 | $OutputArray = @(); 115 | 116 | Write-Verbose ("{0}: Looping through retrived results" -f $Computer); 117 | foreach ($dnsRecord in $dnsCache) { 118 | 119 | $output = $null; 120 | $output = [DNSCache]::new(); 121 | 122 | $output.Computer = $Computer; 123 | $output.DateScanned = Get-Date -Format u; 124 | 125 | $output.Status = $dnsRecord.status; 126 | $output.DataLength = $dnsRecord.dataLength; 127 | $output.RecordResponse = $dnsRecord.section; 128 | $output.TTL = $dnsRecord.TimeToLive; 129 | $output.RecordType = $dnsRecord.Type; 130 | $output.Record = $dnsRecord.data; 131 | $output.Entry = $dnsRecord.entry; 132 | $output.RecordName = $dnsRecord.Name; 133 | 134 | $OutputArray += $output; 135 | }; 136 | 137 | $elapsed = $stopwatch.Elapsed; 138 | $total = $total + 1; 139 | 140 | Write-Verbose ("System {0} complete: `t {1} `t Total Time Elapsed: {2}" -f $total, $Computer, $elapsed); 141 | 142 | $total = $total+1; 143 | Return $OutputArray; 144 | } 145 | else { 146 | 147 | Write-Verbose ("{0}: System failed." -f $Computer); 148 | if ($Fails) { 149 | 150 | $total++; 151 | Add-Content -Path $Fails -Value ("$Computer"); 152 | } 153 | else { 154 | 155 | $output = $null; 156 | $output = [DNSCache]::new(); 157 | 158 | $output.Computer = $Computer; 159 | $output.DateScanned = Get-Date -Format u; 160 | 161 | $total++; 162 | return $output; 163 | }; 164 | }; 165 | }; 166 | 167 | end { 168 | 169 | $elapsed = $stopwatch.Elapsed; 170 | 171 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 172 | }; 173 | }; -------------------------------------------------------------------------------- /Functions/Hunt-ScheduledTasks.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-ScheduledTasks { 2 | <# 3 | .Synopsis 4 | Gets the scheduled tasks on a given system. 5 | 6 | .Description 7 | Gets the scheduled tasks on a given system. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-ScheduledTasks 17 | Hunt-ScheduledTasks SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-ScheduledTasks 19 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-ScheduledTasks 20 | 21 | .Notes 22 | Updated: 2017-10-10 23 | 24 | Contributing Authors: 25 | Anthony Phipps 26 | 27 | LEGAL: Copyright (C) 2017 28 | This program is free software: you can redistribute it and/or modify 29 | it under the terms of the GNU General Public License as published by 30 | the Free Software Foundation, either version 3 of the License, or 31 | (at your option) any later version. 32 | 33 | This program is distributed in the hope that it will be useful, 34 | but WITHOUT ANY WARRANTY; without even the implied warranty of 35 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 | GNU General Public License for more details. 37 | 38 | You should have received a copy of the GNU General Public License 39 | along with this program. If not, see . 40 | #> 41 | 42 | PARAM( 43 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 44 | $Computer = $env:COMPUTERNAME, 45 | [Parameter()] 46 | $Fails 47 | 48 | ); 49 | 50 | BEGIN{ 51 | 52 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 53 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 54 | 55 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 56 | $stopwatch.Start(); 57 | 58 | $total = 0; 59 | 60 | class Task { 61 | [String] $Computer 62 | [DateTime] $DateScanned 63 | 64 | [String] $ActionsArguments 65 | [String] $ActionsExecute 66 | [String] $ActionsId 67 | [String] $ActionsWorkingDirectory 68 | [String] $Author 69 | [String] $Description 70 | [String] $SecurityDescriptor 71 | [String] $Source 72 | [String] $State 73 | [String] $TaskName 74 | [String] $TaskPath 75 | [String] $TriggersDelay 76 | [String] $TriggersEnabled 77 | [String] $TriggersEndBoundary 78 | [String] $TriggersExecutionTimeLimit 79 | [String] $TriggersPSComputerName 80 | [String] $TriggersRepetition 81 | [String] $TriggersStartBoundary 82 | [String] $URI 83 | } 84 | } 85 | 86 | PROCESS{ 87 | 88 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 89 | 90 | $Tasks = $null; 91 | 92 | $Tasks = Invoke-Command -ComputerName $Computer -ScriptBlock {Get-ScheduledTask | Select-Object *} -ErrorAction SilentlyContinue; 93 | 94 | if ($Tasks) { 95 | 96 | $Tasks | ForEach-Object { 97 | 98 | $output = $null; 99 | $output = [Task]::new(); 100 | 101 | $output.Computer = $Computer; 102 | $output.DateScanned = Get-Date -Format u; 103 | 104 | $output.ActionsArguments = ($_.Actions.Arguments -join "; "); 105 | $output.ActionsExecute = ($_.Actions.Execute -join "; "); 106 | $output.ActionsId = ($_.Actions.Id -join "; "); 107 | $output.ActionsWorkingDirectory = ($_.Actions.WorkingDirectory -join "; "); 108 | $output.Author = $_.Author; 109 | $output.Description = $_.Description; 110 | $output.SecurityDescriptor = $_.SecurityDescriptor; 111 | $output.Source = $_.Source; 112 | $output.State = $_.State; 113 | $output.TaskName = $_.TaskName; 114 | $output.TaskPath = $_.TaskPath; 115 | $output.TriggersDelay = ($_.Triggers.Delay -join "; "); 116 | $output.TriggersEnabled = ($_.Triggers.Enabled -join "; "); 117 | $output.TriggersEndBoundary = ($_.Triggers.EndBoundary -join "; "); 118 | $output.TriggersExecutionTimeLimit = ($_.Triggers.ExecutionTimeLimit -join "; "); 119 | $output.TriggersPSComputerName = ($_.Triggers.PSComputerName -join "; "); 120 | $output.TriggersRepetition = ($_.Triggers.Repetition -join "; "); 121 | $output.TriggersStartBoundary = ($_.Triggers.StartBoundary -join "; "); 122 | $output.URI = $_.URI; 123 | 124 | return $output; 125 | }; 126 | } 127 | else { 128 | 129 | Write-Verbose ("{0}: System failed." -f $Computer); 130 | if ($Fails) { 131 | 132 | $total++; 133 | Add-Content -Path $Fails -Value ("$Computer"); 134 | } 135 | else { 136 | 137 | $output = $null; 138 | $output = [Task]::new(); 139 | 140 | $output.Computer = $Computer; 141 | $output.DateScanned = Get-Date -Format u; 142 | 143 | $total++; 144 | return $output; 145 | }; 146 | }; 147 | }; 148 | 149 | end { 150 | 151 | $elapsed = $stopwatch.Elapsed; 152 | 153 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 154 | }; 155 | }; -------------------------------------------------------------------------------- /Functions/Hunt-InterfaceDetails.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-InterfaceDetails { 2 | <# 3 | .Synopsis 4 | Gets the Interface(s) settings for the given computer(s). 5 | 6 | .Description 7 | Gets the Interface(s) settings for the given computer(s) and returns a PS Object. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-InterfaceDetails 17 | Hunt-InterfaceDetails SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-InterfaceDetails 19 | Hunt-InterfaceDetails -Computer $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-InterfaceDetails 21 | 22 | .Notes 23 | Updated: 2017-10-26 24 | 25 | Contributing Authors: 26 | Jeremy Arnold 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | #> 42 | 43 | PARAM( 44 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 45 | $Computer = $env:COMPUTERNAME, 46 | [Parameter()] 47 | $Fails 48 | ); 49 | 50 | BEGIN{ 51 | 52 | $datetime = Get-Date -Format u; 53 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 54 | 55 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 56 | $stopwatch.Start(); 57 | $total = 0; 58 | 59 | class Adapter 60 | { 61 | [String] $Computer 62 | [DateTime] $DateScanned 63 | [String] $FQDN 64 | [String] $Description 65 | [String] $NetConnectionID 66 | [String] $NetConnected 67 | [String] $InterfaceIndex 68 | [String] $Speed 69 | [String] $MACAddress 70 | [String] $IPAddress 71 | [String] $Subnet 72 | [String] $Gateway 73 | [String] $DNS 74 | [String] $MTU 75 | [bool] $PromiscuousMode 76 | }; 77 | 78 | }; 79 | 80 | PROCESS{ 81 | 82 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present get-netadapter 83 | $Adapters = Invoke-Command -ComputerName $Computer -ScriptBlock {Get-NetAdapter -ErrorAction SilentlyContinue}; #get a list of network adapters 84 | 85 | if ($Adapters) { 86 | 87 | $AdapterConfigs = Invoke-Command -ComputerName $Computer -ScriptBlock {Get-CimInstance Win32_NetworkAdapterConfiguration | Select-Object * -ErrorAction SilentlyContinue}; #get the configuration for the current adapter 88 | $OutputArray = $null; 89 | $OutputArray = @(); 90 | 91 | foreach ($Adapter in $Adapters) {#loop through the Interfaces and build the outputArray 92 | 93 | if ($Adapter.MediaConnectionState -eq "Connected") { 94 | 95 | $AdapterConfig = $AdapterConfigs | Where {$_.InterfaceIndex -eq $Adapter.InterfaceIndex}; 96 | $output = $null; 97 | $output = [Adapter]::new(); 98 | 99 | $output.Computer = $Computer; 100 | $output.DateScanned = Get-Date -Format u; 101 | $output.FQDN = $Adapter.SystemName; 102 | $output.Description = $Adapter.InterfaceDescription; 103 | $output.NetConnectionID = $Adapter.Name; 104 | $output.NetConnected= $Adapter.MediaConnectionState; 105 | $output.InterfaceIndex = $Adapter.ifIndex; 106 | $output.Speed = $Adapter.Speed; 107 | $output.MACAddress = $Adapter.MACAddress; 108 | $output.IPAddress = $AdapterConfig.ipaddress[0]; 109 | $output.Subnet = $AdapterConfig.IPsubnet[0]; 110 | $output.Gateway = $AdapterConfig.DefaultIPGateway; 111 | $output.DNS = $AdapterConfig.DNSServerSearchOrder; 112 | $output.MTU = $Adapter.MtuSize; 113 | $output.PromiscuousMode = $Adapter.PromiscuousMode; 114 | 115 | $OutputArray += $output; 116 | 117 | }; 118 | 119 | }; 120 | 121 | Return $OutputArray; 122 | 123 | } 124 | else { 125 | 126 | Write-Verbose ("{0}: System failed." -f $Computer); 127 | if ($Fails) { 128 | 129 | $total++; 130 | Add-Content -Path $Fails -Value ("$Computer"); 131 | } 132 | else { 133 | 134 | $output = $null; 135 | $output = [Adapter]::new(); 136 | 137 | $output.Computer = $Computer; 138 | $output.DateScanned = Get-Date -Format u; 139 | 140 | $total++; 141 | return $output; 142 | }; 143 | }; 144 | }; 145 | 146 | end { 147 | 148 | $elapsed = $stopwatch.Elapsed; 149 | 150 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 151 | }; 152 | }; -------------------------------------------------------------------------------- /Functions/Hunt-Services.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-Services { 2 | <# 3 | .Synopsis 4 | Queries the services on a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries the services on a given hostname, FQDN, or IP address. 8 | 9 | .Parameter Computer 10 | Queries the services on a given hostname, FQDN, or IP address. 11 | 12 | .Example 13 | Hunt-Services 14 | Hunt-Services SomeHostName.domain.com 15 | Get-Content C:\hosts.csv | Hunt-Services 16 | Hunt-Services $env:computername 17 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-Services 18 | 19 | .Notes 20 | Updated: 2017-10-25 21 | 22 | Contributing Authors: 23 | Anthony Phipps 24 | 25 | LEGAL: Copyright (C) 2017 26 | This program is free software: you can redistribute it and/or modify 27 | it under the terms of the GNU General Public License as published by 28 | the Free Software Foundation, either version 3 of the License, or 29 | (at your option) any later version. 30 | 31 | This program is distributed in the hope that it will be useful, 32 | but WITHOUT ANY WARRANTY; without even the implied warranty of 33 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 34 | GNU General Public License for more details. 35 | 36 | You should have received a copy of the GNU General Public License 37 | along with this program. If not, see . 38 | 39 | .LINK 40 | https://github.com/DLACERT/ThreatHunting 41 | #> 42 | 43 | param( 44 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 45 | $Computer = $env:COMPUTERNAME 46 | ); 47 | 48 | begin{ 49 | 50 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 51 | Write-Verbose "Started at $datetime" 52 | 53 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 54 | $stopwatch.Start(); 55 | 56 | $total = 0; 57 | 58 | class Service { 59 | [String] $Computer 60 | [Datetime] $DateScanned 61 | [bool] $AcceptPause 62 | [bool] $AcceptStop 63 | [string] $Caption 64 | [uint32] $CheckPoint 65 | [bool] $DelayedAutoStart 66 | [string] $Description 67 | [bool] $DesktopInteract 68 | [uint32] $DisconnectedSessions 69 | [string] $DisplayName 70 | [string] $ErrorControl 71 | [uint32] $ExitCode 72 | [datetime] $InstallDate 73 | [string] $Name 74 | [string] $PathName 75 | [uint32] $ProcessId 76 | [uint32] $ServiceSpecificExitCode 77 | [string] $ServiceType 78 | [bool] $Started 79 | [string] $StartMode 80 | [string] $StartName 81 | [string] $State 82 | [string] $SystemName 83 | [uint32] $TagId 84 | [uint32] $TotalSessions 85 | [uint32] $WaitHint 86 | }; 87 | }; 88 | 89 | process{ 90 | 91 | $Computer = $Computer.Replace('"', ''); 92 | 93 | Write-Verbose ("{0}: Querying remote system" -f $Computer); 94 | $Services = Get-CIMinstance -class Win32_Service -Filter "Caption LIKE '%'" -ComputerName $Computer -ErrorAction SilentlyContinue; 95 | # Odd filter explanation: http://itknowledgeexchange.techtarget.com/powershell/cim-session-oddity/ 96 | 97 | if ($Services){ 98 | 99 | $Services | ForEach-Object { 100 | 101 | $output = $null; 102 | $output = [Service]::new(); 103 | 104 | $output.Computer = $Computer; 105 | $output.DateScanned = Get-Date -Format u; 106 | 107 | $output.AcceptPause = $_.AcceptPause; 108 | $output.AcceptStop = $_.AcceptStop; 109 | $output.Caption = $_.Caption; 110 | $output.CheckPoint = $_.CheckPoint; 111 | $output.DelayedAutoStart = $_.DelayedAutoStart; 112 | $output.Description = $_.Description; 113 | $output.DesktopInteract = $_.DesktopInteract; 114 | $output.DisconnectedSessions = $_.DisconnectedSessions; 115 | $output.DisplayName = $_.DisplayName; 116 | $output.ErrorControl = $_.ErrorControl; 117 | $output.ExitCode = $_.ExitCode; 118 | if ($_.InstallDate) { 119 | $output.InstallDate = $_.InstallDate; 120 | }; 121 | $output.Name = $_.Name; 122 | $output.PathName = $_.PathName; 123 | $output.ProcessId = $_.ProcessId; 124 | $output.ServiceSpecificExitCode = $_.ServiceSpecificExitCode; 125 | $output.ServiceType = $_.ServiceType; 126 | $output.Started = $_.Started; 127 | $output.StartMode = $_.StartMode; 128 | $output.StartName = $_.StartName; 129 | $output.State = $_.State; 130 | $output.SystemName = $_.SystemName; 131 | $output.TagId = $_.TagId; 132 | $output.TotalSessions = $_.TotalSessions; 133 | $output.WaitHint = $_.WaitHint; 134 | 135 | $total++; 136 | return $output; 137 | }; 138 | } 139 | else { 140 | 141 | Write-Verbose ("{0}: System failed." -f $Computer); 142 | if ($Fails) { 143 | 144 | $total++; 145 | Add-Content -Path $Fails -Value ("$Computer"); 146 | } 147 | else { 148 | 149 | $output = $null; 150 | $output = [Service]::new(); 151 | 152 | $output.Computer = $Computer; 153 | $output.DateScanned = Get-Date -Format u; 154 | 155 | $total++; 156 | return $output; 157 | }; 158 | }; 159 | }; 160 | 161 | end { 162 | 163 | $elapsed = $stopwatch.Elapsed; 164 | 165 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 166 | }; 167 | }; -------------------------------------------------------------------------------- /Functions/Hunt-LocalGroupMembers.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-LocalGroupMembers { 2 | <# 3 | .Synopsis 4 | Gets a list of the members of each local group on a given system. 5 | 6 | .Description 7 | Gets a list of the members of each local group on a given system. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-LocalGroupMembers 17 | Hunt-LocalGroupMembers SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-LocalGroupMembers 19 | Hunt-LocalGroupMembers $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-LocalGroupMembers 21 | 22 | .Notes 23 | Updated: 2017-10-24 24 | 25 | Contributing Authors: 26 | Anthony Phipps 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | 42 | .LINK 43 | https://github.com/DLACERT/ThreatHunting 44 | #> 45 | 46 | param( 47 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 48 | $Computer = $env:COMPUTERNAME, 49 | [Parameter()] 50 | $Fails 51 | ); 52 | 53 | begin{ 54 | 55 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 56 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 57 | 58 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 59 | $stopwatch.Start(); 60 | 61 | $total = 0; 62 | 63 | class Member 64 | { 65 | [String] $Computer 66 | [dateTime] $DateScanned 67 | 68 | [String] $Name 69 | [String] $SID 70 | [String] $PrincipalSource 71 | [String] $ObjectClass 72 | [String] $GroupName 73 | [String] $GroupDescription 74 | [String] $GroupSID 75 | [String] $GroupPrincipalSource 76 | [String] $GroupObjectClass 77 | }; 78 | }; 79 | 80 | process{ 81 | 82 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 83 | 84 | Write-Verbose ("{0}: Querying remote system" -f $Computer); 85 | 86 | $groupMembers = $null; 87 | $groupMembers = Invoke-Command -ComputerName $Computer -ErrorAction SilentlyContinue -ScriptBlock { 88 | 89 | $groups = $null; 90 | $groups = Get-LocalGroup; 91 | 92 | $groupMembers = @(); 93 | 94 | Foreach ($group in $groups) { # get members of each group 95 | 96 | $members = $null; 97 | $members = Get-LocalGroupMember -Group $group.Name; 98 | 99 | Foreach ($member in $members) { # add group properties to each member 100 | 101 | $member | Add-Member -MemberType NoteProperty -Name "GroupDescription" -Value $group.Description; 102 | $member | Add-Member -MemberType NoteProperty -Name "GroupName" -Value $group.Name; 103 | $member | Add-Member -MemberType NoteProperty -Name "GroupSID" -Value $group.SID; 104 | $member | Add-Member -MemberType NoteProperty -Name "GroupPrincipalSource" -Value $group.PrincipalSource; 105 | $member | Add-Member -MemberType NoteProperty -Name "GroupObjectClass" -Value $group.ObjectClass; 106 | $groupMembers += $member; 107 | }; 108 | }; 109 | 110 | return $groupMembers; 111 | }; 112 | 113 | if ($groupMembers) { 114 | 115 | $outputArray = @(); 116 | 117 | Foreach ($groupMember in $groupMembers) { 118 | 119 | $output = $null; 120 | $output = [Member]::new(); 121 | 122 | $output.Computer = $Computer; 123 | $output.DateScanned = Get-Date -Format u; 124 | 125 | $output.Name = $groupMember.Name; 126 | $output.SID = $groupMember.SID; 127 | $output.PrincipalSource = $groupMember.PrincipalSource; 128 | $output.ObjectClass = $groupMember.ObjectClass; 129 | $output.GroupName = $groupMember.GroupName; 130 | $output.GroupDescription = $groupMember.GroupDescription; 131 | $output.GroupSID = $groupMember.GroupSID; 132 | $output.GroupPrincipalSource = $groupMember.GroupPrincipalSource; 133 | $output.GroupObjectClass = $groupMember.GroupObjectClass; 134 | 135 | $outputArray += $output; 136 | }; 137 | 138 | $total++; 139 | return $outputArray; 140 | } 141 | else { 142 | 143 | Write-Verbose ("{0}: System failed." -f $Computer); 144 | if ($Fails) { 145 | 146 | $total++; 147 | Add-Content -Path $Fails -Value ("$Computer"); 148 | } 149 | else { 150 | 151 | $output = $null; 152 | $output = [Member]::new(); 153 | 154 | $output.Computer = $Computer; 155 | $output.DateScanned = Get-Date -Format u; 156 | 157 | $total++; 158 | return $output; 159 | }; 160 | }; 161 | }; 162 | 163 | end { 164 | 165 | $elapsed = $stopwatch.Elapsed; 166 | 167 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 168 | }; 169 | }; -------------------------------------------------------------------------------- /Functions/Hunt-SCCMLocalGroupMembers.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-SCCMLocalGroupMembers { 2 | <# 3 | .Synopsis 4 | Queries SCCM for a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries SCCM for a given hostname, FQDN, or IP address. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter CIM 13 | Use Get-CIMInstance rather than Get-WMIObject. CIM cmdlets use WSMAN (WinRM) 14 | to connect to remote machines, and has better standardized output (e.g. 15 | datetime format). CIM cmdlets require the querying user to be a member of 16 | Administrators or WinRMRemoteWMIUsers_ on the target system. Get-WMIObject 17 | is the default due to lower permission requirements, but can be blocked by 18 | firewalls in some environments. 19 | 20 | .Example 21 | Hunt-SCCMLocalGroupMembers 22 | Hunt-SCCMLocalGroupMembers SomeHostName.domain.com 23 | Get-Content C:\hosts.csv | Hunt-SCCMLocalGroupMembers 24 | Hunt-SCCMLocalGroupMembers $env:computername 25 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-SCCMLocalGroupMembers 26 | 27 | .Notes 28 | Updated: 2017-10-10 29 | 30 | Contributing Authors: 31 | Anthony Phipps 32 | 33 | LEGAL: Copyright (C) 2017 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, either version 3 of the License, or 37 | (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, 40 | but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | GNU General Public License for more details. 43 | 44 | You should have received a copy of the GNU General Public License 45 | along with this program. If not, see . 46 | #> 47 | 48 | PARAM( 49 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 50 | $Computer = $env:COMPUTERNAME, 51 | [Parameter()] 52 | $SiteName="A1", 53 | [Parameter()] 54 | $SCCMServer="server.domain.com", 55 | [Parameter()] 56 | [switch]$CIM 57 | ); 58 | 59 | BEGIN{ 60 | $SCCMNameSpace="root\sms\site_$SiteName"; 61 | 62 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 63 | Write-Verbose "Started at $datetime" 64 | 65 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 66 | $stopwatch.Start(); 67 | 68 | $total = 0; 69 | 70 | class LocalGroup { 71 | [String] $Computer 72 | [DateTime] $DateScanned 73 | 74 | [String] $ResourceNames 75 | [String] $Account 76 | [String] $Category 77 | [String] $Domain 78 | [String] $GroupID 79 | [String] $GroupName 80 | [String] $Type 81 | [String] $RevisionID 82 | [String] $Timestamp 83 | }; 84 | }; 85 | 86 | PROCESS{ 87 | 88 | if ($Computer -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){ # is this an IP address? 89 | 90 | $fqdn = [System.Net.Dns]::GetHostByAddress($Computer).Hostname; 91 | $ThisComputer = $fqdn.Split(".")[0]; 92 | } 93 | 94 | else{ # Convert any FQDN into just hostname 95 | 96 | $ThisComputer = $Computer.Split(".")[0].Replace('"', ''); 97 | }; 98 | 99 | if ($CIM){ 100 | 101 | $SMS_R_System = $Null; 102 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 103 | 104 | if ($SMS_R_System) { 105 | 106 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 107 | $SMS_G_System_LocalGroupMembers = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select Account, Category, Domain, GroupID, Name, RevisionID, TimeStamp, Type from SMS_G_System_LocalGroupMembers where ResourceID='$ResourceID'"; 108 | }; 109 | } 110 | else{ 111 | $SMS_R_System = $Null; 112 | $SMS_R_System = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 113 | 114 | if ($SMS_R_System) { 115 | 116 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 117 | $SMS_G_System_LocalGroupMembers = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select Account, Category, Domain, GroupID, Name, RevisionID, TimeStamp, Type from SMS_G_System_LocalGroupMembers where ResourceID='$ResourceID'"; 118 | }; 119 | }; 120 | 121 | if ($SMS_G_System_LocalGroupMembers){ 122 | 123 | $SMS_G_System_LocalGroupMembers | ForEach-Object { 124 | 125 | $output = $null; 126 | $output = [LocalGroup]::new(); 127 | 128 | $output.Computer = $ThisComputer; 129 | $output.DateScanned = Get-Date -Format u; 130 | 131 | $output.ResourceNames = $SMS_R_System.ResourceNames[0]; 132 | $output.Account = $_.Account; 133 | $output.Category = $_.Category; 134 | $output.Domain = $_.Domain; 135 | $output.GroupID = $_.GroupID; 136 | $output.GroupName = $_.Name; 137 | $output.Type = $_.Type; 138 | $output.RevisionID = $_.RevisionID; 139 | $output.Timestamp = $_.Timestamp; 140 | 141 | return $output; 142 | }; 143 | } 144 | else { 145 | 146 | $output = $null; 147 | $output = [LocalGroup]::new(); 148 | 149 | $output.Computer = $Computer; 150 | $output.DateScanned = Get-Date -Format u; 151 | 152 | return $output; 153 | }; 154 | 155 | $elapsed = $stopwatch.Elapsed; 156 | $total = $total+1; 157 | 158 | Write-Verbose -Message "System $total `t $ThisComputer `t Time Elapsed: $elapsed"; 159 | 160 | }; 161 | 162 | END{ 163 | $elapsed = $stopwatch.Elapsed; 164 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 165 | }; 166 | }; 167 | 168 | 169 | -------------------------------------------------------------------------------- /Functions/Hunt-SCCMConsoleUsers.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-SCCMConsoleUsers { 2 | <# 3 | .Synopsis 4 | Queries SCCM for a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries SCCM for a given hostname, FQDN, or IP address. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter CIM 13 | Use Get-CIMInstance rather than Get-WMIObject. CIM cmdlets use WSMAN (WinRM) 14 | to connect to remote machines, and has better standardized output (e.g. 15 | datetime format). CIM cmdlets require the querying user to be a member of 16 | Administrators or WinRMRemoteWMIUsers_ on the target system. Get-WMIObject 17 | is the default due to lower permission requirements, but can be blocked by 18 | firewalls in some environments. 19 | 20 | .Example 21 | Hunt-SCCMConsoleUsers 22 | Hunt-SCCMConsoleUsers SomeHostName.domain.com 23 | Get-Content C:\hosts.csv | Hunt-SCCMConsoleUsers 24 | Hunt-SCCMConsoleUsers $env:computername 25 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-SCCMConsoleUsers 26 | 27 | .Notes 28 | Updated: 2017-10-10 29 | 30 | Contributing Authors: 31 | Anthony Phipps 32 | 33 | LEGAL: Copyright (C) 2017 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, either version 3 of the License, or 37 | (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, 40 | but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | GNU General Public License for more details. 43 | 44 | You should have received a copy of the GNU General Public License 45 | along with this program. If not, see . 46 | #> 47 | 48 | PARAM( 49 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 50 | $Computer = $env:COMPUTERNAME, 51 | [Parameter()] 52 | $SiteName="A1", 53 | [Parameter()] 54 | $SCCMServer="server.domain.com", 55 | [Parameter()] 56 | [switch]$CIM 57 | ); 58 | 59 | BEGIN{ 60 | $SCCMNameSpace="root\sms\site_$SiteName"; 61 | 62 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 63 | Write-Verbose "Started at $datetime" 64 | 65 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 66 | $stopwatch.Start(); 67 | 68 | $total = 0; 69 | 70 | class User { 71 | [String] $Computer 72 | [DateTime] $DateScanned 73 | 74 | [String] $ResourceNames 75 | [String] $GroupID 76 | [String] $LastConsoleUse 77 | [String] $NumberOfConsoleLogons 78 | [String] $SystemConsoleUser 79 | [String] $TotalUserConsoleMinutes 80 | [String] $TimeStamp 81 | }; 82 | }; 83 | 84 | PROCESS{ 85 | 86 | if ($Computer -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){ # is this an IP address? 87 | 88 | $fqdn = [System.Net.Dns]::GetHostByAddress($Computer).Hostname; 89 | $ThisComputer = $fqdn.Split(".")[0]; 90 | } 91 | 92 | else{ # Convert any FQDN into just hostname 93 | 94 | $ThisComputer = $Computer.Split(".")[0].Replace('"', ''); 95 | }; 96 | 97 | if ($CIM){ 98 | 99 | $SMS_R_System = $Null; 100 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 101 | 102 | if ($SMS_R_System) { 103 | 104 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 105 | $SMS_G_System_SYSTEM_CONSOLE_USER = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select GroupID, LastConsoleUse, NumberOfConsoleLogons, SystemConsoleUser, TimeStamp, TotalUserConsoleMinutes from SMS_G_System_SYSTEM_CONSOLE_USER where ResourceID='$ResourceID'"; 106 | }; 107 | } 108 | else{ 109 | 110 | $SMS_R_System = $Null; 111 | $SMS_R_System = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 112 | 113 | if ($SMS_R_System) { 114 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 115 | $SMS_G_System_SYSTEM_CONSOLE_USER = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select GroupID, LastConsoleUse, NumberOfConsoleLogons, SystemConsoleUser, TimeStamp, TotalUserConsoleMinutes from SMS_G_System_SYSTEM_CONSOLE_USER where ResourceID='$ResourceID'"; 116 | }; 117 | }; 118 | 119 | if ($SMS_G_System_SYSTEM_CONSOLE_USER){ 120 | 121 | $SMS_G_System_SYSTEM_CONSOLE_USER | ForEach-Object { 122 | 123 | $output = $null; 124 | $output = [User]::new(); 125 | 126 | $output.Computer = $ThisComputer; 127 | $output.DateScanned = Get-Date -Format u; 128 | 129 | $output.ResourceNames = $SMS_R_System.ResourceNames[0]; 130 | 131 | $output.LastConsoleUse = $_.LastConsoleUse; 132 | $output.NumberOfConsoleLogons = $_.NumberOfConsoleLogons; 133 | $output.SystemConsoleUser = $_.SystemConsoleUser; 134 | $output.GroupID = $_.GroupID; # does not appear to map to the GroupID in SMS_G_System_LocalGroupMembers 135 | $output.TotalUserConsoleMinutes = $_.TotalUserConsoleMinutes; 136 | $output.Timestamp = $_.Timestamp; 137 | 138 | return $output; 139 | }; 140 | } 141 | else { 142 | 143 | $output = $null; 144 | $output = [User]::new(); 145 | 146 | $output.Computer = $Computer; 147 | $output.DateScanned = Get-Date -Format u; 148 | 149 | return $output; 150 | }; 151 | 152 | $elapsed = $stopwatch.Elapsed; 153 | $total = $total+1; 154 | 155 | Write-Verbose -Message "System $total `t $ThisComputer `t Time Elapsed: $elapsed"; 156 | 157 | }; 158 | 159 | END{ 160 | $elapsed = $stopwatch.Elapsed; 161 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 162 | }; 163 | }; 164 | 165 | 166 | -------------------------------------------------------------------------------- /Functions/Hunt-SCCMBrowserHelperObjects.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-SCCMBrowserHelperObjects { 2 | <# 3 | .Synopsis 4 | Queries SCCM for a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries SCCM for a given hostname, FQDN, or IP address. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter CIM 13 | Use Get-CIMInstance rather than Get-WMIObject. CIM cmdlets use WSMAN (WinRM) 14 | to connect to remote machines, and has better standardized output (e.g. 15 | datetime format). CIM cmdlets require the querying user to be a member of 16 | Administrators or WinRMRemoteWMIUsers_ on the target system. Get-WMIObject 17 | is the default due to lower permission requirements, but can be blocked by 18 | firewalls in some environments. 19 | 20 | .Example 21 | Hunt-SCCMBrowserHelperObjects 22 | Hunt-SCCMBrowserHelperObjects SomeHostName.domain.com 23 | Get-Content C:\hosts.csv | Hunt-SCCMBrowserHelperObjects 24 | Hunt-SCCMBrowserHelperObjects $env:computername 25 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-SCCMBrowserHelperObjects 26 | 27 | .Notes 28 | Updated: 2017-10-10 29 | 30 | Contributing Authors: 31 | Anthony Phipps 32 | 33 | LEGAL: Copyright (C) 2017 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, either version 3 of the License, or 37 | (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, 40 | but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | GNU General Public License for more details. 43 | 44 | You should have received a copy of the GNU General Public License 45 | along with this program. If not, see . 46 | #> 47 | 48 | PARAM( 49 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 50 | $Computer, 51 | [Parameter()] 52 | $SiteName="A1", 53 | [Parameter()] 54 | $SCCMServer="server.domain.com", 55 | [Parameter()] 56 | [switch]$CIM 57 | ); 58 | 59 | BEGIN{ 60 | $SCCMNameSpace="root\sms\site_$SiteName"; 61 | 62 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 63 | Write-Verbose "Started at $datetime" 64 | 65 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 66 | $stopwatch.Start(); 67 | 68 | $total = 0; 69 | }; 70 | 71 | PROCESS{ 72 | 73 | if ($Computer -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){ # is this an IP address? 74 | 75 | $fqdn = [System.Net.Dns]::GetHostByAddress($Computer).Hostname; 76 | $ThisComputer = $fqdn.Split(".")[0]; 77 | } 78 | 79 | else{ # Convert any FQDN into just hostname 80 | 81 | $ThisComputer = $Computer.Split(".")[0].Replace('"', ''); 82 | }; 83 | 84 | $output = [PSCustomObject]@{ 85 | Name = $ThisComputer 86 | ResourceNames = "" 87 | Description = "" 88 | FileName = "" 89 | FilePropertiesHash = "" 90 | FilePropertiesHashEx = "" 91 | FileVersion = "" 92 | Product = "" 93 | ProductVersion = "" 94 | Publisher = "" 95 | RevisionID = "" 96 | Timestamp = "" 97 | }; 98 | 99 | if ($CIM){ 100 | 101 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 102 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 103 | $SMS_G_System_BROWSER_HELPER_OBJECT = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select Description, FileName, FilePropertiesHash, FilePropertiesHashEx, FileVersion, Product, ProductVersion, Publisher, RevisionID, Timestamp from SMS_G_System_BROWSER_HELPER_OBJECT where ResourceID='$ResourceID'"; 104 | } 105 | else{ 106 | $SMS_R_System = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 107 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 108 | $SMS_G_System_BROWSER_HELPER_OBJECT = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select Description, FileName, FilePropertiesHash, FilePropertiesHashEx, FileVersion, Product, ProductVersion, Publisher, RevisionID, Timestamp from SMS_G_System_BROWSER_HELPER_OBJECT where ResourceID='$ResourceID'"; 109 | }; 110 | 111 | if ($SMS_G_System_BROWSER_HELPER_OBJECT){ 112 | 113 | $SMS_G_System_BROWSER_HELPER_OBJECT | ForEach-Object { 114 | 115 | $output.ResourceNames = $SMS_R_System.ResourceNames[0]; 116 | 117 | $output.Description = $_.Description; 118 | $output.FileName = $_.FileName; 119 | $output.FilePropertiesHash = $_.FilePropertiesHash; 120 | $output.FilePropertiesHashEx = $_.FilePropertiesHashEx; 121 | $output.FileVersion = $_.FileVersion; 122 | $output.Product = $_.Product; 123 | $output.ProductVersion = $_.ProductVersion; 124 | $output.Publisher = $_.Publisher; 125 | $output.RevisionID = $_.RevisionID; 126 | $output.Timestamp = $_.Timestamp; 127 | 128 | return $output; 129 | $output.PsObject.Members | ForEach-Object {$output.PsObject.Members.Remove($_.Name)}; 130 | }; 131 | } 132 | else { 133 | 134 | return $output; 135 | $output.PsObject.Members | ForEach-Object {$output.PsObject.Members.Remove($_.Name)}; 136 | }; 137 | 138 | $elapsed = $stopwatch.Elapsed; 139 | $total = $total+1; 140 | 141 | Write-Verbose -Message "System $total `t $ThisComputer `t Time Elapsed: $elapsed"; 142 | 143 | }; 144 | 145 | END{ 146 | $elapsed = $stopwatch.Elapsed; 147 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 148 | }; 149 | }; 150 | 151 | 152 | -------------------------------------------------------------------------------- /Functions/Hunt-ADS.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-ADS { 2 | <# 3 | .SYNOPSIS 4 | Performs a search for alternate data streams (ADS) on a system. 5 | 6 | .DESCRIPTION 7 | Performs a search for alternate data streams (ADS) on a system. Default starting directory is c:\temp. 8 | To test, perform the following steps first: 9 | $file = "C:\temp\testfile.txt"; 10 | Set-Content -Path $file -Value 'Nobody here but us chickens!'; 11 | Add-Content -Path $file -Value 'Super secret squirrel stuff' -Stream 'secretStream'; 12 | 13 | .PARAMETER Computer 14 | Computer can be a single hostname, FQDN, or IP address. 15 | 16 | .PARAMETER Path 17 | Specify a path to search for alternate data streams in. Default is c:\temp 18 | 19 | .PARAMETER Fails 20 | Provide a path to save failed systems to. 21 | 22 | .EXAMPLE 23 | Hunt-ADS -Path "C:\" 24 | Hunt-ADS SomeHostName.domain.com -Path "C:\" 25 | Get-Content C:\hosts.csv | Hunt-ADS -Path "C:\" 26 | Hunt-ADS $env:computername -Path "C:\" 27 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-ADS -Path "C:\" 28 | 29 | .NOTES 30 | Updated: 2017-10-10 31 | 32 | Contributing Authors: 33 | Anthony Phipps 34 | 35 | LEGAL: Copyright (C) 2017 36 | This program is free software: you can redistribute it and/or modify 37 | it under the terms of the GNU General Public License as published by 38 | the Free Software Foundation, either version 3 of the License, or 39 | (at your option) any later version. 40 | 41 | This program is distributed in the hope that it will be useful, 42 | but WITHOUT ANY WARRANTY; without even the implied warranty of 43 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 44 | GNU General Public License for more details. 45 | 46 | You should have received a copy of the GNU General Public License 47 | along with this program. If not, see . 48 | #> 49 | 50 | [CmdletBinding()] 51 | param( 52 | [Parameter(ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] 53 | $Computer = $env:COMPUTERNAME, 54 | 55 | [Parameter()] 56 | $Path = "C:\temp", 57 | 58 | [Parameter()] 59 | $Fails 60 | ); 61 | 62 | begin { 63 | 64 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 65 | Write-Verbose "Started at $datetime"; 66 | 67 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 68 | $stopwatch.Start(); 69 | 70 | $total = 0; 71 | 72 | class ADS { 73 | [String] $Computer 74 | [DateTime] $DateScanned 75 | 76 | [String] $FileName 77 | [String] $StreamName 78 | [String] $StreamLength 79 | [String] $StreamContent 80 | [String] $Attributes 81 | [DateTime] $CreationTimeUtc 82 | [DateTime] $LastAccessTimeUtc 83 | [DateTime] $LastWriteTimeUtc 84 | 85 | }; 86 | }; 87 | 88 | process { 89 | 90 | $Computer = $Computer.Replace('"', ''); 91 | 92 | Write-Verbose "Attemting to run Invoke-Command on remote system."; 93 | $Streams = $null; 94 | 95 | $Streams = Invoke-Command -ArgumentList $Path -ComputerName $Computer -ScriptBlock { 96 | $Path = $args[0]; 97 | 98 | $Streams = Get-ChildItem -Path $Path -Recurse -PipelineVariable FullName | 99 | ForEach-Object { Get-Item $_.FullName -Stream * } | # Doesn't work without foreach 100 | Where-Object {($_.Stream -notlike "*DATA") -AND ($_.Stream -ne "Zone.Identifier")}; 101 | 102 | ForEach ($Stream in $Streams) { 103 | $File = Get-Item $Stream.FileName; 104 | $StreamContent = Get-Content -Path $Stream.FileName -Stream $Stream.Stream; 105 | $Attributes = Get-ItemProperty -Path $Stream.FileName; 106 | 107 | $Stream | Add-Member -MemberType NoteProperty -Name CreationTimeUtc -Value $File.CreationTimeUtc; 108 | $Stream | Add-Member -MemberType NoteProperty -Name LastAccessTimeUtc -Value $File.LastAccessTimeUtc; 109 | $Stream | Add-Member -MemberType NoteProperty -Name LastWriteTimeUtc -Value $File.LastWriteTimeUtc; 110 | $Stream | Add-Member -MemberType NoteProperty -Name StreamContent -Value $StreamContent; 111 | $Stream | Add-Member -MemberType NoteProperty -Name Attributes -Value $Attributes.Mode; 112 | }; 113 | 114 | return $Streams; 115 | }; 116 | 117 | if ($Streams) { 118 | Write-Verbose "Streams were found."; 119 | 120 | $OutputArray = $null; 121 | $OutputArray = @(); 122 | 123 | ForEach ($Stream in $Streams) { 124 | 125 | $output = $null; 126 | $output = [ADS]::new(); 127 | 128 | $output.Computer = $Computer; 129 | $output.DateScanned = Get-Date -Format u; 130 | 131 | $output.FileName = $Stream.FileName; 132 | $output.StreamName = $Stream.Stream; 133 | $output.StreamLength = $Stream.Length; 134 | $output.Attributes = $Stream.Attributes; 135 | $output.StreamContent = $Stream.StreamContent; 136 | $output.CreationTimeUtc = $Stream.CreationTimeUtc; 137 | $output.LastAccessTimeUtc = $Stream.LastAccessTimeUtc; 138 | $output.LastWriteTimeUtc = $Stream.LastWriteTimeUtc; 139 | 140 | $OutputArray += $output; 141 | }; 142 | 143 | $total++; 144 | return $OutputArray; 145 | } 146 | else { 147 | 148 | Write-Verbose ("{0}: System failed." -f $Computer); 149 | if ($Fails) { 150 | 151 | $total++; 152 | Add-Content -Path $Fails -Value ("$Computer"); 153 | } 154 | else { 155 | 156 | $output = $null; 157 | $output = [ADS]::new(); 158 | 159 | $output.Computer = $Computer; 160 | $output.DateScanned = Get-Date -Format u; 161 | 162 | $total++; 163 | return $output; 164 | }; 165 | }; 166 | }; 167 | 168 | end { 169 | 170 | $elapsed = $stopwatch.Elapsed; 171 | 172 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 173 | }; 174 | }; -------------------------------------------------------------------------------- /Functions/Hunt-ProcessHandles.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-ProcessHandles { 2 | <# 3 | .Synopsis 4 | Gets a list of Handles loaded by all process on a given system. 5 | 6 | .Description 7 | Gets a list of Handles loaded by all process on a given system. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter ToolLocation 13 | The location of Sysinternals Handle.exe/Handle64.exe. This parameter is manadatory 14 | and is how the function gets the list of handles. 15 | 16 | .Parameter Fails 17 | Provide a path to save failed systems to. 18 | 19 | .Example 20 | Hunt-ProcessHandles -Toollocation c:\tools\sysinternals 21 | Hunt-ProcessHandles SomeHostName.domain.com -Toollocation c:\tools\sysinternals 22 | Get-Content C:\hosts.csv | Hunt-ProcessHandles -Toollocation c:\tools\sysinternals 23 | Hunt-ProcessHandles $env:computername -Toollocation c:\tools\sysinternals 24 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-ProcessHandles -Toollocation c:\tools\sysinternals 25 | 26 | .Notes 27 | Updated: 2017-11-10 28 | 29 | Contributing Authors: 30 | Jeremy Arnold 31 | 32 | LEGAL: Copyright (C) 2017 33 | This program is free software: you can redistribute it and/or modify 34 | it under the terms of the GNU General Public License as published by 35 | the Free Software Foundation, either version 3 of the License, or 36 | (at your option) any later version. 37 | 38 | This program is distributed in the hope that it will be useful, 39 | but WITHOUT ANY WARRANTY; without even the implied warranty of 40 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 41 | GNU General Public License for more details. 42 | 43 | You should have received a copy of the GNU General Public License 44 | along with this program. If not, see . 45 | 46 | .LINK 47 | https://github.com/DLACERT/ThreatHunting 48 | #> 49 | 50 | param( 51 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 52 | $Computer = $env:COMPUTERNAME, 53 | [Parameter(mandatory=$true)] 54 | $ToolLocation, 55 | [Parameter()] 56 | $Fails 57 | ); 58 | 59 | begin{ 60 | 61 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 62 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 63 | 64 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 65 | $stopwatch.Start(); 66 | 67 | $total = 0; 68 | 69 | class Handles 70 | { 71 | [String] $Computer 72 | [dateTime] $DateScanned 73 | 74 | [string] $ProcessID 75 | [string] $Process 76 | [string] $Owner 77 | [string] $Location 78 | [string] $HandleType 79 | [string] $Attributes 80 | [string] $String 81 | }; 82 | }; 83 | 84 | process{ 85 | 86 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 87 | $remoteOS64 = Invoke-Command -ComputerName $Computer -ErrorAction SilentlyContinue -ScriptBlock { 88 | 89 | $remoteOS64 = [environment]::Is64BitOperatingSystem; 90 | 91 | return $remoteOS64; 92 | }; 93 | 94 | if ($remoteOS64){$tool = 'handle64.exe'} else {$tool = 'handle.exe'}; 95 | 96 | Write-Verbose ("{0}: Copying {1} to {0}." -f $Computer, $tool); 97 | 98 | try{Copy-Item -Path $($ToolLocation+'\'+$tool) -Destination $('\\'+$Computer+'\c$\temp\'+$tool); 99 | }catch{$Error[0]}; 100 | 101 | $handles = $null; 102 | $handles = Invoke-Command -ComputerName $Computer -ErrorAction SilentlyContinue -ScriptBlock { 103 | 104 | $handles = Invoke-Expression "C:\temp\$tool -a -nobanner -accepteula"; 105 | 106 | return $handles; 107 | 108 | }; 109 | 110 | if ($handles) { 111 | [regex]$regexProcess = '(?\S+)\spid:\s(?\d+)\s(?.*)' 112 | [regex]$regexHandle = '(?[A-F0-9]+):\s(?\w+)\s{2}(?\(.*\))?\s+(?.*)' 113 | [regex]$nullHandle = '([A-F0-9]+):\s(\w+)\s+$' 114 | $outputArray = @(); 115 | $handles = $handles | Where-Object {($_.length -gt 0) -and ($_ -notmatch $nullHandle)} 116 | Foreach ($handle in $handles) { 117 | if ($handle -match $regexProcess){ 118 | $process = $Matches.process; 119 | $processPID = $Matches.pid; 120 | $owner = $Matches.string; 121 | } 122 | if ($handle -match $regexHandle){ 123 | $output = $null; 124 | $output = [Handles]::new(); 125 | 126 | $output.Computer = $Computer; 127 | $output.DateScanned = Get-Date -Format u; 128 | 129 | $output.ProcessID = $processPID; 130 | $output.Process = $process; 131 | $output.Owner =$owner; 132 | $output.Location = $Matches.location; 133 | $output.HandleType = $Matches.type; 134 | $output.Attributes = $Matches.attributes; 135 | $output.String = $Matches.string; 136 | 137 | $outputArray += $output; 138 | } 139 | 140 | }; 141 | Remove-Item -Path $('\\'+$Computer+'\c$\temp\'+$tool); 142 | return $outputArray[0..12000];#select first 12000 143 | 144 | } 145 | else { 146 | 147 | Write-Verbose ("{0}: System failed." -f $Computer); 148 | if ($Fails) { 149 | 150 | $total++; 151 | Add-Content -Path $Fails -Value ("$Computer"); 152 | } 153 | else { 154 | 155 | $output = $null; 156 | $output = [Handles]::new(); 157 | 158 | $output.Computer = $Computer; 159 | $output.DateScanned = Get-Date -Format u; 160 | 161 | $total++; 162 | return $output; 163 | }; 164 | }; 165 | }; 166 | 167 | end { 168 | 169 | $elapsed = $stopwatch.Elapsed; 170 | 171 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 172 | }; 173 | }; -------------------------------------------------------------------------------- /Functions/Hunt-SharePermissions.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-SharePermissions { 2 | <# 3 | .Synopsis 4 | Gets the shares configured on a given system. 5 | 6 | .Description 7 | Gets the shares configured on a given system. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-SharePermissions 17 | Hunt-SharePermissions SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-SharePermissions 19 | Hunt-SharePermissions $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-SharePermissions 21 | 22 | .Notes 23 | Updated: 2017-10-10 24 | 25 | Contributing Authors: 26 | Anthony Phipps 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | #> 42 | 43 | param( 44 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 45 | $Computer = $env:COMPUTERNAME, 46 | [Parameter()] 47 | $Fails 48 | ); 49 | 50 | begin{ 51 | 52 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 53 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 54 | 55 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 56 | $stopwatch.Start(); 57 | 58 | $total = 0; 59 | 60 | $PermissionFlags = @{ 61 | 0x1 = "Read-List"; 62 | 0x2 = "Write-Create"; 63 | 0x4 = "Append-Create Subdirectory"; 64 | 0x20 = "Execute file-Traverse directory"; 65 | 0x40 = "Delete child" 66 | 0x10000 = "Delete"; 67 | 0x40000 = "Write access to DACL"; 68 | 0x80000 = "Write Owner" 69 | }; 70 | 71 | class SharePermission 72 | { 73 | [String] $Computer 74 | [Datetime] $DateScanned 75 | [String] $Name 76 | [String] $Path 77 | [String] $Description 78 | [String] $TrusteeName 79 | [String] $TrusteeDomain 80 | [String] $TrusteeSID 81 | [String] $AccessType 82 | [String] $AccessMask 83 | [String] $Permissions 84 | }; 85 | }; 86 | 87 | process{ 88 | 89 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 90 | 91 | $Shares = $null; 92 | $Shares = Get-WmiObject -class Win32_share -Filter "type=0" -ComputerName $Computer -ErrorAction SilentlyContinue; 93 | 94 | if ($Shares) { 95 | $OutputArray = $null; 96 | $OutputArray = @(); 97 | 98 | foreach ($Share in $Shares) { 99 | 100 | $ShareName = $Share.Name; 101 | 102 | $ShareSettings = Get-WmiObject -class Win32_LogicalShareSecuritySetting -Filter "Name='$ShareName'" -ComputerName $Computer -ErrorAction SilentlyContinue; 103 | 104 | $DACLs = $ShareSettings.GetSecurityDescriptor().Descriptor.DACL; 105 | 106 | foreach ($DACL in $DACLs) { 107 | 108 | $TrusteeName = $DACL.Trustee.Name; 109 | $TrusteeDomain = $DACL.Trustee.Domain; 110 | $TrusteeSID = $DACL.Trustee.SIDString; 111 | 112 | # 1 Deny; 0 Allow 113 | if ($DACL.AceType) 114 | { $Type = "Deny" } 115 | else 116 | { $Type = "Allow" }; 117 | 118 | $SharePermission = $null; 119 | 120 | # Convert AccessMask to human-readable format 121 | foreach ($Key in $PermissionFlags.Keys) { 122 | 123 | if ($Key -band $DACL.AccessMask) { 124 | 125 | $SharePermission += $PermissionFlags[$Key]; 126 | $SharePermission += "; "; 127 | }; 128 | }; 129 | 130 | $output = $null; 131 | $output = [SharePermission]::new(); 132 | 133 | $output.Computer = $Computer; 134 | $output.DateScanned = Get-Date -Format u; 135 | $output.Computer = $Share.PSComputerName; 136 | $output.Name = $Share.Name; 137 | $output.Path = $Share.Path; 138 | $output.Description = $Share.Description; 139 | $output.TrusteeName = $TrusteeName; 140 | $output.TrusteeDomain = $TrusteeDomain; 141 | $output.TrusteeSID = $TrusteeSID; 142 | $output.AccessType = $Type; 143 | $output.AccessMask = $DACL.AccessMask; 144 | $output.Permissions = $SharePermission; 145 | 146 | $OutputArray += $output; 147 | }; 148 | }; 149 | 150 | return $OutputArray; 151 | } 152 | else { 153 | 154 | Write-Verbose ("{0}: System failed." -f $Computer); 155 | if ($Fails) { 156 | 157 | $total++; 158 | Add-Content -Path $Fails -Value ("$Computer"); 159 | } 160 | else { 161 | 162 | $output = $null; 163 | $output = [SharePermission]::new(); 164 | 165 | $output.Computer = $Computer; 166 | $output.DateScanned = Get-Date -Format u; 167 | 168 | $total++; 169 | return $output; 170 | }; 171 | }; 172 | }; 173 | 174 | end { 175 | 176 | $elapsed = $stopwatch.Elapsed; 177 | 178 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 179 | }; 180 | }; -------------------------------------------------------------------------------- /Functions/Hunt-SCCMUSBDevices.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-SCCMUSBDevices { 2 | <# 3 | .Synopsis 4 | Queries SCCM for a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries SCCM for a given hostname, FQDN, or IP address. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter CIM 13 | Use Get-CIMInstance rather than Get-WMIObject. CIM cmdlets use WSMAN (WinRM) 14 | to connect to remote machines, and has better standardized output (e.g. 15 | datetime format). CIM cmdlets require the querying user to be a member of 16 | Administrators or WinRMRemoteWMIUsers_ on the target system. Get-WMIObject 17 | is the default due to lower permission requirements, but can be blocked by 18 | firewalls in some environments. 19 | 20 | .Example 21 | Get-USBDevices 22 | Get-USBDevices SomeHostName.domain.com 23 | Get-Content C:\hosts.csv | Get-USBDevices 24 | Get-USBDevices $env:computername 25 | Get-ADComputer -filter * | Select -ExpandProperty Name | Get-USBDevices 26 | 27 | .Notes 28 | Updated: 2017-10-10 29 | 30 | Contributing Authors: 31 | Anthony Phipps 32 | 33 | LEGAL: Copyright (C) 2017 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, either version 3 of the License, or 37 | (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, 40 | but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | GNU General Public License for more details. 43 | 44 | You should have received a copy of the GNU General Public License 45 | along with this program. If not, see . 46 | #> 47 | 48 | PARAM( 49 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 50 | $Computer = $env:COMPUTERNAME, 51 | [Parameter()] 52 | $SiteName="A1", 53 | [Parameter()] 54 | $SCCMServer="server.domain.com", 55 | [Parameter()] 56 | [switch]$CIM 57 | ); 58 | 59 | BEGIN{ 60 | $SCCMNameSpace="root\sms\site_$SiteName"; 61 | 62 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 63 | Write-Verbose "Started at $datetime" 64 | 65 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 66 | $stopwatch.Start(); 67 | 68 | $total = 0; 69 | 70 | class USBDevice { 71 | [String] $Computer 72 | [DateTime] $DateScanned 73 | 74 | [String] $ResourceNames 75 | [String] $Caption 76 | [String] $ClassGuid 77 | [String] $CreationClassName 78 | [String] $Description 79 | [String] $DeviceID 80 | [String] $Manufacturer 81 | [String] $DeviceName 82 | [String] $PNPDeviceID 83 | [String] $Service 84 | [String] $Status 85 | [String] $SystemCreationClassName 86 | [String] $Timestamp 87 | }; 88 | }; 89 | 90 | PROCESS{ 91 | 92 | if ($Computer -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){ # is this an IP address? 93 | 94 | $fqdn = [System.Net.Dns]::GetHostByAddress($Computer).Hostname; 95 | $ThisComputer = $fqdn.Split(".")[0]; 96 | } 97 | 98 | else{ # Convert any FQDN into just hostname 99 | 100 | $ThisComputer = $Computer.Split(".")[0].Replace('"', ''); 101 | }; 102 | 103 | if ($CIM){ 104 | 105 | $SMS_R_System = $Null; 106 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 107 | 108 | if ($SMS_R_System) { 109 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 110 | $SMS_G_System_USB_DEVICE = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select Caption, ClassGuid, CreationClassName, Description, DeviceID, Manufacturer, Name, PNPDeviceID, Service, Status, SystemCreationClassName, TimeStamp from SMS_G_System_USB_DEVICE where ResourceID='$ResourceID'"; 111 | }; 112 | } 113 | else{ 114 | 115 | $SMS_R_System = $Null; 116 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 117 | 118 | if ($SMS_R_System) { 119 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 120 | $SMS_G_System_USB_DEVICE = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select Caption, ClassGuid, CreationClassName, Description, DeviceID, Manufacturer, Name, PNPDeviceID, Service, Status, SystemCreationClassName, TimeStamp from SMS_G_System_USB_DEVICE where ResourceID='$ResourceID'"; 121 | }; 122 | }; 123 | 124 | if ($SMS_G_System_USB_DEVICE){ 125 | 126 | $SMS_G_System_USB_DEVICE | ForEach-Object { 127 | 128 | $output = $null; 129 | $output = [USBDevice]::new(); 130 | 131 | $output.Computer = $ThisComputer; 132 | $output.DateScanned = Get-Date -Format u; 133 | 134 | $output.ResourceNames = $SMS_R_System.ResourceNames[0] 135 | $output.Caption = $_.Caption; 136 | $output.ClassGuid = $_.ClassGuid; 137 | $output.CreationClassName = $_.CreationClassName; 138 | $output.Description = $_.Description; 139 | $output.DeviceID = $_.DeviceID; 140 | $output.Manufacturer = $_.Manufacturer; 141 | $output.DeviceName = $_.Name; 142 | $output.PNPDeviceID = $_.PNPDeviceID; 143 | $output.Service = $_.Service; 144 | $output.Status = $_.Status; 145 | $output.SystemCreationClassName = $_.SystemCreationClassName; 146 | $output.Timestamp = $_.Timestamp; 147 | 148 | return $output; 149 | }; 150 | } 151 | else { 152 | 153 | $output = $null; 154 | $output = [USBDevice]::new(); 155 | 156 | $output.Computer = $Computer; 157 | $output.DateScanned = Get-Date -Format u; 158 | 159 | return $output; 160 | }; 161 | 162 | $elapsed = $stopwatch.Elapsed; 163 | $total = $total+1; 164 | 165 | Write-Verbose -Message "System $total `t $ThisComputer `t Time Elapsed: $elapsed"; 166 | 167 | }; 168 | 169 | END{ 170 | $elapsed = $stopwatch.Elapsed; 171 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 172 | }; 173 | }; 174 | 175 | 176 | -------------------------------------------------------------------------------- /Functions/Hunt-SCCMEnvironments.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-SCCMEnvironments { 2 | <# 3 | .Synopsis 4 | Queries SCCM for a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries SCCM for a given hostname, FQDN, or IP address. 8 | !!WARNING: Long VariableValues vay be truncated using SCCM as a source!! 9 | 10 | .Parameter Computer 11 | Computer can be a single hostname, FQDN, or IP address. 12 | 13 | .Parameter CIM 14 | Use Get-CIMInstance rather than Get-WMIObject. CIM cmdlets use WSMAN (WinRM) 15 | to connect to remote machines, and has better standardized output (e.g. 16 | datetime format). CIM cmdlets require the querying user to be a member of 17 | Administrators or WinRMRemoteWMIUsers_ on the target system. Get-WMIObject 18 | is the default due to lower permission requirements, but can be blocked by 19 | firewalls in some environments. 20 | 21 | .Example 22 | Hunt-SCCMEnvironments 23 | Hunt-SCCMEnvironments SomeHostName.domain.com 24 | Get-Content C:\hosts.csv | Hunt-SCCMEnvironments 25 | Hunt-SCCMEnvironments $env:computername 26 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-SCCMEnvironments 27 | 28 | .Notes 29 | Updated: 2017-10-10 30 | 31 | Contributing Authors: 32 | Anthony Phipps 33 | 34 | LEGAL: Copyright (C) 2017 35 | This program is free software: you can redistribute it and/or modify 36 | it under the terms of the GNU General Public License as published by 37 | the Free Software Foundation, either version 3 of the License, or 38 | (at your option) any later version. 39 | 40 | This program is distributed in the hope that it will be useful, 41 | but WITHOUT ANY WARRANTY; without even the implied warranty of 42 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 43 | GNU General Public License for more details. 44 | 45 | You should have received a copy of the GNU General Public License 46 | along with this program. If not, see . 47 | #> 48 | 49 | PARAM( 50 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 51 | $Computer = $env:COMPUTERNAME, 52 | [Parameter()] 53 | $SiteName="A1", 54 | [Parameter()] 55 | $SCCMServer="server.domain.com", 56 | [Parameter()] 57 | [switch]$CIM 58 | ); 59 | 60 | BEGIN{ 61 | $SCCMNameSpace="root\sms\site_$SiteName"; 62 | 63 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 64 | Write-Verbose "Started at $datetime" 65 | 66 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 67 | $stopwatch.Start(); 68 | 69 | $total = 0; 70 | 71 | class Environment { 72 | [String] $Computer 73 | [DateTime] $DateScanned 74 | [String] $ResourceNames 75 | [String] $Username 76 | [String] $SystemVariable 77 | [String] $VariableValue 78 | [String] $Caption 79 | [String] $Description 80 | [String] $Timestamp 81 | }; 82 | } 83 | 84 | PROCESS{ 85 | 86 | if ($Computer -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){ # is this an IP address? 87 | 88 | $fqdn = [System.Net.Dns]::GetHostByAddress($Computer).Hostname; 89 | $ThisComputer = $fqdn.Split(".")[0]; 90 | } 91 | else{ # Convert any FQDN into just hostname 92 | 93 | $ThisComputer = $Computer.Split(".")[0].Replace('"', ''); 94 | }; 95 | 96 | if ($CIM){ 97 | 98 | $SMS_R_System = $Null; 99 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 100 | 101 | if ($SMS_R_System) { 102 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 103 | $SMS_G_System_ENVIRONMENT = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select Name, VariableValue, SystemVariable, Username, Timestamp, Caption, Description from SMS_G_System_ENVIRONMENT where ResourceID='$ResourceID'"; 104 | }; 105 | } 106 | else{ 107 | 108 | $SMS_R_System = $Null; 109 | $SMS_R_System = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 110 | 111 | if ($SMS_R_System) { 112 | 113 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 114 | $SMS_G_System_ENVIRONMENT = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select Name, VariableValue, SystemVariable, Username, Timestamp, Caption, Description from SMS_G_System_ENVIRONMENT where ResourceID='$ResourceID'"; 115 | }; 116 | }; 117 | 118 | if ($SMS_G_System_ENVIRONMENT){ 119 | 120 | $SMS_G_System_ENVIRONMENT | ForEach-Object { 121 | 122 | $output = $null; 123 | $output = [Environment]::new(); 124 | 125 | $output.Computer = $ThisComputer; 126 | $output.DateScanned = Get-Date -Format u; 127 | 128 | $output.ResourceNames = $SMS_R_System.ResourceNames[0] 129 | $output.VariableValue = $_.VariableValue; # "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" contains remainder of values above 255 characters! 130 | $output.SystemVariable = $_.SystemVariable; 131 | $output.Username = $_.Username; 132 | $output.Timestamp = $_.Timestamp; 133 | 134 | if ($_.Caption.Split("\")[2]){ # These values have variable \'s present until the relevant content. 135 | $output.Caption = $_.Caption.Split("\")[2]; 136 | $output.Description = $_.Description.Split("\")[2]; 137 | } 138 | else{ 139 | $output.Caption = $_.Caption.Split("\")[1]; 140 | $output.Description = $_.Description.Split("\")[1]; 141 | }; 142 | 143 | 144 | return $output; 145 | 146 | }; 147 | } 148 | else { 149 | 150 | $output = $null; 151 | $output = [Environment]::new(); 152 | $output.Computer = $Computer; 153 | $output.DateScanned = Get-Date -Format u; 154 | 155 | $elapsed = $stopwatch.Elapsed; 156 | $total = $total+1; 157 | 158 | return $output; 159 | }; 160 | }; 161 | 162 | END{ 163 | $elapsed = $stopwatch.Elapsed; 164 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 165 | }; 166 | }; 167 | -------------------------------------------------------------------------------- /Functions/Hunt-TPM.ps1: -------------------------------------------------------------------------------- 1 | function Hunt-TPM { 2 | <# 3 | .Synopsis 4 | Gets the TPM info on a given system. 5 | 6 | .Description 7 | Gets the TPM info on a given system. Converts ManufacturerId if the ID is in the list of built-in names. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Fails 13 | Provide a path to save failed systems to. 14 | 15 | .Example 16 | Hunt-TPM 17 | Hunt-TPM SomeHostName.domain.com 18 | Get-Content C:\hosts.csv | Hunt-TPM 19 | Hunt-TPM $env:computername 20 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-TPM 21 | 22 | .Notes 23 | Updated: 2017-10-23 24 | 25 | Contributing Authors: 26 | Anthony Phipps 27 | 28 | LEGAL: Copyright (C) 2017 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | 34 | This program is distributed in the hope that it will be useful, 35 | but WITHOUT ANY WARRANTY; without even the implied warranty of 36 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37 | GNU General Public License for more details. 38 | 39 | You should have received a copy of the GNU General Public License 40 | along with this program. If not, see . 41 | 42 | .LINK 43 | https://trustedcomputinggroup.org/vendor-id-registry/ 44 | https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV170012 45 | #> 46 | 47 | param( 48 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 49 | $Computer = $env:COMPUTERNAME, 50 | [Parameter()] 51 | $Fails 52 | ); 53 | 54 | begin{ 55 | 56 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 57 | Write-Information -MessageData "Started at $datetime" -InformationAction Continue; 58 | 59 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 60 | $stopwatch.Start(); 61 | 62 | $total = 0; 63 | 64 | $Manufacturers = @{ 65 | 0x414D4400 = "AMD"; 66 | 0x41544D4C = "Atmel"; 67 | 0x4252434D = "Broadcom"; 68 | 0x474F4F47 = "Google"; 69 | 0x48504500 = "HPE"; 70 | 0x49424d00 = "IBM"; 71 | 0x49465800 = "Infineon"; 72 | 0x494E5443 = "Intel"; 73 | 0x4C454E00 = "Lenovo"; 74 | 0x4D534654 = "Microsoft"; 75 | 0x4E534D20 = "National Semiconductor"; 76 | 0x4E544300 = "Nuvoton Technology"; 77 | 0x4E545A00 = "Nationz"; 78 | 0x51434F4D = "Qualcomm"; 79 | 0x524F4343 = "Fuzhou Rockchip"; 80 | 0x534D5343 = "SMSC"; 81 | 0x534D534E = "Samsung"; 82 | 0x534E5300 = "Sinosun"; 83 | 0x53544D20 = "ST Microelectronics"; 84 | 0x54584E00 = "Texas Instruments"; 85 | 0x57454300 = "Winbond"; 86 | }; 87 | 88 | class TPM 89 | { 90 | [String] $Computer 91 | [dateTime] $DateScanned 92 | [bool] $TpmPresent 93 | [bool] $TpmReady 94 | [uint32] $ManufacturerId 95 | [String] $ManufacturerIdHex 96 | [String] $ManufacturerName 97 | [String] $ManufacturerVersion 98 | [String] $ManagedAuthLevel 99 | [String] $OwnerAuth 100 | [bool] $OwnerClearDisabled 101 | [String] $AutoProvisioning 102 | [bool] $LockedOut 103 | [String] $LockoutCount 104 | [String] $LockoutMax 105 | [String] $SelfTest 106 | [String] $FirmwareVersionAtLastProvision 107 | }; 108 | }; 109 | 110 | process{ 111 | 112 | $Computer = $Computer.Replace('"', ''); # get rid of quotes, if present 113 | 114 | $TPMInfo = $null; 115 | $TPMInfo = Invoke-Command -ComputerName $Computer -ErrorAction SilentlyContinue -ScriptBlock { 116 | $TPM = Get-Tpm -ErrorAction SilentlyContinue; 117 | $FirmwareVersionAtLastProvision = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\TPM\WMI" -Name "FirmwareVersionAtLastProvision" -ErrorAction SilentlyContinue).FirmwareVersionAtLastProvision; 118 | 119 | $TPM | Add-Member -MemberType NoteProperty -Name "FirmwareVersionAtLastProvision" -Value $FirmwareVersionAtLastProvision; 120 | 121 | return $TPM; 122 | }; 123 | 124 | if ($TPMInfo) { 125 | 126 | $output = $null; 127 | $output = [TPM]::new(); 128 | 129 | $output.Computer = $Computer; 130 | $output.DateScanned = Get-Date -Format u; 131 | 132 | $output.TpmPresent = $TPMInfo.TpmPresent; 133 | $output.TpmReady = $TPMInfo.TpmReady; 134 | $output.ManufacturerId = $TPMInfo.ManufacturerId; 135 | $output.ManufacturerVersion = $TPMInfo.ManufacturerVersion; 136 | $output.ManagedAuthLevel = $TPMInfo.ManagedAuthLevel; 137 | $output.OwnerAuth = $TPMInfo.OwnerAuth; 138 | $output.OwnerClearDisabled = $TPMInfo.OwnerClearDisabled; 139 | $output.AutoProvisioning = $TPMInfo.AutoProvisioning; 140 | $output.LockedOut = $TPMInfo.LockedOut; 141 | $output.LockoutCount = $TPMInfo.LockoutCount; 142 | $output.LockoutMax = $TPMInfo.LockoutMax; 143 | $output.SelfTest = $TPMInfo.SelfTest; 144 | $output.ManufacturerIdHex = "0x{0:x}" -f $TPMInfo.ManufacturerId; 145 | $output.FirmwareVersionAtLastProvision = $TPMInfo.FirmwareVersionAtLastProvision; 146 | 147 | # Convert ManufacturerId to ManufacturerName 148 | foreach ($Key in $Manufacturers.Keys) { 149 | 150 | if ($Key -eq $TPMInfo.ManufacturerId) { 151 | 152 | $output.ManufacturerName = $Manufacturers[$Key]; 153 | }; 154 | }; 155 | 156 | return $output; 157 | } 158 | else { 159 | 160 | Write-Verbose ("{0}: System failed." -f $Computer); 161 | if ($Fails) { 162 | 163 | $total++; 164 | Add-Content -Path $Fails -Value ("$Computer"); 165 | } 166 | else { 167 | 168 | $output = $null; 169 | $output = [TPM]::new(); 170 | 171 | $output.Computer = $Computer; 172 | $output.DateScanned = Get-Date -Format u; 173 | 174 | $total++; 175 | return $output; 176 | }; 177 | }; 178 | }; 179 | 180 | end { 181 | 182 | $elapsed = $stopwatch.Elapsed; 183 | 184 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 185 | }; 186 | }; -------------------------------------------------------------------------------- /Functions/Hunt-SCCMLogicalDisks.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-SCCMLogicalDisks { 2 | <# 3 | .Synopsis 4 | Queries SCCM for a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries SCCM for a given hostname, FQDN, or IP address. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter CIM 13 | Use Get-CIMInstance rather than Get-WMIObject. CIM cmdlets use WSMAN (WinRM) 14 | to connect to remote machines, and has better standardized output (e.g. 15 | datetime format). CIM cmdlets require the querying user to be a member of 16 | Administrators or WinRMRemoteWMIUsers_ on the target system. Get-WMIObject 17 | is the default due to lower permission requirements, but can be blocked by 18 | firewalls in some environments. 19 | 20 | .Example 21 | Hunt-SCCMLogicalDisks 22 | Hunt-SCCMLogicalDisks SomeHostName.domain.com 23 | Get-Content C:\hosts.csv | Hunt-SCCMLogicalDisks 24 | Hunt-SCCMLogicalDisks $env:computername 25 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-SCCMLogicalDisks 26 | 27 | .Notes 28 | Updated: 2017-10-10 29 | 30 | Contributing Authors: 31 | Anthony Phipps 32 | 33 | LEGAL: Copyright (C) 2017 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, either version 3 of the License, or 37 | (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, 40 | but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | GNU General Public License for more details. 43 | 44 | You should have received a copy of the GNU General Public License 45 | along with this program. If not, see . 46 | #> 47 | 48 | PARAM( 49 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 50 | $Computer, 51 | [Parameter()] 52 | $SiteName="A1", 53 | [Parameter()] 54 | $SCCMServer="server.domain.com", 55 | [Parameter()] 56 | [switch]$CIM 57 | ); 58 | 59 | BEGIN{ 60 | $SCCMNameSpace="root\sms\site_$SiteName"; 61 | 62 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 63 | Write-Verbose "Started at $datetime" 64 | 65 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 66 | $stopwatch.Start(); 67 | 68 | $total = 0; 69 | } 70 | 71 | PROCESS{ 72 | 73 | if ($Computer -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){ # is this an IP address? 74 | 75 | $fqdn = [System.Net.Dns]::GetHostByAddress($Computer).Hostname; 76 | $ThisComputer = $fqdn.Split(".")[0]; 77 | } 78 | 79 | else{ # Convert any FQDN into just hostname 80 | 81 | $ThisComputer = $Computer.Split(".")[0].Replace('"', ''); 82 | }; 83 | 84 | $output = [PSCustomObject]@{ 85 | Name = $ThisComputer 86 | ResourceNames = "" 87 | Caption = "" 88 | Compressed = "" 89 | Description = "" 90 | DeviceID = "" 91 | DriveType = "" 92 | ErrorDescription = "" 93 | FileSystem = "" 94 | FreeSpace = "" 95 | InstallDate = "" 96 | LastErrorCode = "" 97 | DiskName = "" 98 | Size = "" 99 | Status = "" 100 | StatusInfo = "" 101 | VolumeName = "" 102 | VolumeSerialNumber = "" 103 | Timestamp = "" 104 | }; 105 | 106 | if ($CIM){ 107 | 108 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 109 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 110 | $SMS_G_System_LOGICAL_DISK = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select Caption, Compressed, Description, DeviceID, DriveType, ErrorDescription, FileSystem, FreeSpace, InstallDate, LastErrorCode, Name, Size, Status, StatusInfo, TimeStamp, VolumeName, VolumeSerialNumber from SMS_G_System_LOGICAL_DISK where ResourceID='$ResourceID'"; 111 | } 112 | else { 113 | 114 | $SMS_R_System = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 115 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 116 | $SMS_G_System_LOGICAL_DISK = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select Caption, Compressed, Description, DeviceID, DriveType, ErrorDescription, FileSystem, FreeSpace, InstallDate, LastErrorCode, Name, Size, Status, StatusInfo, TimeStamp, VolumeName, VolumeSerialNumber from SMS_G_System_LOGICAL_DISK where ResourceID='$ResourceID'"; 117 | }; 118 | 119 | if ($SMS_G_System_LOGICAL_DISK){ 120 | 121 | $SMS_G_System_LOGICAL_DISK | ForEach-Object { 122 | 123 | $output.ResourceNames = $SMS_R_System.ResourceNames[0] 124 | 125 | $output.Caption = $_.Caption; 126 | $output.Compressed = $_.Compressed; 127 | $output.Description = $_.Description; 128 | $output.DeviceID = $_.DeviceID; 129 | $output.DriveType = $_.DriveType; 130 | $output.ErrorDescription = $_.ErrorDescription; 131 | $output.FileSystem = $_.FileSystem; 132 | $output.FreeSpace = $_.FreeSpace; 133 | $output.InstallDate = $_.InstallDate; 134 | $output.LastErrorCode = $_.LastErrorCode; 135 | $output.DiskName = $_.Name; 136 | $output.Size = $_.Size; 137 | $output.Status = $_.Status; 138 | $output.StatusInfo = $_.StatusInfo; 139 | $output.VolumeName = $_.VolumeName; 140 | $output.VolumeSerialNumber = $_.VolumeSerialNumber; 141 | 142 | $output.Timestamp = $_.Timestamp; 143 | 144 | return $output; 145 | $output.PsObject.Members | ForEach-Object {$output.PsObject.Members.Remove($_.Name)}; 146 | }; 147 | } 148 | else { 149 | 150 | return $output; 151 | $output.PsObject.Members | ForEach-Object {$output.PsObject.Members.Remove($_.Name)}; 152 | }; 153 | 154 | $elapsed = $stopwatch.Elapsed; 155 | $total = $total+1; 156 | 157 | Write-Verbose -Message "System $total `t $ThisComputer `t Time Elapsed: $elapsed"; 158 | 159 | }; 160 | 161 | END{ 162 | $elapsed = $stopwatch.Elapsed; 163 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 164 | }; 165 | }; 166 | 167 | 168 | -------------------------------------------------------------------------------- /Functions/Hunt-SCCMAutostarts.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-SCCMAutostarts { 2 | <# 3 | .Synopsis 4 | Queries SCCM for a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries SCCM for a given hostname, FQDN, or IP address. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter CIM 13 | Use Get-CIMInstance rather than Get-WMIObject. CIM cmdlets use WSMAN (WinRM) 14 | to connect to remote machines, and has better standardized output (e.g. 15 | datetime format). CIM cmdlets require the querying user to be a member of 16 | Administrators or WinRMRemoteWMIUsers_ on the target system. Get-WMIObject 17 | is the default due to lower permission requirements, but can be blocked by 18 | firewalls in some environments. 19 | 20 | .Example 21 | Hunt-SCCMAutostarts 22 | Hunt-SCCMAutostarts SomeHostName.domain.com 23 | Get-Content C:\hosts.csv | Hunt-SCCMAutostarts 24 | Hunt-SCCMAutostarts $env:computername 25 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-SCCMAutostarts 26 | 27 | .Notes 28 | Updated: 2017-10-10 29 | 30 | Contributing Authors: 31 | Anthony Phipps 32 | 33 | LEGAL: Copyright (C) 2017 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, either version 3 of the License, or 37 | (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, 40 | but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | GNU General Public License for more details. 43 | 44 | You should have received a copy of the GNU General Public License 45 | along with this program. If not, see . 46 | #> 47 | 48 | PARAM( 49 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 50 | $Computer = $env:COMPUTERNAME, 51 | [Parameter()] 52 | $SiteName="A1", 53 | [Parameter()] 54 | $SCCMServer="server.domain.com", 55 | [Parameter()] 56 | [switch]$CIM 57 | ); 58 | 59 | BEGIN{ 60 | $SCCMNameSpace="root\sms\site_$SiteName"; 61 | 62 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 63 | Write-Verbose "Started at $datetime" 64 | 65 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 66 | $stopwatch.Start(); 67 | 68 | $total = 0; 69 | 70 | class Autostart { 71 | [String] $Computer 72 | [DateTime] $DateScanned 73 | [String] $ResourceNames 74 | [String] $Description 75 | [String] $FileName 76 | [String] $FilePropertiesHash 77 | [String] $FilePropertiesHashEx 78 | [String] $FileVersion 79 | [String] $Location 80 | [String] $Product 81 | [String] $ProductVersion 82 | [String] $Publisher 83 | [String] $RevisionID 84 | [String] $StartupType 85 | [String] $StartupValue 86 | [String] $Timestamp 87 | }; 88 | }; 89 | 90 | PROCESS{ 91 | 92 | if ($Computer -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){ # is this an IP address? 93 | 94 | $fqdn = [System.Net.Dns]::GetHostByAddress($Computer).Hostname; 95 | $ThisComputer = $fqdn.Split(".")[0]; 96 | } 97 | 98 | else{ # Convert any FQDN into just hostname 99 | 100 | $ThisComputer = $Computer.Split(".")[0].Replace('"', ''); 101 | }; 102 | 103 | 104 | if ($CIM){ 105 | 106 | $SMS_R_System = $Null; 107 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 108 | 109 | if ($SMS_R_System) { 110 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 111 | $SMS_G_System_AUTOSTART_SOFTWARE = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select Description, FileName, FilePropertiesHash, FilePropertiesHashEx, FileVersion, Location, Product, ProductVersion, Publisher, RevisionID, StartupType, StartupValue, TimeStamp from SMS_G_System_AUTOSTART_SOFTWARE where ResourceID='$ResourceID'"; 112 | }; 113 | } 114 | else{ 115 | 116 | $SMS_R_System = $Null; 117 | $SMS_R_System = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 118 | 119 | if ($SMS_R_System) { 120 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 121 | $SMS_G_System_AUTOSTART_SOFTWARE = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select Description, FileName, FilePropertiesHash, FilePropertiesHashEx, FileVersion, Location, Product, ProductVersion, Publisher, RevisionID, StartupType, StartupValue, TimeStamp from SMS_G_System_AUTOSTART_SOFTWARE where ResourceID='$ResourceID'"; 122 | }; 123 | }; 124 | 125 | if ($SMS_G_System_AUTOSTART_SOFTWARE){ 126 | 127 | $SMS_G_System_AUTOSTART_SOFTWARE | ForEach-Object { 128 | 129 | $output = $null; 130 | $output = [Autostart]::new(); 131 | 132 | $output.Computer = $ThisComputer; 133 | $output.DateScanned = Get-Date -Format u; 134 | 135 | $output.ResourceNames = $SMS_R_System.ResourceNames[0]; 136 | $output.Description = $_.Description; 137 | $output.FileName = $_.FileName; 138 | $output.FilePropertiesHash = $_.FilePropertiesHash; 139 | $output.FilePropertiesHashEx = $_.FilePropertiesHashEx; 140 | $output.FileVersion = $_.FileVersion; 141 | $output.Location = $_.Location; 142 | $output.Product = $_.Product; 143 | $output.ProductVersion = $_.ProductVersion; 144 | $output.Publisher = $_.Publisher; 145 | $output.RevisionID = $_.RevisionID; 146 | $output.StartupType = $_.StartupType; 147 | $output.StartupValue = $_.StartupValue; 148 | $output.Timestamp = $_.Timestamp; 149 | 150 | return $output; 151 | }; 152 | } 153 | else { 154 | 155 | $output = $null; 156 | $output = [Autostart]::new(); 157 | 158 | $output.Computer = $Computer; 159 | $output.DateScanned = Get-Date -Format u; 160 | 161 | return $output; 162 | }; 163 | 164 | $elapsed = $stopwatch.Elapsed; 165 | $total = $total+1; 166 | 167 | Write-Verbose -Message "System $total `t $ThisComputer `t Time Elapsed: $elapsed"; 168 | 169 | }; 170 | 171 | END{ 172 | $elapsed = $stopwatch.Elapsed; 173 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 174 | }; 175 | }; 176 | 177 | 178 | -------------------------------------------------------------------------------- /Functions/Hunt-SCCMInstalledSoftware.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-SCCMInstalledSoftware { 2 | <# 3 | .Synopsis 4 | Queries SCCM for a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries SCCM for a given hostname, FQDN, or IP address. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter CIM 13 | Use Get-CIMInstance rather than Get-WMIObject. CIM cmdlets use WSMAN (WinRM) 14 | to connect to remote machines, and has better standardized output (e.g. 15 | datetime format). CIM cmdlets require the querying user to be a member of 16 | Administrators or WinRMRemoteWMIUsers_ on the target system. Get-WMIObject 17 | is the default due to lower permission requirements, but can be blocked by 18 | firewalls in some environments. 19 | 20 | .Example 21 | Hunt-SCCMInstalledSoftware 22 | Hunt-SCCMInstalledSoftware SomeHostName.domain.com 23 | Get-Content C:\hosts.csv | Hunt-SCCMInstalledSoftware 24 | Hunt-SCCMInstalledSoftware $env:computername 25 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-SCCMInstalledSoftware 26 | 27 | .Notes 28 | Updated: 2017-10-10 29 | 30 | Contributing Authors: 31 | Anthony Phipps 32 | 33 | LEGAL: Copyright (C) 2017 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, either version 3 of the License, or 37 | (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, 40 | but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | GNU General Public License for more details. 43 | 44 | You should have received a copy of the GNU General Public License 45 | along with this program. If not, see . 46 | #> 47 | 48 | PARAM( 49 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 50 | $Computer, 51 | [Parameter()] 52 | $SiteName="A1", 53 | [Parameter()] 54 | $SCCMServer="server.domain.com", 55 | [Parameter()] 56 | [switch]$CIM 57 | ); 58 | 59 | BEGIN{ 60 | $SCCMNameSpace="root\sms\site_$SiteName"; 61 | 62 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 63 | Write-Verbose "Started at $datetime" 64 | 65 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 66 | $stopwatch.Start(); 67 | 68 | $total = 0; 69 | } 70 | 71 | PROCESS{ 72 | 73 | if ($Computer -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){ # is this an IP address? 74 | 75 | $fqdn = [System.Net.Dns]::GetHostByAddress($Computer).Hostname; 76 | $ThisComputer = $fqdn.Split(".")[0]; 77 | } 78 | 79 | else{ # Convert any FQDN into just hostname 80 | 81 | $ThisComputer = $Computer.Split(".")[0].Replace('"', ''); 82 | }; 83 | 84 | $output = [PSCustomObject]@{ 85 | Name = $ThisComputer 86 | ResourceNames = "" 87 | ARPDisplayName = "" 88 | InstallDate = "" 89 | InstallDirectoryValidation = "" 90 | InstalledLocation = "" 91 | InstallSource = "" 92 | InstallType = "" 93 | Language = "" 94 | LocalPackage = "" 95 | OSComponent = "" 96 | ProductName = "" 97 | ProductVersion = "" 98 | Publisher = "" 99 | RegisteredUser = "" 100 | ServicePack = "" 101 | UninstallString = "" 102 | VersionMajor = "" 103 | VersionMinor = "" 104 | Timestamp = "" 105 | }; 106 | 107 | if ($CIM){ 108 | 109 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 110 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 111 | $SMS_G_System_INSTALLED_SOFTWARE = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ARPDisplayName, InstallDate, InstallDirectoryValidation, InstalledLocation, InstallSource, InstallType, Language, LocalPackage, OSComponent, ProductName, ProductVersion, Publisher, RegisteredUser, ServicePack, TimeStamp, UninstallString, VersionMajor, VersionMinor from SMS_G_System_INSTALLED_SOFTWARE where ResourceID='$ResourceID'"; 112 | } 113 | else{ 114 | 115 | $SMS_R_System = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 116 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 117 | $SMS_G_System_INSTALLED_SOFTWARE = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select ARPDisplayName, InstallDate, InstallDirectoryValidation, InstalledLocation, InstallSource, InstallType, Language, LocalPackage, OSComponent, ProductName, ProductVersion, Publisher, RegisteredUser, ServicePack, TimeStamp, UninstallString, VersionMajor, VersionMinor from SMS_G_System_INSTALLED_SOFTWARE where ResourceID='$ResourceID'"; 118 | }; 119 | 120 | if ($SMS_G_System_INSTALLED_SOFTWARE){ 121 | 122 | $SMS_G_System_INSTALLED_SOFTWARE | ForEach-Object { 123 | 124 | $output.ResourceNames = $SMS_R_System.ResourceNames[0] 125 | 126 | $output.ARPDisplayName = $_.ARPDisplayName; 127 | $output.InstallDate = $_.InstallDate; 128 | $output.InstallDirectoryValidation = $_.InstallDirectoryValidation; 129 | $output.InstalledLocation = $_.InstalledLocation; 130 | $output.InstallSource = $_.InstallSource; 131 | $output.InstallType = $_.InstallType; 132 | $output.Language = $_.Language; 133 | $output.LocalPackage = $_.LocalPackage; 134 | $output.OSComponent = $_.OSComponent; 135 | $output.ProductName = $_.ProductName; 136 | $output.Publisher = $_.Publisher; 137 | $output.RegisteredUser = $_.RegisteredUser; 138 | $output.ServicePack = $_.ServicePack; 139 | $output.UninstallString = $_.UninstallString; 140 | $output.VersionMajor = $_.VersionMajor; 141 | $output.VersionMinor = $_.VersionMinor; 142 | 143 | $output.Timestamp = $_.Timestamp; 144 | 145 | return $output; 146 | $output.PsObject.Members | ForEach-Object {$output.PsObject.Members.Remove($_.Name)}; 147 | }; 148 | } 149 | else { 150 | 151 | return $output; 152 | $output.PsObject.Members | ForEach-Object {$output.PsObject.Members.Remove($_.Name)}; 153 | }; 154 | 155 | $elapsed = $stopwatch.Elapsed; 156 | $total = $total+1; 157 | 158 | Write-Verbose -Message "System $total `t $ThisComputer `t Time Elapsed: $elapsed"; 159 | 160 | }; 161 | 162 | END{ 163 | $elapsed = $stopwatch.Elapsed; 164 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 165 | }; 166 | }; 167 | 168 | 169 | -------------------------------------------------------------------------------- /Functions/Hunt-SCCMServices.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION Hunt-SCCMServices { 2 | <# 3 | .Synopsis 4 | Queries SCCM for a given hostname, FQDN, or IP address. 5 | 6 | .Description 7 | Queries SCCM for a given hostname, FQDN, or IP address. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter CIM 13 | Use Get-CIMInstance rather than Get-WMIObject. CIM cmdlets use WSMAN (WinRM) 14 | to connect to remote machines, and has better standardized output (e.g. 15 | datetime format). CIM cmdlets require the querying user to be a member of 16 | Administrators or WinRMRemoteWMIUsers_ on the target system. Get-WMIObject 17 | is the default due to lower permission requirements, but can be blocked by 18 | firewalls in some environments. 19 | 20 | .Example 21 | Hunt-SCCMServices 22 | Hunt-SCCMServices SomeHostName.domain.com 23 | Get-Content C:\hosts.csv | Hunt-SCCMServices 24 | Hunt-SCCMServices $env:computername 25 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-SCCMServices 26 | 27 | .Notes 28 | Updated: 2017-10-10 29 | 30 | Contributing Authors: 31 | Anthony Phipps 32 | 33 | LEGAL: Copyright (C) 2017 34 | This program is free software: you can redistribute it and/or modify 35 | it under the terms of the GNU General Public License as published by 36 | the Free Software Foundation, either version 3 of the License, or 37 | (at your option) any later version. 38 | 39 | This program is distributed in the hope that it will be useful, 40 | but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | GNU General Public License for more details. 43 | 44 | You should have received a copy of the GNU General Public License 45 | along with this program. If not, see . 46 | #> 47 | 48 | PARAM( 49 | [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] 50 | $Computer = $env:COMPUTERNAME, 51 | [Parameter()] 52 | $SiteName="A1", 53 | [Parameter()] 54 | $SCCMServer="server.domain.com", 55 | [Parameter()] 56 | [switch]$CIM 57 | ); 58 | 59 | BEGIN{ 60 | $SCCMNameSpace="root\sms\site_$SiteName"; 61 | 62 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 63 | Write-Verbose "Started at $datetime" 64 | 65 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 66 | $stopwatch.Start(); 67 | 68 | $total = 0; 69 | 70 | class Service { 71 | [String] $Computer 72 | [Datetime] $DateScanned 73 | [String] $ResourceNames 74 | [String] $AcceptPause 75 | [String] $AcceptStop 76 | [String] $Caption 77 | [String] $CheckPoint 78 | [String] $Description 79 | [String] $DesktopInteract 80 | [String] $DisplayName 81 | [String] $ErrorControl 82 | [String] $ExitCode 83 | [String] $InstallDate 84 | [String] $ServiceName 85 | [String] $PathName 86 | [String] $ProcessId 87 | [String] $ServiceSpecificExitCode 88 | [String] $ServiceType 89 | [String] $Started 90 | [String] $StartMode 91 | [String] $StartName 92 | [String] $State 93 | [String] $Status 94 | [String] $WaitHint 95 | [String] $Timestamp 96 | }; 97 | }; 98 | 99 | PROCESS{ 100 | 101 | if ($Computer -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){ # is this an IP address? 102 | 103 | $fqdn = [System.Net.Dns]::GetHostByAddress($Computer).Computername; 104 | $ThisComputer = $fqdn.Split(".")[0]; 105 | } 106 | 107 | else{ # Convert any FQDN into just hostname 108 | 109 | $ThisComputer = $Computer.Split(".")[0].Replace('"', ''); 110 | }; 111 | 112 | if ($CIM){ 113 | 114 | $SMS_R_System = $null; 115 | $SMS_R_System = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 116 | 117 | if ($SMS_R_System) { 118 | 119 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 120 | $SMS_G_System_SERVICE = Get-CIMInstance -namespace $SCCMNameSpace -computer $SCCMServer -query "select AcceptPause, AcceptStop, Caption, CheckPoint, Description, DesktopInteract, DisplayName, ErrorControl, ExitCode, InstallDate, Name, PathName, ProcessId, ServiceSpecificExitCode, ServiceType, Started, StartMode, StartName, State, Status, WaitHint, Timestamp from SMS_G_System_SERVICE where ResourceID='$ResourceID'"; 121 | }; 122 | } 123 | else{ 124 | 125 | $SMS_R_System = $null; 126 | $SMS_R_System = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select ResourceNames, ResourceID from SMS_R_System where name='$ThisComputer'"; 127 | 128 | if ($SMS_R_System) { 129 | 130 | $ResourceID = $SMS_R_System.ResourceID; # Needed since -query seems to lack support for calling $SMS_R_System.ResourceID directly. 131 | $SMS_G_System_SERVICE = Get-WmiObject -namespace $SCCMNameSpace -computer $SCCMServer -query "select AcceptPause, AcceptStop, Caption, CheckPoint, Description, DesktopInteract, DisplayName, ErrorControl, ExitCode, InstallDate, Name, PathName, ProcessId, ServiceSpecificExitCode, ServiceType, Started, StartMode, StartName, State, Status, WaitHint, Timestamp from SMS_G_System_SERVICE where ResourceID='$ResourceID'"; 132 | }; 133 | }; 134 | 135 | if ($SMS_G_System_SERVICE){ 136 | 137 | $SMS_G_System_SERVICE | ForEach-Object { 138 | 139 | 140 | $output = $null; 141 | $output = [Service]::new(); 142 | 143 | $output.Computer = $ThisComputer; 144 | $output.DateScanned = Get-Date -Format u; 145 | 146 | $output.ResourceNames = $SMS_R_System.ResourceNames[0]; 147 | $output.AcceptPause = $_.AcceptPause; 148 | $output.AcceptStop = $_.AcceptStop; 149 | $output.Caption = $_.Caption; 150 | $output.CheckPoint = $_.CheckPoint; 151 | $output.Description = $_.Description; 152 | $output.DesktopInteract = $_.DesktopInteract; 153 | $output.DisplayName = $_.DisplayName; 154 | $output.ErrorControl = $_.ErrorControl; 155 | $output.ExitCode = $_.ExitCode; 156 | $output.InstallDate = $_.InstallDate; 157 | $output.ServiceName = $_.Name; 158 | $output.PathName = $_.PathName; 159 | $output.ProcessId = $_.ProcessId; 160 | $output.ServiceSpecificExitCode = $_.ServiceSpecificExitCode; 161 | $output.ServiceType = $_.ServiceType; 162 | $output.Started = $_.Started; 163 | $output.StartMode = $_.StartMode; 164 | $output.StartName = $_.StartName; 165 | $output.State = $_.State; 166 | $output.Status = $_.Status; 167 | $output.WaitHint = $_.WaitHint; 168 | $output.Timestamp = $_.Timestamp; 169 | 170 | return $output; 171 | }; 172 | } 173 | else{ 174 | 175 | $output = $null; 176 | $output = [Service]::new(); 177 | $output.Computer = $Computer; 178 | $output.DateScanned = Get-Date -Format u; 179 | 180 | return $output; 181 | }; 182 | 183 | $elapsed = $stopwatch.Elapsed; 184 | $total = $total+1; 185 | 186 | Write-Verbose -Message "System $total `t $ThisComputer `t Time Elapsed: $elapsed"; 187 | 188 | }; 189 | 190 | END{ 191 | $elapsed = $stopwatch.Elapsed; 192 | Write-Verbose "Total Systems: $total `t Total time elapsed: $elapsed"; 193 | }; 194 | }; 195 | 196 | -------------------------------------------------------------------------------- /Functions/Hunt-Processes.ps1: -------------------------------------------------------------------------------- 1 | Function Hunt-Processes { 2 | <# 3 | .Synopsis 4 | Gets the processes applied to a given system. 5 | 6 | .Description 7 | Gets the processes applied to a given system, including usernames. 8 | 9 | .Parameter Computer 10 | Computer can be a single hostname, FQDN, or IP address. 11 | 12 | .Parameter Services 13 | Includes Services associated with each Process ID. Slows processing per system by a small amount while service are pulled. 14 | 15 | .Parameter DLLs 16 | Includes DLLs associated with each Process ID. Note that DLLs cannot be pulled on remote systems due to lack of support in Get-Process. 17 | 18 | .Parameter Fails 19 | Provide a path to save failed systems to. 20 | 21 | .Example 22 | Hunt-Processes 23 | Hunt-Processes SomeHostName.domain.com 24 | Get-Content C:\hosts.csv | Hunt-Processes 25 | Hunt-Processes $env:computername 26 | Get-ADComputer -filter * | Select -ExpandProperty Name | Hunt-Processes 27 | 28 | .Notes 29 | Updated: 2017-10-10 30 | 31 | Contributing Authors: 32 | Anthony Phipps 33 | 34 | LEGAL: Copyright (C) 2017 35 | This program is free software: you can redistribute it and/or modify 36 | it under the terms of the GNU General Public License as published by 37 | the Free Software Foundation, either version 3 of the License, or 38 | (at your option) any later version. 39 | 40 | This program is distributed in the hope that it will be useful, 41 | but WITHOUT ANY WARRANTY; without even the implied warranty of 42 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 43 | GNU General Public License for more details. 44 | 45 | You should have received a copy of the GNU General Public License 46 | along with this program. If not, see . 47 | #> 48 | 49 | [CmdletBinding()] 50 | PARAM( 51 | [Parameter(ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] 52 | $Computer = $env:COMPUTERNAME, 53 | [Parameter()] 54 | [switch]$Services, 55 | [Parameter()] 56 | [switch]$DLLs, 57 | [Parameter()] 58 | $Fails 59 | ); 60 | 61 | BEGIN { 62 | 63 | $datetime = Get-Date -Format "yyyy-MM-dd_hh.mm.ss.ff"; 64 | Write-Verbose "Started at $datetime"; 65 | 66 | $stopwatch = New-Object System.Diagnostics.Stopwatch; 67 | $stopwatch.Start(); 68 | 69 | $total = 0; 70 | 71 | class Process { 72 | [String] $Computer 73 | [DateTime] $DateScanned 74 | 75 | [String] $Mode 76 | [String] $BasePriority 77 | [String] $CPU 78 | [String] $CommandLine 79 | [String] $Company 80 | [String] $Description 81 | [String] $EnableRaisingEvents 82 | [String] $FileVersion 83 | [String] $Handle 84 | [Int32] $HandleCount 85 | [Int32] $Id 86 | [String] $MainModule 87 | [String] $MainWindowHandle 88 | [String] $MainWindowTitle 89 | [Int32] $ModuleCount 90 | [String] $DisplayName 91 | [String] $Path 92 | [String] $PriorityBoostEnabled 93 | [String] $PriorityClass 94 | [String] $PrivilegedProcessorTime 95 | [String] $ProcessName 96 | [String] $ProcessorAffinity 97 | [String] $Product 98 | [String] $ProductVersion 99 | [String] $Responding 100 | [Int32] $SessionId 101 | [String] $StartTime 102 | [Int32] $Threads 103 | [String] $TotalProcessorTime 104 | [String] $UserName 105 | [String] $Services 106 | [String] $DLLs 107 | }; 108 | }; 109 | 110 | PROCESS { 111 | 112 | $Computer = $Computer.Replace('"', ''); 113 | 114 | $Processes = $null; 115 | $Mode = $null; 116 | 117 | Write-Verbose "Attempting Get-Process -IncludeUserName"; 118 | $Processes = Invoke-Command -ComputerName $Computer -ScriptBlock {Get-Process -IncludeUserName} -ErrorAction SilentlyContinue; 119 | $Mode = "1"; 120 | 121 | If ($Processes -eq $null) { 122 | 123 | Write-Verbose "FAILED: Get-Process -IncludeUserName"; 124 | Write-Verbose "Attempting Get-Process"; 125 | $Processes = Invoke-Command -ComputerName $Computer -ScriptBlock {Get-Process} -ErrorAction SilentlyContinue; 126 | $Mode = "2"; 127 | 128 | If ($Processes -eq $null) { 129 | 130 | Write-Verbose "FAILED: Get-Process"; 131 | Write-Verbose "Attempting Get-Process without -Invoke-Command"; 132 | $Processes = Get-Process -ComputerName $Computer -ErrorAction SilentlyContinue; 133 | $Mode = "3"; 134 | }; 135 | }; 136 | 137 | if ($Processes) { 138 | 139 | Write-Verbose "Processes collected."; 140 | 141 | if ($Services) { 142 | 143 | Write-Verbose "-Services switch was activated, pulling full service info."; 144 | $CIM_Services = $null; 145 | $CIM_Services = Get-CIMinstance -class Win32_Service -Filter "Caption LIKE '%'" -ComputerName $Computer -ErrorAction SilentlyContinue; 146 | # Odd filter explanation: http://itknowledgeexchange.techtarget.com/powershell/cim-session-oddity/ 147 | }; 148 | 149 | $CIM_Processes = $null; 150 | $CIM_Processes = Get-CIMinstance -class Win32_Process -Filter "Caption LIKE '%'" -ComputerName $Computer -ErrorAction SilentlyContinue; 151 | 152 | Write-Verbose "Cycling through each process." 153 | $Processes | ForEach-Object { 154 | 155 | $ProcessID = $null; 156 | $ProcessID = $_.Id; 157 | 158 | if ($Services -AND $CIM_Services) { 159 | 160 | Write-Verbose "Pulling service info on this process."; 161 | $ThisServices = $null; 162 | $ThisServices = $CIM_Services | Where-Object ProcessID -eq $ProcessID; 163 | }; 164 | 165 | if ($CIM_Processes) { 166 | 167 | Write-Verbose "Pulling commandline and owner information."; 168 | $CommandLine = $null; 169 | $CommandLine = $CIM_Processes | Where-Object ProcessID -eq $ProcessID | Select-Object -ExpandProperty CommandLine; 170 | 171 | if ($_.UserName -eq $null) { 172 | 173 | $ProcessInfo = $null; 174 | $ProcessInfo = $CIM_Processes | Where-Object ProcessID -eq $ProcessID | Invoke-CimMethod -MethodName GetOwner -ErrorAction SilentlyContinue | Select-Object Domain, User; 175 | 176 | if ($ProcessInfo) { 177 | $ProcessOwner = $null; 178 | $ProcessOwner = $ProcessInfo.Domain + "\" + $ProcessInfo.User; 179 | if ($ProcessOwner -eq "\") {$ProcessOwner = $null}; 180 | }; 181 | }; 182 | }; 183 | 184 | $output = $null; 185 | $output = [Process]::new(); 186 | 187 | $output.Computer = $Computer; 188 | $output.DateScanned = Get-Date -Format u; 189 | 190 | $output.Mode = $Mode; 191 | $output.BasePriority = $_.BasePriority; 192 | $output.CPU = $_.CPU; 193 | $output.CommandLine = $CommandLine; 194 | $output.Company = $_.Company; 195 | $output.Description = $_.Description; 196 | $output.EnableRaisingEvents = $_.EnableRaisingEvents; 197 | $output.FileVersion = $_.FileVersion; 198 | $output.Handle = $_.Handle; 199 | $output.HandleCount = $_.HandleCount; 200 | $output.Id = $_.Id; 201 | $output.MainModule = $_.MainModule; 202 | $output.MainModule = $output.MainModule.Replace('System.Diagnostics.ProcessModule (', '').Replace(')', ''); 203 | $output.MainWindowHandle = $_.MainWindowHandle; 204 | $output.MainWindowTitle = $_.MainWindowTitle; 205 | $output.ModuleCount = @($_.Modules).Count; 206 | $output.DisplayName = $_.Name; 207 | $output.Path = $_.Path; 208 | $output.PriorityBoostEnabled = $_.PriorityBoostEnabled; 209 | $output.PriorityClass = $_.PriorityClass; 210 | $output.PrivilegedProcessorTime = $_.PrivilegedProcessorTime; 211 | $output.ProcessName = $_.ProcessName; 212 | $output.ProcessorAffinity = $_.ProcessorAffinity; 213 | $output.Product = $_.Product; 214 | $output.ProductVersion = $_.ProductVersion; 215 | $output.Responding = $_.Responding; 216 | $output.SessionId = $_.SessionId; 217 | $output.StartTime = $_.StartTime; 218 | $output.Threads = @($_.Threads).Count; 219 | $output.TotalProcessorTime = $_.TotalProcessorTime; 220 | $output.UserName = if ($_.UserName) {$_.UserName} elseif ($ProcessOwner) {$ProcessOwner}; 221 | $output.Services = if ($ThisServices) {$ThisServices.PathName -Join "; "; }; 222 | $output.DLLs = if ($DLLs -AND $_.Modules) {$_.Modules -join "; "; }; 223 | $output.DLLs = $output.DLLs.Replace('System.Diagnostics.ProcessModule (', '').Replace(')', ''); 224 | 225 | return $output; 226 | }; 227 | } 228 | else { 229 | 230 | Write-Verbose ("{0}: System failed." -f $Computer); 231 | if ($Fails) { 232 | 233 | $total++; 234 | Add-Content -Path $Fails -Value ("$Computer"); 235 | } 236 | else { 237 | 238 | $output = $null; 239 | $output = [Process]::new(); 240 | 241 | $output.Computer = $Computer; 242 | $output.DateScanned = Get-Date -Format u; 243 | 244 | $total++; 245 | return $output; 246 | }; 247 | }; 248 | }; 249 | 250 | end { 251 | 252 | $elapsed = $stopwatch.Elapsed; 253 | 254 | Write-Verbose ("Total Systems: {0} `t Total time elapsed: {1}" -f $total, $elapsed); 255 | }; 256 | }; --------------------------------------------------------------------------------