Last active
June 10, 2024 05:33
-
-
Save aikiox/98f97ccc092557acc1ea958d65f8f361 to your computer and use it in GitHub Desktop.
PingCastle - Generate and send report after score comparison
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<#PSScriptInfo | |
.VERSION 0.1 | |
.GUID dcf37da6-cd01-43c7-8e51-a5ce735aab42 | |
.AUTHOR Romain Tiennot | |
.COMPANYNAME Colibri SAS / ManoMano | |
.COPYRIGHT Copyright (c) Colibri SAS / Manomano 2021 | |
.TAGS pingcastle security activedirectory | |
.PROJECTURI https://gist.github.com/aikiox/98f97ccc092557acc1ea958d65f8f361 | |
.EXTERNALMODULEDEPENDENCIES | |
.REQUIREDSCRIPTS | |
.EXTERNALSCRIPTDEPENDENCIES | |
.RELEASENOTES | |
Version 1.0: Original published version. | |
#> | |
<# | |
.SYNOPSIS | |
Example of a script to send the PingCastle report | |
Copyright (c) Colibri SAS / Manomano 2021 | |
Permission to use, copy, modify, and distribute this software for any | |
purpose with or without fee is hereby granted, provided that the above | |
copyright notice and this permission notice appear in all copies. | |
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
.DESCRIPTION | |
Execute PingCastle for generate report | |
Compares values to the previous report | |
Moves reports to a directory | |
Update PingCastle | |
.EXAMPLE | |
PS C:\> Send-PingCastleReport.ps1 | |
#> | |
$ErrorActionPreference = 'Stop' | |
$InformationPreference = 'Continue' | |
#region Variable | |
$ApplicationName = 'PingCastle' | |
$PingCastle = [pscustomobject]@{ | |
Name = $ApplicationName | |
ProgramPath = Join-Path $PSScriptRoot $ApplicationName | |
ProgramName = '{0}.exe' -f $ApplicationName | |
Arguments = '--healthcheck --level Full' | |
ReportFileName = 'ad_hc_{0}' -f ($env:USERDNSDOMAIN).ToLower() | |
ReportFolder = "Reports" | |
ScoreFileName = '{0}Score.txt' -f $ApplicationName | |
ProgramUpdate = '{0}AutoUpdater.exe' -f $ApplicationName | |
ArgumentsUpdate = '--wait-for-days 30' | |
} | |
$pingCastleFullpath = Join-Path $PingCastle.ProgramPath $PingCastle.ProgramName | |
$pingCastleUpdateFullpath = Join-Path $PingCastle.ProgramPath $PingCastle.ProgramUpdate | |
$pingCastleReportLogs = Join-Path $PingCastle.ProgramPath $PingCastle.ReportFolder | |
$pingCastleScoreFileFullpath = Join-Path $pingCastleReportLogs $PingCastle.ScoreFileName | |
$pingCastleReportFullpath = Join-Path $PingCastle.ProgramPath ('{0}.html' -f $PingCastle.ReportFileName) | |
$pingCastleReportXMLFullpath = Join-Path $PingCastle.ProgramPath ('{0}.xml' -f $PingCastle.ReportFileName) | |
$pingCastleReportDate = Get-Date -UFormat %Y%m%d_%H%M%S | |
$pingCastleReportFileNameDate = ('{0}_{1}' -f $pingCastleReportDate, ('{0}.html' -f $PingCastle.ReportFileName)) | |
$sentNotification = $false | |
$splatProcess = @{ | |
WindowStyle = 'Hidden' | |
Wait = $true | |
} | |
#endregion | |
# Check if program exist | |
if (-not(Test-Path $pingCastleFullpath)) { | |
Write-Error -Message ("Path not found {0}" -f $pingCastleFullpath) | |
} | |
# Check if log directory exist. If not, create it | |
if (-not (Test-Path $pingCastleReportLogs)) { | |
try { | |
$null = New-Item -Path $pingCastleReportLogs -ItemType directory | |
} | |
Catch { | |
Write-Error -Message ("Error for create directory {0}" -f $pingCastleReportLogs) | |
} | |
} | |
# Try to start program and catch any error | |
try { | |
Set-Location -Path $PingCastle.ProgramPath | |
#Start-Process -FilePath $pingCastleFullpath -ArgumentList $PingCastle.Arguments @splatProcess | |
} | |
Catch { | |
Write-Error -Message ("Error for execute {0}" -f $pingCastleFullpath) | |
} | |
# Check if report exist after execution | |
foreach ($pingCastleTestFile in ($pingCastleReportFullpath, $pingCastleReportXMLFullpath)) { | |
if (-not (Test-Path $pingCastleTestFile)) { | |
Write-Error -Message ("Report file not found {0}" -f $pingCastleTestFile) | |
} | |
} | |
# Get content on XML file | |
try { | |
$contentPingCastleReportXML = $null | |
$contentPingCastleReportXML = (Select-Xml -Path $pingCastleReportXMLFullpath -XPath "/HealthcheckData").node | |
} | |
catch { | |
Write-Error -Message ("Unable to read the content of the xml file {0}" -f $pingCastleReportXMLFullpath) | |
} | |
# Convert to json all score from xml file | |
try { | |
$contentPingCastleReport = $contentPingCastleReportXMLToJSON = $null | |
$contentPingCastleReport = $contentPingCastleReportXML | Select-Object *Score | |
$contentPingCastleReportXMLToJSON = $contentPingCastleReport | ConvertTo-Json -Compress | |
} | |
catch { | |
Write-Error -Message "Unable to convert the content to json" | |
} | |
# Check if PingCastle previous score file exist | |
if (-not (Test-Path $pingCastleScoreFileFullpath)) { | |
# if don't exist, sent report | |
$sentNotification = $true | |
} | |
else { | |
try { | |
# Get content of previous PingCastle score | |
$contentPingCastleScoreFile = Get-Content $pingCastleScoreFileFullpath | |
# Compare value between previous score and current score | |
if ($contentPingCastleScoreFile -cne $contentPingCastleReportXMLToJSON) { | |
# If value is different, sent report | |
$sentNotification = $true | |
} | |
} | |
catch { | |
Write-Warning -Message ("Unable to read the content of the txt file {0}" -f $pingCastleScoreFileFullpath) | |
$sentNotification = $true | |
} | |
} | |
# If content is same, don't sent report | |
if ($sentNotification -eq $false) { | |
Remove-Item ("{0}.{1}" -f (Join-Path $PingCastle.ProgramPath $PingCastle.ReportFileName), '*') | |
Write-Information "Same value on PingCastle report. Report deleted." | |
exit | |
} | |
Write-Information "Sending information by email, webhook, etc..." | |
$contentPingCastleReport | |
# Update report file with current score | |
try { | |
$contentPingCastleReportXMLToJSON | Out-File $pingCastleScoreFileFullpath -Force | |
} | |
Catch { | |
Write-Error -Message ("Error for update report score file {0}" -f $pingCastleScoreFileFullpath) | |
} | |
# Move report to logs directory | |
try { | |
$pingCastleMoveFile = (Join-Path $pingCastleReportLogs $pingCastleReportFileNameDate) | |
Move-Item -Path $pingCastleReportFullpath -Destination $pingCastleMoveFile | |
} | |
catch { | |
Write-Error -Message ("Error for move report file to logs directory {0}" -f $pingCastleReportFullpath) | |
} | |
# Try to start update program and catch any error | |
try { | |
Write-Information "Trying to update" | |
Start-Process -FilePath $pingCastleUpdateFullpath -ArgumentList $PingCastle.ArgumentsUpdate @splatProcess | |
Write-Information "Update completed" | |
} | |
Catch { | |
Write-Error -Message ("Error for execute update program {0}" -f $pingCastleUpdateFullpath) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment