├── Admin ├── .test.txt ├── 2016-09-10 22_13_47-RAT - Google Slides.png ├── 2016-09-10 22_15_27-RAT - Google Slides.png └── 2016-09-10 22_16_39-RAT - Google Slides.png ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md └── Invoke-FindPersistence.ps1 /Admin/.test.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Admin/2016-09-10 22_13_47-RAT - Google Slides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/killswitch-GUI/Persistence-Survivability/HEAD/Admin/2016-09-10 22_13_47-RAT - Google Slides.png -------------------------------------------------------------------------------- /Admin/2016-09-10 22_15_27-RAT - Google Slides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/killswitch-GUI/Persistence-Survivability/HEAD/Admin/2016-09-10 22_15_27-RAT - Google Slides.png -------------------------------------------------------------------------------- /Admin/2016-09-10 22_16_39-RAT - Google Slides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/killswitch-GUI/Persistence-Survivability/HEAD/Admin/2016-09-10 22_16_39-RAT - Google Slides.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | File: Invoke-FindPersistence.ps1 2 | Author: Alexander Rymdeko-Harvey(@Killswitch-GUI) 3 | License: BSD 3-Clause 4 | 5 | Copyright (c) 2016, Alexander Rymdeko-Harvey 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of nor the names of its contributors may be used to 17 | endorse or promote products derived from this software without specific 18 | prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | 32 | --------------------------------------------------------------------------- 33 | PowerView is provided under the 3-clause BSD license below. 34 | 35 | ************************************************************* 36 | 37 | Copyright (c) 2015, Will Schroeder 38 | All rights reserved. 39 | 40 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 41 | 42 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 43 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 44 | The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. 45 | 46 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 47 | 48 | --------------------------------------------------------------------------- 49 | Invoke-Ping 50 | 51 | MIT License 52 | 53 | Copyright (c) 2016 Warren Frame 54 | 55 | Permission is hereby granted, free of charge, to any person obtaining a copy 56 | of this software and associated documentation files (the "Software"), to deal 57 | in the Software without restriction, including without limitation the rights 58 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 59 | copies of the Software, and to permit persons to whom the Software is 60 | furnished to do so, subject to the following conditions: 61 | 62 | The above copyright notice and this permission notice shall be included in all 63 | copies or substantial portions of the Software. 64 | 65 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 66 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 67 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 68 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 69 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 70 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 71 | SOFTWARE. 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Persistence Survivability Rating 2 | This project uses the Duqu style persistence as a TTP and was presented at Bsides Augusta – RAT. This project is PowerShell based and can be used with credentials and without. For more info please read the .ps1 file. 3 | 4 | # Basic use: 5 | ``` 6 | Invoke-FindPersitence 7 | Invoke-FindPersitence -MaxHosts 100 -Top 5 8 | Invoke-FindPersitence -Domain tester.org -OperatingSystem *7* 9 | Invoke-FindPersitence -Domain tester.org -OperatingSystem *2008* -Top 3 -Jit 2 -Delay 5 -ADSPath "LDAP://OU=iis=servers=,DC=testlab,DC=Local" -Threads 10 10 | ``` 11 | ## Demo / Slides: 12 | - http://www.slideshare.net/AlexanderRymdekoHarv/rat-repurposing-adversarial-tradecraft 13 | - https://youtu.be/VDwxhkIK4TY 14 | 15 | ## How does it work: 16 | ![alt tag](https://github.com/killswitch-GUI/Persistence-Survivability/blob/master/Admin/2016-09-10%2022_13_47-RAT%20-%20Google%20Slides.png) 17 | ![alt tag](https://github.com/killswitch-GUI/Persistence-Survivability/blob/master/Admin/2016-09-10%2022_15_27-RAT%20-%20Google%20Slides.png) 18 | ![alt tag](https://github.com/killswitch-GUI/Persistence-Survivability/blob/master/Admin/2016-09-10%2022_16_39-RAT%20-%20Google%20Slides.png) 19 | 20 | ### Build Out Path 21 | Current value based supported remote queries: 22 | 23 | | Query | Weighted Value| implemented| 24 | | ------------- |:-------------:|:-----:| 25 | | WmiBootTime | 40% | Yes | 26 | | WmiInstallDate | 5% | Yes | 27 | | WmiOS | 5% | Yes | 28 | | WmiServer | 10% | Yes | 29 | | WmiRamSize | 5% | Yes | 30 | | WmiArch | 5% | Yes | 31 | | WmiDisk | 5% | Yes | 32 | | WmiLProcessorCount | 5% | Yes | 33 | | WmiProcessorCores | 5% | Yes | 34 | | WmiProcessorSpeed | 5% | Yes | 35 | | WmiProcessCount | 5% | Yes | 36 | | WmiSystemEnclosure | 10% | Yes | 37 | | WmiLoggedOnUsers | centered | No | 38 | | WmiCollectorService| centered | No | 39 | | WmiNICData | centered | No | 40 | | WmiAVQuery | centered | No | 41 | | WmiPowerSettings | centered | No | 42 | | WmiOSuite | centered | No | 43 | | WmiPointerDevice | centered | No | 44 | 45 | Current boolean based supported remote queries: 46 | 47 | | Query | Impact | implemented| 48 | | ------------- |:-------------:|:-----:| 49 | | WmiPortableOS | Implant location| Yes | 50 | | WmiVMChecks | Truth of data | Yes | 51 | | WmiLogging |Alerts in logging| No | 52 | 53 | ### Sample output: 54 | ``` 55 | 56 | PS C:\Users\Administrator\Desktop> Invoke-FindPersitence 57 | [*] Top Server locations based on Persistence Survivability rating: 58 | [*] Top Desktop locations based on Persistence Survivability rating: 59 | [*] Top VM locations based on Persistence Survivability rating: 60 | 61 | 62 | NetBIOSName : ALEX32-PC.tester.org 63 | IpAddress : 172.16.168.136 64 | LastBoot : 20160509061014.500000-420 65 | InstallDate : 20150707115729.000000-420 66 | OSArch : 64-bit 67 | ServerType : 1 68 | SystemEnclosure : 1 69 | RamSize : 2 70 | DiskSize : 38.6479606628418 71 | ProcessorSpeed : 2999 72 | ProcessorLogicalCores : 1 73 | ProcessorCores : 1 74 | ProcessCount : 38 75 | PortableOS : 76 | VMware : True 77 | LastBootV : 0.3 78 | InstallDateV : 0.4 79 | OSArchV : 0.3 80 | ServerTypeV : 0.33 81 | SystemEnclosureV : 0.1 82 | DiskSizeV : 0.3 83 | RamSizeV : 0.5 84 | ProcessorSpeedV : 1 85 | ProcessorLogicalCoreV : 0.3 86 | ProcessCountV : 1 87 | LastBootWV : 0.12 88 | InstallDateWV : 0.02 89 | OSArchWV : 0.015 90 | ServerTypeWV : 0.033 91 | SystemEnclosureWV : 0.01 92 | DiskSizeWV : 0.015 93 | RamSizeWV : 0.1 94 | ProcessorSpeedWV : 0.05 95 | ProcessorLogicalCoreWV : 0.015 96 | ProcessCountWV : 0.05 97 | PersistenceSurvivability : 0.378 98 | 99 | NetBIOSName : ALEX2-PC.tester.org 100 | IpAddress : 172.16.168.160 101 | LastBoot : 20160508162848.500000-420 102 | InstallDate : 20150707115729.000000-420 103 | OSArch : 64-bit 104 | ServerType : 1 105 | SystemEnclosure : 1 106 | RamSize : 2 107 | DiskSize : 48.5253257751465 108 | ProcessorSpeed : 2999 109 | ProcessorLogicalCores : 1 110 | ProcessorCores : 1 111 | ProcessCount : 32 112 | PortableOS : 113 | VMware : True 114 | LastBootV : 0.3 115 | InstallDateV : 0.4 116 | OSArchV : 0.3 117 | ServerTypeV : 0.33 118 | SystemEnclosureV : 0.1 119 | DiskSizeV : 0.3 120 | RamSizeV : 0.5 121 | ProcessorSpeedV : 1 122 | ProcessorLogicalCoreV : 0.3 123 | ProcessCountV : 1 124 | LastBootWV : 0.12 125 | InstallDateWV : 0.02 126 | OSArchWV : 0.015 127 | ServerTypeWV : 0.033 128 | SystemEnclosureWV : 0.01 129 | DiskSizeWV : 0.015 130 | RamSizeWV : 0.1 131 | ProcessorSpeedWV : 0.05 132 | ProcessorLogicalCoreWV : 0.015 133 | ProcessCountWV : 0.05 134 | PersistenceSurvivability : 0.378 135 | 136 | NetBIOSName : WIN-2PNK85BO0TD.tester.org 137 | IpAddress : {fe80::9a7:551a:2614:ae6c%12, 172.16.168.223} 138 | LastBoot : 20160227200724.489034-480 139 | InstallDate : 20150707115648.000000-420 140 | OSArch : 64-bit 141 | ServerType : 2 142 | SystemEnclosure : 1 143 | RamSize : 2 144 | DiskSize : 43.868766784668 145 | ProcessorSpeed : 2999 146 | ProcessorLogicalCores : 1 147 | ProcessorCores : 1 148 | ProcessCount : 73 149 | PortableOS : False 150 | VMware : True 151 | LastBootV : 0.85 152 | InstallDateV : 0.4 153 | OSArchV : 0.3 154 | ServerTypeV : 0.66 155 | SystemEnclosureV : 0.1 156 | DiskSizeV : 0.3 157 | RamSizeV : 0.5 158 | ProcessorSpeedV : 1 159 | ProcessorLogicalCoreV : 0.3 160 | ProcessCountV : 1 161 | LastBootWV : 0.34 162 | InstallDateWV : 0.02 163 | OSArchWV : 0.015 164 | ServerTypeWV : 0.066 165 | SystemEnclosureWV : 0.01 166 | DiskSizeWV : 0.015 167 | RamSizeWV : 0.1 168 | ProcessorSpeedWV : 0.05 169 | ProcessorLogicalCoreWV : 0.015 170 | ProcessCountWV : 0.05 171 | PersistenceSurvivability : 0.631 172 | 173 | [*] Overall Persistence Survivability stats: 174 | Total number of hosts: 3 175 | Total VMware hosts: 3 176 | Total Desktop hosts: 0 177 | Total Server hosts: 0 178 | Survivability mean: 46 % 179 | ``` 180 | # license 181 | File: Persistence-Survivability 182 | Author: Alexander Rymdeko-Harvey(@Killswitch-GUI) 183 | License: BSD 3-Clause 184 | 185 | Copyright (c) 2016, Alexander Rymdeko-Harvey 186 | All rights reserved. 187 | 188 | Redistribution and use in source and binary forms, with or without 189 | modification, are permitted provided that the following conditions are met: 190 | 191 | * Redistributions of source code must retain the above copyright notice, 192 | this list of conditions and the following disclaimer. 193 | * Redistributions in binary form must reproduce the above copyright 194 | notice, this list of conditions and the following disclaimer in the 195 | documentation and/or other materials provided with the distribution. 196 | * Neither the name of nor the names of its contributors may be used to 197 | endorse or promote products derived from this software without specific 198 | prior written permission. 199 | 200 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 201 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 202 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 203 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 204 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 205 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 206 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 207 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 208 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 209 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 210 | POSSIBILITY OF SUCH DAMAGE. 211 | -------------------------------------------------------------------------------- /Invoke-FindPersistence.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 2 2 | 3 | <# 4 | File: Invoke-FindPersistence.ps1 5 | Author: Alexander Rymdeko-Harvey(@Killswitch-GUI) 6 | License: BSD 3-Clause 7 | 8 | Copyright (c) 2016, Alexander Rymdeko-Harvey 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, 15 | this list of conditions and the following disclaimer. 16 | * Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | * Neither the name of nor the names of its contributors may be used to 20 | endorse or promote products derived from this software without specific 21 | prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 27 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 | POSSIBILITY OF SUCH DAMAGE. 34 | #> 35 | 36 | <# 37 | PowerSploit File: PowerView.ps1 38 | Functions Used: Get-NetComputer, Convert-LDAPProperty, Get-NetDomain 39 | Author: Will Schroeder (@harmj0y) 40 | License: BSD 3-Clause 41 | Required Dependencies: None 42 | Optional Dependencies: None 43 | #> 44 | 45 | <# 46 | Test Weighted values and their max 47 | coresponding values. All have the max 48 | values of 100 int. 49 | 50 | Keep in mind all values are relational to the 51 | highest and lowest values which is why we 52 | will caculate the Stnadard deviation. This 53 | will help us identify unique points in the 54 | network with ease. 55 | 56 | 1) WmiBootTime = %40 WA 57 | # in months: 58 | - .25 = 30 59 | - .5 = 40 60 | - 1 = 60 61 | - 2 = 75 62 | - 3 = 85 63 | - 4 = 90 64 | - 5 = 95 65 | - 6 = 100 66 | 2) WmiOS = %10 67 | 4) WmiServer = %10 68 | 3) WmiInstallDate = %5 69 | - Bellow 6 months = 20 70 | - Bellow 1 years = 40 71 | - Bellow 2 years = 80 72 | - Bellow 3 years = 100 73 | 5) WmiArch = %2 74 | - 32 bit = 50 75 | - 64 bit = 100 76 | 6) WmiSuite = %5 77 | 7) WmiDisk = %2 78 | 8) WmiLPorcCount = %5 79 | - 80 | 9) WmiPorcCores = %2 81 | - 82 | 10) WmiProcSpeed = %2 83 | - 1500 = 20 I3 84 | - 2000 = 40 I5 85 | - 2500 = 80 I5 86 | - 2950 = 100 I7 87 | 11) WmiPowerSettign= %5 88 | 12) WmiEnlosure = %10 89 | 13) WmiPointerDevice = %2 90 | 14) WmiLoggedOnUser = %5 91 | - 0 = 20 92 | - 1 = 30 93 | - 2 = 50 94 | - 3 = 70 95 | - 4 = 90 96 | - 5 = 100 97 | 15) WmiPorcessCount = %5 98 | Less than: 99 | - 7 = 20 100 | - 9 = 40 101 | - 10 = 50 102 | - 12 = 65 103 | - 15 = 80 104 | - 18 = 100 105 | 16) WmiPatchLevel = 2% 106 | 17) WmiSystemEnclosure = %10 107 | 18) WmiCollectorService = %5 108 | 19) WmiRamSize = %5 109 | in GB: 110 | - 1 = 20 111 | - 2 = 30 112 | - 113 | 20) WmiNICData = %5 114 | 21) WmiAVQuery %2 115 | 116 | Bool Values for sorting 117 | 23) WmiPortabelOS 118 | 24) WmiVMChecks 119 | 25) WmiLogging 120 | #> 121 | 122 | ###################### 123 | # PS Wmi Object Calls# 124 | ###################### 125 | function Get-WmiOS{ 126 | <# 127 | .SYNOPSIS 128 | This function will query the target for its OS wmi object and return this object. 129 | 130 | .PARAMETER Credential 131 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 132 | 133 | .PARAMETER UserName 134 | DOMAIN\UserName to pass to CLI. 135 | 136 | .PARAMETER Password 137 | String Password to pass to CLI. 138 | 139 | .PARAMETER Targets 140 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 141 | 142 | .EXAMPLE 143 | > Get-WmiBootTime 144 | NONE 145 | 146 | .LINK 147 | NONE 148 | #> 149 | [CmdletBinding()] 150 | param( 151 | [Parameter(ValueFromPipeline=$True)] 152 | $Credential, 153 | 154 | [Parameter(ValueFromPipeline=$True)] 155 | [string]$User, 156 | 157 | [Parameter(ValueFromPipeline=$True)] 158 | [string]$Password, 159 | 160 | [Parameter(ValueFromPipeline=$True)] 161 | [string]$HostName 162 | ) 163 | 164 | Process 165 | { 166 | if( -Not $HostName) 167 | { 168 | $HostName = $env:computername 169 | } 170 | 171 | if ($Credential) 172 | { 173 | # execute with cred object 174 | try 175 | { 176 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 177 | return $Wmi 178 | } 179 | catch 180 | { 181 | Write-Warning "[!] Error opening Wmi OS on $HostName." 182 | } 183 | } 184 | elseif ($User -and $Password) 185 | { 186 | # execute with built credential object 187 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 188 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 189 | try 190 | { 191 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 192 | return $Wmi 193 | } 194 | catch 195 | { 196 | Write-Warning "[!] Error opening Wmi OS on $HostName." 197 | } 198 | } 199 | else 200 | { 201 | try 202 | { 203 | # execute in current user context 204 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName 205 | return $Wmi 206 | } 207 | catch 208 | { 209 | Write-Warning "[!] Error opening Wmi OS on $HostName." 210 | } 211 | 212 | } 213 | } 214 | } 215 | #################### 216 | # Weighted Average # 217 | #################### 218 | 219 | function Get-WmiBootTime{ 220 | <# 221 | .SYNOPSIS 222 | This function will query the target for last boot time in epoch time. 223 | 224 | .DESCRIPTION 225 | This function will query the target for last boot time in epoch time. 226 | 227 | .PARAMETER Credential 228 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 229 | 230 | .PARAMETER UserName 231 | DOMAIN\UserName to pass to CLI. 232 | 233 | .PARAMETER Password 234 | String Password to pass to CLI. 235 | 236 | .PARAMETER WmiOS 237 | Pass the OS Wmi on the CLI to enhance speed / remote calls. 238 | 239 | .PARAMETER Targets 240 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 241 | 242 | .EXAMPLE 243 | > Get-WmiBootTime 244 | NONE 245 | 246 | .LINK 247 | NONE 248 | #> 249 | [CmdletBinding()] 250 | param( 251 | [Parameter(ValueFromPipeline=$True)] 252 | $Credential, 253 | 254 | [Parameter(ValueFromPipeline=$True)] 255 | [string]$User, 256 | 257 | [Parameter(ValueFromPipeline=$True)] 258 | [string]$Password, 259 | 260 | [Parameter(ValueFromPipeline=$True)] 261 | [string]$HostName, 262 | 263 | [Parameter(ValueFromPipeline=$True)] 264 | $WmiOS 265 | ) 266 | 267 | Process 268 | { 269 | if( -Not $HostName) 270 | { 271 | $HostName = $env:computername 272 | } 273 | 274 | if ($Credential) 275 | { 276 | # execute with cred object 277 | try 278 | { 279 | if ($WmiOS){ 280 | $LastBoot = $WmiOS.LastBootUpTime 281 | } 282 | else{ 283 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 284 | $LastBoot = $Wmi.LastBootUpTime 285 | } 286 | return $LastBoot 287 | } 288 | catch 289 | { 290 | Write-Warning "[!] Error opening lastboot time one $HostName." 291 | } 292 | } 293 | elseif ($User -and $Password) 294 | { 295 | # execute with built credential object 296 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 297 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 298 | try 299 | { 300 | if ($WmiOS){ 301 | $LastBoot = $WmiOS.LastBootUpTime 302 | } 303 | else{ 304 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 305 | $LastBoot = $Wmi.LastBootUpTime 306 | } 307 | return $LastBoot 308 | } 309 | catch 310 | { 311 | Write-Warning "[!] Error opening lastboot time one $HostName." 312 | } 313 | } 314 | else 315 | { 316 | try 317 | { 318 | # execute in current user context 319 | if ($WmiOS){ 320 | $LastBoot = $WmiOS.LastBootUpTime 321 | } 322 | else{ 323 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName 324 | $LastBoot = $Wmi.LastBootUpTime 325 | } 326 | return $LastBoot 327 | } 328 | catch 329 | { 330 | Write-Warning "[!] Error opening lastboot time one $HostName." 331 | } 332 | 333 | } 334 | } 335 | } 336 | function Get-WmiInstallDate{ 337 | <# 338 | .SYNOPSIS 339 | This function will query the target for install date of OS. 340 | 341 | .DESCRIPTION 342 | Date object was installed. This property does not require a value to indicate that the object is installed. 343 | 344 | .PARAMETER Credential 345 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 346 | 347 | .PARAMETER WmiOS 348 | Pass the OS Wmi on the CLI to enhance speed / remote calls. 349 | 350 | .PARAMETER Targets 351 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 352 | 353 | .EXAMPLE 354 | > Get-WmiBootTime 355 | NONE 356 | 357 | .LINK 358 | NONE 359 | #> 360 | [CmdletBinding()] 361 | param( 362 | [Parameter(ValueFromPipeline=$True)] 363 | $Credential, 364 | 365 | [Parameter(ValueFromPipeline=$True)] 366 | [string]$User, 367 | 368 | [Parameter(ValueFromPipeline=$True)] 369 | [string]$Password, 370 | 371 | [Parameter(ValueFromPipeline=$True)] 372 | [string]$HostName, 373 | 374 | [Parameter(ValueFromPipeline=$True)] 375 | $WmiOS 376 | ) 377 | 378 | Process 379 | { 380 | if( -Not $HostName) 381 | { 382 | $HostName = $env:computername 383 | } 384 | 385 | if ($Credential) 386 | { 387 | # execute with cred object 388 | try 389 | { 390 | if ($WmiOS){ 391 | $InstallDate = $WmiOS.InstallDate 392 | } 393 | else{ 394 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 395 | $InstallDate = $Wmi.InstallDate 396 | } 397 | return $InstallDate 398 | } 399 | catch 400 | { 401 | Write-Warning "[!] Error opening lastboot time one $HostName." 402 | } 403 | } 404 | elseif ($User -and $Password) 405 | { 406 | # execute with built credential object 407 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 408 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 409 | try 410 | { 411 | if ($WmiOS){ 412 | $InstallDate = $WmiOS.InstallDate 413 | } 414 | else{ 415 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 416 | $InstallDate = $Wmi.InstallDate 417 | } 418 | return $InstallDate 419 | } 420 | catch 421 | { 422 | Write-Warning "[!] Error opening lastboot time one $HostName." 423 | } 424 | } 425 | else 426 | { 427 | try 428 | { 429 | # execute in current user context 430 | if ($WmiOS){ 431 | $InstallDate = $WmiOS.InstallDate 432 | } 433 | else{ 434 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName 435 | $InstallDate = $Wmi.InstallDate 436 | } 437 | return $InstallDate 438 | } 439 | catch 440 | { 441 | Write-Warning "[!] Error opening lastboot time one $HostName." 442 | } 443 | 444 | } 445 | } 446 | } 447 | function Get-WmiOS{ 448 | <# 449 | .SYNOPSIS 450 | This function will query the target for the current OS level. 451 | 452 | .DESCRIPTION 453 | This function will query the target for the current OS level. This will use the current verison a build number to indicate the highest 454 | windows version. This can help us determine the newest verison of windows we want. We can also apply filters to this value. 455 | 456 | .PARAMETER Credential 457 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 458 | 459 | .PARAMETER UserName 460 | DOMAIN\UserName to pass to CLI. 461 | 462 | .PARAMETER Password 463 | String Password to pass to CLI. 464 | 465 | .PARAMETER Targets 466 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 467 | 468 | .EXAMPLE 469 | > Get-WmiOS 470 | NONE 471 | 472 | .LINK 473 | NONE 474 | #> 475 | [CmdletBinding()] 476 | param( 477 | [Parameter(ValueFromPipeline=$True)] 478 | $Credential, 479 | 480 | [Parameter(ValueFromPipeline=$True)] 481 | [string]$User, 482 | 483 | [Parameter(ValueFromPipeline=$True)] 484 | [string]$Password, 485 | 486 | [Parameter(ValueFromPipeline=$True)] 487 | [string]$HostName 488 | ) 489 | } 490 | function Get-WmiServer{ 491 | <# 492 | .SYNOPSIS 493 | This function will query the product type of the OS at a basic level. 494 | 495 | .DESCRIPTION 496 | Additional system information on the product type. 497 | 498 | .PARAMETER Credential 499 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 500 | 501 | .PARAMETER UserName 502 | DOMAIN\UserName to pass to CLI. 503 | 504 | .PARAMETER Password 505 | String Password to pass to CLI. 506 | 507 | .PARAMETER WmiOS 508 | Pass the OS Wmi on the CLI to enhance speed / remote calls. 509 | 510 | .PARAMETER Targets 511 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 512 | 513 | .EXAMPLE 514 | > Get-WmiBootTime 515 | NONE 516 | 517 | .LINK 518 | NONE 519 | #> 520 | [CmdletBinding()] 521 | param( 522 | [Parameter(ValueFromPipeline=$True)] 523 | $Credential, 524 | 525 | [Parameter(ValueFromPipeline=$True)] 526 | [string]$User, 527 | 528 | [Parameter(ValueFromPipeline=$True)] 529 | [string]$Password, 530 | 531 | [Parameter(ValueFromPipeline=$True)] 532 | [string]$HostName, 533 | 534 | [Parameter(ValueFromPipeline=$True)] 535 | $WmiOS 536 | ) 537 | 538 | Process 539 | { 540 | if( -Not $HostName) 541 | { 542 | $HostName = $env:computername 543 | } 544 | 545 | if ($Credential) 546 | { 547 | # execute with cred object 548 | try 549 | { 550 | if ($WmiOS){ 551 | $ProductType = $WmiOS.ProductType 552 | } 553 | else{ 554 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 555 | $ProductType = $Wmi.ProductType 556 | } 557 | return $ProductType 558 | } 559 | catch 560 | { 561 | Write-Warning "[!] Error opening lastboot time one $HostName." 562 | } 563 | } 564 | elseif ($User -and $Password) 565 | { 566 | # Server Types 567 | # Work Station (1) 568 | # Domain Controller (2) 569 | # Server (3) 570 | # execute with built credential object 571 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 572 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 573 | try 574 | { 575 | if ($WmiOS){ 576 | $ProductType = $WmiOS.ProductType 577 | } 578 | else{ 579 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 580 | $ProductType = $Wmi.ProductType 581 | } 582 | return $ProductType 583 | } 584 | catch 585 | { 586 | Write-Warning "[!] Error opening lastboot time one $HostName." 587 | } 588 | } 589 | else 590 | { 591 | try 592 | { 593 | # execute in current user context 594 | if ($WmiOS){ 595 | $ProductType = $WmiOS.ProductType 596 | } 597 | else{ 598 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName 599 | $ProductType = $Wmi.ProductType 600 | } 601 | return $ProductType 602 | } 603 | catch 604 | { 605 | Write-Warning "[!] Error opening lastboot time one $HostName." 606 | } 607 | 608 | } 609 | } 610 | } 611 | function Get-WmiRamSize{ 612 | <# 613 | .SYNOPSIS 614 | Total capacity of the physical memory in bytes. 615 | 616 | .DESCRIPTION 617 | This value comes from the Memory Device structure in the SMBIOS version information. 618 | For SMBIOS versions 2.1 thru 2.6 the value comes from the Size member. 619 | For SMBIOS version 2.7+ the value comes from the Extended Size member. 620 | 621 | .PARAMETER UserName 622 | DOMAIN\UserName to pass to CLI. 623 | 624 | .PARAMETER Password 625 | String Password to pass to CLI. 626 | 627 | .PARAMETER Credential 628 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 629 | 630 | .PARAMETER HostName 631 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 632 | 633 | .EXAMPLE 634 | > Get-WmiRamSize 635 | NONE 636 | 637 | .LINK 638 | https://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx 639 | #> 640 | [CmdletBinding()] 641 | param( 642 | [Parameter(ValueFromPipeline=$True)] 643 | $Credential, 644 | 645 | [Parameter(ValueFromPipeline=$True)] 646 | [string]$User, 647 | 648 | [Parameter(ValueFromPipeline=$True)] 649 | [string]$Password, 650 | 651 | [Parameter(ValueFromPipeline=$True)] 652 | [string]$HostName 653 | ) 654 | 655 | Process 656 | { 657 | if( -Not $HostName) 658 | { 659 | $HostName = $env:computername 660 | } 661 | 662 | if ($Credential) 663 | { 664 | # execute with cred object 665 | try 666 | { 667 | $Capacity = 0 668 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_PhysicalMemory -computername $HostName -credential $Credential | %{$Capacity = $_.Capacity / 1GB + $Capacity} 669 | return $Capacity 670 | } 671 | catch 672 | { 673 | Write-Warning "[!] Error opening lastboot time one $HostName." 674 | } 675 | } 676 | elseif ($User -and $Password) 677 | { 678 | # execute with built credential object 679 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 680 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 681 | try 682 | { 683 | $Capacity = 0 684 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_PhysicalMemory -computername $HostName -credential $Credential | %{$Capacity = $_.Capacity / 1GB + $Capacity} 685 | return $Capacity 686 | } 687 | catch 688 | { 689 | Write-Warning "[!] Error opening lastboot time one $HostName." 690 | } 691 | } 692 | else 693 | { 694 | try 695 | { 696 | $Capacity = 0 697 | # execute in current user context 698 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_PhysicalMemory -computername $HostName | %{$Capacity = $_.Capacity / 1GB + $Capacity} 699 | return $Capacity 700 | } 701 | catch 702 | { 703 | Write-Warning "[!] Error opening Ram Size time one $HostName." 704 | } 705 | 706 | } 707 | } 708 | } 709 | function Get-WmiArch{ 710 | <# 711 | .SYNOPSIS 712 | This function will query the target for its OS arch. 713 | 714 | .DESCRIPTION 715 | Architecture of the operating system, as opposed to the processor. This property can be localized. 716 | 717 | .PARAMETER UserName 718 | DOMAIN\UserName to pass to CLI. 719 | 720 | .PARAMETER Password 721 | String Password to pass to CLI. 722 | 723 | .PARAMETER WmiOS 724 | Pass the OS Wmi obj on the CLI to enhance speed / remote calls. 725 | 726 | .PARAMETER Credential 727 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 728 | 729 | .PARAMETER HostName 730 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 731 | 732 | .EXAMPLE 733 | > Get-WmiArch 734 | NONE 735 | 736 | .LINK 737 | NONE 738 | #> 739 | [CmdletBinding()] 740 | param( 741 | [Parameter(ValueFromPipeline=$True)] 742 | $Credential, 743 | 744 | [Parameter(ValueFromPipeline=$True)] 745 | [string]$User, 746 | 747 | [Parameter(ValueFromPipeline=$True)] 748 | [string]$Password, 749 | 750 | [Parameter(ValueFromPipeline=$True)] 751 | [string]$HostName, 752 | 753 | [Parameter(ValueFromPipeline=$True)] 754 | $WmiOS 755 | 756 | ) 757 | 758 | Process 759 | { 760 | if( -Not $HostName) 761 | { 762 | $HostName = $env:computername 763 | } 764 | 765 | if ($Credential) 766 | { 767 | # execute with cred object 768 | try 769 | { 770 | if ($WmiOS){ 771 | $OSArchitecture = $WmiOS.OSArchitecture 772 | } 773 | else{ 774 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 775 | $OSArchitecture = $Wmi.OSArchitecture 776 | } 777 | return $OSArchitecture 778 | } 779 | catch 780 | { 781 | Write-Warning "[!] Error opening lastboot time one $HostName." 782 | } 783 | } 784 | elseif ($User -and $Password) 785 | { 786 | # execute with built credential object 787 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 788 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 789 | try 790 | { 791 | if ($WmiOS){ 792 | $OSArchitecture = $WmiOS.OSArchitecture 793 | } 794 | else{ 795 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 796 | $OSArchitecture = $Wmi.OSArchitecture 797 | } 798 | return $OSArchitecture 799 | } 800 | catch 801 | { 802 | Write-Warning "[!] Error opening lastboot time one $HostName." 803 | } 804 | } 805 | else 806 | { 807 | try 808 | { 809 | # execute in current user context 810 | if ($WmiOS){ 811 | $OSArchitecture = $WmiOS.OSArchitecture 812 | } 813 | else{ 814 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName 815 | $OSArchitecture = $Wmi.OSArchitecture 816 | } 817 | return $OSArchitecture 818 | } 819 | catch 820 | { 821 | Write-Warning "[!] Error opening lastboot time one $HostName." 822 | } 823 | 824 | } 825 | } 826 | } 827 | function Get-WMiDisk{ 828 | <# 829 | .SYNOPSIS 830 | This function will query the target for its free space on the disk count. 831 | 832 | .DESCRIPTION 833 | Space, in bytes, available on the logical disk. returns the space size in GB. 834 | 835 | .PARAMETER UserName 836 | DOMAIN\UserName to pass to CLI. 837 | 838 | .PARAMETER Password 839 | String Password to pass to CLI. 840 | 841 | .PARAMETER Credential 842 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 843 | 844 | .PARAMETER HostName 845 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 846 | 847 | .EXAMPLE 848 | > Get-WMiDisk 849 | NONE 850 | 851 | .LINK 852 | https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx 853 | #> 854 | [CmdletBinding()] 855 | param( 856 | [Parameter(ValueFromPipeline=$True)] 857 | $Credential, 858 | 859 | [Parameter(ValueFromPipeline=$True)] 860 | [string]$User, 861 | 862 | [Parameter(ValueFromPipeline=$True)] 863 | [string]$Password, 864 | 865 | [Parameter(ValueFromPipeline=$True)] 866 | [string]$HostName 867 | ) 868 | Process 869 | { 870 | if( -Not $HostName) 871 | { 872 | $HostName = $env:computername 873 | } 874 | 875 | if ($Credential) 876 | { 877 | # execute with cred object 878 | try 879 | { 880 | $TotalSpace = 0 881 | Get-WmiObject -Namespace "root\cimv2" -Class Win32_LogicalDisk -computername $HostName -credential $Credential | %{$TotalSpace = $_.freespace / 1GB + $TotalSpace} 882 | return $TotalSpace 883 | } 884 | catch 885 | { 886 | Write-Warning "[!] Error opening lastboot time one $HostName." 887 | } 888 | } 889 | elseif ($User -and $Password) 890 | { 891 | # execute with built credential object 892 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 893 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 894 | try 895 | { 896 | $TotalSpace = 0 897 | Get-WmiObject -Namespace "root\cimv2" -Class Win32_LogicalDisk -computername $HostName -credential $Credential | %{$TotalSpace = $_.freespace / 1GB + $TotalSpace} 898 | return $TotalSpace 899 | } 900 | catch 901 | { 902 | Write-Warning "[!] Error opening lastboot time one $HostName." 903 | } 904 | } 905 | else 906 | { 907 | try 908 | { 909 | # execute in current user context 910 | $TotalSpace = 0 911 | Get-WmiObject -Namespace "root\cimv2" -Class Win32_LogicalDisk -computername $HostName | %{$TotalSpace = $_.freespace / 1GB + $TotalSpace} 912 | return $TotalSpace 913 | } 914 | catch 915 | { 916 | Write-Warning "[!] Error opening Disk Size on $HostName." 917 | } 918 | 919 | } 920 | } 921 | } 922 | function Get-WmiLProcessorCount{ 923 | <# 924 | .SYNOPSIS 925 | This function will query the target for its Number Of Logical Processors count. 926 | 927 | .DESCRIPTION 928 | Number of logical processors for the current instance of the processor. 929 | For processors capable of hyperthreading, this value includes only the processors which have hyperthreading enabled. 930 | 931 | .PARAMETER UserName 932 | DOMAIN\UserName to pass to CLI. 933 | 934 | .PARAMETER Password 935 | String Password to pass to CLI. 936 | 937 | .PARAMETER Credential 938 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 939 | 940 | .PARAMETER HostName 941 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 942 | 943 | .EXAMPLE 944 | > Get-WmiLProcessorCount 945 | NONE 946 | 947 | .LINK 948 | https://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx 949 | #> 950 | [CmdletBinding()] 951 | param( 952 | [Parameter(ValueFromPipeline=$True)] 953 | $Credential, 954 | 955 | [Parameter(ValueFromPipeline=$True)] 956 | [string]$User, 957 | 958 | [Parameter(ValueFromPipeline=$True)] 959 | [string]$Password, 960 | 961 | [Parameter(ValueFromPipeline=$True)] 962 | [string]$HostName 963 | ) 964 | 965 | Process 966 | { 967 | if( -Not $HostName) 968 | { 969 | $HostName = $env:computername 970 | } 971 | 972 | if ($Credential) 973 | { 974 | # execute with cred object 975 | try 976 | { 977 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_Processor -computername $HostName -credential $Credential 978 | $NumberOfLogicalProcessors = $Wmi.NumberOfLogicalProcessors 979 | return $NumberOfLogicalProcessors 980 | } 981 | catch 982 | { 983 | Write-Warning "[!] Error opening lastboot time one $HostName." 984 | } 985 | } 986 | elseif ($User -and $Password) 987 | { 988 | # execute with built credential object 989 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 990 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 991 | try 992 | { 993 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_Processor -computername $HostName -credential $Credential 994 | $NumberOfLogicalProcessors = $Wmi.NumberOfLogicalProcessors 995 | return $NumberOfLogicalProcessors 996 | } 997 | catch 998 | { 999 | Write-Warning "[!] Error opening lastboot time one $HostName." 1000 | } 1001 | } 1002 | else 1003 | { 1004 | try 1005 | { 1006 | # execute in current user context 1007 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_Processor -computername $HostName 1008 | $NumberOfLogicalProcessors = $Wmi.NumberOfLogicalProcessors 1009 | return $NumberOfLogicalProcessors 1010 | } 1011 | catch 1012 | { 1013 | Write-Warning "[!] Error opening lastboot time one $HostName." 1014 | } 1015 | 1016 | } 1017 | } 1018 | } 1019 | function Get-WmiProcessorCores{ 1020 | <# 1021 | .SYNOPSIS 1022 | This function will query the target for its Number Of Processors Cores. 1023 | 1024 | .DESCRIPTION 1025 | Number of cores for the current instance of the processor. 1026 | A core is a physical processor on the integrated circuit. 1027 | For example, in a dual-core processor this property has a value of 2. 1028 | 1029 | .PARAMETER UserName 1030 | DOMAIN\UserName to pass to CLI. 1031 | 1032 | .PARAMETER Password 1033 | String Password to pass to CLI. 1034 | 1035 | .PARAMETER Credential 1036 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 1037 | 1038 | .PARAMETER HostName 1039 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 1040 | 1041 | .EXAMPLE 1042 | > Get-WmiLProcessorCount 1043 | NONE 1044 | 1045 | .LINK 1046 | https://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx 1047 | #> 1048 | [CmdletBinding()] 1049 | param( 1050 | [Parameter(ValueFromPipeline=$True)] 1051 | $Credential, 1052 | 1053 | [Parameter(ValueFromPipeline=$True)] 1054 | [string]$User, 1055 | 1056 | [Parameter(ValueFromPipeline=$True)] 1057 | [string]$Password, 1058 | 1059 | [Parameter(ValueFromPipeline=$True)] 1060 | [string]$HostName 1061 | ) 1062 | 1063 | Process 1064 | { 1065 | if( -Not $HostName) 1066 | { 1067 | $HostName = $env:computername 1068 | } 1069 | 1070 | if ($Credential) 1071 | { 1072 | # execute with cred object 1073 | try 1074 | { 1075 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_Processor -computername $HostName -credential $Credential 1076 | $NumberOfCores = $Wmi.NumberOfCores 1077 | return $NumberOfCores 1078 | } 1079 | catch 1080 | { 1081 | Write-Warning "[!] Error opening lastboot time one $HostName." 1082 | } 1083 | } 1084 | elseif ($User -and $Password) 1085 | { 1086 | # execute with built credential object 1087 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 1088 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 1089 | try 1090 | { 1091 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_Processor -computername $HostName -credential $Credential 1092 | $NumberOfCores = $Wmi.NumberOfCores 1093 | return $NumberOfCores 1094 | } 1095 | catch 1096 | { 1097 | Write-Warning "[!] Error opening lastboot time one $HostName." 1098 | } 1099 | } 1100 | else 1101 | { 1102 | try 1103 | { 1104 | # execute in current user context 1105 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_Processor -computername $HostName 1106 | $NumberOfCores = $Wmi.NumberOfCores 1107 | return $NumberOfCores 1108 | } 1109 | catch 1110 | { 1111 | Write-Warning "[!] Error opening lastboot time one $HostName." 1112 | } 1113 | 1114 | } 1115 | } 1116 | } 1117 | function Get-WmiProcessorSpeed{ 1118 | <# 1119 | .SYNOPSIS 1120 | This function will query the target for Maximum speed of the processor, in MHz. 1121 | 1122 | .DESCRIPTION 1123 | This value comes from the Max Speed member of the Processor 1124 | Information structure in the SMBIOS information. 1125 | 1126 | .PARAMETER UserName 1127 | DOMAIN\UserName to pass to CLI. 1128 | 1129 | .PARAMETER Password 1130 | String Password to pass to CLI. 1131 | 1132 | .PARAMETER Credential 1133 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 1134 | 1135 | .PARAMETER HostName 1136 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 1137 | 1138 | .EXAMPLE 1139 | > Get-WmiLProcessorCount 1140 | NONE 1141 | 1142 | .LINK 1143 | https://msdn.microsoft.com/en-us/library/aa394373(v=vs.85).aspx 1144 | #> 1145 | [CmdletBinding()] 1146 | param( 1147 | [Parameter(ValueFromPipeline=$True)] 1148 | $Credential, 1149 | 1150 | [Parameter(ValueFromPipeline=$True)] 1151 | [string]$User, 1152 | 1153 | [Parameter(ValueFromPipeline=$True)] 1154 | [string]$Password, 1155 | 1156 | [Parameter(ValueFromPipeline=$True)] 1157 | [string]$HostName 1158 | ) 1159 | 1160 | Process 1161 | { 1162 | if( -Not $HostName) 1163 | { 1164 | $HostName = $env:computername 1165 | } 1166 | 1167 | if ($Credential) 1168 | { 1169 | # execute with cred object 1170 | try 1171 | { 1172 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_Processor -computername $HostName -credential $Credential 1173 | $MaxClockSpeed = $Wmi.MaxClockSpeed 1174 | return $MaxClockSpeed 1175 | } 1176 | catch 1177 | { 1178 | Write-Warning "[!] Error opening lastboot time one $HostName." 1179 | } 1180 | } 1181 | elseif ($User -and $Password) 1182 | { 1183 | # execute with built credential object 1184 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 1185 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 1186 | try 1187 | { 1188 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_Processor -computername $HostName -credential $Credential 1189 | $MaxClockSpeed = $Wmi.MaxClockSpeed 1190 | return $MaxClockSpeed 1191 | } 1192 | catch 1193 | { 1194 | Write-Warning "[!] Error opening lastboot time one $HostName." 1195 | } 1196 | } 1197 | else 1198 | { 1199 | try 1200 | { 1201 | # execute in current user context 1202 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_Processor -computername $HostName 1203 | $MaxClockSpeed = $Wmi.MaxClockSpeed 1204 | return $MaxClockSpeed 1205 | } 1206 | catch 1207 | { 1208 | Write-Warning "[!] Error opening lastboot time one $HostName." 1209 | } 1210 | 1211 | } 1212 | } 1213 | } 1214 | function Get-WmiProcessCount{ 1215 | <# 1216 | .SYNOPSIS 1217 | This function will query the target for its process count. 1218 | 1219 | .PARAMETER UserName 1220 | DOMAIN\UserName to pass to CLI. 1221 | 1222 | .PARAMETER Password 1223 | String Password to pass to CLI. 1224 | 1225 | .PARAMETER Credential 1226 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 1227 | 1228 | .PARAMETER HostName 1229 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 1230 | 1231 | .EXAMPLE 1232 | > Get-WMiDisk 1233 | NONE 1234 | 1235 | .LINK 1236 | https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx 1237 | #> 1238 | [CmdletBinding()] 1239 | param( 1240 | [Parameter(ValueFromPipeline=$True)] 1241 | $Credential, 1242 | 1243 | [Parameter(ValueFromPipeline=$True)] 1244 | [string]$User, 1245 | 1246 | [Parameter(ValueFromPipeline=$True)] 1247 | [string]$Password, 1248 | 1249 | [Parameter(ValueFromPipeline=$True)] 1250 | [string]$HostName 1251 | ) 1252 | Process 1253 | { 1254 | if( -Not $HostName) 1255 | { 1256 | $HostName = $env:computername 1257 | } 1258 | 1259 | if ($Credential) 1260 | { 1261 | # execute with cred object 1262 | try 1263 | { 1264 | $TotalCount = 0 1265 | Get-WmiObject -Namespace "root\cimv2" -Class Win32_Process -computername $HostName -credential $Credential | %{$TotalCount = 1 + $TotalCount} 1266 | return $TotalCount 1267 | } 1268 | catch 1269 | { 1270 | Write-Warning "[!] Error opening lastboot time one $HostName." 1271 | } 1272 | } 1273 | elseif ($User -and $Password) 1274 | { 1275 | # execute with built credential object 1276 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 1277 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 1278 | try 1279 | { 1280 | $TotalCount = 0 1281 | Get-WmiObject -Namespace "root\cimv2" -Class Win32_Process -computername $HostName -credential $Credential | %{$TotalCount = 1 + $TotalCount} 1282 | return $TotalCount 1283 | } 1284 | catch 1285 | { 1286 | Write-Warning "[!] Error opening lastboot time one $HostName." 1287 | } 1288 | } 1289 | else 1290 | { 1291 | try 1292 | { 1293 | # execute in current user context 1294 | $TotalCount = 0 1295 | Get-WmiObject -Namespace "root\cimv2" -Class Win32_Process -computername $HostName | %{$TotalCount = 1 + $TotalCount} 1296 | return $TotalCount 1297 | } 1298 | catch 1299 | { 1300 | Write-Warning "[!] Error opening Disk Size on $HostName." 1301 | } 1302 | 1303 | } 1304 | } 1305 | } 1306 | function Get-WmiSystemEnclosure{ 1307 | <# 1308 | .SYNOPSIS 1309 | This function will query the target for its $ChassisTypes and return an array. 1310 | 1311 | .PARAMETER UserName 1312 | DOMAIN\UserName to pass to CLI. 1313 | 1314 | .PARAMETER Password 1315 | String Password to pass to CLI. 1316 | 1317 | .PARAMETER Credential 1318 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 1319 | 1320 | .PARAMETER HostName 1321 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 1322 | 1323 | .EXAMPLE 1324 | > Get-WMiDisk 1325 | NONE 1326 | 1327 | .LINK 1328 | https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx 1329 | #> 1330 | [CmdletBinding()] 1331 | param( 1332 | [Parameter(ValueFromPipeline=$True)] 1333 | $Credential, 1334 | 1335 | [Parameter(ValueFromPipeline=$True)] 1336 | [string]$User, 1337 | 1338 | [Parameter(ValueFromPipeline=$True)] 1339 | [string]$Password, 1340 | 1341 | [Parameter(ValueFromPipeline=$True)] 1342 | [string]$HostName 1343 | ) 1344 | Process 1345 | { 1346 | if( -Not $HostName) 1347 | { 1348 | $HostName = $env:computername 1349 | } 1350 | 1351 | if ($Credential) 1352 | { 1353 | # execute with cred object 1354 | try 1355 | { 1356 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_SystemEnclosure -computername $HostName -credential $Credential 1357 | $ChassisTypes = $Wmi.ChassisTypes 1358 | return $ChassisTypes 1359 | } 1360 | catch 1361 | { 1362 | Write-Warning "[!] Error opening lastboot time one $HostName." 1363 | } 1364 | } 1365 | elseif ($User -and $Password) 1366 | { 1367 | # execute with built credential object 1368 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 1369 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 1370 | try 1371 | { 1372 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_SystemEnclosure -computername $HostName -credential $Credential 1373 | $ChassisTypes = $Wmi.ChassisTypes 1374 | return $ChassisTypes 1375 | } 1376 | catch 1377 | { 1378 | Write-Warning "[!] Error opening lastboot time one $HostName." 1379 | } 1380 | } 1381 | else 1382 | { 1383 | try 1384 | { 1385 | # execute in current user context 1386 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_SystemEnclosure -computername $HostName 1387 | $ChassisTypes = $Wmi.ChassisTypes 1388 | return $ChassisTypes 1389 | } 1390 | catch 1391 | { 1392 | Write-Warning "[!] Error opening Disk Size on $HostName." 1393 | } 1394 | 1395 | } 1396 | } 1397 | } 1398 | 1399 | #function Get-WmiLoggedOnUsers{} 1400 | #function Get-WmiCollectorService{} 1401 | #function Get-WmiNICData{} 1402 | #function Get-WmiAVQuery{} 1403 | #function Get-WmiPowerSettings{} 1404 | #function Get-WmiOSuite{} 1405 | #function Get-WmiPointerDevice{} 1406 | 1407 | #################### 1408 | # Boolean Values # 1409 | #################### 1410 | function Get-WmiPortableOS{ 1411 | <# 1412 | .SYNOPSIS 1413 | This function will query the target for its OS portable Bool Values. 1414 | 1415 | .DESCRIPTION 1416 | Specifies whether the operating system booted from an external USB device. If true, 1417 | the operating system has detected it is booting on a supported locally connected storage device. 1418 | 1419 | .PARAMETER UserName 1420 | DOMAIN\UserName to pass to CLI. 1421 | 1422 | .PARAMETER Password 1423 | String Password to pass to CLI. 1424 | 1425 | .PARAMETER Credential 1426 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 1427 | 1428 | .PARAMETER WmiOS 1429 | Pass the OS Wmi on the CLI to enhance speed / remote calls. 1430 | 1431 | .PARAMETER Targets 1432 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 1433 | 1434 | .EXAMPLE 1435 | > Get-WmiPortableOS 1436 | NONE 1437 | 1438 | .LINK 1439 | NONE 1440 | #> 1441 | [CmdletBinding()] 1442 | param( 1443 | [Parameter(ValueFromPipeline=$True)] 1444 | $Credential, 1445 | 1446 | [Parameter(ValueFromPipeline=$True)] 1447 | [string]$User, 1448 | 1449 | [Parameter(ValueFromPipeline=$True)] 1450 | [string]$Password, 1451 | 1452 | [Parameter(ValueFromPipeline=$True)] 1453 | [string]$HostName, 1454 | 1455 | [Parameter(ValueFromPipeline=$True)] 1456 | $WmiOS 1457 | ) 1458 | 1459 | Process 1460 | { 1461 | if( -Not $HostName) 1462 | { 1463 | $HostName = $env:computername 1464 | } 1465 | 1466 | if ($Credential) 1467 | { 1468 | # execute with cred object 1469 | try 1470 | { 1471 | if ($WmiOS){ 1472 | $PortableOS = $Wmi.PortableOperatingSystem 1473 | return $PortableOS 1474 | } 1475 | else{ 1476 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credentiall 1477 | $PortableOS = $Wmi.PortableOperatingSystem 1478 | return $PortableOS 1479 | } 1480 | } 1481 | catch 1482 | { 1483 | Write-Warning "[!] Error opening lastboot time one $HostName." 1484 | } 1485 | } 1486 | elseif ($User -and $Password) 1487 | { 1488 | # execute with built credential object 1489 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 1490 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 1491 | try 1492 | { 1493 | if ($WmiOS){ 1494 | $PortableOS = $Wmi.PortableOperatingSystem 1495 | return $PortableOS 1496 | } 1497 | else{ 1498 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName -credential $Credential 1499 | $PortableOS = $Wmi.PortableOperatingSystem 1500 | return $PortableOS 1501 | } 1502 | } 1503 | catch 1504 | { 1505 | Write-Warning "[!] Error opening lastboot time one $HostName." 1506 | } 1507 | } 1508 | else 1509 | { 1510 | try 1511 | { 1512 | # execute in current user context 1513 | if ($WmiOS){ 1514 | $PortableOS = $Wmi.PortableOperatingSystem 1515 | return $PortableOS 1516 | } 1517 | else{ 1518 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_OperatingSystem -computername $HostName 1519 | $PortableOS = $Wmi.PortableOperatingSystem 1520 | return $PortableOS 1521 | } 1522 | } 1523 | catch 1524 | { 1525 | Write-Warning "[!] Error opening lastboot time one $HostName." 1526 | } 1527 | 1528 | } 1529 | } 1530 | } 1531 | # VM checks are very important as values 1532 | # will lie to you! but they have 1533 | # there place in implants 1534 | function Get-WmiVMChecks{ 1535 | <# 1536 | .SYNOPSIS 1537 | This function will query the target for a few enviromental variables. 1538 | 1539 | .DESCRIPTION 1540 | Specifies whether the OS is being virtulized or on metal. This is an important factor 1541 | to the reliablity of the returned values as uptime can lie. 1542 | 1543 | .PARAMETER UserName 1544 | DOMAIN\UserName to pass to CLI. 1545 | 1546 | .PARAMETER Password 1547 | String Password to pass to CLI. 1548 | 1549 | .PARAMETER Credential 1550 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 1551 | 1552 | .PARAMETER Targets 1553 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost. 1554 | 1555 | .EXAMPLE 1556 | > Get-WmiPortableOS 1557 | NONE 1558 | 1559 | .LINK 1560 | NONE 1561 | #> 1562 | [CmdletBinding()] 1563 | param( 1564 | [Parameter(ValueFromPipeline=$True)] 1565 | $Credential, 1566 | 1567 | [Parameter(ValueFromPipeline=$True)] 1568 | [string]$User, 1569 | 1570 | [Parameter(ValueFromPipeline=$True)] 1571 | [string]$Password, 1572 | 1573 | [Parameter(ValueFromPipeline=$True)] 1574 | [string]$HostName 1575 | ) 1576 | 1577 | Process 1578 | { 1579 | if( -Not $HostName) 1580 | { 1581 | $HostName = $env:computername 1582 | } 1583 | 1584 | if ($Credential) 1585 | { 1586 | # execute with cred object 1587 | try 1588 | { 1589 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_PointingDevice -computername $HostName -credential $Credential 1590 | $VMware = $False 1591 | $Wmi.HardwareType | foreach{ 1592 | if ($_ -match "VMware"){ 1593 | $VMware = $True 1594 | 1595 | } 1596 | } 1597 | return $VMware 1598 | } 1599 | catch 1600 | { 1601 | Write-Warning "[!] Error opening lastboot time one $HostName." 1602 | } 1603 | } 1604 | elseif ($User -and $Password) 1605 | { 1606 | # execute with built credential object 1607 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 1608 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 1609 | try 1610 | { 1611 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_PointingDevice -computername $HostName -credential $Credential 1612 | $VMware = $False 1613 | $Wmi.HardwareType | foreach{ 1614 | if ($_ -match "VMware"){ 1615 | $VMware = $True 1616 | 1617 | } 1618 | } 1619 | return $VMware 1620 | } 1621 | catch 1622 | { 1623 | Write-Warning "[!] Error opening lastboot time one $HostName." 1624 | } 1625 | } 1626 | else 1627 | { 1628 | try 1629 | { 1630 | # execute in current user context 1631 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_PointingDevice -computername $HostName 1632 | $VMware = $False 1633 | $Wmi.HardwareType | foreach{ 1634 | if ($_ -match "VMware"){ 1635 | $VMware = $True 1636 | 1637 | } 1638 | } 1639 | return $VMware 1640 | } 1641 | catch 1642 | { 1643 | Write-Warning "[!] Error opening lastboot time one $HostName." 1644 | } 1645 | 1646 | } 1647 | } 1648 | } 1649 | function Get-WmiLogging{} 1650 | 1651 | ######################## 1652 | # Claculate Functions # 1653 | ######################## 1654 | 1655 | function Calc-WmiBootTime{ 1656 | <# 1657 | .SYNOPSIS 1658 | This function will query the target for last boot time in epoch time. 1659 | 1660 | .DESCRIPTION 1661 | This function will query the target for last boot time in epoch time. 1662 | 1663 | .PARAMETER Time 1664 | Pass a time to calculate the values and return them. 1665 | 1666 | .EXAMPLE 1667 | > 1668 | NONE 1669 | 1670 | .LINK 1671 | NONE 1672 | #> 1673 | 1674 | [CmdletBinding()] 1675 | param( 1676 | [Parameter(ValueFromPipeline=$True)] 1677 | $Time 1678 | ) 1679 | Process 1680 | { 1681 | # we will now caculate the value of the time 1682 | if($Time) 1683 | { 1684 | # Enter the main loop 1685 | # Get current date and time 1686 | $TodaysDate=(Get-Date) 1687 | # Do i need to build this to get the datetime object? 1688 | $Boot = Get-WmiObject Win32_OperatingSystem 1689 | $BootDate= $Boot.ConvertToDateTime($Time) 1690 | $TimeDif = New-TimeSpan -Start $BootDate -End $TodaysDate 1691 | if($TimeDif) 1692 | { 1693 | $Days = $TimeDif.Days 1694 | switch ($Days) 1695 | { 1696 | {$_ -lt 8} 1697 | { 1698 | $Value = .30 1699 | break 1700 | } 1701 | {$_ -lt 16} 1702 | { 1703 | $Value = .40 1704 | break 1705 | } 1706 | {$_ -lt 31} 1707 | { 1708 | $Value = .60 1709 | break 1710 | } 1711 | {$_ -lt 61} 1712 | { 1713 | $Value = .75 1714 | break 1715 | } 1716 | {$_ -lt 91} 1717 | { 1718 | $Value = .85 1719 | break 1720 | } 1721 | {$_ -lt 121} 1722 | { 1723 | $Value = .90 1724 | break 1725 | } 1726 | {$_ -lt 151} 1727 | { 1728 | $Value = .95 1729 | break 1730 | } 1731 | {$_ -gt 152} 1732 | { 1733 | $Value = 1.00 1734 | } 1735 | default{$Value = .20} 1736 | } 1737 | return $Value 1738 | } 1739 | } 1740 | else 1741 | { 1742 | # Return a zero value 1743 | $Value = 0 1744 | return $Value 1745 | } 1746 | } 1747 | 1748 | } 1749 | function Calc-WmiInstallDate{ 1750 | <# 1751 | .SYNOPSIS 1752 | This function will query the target for last boot time in epoch time. 1753 | 1754 | .PARAMETER Time 1755 | Pass a time to calculate the values and return them. 1756 | 1757 | .EXAMPLE 1758 | > 1759 | NONE 1760 | 1761 | .LINK 1762 | NONE 1763 | #> 1764 | 1765 | [CmdletBinding()] 1766 | param( 1767 | [Parameter(ValueFromPipeline=$True)] 1768 | $Time 1769 | ) 1770 | Process 1771 | { 1772 | # we will now caculate the value of the time 1773 | if($Time) 1774 | { 1775 | # Enter the main loop 1776 | # Get current date and time 1777 | $TodaysDate=(Get-Date) 1778 | # Do i need to build this to get the datetime object? 1779 | $Boot = Get-WmiObject Win32_OperatingSystem 1780 | $BootDate= $Boot.ConvertToDateTime($Time) 1781 | $TimeDif = New-TimeSpan -Start $BootDate -End $TodaysDate 1782 | if($TimeDif) 1783 | { 1784 | $Days = $TimeDif.Days 1785 | switch ($Days) 1786 | { 1787 | {$_ -lt 180} 1788 | { 1789 | $Value = .20 1790 | break 1791 | } 1792 | {$_ -lt 360} 1793 | { 1794 | $Value = .40 1795 | break 1796 | } 1797 | {$_ -lt 720} 1798 | { 1799 | $Value = .80 1800 | break 1801 | } 1802 | {$_ -gt 1080} 1803 | { 1804 | $Value = 1.00 1805 | } 1806 | default{$Value = .20} 1807 | } 1808 | return $Value 1809 | } 1810 | } 1811 | else 1812 | { 1813 | # Return a zero value 1814 | $Value = 0 1815 | return $Value 1816 | } 1817 | } 1818 | 1819 | } 1820 | function Calc-WmiArch{ 1821 | <# 1822 | .SYNOPSIS 1823 | This function will query the target for last boot time in epoch time. 1824 | 1825 | .PARAMETER Arch 1826 | Pass a time to calculate the values and return them. 1827 | 1828 | .EXAMPLE 1829 | > 1830 | NONE 1831 | 1832 | .LINK 1833 | NONE 1834 | #> 1835 | 1836 | [CmdletBinding()] 1837 | param( 1838 | [Parameter(ValueFromPipeline=$True)] 1839 | $Arch 1840 | ) 1841 | Process 1842 | { 1843 | # we will now caculate the value of the time 1844 | if($Arch) 1845 | { 1846 | # Enter the main loop 1847 | switch ($Arch) 1848 | { 1849 | {$_ -eq 32} 1850 | { 1851 | $Value = .50 1852 | break 1853 | } 1854 | {$_ -eq 64} 1855 | { 1856 | $Value = 1.00 1857 | } 1858 | default{$Value = .30} 1859 | } 1860 | return $Value 1861 | } 1862 | else 1863 | { 1864 | # Return a zero value 1865 | $Value = 0.0 1866 | return $Value 1867 | } 1868 | } 1869 | } 1870 | function Calc-WmiProcSpeed{ 1871 | <# 1872 | .SYNOPSIS 1873 | This function will query the target for last boot time in epoch time. 1874 | 1875 | .PARAMETER Speed 1876 | Pass a time to calculate the values and return them. 1877 | 1878 | .EXAMPLE 1879 | > 1880 | NONE 1881 | 1882 | .LINK 1883 | NONE 1884 | #> 1885 | 1886 | [CmdletBinding()] 1887 | param( 1888 | [Parameter(ValueFromPipeline=$True)] 1889 | $Speed 1890 | ) 1891 | Process 1892 | { 1893 | # caculate the value of the Proc Speed in MHz 1894 | if($Speed) 1895 | { 1896 | # Enter the main loop 1897 | switch ($Speed) 1898 | { 1899 | {$_ -lt 1500} 1900 | { 1901 | $Value = 0.20 1902 | break 1903 | } 1904 | {$_ -lt 2000} 1905 | { 1906 | $Value = 0.40 1907 | break 1908 | } 1909 | {$_ -lt 2500} 1910 | { 1911 | $Value = 0.80 1912 | break 1913 | } 1914 | {$_ -lt 2949} 1915 | { 1916 | $Value = 0.90 1917 | break 1918 | } 1919 | {$_ -gt 2950} 1920 | { 1921 | $Value = 1.00 1922 | } 1923 | default{$Value = 0.30} 1924 | } 1925 | return $Value 1926 | } 1927 | else 1928 | { 1929 | # Return a zero value 1930 | $Value = 0 1931 | return $Value 1932 | } 1933 | } 1934 | } 1935 | function Calc-WmiLProcCount{ 1936 | <# 1937 | .SYNOPSIS 1938 | 1939 | 1940 | .PARAMETER LProc 1941 | Pass a LProc Count to calculate the values and return them. 1942 | 1943 | .EXAMPLE 1944 | > 1945 | NONE 1946 | 1947 | .LINK 1948 | NONE 1949 | #> 1950 | 1951 | [CmdletBinding()] 1952 | param( 1953 | [Parameter(ValueFromPipeline=$True)] 1954 | $LProc 1955 | ) 1956 | Process 1957 | { 1958 | # caculate the value of Logical Proc. 1959 | if($Lproc) 1960 | { 1961 | # Enter the main loop 1962 | switch ($LProc) 1963 | { 1964 | {$_ -lt 2} 1965 | { 1966 | $Value = .30 1967 | break 1968 | } 1969 | {$_ -lt 3} 1970 | { 1971 | $Value = .50 1972 | break 1973 | } 1974 | {$_ -lt 4} 1975 | { 1976 | $Value = .65 1977 | break 1978 | } 1979 | {$_ -lt 5} 1980 | { 1981 | $Value = .80 1982 | break 1983 | } 1984 | {$_ -lt 6} 1985 | { 1986 | $Value = .90 1987 | } 1988 | {$_ -gt 6} 1989 | { 1990 | $Value = 1.00 1991 | } 1992 | default{$Value = .30} 1993 | } 1994 | return $Value 1995 | } 1996 | else 1997 | { 1998 | # Return a zero value 1999 | $Value = 0 2000 | return $Value 2001 | } 2002 | } 2003 | } 2004 | function Calc-WmiDisk{ 2005 | <# 2006 | .SYNOPSIS 2007 | 2008 | 2009 | .PARAMETER LProc 2010 | Pass a GB Disk size and calculate the value. 2011 | 2012 | .EXAMPLE 2013 | > 2014 | NONE 2015 | 2016 | .LINK 2017 | NONE 2018 | #> 2019 | 2020 | [CmdletBinding()] 2021 | param( 2022 | [Parameter(ValueFromPipeline=$True)] 2023 | $Disk 2024 | ) 2025 | Process 2026 | { 2027 | # caculate the value of Logical Proc. 2028 | if($Disk) 2029 | { 2030 | # Enter the main loop 2031 | switch ($Disk) 2032 | { 2033 | {$_ -lt 50} 2034 | { 2035 | $Value = .30 2036 | break 2037 | } 2038 | {$_ -lt 200} 2039 | { 2040 | $Value = .50 2041 | break 2042 | } 2043 | {$_ -lt 500} 2044 | { 2045 | $Value = .70 2046 | break 2047 | } 2048 | {$_ -lt 1000} 2049 | { 2050 | $Value = .80 2051 | break 2052 | } 2053 | {$_ -lt 1500} 2054 | { 2055 | $Value = .90 2056 | } 2057 | {$_ -gt 1800} 2058 | { 2059 | $Value = 1.00 2060 | } 2061 | default{$Value = .30} 2062 | } 2063 | return $Value 2064 | } 2065 | else 2066 | { 2067 | # Return a zero value 2068 | $Value = 0.0 2069 | return $Value 2070 | } 2071 | } 2072 | } 2073 | function Calc-WmiRamSize{ 2074 | <# 2075 | .SYNOPSIS 2076 | 2077 | 2078 | .PARAMETER LProc 2079 | Pass a GB Ram size and calculate the value. 2080 | 2081 | .EXAMPLE 2082 | > 2083 | NONE 2084 | 2085 | .LINK 2086 | NONE 2087 | #> 2088 | 2089 | [CmdletBinding()] 2090 | param( 2091 | [Parameter(ValueFromPipeline=$True)] 2092 | $Ram 2093 | ) 2094 | Process 2095 | { 2096 | # caculate the value of Logical Proc. 2097 | if($Ram) 2098 | { 2099 | # Enter the main loop 2100 | switch ($Ram) 2101 | { 2102 | {$_ -lt 1} 2103 | { 2104 | $Value = .20 2105 | break 2106 | } 2107 | {$_ -lt 2} 2108 | { 2109 | $Value = .30 2110 | break 2111 | } 2112 | {$_ -lt 3} 2113 | { 2114 | $Value = .50 2115 | break 2116 | } 2117 | {$_ -lt 4} 2118 | { 2119 | $Value = .70 2120 | break 2121 | } 2122 | {$_ -lt 6} 2123 | { 2124 | $Value = .80 2125 | } 2126 | {$_ -lt 8} 2127 | { 2128 | $Value = .90 2129 | } 2130 | {$_ -gt 20} 2131 | { 2132 | $Value = 1.00 2133 | } 2134 | default{$Value = .30} 2135 | } 2136 | return $Value 2137 | } 2138 | else 2139 | { 2140 | # Return a zero value 2141 | $Value = 0.0 2142 | return $Value 2143 | } 2144 | } 2145 | } 2146 | function Calc-WmiServer{ 2147 | <# 2148 | .SYNOPSIS 2149 | 2150 | 2151 | .PARAMETER Type 2152 | Pass a Os Type Code, and return proper value. 2153 | 2154 | .EXAMPLE 2155 | > 2156 | NONE 2157 | 2158 | .LINK 2159 | NONE 2160 | #> 2161 | 2162 | [CmdletBinding()] 2163 | param( 2164 | [Parameter(ValueFromPipeline=$True)] 2165 | $Type 2166 | ) 2167 | Process 2168 | { 2169 | # caculate the value of Logical Proc. 2170 | if($Type) 2171 | { 2172 | # Enter the main loop 2173 | switch ($Type) 2174 | { 2175 | {$_ -eq 1} 2176 | { 2177 | # Workstation 2178 | $Value = 0.33 2179 | break 2180 | } 2181 | {$_ -eq 2} 2182 | { 2183 | # DC 2184 | $Value = 0.66 2185 | break 2186 | } 2187 | {$_ -eq 3} 2188 | { 2189 | # Server 2190 | $Value = 1.00 2191 | break 2192 | } 2193 | default{$Value = 0.30} 2194 | } 2195 | return $Value 2196 | } 2197 | else 2198 | { 2199 | # Return a zero value 2200 | $Value = 0.0 2201 | return $Value 2202 | } 2203 | } 2204 | } 2205 | function Calc-WmiProcessCount{ 2206 | <# 2207 | .SYNOPSIS 2208 | 2209 | 2210 | .PARAMETER Type 2211 | Pass a Process count for a return value. 2212 | 2213 | .EXAMPLE 2214 | > 2215 | NONE 2216 | 2217 | .LINK 2218 | NONE 2219 | #> 2220 | 2221 | [CmdletBinding()] 2222 | param( 2223 | [Parameter(ValueFromPipeline=$True)] 2224 | $Count 2225 | ) 2226 | Process 2227 | { 2228 | # caculate the value of Logical Proc. 2229 | if($Count) 2230 | { 2231 | # Enter the main loop 2232 | switch ($Count) 2233 | { 2234 | {$_ -lt 8} 2235 | { 2236 | # Workstation 2237 | $Value = 0.40 2238 | break 2239 | } 2240 | {$_ -lt 10} 2241 | { 2242 | # Workstation 2243 | $Value = 0.60 2244 | break 2245 | } 2246 | {$_ -lt 12} 2247 | { 2248 | # DC 2249 | $Value = 0.70 2250 | break 2251 | } 2252 | {$_ -lt 15} 2253 | { 2254 | # Workstation 2255 | $Value = 0.80 2256 | break 2257 | } 2258 | {$_ -gt 15} 2259 | { 2260 | # Server 2261 | $Value = 1.00 2262 | break 2263 | } 2264 | default{$Value = 0.30} 2265 | } 2266 | return $Value 2267 | } 2268 | else 2269 | { 2270 | # Return a zero value 2271 | $Value = 0.0 2272 | return $Value 2273 | } 2274 | } 2275 | } 2276 | function Calc-WmiSystemEnclosure{ 2277 | <# 2278 | .SYNOPSIS 2279 | Calcuate the value of an array of system enclosures. 2280 | 2281 | .PARAMETER Code 2282 | Pass a Process count for a return value. 2283 | 2284 | .EXAMPLE 2285 | > 2286 | NONE 2287 | 2288 | .LINK 2289 | NONE 2290 | #> 2291 | 2292 | [CmdletBinding()] 2293 | param( 2294 | [Parameter(ValueFromPipeline=$True)] 2295 | $Code 2296 | ) 2297 | Process 2298 | { 2299 | if($Code) 2300 | { 2301 | # Enter the main loop 2302 | $Value = 0 2303 | ForEach ($i in $Code) 2304 | { 2305 | switch ($i) 2306 | <# 2307 | Other (1) 2308 | Unknown (2) 2309 | Desktop (3) 2310 | Low Profile Desktop (4) 2311 | Pizza Box (5) 2312 | Mini Tower (6) 2313 | Tower (7) 2314 | Portable (8) 2315 | Laptop (9) 2316 | Notebook (10) 2317 | Hand Held (11) 2318 | Docking Station (12) 2319 | All in One (13) 2320 | Sub Notebook (14) 2321 | Space-Saving (15) 2322 | Lunch Box (16) 2323 | Main System Chassis (17) 2324 | Expansion Chassis (18) 2325 | SubChassis (19) 2326 | Bus Expansion Chassis (20) 2327 | Peripheral Chassis (21) 2328 | Storage Chassis (22) 2329 | Rack Mount Chassis (23) 2330 | Sealed-Case PC (24) 2331 | #> 2332 | { 2333 | {$i -eq 1} 2334 | { 2335 | # Other 2336 | $Value += 0.10 2337 | break 2338 | } 2339 | {$i -eq 2} 2340 | { 2341 | $Value += 0.10 2342 | break 2343 | } 2344 | {$i -eq 3} 2345 | { 2346 | $Value += .50 2347 | break 2348 | } 2349 | {$i -eq 4} 2350 | { 2351 | $Value = 0.10 2352 | break 2353 | } 2354 | {$i -eq 6} 2355 | { 2356 | $Value = .20 2357 | break 2358 | } 2359 | {$i -eq 7} 2360 | { 2361 | $Value = .60 2362 | break 2363 | } 2364 | {$i -eq 8} 2365 | { 2366 | $Value = 0.10 2367 | break 2368 | } 2369 | {$i -eq 9} 2370 | { 2371 | $Value = 0.10 2372 | break 2373 | } 2374 | {$i -eq 10} 2375 | { 2376 | $Value = 0.10 2377 | break 2378 | } 2379 | {$i -eq 11} 2380 | { 2381 | $Value = 0.10 2382 | break 2383 | } 2384 | {$i -eq 13} 2385 | { 2386 | $Value = 0.10 2387 | break 2388 | } 2389 | {$i -eq 14} 2390 | { 2391 | $Value = 0.10 2392 | break 2393 | } 2394 | {$i -gt 17} 2395 | { 2396 | $Value = 1.00 2397 | break 2398 | } 2399 | default{$Value = .30} 2400 | } 2401 | if ($Value -gt 1.00) 2402 | { 2403 | $Value = 1.00 2404 | } 2405 | return $Value 2406 | } 2407 | } 2408 | else 2409 | { 2410 | # Return a zero value 2411 | $Value = 0.0 2412 | return $Value 2413 | } 2414 | } 2415 | } 2416 | 2417 | function Calc-WeightedAverage{ 2418 | <# 2419 | .SYNOPSIS 2420 | This function will take a set of values and turn them into a object. 2421 | This will return an object for manipulation. 2422 | 2423 | .PARAMETER Percent 2424 | Pass the float value to be calculated. 2425 | 2426 | .PARAMETER Weight 2427 | Pass the weight in float for the value. 2428 | 2429 | .EXAMPLE 2430 | > Get-WmiPortableOS 2431 | NONE 2432 | 2433 | .LINK 2434 | NONE 2435 | #> 2436 | [CmdletBinding()] 2437 | param( 2438 | [Parameter(Mandatory=$True, ValueFromPipeline=$True)] 2439 | $Percent, 2440 | 2441 | [Parameter(Mandatory=$True, ValueFromPipeline=$True)] 2442 | $Weight 2443 | ) 2444 | Process{ 2445 | if ($Percent -and $Weight) { 2446 | try { 2447 | $WeightedValue = $Percent * $Weight 2448 | return $WeightedValue 2449 | } 2450 | catch{ 2451 | Write-Verbose "[!] Failed to get weighted average." 2452 | return 0.0 2453 | } 2454 | } # end of if 2455 | } # end of process 2456 | } 2457 | function Calc-StandardDeviation{ 2458 | 2459 | Process{ 2460 | $ArrayLen = $PersistenceObjects.count 2461 | $PSTotal = 0 2462 | $PersistenceObjects | ForEach-Object{ 2463 | $PSTotal += $_.PersistenceSurvivability 2464 | } 2465 | $PSMean = $PSTotal / $ArrayLen 2466 | $PSMeanPercent = "{0:P0}" -f $PSMean 2467 | # now calculate the 2468 | standard deviation 2469 | $ValueofSepration = 0 2470 | $PersistenceObjects | ForEach-Object{ 2471 | # get the current value in float 2472 | $PSValue = $_.PersistenceSurvivability 2473 | # Sub the float values by the mean 2474 | $DiffrenceFromMean = $PSValue - $PSMean 2475 | # now square root the value 2476 | $ValueofSepration += [Math]::Pow($DiffrenceFromMean, 2) 2477 | } 2478 | # now we will calculate the Variance 2479 | # also account for sample data if needed 2480 | $Variance = $ValueofSepration / $ArrayLen 2481 | $Variance =[Math]::SQRT($Variance) 2482 | 2483 | 2484 | } 2485 | } 2486 | function Weighted-Values{ 2487 | <# 2488 | .SYNOPSIS 2489 | This function will return an object of weighted 2490 | values for calculation. 2491 | #> 2492 | Process{ 2493 | $WeightedValue = New-Object PSObject 2494 | $WeightedValue | Add-Member Noteproperty 'LastBoot' 0.40 2495 | $WeightedValue | Add-Member Noteproperty 'InstallDate' 0.05 2496 | $WeightedValue | Add-Member Noteproperty 'OSArch' 0.05 2497 | $WeightedValue | Add-Member Noteproperty 'ServerType' 0.10 2498 | $WeightedValue | Add-Member Noteproperty 'SystemEnclosure' 0.10 2499 | $WeightedValue | Add-Member Noteproperty 'RamSize' 0.05 2500 | $WeightedValue | Add-Member Noteproperty 'DiskSize' 0.05 2501 | $WeightedValue | Add-Member Noteproperty 'ProcessorSpeed' 0.05 2502 | $WeightedValue | Add-Member Noteproperty 'ProcessorLogicalCores' 0.05 2503 | $WeightedValue | Add-Member Noteproperty 'ProcessorCores' 0.05 2504 | $WeightedValue | Add-Member Noteproperty 'ProcessCount' 0.05 2505 | # boolean values 2506 | $WeightedValue | Add-Member Noteproperty 'PortableOS' 0.25 2507 | return $WeightedValue 2508 | } 2509 | } 2510 | 2511 | 2512 | 2513 | ######################### 2514 | # # 2515 | # Main function Calls # 2516 | # # 2517 | ######################### 2518 | 2519 | function Invoke-FindPersitence{ 2520 | <# 2521 | .SYNOPSIS 2522 | Queries all machines on the domain, for Networks Name, 2523 | DNS Suffix and the MAC of the connected Network. 2524 | 2525 | .PARAMETER Top 2526 | Display the top # of results for each category. Defualts to top 3 results. 2527 | 2528 | .PARAMETER MaxHosts 2529 | Only query the selected number of hosts 2530 | 2531 | .PARAMETER UserName 2532 | One or more computers to test. DOMAIN\UserName 2533 | 2534 | .PARAMETER Password 2535 | One or more computers to test 2536 | 2537 | .PARAMETER Credential 2538 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 2539 | 2540 | .PARAMETER NoPing 2541 | Don't ping each host to ensure it's up before enumerating. 2542 | 2543 | .PARAMETER Delay 2544 | Delay between enumerating hosts, defaults to 0 milliseconds. 2545 | 2546 | .PARAMETER Jitter 2547 | Jitter for the host delay, defaults to +/- 0-100 milliseconds 2548 | 2549 | .PARAMETER HostList 2550 | Provid a hostlist on the CLI (IP, NAME). 2551 | 2552 | .PARAMETER IpSubnet 2553 | Provid a IP with subnet to target. 2554 | 2555 | .PARAMETER OperatingSystem 2556 | Return computers with a specific operating system, wildcards accepted. 2557 | 2558 | .PARAMETER ServicePack 2559 | Return computers with a specific service pack, wildcards accepted. 2560 | 2561 | .PARAMETER Domain 2562 | Domain to query for machines, defaults to the current domain. 2563 | 2564 | .PARAMETER SPN 2565 | Return computers with a specific service principal name, wildcards accepted. 2566 | 2567 | .PARAMETER SearchForest 2568 | Switch. Search all domains in the forest for target users instead of just 2569 | a single domain. 2570 | 2571 | .PARAMETER CheckAdmin 2572 | Switch. Check if the current user has access to the box before procedding. 2573 | This may be important within a forest. 2574 | 2575 | .PARAMETER Threads 2576 | The maximum concurrent threads to execute. **NEED TO BUILD** 2577 | 2578 | .PARAMETER RawOutput 2579 | Will return every object to the CLI, this can be used for out-file or 2580 | just to test data being returned. 2581 | 2582 | .EXAMPLE 2583 | PS> Invoke-FindPersitence 2584 | This will query the current domain and ALL the hosts that up. 2585 | 2586 | .EXAMPLE 2587 | PS> Invoke-FindPersitence -Domain tester.org -OperatingSystem *7* 2588 | This will query for computers inside a unique domain, with a specfic OS filter. In this 2589 | case we are querying for all windows 7 platforms. 2590 | 2591 | PS> Invoke-FindPersitence -MaxHosts 100 -Top 5 2592 | This will query for computers untill the host limit is reached, as well as 2593 | only display the top 5 hosts of the report. 2594 | 2595 | PS> Invoke-FindPersitence -ReturnObjects 2596 | This will allow you to return an PS array of computer objects built. 2597 | #> 2598 | [CmdletBinding()] 2599 | Param ( 2600 | [Parameter(ValueFromPipeline=$True)] 2601 | [Alias('HostName')] 2602 | [String] 2603 | $ComputerName = '*', 2604 | 2605 | [Parameter(ValueFromPipeline=$True)] 2606 | [Int]$Top = 3, 2607 | 2608 | [Parameter(ValueFromPipeline=$True)] 2609 | $HostList, 2610 | 2611 | [Parameter(ValueFromPipeline=$True)] 2612 | $IpSubnet, 2613 | 2614 | [Parameter(ValueFromPipeline=$True)] 2615 | [Int]$TimeOut = 5, 2616 | 2617 | [Parameter(ValueFromPipeline=$True)] 2618 | [Int]$Delay = 0, 2619 | 2620 | [Parameter(ValueFromPipeline=$True)] 2621 | [Int]$Jitter = 100, 2622 | 2623 | [Parameter(ValueFromPipeline=$True)] 2624 | [Int]$MaxHosts, 2625 | 2626 | [Parameter(ValueFromPipeline=$True)] 2627 | $Credential, 2628 | 2629 | [Parameter(ValueFromPipeline=$True)] 2630 | [String]$User, 2631 | 2632 | [Parameter(ValueFromPipeline=$True)] 2633 | [String]$Password, 2634 | 2635 | [Parameter(ValueFromPipeline=$True)] 2636 | [String]$SPN, 2637 | 2638 | [Parameter(ValueFromPipeline=$True)] 2639 | [String]$OperatingSystem, 2640 | 2641 | [Parameter(ValueFromPipeline=$True)] 2642 | [String]$ServicePack, 2643 | 2644 | [Parameter(ValueFromPipeline=$True)] 2645 | [String]$Filter, 2646 | 2647 | [Parameter(ValueFromPipeline=$True)] 2648 | [String]$Domain, 2649 | 2650 | [Parameter(ValueFromPipeline=$True)] 2651 | [String]$DomainController, 2652 | 2653 | [Parameter(ValueFromPipeline=$True)] 2654 | [String]$ADSpath, 2655 | 2656 | [Parameter(ValueFromPipeline=$True)] 2657 | [Switch]$Unconstrained, 2658 | 2659 | [Parameter(ValueFromPipeline=$True)] 2660 | [Switch]$ReturnObjects, 2661 | 2662 | [Parameter(ValueFromPipeline=$True)] 2663 | [Switch]$RawOutput, 2664 | 2665 | [ValidateRange(1,100)] 2666 | [Int]$Threads=4, 2667 | 2668 | [ValidateRange(1,10000)] 2669 | [Int] 2670 | $PageSize = 200 2671 | ) 2672 | begin { 2673 | Write-Verbose "[*] Strating Invoke-FindPersitence" 2674 | if ($HostList){ 2675 | $Computers = $HostList 2676 | Write-Verbose "[*] IP MAIN: hosts passed:" 2677 | } 2678 | if ($IpSubnet){ 2679 | $Computers = Get-NetworkRange $IpSubnet 2680 | } 2681 | else { 2682 | # so this isn't repeated if users are passed on the pipeline 2683 | $Computers = Get-NetComputer -Domain $Domain -DomainController $DomainController -OperatingSystem $OperatingSystem -ServicePack $ServicePack -SPN $SPN -PageSize $PageSize -ADSpath $ADSpath -Filter $Filter -ComputerName $ComputerName 2684 | } 2685 | } 2686 | Process { 2687 | 2688 | if ($Computers) { 2689 | # create weighted value object before loop. 2690 | # declare an array for 2691 | $PersistenceObjects = @() 2692 | $FinalComputerObjects = @() 2693 | # start main 2694 | $Counter = 1 2695 | if($MaxHosts){ 2696 | # Should we ping all boxes first and supply the right number of hosts 2697 | # or just feed x hosts? 2698 | $Computers = $Computers | Select-Object -first $MaxHosts 2699 | } 2700 | # Test if they are up first: 2701 | Write-Verbose "[*] IP MAIN: Calling Invoke-Ping" 2702 | $Computers = Invoke-Ping -Timeout 5 -ComputerName $Computers 2703 | Write-Verbose "[*] IP MAIN: Invoke-Ping Complete" 2704 | # Make sure we can reach RPC / talk to WMI 2705 | Write-Verbose "[*] IP MAIN: Calling Test-Wmi" 2706 | $FinalComputerObjects = Test-Wmi -ComputerName $Computers -Credential $Credential -User $User -Password $Password -Threads $Threads 2707 | Write-Verbose "[*] IP MAIN: Test-Wmi Complete" 2708 | # Build a Script Block 2709 | Write-Verbose "[*] IP MAIN: Building script blokc for wmi collection" 2710 | $sb = [scriptblock] { param($ComputerName) param($User) param($Password) param($Credential) param($Delay) param($Jitter) if($Delay){ 2711 | # create sleep for jitter /delay time 2712 | $JitterValue = Get-Random -Minimum 0 -Maximum $Jitter 2713 | # for Postive / Negative Jitter count 2714 | $RandMulti = Get-Random -input -1,1 2715 | $SleepJitter = $JitterValue * $RandMulti 2716 | # calculate the sleep time by adding pot negative # 2717 | $SleepTime = $Delay + $SleepJitter 2718 | Start-Sleep -Milliseconds $SleepTime 2719 | } 2720 | # setup meta calls for repeated Wmi calls to reduce call traffic 2721 | $WmiOS = Get-WmiOS -User $User -Password $Password -Credential $Credential -HostName $ComputerName 2722 | # Obtain required values for calculation 2723 | try{ 2724 | $LastBoot = Get-WmiBootTime -User $User -Password $Password -Credential $Credential -HostName $ComputerName -WmiOS $WmiOS 2725 | $InstallDate = Get-WmiInstallDate -User $User -Password $Password -Credential $Credential -HostName $ComputerName -WmiOS $WmiOS 2726 | $Arch = Get-WmiArch -User $User -Password $Password -Credential $Credential -HostName $ComputerName -WmiOS $WmiOS 2727 | $Server = Get-WmiServer -User $User -Password $Password -Credential $Credential -HostName $ComputerName -WmiOS $WmiOS 2728 | $SystemEncl = Get-WmiSystemEnclosure -User $User -Password $Password -Credential $Credential -HostName $ComputerName 2729 | $RamSize = Get-WmiRamSize -User $User -Password $Password -Credential $Credential -HostName $ComputerName 2730 | $DiskSize = Get-WMiDisk -User $User -Password $Password -Credential $Credential -HostName $ComputerName 2731 | $ProcSpeed = Get-WmiProcessorSpeed -User $User -Password $Password -Credential $Credential -HostName $ComputerName 2732 | $LProcCount = Get-WmiLProcessorCount -User $User -Password $Password -Credential $Credential -HostName $ComputerName 2733 | $ProcCores = Get-WmiProcessorCores -User $User -Password $Password -Credential $Credential -HostName $ComputerName 2734 | $ProcCount = Get-WmiProcessCount -User $User -Password $Password -Credential $Credential -HostName $ComputerName 2735 | # Obtain required boolean values 2736 | $PortOS = Get-WmiPortableOS -User $User -Password $Password -Credential $Credential -HostName $ComputerName -WmiOS $WmiOS 2737 | $VMware = Get-WmiVMChecks -User $User -Password $Password -Credential $Credential -HostName $ComputerName 2738 | } 2739 | 2740 | catch{ 2741 | Write-Verbose "[!] Failed to get WMI values" 2742 | } 2743 | try{ 2744 | # Calculate the values of the object 2745 | $VLastBoot = Calc-WmiBootTime -Time $LastBoot 2746 | $VInstallDate = Calc-WmiInstallDate -Time $InstallDate 2747 | $VArch = Calc-WmiArch -Arch $Arch 2748 | $VServer = Calc-WmiServer -Type $Server 2749 | $VSystemEncl = Calc-WmiSystemEnclosure -Code $SystemEncl 2750 | $VRamSize = Calc-WmiRamSize -Ram $RamSize 2751 | $VDiskSpace = Calc-WmiDisk -Disk $DiskSize 2752 | $VProcSpeed = Calc-WmiProcSpeed -Speed $ProcSpeed 2753 | $VLProcCount = Calc-WmiLProcCount -LProc $LProcCount 2754 | # $WProcCores = Calc-WmiProcCores -Cores $ProcCores 2755 | $VProcCount = Calc-WmiProcessCount -Count $ProcCount 2756 | } 2757 | catch { 2758 | Write-Verbose "[!] Failed to calculate values" 2759 | } 2760 | try{ 2761 | # calculate weighted averages 2762 | $WeightedValue = Weighted-Values 2763 | $WLastBoot = Calc-WeightedAverage -Percent $VLastBoot -Weight $WeightedValue.LastBoot 2764 | $WInstallDate = Calc-WeightedAverage -Percent $VInstallDate -Weight $WeightedValue.InstallDate 2765 | $WArch = Calc-WeightedAverage -Percent $VArch -Weight $WeightedValue.OSArch 2766 | $WServer = Calc-WeightedAverage -Percent $VServer -Weight $WeightedValue.ServerType 2767 | $WSystemEncl = Calc-WeightedAverage -Percent $VSystemEncl -Weight $WeightedValue.SystemEnclosure 2768 | $WRamSize = Calc-WeightedAverage -Percent $VRamSize -Weight $WeightedValue.RamSize 2769 | $WDiskSpace = Calc-WeightedAverage -Percent $VDiskSpace -Weight $WeightedValue.DiskSize 2770 | $WProcSpeed = Calc-WeightedAverage -Percent $VProcSpeed -Weight $WeightedValue.ProcessorSpeed 2771 | $WLProcCount = Calc-WeightedAverage -Percent $VLProcCount -Weight $WeightedValue.ProcessorLogicalCores 2772 | # Cores 2773 | $WProcCount = Calc-WeightedAverage -Percent $VProcCount -Weight $WeightedValue.ProcessCount 2774 | # calc the PersistenceSurvivability rating 2775 | [float]$PersistenceSurvivability = $WLastBoot + $WInstallDate + $WArch + $WServer + $WSystemEncl + $WDiskSpace + $WProcSpeed + $WLProcCount + $WRamSize 2776 | } 2777 | catch{ 2778 | Write-Verbose "[!] Failed to build weighted Averages" 2779 | } 2780 | try{ 2781 | $IpAddress = [System.Net.Dns]::GetHostAddresses("$ComputerName").IPAddressToString 2782 | } 2783 | catch{ 2784 | $IpAddress = "Uknown" 2785 | } 2786 | try{ 2787 | # build our object of values 2788 | $ComputerObject = New-Object PSObject 2789 | $ComputerObject | Add-Member NoteProperty 'NetBIOSName' $ComputerName 2790 | $ComputerObject | Add-Member NoteProperty 'IpAddress' $IpAddress 2791 | $ComputerObject | Add-Member Noteproperty 'LastBoot' $LastBoot 2792 | $ComputerObject | Add-Member Noteproperty 'InstallDate' $InstallDate 2793 | $ComputerObject | Add-Member Noteproperty 'OSArch' $Arch 2794 | $ComputerObject | Add-Member Noteproperty 'ServerType' $Server 2795 | $ComputerObject | Add-Member Noteproperty 'SystemEnclosure' $SystemEncl 2796 | $ComputerObject | Add-Member Noteproperty 'RamSize' $RamSize 2797 | $ComputerObject | Add-Member Noteproperty 'DiskSize' $DiskSize 2798 | $ComputerObject | Add-Member Noteproperty 'ProcessorSpeed' $ProcSpeed 2799 | $ComputerObject | Add-Member Noteproperty 'ProcessorLogicalCores' $LProcCount 2800 | $ComputerObject | Add-Member Noteproperty 'ProcessorCores' $ProcCores 2801 | $ComputerObject | Add-Member Noteproperty 'ProcessCount' $ProcCount 2802 | # boolean values 2803 | $ComputerObject | Add-Member Noteproperty 'PortableOS' $PortOS 2804 | $ComputerObject | Add-Member NoteProperty 'VMware' $VMware 2805 | # calculated values 2806 | $ComputerObject | Add-Member NoteProperty 'LastBootV' $VLastBoot 2807 | $ComputerObject | Add-Member NoteProperty 'InstallDateV' $VInstallDate 2808 | $ComputerObject | Add-Member NoteProperty 'OSArchV' $VArch 2809 | $ComputerObject | Add-Member NoteProperty 'ServerTypeV' $VServer 2810 | $ComputerObject | Add-Member NoteProperty 'SystemEnclosureV' $VSystemEncl 2811 | #$ComputerObject | Add-Member NoteProperty 'LastBootValue' $VRamSize 2812 | $ComputerObject | Add-Member NoteProperty 'DiskSizeV' $VDiskSpace 2813 | $ComputerObject | Add-Member NoteProperty 'RamSizeV' $VRamSize 2814 | $ComputerObject | Add-Member NoteProperty 'ProcessorSpeedV' $VProcSpeed 2815 | $ComputerObject | Add-Member NoteProperty 'ProcessorLogicalCoreV' $VLProcCount 2816 | #$ComputerObject | Add-Member NoteProperty 'ProcessorCoresV' $VProcCores 2817 | $ComputerObject | Add-Member NoteProperty 'ProcessCountV' $VProcCount 2818 | # build out weighted values 2819 | $ComputerObject | Add-Member NoteProperty 'LastBootWV' $WLastBoot 2820 | $ComputerObject | Add-Member NoteProperty 'InstallDateWV' $WInstallDate 2821 | $ComputerObject | Add-Member NoteProperty 'OSArchWV' $WArch 2822 | $ComputerObject | Add-Member NoteProperty 'ServerTypeWV' $WServer 2823 | $ComputerObject | Add-Member NoteProperty 'SystemEnclosureWV' $WSystemEncl 2824 | $ComputerObject | Add-Member NoteProperty 'DiskSizeWV' $WDiskSpace 2825 | $ComputerObject | Add-Member NoteProperty 'RamSizeWV' $WRamSize 2826 | $ComputerObject | Add-Member NoteProperty 'ProcessorSpeedWV' $WProcSpeed 2827 | $ComputerObject | Add-Member NoteProperty 'ProcessorLogicalCoreWV' $WLProcCount 2828 | $ComputerObject | Add-Member NoteProperty 'ProcessCountWV' $WProcCount 2829 | # our total values 2830 | $ComputerObject | Add-Member NoteProperty 'PersistenceSurvivability' $PersistenceSurvivability 2831 | 2832 | 2833 | # print / return value 2834 | $ComputerObject 2835 | } 2836 | catch{ 2837 | "[!] Failed to build computer object!" 2838 | } 2839 | } # End of script block 2840 | Write-Verbose "[*] IP MAIN: Script block creation complete" 2841 | # call threaded function 2842 | $ScriptParams = @{ 2843 | 'Computers' = $ComputerName 2844 | 'User' = $User 2845 | 'Password' = $Password 2846 | 'Credential' = $Password 2847 | 'Delay' = $Delay 2848 | 'Jitter' = $Jitter 2849 | } 2850 | Write-Verbose "[*] IP MAIN: Strating threads on script block" 2851 | $PersistenceObjects = Invoke-ThreadedFunction -ComputerName $FinalComputerObjects -ScriptBlock $sb -Threads $Threads -ScriptParameters $ScriptParams 2852 | if ($RawOutput){ 2853 | $PersistenceObjects 2854 | } 2855 | if (!$ReturnObjects){ 2856 | # declare arrays for each section 2857 | $VMwareObjects = @() 2858 | $DesktopObjects = @() 2859 | $ServerObjects = @() 2860 | # create loop for sorting etc. 2861 | $PersistenceObjects | ForEach-Object{ 2862 | if($_.VMware){ 2863 | $VMwareObjects += $_ 2864 | } 2865 | elseif($_.ServerType -gt 1 -and !$_.VMware){ 2866 | # we should also check for VMware? 2867 | $ServerObjects += $_ 2868 | } 2869 | else{ 2870 | # we should also check for VMware? 2871 | $DesktopObjects += $_ 2872 | } 2873 | }# end of foreach loop 2874 | 2875 | # now sort the objects by persistence rating 2876 | try{ 2877 | Write-Host "[*] Top Server locations based on Persistence Survivability rating: " 2878 | $SortedObjectsServer = Sort-Object -Descending -Property PersistenceSurvivability -InputObject $ServerObjects 2879 | $SortedObjectsServer | Select-Object -first $Top 2880 | } 2881 | catch{ 2882 | Write-Verbose "[!] Failed to print the top results (Server Objects)" 2883 | } 2884 | try{ 2885 | Write-Host "[*] Top Desktop locations based on Persistence Survivability rating: " 2886 | $SortedObjectsDesktop = Sort-Object -Descending -Property PersistenceSurvivability -InputObject $DesktopObjects 2887 | $SortedObjectsDesktop | Select-Object -first $Top 2888 | } 2889 | catch{ 2890 | Write-Verbose "[!] Failed to sort Desktop objects" 2891 | } 2892 | try{ 2893 | Write-Host "[*] Top VM locations based on Persistence Survivability rating: " 2894 | $SortedObjectsVM = Sort-Object -Descending -Property PersistenceSurvivability -InputObject $VMwareObjects 2895 | $SortedObjectsVM | Select-Object -first $Top 2896 | } 2897 | catch{ 2898 | Write-Verbose "[!] Failed to sort VMware objects" 2899 | } 2900 | # now build the stat data 2901 | if($PersistenceObjects){ 2902 | $ArrayLen = $PersistenceObjects.count 2903 | $PSTotal = 0 2904 | $PersistenceObjects | ForEach-Object{ 2905 | $PSTotal += $_.PersistenceSurvivability 2906 | } 2907 | $PSMean = $PSTotal / $ArrayLen 2908 | $PSMeanPercent = "{0:P0}" -f $PSMean 2909 | # now calculate the 2910 | # standard deviation 2911 | $ValueofSepration = 0 2912 | $PersistenceObjects | ForEach-Object{ 2913 | # get the current value in float 2914 | $PSValue = $_.PersistenceSurvivability 2915 | # Sub the float values by the mean 2916 | $DiffrenceFromMean = $PSValue - $PSMean 2917 | # now square root the value 2918 | $ValueofSepration += [Math]::Pow($DiffrenceFromMean, 2) 2919 | } 2920 | # now we will calculate the Variance 2921 | # also account for sample data if needed 2922 | $Variance = $ValueofSepration / $ArrayLen 2923 | $Variance =[Math]::SQRT($Variance) 2924 | # now build the stat object 2925 | $StatObject = New-Object PSObject 2926 | $StatObject | Add-Member NoteProperty 'ArrayLen' $PersistenceObjects.count 2927 | $StatObject | Add-Member NoteProperty 'VMwareLen' $VMwareObjects.count 2928 | $StatObject | Add-Member NoteProperty 'DesktopLen' $DesktopObjects.count 2929 | $StatObject | Add-Member NoteProperty 'ServerLen' $ServerObjects.count 2930 | $StatObject | Add-Member NoteProperty 'PSMean' $PSMeanPercent 2931 | $StatObject | Add-Member NoteProperty 'Variance' $Variance 2932 | 2933 | # print final data stats: 2934 | Write-Host "[*] Overall Persistence Survivability stats: " 2935 | Write-Host " Total number of hosts: " $StatObject.ArrayLen 2936 | Write-Host " Total VMware hosts: " $StatObject.VMwareLen 2937 | Write-Host " Total Desktop hosts: " $StatObject.DesktopLen 2938 | Write-Host " Total Server hosts: " $StatObject.ServerLen 2939 | Write-Host " Survivability mean: " $StatObject.PSMean 2940 | Write-Host " Standard Deviation Value: " $StatObject.Variance 2941 | 2942 | } # end if print 2943 | } # end of if return objects 2944 | else{ 2945 | return $PersistenceObjects 2946 | } # return just the objects for your own parsing 2947 | } # End of if computers 2948 | } 2949 | 2950 | 2951 | } 2952 | 2953 | ######################### 2954 | # # 2955 | # Helper Calls # 2956 | # # 2957 | ######################### 2958 | 2959 | # all subnet math http://www.indented.co.uk/2010/01/23/powershell-subnet-math/ 2960 | # all credit to them for that hard work! 2961 | function ConvertTo-Mask { 2962 | <# 2963 | .Synopsis 2964 | Returns a dotted decimal subnet mask from a mask length. 2965 | .Description 2966 | ConvertTo-Mask returns a subnet mask in dotted decimal format from an integer value ranging 2967 | between 0 and 32. ConvertTo-Mask first creates a binary string from the length, converts 2968 | that to an unsigned 32-bit integer then calls ConvertTo-DottedDecimalIP to complete the operation. 2969 | .Parameter MaskLength 2970 | The number of bits which must be masked. 2971 | #> 2972 | 2973 | [CmdLetBinding()] 2974 | param( 2975 | [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] 2976 | [Alias("Length")] 2977 | [ValidateRange(0, 32)] 2978 | $MaskLength 2979 | ) 2980 | 2981 | Process { 2982 | return ConvertTo-DottedDecimalIP ([Convert]::ToUInt32($(("1" * $MaskLength).PadRight(32, "0")), 2)) 2983 | } 2984 | } 2985 | 2986 | function ConvertTo-DottedDecimalIP { 2987 | <# 2988 | .Synopsis 2989 | Returns a dotted decimal IP address from either an unsigned 32-bit integer or a dotted binary string. 2990 | .Description 2991 | ConvertTo-DottedDecimalIP uses a regular expression match on the input string to convert to an IP address. 2992 | .Parameter IPAddress 2993 | A string representation of an IP address from either UInt32 or dotted binary. 2994 | #> 2995 | 2996 | [CmdLetBinding()] 2997 | param( 2998 | [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] 2999 | [String]$IPAddress 3000 | ) 3001 | 3002 | process { 3003 | Switch -RegEx ($IPAddress) { 3004 | "([01]{8}.){3}[01]{8}" { 3005 | return [String]::Join('.', $( $IPAddress.Split('.') | ForEach-Object { [Convert]::ToUInt32($_, 2) } )) 3006 | } 3007 | "\d" { 3008 | $IPAddress = [UInt32]$IPAddress 3009 | $DottedIP = $( For ($i = 3; $i -gt -1; $i--) { 3010 | $Remainder = $IPAddress % [Math]::Pow(256, $i) 3011 | ($IPAddress - $Remainder) / [Math]::Pow(256, $i) 3012 | $IPAddress = $Remainder 3013 | } ) 3014 | 3015 | return [String]::Join('.', $DottedIP) 3016 | } 3017 | default { 3018 | Write-Error "Cannot convert this format" 3019 | } 3020 | } 3021 | } 3022 | } 3023 | function ConvertTo-DottedDecimalIP { 3024 | <# 3025 | .Synopsis 3026 | Returns a dotted decimal IP address from either an unsigned 32-bit integer or a dotted binary string. 3027 | .Description 3028 | ConvertTo-DottedDecimalIP uses a regular expression match on the input string to convert to an IP address. 3029 | .Parameter IPAddress 3030 | A string representation of an IP address from either UInt32 or dotted binary. 3031 | #> 3032 | 3033 | [CmdLetBinding()] 3034 | param( 3035 | [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] 3036 | [String]$IPAddress 3037 | ) 3038 | 3039 | process { 3040 | Switch -RegEx ($IPAddress) { 3041 | "([01]{8}.){3}[01]{8}" { 3042 | return [String]::Join('.', $( $IPAddress.Split('.') | ForEach-Object { [Convert]::ToUInt32($_, 2) } )) 3043 | } 3044 | "\d" { 3045 | $IPAddress = [UInt32]$IPAddress 3046 | $DottedIP = $( For ($i = 3; $i -gt -1; $i--) { 3047 | $Remainder = $IPAddress % [Math]::Pow(256, $i) 3048 | ($IPAddress - $Remainder) / [Math]::Pow(256, $i) 3049 | $IPAddress = $Remainder 3050 | } ) 3051 | 3052 | return [String]::Join('.', $DottedIP) 3053 | } 3054 | default { 3055 | Write-Error "Cannot convert this format" 3056 | } 3057 | } 3058 | } 3059 | } 3060 | function ConvertTo-DecimalIP { 3061 | <# 3062 | .Synopsis 3063 | Converts a Decimal IP address into a 32-bit unsigned integer. 3064 | .Description 3065 | ConvertTo-DecimalIP takes a decimal IP, uses a shift-like operation on each octet and returns a single UInt32 value. 3066 | .Parameter IPAddress 3067 | An IP Address to convert. 3068 | #> 3069 | 3070 | [CmdLetBinding()] 3071 | param( 3072 | [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] 3073 | [Net.IPAddress]$IPAddress 3074 | ) 3075 | 3076 | process { 3077 | $i = 3; $DecimalIP = 0; 3078 | $IPAddress.GetAddressBytes() | ForEach-Object { $DecimalIP += $_ * [Math]::Pow(256, $i); $i-- } 3079 | 3080 | return [UInt32]$DecimalIP 3081 | } 3082 | } 3083 | function ConvertTo-BinaryIP { 3084 | <# 3085 | .Synopsis 3086 | Converts a Decimal IP address into a binary format. 3087 | .Description 3088 | ConvertTo-BinaryIP uses System.Convert to switch between decimal and binary format. The output from this function is dotted binary. 3089 | .Parameter IPAddress 3090 | An IP Address to convert. 3091 | #> 3092 | 3093 | [CmdLetBinding()] 3094 | param( 3095 | [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] 3096 | [Net.IPAddress]$IPAddress 3097 | ) 3098 | 3099 | process { 3100 | return [String]::Join('.', $( $IPAddress.GetAddressBytes() | 3101 | ForEach-Object { [Convert]::ToString($_, 2).PadLeft(8, '0') } )) 3102 | } 3103 | } 3104 | function ConvertTo-MaskLength { 3105 | <# 3106 | .Synopsis 3107 | Returns the length of a subnet mask. 3108 | .Description 3109 | ConvertTo-MaskLength accepts any IPv4 address as input, however the output value 3110 | only makes sense when using a subnet mask. 3111 | .Parameter SubnetMask 3112 | A subnet mask to convert into length 3113 | #> 3114 | 3115 | [CmdLetBinding()] 3116 | param( 3117 | [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)] 3118 | [Alias("Mask")] 3119 | [Net.IPAddress]$SubnetMask 3120 | ) 3121 | 3122 | process { 3123 | $Bits = "$( $SubnetMask.GetAddressBytes() | ForEach-Object { [Convert]::ToString($_, 2) } )" -replace '[\s0]' 3124 | 3125 | return $Bits.Length 3126 | } 3127 | } 3128 | function Get-NetworkRange( [String]$IP, [String]$Mask ) { 3129 | if ($IP.Contains("/")) { 3130 | $Temp = $IP.Split("/") 3131 | $IP = $Temp[0] 3132 | $Mask = $Temp[1] 3133 | } 3134 | 3135 | if (!$Mask.Contains(".")) { 3136 | $Mask = ConvertTo-Mask $Mask 3137 | } 3138 | 3139 | $DecimalIP = ConvertTo-DecimalIP $IP 3140 | $DecimalMask = ConvertTo-DecimalIP $Mask 3141 | 3142 | $Network = $DecimalIP -band $DecimalMask 3143 | $Broadcast = $DecimalIP -bor ((-bnot $DecimalMask) -band [UInt32]::MaxValue) 3144 | 3145 | for ($i = $($Network + 1); $i -lt $Broadcast; $i++) { 3146 | ConvertTo-DottedDecimalIP $i 3147 | } 3148 | } 3149 | 3150 | function Test-Wmi { 3151 | <# 3152 | .SYNOPSIS 3153 | This function will query the target with Wmi to test creds and make sure we have the 3154 | ability to talk to RPC. 3155 | 3156 | .PARAMETER Credential 3157 | Pass a credential object on the CLI. Rather than recreating a new credential object it can be re-used. 3158 | 3159 | .PARAMETER UserName 3160 | DOMAIN\UserName to pass to CLI. 3161 | 3162 | .PARAMETER Password 3163 | String Password to pass to CLI. 3164 | 3165 | .PARAMETER ComputerName 3166 | Host to target for the data. Can be a hostname, IP address, or FQDN. Default is set to localhost or list of computers. 3167 | 3168 | .EXAMPLE 3169 | > Get-WmiBootTime 3170 | NONE 3171 | 3172 | .LINK 3173 | NONE 3174 | #> 3175 | [CmdletBinding()] 3176 | param( 3177 | [Parameter(ValueFromPipeline=$True)] 3178 | $Credential, 3179 | 3180 | [Parameter(ValueFromPipeline=$True)] 3181 | [string]$User, 3182 | 3183 | [Parameter(ValueFromPipeline=$True)] 3184 | [string]$Password, 3185 | 3186 | [Parameter(ValueFromPipeline=$True)] 3187 | $ComputerName, 3188 | 3189 | [ValidateRange(1,100)] 3190 | [Int] 3191 | $Threads=4 3192 | 3193 | ) 3194 | Process 3195 | { 3196 | $sb = [scriptblock] { param($ComputerName) if( -Not $ComputerName) 3197 | { 3198 | $ComputerName = $env:computername 3199 | } 3200 | # execute with cred object 3201 | if ($Credential) 3202 | { 3203 | # execute with cred object 3204 | try 3205 | { 3206 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_COMSetting -computername $ComputerName -credential $Credential 3207 | if ($wmi){ 3208 | return $ComputerName 3209 | } 3210 | else{ 3211 | } 3212 | } 3213 | catch 3214 | { 3215 | } 3216 | } 3217 | elseif ($User -and $Password) 3218 | { 3219 | # execute with built credential object 3220 | $Password = ConvertTo-SecureString $Password -AsPlainText -Force 3221 | $Credential = New-Object -typename System.Management.Automation.PSCredential -argumentlist $UserName, $Password 3222 | try 3223 | { 3224 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_COMSetting -computername $ComputerName -credential $Credential -EA Stop 3225 | if ($wmi){ 3226 | return $ComputerName 3227 | } 3228 | else{ 3229 | } 3230 | } 3231 | catch 3232 | { 3233 | } 3234 | } 3235 | else 3236 | { 3237 | try 3238 | { 3239 | # execute in current user context 3240 | $Wmi = Get-WmiObject -Namespace "root\cimv2" -Class Win32_COMSetting -computername $ComputerName -EA Stop 3241 | if ($wmi){ 3242 | return $ComputerName 3243 | } 3244 | else{ 3245 | } 3246 | } 3247 | catch 3248 | { 3249 | } 3250 | 3251 | } 3252 | } # end of script block 3253 | $ScriptParams = @{ 3254 | 'Computers' = $ComputerName 3255 | } 3256 | Invoke-ThreadedFunction -ComputerName $ComputerName -ScriptBlock $sb -Threads $Threads 3257 | } 3258 | } 3259 | 3260 | function Invoke-ThreadedFunction { 3261 | # Helper used by any threaded host enumeration functions 3262 | [CmdletBinding()] 3263 | param( 3264 | [Parameter(Position=0,Mandatory=$True)] 3265 | [String[]] 3266 | $ComputerName, 3267 | 3268 | [Parameter(Position=1,Mandatory=$True)] 3269 | [System.Management.Automation.ScriptBlock] 3270 | $ScriptBlock, 3271 | 3272 | [Parameter(Position=2)] 3273 | [Hashtable] 3274 | $ScriptParameters, 3275 | 3276 | [Int] 3277 | $Threads = 20, 3278 | 3279 | [Switch] 3280 | $NoImports 3281 | ) 3282 | 3283 | begin { 3284 | 3285 | if ($PSBoundParameters['Debug']) { 3286 | $DebugPreference = 'Continue' 3287 | } 3288 | 3289 | Write-Verbose "[*] Total number of hosts: $($ComputerName.count)" 3290 | 3291 | # Adapted from: 3292 | # http://powershell.org/wp/forums/topic/invpke-parallel-need-help-to-clone-the-current-runspace/ 3293 | $SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault() 3294 | $SessionState.ApartmentState = [System.Threading.Thread]::CurrentThread.GetApartmentState() 3295 | 3296 | # import the current session state's variables and functions so the chained PowerView 3297 | # functionality can be used by the threaded blocks 3298 | if(!$NoImports) { 3299 | 3300 | # grab all the current variables for this runspace 3301 | $MyVars = Get-Variable -Scope 2 3302 | 3303 | # these Variables are added by Runspace.Open() Method and produce Stop errors if you add them twice 3304 | $VorbiddenVars = @("?","args","ConsoleFileName","Error","ExecutionContext","false","HOME","Host","input","InputObject","MaximumAliasCount","MaximumDriveCount","MaximumErrorCount","MaximumFunctionCount","MaximumHistoryCount","MaximumVariableCount","MyInvocation","null","PID","PSBoundParameters","PSCommandPath","PSCulture","PSDefaultParameterValues","PSHOME","PSScriptRoot","PSUICulture","PSVersionTable","PWD","ShellId","SynchronizedHash","true") 3305 | 3306 | # Add Variables from Parent Scope (current runspace) into the InitialSessionState 3307 | ForEach($Var in $MyVars) { 3308 | if($VorbiddenVars -NotContains $Var.Name) { 3309 | $SessionState.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $Var.name,$Var.Value,$Var.description,$Var.options,$Var.attributes)) 3310 | } 3311 | } 3312 | 3313 | # Add Functions from current runspace to the InitialSessionState 3314 | ForEach($Function in (Get-ChildItem Function:)) { 3315 | $SessionState.Commands.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $Function.Name, $Function.Definition)) 3316 | } 3317 | } 3318 | 3319 | # threading adapted from 3320 | # https://github.com/darkoperator/Posh-SecMod/blob/master/Discovery/Discovery.psm1#L407 3321 | # Thanks Carlos! 3322 | 3323 | # create a pool of maxThread runspaces 3324 | $Pool = [runspacefactory]::CreateRunspacePool(1, $Threads, $SessionState, $Host) 3325 | $Pool.Open() 3326 | 3327 | $Jobs = @() 3328 | $PS = @() 3329 | $Wait = @() 3330 | 3331 | $Counter = 0 3332 | } 3333 | 3334 | process { 3335 | 3336 | ForEach ($Computer in $ComputerName) { 3337 | 3338 | # make sure we get a server name 3339 | if ($Computer -ne '') { 3340 | # Write-Verbose "[*] Enumerating server $Computer ($($Counter+1) of $($ComputerName.count))" 3341 | 3342 | While ($($Pool.GetAvailableRunspaces()) -le 0) { 3343 | Start-Sleep -MilliSeconds 500 3344 | } 3345 | 3346 | # create a "powershell pipeline runner" 3347 | $PS += [powershell]::create() 3348 | 3349 | $PS[$Counter].runspacepool = $Pool 3350 | 3351 | # add the script block + arguments 3352 | $Null = $PS[$Counter].AddScript($ScriptBlock).AddParameter('ComputerName', $Computer) 3353 | if($ScriptParameters) { 3354 | ForEach ($Param in $ScriptParameters.GetEnumerator()) { 3355 | $Null = $PS[$Counter].AddParameter($Param.Name, $Param.Value) 3356 | } 3357 | } 3358 | 3359 | # start job 3360 | $Jobs += $PS[$Counter].BeginInvoke(); 3361 | 3362 | # store wait handles for WaitForAll call 3363 | $Wait += $Jobs[$Counter].AsyncWaitHandle 3364 | } 3365 | $Counter = $Counter + 1 3366 | } 3367 | } 3368 | 3369 | end { 3370 | 3371 | Write-Verbose "Waiting for scanning threads to finish..." 3372 | 3373 | $WaitTimeout = Get-Date 3374 | 3375 | # set a 60 second timeout for the scanning threads 3376 | while ($($Jobs | Where-Object {$_.IsCompleted -eq $False}).count -gt 0 -or $($($(Get-Date) - $WaitTimeout).totalSeconds) -gt 60) { 3377 | Start-Sleep -MilliSeconds 500 3378 | } 3379 | 3380 | # end async call 3381 | for ($y = 0; $y -lt $Counter; $y++) { 3382 | 3383 | try { 3384 | # complete async job 3385 | $PS[$y].EndInvoke($Jobs[$y]) 3386 | 3387 | } catch { 3388 | Write-Warning "error: $_" 3389 | } 3390 | finally { 3391 | $PS[$y].Dispose() 3392 | } 3393 | } 3394 | 3395 | $Pool.Dispose() 3396 | Write-Verbose "All threads completed!" 3397 | } 3398 | } 3399 | 3400 | 3401 | 3402 | function Invoke-Ping { 3403 | # Invoke-Ping adapted from RamblingCookieMonster's code at 3404 | # https://github.com/RamblingCookieMonster/PowerShell/blob/master/Invoke-Ping.ps1 3405 | <# 3406 | .SYNOPSIS 3407 | Ping systems in parallel 3408 | Author: RamblingCookieMonster 3409 | 3410 | .PARAMETER ComputerName 3411 | One or more computers to test 3412 | 3413 | .PARAMETER Timeout 3414 | Time in seconds before we attempt to dispose an individual query. Default is 20 3415 | 3416 | .PARAMETER Throttle 3417 | Throttle query to this many parallel runspaces. Default is 100. 3418 | 3419 | .PARAMETER NoCloseOnTimeout 3420 | Do not dispose of timed out tasks or attempt to close the runspace if threads have timed out 3421 | 3422 | This will prevent the script from hanging in certain situations where threads become non-responsive, at the expense of leaking memory within the PowerShell host. 3423 | 3424 | .EXAMPLE 3425 | $Responding = $Computers | Invoke-Ping 3426 | 3427 | # Create a list of computers that successfully responded to Test-Connection 3428 | 3429 | .LINK 3430 | https://github.com/RamblingCookieMonster/PowerShell/blob/master/Invoke-Ping.ps1 3431 | https://gallery.technet.microsoft.com/scriptcenter/Invoke-Ping-Test-in-b553242a 3432 | #> 3433 | 3434 | [cmdletbinding(DefaultParameterSetName='Ping')] 3435 | param( 3436 | [Parameter( ValueFromPipeline=$true, 3437 | ValueFromPipelineByPropertyName=$true, 3438 | Position=0)] 3439 | [string[]]$ComputerName, 3440 | 3441 | [int]$Timeout = 20, 3442 | 3443 | [int]$Throttle = 100, 3444 | 3445 | [switch]$NoCloseOnTimeout 3446 | ) 3447 | 3448 | Begin 3449 | { 3450 | $Quiet = $True 3451 | 3452 | #http://gallery.technet.microsoft.com/Run-Parallel-Parallel-377fd430 3453 | function Invoke-Parallel { 3454 | [cmdletbinding(DefaultParameterSetName='ScriptBlock')] 3455 | Param ( 3456 | [Parameter(Mandatory=$false,position=0,ParameterSetName='ScriptBlock')] 3457 | [System.Management.Automation.ScriptBlock]$ScriptBlock, 3458 | 3459 | [Parameter(Mandatory=$false,ParameterSetName='ScriptFile')] 3460 | [ValidateScript({test-path $_ -pathtype leaf})] 3461 | $ScriptFile, 3462 | 3463 | [Parameter(Mandatory=$true,ValueFromPipeline=$true)] 3464 | [Alias('CN','__Server','IPAddress','Server','ComputerName')] 3465 | [PSObject]$InputObject, 3466 | 3467 | [PSObject]$Parameter, 3468 | 3469 | [switch]$ImportVariables, 3470 | 3471 | [switch]$ImportModules, 3472 | 3473 | [int]$Throttle = 20, 3474 | 3475 | [int]$SleepTimer = 200, 3476 | 3477 | [int]$RunspaceTimeout = 0, 3478 | 3479 | [switch]$NoCloseOnTimeout = $false, 3480 | 3481 | [int]$MaxQueue, 3482 | 3483 | [validatescript({Test-Path (Split-Path $_ -parent)})] 3484 | [string]$LogFile = "C:\temp\log.log", 3485 | 3486 | [switch] $Quiet = $false 3487 | ) 3488 | 3489 | Begin { 3490 | 3491 | #No max queue specified? Estimate one. 3492 | #We use the script scope to resolve an odd PowerShell 2 issue where MaxQueue isn't seen later in the function 3493 | if( -not $PSBoundParameters.ContainsKey('MaxQueue') ) 3494 | { 3495 | if($RunspaceTimeout -ne 0){ $script:MaxQueue = $Throttle } 3496 | else{ $script:MaxQueue = $Throttle * 3 } 3497 | } 3498 | else 3499 | { 3500 | $script:MaxQueue = $MaxQueue 3501 | } 3502 | 3503 | Write-Verbose "Throttle: '$throttle' SleepTimer '$sleepTimer' runSpaceTimeout '$runspaceTimeout' maxQueue '$maxQueue' logFile '$logFile'" 3504 | 3505 | #If they want to import variables or modules, create a clean runspace, get loaded items, use those to exclude items 3506 | if ($ImportVariables -or $ImportModules) 3507 | { 3508 | $StandardUserEnv = [powershell]::Create().addscript({ 3509 | 3510 | #Get modules and snapins in this clean runspace 3511 | $Modules = Get-Module | Select -ExpandProperty Name 3512 | $Snapins = Get-PSSnapin | Select -ExpandProperty Name 3513 | 3514 | #Get variables in this clean runspace 3515 | #Called last to get vars like $? into session 3516 | $Variables = Get-Variable | Select -ExpandProperty Name 3517 | 3518 | #Return a hashtable where we can access each. 3519 | @{ 3520 | Variables = $Variables 3521 | Modules = $Modules 3522 | Snapins = $Snapins 3523 | } 3524 | }).invoke()[0] 3525 | 3526 | if ($ImportVariables) { 3527 | #Exclude common parameters, bound parameters, and automatic variables 3528 | Function _temp {[cmdletbinding()] param() } 3529 | $VariablesToExclude = @( (Get-Command _temp | Select -ExpandProperty parameters).Keys + $PSBoundParameters.Keys + $StandardUserEnv.Variables ) 3530 | Write-Verbose "Excluding variables $( ($VariablesToExclude | sort ) -join ", ")" 3531 | 3532 | # we don't use 'Get-Variable -Exclude', because it uses regexps. 3533 | # One of the veriables that we pass is '$?'. 3534 | # There could be other variables with such problems. 3535 | # Scope 2 required if we move to a real module 3536 | $UserVariables = @( Get-Variable | Where { -not ($VariablesToExclude -contains $_.Name) } ) 3537 | Write-Verbose "Found variables to import: $( ($UserVariables | Select -expandproperty Name | Sort ) -join ", " | Out-String).`n" 3538 | 3539 | } 3540 | 3541 | if ($ImportModules) 3542 | { 3543 | $UserModules = @( Get-Module | Where {$StandardUserEnv.Modules -notcontains $_.Name -and (Test-Path $_.Path -ErrorAction SilentlyContinue)} | Select -ExpandProperty Path ) 3544 | $UserSnapins = @( Get-PSSnapin | Select -ExpandProperty Name | Where {$StandardUserEnv.Snapins -notcontains $_ } ) 3545 | } 3546 | } 3547 | 3548 | #region functions 3549 | 3550 | Function Get-RunspaceData { 3551 | [cmdletbinding()] 3552 | param( [switch]$Wait ) 3553 | 3554 | #loop through runspaces 3555 | #if $wait is specified, keep looping until all complete 3556 | Do { 3557 | 3558 | #set more to false for tracking completion 3559 | $more = $false 3560 | 3561 | #run through each runspace. 3562 | Foreach($runspace in $runspaces) { 3563 | 3564 | #get the duration - inaccurate 3565 | $currentdate = Get-Date 3566 | $runtime = $currentdate - $runspace.startTime 3567 | $runMin = [math]::Round( $runtime.totalminutes ,2 ) 3568 | 3569 | #set up log object 3570 | $log = "" | select Date, Action, Runtime, Status, Details 3571 | $log.Action = "Removing:'$($runspace.object)'" 3572 | $log.Date = $currentdate 3573 | $log.Runtime = "$runMin minutes" 3574 | 3575 | #If runspace completed, end invoke, dispose, recycle, counter++ 3576 | If ($runspace.Runspace.isCompleted) { 3577 | 3578 | $script:completedCount++ 3579 | 3580 | #check if there were errors 3581 | if($runspace.powershell.Streams.Error.Count -gt 0) { 3582 | 3583 | #set the logging info and move the file to completed 3584 | $log.status = "CompletedWithErrors" 3585 | Write-Verbose ($log | ConvertTo-Csv -Delimiter ";" -NoTypeInformation)[1] 3586 | foreach($ErrorRecord in $runspace.powershell.Streams.Error) { 3587 | Write-Error -ErrorRecord $ErrorRecord 3588 | } 3589 | } 3590 | else { 3591 | 3592 | #add logging details and cleanup 3593 | $log.status = "Completed" 3594 | Write-Verbose ($log | ConvertTo-Csv -Delimiter ";" -NoTypeInformation)[1] 3595 | } 3596 | 3597 | #everything is logged, clean up the runspace 3598 | $runspace.powershell.EndInvoke($runspace.Runspace) 3599 | $runspace.powershell.dispose() 3600 | $runspace.Runspace = $null 3601 | $runspace.powershell = $null 3602 | 3603 | } 3604 | 3605 | #If runtime exceeds max, dispose the runspace 3606 | ElseIf ( $runspaceTimeout -ne 0 -and $runtime.totalseconds -gt $runspaceTimeout) { 3607 | 3608 | $script:completedCount++ 3609 | $timedOutTasks = $true 3610 | 3611 | #add logging details and cleanup 3612 | $log.status = "TimedOut" 3613 | Write-Verbose ($log | ConvertTo-Csv -Delimiter ";" -NoTypeInformation)[1] 3614 | Write-Error "Runspace timed out at $($runtime.totalseconds) seconds for the object:`n$($runspace.object | out-string)" 3615 | 3616 | #Depending on how it hangs, we could still get stuck here as dispose calls a synchronous method on the powershell instance 3617 | if (!$noCloseOnTimeout) { $runspace.powershell.dispose() } 3618 | $runspace.Runspace = $null 3619 | $runspace.powershell = $null 3620 | $completedCount++ 3621 | 3622 | } 3623 | 3624 | #If runspace isn't null set more to true 3625 | ElseIf ($runspace.Runspace -ne $null ) { 3626 | $log = $null 3627 | $more = $true 3628 | } 3629 | 3630 | #log the results if a log file was indicated 3631 | if($logFile -and $log){ 3632 | ($log | ConvertTo-Csv -Delimiter ";" -NoTypeInformation)[1] | out-file $LogFile -append 3633 | } 3634 | } 3635 | 3636 | #Clean out unused runspace jobs 3637 | $temphash = $runspaces.clone() 3638 | $temphash | Where { $_.runspace -eq $Null } | ForEach { 3639 | $Runspaces.remove($_) 3640 | } 3641 | 3642 | #sleep for a bit if we will loop again 3643 | if($PSBoundParameters['Wait']){ Start-Sleep -milliseconds $SleepTimer } 3644 | 3645 | #Loop again only if -wait parameter and there are more runspaces to process 3646 | } while ($more -and $PSBoundParameters['Wait']) 3647 | 3648 | #End of runspace function 3649 | } 3650 | 3651 | #endregion functions 3652 | 3653 | #region Init 3654 | 3655 | if($PSCmdlet.ParameterSetName -eq 'ScriptFile') 3656 | { 3657 | $ScriptBlock = [scriptblock]::Create( $(Get-Content $ScriptFile | out-string) ) 3658 | } 3659 | elseif($PSCmdlet.ParameterSetName -eq 'ScriptBlock') 3660 | { 3661 | #Start building parameter names for the param block 3662 | [string[]]$ParamsToAdd = '$_' 3663 | if( $PSBoundParameters.ContainsKey('Parameter') ) 3664 | { 3665 | $ParamsToAdd += '$Parameter' 3666 | } 3667 | 3668 | $UsingVariableData = $Null 3669 | 3670 | # This code enables $Using support through the AST. 3671 | # This is entirely from Boe Prox, and his https://github.com/proxb/PoshRSJob module; all credit to Boe! 3672 | 3673 | if($PSVersionTable.PSVersion.Major -gt 2) 3674 | { 3675 | #Extract using references 3676 | $UsingVariables = $ScriptBlock.ast.FindAll({$args[0] -is [System.Management.Automation.Language.UsingExpressionAst]},$True) 3677 | 3678 | If ($UsingVariables) 3679 | { 3680 | $List = New-Object 'System.Collections.Generic.List`1[System.Management.Automation.Language.VariableExpressionAst]' 3681 | ForEach ($Ast in $UsingVariables) 3682 | { 3683 | [void]$list.Add($Ast.SubExpression) 3684 | } 3685 | 3686 | $UsingVar = $UsingVariables | Group Parent | ForEach {$_.Group | Select -First 1} 3687 | 3688 | #Extract the name, value, and create replacements for each 3689 | $UsingVariableData = ForEach ($Var in $UsingVar) { 3690 | Try 3691 | { 3692 | $Value = Get-Variable -Name $Var.SubExpression.VariablePath.UserPath -ErrorAction Stop 3693 | $NewName = ('$__using_{0}' -f $Var.SubExpression.VariablePath.UserPath) 3694 | [pscustomobject]@{ 3695 | Name = $Var.SubExpression.Extent.Text 3696 | Value = $Value.Value 3697 | NewName = $NewName 3698 | NewVarName = ('__using_{0}' -f $Var.SubExpression.VariablePath.UserPath) 3699 | } 3700 | $ParamsToAdd += $NewName 3701 | } 3702 | Catch 3703 | { 3704 | Write-Error "$($Var.SubExpression.Extent.Text) is not a valid Using: variable!" 3705 | } 3706 | } 3707 | 3708 | $NewParams = $UsingVariableData.NewName -join ', ' 3709 | $Tuple = [Tuple]::Create($list, $NewParams) 3710 | $bindingFlags = [Reflection.BindingFlags]"Default,NonPublic,Instance" 3711 | $GetWithInputHandlingForInvokeCommandImpl = ($ScriptBlock.ast.gettype().GetMethod('GetWithInputHandlingForInvokeCommandImpl',$bindingFlags)) 3712 | 3713 | $StringScriptBlock = $GetWithInputHandlingForInvokeCommandImpl.Invoke($ScriptBlock.ast,@($Tuple)) 3714 | 3715 | $ScriptBlock = [scriptblock]::Create($StringScriptBlock) 3716 | 3717 | Write-Verbose $StringScriptBlock 3718 | } 3719 | } 3720 | 3721 | $ScriptBlock = $ExecutionContext.InvokeCommand.NewScriptBlock("param($($ParamsToAdd -Join ", "))`r`n" + $Scriptblock.ToString()) 3722 | } 3723 | else 3724 | { 3725 | Throw "Must provide ScriptBlock or ScriptFile"; Break 3726 | } 3727 | 3728 | Write-Debug "`$ScriptBlock: $($ScriptBlock | Out-String)" 3729 | Write-Verbose "Creating runspace pool and session states" 3730 | 3731 | #If specified, add variables and modules/snapins to session state 3732 | $sessionstate = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault() 3733 | if ($ImportVariables) 3734 | { 3735 | if($UserVariables.count -gt 0) 3736 | { 3737 | foreach($Variable in $UserVariables) 3738 | { 3739 | $sessionstate.Variables.Add( (New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $Variable.Name, $Variable.Value, $null) ) 3740 | } 3741 | } 3742 | } 3743 | if ($ImportModules) 3744 | { 3745 | if($UserModules.count -gt 0) 3746 | { 3747 | foreach($ModulePath in $UserModules) 3748 | { 3749 | $sessionstate.ImportPSModule($ModulePath) 3750 | } 3751 | } 3752 | if($UserSnapins.count -gt 0) 3753 | { 3754 | foreach($PSSnapin in $UserSnapins) 3755 | { 3756 | [void]$sessionstate.ImportPSSnapIn($PSSnapin, [ref]$null) 3757 | } 3758 | } 3759 | } 3760 | 3761 | #Create runspace pool 3762 | $runspacepool = [runspacefactory]::CreateRunspacePool(1, $Throttle, $sessionstate, $Host) 3763 | $runspacepool.Open() 3764 | 3765 | Write-Verbose "Creating empty collection to hold runspace jobs" 3766 | $Script:runspaces = New-Object System.Collections.ArrayList 3767 | 3768 | #If inputObject is bound get a total count and set bound to true 3769 | $global:__bound = $false 3770 | $allObjects = @() 3771 | if( $PSBoundParameters.ContainsKey("inputObject") ){ 3772 | $global:__bound = $true 3773 | } 3774 | 3775 | #Set up log file if specified 3776 | if( $LogFile ){ 3777 | New-Item -ItemType file -path $logFile -force | Out-Null 3778 | ("" | Select Date, Action, Runtime, Status, Details | ConvertTo-Csv -NoTypeInformation -Delimiter ";")[0] | Out-File $LogFile 3779 | } 3780 | 3781 | #write initial log entry 3782 | $log = "" | Select Date, Action, Runtime, Status, Details 3783 | $log.Date = Get-Date 3784 | $log.Action = "Batch processing started" 3785 | $log.Runtime = $null 3786 | $log.Status = "Started" 3787 | $log.Details = $null 3788 | if($logFile) { 3789 | ($log | convertto-csv -Delimiter ";" -NoTypeInformation)[1] | Out-File $LogFile -Append 3790 | } 3791 | 3792 | $timedOutTasks = $false 3793 | 3794 | #endregion INIT 3795 | } 3796 | 3797 | Process { 3798 | #add piped objects to all objects or set all objects to bound input object parameter 3799 | if( -not $global:__bound ){ 3800 | $allObjects += $inputObject 3801 | } 3802 | else{ 3803 | $allObjects = $InputObject 3804 | } 3805 | } 3806 | 3807 | End { 3808 | 3809 | #Use Try/Finally to catch Ctrl+C and clean up. 3810 | Try 3811 | { 3812 | #counts for progress 3813 | $totalCount = $allObjects.count 3814 | $script:completedCount = 0 3815 | $startedCount = 0 3816 | 3817 | foreach($object in $allObjects){ 3818 | 3819 | #region add scripts to runspace pool 3820 | 3821 | #Create the powershell instance, set verbose if needed, supply the scriptblock and parameters 3822 | $powershell = [powershell]::Create() 3823 | 3824 | if ($VerbosePreference -eq 'Continue') 3825 | { 3826 | [void]$PowerShell.AddScript({$VerbosePreference = 'Continue'}) 3827 | } 3828 | 3829 | [void]$PowerShell.AddScript($ScriptBlock).AddArgument($object) 3830 | 3831 | if ($parameter) 3832 | { 3833 | [void]$PowerShell.AddArgument($parameter) 3834 | } 3835 | 3836 | # $Using support from Boe Prox 3837 | if ($UsingVariableData) 3838 | { 3839 | Foreach($UsingVariable in $UsingVariableData) { 3840 | Write-Verbose "Adding $($UsingVariable.Name) with value: $($UsingVariable.Value)" 3841 | [void]$PowerShell.AddArgument($UsingVariable.Value) 3842 | } 3843 | } 3844 | 3845 | #Add the runspace into the powershell instance 3846 | $powershell.RunspacePool = $runspacepool 3847 | 3848 | #Create a temporary collection for each runspace 3849 | $temp = "" | Select-Object PowerShell, StartTime, object, Runspace 3850 | $temp.PowerShell = $powershell 3851 | $temp.StartTime = Get-Date 3852 | $temp.object = $object 3853 | 3854 | #Save the handle output when calling BeginInvoke() that will be used later to end the runspace 3855 | $temp.Runspace = $powershell.BeginInvoke() 3856 | $startedCount++ 3857 | 3858 | #Add the temp tracking info to $runspaces collection 3859 | Write-Verbose ( "Adding {0} to collection at {1}" -f $temp.object, $temp.starttime.tostring() ) 3860 | $runspaces.Add($temp) | Out-Null 3861 | 3862 | #loop through existing runspaces one time 3863 | Get-RunspaceData 3864 | 3865 | #If we have more running than max queue (used to control timeout accuracy) 3866 | #Script scope resolves odd PowerShell 2 issue 3867 | $firstRun = $true 3868 | while ($runspaces.count -ge $Script:MaxQueue) { 3869 | 3870 | #give verbose output 3871 | if($firstRun){ 3872 | Write-Verbose "$($runspaces.count) items running - exceeded $Script:MaxQueue limit." 3873 | } 3874 | $firstRun = $false 3875 | 3876 | #run get-runspace data and sleep for a short while 3877 | Get-RunspaceData 3878 | Start-Sleep -Milliseconds $sleepTimer 3879 | } 3880 | #endregion add scripts to runspace pool 3881 | } 3882 | 3883 | Write-Verbose ( "Finish processing the remaining runspace jobs: {0}" -f ( @($runspaces | Where {$_.Runspace -ne $Null}).Count) ) 3884 | Get-RunspaceData -wait 3885 | } 3886 | Finally 3887 | { 3888 | #Close the runspace pool, unless we specified no close on timeout and something timed out 3889 | if ( ($timedOutTasks -eq $false) -or ( ($timedOutTasks -eq $true) -and ($noCloseOnTimeout -eq $false) ) ) { 3890 | Write-Verbose "Closing the runspace pool" 3891 | $runspacepool.close() 3892 | } 3893 | #collect garbage 3894 | [gc]::Collect() 3895 | } 3896 | } 3897 | } 3898 | 3899 | Write-Verbose "PSBoundParameters = $($PSBoundParameters | Out-String)" 3900 | 3901 | $bound = $PSBoundParameters.keys -contains "ComputerName" 3902 | if(-not $bound) 3903 | { 3904 | [System.Collections.ArrayList]$AllComputers = @() 3905 | } 3906 | } 3907 | Process 3908 | { 3909 | #Handle both pipeline and bound parameter. We don't want to stream objects, defeats purpose of parallelizing work 3910 | if($bound) 3911 | { 3912 | $AllComputers = $ComputerName 3913 | } 3914 | Else 3915 | { 3916 | foreach($Computer in $ComputerName) 3917 | { 3918 | $AllComputers.add($Computer) | Out-Null 3919 | } 3920 | } 3921 | } 3922 | End 3923 | { 3924 | #Built up the parameters and run everything in parallel 3925 | $params = @() 3926 | $splat = @{ 3927 | Throttle = $Throttle 3928 | RunspaceTimeout = $Timeout 3929 | InputObject = $AllComputers 3930 | } 3931 | if($NoCloseOnTimeout) 3932 | { 3933 | $splat.add('NoCloseOnTimeout',$True) 3934 | } 3935 | 3936 | Invoke-Parallel @splat -ScriptBlock { 3937 | $computer = $_.trim() 3938 | Try 3939 | { 3940 | #Pick out a few properties, add a status label. If quiet output, just return the address 3941 | $result = $null 3942 | if( $result = @( Test-Connection -ComputerName $computer -Count 1 -erroraction Stop ) ) 3943 | { 3944 | $Output = $result | Select -first 1 -Property Address, IPV4Address, IPV6Address, ResponseTime, @{ label = "STATUS"; expression = {"Responding"} } 3945 | $Output.address 3946 | } 3947 | } 3948 | Catch 3949 | { 3950 | } 3951 | } 3952 | } 3953 | } 3954 | function Get-DomainSearcher { 3955 | <# 3956 | .SYNOPSIS 3957 | Helper used by various functions that takes an ADSpath and 3958 | domain specifier and builds the correct ADSI searcher object. 3959 | .PARAMETER Domain 3960 | The domain to use for the query, defaults to the current domain. 3961 | .PARAMETER DomainController 3962 | Domain controller to reflect LDAP queries through. 3963 | .PARAMETER ADSpath 3964 | The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local" 3965 | Useful for OU queries. 3966 | .PARAMETER ADSprefix 3967 | Prefix to set for the searcher (like "CN=Sites,CN=Configuration") 3968 | .PARAMETER PageSize 3969 | The PageSize to set for the LDAP searcher object. 3970 | .EXAMPLE 3971 | PS C:\> Get-DomainSearcher -Domain testlab.local 3972 | .EXAMPLE 3973 | PS C:\> Get-DomainSearcher -Domain testlab.local -DomainController SECONDARY.dev.testlab.local 3974 | #> 3975 | 3976 | [CmdletBinding()] 3977 | param( 3978 | [String] 3979 | $Domain, 3980 | 3981 | [String] 3982 | $DomainController, 3983 | 3984 | [String] 3985 | $ADSpath, 3986 | 3987 | [String] 3988 | $ADSprefix, 3989 | 3990 | [ValidateRange(1,10000)] 3991 | [Int] 3992 | $PageSize = 200 3993 | ) 3994 | 3995 | if(!$Domain) { 3996 | $Domain = (Get-NetDomain).name 3997 | } 3998 | else { 3999 | if(!$DomainController) { 4000 | try { 4001 | # if there's no -DomainController specified, try to pull the primary DC 4002 | # to reflect queries through 4003 | $DomainController = ((Get-NetDomain).PdcRoleOwner).Name 4004 | } 4005 | catch { 4006 | throw "Get-DomainSearcher: Error in retrieving PDC for current domain" 4007 | } 4008 | } 4009 | } 4010 | 4011 | $SearchString = "LDAP://" 4012 | 4013 | if($DomainController) { 4014 | $SearchString += $DomainController + "/" 4015 | } 4016 | if($ADSprefix) { 4017 | $SearchString += $ADSprefix + "," 4018 | } 4019 | 4020 | if($ADSpath) { 4021 | if($ADSpath -like "GC://*") { 4022 | # if we're searching the global catalog 4023 | $DistinguishedName = $AdsPath 4024 | $SearchString = "" 4025 | } 4026 | else { 4027 | if($ADSpath -like "LDAP://*") { 4028 | $ADSpath = $ADSpath.Substring(7) 4029 | } 4030 | $DistinguishedName = $ADSpath 4031 | } 4032 | } 4033 | else { 4034 | $DistinguishedName = "DC=$($Domain.Replace('.', ',DC='))" 4035 | } 4036 | 4037 | $SearchString += $DistinguishedName 4038 | Write-Verbose "Get-DomainSearcher search string: $SearchString" 4039 | 4040 | $Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]$SearchString) 4041 | $Searcher.PageSize = $PageSize 4042 | $Searcher 4043 | } 4044 | function Get-NetComputer { 4045 | <# 4046 | .SYNOPSIS 4047 | This function utilizes adsisearcher to query the current AD context 4048 | for current computer objects. Based off of Carlos Perez's Audit.psm1 4049 | script in Posh-SecMod (link below). 4050 | .PARAMETER ComputerName 4051 | Return computers with a specific name, wildcards accepted. 4052 | .PARAMETER SPN 4053 | Return computers with a specific service principal name, wildcards accepted. 4054 | .PARAMETER OperatingSystem 4055 | Return computers with a specific operating system, wildcards accepted. 4056 | .PARAMETER ServicePack 4057 | Return computers with a specific service pack, wildcards accepted. 4058 | .PARAMETER Filter 4059 | A customized ldap filter string to use, e.g. "(description=*admin*)" 4060 | .PARAMETER Printers 4061 | Switch. Return only printers. 4062 | .PARAMETER Ping 4063 | Switch. Ping each host to ensure it's up before enumerating. 4064 | .PARAMETER FullData 4065 | Switch. Return full computer objects instead of just system names (the default). 4066 | .PARAMETER Domain 4067 | The domain to query for computers, defaults to the current domain. 4068 | .PARAMETER DomainController 4069 | Domain controller to reflect LDAP queries through. 4070 | .PARAMETER ADSpath 4071 | The LDAP source to search through, e.g. "LDAP://OU=secret,DC=testlab,DC=local" 4072 | Useful for OU queries. 4073 | .PARAMETER Unconstrained 4074 | Switch. Return computer objects that have unconstrained delegation. 4075 | .PARAMETER PageSize 4076 | The PageSize to set for the LDAP searcher object. 4077 | .EXAMPLE 4078 | PS C:\> Get-NetComputer 4079 | 4080 | Returns the current computers in current domain. 4081 | .EXAMPLE 4082 | PS C:\> Get-NetComputer -SPN mssql* 4083 | 4084 | Returns all MS SQL servers on the domain. 4085 | .EXAMPLE 4086 | PS C:\> Get-NetComputer -Domain testing 4087 | 4088 | Returns the current computers in 'testing' domain. 4089 | .EXAMPLE 4090 | PS C:\> Get-NetComputer -Domain testing -FullData 4091 | 4092 | Returns full computer objects in the 'testing' domain. 4093 | .LINK 4094 | https://github.com/darkoperator/Posh-SecMod/blob/master/Audit/Audit.psm1 4095 | #> 4096 | 4097 | [CmdletBinding()] 4098 | Param ( 4099 | [Parameter(ValueFromPipeline=$True)] 4100 | [Alias('HostName')] 4101 | [String] 4102 | $ComputerName = '*', 4103 | 4104 | [String] 4105 | $SPN, 4106 | 4107 | [String] 4108 | $OperatingSystem, 4109 | 4110 | [String] 4111 | $ServicePack, 4112 | 4113 | [String] 4114 | $Filter, 4115 | 4116 | [Switch] 4117 | $Printers, 4118 | 4119 | [Switch] 4120 | $Ping, 4121 | 4122 | [Switch] 4123 | $FullData, 4124 | 4125 | [String] 4126 | $Domain, 4127 | 4128 | [String] 4129 | $DomainController, 4130 | 4131 | [String] 4132 | $ADSpath, 4133 | 4134 | [Switch] 4135 | $Unconstrained, 4136 | 4137 | [ValidateRange(1,10000)] 4138 | [Int] 4139 | $PageSize = 200 4140 | ) 4141 | 4142 | begin { 4143 | # so this isn't repeated if users are passed on the pipeline 4144 | $CompSearcher = Get-DomainSearcher -Domain $Domain -DomainController $DomainController -ADSpath $ADSpath -PageSize $PageSize 4145 | } 4146 | 4147 | process { 4148 | 4149 | if ($CompSearcher) { 4150 | 4151 | # if we're checking for unconstrained delegation 4152 | if($Unconstrained) { 4153 | Write-Verbose "Searching for computers with for unconstrained delegation" 4154 | $Filter += "(userAccountControl:1.2.840.113556.1.4.803:=524288)" 4155 | } 4156 | # set the filters for the seracher if it exists 4157 | if($Printers) { 4158 | Write-Verbose "Searching for printers" 4159 | # $CompSearcher.filter="(&(objectCategory=printQueue)$Filter)" 4160 | $Filter += "(objectCategory=printQueue)" 4161 | } 4162 | if($SPN) { 4163 | Write-Verbose "Searching for computers with SPN: $SPN" 4164 | $Filter += "(servicePrincipalName=$SPN)" 4165 | } 4166 | if($OperatingSystem) { 4167 | $Filter += "(operatingsystem=$OperatingSystem)" 4168 | } 4169 | if($ServicePack) { 4170 | $Filter += "(operatingsystemservicepack=$ServicePack)" 4171 | } 4172 | 4173 | $CompSearcher.filter = "(&(sAMAccountType=805306369)(dnshostname=$ComputerName)$Filter)" 4174 | 4175 | try { 4176 | 4177 | $CompSearcher.FindAll() | Where-Object {$_} | ForEach-Object { 4178 | $Up = $True 4179 | if($Ping) { 4180 | # TODO: how can these results be piped to ping for a speedup? 4181 | $Up = Test-Connection -Count 1 -Quiet -ComputerName $_.properties.dnshostname 4182 | } 4183 | if($Up) { 4184 | # return full data objects 4185 | if ($FullData) { 4186 | # convert/process the LDAP fields for each result 4187 | Convert-LDAPProperty -Properties $_.Properties 4188 | } 4189 | else { 4190 | # otherwise we're just returning the DNS host name 4191 | $_.properties.dnshostname 4192 | } 4193 | } 4194 | } 4195 | } 4196 | catch { 4197 | Write-Warning "Error: $_" 4198 | } 4199 | } 4200 | } 4201 | } 4202 | function Convert-LDAPProperty { 4203 | # helper to convert specific LDAP property result fields 4204 | param( 4205 | [Parameter(Mandatory=$True,ValueFromPipeline=$True)] 4206 | [ValidateNotNullOrEmpty()] 4207 | $Properties 4208 | ) 4209 | 4210 | $ObjectProperties = @{} 4211 | 4212 | $Properties.PropertyNames | ForEach-Object { 4213 | if (($_ -eq "objectsid") -or ($_ -eq "sidhistory")) { 4214 | # convert the SID to a string 4215 | $ObjectProperties[$_] = (New-Object System.Security.Principal.SecurityIdentifier($Properties[$_][0],0)).Value 4216 | } 4217 | elseif($_ -eq "objectguid") { 4218 | # convert the GUID to a string 4219 | $ObjectProperties[$_] = (New-Object Guid (,$Properties[$_][0])).Guid 4220 | } 4221 | elseif( ($_ -eq "lastlogon") -or ($_ -eq "lastlogontimestamp") -or ($_ -eq "pwdlastset") -or ($_ -eq "lastlogoff") -or ($_ -eq "badPasswordTime") ) { 4222 | # convert timestamps 4223 | if ($Properties[$_][0] -is [System.MarshalByRefObject]) { 4224 | # if we have a System.__ComObject 4225 | $Temp = $Properties[$_][0] 4226 | [Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null) 4227 | [Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null) 4228 | $ObjectProperties[$_] = ([datetime]::FromFileTime([Int64]("0x{0:x8}{1:x8}" -f $High, $Low))) 4229 | } 4230 | else { 4231 | $ObjectProperties[$_] = ([datetime]::FromFileTime(($Properties[$_][0]))) 4232 | } 4233 | } 4234 | elseif($Properties[$_][0] -is [System.MarshalByRefObject]) { 4235 | # convert misc com objects 4236 | $Prop = $Properties[$_] 4237 | try { 4238 | $Temp = $Prop[$_][0] 4239 | Write-Verbose $_ 4240 | [Int32]$High = $Temp.GetType().InvokeMember("HighPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null) 4241 | [Int32]$Low = $Temp.GetType().InvokeMember("LowPart", [System.Reflection.BindingFlags]::GetProperty, $null, $Temp, $null) 4242 | $ObjectProperties[$_] = [Int64]("0x{0:x8}{1:x8}" -f $High, $Low) 4243 | } 4244 | catch { 4245 | $ObjectProperties[$_] = $Prop[$_] 4246 | } 4247 | } 4248 | elseif($Properties[$_].count -eq 1) { 4249 | $ObjectProperties[$_] = $Properties[$_][0] 4250 | } 4251 | else { 4252 | $ObjectProperties[$_] = $Properties[$_] 4253 | } 4254 | } 4255 | 4256 | New-Object -TypeName PSObject -Property $ObjectProperties 4257 | } 4258 | function Get-NetDomain { 4259 | <# 4260 | .SYNOPSIS 4261 | Returns a given domain object. 4262 | .PARAMETER Domain 4263 | The domain name to query for, defaults to the current domain. 4264 | .EXAMPLE 4265 | PS C:\> Get-NetDomain -Domain testlab.local 4266 | .LINK 4267 | http://social.technet.microsoft.com/Forums/scriptcenter/en-US/0c5b3f83-e528-4d49-92a4-dee31f4b481c/finding-the-dn-of-the-the-domain-without-admodule-in-powershell?forum=ITCG 4268 | #> 4269 | 4270 | [CmdletBinding()] 4271 | param( 4272 | [Parameter(ValueFromPipeline=$True)] 4273 | [String] 4274 | $Domain 4275 | ) 4276 | 4277 | process { 4278 | if($Domain) { 4279 | $DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext('Domain', $Domain) 4280 | try { 4281 | [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext) 4282 | } 4283 | catch { 4284 | Write-Warning "The specified domain $Domain does not exist, could not be contacted, or there isn't an existing trust." 4285 | $Null 4286 | } 4287 | } 4288 | else { 4289 | [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() 4290 | } 4291 | } 4292 | } 4293 | 4294 | 4295 | 4296 | --------------------------------------------------------------------------------