SCCM Compliance state always 'Compliant' when remediation script runs - powershell

We're trying to use SCCM 2012 R2 to run some checks on clients and fix problems when needed. For this we use the PowerShell 'Script' option.
Problem description:
When a 'Discovery script' reports ‘Non-Compliant’ the ‘Remediation script’ is launched. Regardless of the output of the ‘Remediation script’, the result in the report on the client in ‘Configuration Manager > Configurations’ is always ‘Compliant’ even when the ‘Remediation script’ failed to fix the issue and as a result has different output then defined in the ‘Rules for compliance conditions’.
It seems that from the moment a ‘Remediation script’ is selected, the output of the SCCM Compliance State is always ‘Compliant’.
Example:
- Situation:
When there are files or folders in the folder ‘C:\Users\me\Downloads\Input_Test’ the ‘Discovery script’ reports ‘Not compliant to anything’ and kicks of the ‘Remediation script’. The remediation script takes action and can’t fix the problem so it reports back something else then ‘Compliant’, like ‘Non-Compliant’. The SCCM Compliance State should say after execution of the ‘Remediation script’: ‘Non-Compliant’ (which is not the case).
- PowerShell Discovery script:
$Paths = Get-ChildItem -Path 'C:\Users\me\Downloads\Input_Test' | Select -ExpandProperty FullName
New-EventLog -LogName Application -Source SCCMCompliance
if ($Paths) {
$Compliance = 'Non-Compliant'
Write-EventLog -LogName Application -Source SCCMCompliance -EntryType Warning -EventID 1 -Message “Discovery script: Non-Compliant”
}
else {
$Compliance = 'Compliant'
Write-EventLog -LogName Application -Source SCCMCompliance -EntryType Information -EventID 0 -Message “Discovery script: Compliant”
}
$Compliance
- PowerShell Remediation script:
Write-Output 'Non-Compliant'
Write-EventLog -LogName Application -Source SCCMCompliance -EntryType Warning -EventID 1 -Message “Remediation script: Non-Compliant $Paths”
- SCCM Rules for compliance conditions:
- SCCM Compliance State in the Configuration Manager:
In the Windows event viewer all steps can be tracked easily. Am I missing something super obvious here?

After much pain and hurt myself and #DarkLite1 have found that SCCM does not check compliance state after it has performed remediation
From the moment you use a 'Remediation script' the only 2 possible Compliance statusses are: 'Compliant' or 'Exit with error code'. This is done in PowerShell with 'Exit 1'.
For more information please see.
https://social.technet.microsoft.com/Forums/en-US/0f0f3e6f-7e9f-4376-a926-fc0b6aef5bf1/sccm-compliance-state-always-compliant-when-remediation-script-runs?forum=configmanagersecurity

Related

Powershell script behaves differently when ran in SQL Server Agent job

OS: Windows Server 2019 Standard
SQL: Microsoft SQL Server 2017 Standard CU28
PS version: 5.1.17763.2268
I've made a simple script to check if share is accessible before doing restore of databases. If the share is not accessible, it loops until the share becomes accessible.
Script is the first step in SQL Agent job and is set as PowerShell type.
while(!(Test-Path \\192.168.1.92\Share\))
{
Write-EventLog -LogName "Application" -Source "DB_Refresh" -EventID 1001 -EntryType Information -Message "Backup share is not accessible!" -Category 1
sleep 30
}
Write-EventLog -LogName "Application" -Source "DB_Refresh" -EventID 1001 -EntryType Information -Message "Backup share is accessible!" -Category 1
When I ran the script in PS ISE it works as it should. When I ran it in SQL Agent job step, negation works just the opposite as it should. When share is accessible it will loop and when it is not accessible it will not loop.
Any thoughts why does it behave like that? I have tried with -Not instead exclamation mark, but it behaves same.

Forward application log to windows Event log

I want to create a new EventLog for an application running on my server and the log should be taken from the default log file of the application.
Any idea on how to achieve this??.
Do you mean event source?
PowerShell would be
New-EventLog command found here
MSDM New-eventLog
Edit after more detail supplied.
Basic principle of what you want is to query the log file and write the lines found into a event log. This is done like the below:
#Get the content of the error log, gets the top 10 lines ONLY!!
$GetLog = Get-Content -Path D:\Errorlog.txt -totalcount 10
#Now take the data found and write it to the event log under the source and log below
Write-EventLog -LogName "Application" -Source "My Application" -Eventid 1001
-EntryType Error -Message "$Getlog" -Category 1

Write-EventLog for errors

