Skip to content

Instantly share code, notes, and snippets.

@pkutzner
Last active August 7, 2024 03:12
Show Gist options
  • Save pkutzner/b0a5ff825b7fc63c7ec7554205dd851f to your computer and use it in GitHub Desktop.
Save pkutzner/b0a5ff825b7fc63c7ec7554205dd851f to your computer and use it in GitHub Desktop.
Get various bits of info from endpoints.
[CmdletBinding(SupportsShouldProcess,DefaultParameterSetName='[INSERT]')]
Param (
[Parameter(ParameterSetName='Devices')]
$Devices,
[string[]]$Items = 'All',
[uint16]$MaxThreads = 20,
[uint16]$SleepTimer = 500,
[uint16]$MaxWaitAtEnd = 600,
[switch]$Progress,
[switch]$Batch
)
$IP4Regex = "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
$RegHive_Map = @{
"HKCR" = [uint32]"0x80000000"
"HKCU" = [uint32]"0x80000001"
"HKLM" = [uint32]"0x80000002"
"HKU" = [uint32]"0x80000003"
"HKCC" = [uint32]"0x80000005"
}
function Ping-Computer {
param (
[Parameter(Mandatory=$true)][string]$ComputerName,
[int]$TimeoutMS = 1500,
[switch]$Details,
[switch]$Progress = $script:Progress
)
$Filter = "Address=`"$($ComputerName)`" and Timeout=$($TimeoutMS)"
$Result = Get-WmiObject -Class Win32_PingStatus -Filter $Filter | Select-Object Address,ResponseTime
if ($Details) {
$Result
} else {
if ( -not [string]::IsNullOrEmpty($Result.ResponseTime) ) { $true } else { $false }
}
}
function Get-WSManStatus {
param (
[Parameter(Mandatory=$true)][string]$ComputerName
)
$result = Test-WSMan -ComputerName $ComputerName -ErrorAction SilentlyContinue
if ($result) {
return $true
} else {
return $false
}
}
Function Get-DecodedKey($key) {
$KeyOffset = 52
$IsWin8 = [int]($Key[66] / 6) -band 1
$HF7 = 0xF7
$Key[66] = ($Key[66] -band $HF7) -bor (($IsWin8 -band 2) * 4)
[string]$Map = "BCDFGHJKMPQRTVWXY2346789"
for ($i=24; $i -ge 0; $i--) {
$cur = 0
for ($j=14; $j -ge 0; $j--) {
$Cur = $Cur * 256
$Cur = $Key[$j + $KeyOffset] + $Cur
$Key[$j + $KeyOffset] = [math]::Floor([Double]($Cur / 24))
$Cur = $Cur % 24
}
$KeyOutput = $Map.Substring($Cur,1) + $KeyOutput
$Last = $Cur
}
$Keypart1 = $KeyOutput.Substring(1,$Last)
$Keypart2 = $KeyOutput.Substring(1,$KeyOutput.Length - 1)
if ($Last -eq 0) {
$KeyOutput = "N" + $Keypart2
} else {
$KeyOutput = $Keypart2.Insert($Keypart2.IndexOf($Keypart1) + $Keypart1.Length, "N")
}
$KeyProduct = ""
for ($i=0; $i -le 24; $i++) {
$KeyProduct = $KeyProduct + $KeyOutput[$i]
if ((($i + 1) % 5 -eq 0) -and ($i -ne 0) -and ($i -le 20)) {
$KeyProduct = $KeyProduct + "-"
}
}
return $KeyProduct
}
function Get-QUserInfo {
param (
[string]$ComputerName = $env:COMPUTERNAME
)
$Header = 'UserName','SessionName','ID','State','IdleTime','LogonTime'
$No_Connection = '-- No Connection --'
$Vacant = '-- Vacant --'
foreach ($CN_Item in $ComputerName) {
if (Test-Connection -ComputerName $CN_Item -Count 1 -Quiet) {
$Users = ((quser /server:$CN_Item 2>&1 | Select-Object -Skip 1) | Where-Object { $_ -imatch '(active|disc)' })
if ($Users.Count -gt 0) {
$UserInfo = $Users | ForEach-Object -Process {($_ -replace '\s{2,}',',').Trim()}
} else {
$UserInfo = "$Vacant,"*($Header.Count-1)+$Vacant
}
} else {
$UserInfo = "$No_Connection,"*($Header.Count-1)+$No_Connection
}
$UserInfo | ConvertFrom-Csv -Header $Header
}
}
function Write-ProgressHelper {
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)]
[string]$Title,
[string]$Message,
[string]$Operation,
[uint16]$StepNumber,
[uint16]$Steps = $script:Steps,
[uint16]$Id = 1,
[uint16]$ParentId,
[switch]$Completed
)
$Arguments = @{
'Activity' = $Title
'Id' = $Id
}
if ($ParentId) {
$Arguments += @{ParentID = $ParentId}
}
if (-not [string]::IsNullOrWhiteSpace($Message)) {
$Arguments += @{Status = $Message}
}
if (-not [string]::IsNullOrWhiteSpace($Operation)) {
$Arguments += @{CurrentOperation = $Operation}
}
if ($Completed) {
$Arguments += @{Completed = $Completed}
}
if ($StepNumber) {
$Arguments += @{PercentComplete = (($StepNumber / $Steps) * 100)}
}
Write-Progress @Arguments
}
function New-Connection {
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory)]
[string]$ComputerName
)
if (Ping-Computer -ComputerName $ComputerName) {
if (Get-WSManStatus -ComputerName $ComputerName) {
$SessionOption = New-CimSessionOption -Protocol Wsman
} else {
$SessionOption = New-CimSessionOption -Protocol Dcom
}
New-CimSession -ComputerName $ComputerName -SessionOption $SessionOption
} else {
Write-Error "Unable to establish CimSession" -ErrorAction Stop
}
}
function Get-ComputerSystem {
[CmdletBinding(SupportsShouldProcess,DefaultParameterSetName = 'ComputerName')]
param (
[Parameter(Mandatory,ParameterSetName = 'ComputerName')]
[string]$ComputerName,
[Parameter(Mandatory,ParameterSetName = 'CimSession')]
$CimSession,
[switch]$Progress = $script:Progress
)
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession = New-Connection -ComputerName $ComputerName
}
Get-CimInstance -CimSession $CimSession -ClassName Win32_ComputerSystem
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession | Remove-CimSession
}
}
function Get-Bios {
[CmdletBinding(SupportsShouldProcess,DefaultParameterSetName = 'ComputerName')]
param (
[Parameter(Mandatory,ParameterSetName = 'ComputerName')]
[string]$ComputerName,
[Parameter(Mandatory,ParameterSetName = 'CimSession')]
$CimSession,
[switch]$Progress = $script:Progress
)
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession = New-Connection -ComputerName $ComputerName
}
Get-CimInstance -CimSession $CimSession -ClassName Win32_Bios
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession | Remove-CimSession
}
}
function Get-Processor {
[CmdletBinding(SupportsShouldProcess,DefaultParameterSetName = 'ComputerName')]
param (
[Parameter(Mandatory,ParameterSetName = 'ComputerName')]
[string]$ComputerName,
[Parameter(Mandatory,ParameterSetName = 'CimSession')]
$CimSession,
[switch]$Progress = $script:Progress
)
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession = New-Connection -ComputerName $ComputerName
}
$Processor = Get-CimInstance -CimSession $CimSession -ClassName Win32_Processor
$_CPUs = @()
foreach ($cpu in $Processor) {
$o = [pscustomobject]@{
'Name' = $cpu.Name
'DeviceID' = $cpu.DeviceID
'CurrentVoltage' = "$($cpu.CurrentVoltage / 10)V"
'NumberOfCores' = $cpu.NumberOfCores
'NumberOfThreads' = $cpu.ThreadCount
'CurrentClockSpeed' = $cpu.CurrentClockSpeed
'L2CacheSize' = $cpu.L2CacheSize
'L3CacheSize' = $cpu.L3CacheSize
}
$_CPUs += $o
$_TotalCpuCores = $_TotalCpuCores + $cpu.NumberOfCores
$_TotalCpuThreads = $_TotalCpuThreads + $cpu.ThreadCount
}
$_CPUInfo = [pscustomobject]@{
'Model' = ($_CPUs.Name | Select -Unique) -join "|"
'TotalCPUs' = $_CPUs.Count
'TotalCores' = $_TotalCpuCores
'TotalThreads' = $_TotalCpuThreads
'CPUs' = $_CPUs
'LoadPercentage' = $Processor.LoadPercentage
}
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession | Remove-CimSession
}
$_CPUInfo
}
function Get-VideoController {
[CmdletBinding(SupportsShouldProcess,DefaultParameterSetName = 'ComputerName')]
param (
[Parameter(ParameterSetName = 'ComputerName')]
[string]$ComputerName = $env:COMPUTERNAME,
[Parameter(Mandatory,ParameterSetName = 'CimSession')]
$CimSession,
[switch]$Progress = $script:Progress
)
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession = New-Connection -ComputerName $ComputerName
}
Get-CimInstance -CimSession $CimSession -ClassName Win32_VideoController
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession | Remove-CimSession
}
}
function Get-DiskInfo {
[CmdletBinding(SupportsShouldProcess,DefaultParameterSetName = 'ComputerName')]
param (
[Parameter(ParameterSetName = 'ComputerName')]
[string]$ComputerName = $env:COMPUTERNAME,
[Parameter(Mandatory,ParameterSetName = 'CimSession')]
$CimSession,
[switch]$Progress = $script:Progress
)
$MyName = $PSCmdlet.CommandRuntime.ToString()
$StepCounter = 0
$NestLevel = (Get-PSCallStack).Count - 1
$Steps = ([System.Management.Automation.PSParser]::Tokenize((Get-Command $PSCmdlet.CommandRuntime).Definition, [ref]$null) | Where-Object {$_.Type -eq 'Command' -and $_.Content -eq 'Write-ProgressHelper'}).Count
$ProgressArgs = @{
Title = $MyName
Steps = $Steps
Id = $NestLevel
}
if ($NestLevel -gt 1) {
$ProgressArgs += @{ParentId = $NestLevel - 1}
}
$DriveType_map = @{
1 = 'Undetermined'
2 = 'Removable Disk'
3 = 'Local Hard Disk'
4 = 'Network Disk'
5 = 'Compact Disc'
6 = 'RAM Disk'
}
$BusType_map = @{
0 = 'Unknown'
1 = 'SCSI'
2 = 'ATAPI'
3 = 'ATA'
4 = 'IEEE 1394'
5 = 'SSA'
6 = 'Fibre Channel'
7 = 'USB'
8 = 'RAID'
9 = 'iSCSI'
10 = 'SAS'
11 = 'SATA'
12 = 'SD'
13 = 'MMC'
14 = 'MAX'
15 = 'File Backed Virtual'
16 = 'Storage Spaces'
17 = 'NVMe'
18 = 'Microsoft Reserved'
}
$MediaType_map = @{
0 = 'Unspecified'
1 = 'HDD'
2 = 'SSD'
3 = 'SCM'
}
$ProvisioningType_map = @{
0 = 'Unknown'
1 = 'Thin'
2 = 'Fixed'
}
$PartitionStyle_map = @{
0 = 'Unknown'
1 = 'MBR'
2 = 'GPT'
}
$ConversionStatus_map = @{
0 = 'Fully Decrypted'
1 = 'Fully Encrypted'
2 = 'Encryption in Progress'
3 = 'Decryption in Progress'
4 = 'Encryption Paused'
5 = 'Decryption Paused'
}
$EncryptionMethod_map = @{
0 = 'NOT ENCRYPTED'
1 = 'AES 128 WITH DIFFUSER'
2 = 'AES 256 WITH DIFFUSER'
3 = 'AES 128'
4 = 'AES 256'
5 = 'HARDWARE ENCRYPTION'
6 = 'XTS-AES 128'
7 = 'XTS-AES 256 WITH DIFFUSER'
}
$ProtectionStatus_map = @{
0 = 'PROTECTION OFF'
1 = 'PROTECTION ON'
2 = 'PROTECTION UNKNOWN'
}
$EncryptionFlags_map = @{
0 = 'Full Disk Encrption'
1 = 'Used Space Only Encryption'
}
$LockStatus_map = @{
0 = 'Unlocked'
1 = 'Locked'
}
$KeyProtector_map = @{
0 = 'Unknown or other protector type'
1 = 'Trusted Platform Module (TPM)'
2 = 'External Key'
3 = 'Numerical Password'
4 = 'TPM and PIN'
5 = 'TPM and Startup Key'
6 = 'TPM and PIN and Startup Key'
7 = 'Public Key'
8 = 'Passphrase'
9 = 'TPM Certificate'
10 = 'CryptoAPI Next Generation (CNG) Protector'
}
$DiskStatus_map = @{
0 = 'Healthy'
1 = 'Warning'
2 = 'Unhealthy'
5 = 'Unknown'
}
$SMARTNames_map = @{
0x00 = 'Invalid'
0x01 = 'Raw read error rate'
0x02 = 'Throughput performance'
0x03 = 'Spinup time'
0x04 = 'Start/Stop count'
0x05 = 'Reallocated sector count'
0x06 = 'Read channel margin'
0x07 = 'Seek error rate'
0x08 = 'Seek timer performance'
0x09 = 'Power-on hours count'
0x0A = 'Spinup retry count'
0x0B = 'Calibration retry count'
0x0C = 'Power cycle count'
0x0D = 'Soft read error rate'
0x16 = 'Current helium level'
0xAA = 'Available reserved space'
0xAB = 'Program fail count'
0xAC = 'Erase fail count'
0xAD = 'Wear leveling count'
0xAE = 'Unexpected power loss count'
0xAF = 'Power loss protection failure'
0xB0 = 'Erase fail count'
0xB1 = 'Wear range delta'
0xB3 = 'Used reserved block count'
0xB4 = 'Unused reserved block count'
0xB5 = 'Program fail count total / non-4k aligned access count'
0xB6 = 'Erase fail count'
0xB7 = 'SATA downshift error count / Runtime bad block'
0xB8 = 'End-to-End error'
0xB9 = 'Head stability'
0xBA = 'Induced Op-vibration detection'
0xBB = 'Reported uncorrectable errors'
0xBC = 'Command timeout'
0xBD = 'High fly writes'
0xBE = 'Airflow Temperature Celsius'
0xBF = 'G-sense error rate'
0xC0 = 'Power-off retract count'
0xC1 = 'Load/Unload cycle count'
0xC2 = 'HDD temperature'
0xC3 = 'Hardware ECC recoverd'
0xC4 = 'Reallocation count'
0xC5 = 'Current pending sector count'
0xC6 = 'Offline scan uncorrectable count'
0xC7 = 'UDMA CRC error rate'
0xC8 = 'Write error rate'
0xC9 = 'Soft read error rate'
0xCA = 'Data address mark errors'
0xCB = 'Run out cancel'
0xCC = 'Soft ECC Correction'
0xCD = 'Thermal asperity rate (TAR)'
0xCE = 'Flying height'
0xCF = 'Spin high current'
0xD0 = 'Spin buzz'
0xD1 = 'Offline seek performance'
0xD2 = 'Vibration during write'
0xD3 = 'Vibration during write' # During read? TODO: Double-check documentation that this isn't a typo
0xD4 = 'Shock durign write'
0xDC = 'Disk shift'
0xDD = 'G-sense error rate'
0xDE = 'Loaded hours'
0xDF = 'Load/unload retry count'
0xE0 = 'Load friction'
0xE1 = 'Load/unload cycle count'
0xE2 = 'Load-in time'
0xE3 = 'Torque amplification count'
0xE4 = 'Power-off retract count'
0xE6 = 'GMR head amplitude'
0xE7 = 'Temperature'
0xE8 = 'Endurance remaining / available reserved space'
0xE9 = 'Power-on hours / media wearout indicator'
0xEA = 'Average erase count / maximum erase count'
0xEB = 'Good block count / System free block count'
0xF0 = 'Head flying hours'
0xF1 = 'Total LBAs written'
0xF2 = 'Total LBAs read'
0xF3 = 'Total LBAs written expanded'
0xF4 = 'Total LBAs read expanded'
0xF9 = 'NAND writes 1GiB'
0xFA = 'Read error retry rate'
0xFB = 'Minimum spares remaining'
0xFC = 'Newly added bad flash block'
0xFE = 'Free fall protection'
}
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession = New-Connection -ComputerName $ComputerName
} else {
$ComputerName = $CimSession.ComputerName
}
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Logical Disks' -StepNumber ($StepCounter++) }
$Disks = Get-CimInstance -CimSession $CimSession -Namespace root\Microsoft\Windows\Storage -ClassName MSFT_Disk
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Physical Disks' -StepNumber ($StepCounter++) }
$PhysicalDisks = Get-CimInstance -CimSession $CimSession -Namespace root\Microsoft\Windows\Storage -ClassName MSFT_PhysicalDisk
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Storage Reliability Counters' -StepNumber ($StepCounter++) }
$StorageRelCount = $PhysicalDisks | Get-StorageReliabilityCounter -CimSession $CimSession
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Storage Failure Prediction Thresholds' -StepNumber ($StepCounter++) }
$FailPredThresh = Get-CimInstance -CimSession $CimSession -Namespace root\wmi -ClassName MSStorageDriver_FailurePredictThresholds -ErrorAction SilentlyContinue
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Storage Failure Prediction Data' -StepNumber ($StepCounter++) }
$FailPredData = Get-CimInstance -CimSession $CimSession -Namespace root\wmi -ClassName MSStorageDriver_FailurePredictData -ErrorAction SilentlyContinue
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Paritions' -StepNumber ($StepCounter++) }
$Partitions = Get-CimInstance -CimSession $CimSession -Namespace root\Microsoft\Windows\Storage -ClassName MSFT_Partition
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Volumes' -StepNumber ($StepCounter++) }
$Volumes = Get-CimInstance -CimSession $CimSession -Namespace root\Microsoft\Windows\Storage -ClassName MSFT_Volume
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting BitLocker Info' -StepNumber ($StepCounter++) }
$BitLocker = Get-CimInstance -CimSession $CimSession -Namespace root\CIMv2\Security\MicrosoftVolumeEncryption -ClassName Win32_EncryptableVolume
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting AD Bitlocker Info' -StepNumber ($StepCounter++) }
$BLADInfo = Get-ADObject -Filter {objectClass -eq 'msFVE-RecoveryInformation'} -SearchBase (Get-ADComputer -Identity $ComputerName).DistinguishedName -ErrorAction SilentlyContinue
$Info = @()
foreach ($Disk in $Disks) {
$p = @()
$v = @()
$_mediatype = $($DUID = $Disk.UniqueId; ($PhysicalDisks | Where-Object {$_.UniqueId -eq $DUID}).MediaType)
$_pdid = $($DUID = $Disk.UniqueId; ($PhysicalDisks | Where-Object {$_.UniqueId -eq $DUID}).DeviceId)
$_diskpath = $([regex]::Match($Disk.Path,'scsi#.*(?=#{)')).Value -replace '#','\'
$_fpt = $FailPredThresh | Where-Object {($_.InstanceName -replace '_0$','') -ieq $_diskpath}
$_fpd = $FailPredData | Where-Object {($_.InstanceName -replace '_0$','') -ieq $_diskpath}
$_pwronhrs = $($DID = $_pdid; ($StorageRelCount | Where-Object {$_.DeviceId -eq $DID}).PowerOnHours)
$_wear = $($DID = $_pdid; ($StorageRelCount | Where-Object {$_.DeviceId -eq $DID}).Wear)
$_readerru = $($DID = $_pdid; ($StorageRelCount | Where-Object {$_.DeviceId -eq $DID}).ReadErrorsUncorrected)
$_writeerru = $($DID = $_pdid; ($StorageRelCount | Where-Object {$_.DeviceId -eq $DID}).WriteErrorsUncorrected)
$_size = ([string]$([math]::Round($Disk.Size / 1GB)) + " GB")
$_allocsize = ([string]$([math]::Round($Disk.AllocatedSize / 1GB)) + " GB")
$Serial = try { $Disk.SerialNumber.Trim() } catch { $null }
foreach ($part in ($Partitions | Where-Object {$_.DiskId -like $Disk.Path})) {
if ($part.Size -lt 1GB) {
$PartSize = "$([math]::Round($part.Size / 1MB)) MB"
} else {
$PartSize = "$([math]::Round($part.Size / 1GB)) GB"
}
$po = [pscustomobject]@{
'PartitionNumber' = $part.PartitionNumber
'IsBoot' = $part.IsBoot
'DriveLetter' = $part.DriveLetter
'Size' = $PartSize
'RawSize' = $part.Size
'NoDefaultDriveLetter' = $part.NoDefaultDriveLetter
'ParentDiskSerial' = try { $Disk.SerialNumber.Trim() } catch { $null }
}
$p += $po
}
foreach ($vol in ($Volumes | Where-Object {$_.Path -in ($Partitions | Where-Object {$_.DiskId -eq $Disk.Path}).AccessPaths})) {
if ($vol.Size -lt 1GB) {
$VolSize = "$([math]::Round($vol.Size / 1MB)) MB"
} else {
$VolSize = "$([math]::Round($vol.Size / 1GB)) GB"
}
if ($vol.SizeRemaining -lt 1GB) {
if ($vol.SizeRemaining -lt 1MB) {
$VolRemain = "$([math]::Round($vol.SizeRemaining / 1KB)) KB"
} else {
$VolRemain = "$([math]::Round($vol.SizeRemaining / 1MB)) MB"
}
} else {
$VolRemain = "$([math]::Round($vol.SizeRemaining / 1GB)) GB"
}
$ADKeyList = @()
if ($BLADInfo -ne $null) {
foreach ($item in $BLADInfo) {
$Var = $item.Name.ToString()
$ADKeyList += $Var.Substring($Var.IndexOf("{"),$Var.IndexOf("}")-$Var.IndexOf("{")+1)
}
}
$PercentFree = "$([math]::Round(($vol.SizeRemaining / $vol.Size) * 100))%"
$BitlockerInfo = $BitLocker | Where-Object {$_.DeviceID -eq $vol.UniqueID}
$Protected = $BitlockerInfo.IsVolumeInitializedForProtection
if ($Protected) {
$StatusID = $BitlockerInfo | Invoke-CimMethod -MethodName GetLockStatus | Select -ExpandProperty LockStatus
$LockStatus = $LockStatus_map[[int32]$StatusID]
$NumericKeyID = $BitlockerInfo | Invoke-CimMethod -MethodName GetKeyProtectors -Arguments @{KeyProtectorType=3} -ErrorAction SilentlyContinue | Select -ExpandProperty VolumeKeyProtectorID -ErrorAction SilentlyContinue
if ($NumericKeyID) {
$RecoveryPassword = $BitlockerInfo | Invoke-CimMethod -MethodName GetProtectorNumericalPassword -Arguments @{VolumeKeyProtectorID=$NumericKeyID} -ErrorAction SilentlyContinue | Select -ExpandProperty NumericalPassword -ErrorAction SilentlyContinue
} else {
$RecoveryPassword = $null
}
$ProtectorIDs = $BitlockerInfo | Invoke-CimMethod -MethodName GetKeyProtectors | Select -ExpandProperty VolumeKeyProtectorID
$KeyProtectorDescriptions = $ProtectorIDs | foreach { $KeyProtector_map[[int32]$_.KeyProtectorType] }
$ConversionStatus = $BitlockerInfo | Invoke-CimMethod -MethodName GetConversionStatus -ErrorAction SilentlyContinue
$ADBacked = if (($ADKeyList.Count -gt 0) -and ($NumericKeyID -in $ADKeyList)) { $true } else { $false }
$EncryptionFlags = $ConversionStatus.EncryptionFlags
} else {
$LockStatus = $null
$NumericID = $null
$RecoveryPassword = $null
$KeyProtectorDescriptions = $null
$EncryptionFlags = $null
$ADBacked = $null
}
$vo = [pscustomobject]@{
'DriveLetter' = $vol.DriveLetter
'Label' = $vol.FileSystemLabel
'Size' = $VolSize
'RawSize' = $vol.Size
'SizeRemaining' = $VolRemain
'RawSizeRemaining' = $vol.SizeRemaining
'PercentFree' = $PercentFree
'ProtectionStatus' = $ProtectionStatus_map[[int32]$BitlockerInfo.ProtectionStatus]
'ConversionStatus' = $ConversionStatus_map[[int32]$BitlockerInfo.ConversionStatus]
'EncryptionMethod' = $EncryptionMethod_map[[int32]$BitlockerInfo.EncryptionMethod]
'EncryptionFlag' = if ($EncryptionFlags -ne $null) { $EncryptionFlags_map[[int32]$EncryptionFlags] } else { $null }
'LockStatus' = $LockStatus
'KeyProtectors' = $KeyProtectorDescriptions
'NumericPwdKeyID' = $NumericKeyID
'ADBacked' = $ADBacked
'RecoveryPassword' = $RecoveryPassword
'BitLockerInit' = $Protected
'ParentDiskSerial' = $Serial
}
$v += $vo
}
$do = [pscustomobject]@{
'Name' = $Disk.FriendlyName
'Model' = $Disk.Model
'Manufacturer' = $Disk.Manufacturer
'BusType' = $Disk.BusType
'MediaType' = $_mediatype
'DiskNumber' = $Disk.Number
'Type' = $Disk.ProvisioningType
'HealthStatus' = $Disk.HealthStatus
'PartitionStyle' = $Disk.PartitionStyle
'BootDisk' = $Disk.IsBoot
'Size' = $_size
'RawSize' = $Disk.Size
'AllocatedSize' = $_allocsize
'RawAllocatedSize' = $Disk.AllocatedSize
'FirmwareVersion' = $Disk.FirmwareVersion
'SerialNumber' = $Serial
'PowerOnHours' = $_pwronhrs
'Wear' = $_wear
'ReadErrorsUncorrectable' = $_readerru
'WriteErrorsUncorrectable' = $_writeerru
'SMART' = [Collections.ArrayList]@()
'Partitions' = $p
'Volumes' = $v
}
$ftbytes = $_fpt.VendorSpecific
$thresholds = @{}
for ($i = 0; $i -lt 30; $i++) {
try {
$idnumeric = [int]$ftbytes[$i * 12 + 2]
if ($idnumeric -eq 0) { continue }
$thresh = $ftbytes[$i * 12 + 3]
$thresholds[$idnumeric] = $thresh
} catch {
# Given key does not exist in attribute collection (attribute not in the dictionary of attributes)
}
}
$fpbytes = $_fpd.VendorSpecific
for ($i = 0; $i -lt 30; $i++) {
try {
$idnumeric = [int]$fpbytes[$i * 12 + 2]
if ($idnumeric -eq 0) { continue }
if ($SMARTNames_map.ContainsKey($idnumeric)) {
$id = $SMARTNames_map[$idnumeric]
} else {
$id = "ID $($idnumeric)"
}
$flags = $fpbytes[$i * 12 + 4]
$advisory = ($flags -band 0x1) -eq 0x0
$failureImminent = ($flags -band 0x1) -eq 0x1
$value = $fpbytes[$i * 12 + 5]
$worst = $fpbytes[$i * 12 + 6]
$vendordata = [System.BitConverter]::ToInt32($fpbytes, $i * 12 + 7)
$thresholdUndefined = $thresholds.ContainsKey($idnumeric) -eq $false
if (!$thresholdUndefined) {
$threshold = $thresholds[$idnumeric]
} else {
$threshold = $null
}
$null = $do.SMART.Add(
[pscustomobject]@{
Name = $id
Current = $value
Worst = $worst
Data = $vendordata
IsOK = $failureImminent -eq $false
Threshold = $threshold
ThresholdUndefined = $thresholdUndefined
}
)
} catch {
# Given key doesn't exist in attribute collection (attribute not in dictionary of attributes)
}
}
$Info += $do
}
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession | Remove-CimSession
}
#if ($Progress) { Write-ProgressHelper @ProgressArgs -Completed }
$Info
}
function Get-NetworkInfo {
[CmdletBinding(SupportsShouldProcess,DefaultParameterSetName = 'ComputerName')]
param (
[Parameter(ParameterSetName = 'ComputerName')]
[string]$ComputerName = $env:COMPUTERNAME,
[Parameter(Mandatory,ParameterSetName = 'CimSession')]
$CimSession,
[switch]$Progress = $script:Progress
)
$MyName = $PSCmdlet.CommandRuntime.ToString()
$StepCounter = 0
$NestLevel = (Get-PSCallStack).Count - 1
$Steps = ([System.Management.Automation.PSParser]::Tokenize((Get-Command $PSCmdlet.CommandRuntime).Definition, [ref]$null) | Where-Object {$_.Type -eq 'Command' -and $_.Content -eq 'Write-ProgressHelper'}).Count
$ProgressArgs = @{
Title = $MyName
Steps = $Steps
Id = $NestLevel
}
if ($NestLevel -gt 1) {
$ProgressArgs += @{ParentID = $NestLevel - 1}
}
$NetConfSubkey = 'SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}'
$NetConfigArgs = @{
'hDefKey' = $RegHive_Map['HKLM']
'sSubKeyName' = $NetConfSubkey
'sValueName' = ''
}
$FirewallArgs = @()
$FirewallRegPath = 'SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy'
$FirewallRegTemplate = @{
'hDefKey' = $RegHive_Map['HKLM']
'sSubKeyName' = $null
'sValueName' = 'EnableFirewall'
}
$FirewallPolicies = ('DomainProfile','PublicProfile','StandardProfile')
foreach($Policy in $FirewallPolicies) {
$FirewallRegTemplate['sSubKeyName'] = "$($FirewallRegPath)\$($Policy)"
$FirewallArgs += [pscustomobject]@{Policy=$Policy; FirewallArgs=$FirewallRegTemplate}
}
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession = New-Connection -ComputerName $ComputerName
}
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Network Adapter Configuration' -StepNumber $($StepCounter++) }
$NetConfig = Get-CimInstance -CimSession $CimSession -ClassName Win32_NetworkAdapterConfiguration -Filter IPEnabled=True
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Physical Network Adapters' -StepNumber $($StepCounter++) }
$NetAdapters = Get-NetAdapter -CimSession $CimSession -Physical
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Network Adapter Statistics' -StepNumber ($StepCounter++) }
$NetAdapterStatistics = Get-NetAdapterStatistics -CimSession $CimSession
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Network Adapter Hardware Info' -StepNumber ($StepCounter++) }
$NetAdapterHwInfo = Get-NetAdapterHardwareInfo -CimSession $CimSession
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Network Adapter Advanced Properties' -StepNumber ($StepCounter++) }
$NetAdaptersAdvProps = Get-NetAdapterAdvancedProperty -CimSession $CimSession
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Network TCP Settings' -StepNumber ($StepCounter++) }
$NetTCPSettings = Get-NetTCPSetting -CimSession $CimSession
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Network TCP Connection Settings' -StepNumber ($StepCounter++) }
$NetTCPConnection = Get-NetTCPConnection -CimSession $CimSession
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Network Transport Filter Settings' -StepNumber ($StepCounter++) }
$NetTransportFilter = Get-NetTransportFilter -CimSession $CimSession
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Net Offload Global Settings' -StepNumber ($StepCounter++) }
$NetOffloadGlobalSettings = Get-NetOffloadGlobalSetting -CimSession $CimSession
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Net Apapter Power Management Settings' -StepNumber ($StepCounter++) }
$NetAdapterPowerManagement = Get-NetAdapterPowerManagement -CimSession $CimSession
$FirewallStatus = @()
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting Firewall Profile Statuses' -StepNumber ($StepCounter++) }
$FirewallArgs | foreach {
$fs = if ((Invoke-CimMethod -CimSession $CimSession -ClassName 'StdRegProv' -MethodName 'GetDWORDValue' -Arguments $_.FirewallArgs).uValue -eq 1) { $true } else { $false }
$FirewallStatus += [pscustomobject]@{Policy=$_.Policy;Status=$fs}
}
$_Online = @()
$_Offline = @()
foreach ($adapter in ($NetAdapters | Where-Object {$_.MediaType -eq '802.3'})) {
$o = [pscustomobject]@{
'Name' = $adapter.Name
'Description' = $adapter.ifDesc
'Status' = $adapter.Status
'MAC' = $adapter.MacAddress
'LinkSpeed' = $adapter.LinkSpeed
'MediaType' = $adapter.MediaType
'DriverInfo' = $adapter.DriverInformation
'DriverVersion' = $adapter.DriverVersion
'DriverFileName' = $adapter.DriverFileName
'DriverDate' = $adapter.DriverDate
'MTU' = $adapter.ActiveMaximumTransmissionUnit
'FullDuplex' = $adapter.FullDuplex
'DnsDomain' = ($NetConfig | Where-Object {$_.SettingID -eq $adapter.InterfaceGuid}).DNSDomain
'DnsDomainSuffixSearchOrder' = ($NetConfig | Where-Object {$_.SettingId -eq $adapter.InterfaceGuid} | Select -ExpandProperty DNSDomainSuffixSearchOrder) -join ','
'DnsServerSearchOrder' = ($NetConfig | Where-Object {$_.SettingId -eq $adapter.InterfaceGuid} | Select -ExpandProperty DNSServerSearchOrder) -join ','
'IPAddress' = @(($NetConfig | Where-Object { $_.SettingId -eq $adapter.InterfaceGuid}).IPAddress | Where-Object -FilterScript { $_ -match $IPRegex }) -join ','
'DefaultIPGateway' = ($NetConfig | Where-Object {$_.SettingId -eq $adapter.InterfaceGuid}).DefaultIPGateway -join ','
'PortNumber' = ($NetAdapterHwInfo | Where-Object {$_.ifAlias -eq $adapter.Name}).FunctionNumber
'FlowControl' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'FlowControl')}).DisplayValue
'InterruptModeration' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'InterruptModeration')}).DisplayValue
'LargeSendOffloadv4' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'LsoV2IPv4')}).DisplayValue
'LargeSendOffloadv6' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'LsoV2IPv6')}).DisplayValue
'ReceiveBuffers' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'ReceiveBuffers')}).DisplayValue
'SpeedDuplex' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'SpeedDuplex')}).DisplayValue
'IPv4ChecksumOffload' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'IPChecksumOffloadIPv4')}).DisplayValue
'TcpChecksumOffloadIPv4' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'TcpChecksumOffloadIPv4')}).DisplayValue
'TcpChecksumOffloadIPv6' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'TcpChecksumOffloadIPv6')}).DisplayValue
'UdpChecksomOffloadIPv4' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'UcpChecksumOffloadIPv4')}).DisplayValue
'UdpChecksomOffloadIPv6' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'UcpChecksumOffloadIPv6')}).DisplayValue
'MaxNumRSSQueues' = ($NetAdaptersAdvProps | Where-Object {($_.InstanceID -match $adapter.InstanceID) -and ($_.RegistryKeyword -match 'NumRssQueues')}).DisplayValue
'TransportFilter' = $NetTransportFilter.SettingName
'AutoTuningLevel' = ($NetTCPSettings | Where-Object {$_.SettingName -eq $NetTransportFilter.SettingName}).AutoTuningLevelLocal
'ScalingHeuristics' = ($NetTCPSettings | Where-Object {$_.SettingName -eq $NetTransportFilter.SettingName}).ScalingHeuristics
'PowerManagement' = ($NetAdapterPowerManagement | Where-Object {$_.InstanceID -eq $adapter.DeviceID}).AllowComputerToTurnOffDevice
'WakeOnPattern' = ($NetAdapterPowerManagement | Where-Object {$_.InstanceID -eq $adapter.DeviceID}).WakeOnPattern
}
if ($o.Status -eq 'Up') {
$_Online += $o
} else {
$_Offline += $o
}
}
$Info = [pscustomobject]@{
'TaskOffload' = $NetOffloadGlobalSettings.TaskOffload
'RSS' = $NetOffloadGlobalSettings.ReceiveSideScaling
'FirewallStatus' = $FirewallStatus
'OnlineAdapters' = $_Online
'OfflineAdapters' = $_Offline
}
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession | Remove-CimSession
}
#if ($Progress) { Write-ProgressHelper @ProgressArgs -Completed }
$Info
}
function Get-InstalledApplications {
[CmdletBinding(SupportsShouldProcess,DefaultParameterSetName = 'ComputerName')]
param (
[Parameter(Mandatory,ParameterSetName = 'ComputerName')]
[string]$ComputerName,
[Parameter(Mandatory,ParameterSetName = 'CimSession')]
$CimSession,
[switch]$Progress
)
$RegKeys = @()
$RegKeys += [pscustomobject]@{Arch='x86';Hive='HKLM';Key='SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'}
$RegKeys += [pscustomobject]@{Arch='x64';Hive='HKLM';Key='SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'}
$Values = @(
'DisplayName',
'DisplayVersion',
'Publisher',
'InstallDate',
'InstallLocation'
)
$_Apps = @()
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession = New-Connection -ComputerName $ComputerName
}
foreach ($Key in $RegKeys) {
$Args = @{
'hDefKey' = $RegHive_Map["$($Key.Hive)"]
'sSubKeyName' = $Key.Key
}
$AppSubKeys = @((Invoke-CimMethod -CimSession $CimSession -ClassName StdRegProv -MethodName 'EnumKey' -Arguments $Args).sNames)
foreach ($SubKey in $AppSubKeys) {
$SubKeyArgs = @{
'hDefKey' = $Args['hDefKey']
'sSubKeyName' = $Args['sSubKeyName'] + "\" + $SubKey
}
$AppObj = New-Object -TypeName pscustomobject
foreach ($Value in $Values) {
$SubKeyArgs['sValueName'] = $Value
$String = (Invoke-CimMethod -CimSession $CimSession -ClassName 'StdRegProv' -MethodName 'GetStringValue' -Arguments $SubKeyArgs).sValue
$AppObj | Add-Member -Type NoteProperty -Name $Value -Value $String
}
$AppObj | Add-Member -MemberType NoteProperty -Name Arch -Value $Key.Arch
if ( -not [string]::IsNullOrEmpty($AppObj.DisplayName) ) {
$_Apps += $AppObj
}
}
}
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession | Remove-CimSession
}
$_Apps
}
function Get-WindowsInfo {
[CmdletBinding(SupportsShouldProcess,DefaultParameterSetName = 'ComputerName')]
param (
[Parameter(Mandatory,ParameterSetName = 'ComputerName')]
[string]$ComputerName,
[Parameter(Mandatory,ParameterSetName = 'CimSession')]
$CimSession,
[switch]$Progress = $script:Progress
)
$SoftwareArgs = @{
'hDefKey' = $RegHive_Map['HKLM']
'sSubKeyName' = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'
}
$ProdIdArgs = @{
'hDefKey' = $RegHive_Map['HKLM']
'sSubKeyName' = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
'sValueName' = 'DigitalProductId'
}
$WUArgs = @{
'hDefKey' = $RegHive_Map['HKLM']
'sSubKeyName' = 'Software\Policies\Microsoft\Windows\Windows'
}
$PatchLevelArgs = @{
'hDefKey' = $RegHive_Map['HKLM']
'sSubKeyName' = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion'
'sValueName' = 'UBR'
}
$BPKDArgs = @{
'hDefKey' = $RegHive_Map['HKLM']
'sSubKeyName' = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform'
'sValueName' = 'BackupProductKeyDefault'
}
$OperatingSystemSKU_Map = @{
0 = 'PRODUCT_UNDEFINED'
1 = 'PRODUCT_ULTIMATE'
2 = 'PRODUCT_HOME_BASIC'
3 = 'PRODUCT_HOME_PREMIUM'
4 = 'PRODUCT_ENTERPRISE'
5 = 'PRODUCT_HOME_BASIC_N'
6 = 'PRODUCT_BUSINESS'
7 = 'PRODUCT_STANDARD_SERVER'
8 = 'PRODUCT_DATACENTER_SERVER'
9 = 'PRODUCT_SMALLBUSINESS_SERVER'
10 = 'PRODUCT_ENTERPRISE_SERVER'
11 = 'PRODUCT_STARTER'
12 = 'PRODUCT_DATACENTER_SERVER_CORE'
13 = 'PRODUCT_STANDARD_SERVER_CORE'
14 = 'PRODUCT_ENTERPRISE_SERVER_CORE'
15 = 'PRODUCT_ENTERPRISE_SERVER_IA64'
16 = 'PRODUCT_BUSINESS_N'
17 = 'PRODUCT_WEB_SERVER'
18 = 'PRODUCT_CLUSTER_SERVER'
19 = 'PRODUCT_HOME_SERVER'
20 = 'PRODUCT_STORAGE_EXPRESS_SERVER'
21 = 'PRODUCT_STORAGE_STANDARD_SERVER'
22 = 'PRODUCT_STORAGE_WORKGROUP_SERVER'
23 = 'PRODUCT_STORAGE_ENTERPRISE_SERVER'
24 = 'PRODUCT_SERVER_FOR_SMALLBUSINESS'
25 = 'PRODUCT_SMALLBUSINESS_SERVER_PREMIUM'
26 = 'PRODUCT_HOME_PREMIUM_N'
27 = 'PRODUCT_ENTERPRISE_N'
28 = 'PRODUCT_ULTIMATE_N'
29 = 'PRODUCT_WEB_SERVER_CORE'
30 = 'PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT'
31 = 'PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY'
32 = 'PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING'
33 = 'PRODUCT_SERVER_FOUNDATION'
34 = 'PRODUCT_HOME_PREMIUM_SERVER'
35 = 'PRODUCT_SERVER_FOR_SMALLBUSINESS_V'
36 = 'PRODUCT_STANDARD_SERVER_V'
37 = 'PRODUCT_DATACENTER_SERVER_V'
38 = 'PRODUCT_ENTERPRISE_SERVER_V'
39 = 'PRODUCT_DATACENTER_SERVER_CORE_V'
40 = 'PRODUCT_STANDARD_SERVER_CORE_V'
41 = 'PRODUCT_ENTERPRISE_SERVER_CORE_V'
42 = 'PRODUCT_HYPERV'
43 = 'PRODUCT_STORAGE_EXPRESS_SERVER_CORE'
44 = 'PRODUCT_STORAGE_STANDARD_SERVER_CORE'
45 = 'PRODUCT_STORAGE_WORKGROUP_SERVER_CORE'
46 = 'PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE'
47 = 'PRODUCT_STARTER_N'
48 = 'PRODUCT_PROFESSIONAL'
49 = 'PRODUCT_PROFESSIONAL_N'
50 = 'PRODUCT_SB_SOLUTION_SERVER'
51 = 'PRODUCT_SERVER_FOR_SB_SOLUTIONS'
52 = 'PRODUCT_STANDARD_SERVER_SOLUTIONS'
53 = 'PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE'
54 = 'PRODUCT_SB_SOLUTION_SERVER_EM'
55 = 'PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM'
56 = 'PRODUCT_SOLUTION_EMBEDDEDSERVER'
57 = 'PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE'
58 = 'PRODUCT_PROFESSIONAL_EMBEDDED'
59 = 'PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT'
60 = 'PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL'
61 = 'PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC'
62 = 'PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC'
63 = 'PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE'
64 = 'PRODUCT_CLUSTER_SERVER_V'
65 = 'PRODUCT_EMBEDDED'
66 = 'PRODUCT_STARTER_E'
67 = 'PRODUCT_HOME_BASIC_E'
68 = 'PRODUCT_HOME_PREMIUM_E'
69 = 'PRODUCT_PROFESSIONAL_E'
70 = 'PRODUCT_ENTERPRISE_E'
71 = 'PRODUCT_ULTIMATE_E'
72 = 'PRODUCT_ENTERPRISE_EVALUATION'
76 = 'PRODUCT_MULTIPOINT_STANDARD_SERVER'
77 = 'PRODUCT_MULTIPOINT_PREMIUM_SERVER'
79 = 'PRODUCT_STANDARD_EVALUATION_SERVER'
80 = 'PRODUCT_DATACENTER_EVALUATION_SERVER'
84 = 'PRODUCT_ENTERPRISE_N_EVALUATION'
85 = 'PRODUCT_EMBEDDED_AUTOMOTIVE'
86 = 'PRODUCT_EMBEDDED_INDUSTRY_A'
87 = 'PRODUCT_THINPC'
88 = 'PRODUCT_EMBEDDED_A'
89 = 'PRODUCT_EMBEDDED_INDUSTRY'
90 = 'PRODUCT_EMBEDDED_E'
91 = 'PRODUCT_EMBEDDED_INDUSTRY_E'
92 = 'PRODUCT_EMBEDDED_INDUSTRY_A_E'
95 = 'PRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVE'
96 = 'PRODUCT_STORAGE_STANDARD_EVALUATION_SERVER'
97 = 'PRODUCT_CORE_ARM'
98 = 'PRODUCT_CORE_N'
99 = 'PRODUCT_CORE_COUNTRYSPECIFIC'
100 = 'PRODUCT_CORE_SINGLELANGUAGE'
101 = 'PRODUCT_CORE'
103 = 'PRODUCT_PROFESSIONAL_WMC'
105 = 'PRODUCT_EMBEDDED_INDUSTRY_EVAL'
106 = 'PRODUCT_EMBEDDED_INDUSTRY_E_EVAL'
107 = 'PRODUCT_EMBEDDED_EVAL'
108 = 'PRODUCT_EMBEDDED_E_EVAL'
109 = 'PRODUCT_NANO_SERVER'
110 = 'PRODUCT_CLOUD_STORAGE_SERVER'
111 = 'PRODUCT_CORE_CONNECTED'
112 = 'PRODUCT_PROFESSIONAL_STUDENT'
113 = 'PRODUCT_CORE_CONNECTED_N'
114 = 'PRODUCT_PROFESSIONAL_STUDENT_N'
115 = 'PRODUCT_CORE_CONNECTED_SINGLELANGUAGE'
116 = 'PRODUCT_CORE_CONNECTED_COUNTRYSPECIFIC'
117 = 'PRODUCT_CONNECTED_CAR'
118 = 'PRODUCT_INDUSTRY_HANDHELD'
119 = 'PRODUCT_PPI_PRO'
120 = 'PRODUCT_ARM64_SERVER'
121 = 'PRODUCT_EDUCATION'
122 = 'PRODUCT_EDUCATION_N'
123 = 'PRODUCT_IOTUAP'
124 = 'PRODUCT_CLOUD_HOST_INFRASTRUCTURE_SERVER'
125 = 'PRODUCT_ENTERPRISE_S'
126 = 'PRODUCT_ENTERPRISE_S_N'
127 = 'PRODUCT_PROFESSIONAL_S'
128 = 'PRODUCT_PROFESSIONAL_S_N'
129 = 'PRODUCT_ENTERPRISE_S_EVALUATION'
130 = 'PRODUCT_ENTERPRISE_S_N_EVALUATION'
135 = 'PRODUCT_HOLOGRAPHIC'
138 = 'PRODUCT_PRO_SINGLE_LANGUAGE'
139 = 'PRODUCT_PRO_CHINA'
140 = 'PRODUCT_ENTERPRISE_SUBSCRIPTION'
141 = 'PRODUCT_ENTERPRISE_SUBSCRIPTION_N'
143 = 'PRODUCT_DATACENTER_NANO_SERVER'
144 = 'PRODUCT_STANDARD_NANO_SERVER'
145 = 'PRODUCT_DATACENTER_A_SERVER_CORE'
146 = 'PRODUCT_STANDARD_A_SERVER_CORE'
147 = 'PRODUCT_DATACENTER_WS_SERVER_CORE'
148 = 'PRODUCT_STANDARD_WS_SERVER_CORE'
149 = 'PRODUCT_UTILITY_VM'
159 = 'PRODUCT_DATACENTER_EVALUATION_SERVER_CORE'
160 = 'PRODUCT_STANDARD_EVALUATION_SERVER_CORE'
161 = 'PRODUCT_PRO_WORKSTATION'
162 = 'PRODUCT_PRO_WORKSTATION_N'
164 = 'PRODUCT_PRO_FOR_EDUCATION'
165 = 'PRODUCT_PRO_FOR_EDUCATION_N'
168 = 'PRODUCT_AZURE_SERVER_CORE'
169 = 'PRODUCT_AZURE_NANO_SERVER'
171 = 'PRODUCT_ENTERPRISEG'
172 = 'PRODUCT_ENTERPRISEGN'
178 = 'PRODUCT_CLOUD'
179 = 'PRODUCT_CLOUDN'
180 = 'PRODUCT_HUBOS'
182 = 'PRODUCT_ONECOREUPDATEOS'
183 = 'PRODUCT_CLOUDE'
184 = 'PRODUCT_ANDROMEDA'
185 = 'PRODUCT_IOTOS'
186 = 'PRODUCT_CLOUDEN'
}
$WindowsVersion_map = @{
22631 = 'Windows 11 (23H2)'
22621 = 'Windows 11 (22H2)'
22000 = 'Windows 11 (21H2)'
19045 = 'Windows 10 (22H2)'
19044 = 'Windows 10 (21H2)'
19043 = 'Windows 10 (21H1)'
19042 = 'Windows 10 (20H2)'
19041 = 'Windows 10 (2004)'
18363 = 'Windows 10 (1909)'
18362 = 'Windows 10 (1903)'
17763 = 'Windows 10 (1809)'
17134 = 'Windows 10 (1803)'
16299 = 'Windows 10 (1709)'
15063 = 'Windows 10 (1703)'
14393 = 'Windows 10 (1607)'
10586 = 'Windows 10 (1511)'
10240 = 'Windows 10 (1507)'
}
$MyName = $PSCmdlet.CommandRuntime.ToString()
$StepCounter = 0
$NestLevel = (Get-PSCallStack).Count - 1
$Steps = ([System.Management.Automation.PSParser]::Tokenize((Get-Command $PSCmdlet.CommandRuntime).Definition, [ref]$null) | Where-Object {$_.Type -eq 'Command' -and $_.Content -eq 'Write-ProgressHelper'}).Count
$ProgressArgs = @{
Title = $MyName
Steps = $Steps
Id = $NestLevel
}
if ($NestLevel -ge 1) {
$ProgressArgs += @{ParentId = $NestLevel - 1}
}
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession = New-Connection -ComputerName $ComputerName
} else {
$ComputerName = $CimSession.ComputerName
}
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting operating system info' -StepNumber ($StepCounter++) }
$OperatingSystem = Get-CimInstance -CimSession $CimSession -ClassName Win32_OperatingSystem
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting patch level' -StepNumber ($StepCounter++) }
$PatchLevel = (Invoke-CimMethod -CimSession $CimSession -ClassName 'StdRegProv' -MethodName 'GetDWORDValue' -Arguments $PatchLevelArgs).uValue
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting installed patches' -StepNumber ($StepCounter++) }
$Patches = Get-CimInstance -CimSession $CimSession -ClassName Win32_QuickFixEngineering
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting SCCM client info' -StepNumber ($StepCounter++) }
$SCCMInfo = Get-CimInstance -CimSession $CimSession -Namespace root\ccm -ClassName SMS_Client -ErrorAction SilentlyContinue
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting software licensing service info' -StepNumber ($StepCounter++) }
$SLS = Get-CimInstance -CimSession $CimSession -Query "SELECT * FROM SoftwareLicensingService"
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting backup product key default' -StepNumber ($StepCounter++) }
$BPKD = Invoke-CimMethod -CimSession $CimSession -ClassName 'StdRegProv' -MethodName 'GetStringValue' -Arguments $BPKDArgs
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message 'Getting digital product id' -StepNumber ($StepCounter++) }
$DPID = Get-DecodedKey (Invoke-CimMethod -CimSession $CimSession -ClassName 'StdRegProv' -MethodName 'GetBinaryValue' -Arguments $ProdIdArgs).uValue
$Info = [pscustomobject]@{
'ComputerName' = $ComputerName
'WindowsVersion' = $WindowsVersion_map[[int32]$OperatingSystem.BuildNumber]
'WindowsSKU' = $OperatingSystemSKU_Map[[int32]$OperatingSystem.OperatingSystemSKU]
'WindowsBuildNumber' = $OperatingSystem.BuildNumber
'WindowsPatchLevel' = $PatchLevel
'WindowsInstallDate' = $OperatingSystem.InstallDate
'SLSPK' = if ($SLS) { $SLS.OA3xOriginalProductKey } else { $null }
'BPKD' = if ($BPKD) { $BPKD.sValue } else { $null }
'DPID' = if ($DPID) { $DPID } else { $null }
'Patches' = $Patches
}
if ($PSCmdlet.ParameterSetName -eq 'ComputerName') {
$CimSession | Remove-CimSession
}
if ($Progress) { Write-ProgressHelper @ProgressArgs -Completed }
return $Info
}
function Get-EndpointInfo {
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)]
[string[]]$Devices,
[string[]]$Items = $script:Items,
[switch]$Progress = $script:Progress,
[switch]$Batch = $script:Batch
)
if ($Devices.Count -gt 1) {
$Batch = $true
}
$MyName = $PSCmdlet.CommandRuntime.ToString()
$StepCounter = 0
$NestLevel = (Get-PSCallStack).Count - 1
$ProgressArgs = @{
Title = "Polling $($Devices.Count) endpoints"
Steps = $Devices.Count
Id = $NestLevel
}
if ($Batch) {
$Jobs = @()
$i = 0
Get-Job -Name "INFO-*" | Stop-Job -PassThru | Remove-Job -Force
foreach ($Device in $Devices) {
$Arguments = @{
Devices = $Device
Items = $script:Items -join ','
}
while (($(Get-Job -State NotStarted).Count + $(Get-Job -State Running).Count) -ge $MaxThreads) {
Write-ProgressHelper @ProgressArgs -Message "Waiting for free job slot(s)" -Operation "($i) jobs created | $(($Jobs | Where-Object {$_.State -match '(NotStarted|Running)'}).Count) jobs running" -StepNumber $Jobs.Count
Start-Sleep -Milliseconds $SleepTimer
}
$i++
$ScriptBlock = [scriptblock]::Create(".{$(Get-Content $script:MyInvocation.MyCommand.Path -Raw)} $(&{$args} @Arguments)")
$Jobs += Start-Job -Name "INFO-$($Device)" -ScriptBlock $ScriptBlock
Write-ProgressHelper @ProgressArgs -Message "Starting job(s)" -Operation "$($i) jobs created | $(($Jobs | Where-Object {$_.State -match '(NotStarted|Running)'}).Count) jobs running" -StepNumber $Jobs.Count
}
$JobsRemaining = ($(Get-Job -State NotStarted).Count + $(Get-Job -State Running).Count)
$ProgressArgs.Steps = $JobsRemaining
while (($(Get-Job -State NotStarted).Count + $(Get-Job -State Running).Count) -gt 0) {
foreach ($Job in @($Jobs | Where-Object {$_.State -match '(NotStarted|Running)'})) {
if ($(New-TimeSpan $Job.PSBeginTime $(Get-Date)).TotalSeconds -gt $MaxWaitAtEnd) {
Write-Warning -Message "$($Job.Name) exceeded runtime. Killing job." -WarningAction SilentlyContinue
Get-Job $Job.Name | Stop-Job -PassThru | Remove-Job -Force
}
}
$CurrJobs = $($Jobs | Where-Object {$_.State -match '(NotStarted|Running)'}).Count
$JobsFin = ($JobsRemaining - $CurrJobs)
Write-ProgressHelper @ProgressArgs -Message "Waiting for job(s) to finish" -Operation "$($CurrJobs) of $($JobsRem) jobs remaining" -StepNumber $JobsFin
}
Write-ProgressHelper @ProgressArgs -Completed
$Jobs | Receive-Job -Wait -AutoRemoveJob 2>$null
} else {
$StepCounter = 0
$NestLevel = (Get-PSCallStack).Count - 1
$ComputerName = $Devices[0]
$HostAlive = Ping-Computer -ComputerName $ComputerName
$OutputObject = [pscustomobject]@{
Name = $ComputerName
HostAlive = $HostAlive
}
$ProgressArgs = @{
Title = $ComputerName
Steps = if ($Items -ilike 'all') { 13 } else { $Items.Count + 5 }
Id = $NestLevel
}
if ($HostAlive) {
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Connecting..." -StepNumber ($StepCounter++) }
try {
$CimSession = New-Connection -ComputerName $ComputerName -ErrorAction Stop
} catch {
$OutputObject
}
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Checking Remote PowerShell (WSMan) Status" -StepNumber ($StepCounter++) }
$WSMan = Get-WSManStatus -ComputerName $ComputerName
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting System Info" -StepNumber ($StepCounter++) }
$System = Get-ComputerSystem -CimSession $CimSession
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting FQDN" -StepNumber ($StepCounter++) }
$FQDN = Resolve-DnsName -Name $ComputerName -Type A
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting PTR" -StepNumber ($StepCounter++) }
try {
$PTR = Resolve-DnsName -Type PTR -Name $FQDN.IP4Address -ErrorAction Stop
} catch {
$PTR = "None"
}
$OutputObject = [pscustomobject]@{
'Name' = $ComputerName
'HostName' = $System.Name
'Online' = $HostAlive
'WSMan' = $WSMan
'IPAddress' = ($FQDN.IP4Address | Select -Unique) -join "|"
'FQDN' = ($FQDN.Name | Select -Unique) -join "|"
'PTR' = ($PTR.NameHost | Select -Unique) -join "|"
}
Foreach ($Item in $Items) {
switch -Regex ($Item) {
"^(All|ComputerSystem|System)$" {
$InfoObject = [pscustomobject]@{
'Memory' = ([string]$([math]::Round($System.TotalPhysicalMemory / 1GB)) + "GB")
'Manufacturer' = $System.Manufacturer
'Model' = $System.Model
'NumCPUs' = $System.NumberOfProcessors
'ComputerSystem' = $System
}
if (-not $OutputObject.SysInfo) {
$OutputObject | Add-Member -MemberType NoteProperty -Name SysInfo -Value $InfoObject
}
}
"^(All|[bB][iI][oO][sS]$)" {
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting BIOS Information" -StepNumber ($StepCounter++) }
$BIOS = Get-Bios -ComputerName $ComputerName -Progress:$Progress
$Values = [pscustomobject]@{
Serial = $BIOS.SerialNumber
BIOSManufacturer = $BIOS.Manufacturer
BIOSVersion = $BIOS.SMBIOSBIOSVersion
BIOS = $BIOS
}
if (-not $OutputObject.SysInfo) {
$OutputObject | Add-Member -MemberType NoteProperty -Name SysInfo -Value $([pscustomobject]$Values)
}
$Values.PSObject.Properties | foreach {
$OutputObject.SysInfo | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value
}
}
"^(All|Processor|CPU(s|S)?)$" {
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting Processor Information" -StepNumber ($StepCounter++) }
$Processor = Get-Processor -ComputerName $ComputerName -Progress:$Progress
if (-not $OutputObject.SysInfo) {
$OutputObject | Add-Member -MemberType NoteProperty -Name SysInfo -Value $([pscustomobject]@{})
}
$OutputObject.SysInfo | Add-Member -MemberType NoteProperty -Name CpuInfo -Value $Processor
}
"^(All|Graphics|Video)$" {
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting Video Controller Information" -StepNumber ($StepCounter++) }
$Graphics = Get-VideoController -CimSession $CimSession -Progress:$Progress
$Values = [pscustomobject]@{
VideoCardDesc = $Graphics.Name
VideoProcessor = $Graphics.VideoProcessor
VideoDrvrVers = $Graphics.DriverVersion
VideoDrvrDate = $Graphics.DriverDate
}
if (-not $OutputObject.SysInfo) {
$OutputObject | Add-Member -MemberType NoteProperty -Name SysInfo -Value $([pscustomobject]@{})
}
$Values.PSObject.Properties | foreach {
$OutputObject.SysInfo | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value
}
}
"^(All|Disk(Info|s)?)$" {
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting Disk Information" -StepNumber $($StepCounter++) }
$Disks = Get-DiskInfo -CimSession $CimSession
if (-not $OutputObject.SysInfo) {
$OutputObject | Add-Member -MemberType NoteProperty -Name SysInfo -Value $([pscustomobject]@{})
}
$OutputObject.SysInfo | Add-Member -MemberType NoteProperty -Name Disks -Value $Disks
}
"^(All|Net(work)?Info)$" {
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting Network Information" -StepNumber ($StepCounter++) }
$NetInfo = Get-NetworkInfo -CimSession $CimSession -Progress:$Progress
$OutputObject | Add-Member -MemberType NoteProperty -Name NetInfo -Value $NetInfo
}
"^(All|(Installed)?Apps)$" {
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting Installed Applications" -StepNumber ($StepCounter++) }
if (-not $OutputObject.SysInfo) {
$OutputObject | Add-Member -MemberType NoteProperty -Name SysInfo -Value $([pscustomobject]@{})
}
$OutputObject.SysInfo | Add-Member -MemberType NoteProperty -Name Applications -Value $(Get-InstalledApplications -CimSession $CimSession)
}
"^(All|(Windows|O[sS])Info)$" {
if ($Progress) { Write-ProgressHelper @ProgressArgs -Message "Getting Operating System Info" -StepNumber ($StepCounter++) }
$OSInfo = Get-WindowsInfo -CimSession $CimSession
if (-not $OutputObject.SysInfo) {
$OutputObject | Add-Member -MemberType NoteProperty -Name SysInfo -Value $([pscustomobject]@{})
}
$OSInfo.PSObject.Properties | foreach {
$OutputObject.SysInfo | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value
}
}
"^(All|Users)$" {
if (-not $OutputObject.SysInfo) {
$OutputObject | Add-Member -MemberType NoteProperty -Name SysInfo -Value $([pscustomobject]@{})
}
$OutputObject.SysInfo | Add-Member -MemberType NoteProperty -Name Users -Value $(Get-QUserInfo -ComputerName $ComputerName)
}
}
}
$CimSession | Remove-CimSession
}
return $OutputObject
}
}
$LineNo = 1
if ($Devices) {
if (($Devices.GetType().Name -eq 'String') -and (Test-Path -Path $Devices)) {
$List = (Get-Content -Path $Devices | Where-Object -FilterScript {-not [string]::IsNullOrWhiteSpace($_)})
$Devices = $List
}
$DeviceString = "(|"
$Devices | Foreach {
if ($_ -match "(?sm)/\*.*?\*/|^[ \t]*//[^\r\n]*|^[ \t]*#[^\r\n]*|^[ \t]*;[^\r\n]*") {
} elseif ($_ -match $IP4Regex) {
Write-Warning "Cannot use IP addresses with this script: Line $($LineNo): $($_)"
} elseif ($_ -notmatch "^(\S+)$") {
Write-Warning "Multi-word line, ignoring: Line $($LineNo): '$($_)'"
} else {
$DeviceString += "(Name=$($_))"
}
$LineNo++
}
$DeviceString += ")"
}
$objSearcher = [adsisearcher]"(&(objectClass=computer)$($DeviceString))"
$objSearcher.SearchRoot = [ADSI]"LDAP://$(Get-ADDomain | Select -ExpandProperty DistinguishedName)"
$Servers += $objSearcher.FindAll().Properties.name | Sort-Object
Get-EndpointInfo -Devices $Servers -Items $Items
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment