diff --git a/src/Public/Add-ProductStates.ps1 b/src/Public/Add-ProductStates.ps1 new file mode 100644 index 0000000..dea552f --- /dev/null +++ b/src/Public/Add-ProductStates.ps1 @@ -0,0 +1,147 @@ +function Add-ProductStates { +<# +.SYNOPSIS + Adds statuses to a product PSObject. + +.DESCRIPTION + Adds statuses to a product PSObject. If this function is used + in a command pipeline it will add properties to the resulting PSObject containing boolean properties. These properties reflect + status of Product Enablement and if it is updated. These values are calculated using the State DWORD using bitfields. + +.PARAMETER ProductState + The value (DWORD) containing the bitflags. + +.PARAMETER Products + PSObject containing object array of Microsoft.Management.Infrastructure.CimInstance#ROOT/SecurityCenter2/AntiVirusProduct + +.EXAMPLE + PS C:\Users\maurice> Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct | Add-ProductStates + + enabled : True + displayName : Trend Micro Antivirus+ + instanceGuid : {AFEE279F-FAE7-BAEE-3A88-4BF7277B8551} + pathToSignedProductExe : C:\Program Files\Trend Micro\Titanium\TmWscSvc\wschandler.exe + pathToSignedReportingExe : C:\Program Files\Trend Micro\Titanium\TmWscSvc\WSCStatusController.exe + productState : 266240 + timestamp : Sun, 12 Apr 2020 15:09:56 GMT + PSComputerName : + + enabled : True + displayName : Sophos Home + instanceGuid : {FFADE7EA-DC92-4602-D6B2-626CD3450A0F} + pathToSignedProductExe : C:\Program Files (x86)\Sophos\Sophos Anti-Virus\WSCClient.exe + pathToSignedReportingExe : C:\Program Files (x86)\Sophos\Sophos Anti-Virus\WSCClient.exe + productState : 331776 + timestamp : Sun, 12 Apr 2020 15:18:39 GMT + PSComputerName : + + enabled : False + displayName : Windows Defender + instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} + pathToSignedProductExe : windowsdefender:// + pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe + productState : 393472 + timestamp : Sun, 12 Apr 2020 15:08:57 GMT + PSComputerName : + +.EXAMPLE + PS C:\Users\maurice> $products = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct + PS C:\Users\maurice> Add-ProductStates -Products $products + + enabled : True + displayName : Trend Micro Antivirus+ + instanceGuid : {AFEE279F-FAE7-BAEE-3A88-4BF7277B8551} + pathToSignedProductExe : C:\Program Files\Trend Micro\Titanium\TmWscSvc\wschandler.exe + pathToSignedReportingExe : C:\Program Files\Trend Micro\Titanium\TmWscSvc\WSCStatusController.exe + productState : 266240 + timestamp : Sun, 12 Apr 2020 15:09:56 GMT + PSComputerName : + + enabled : True + displayName : Sophos Home + instanceGuid : {FFADE7EA-DC92-4602-D6B2-626CD3450A0F} + pathToSignedProductExe : C:\Program Files (x86)\Sophos\Sophos Anti-Virus\WSCClient.exe + pathToSignedReportingExe : C:\Program Files (x86)\Sophos\Sophos Anti-Virus\WSCClient.exe + productState : 331776 + timestamp : Sun, 12 Apr 2020 15:18:39 GMT + PSComputerName : + + enabled : False + displayName : Windows Defender + instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46} + pathToSignedProductExe : windowsdefender:// + pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe + productState : 393472 + timestamp : Sun, 12 Apr 2020 15:08:57 GMT + PSComputerName : + +.EXAMPLE + PS C:\Users\maurice> (Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct)[0].productState | Add-ProductStates + + enabled : True + +.EXAMPLE + PS C:\Users\maurice> $prodState = (Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct)[0].productState + PS C:\Users\maurice> Add-ProductStates -ProductState $prodState + + enabled : True + +.NOTES + This function utilizes Test-IsProductEnabled, ... To enrich information on State. +#> + [CmdletBinding()] + param ( + # This parameter can be passed from pipeline and can contain and array of collections that contain State or productstate members + [Parameter(ValueFromPipeline)] + [Microsoft.Management.Infrastructure.CimInstance[]] + $Products, + # Product State contains a value (DWORD) that contains multiple bitflags and we use the productState flag (0000F000) + [Parameter(Position = 0, ValueFromPipelineByPropertyName, ValueFromPipeline, HelpMessage = "The value (DWORD) containing the bitflags.")] + [Alias("STATE")] + [UInt32]$ProductState + ) + + begin { + $results = $null + } + + process { + If ($Products -is [array]) { + If ($Products.Count -gt 0) { + If (Get-Member -inputobject $Products[0] -name "productState" -Membertype Properties) { + $results += $Products.PSObject.Copy() + foreach ($item in $Products) { + If($results.Where({$_.instanceGuid -eq $item.instanceGuid}).Properties.name -notmatch "state") { + $results.Where({$_.instanceGuid -eq $item.instanceGuid}) | + Add-Member -NotePropertyName state -NotePropertyValue $([ProductState]($item.productState -band [ProductFlags]::ProductState)) + } + else { + Write-Error 'Could not add state property it already exists...' + } + If($results.Where({$_.instanceGuid -eq $item.instanceGuid}).Properties.name -notmatch "signatureStatus") { + $results.Where({$_.instanceGuid -eq $item.instanceGuid}) | + Add-Member -NotePropertyName signatureStatus -NotePropertyValue $([SignatureStatus]($item.productState -band [ProductFlags]::SignatureStatus)) + } + else { + Write-Error 'Could not add signatureStatus property it already exists...' + } + } + } + } + } + If ($ProductState -and (-not $Products)) { + If($results.Properties.name -notmatch "enabled") { + $results += New-Object PSObject -Property @{ + state = $([ProductState]($item.productState -band [ProductFlags]::ProductState)) + signatureStatus = $([SignatureStatus]($item.productState -band [ProductFlags]::SignatureStatus)) + } + } + } + } + + end { + If($results) { + return $results + } + } +} \ No newline at end of file diff --git a/src/Public/Test-IsProductEnabled.ps1 b/src/Public/Test-IsProductEnabled.ps1 deleted file mode 100644 index e0ed60e..0000000 --- a/src/Public/Test-IsProductEnabled.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -function Test-IsProductEnabled { - <# - .SYNOPSIS - Tests if given product state has product state flag enabled - .DESCRIPTION - Registry, WMI and other propties may contain a DWORD value or data object that represents the state of the corresponding product. - Specific enablement of the product is set to a bit in this DWORD, it can be challenging to gather the exact value of the flag. - This function will return true if the flag is set, meaning it is enabled. - .PARAMETER ProductState - The value (DWORD) containing the bitflags. - .EXAMPLE - PS C:\> Test-IsProductEnabled -ProductState 393472 - $false - This example shows basic functionality - .OUTPUTS - Bool - .NOTES - This function was build to resolve the state of a Antivirus Provider registered in Security Center. - Using this function it is possible to read which provider is enabled or not. - Other states are Snoozed which can be tested with Test-ProductIsSnoozed - #> - [CmdletBinding()] - param ( - # Product State contains a value (DWORD) that contains multiple bitflags and we use the productState flag (0000F000) - [Parameter(Mandatory, Position=0, ValueFromPipeline, HelpMessage="The value (DWORD) containing the bitflags.")] - [Int32]$ProductState - ) - $ProductEnabled = 0x1000 - $ProductStateMask = 0x0000f000 - - try - { - if( $($ProductEnabled -and $($ProductState -band $ProductStateMask) ) ) - { - return $true - } - else - { - return $false - } - } - catch - { - return $false - } -} \ No newline at end of file diff --git a/src/Public/Test-IsProductStateOn.ps1 b/src/Public/Test-IsProductStateOn.ps1 new file mode 100644 index 0000000..0f5922c --- /dev/null +++ b/src/Public/Test-IsProductStateOn.ps1 @@ -0,0 +1,50 @@ +function Test-IsProductStateOn { + <# + .SYNOPSIS + Tests if given product state has product state flag to On + .DESCRIPTION + Registry, WMI and other properties may contain a DWORD value or data object that represents the state of the corresponding product. + Specific state of the product is set to a bit in this DWORD, these states can be optained using bitwise operations. + This function will return true if the flag for product state is set to on, meaning this product is enabled. + .PARAMETER ProductState + The value (DWORD) containing the bitflags. + .EXAMPLE + PS C:\> Test-IsProductStateOn -ProductState 393472 + False + This example shows basic functionality + .OUTPUTS + Bool + .NOTES + This function was build to resolve the state of a Antivirus Provider registered in Security Center. + Using this function it is possible to read which product is set to On or not. + Other states are Off, Snoozed and Expired which can be resolved by using the enums provided in this module. + Example: Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct | Where-Object {($_.productState -band [ProductFlags]::ProductState) -eq [ProductState]::Off} + Will list all products that are disabled. + Use Add-ProductStates to return the actual state or cast the value using the stateflag + $prod = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct + [SignatureStatus]($prod[0].productState -band [ProductFlags]::SignatureStatus) + #> + [CmdletBinding()] + param ( + # Product State contains a value (DWORD) that contains multiple bitflags and we use the productState flag (0000F000) + [Parameter(Mandatory, Position = 0, ValueFromPipelineByPropertyName, HelpMessage = "The value (DWORD) containing the bitflags.")] + [Alias("STATE")] + [UInt32]$ProductState + ) + + try + { + if( $([ProductState]::On -and $($ProductState -band [ProductFlags]::ProductState) ) ) + { + return $true + } + else + { + return $false + } + } + catch + { + return $false + } +} \ No newline at end of file diff --git a/src/enums/ProductFlags.ps1 b/src/enums/ProductFlags.ps1 new file mode 100644 index 0000000..11aa6e8 --- /dev/null +++ b/src/enums/ProductFlags.ps1 @@ -0,0 +1,6 @@ +[Flags()] enum ProductFlags +{ + SignatureStatus = 0x000000F0 + ProductOwner = 0x00000F00 + ProductState = 0x0000F000 +} \ No newline at end of file diff --git a/src/enums/ProductOwner.ps1 b/src/enums/ProductOwner.ps1 new file mode 100644 index 0000000..6fbebf2 --- /dev/null +++ b/src/enums/ProductOwner.ps1 @@ -0,0 +1,5 @@ +[Flags()] enum ProductOwner +{ + NonMs = 0x000 + Windows = 0x100 +} \ No newline at end of file diff --git a/src/enums/ProductState.ps1 b/src/enums/ProductState.ps1 new file mode 100644 index 0000000..5c47b3c --- /dev/null +++ b/src/enums/ProductState.ps1 @@ -0,0 +1,7 @@ +[Flags()] enum ProductState +{ + Off = 0x0000 + On = 0x1000 + Snoozed = 0x2000 + Expired = 0x3000 +} \ No newline at end of file diff --git a/src/enums/SignatureStatus.ps1 b/src/enums/SignatureStatus.ps1 new file mode 100644 index 0000000..dacf041 --- /dev/null +++ b/src/enums/SignatureStatus.ps1 @@ -0,0 +1,5 @@ +[Flags()] enum SignatureStatus +{ + UpToDate = 0x00 + OutOfDate = 0x10 +} \ No newline at end of file diff --git a/src/wrt.helpers.psd1 b/src/wrt.helpers.psd1 index 778a7a3..7ff2e2f 100644 --- a/src/wrt.helpers.psd1 +++ b/src/wrt.helpers.psd1 @@ -13,7 +13,7 @@ # Version number of this module. - ModuleVersion = '1.0.3' + ModuleVersion = '1.0.8' # Supported PSEditions CompatiblePSEditions = 'Core', 'Desktop' @@ -77,10 +77,13 @@ # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. FunctionsToExport = @( + 'Add-ProductStates' 'Deploy-CompressedFile', 'Deploy-File', 'Find-File', + 'Remove-RegistryKey', 'Remove-RegistryValue', + 'Search-Registry', 'Send-MessageToLocalUsers', 'Send-ToLogAnalytics', 'Test-IsProductEnabled', @@ -111,7 +114,8 @@ # Tags applied to this module. These help with module discovery in online galleries. Tags = @( 'helper', - 'productstate' + 'productstate', + 'registry' ) # A URL to the license for this module. @@ -124,7 +128,7 @@ # IconUri = '' # ReleaseNotes of this module - ReleaseNotes = 'First release' + ReleaseNotes = 'Added Resolve-ProductState' } # End of PSData hashtable