When running the following one liner:
Write-EventLog -LogName Application -Source 'Application Error' -EntryType Error -EventID 1001 -Message 'Problem description'
We see the entry in the log Application:
According to Microsoft for EventID 1001, one should provide the values for %1, %2 and %3:
Detection of product '%1', feature '%2' failed during request for
component '%3'
How is this possible in PowerShell? When adding the switch -RawData 10, 20 only the type is filled in as following:
Is there a way to not have the other text available without creating a new log name or source in the Event log? Or to be able to fill in the variables? I'm writing to Application error in case the custom made log name or source isn't available. So there is somewhere a trace.
Thank you for your help.
The Event ID 1001 description you link to is specific to the MsiInstaller source.
For your own custom error events, use a custom Source identifier. You can check whether a source definition already exists on the machine, and if not, create it:
$CustomSource = 'MyCustomApplication'
# Wrap check i try/false to catch SourceExists() throwing access denied on failure
$SourceExists = try {
[System.Diagnostics.EventLog]::SourceExists($CustomSource)
} catch {
$false
}
if(-not $SourceExists)
{
# Create the Source definition
New-EventLog -Source $CustomSource -LogName Application
}
Write-EventLog -LogName Application -Source $CustomSource -EntryType Error -EventID 1001 -Message 'Problem description'
If you have a message resource file (the file containing the "templates" for your events), you can also include that in the call to New-EventLog

PowerShell: get-eventlog takes too long to complete

I am trying to script the review of the past 30 days of the Application and System Event Logs on remote servers, looking for only Warnings, Errors, or Critical entries.
Borrowing from what I have found here and in other forums, I have come up with:
$Date = Get-Date
$Range = $Date.AddDays(-30)
$Range = $range.ToShortDateString();
$LogName = Read-Host "Which Log? (Application, System)"
$Server = Read-Host "Please Enter Server Name"
get-eventlog $LogName -ComputerName $Server -After $range | where {$_.EntryType -eq "Error" -or $_.EntryType -eq "Warning" -or $_.EntryType -eq "Critical"}
This seems to run fairly quickly, but then hangs several (5-10+) minutes before returning to a prompt, if it does....
Note: if I remove the code:
-After $range
I can simply break the output with ctrl-c and get on with my day, but I'd rather it run as intended and then stop...
So: Any ideas on how to eliminate this hang?
I am also open to ideas on how to make the code more elegant (and faster)!
And I wouldn't mind the script checking both the Application and System logs without having to run twice....
Using the -EntryType string-array parameter on Get-EventLog is much faster than retrieving the entire event log and then filtering with Where-Object
Try get-eventlog -Logname System -EntryType ("Error", "Warning")
However... if I put "Critical" in the -EntryType array, I get: The argument "Critical" does not belong to the set "Error,Information,FailureAudit,SuccessAudit,Warning" specified by the ValidateSet attribute. which makes me wonder whether you should be heeding the advice as listed in Get-Help Get-EventLog:
The cmdlets that contain the EventLog noun (the EventLog cmdlets) work
only on classic event logs. To get events from logs that use the
Windows Event Log technology in Windows Vista and later versions of
Windows, use Get-WinEvent.
Using Get-WinEvent instead, I think this is what you want:
Get-Winevent -FilterHashtable #{LogName="System","Application"; Level=1,2,3; startTime=$range}
That will check for events of level 1, 2, or 3 (Critical, Error, Warning, respectively), and search both the Application and System logs in the same invocation.
I found that for remote systems, I could query several systems at once faster than I could individually, using the same command, if I wrapped it into an Invoke-Command. This is my solution. The more systems, the more time it saved. YMMV
$command = {Get-EventLog -LogName Application -After (Get-Date).AddHours("-24")}
Invoke-Command -ComputerName "foo1","foo2","foo3","foo4" -ScriptBlock $command

Creating a log for a powershell command

I have a simple command to create a CSV file in powershell. Is there a way to log this information separate from the file? I will be needing to manipulate the CSV file, so I don't want to rely on it being my only way of logging the data.
You can also export the output of commands by using the > and >> operators.
example:
You can write all of the Adobe services and their information to a file with this code:
get-service -DisplayName Adobe* > C:\services.txt
if you wanted to append to that with Windows services:
get-service -DisplayName Windows* >> C:\services.txt
so if you wanted to export your CSV to a file you can easily do so by adding a > at the end of the command pointing to the filename you wish to export it to:
> C:\Log_$date.csv
and if you ever needed to append more logs you can simply do so by using the >>
>> C:\Log_$date.csv
if you use > it will overwrite and existing data in the file with new data. >> appends.
If you need a log for people who are in charge of the production you can add your own application log using dedicated Cmdlets. A the moment I create and use one PowerShell log for all my scripts to publish details of the execution (information) and errors (in coordination with good exception handling) for people who are in charge of the production. You can dedicate a log for one script (as it exists a log for DNS etc.)
Here is an example :
# List of logs
Get-EventLog -list
# Creating your own log
New-EventLog -LogName "SlxScripting" -Source "MaSource"
# List of logs
Get-EventLog -list
# Writting in your own log
Write-EventLog -LogName "SlxScripting" -EventId 12 `
-Message "Mon Message"
-Source "MaSource" -EntryType Warning
# Reading in your own log
Get-EventLog -LogName "SlxScripting"
# Suppressing your log
Remove-EventLog -LogName "SlxScripting"