wrt.helpers.psm1
[Flags()] enum ProductFlags { SignatureStatus = 0x000000F0 ProductOwner = 0x00000F00 ProductState = 0x0000F000 } [Flags()] enum ProductOwner { NonMs = 0x000 Windows = 0x100 } [Flags()] enum ProductState { Off = 0x0000 On = 0x1000 Snoozed = 0x2000 Expired = 0x3000 } [Flags()] enum SignatureStatus { UpToDate = 0x00 OutOfDate = 0x10 } <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE PS C:\> <example usage> Explanation of what the example does .INPUTS Inputs (if any) .OUTPUTS Output (if any) .NOTES General notes #> # Create the function to create the authorization signature that is used by Post-LogAnalyticsData Function Build-Signature ($customerId, $sharedKey, $date, $contentLength, $method, $contentType, $resource) { $xHeaders = "x-ms-date:" + $date $stringToHash = $method + "`n" + $contentLength + "`n" + $contentType + "`n" + $xHeaders + "`n" + $resource $bytesToHash = [Text.Encoding]::UTF8.GetBytes($stringToHash) $keyBytes = [Convert]::FromBase64String($sharedKey) $sha256 = New-Object System.Security.Cryptography.HMACSHA256 $sha256.Key = $keyBytes $calculatedHash = $sha256.ComputeHash($bytesToHash) $encodedHash = [Convert]::ToBase64String($calculatedHash) $authorization = 'SharedKey {0}:{1}' -f $customerId,$encodedHash return $authorization } <# .SYNOPSIS Compare PS Objects and return them with a clear equality sign .DESCRIPTION This function is used for comparison to see if an object needs to be updated .PARAMETER ReferenceObject Reference object is the data of the object as present or persistent .PARAMETER DifferenceObject Difference object is data that is or is expected to be altered .EXAMPLE Compare-PSObject -ReferenceObject $PSObject1 -ReferenceObject $PSObject2 .NOTES NAME: Compare-PSObject #> function Compare-PSObject { [CmdletBinding()] param ( # Reference value is the Online available [Parameter(Mandatory)] [psobject]$ReferenceObject, # Difference template is the template that will be uploaded [Parameter(Mandatory)] [psobject]$DifferenceObject ) process { $objprops = $ReferenceObject | Get-Member -MemberType Property, NoteProperty | ForEach-Object Name $objprops += $DifferenceObject | Get-Member -MemberType Property, NoteProperty | ForEach-Object Name $objprops = $objprops | Sort-Object -Unique | Select-Object $diffs = @() foreach ($objprop in $objprops) { $diff = Compare-Object $ReferenceObject $DifferenceObject -Property $objprop if ($diff) { $diffprops = @{ PropertyName = $objprop RefValue = ($diff | Where-Object { $_.SideIndicator -eq '<=' } | ForEach-Object $($objprop)) DiffValue = ($diff | Where-Object { $_.SideIndicator -eq '=>' } | ForEach-Object $($objprop)) } $diffs += New-Object PSObject -Property $diffprops } } if ($diffs) { return ($diffs | Select-Object PropertyName, RefValue, DiffValue) } } } 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 } } } function Convert-StringToShort { <# .SYNOPSIS returns an abreviate from the string you provide, try to get a 3 letter word .EXAMPLE PS> Get-ShortEnvironment -StringInput 'Test' tst PS>_ .PARAMETER StringInput The string of the text file you'd like to make shorter If the word your provide is a well known one I try to make the best of it #> [CmdletBinding()] param ( # this where you provide the string [Parameter(Mandatory = $true)] [string]$StringInput ) begin { # we do nothing here noting to initialise } process { if($StringInput.Length -gt 3 ) { Switch ($StringInput) { "development"{ "dev" } "production"{ "prd" } "prod" { "prd" } "testing" { "tst" } "test" { "tst" } "staging" { "stg" } "testing" { "tst" } "acceptance"{ "acc" } default { ($StringInput.ToLower() -replace '[aeiouy]').SubString(0,3) } } } else { Write-Host $StringInput.ToLower() } } end { # we do nothing here noting to cleanup } } function Convert-ToShortString { <# .SYNOPSIS returns an abreviate from the string you provide, try to get a 3 letter word .EXAMPLE PS> Get-ShortEnvironment -StringInput 'Test' tst PS>_ .PARAMETER StringInput The string of the text file you'd like to make shorter If the word your provide is a well known one I try to make the best of it #> [CmdletBinding()] param ( # this where you provide the string [Parameter(Mandatory = $true, ValueFromPipeline)] [string]$StringInput ) begin { # we do nothing here noting to initialise } process { if($StringInput.Length -gt 3 ) { Switch ($StringInput) { "development"{ return "dev" } "production"{ return "prd" } "prod" { return "prd" } "testing" { return "tst" } "test" { return "tst" } "staging" { return "stg" } "testing" { return "tst" } "acceptance"{ return "acc" } default { return ($StringInput.ToLower() -replace '[aeiouy]').SubString(0,3) } } } else { return $StringInput.ToLower() } } end { # we do nothing here noting to cleanup } } Function Deploy-CompressedFile { [CmdletBinding()] param ( [Parameter()] [string] $Url, [Parameter()] [string] $CorrelationId, # if should be logged to LogAnalytics [Parameter()] [switch] $Log ) $PSDefaultParameterValues = $Global:PSDefaultParameterValues $ProgressPreference = "SilentlyContinue" $targetPath = "$env:TEMP\{$correlationId}" $fullpathZip = "$env:TEMP\{$correlationId}.zip" try { Invoke-WebRequest $Url -OutFile $fullpathZip -ErrorAction Stop If($Log) { Send-ToLogAnalytics -message "The compressed uninstall package from Azure Blob to the local computer, $fullpathZip" } } catch { If($Log) { Send-ToLogAnalytics -message "Uninstall package could not be downloaded $($_.Exception) $($_.ErrorDetails)" } return $false } try { Expand-Archive -Path $fullpathZip -DestinationPath $targetPath -Force -ErrorAction Stop If($Log) { Send-ToLogAnalytics -message "Extracted the compressed uninstall package to: $targetPath" } } catch { If($Log) { Send-ToLogAnalytics -message "Uninstall package could not be extracted $($_.Exception) $($_.ErrorDetails)" } return $false } return $true } function Deploy-File { [CmdletBinding()] param ( # Url of the location of the script [Parameter()] [string] $Url, [Parameter()] [string] $CorrelationId, # if should be logged to LogAnalytics [Parameter()] [switch] $Log ) $PSDefaultParameterValues = $Global:PSDefaultParameterValues $ProgressPreference = "SilentlyContinue" $targetPath = "$env:TEMP\{$correlationId}" try { #Invoke-WebRequest $item -OutFile $($targetPath + $item.Split('/')[-1]) -ErrorAction Stop $outFile = $($targetPath + "\$correlationId.ps1") Invoke-WebRequest $Url -OutFile $outFile -ErrorAction Stop If($Log) { Send-ToLogAnalytics -message "PS1File is downloaded." } return $outFile } catch { If($Log) { Send-ToLogAnalytics -message "Could not download PS1File. $($_.Exception) $($_.ErrorDetails)" } return $false } } Function Find-File { [CmdletBinding()] param ( # Specifies a path to one location. Unlike the Path parameter, the value of the LiteralPath parameter is # used exactly as it is typed. No characters are interpreted as wildcards. If the path includes escape characters, # enclose it in single quotation marks. Single quotation marks tell Windows PowerShell not to interpret any # characters as escape sequences. [Parameter(Mandatory=$true, Position=0, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName=$true, HelpMessage="Literal path to one location.")] [Alias("PSPath")] [ValidateNotNullOrEmpty()] [string] $LiteralPath, #filename to search recursively in LiteralPath for [Parameter()] [string] $filename, # if should be logged to LogAnalytics [Parameter()] [switch] $Log ) $PSDefaultParameterValues = $Global:PSDefaultParameterValues try { $filefound = Get-ChildItem -Path $LiteralPath -Filter $filename -Recurse -ErrorAction Stop $result = $filefound[0].FullName } catch { If($Log) { Write-LogAnalyticsMessage -message "Could not locate $filename in $LiteralPath " } } return $result } function Find-InTextFile { <# .SYNOPSIS Performs a find (or replace) on a string in a text file or files. .EXAMPLE PS> Find-InTextFile -FilePath 'C:\MyFile.txt' -Find 'water' -Replace 'wine' Replaces all instances of the string 'water' into the string 'wine' in 'C:\MyFile.txt'. .EXAMPLE PS> Find-InTextFile -FilePath 'C:\MyFile.txt' -Find 'water' Finds all instances of the string 'water' in the file 'C:\MyFile.txt'. .PARAMETER FilePath The file path of the text file you'd like to perform a find/replace on. .PARAMETER Find The string you'd like to replace. .PARAMETER Replace The string you'd like to replace your 'Find' string with. .PARAMETER NewFilePath If a new file with the replaced the string needs to be created instead of replacing the contents of the existing file use this param to create a new file. .PARAMETER Force If the NewFilePath param is used using this param will overwrite any file that exists in NewFilePath. .NOTES from: https://adamtheautomator.com/powershell-replace-text-in-file/ Thanks to: https://github.com/adbertram Visit: https://adamtheautomator.com/ #> [CmdletBinding(DefaultParameterSetName = 'NewFile')] [OutputType()] param ( [Parameter(Mandatory = $true)] [ValidateScript({Test-Path -Path $_ -PathType 'Leaf'})] [string[]]$FilePath, [Parameter(Mandatory = $true)] [string]$Find, [Parameter()] [string]$Replace, [Parameter(ParameterSetName = 'NewFile')] [ValidateScript({ Test-Path -Path ($_ | Split-Path -Parent) -PathType 'Container' })] [string]$NewFilePath, [Parameter(ParameterSetName = 'NewFile')] [switch]$Force ) begin { $Find = [regex]::Escape($Find) } process { try { foreach ($File in $FilePath) { if ($Replace) { if ($NewFilePath) { if ((Test-Path -Path $NewFilePath -PathType 'Leaf') -and $Force.IsPresent) { Remove-Item -Path $NewFilePath -Force (Get-Content $File) -replace $Find, $Replace | Add-Content -Path $NewFilePath -Force } elseif ((Test-Path -Path $NewFilePath -PathType 'Leaf') -and !$Force.IsPresent) { Write-Warning "The file at '$NewFilePath' already exists and the -Force param was not used" } else { (Get-Content $File) -replace $Find, $Replace | Add-Content -Path $NewFilePath -Force } } else { (Get-Content $File) -replace $Find, $Replace | Add-Content -Path "$File.tmp" -Force Remove-Item -Path $File Move-Item -Path "$File.tmp" -Destination $File } } else { Select-String -Path $File -Pattern $Find } } } catch { Write-Error $_.Exception.Message } } } <# .SYNOPSIS Removes a complete key from the registry .DESCRIPTION Removes a complete key from the registry and returns true or false if successfull or not .EXAMPLE PS C:\> Remove-RegistryKey -Path "HKLM:\testkey" Removes the Key HKLM:\testkey .NOTES General notes .OUTPUTS Boolean value which corresponds to the outcome #> function Remove-RegistryKey { param ( # the path to the value [Parameter()] [string] $KeyPath, # if should be logged to LogAnalytics [Parameter()] [switch] $Log ) $PSDefaultParameterValues = $Global:PSDefaultParameterValues If(Test-Path $KeyPath) { try { Remove-Item -Path $KeyPath -ErrorAction Stop -Recurse -Force If($Log) { Send-ToLogAnalytics -message "Removed $KeyPath." } } catch { If($Log) { Send-ToLogAnalytics -message "Could not remove $KeyPath. $($_.Exception) $($_.ErrorDetails)" } } } } <# .SYNOPSIS Removes a value from the registry .DESCRIPTION Removes a value from the registry and returns true or false if successfull or not .EXAMPLE PS C:\> Remove-Registry -Path "HKLM:\testkey" -Value "testValue" Removes the value testValue from HKLM:\testkey .NOTES General notes .OUTPUTS Boolean value which corresponds to the outcome #> function Remove-RegistryValue { param ( # the path to the value [Parameter()] [string] $Path, # the name of the value [Parameter()] [string] $Value, # if should be logged to LogAnalytics [Parameter()] [switch] $Log ) $PSDefaultParameterValues = $Global:PSDefaultParameterValues If(Test-Path $Path) { If(Test-RegistryValue -Path $Path -Value $RegistryValue) { try { Remove-ItemProperty -Path $Path -Name $RegistryValue -ErrorAction Stop If($Log) { Send-ToLogAnalytics -message "Removed $Path in path $RegistryPath." } } catch { If($Log) { Send-ToLogAnalytics -message "Could not remove $Path in path $RegistryPath. $($_.Exception) $($_.ErrorDetails)" } } } } } function Search-Registry { <# .SYNOPSIS Searches registry key names, value names, and value data (limited). .DESCRIPTION This function can search registry key names, value names, and value data (in a limited fashion). It outputs custom objects that contain the key and the first match type (KeyName, ValueName, or ValueData). .EXAMPLE Search-Registry -Path HKLM:\SYSTEM\CurrentControlSet\Services\* -SearchRegex "svchost" -ValueData .EXAMPLE Search-Registry -Path HKLM:\SOFTWARE\Microsoft -Recurse -ValueNameRegex "ValueName1|ValueName2" -ValueDataRegex "ValueData" -KeyNameRegex "KeyNameToFind1|KeyNameToFind2" .NOTES from: https://gallery.technet.microsoft.com/scriptcenter/Search-Registry-Find-Keys-b4ce08b4 Thanks to: https://social.technet.microsoft.com/profile/rohn%20edwards/ #> [CmdletBinding()] param( [Parameter(Mandatory, Position=0, ValueFromPipelineByPropertyName)] [Alias("PsPath")] # Registry path to search [string[]] $Path, # Specifies whether or not all subkeys should also be searched [switch] $Recurse, [Parameter(ParameterSetName="SingleSearchString", Mandatory)] # A regular expression that will be checked against key names, value names, and value data (depending on the specified switches) [string] $SearchRegex, [Parameter(ParameterSetName="SingleSearchString")] # When the -SearchRegex parameter is used, this switch means that key names will be tested (if none of the three switches are used, keys will be tested) [switch] $KeyName, [Parameter(ParameterSetName="SingleSearchString")] # When the -SearchRegex parameter is used, this switch means that the value names will be tested (if none of the three switches are used, value names will be tested) [switch] $ValueName, [Parameter(ParameterSetName="SingleSearchString")] # When the -SearchRegex parameter is used, this switch means that the value data will be tested (if none of the three switches are used, value data will be tested) [switch] $ValueData, [Parameter(ParameterSetName="MultipleSearchStrings")] # Specifies a regex that will be checked against key names only [string] $KeyNameRegex, [Parameter(ParameterSetName="MultipleSearchStrings")] # Specifies a regex that will be checked against value names only [string] $ValueNameRegex, [Parameter(ParameterSetName="MultipleSearchStrings")] # Specifies a regex that will be checked against value data only [string] $ValueDataRegex ) begin { switch ($PSCmdlet.ParameterSetName) { SingleSearchString { $NoSwitchesSpecified = -not ($PSBoundParameters.ContainsKey("KeyName") -or $PSBoundParameters.ContainsKey("ValueName") -or $PSBoundParameters.ContainsKey("ValueData")) if ($KeyName -or $NoSwitchesSpecified) { $KeyNameRegex = $SearchRegex } if ($ValueName -or $NoSwitchesSpecified) { $ValueNameRegex = $SearchRegex } if ($ValueData -or $NoSwitchesSpecified) { $ValueDataRegex = $SearchRegex } } MultipleSearchStrings { # No extra work needed } } } process { foreach ($CurrentPath in $Path) { Get-ChildItem $CurrentPath -Recurse:$Recurse | ForEach-Object { $Key = $_ if ($KeyNameRegex) { Write-Verbose ("{0}: Checking KeyNamesRegex" -f $Key.Name) if ($Key.PSChildName -match $KeyNameRegex) { Write-Verbose " -> Match found!" return [PSCustomObject] @{ Key = $Key Reason = "KeyName" } } } if ($ValueNameRegex) { Write-Verbose ("{0}: Checking ValueNamesRegex" -f $Key.Name) if ($Key.GetValueNames() -match $ValueNameRegex) { Write-Verbose " -> Match found!" return [PSCustomObject] @{ Key = $Key Reason = "ValueName" } } } if ($ValueDataRegex) { Write-Verbose ("{0}: Checking ValueDataRegex" -f $Key.Name) if (($Key.GetValueNames() | % { $Key.GetValue($_) }) -match $ValueDataRegex) { Write-Verbose " -> Match!" return [PSCustomObject] @{ Key = $Key Reason = "ValueData" } } } } } } } Function Send-MessageToLocalUsers { [CmdletBinding()] param ( [Parameter()] [string] $Message, # timeout for message [Parameter(HelpMessage="Seconds until the message is automatically discarded. Default is 0, means never.")] [int] $TimeOut = 0, # if should be logged to LogAnalytics [Parameter()] [switch] $Log ) $PSDefaultParameterValues = $Global:PSDefaultParameterValues try { Start-Process "$env:SystemRoot\System32\msg.exe" -ArgumentList "* /time $TimeOut /v '$Message' " -ErrorAction Stop If($Log) { Send-ToLogAnalytics -message "Message send to all users on this system." } } catch { If($Log) { Send-ToLogAnalytics -message "Could not send message." } } } <# .SYNOPSIS Sends a given message to a custom log in Log Analytics workspace .DESCRIPTION Sends a given message to a custom log in Log Analytics workspace. Use PSDefaultParameterValues to shorten this command. This will improve readability of the script. .EXAMPLE You could set some paramters once like here using $PSDefaultParameterValues $PSDefaultParameterValues = @{ "Send-ToLogAnalytics:LogName"="myCustomLog"; "Send-ToLogAnalytics:SharedKey"="<sharedKey>"; "Send-ToLogAnalytics:CustomerId"="CustomerID or WorkspaceID"; "Send-ToLogAnalytics:ScriptVersion"="<any value>"; "Send-ToLogAnalytics:CorrelationId"= $(New-Guid | Select-Object -ExpandProperty Guid); } Send-ToLogAnalytics -message 'Send from Powershell to LogAnalytics using wrt.helpers Send-ToLogAnalytics' .PARAMETER Message Contents if this parameter will be passed to log analytics in the collumn message .NOTES Besides #> Function Send-ToLogAnalytics { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string] $Message, # the log name [Parameter(Mandatory)] [string] $LogName, # parameter to set a script version to the log message [Parameter(Mandatory)] [string] $ScriptVersion, # sets the correlationId to the log message, see this as a session ID this is unique to the session this script runs [Parameter(Mandatory)] [string] $CorrelationId, # sets the customer or workspaceId to which this message is send [Parameter(Mandatory)] [string] $CustomerId, # the sharedsecret which is used to as an API key [Parameter(Mandatory)] [string] $SharedKey ) $ProgressPreference = "SilentlyContinue" Write-Verbose $message $method = "POST" $contentType = "application/json" $resource = "/api/logs" $rfc1123date = [DateTime]::UtcNow.ToString("r") $ISO8601DateTime = [DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ") $LogObject = New-Object -TypeName PSObject $LogObject | Add-Member -NotePropertyName ISO8601DateTime -NotePropertyValue $ISO8601DateTime $LogObject | Add-Member -NotePropertyName Computer -NotePropertyValue $($env:COMPUTERNAME) $LogObject | Add-Member -NotePropertyName Message -NotePropertyValue $Message $LogObject | Add-Member -NotePropertyName ScriptVersion -NotePropertyValue $ScriptVersion $LogObject | Add-Member -NotePropertyName LoggedOnUser -NotePropertyValue $loggedOnUser $LogObject | Add-Member -NotePropertyName CorrelationId -NotePropertyValue $CorrelationId $json = $LogObject | ConvertTo-Json -Compress $body = [System.Text.Encoding]::UTF8.GetBytes($json) $contentLength = $body.Length $signature = Build-Signature ` -customerId $CustomerId ` -sharedKey $SharedKey ` -date $rfc1123date ` -contentLength $contentLength ` -fileName $fileName ` -method $method ` -contentType $contentType ` -resource $resource $uri = "https://" + $CustomerId + ".ods.opinsights.azure.com" + $resource + "?api-version=2016-04-01" # time-generated-field The name of a field in the data that contains the timestamp of the data item. If you specify a field then its contents are used for TimeGenerated. If this field isn’t specified, the default for TimeGenerated is the time that the message is ingested. The contents of the message field should follow the ISO 8601 format YYYY-MM-DDThh:mm:ssZ. $headers = @{ "Authorization" = $signature; "Log-Type" = $LogName; "x-ms-date" = $rfc1123date; "time-generated-field" = "ISO8601DateTime"; } $response = Invoke-WebRequest -Uri $uri -Method $method -ContentType $contentType -Headers $headers -Body $body -UseBasicParsing Start-Sleep -Milliseconds 100 } 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 } } <# .SYNOPSIS Return $true if the value is found .DESCRIPTION Return $true if the value is found, $false if not .EXAMPLE PS C:\> Test-RegistryValue -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Value "ProductName" The output of the function above will return true. .OUTPUTS Boolean value which corresponds to the outcome #> function Test-RegistryValue { param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()]$Path, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()]$Value ) try { Get-ItemProperty -Path $Path -ErrorAction Stop | Select-Object -ExpandProperty $Value -ErrorAction Stop | Out-Null return $true } catch { return $false } } |