I originally asked this question here: Powershell script for checking AD replication which helped resolve the logic for my script. I've since added additional information and checks to the script and the final result is below:
function ExitWithCode {
<#
.SYNOPSIS
Specifies custom exit code.
.DESCRIPTION
The ExitWithCode function allows you to pass in a custom exit code
throughout your script by calling the function.
.PARAMETER
Use the -exitcode parameter followed by an integer to specify the error
code
.EXAMPLE
Calling ExitWithCode -exitcode 2 will stop the powershell.exe process
and report an exit code of 2 to the system.
#>
param
(
$exitcode
)
$host.SetShouldExit($exitcode)
exit
}
function Write-Log {
<#
.SYNOPSIS
Write-Log writes a message to a logfile
.DESCRIPTION
The Write-Log function is designed to add logging capability to other
scripts. In addition to writing output and/or verbose you can write to
a log file for later debugging.
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[Alias('LogContent')]
[string]$Message,
[Parameter(Mandatory = $false)]
[ValidateSet("Error", "Info", "Status")]
[string]$Level = "Info",
[Parameter(Mandatory = $false)]
[Alias('LogPath')]
[string]$Path = ('C:\dataloop\ADHealthCheck\ADHealthCheck' + '_' + "$(Get-Date -Format MM-dd-yyyy)" + '.log'),
[Parameter(Mandatory = $false)]
[string]$logFolderPath = 'c:\dataloop\ADHealthCheck\'
)
BEGIN {
[string]$FormattedDate = Get-Date -Format "dd-MM-yyyy HH:mm"
#Test to see if the 'c:\dataloop\ADHealthCheck\' directory exist. If it does not, than create it.
If (-NOT (Test-Path $logFolderPath)) {
Write-Verbose "Creating the folder, $logFolderPath"
New-Item $logFolderPath -Force -ItemType directory
}
#Test to see if the file 'c:\dataloop\ADHeatlhCheck\ADHealthCheck_{current_date}.log' exist. If it does not, than create it.
If (-NOT (Test-Path $path)) {
Write-Verbose "Creating $Path"
[System.IO.FileInfo]$LogFile = New-Item $Path -Force -ItemType file
}
}
PROCESS {
[string]$LogLine = "$FormattedDate - $Level - $message"
$LogLine | Out-File -FilePath $Path -Append
Switch ($Level) {
"Info" {Write-Verbose $LogLine}
"Status" {Write-Output $LogLine}
"Error" {Write-Error $LogLine}
}
}
END {}
}
function Get-ADHealthCheck {
[CmdletBinding()]
param()
BEGIN {
Write-Log "Beginning the AD Health Check..."
}
PROCESS {
#Obtain a list of all the domain controllers and sort them by name in ascedening order
$DCs = Get-ADDomainController -Filter * |sort name
Write-Log "$($DCs.Count) Domain Controllers found" -level Info
#Create an empty array to store object properties later
$results = @()
ForEach ($DC in $DCs) {
Write-Log "Getting replication metadata for $($DC.HostName)" -level Status
#Grab replication metadata for each domain controller. Reports metadata for both inbound and outbound partners
$ReplStatuses = Get-ADReplicationPartnerMetadata -target $DC.HostName -PartnerType Both -ErrorAction SilentlyContinue
If ($ReplStatuses) {
#Reports the number of replication links found for each successful query
Write-Log "$($ReplStatuses.Count) replication links found for $($DC.HostName)" -level Info
ForEach ($ReplStatus in $ReplStatuses) {
#Retrieves the hostname of each partner by splitting the 'Partner' key
$Partner = $ReplStatus.Partner.Split(",")[1].Replace("CN=","")
#create a custom object and set custom properties
$results += [pscustomobject] @{
'Source DC' = $DC.Hostname.ToUpper()
'Partner DC' = (Get-ADComputer $Partner).DNSHostName.ToUpper()
'Direction' = $ReplStatus.PartnerType
'Type' = $ReplStatus.IntersiteTransportType
'Last Attempt' = $ReplStatus.LastReplicationAttempt
'Last Success' = $ReplStatus.LastReplicationSuccess
'Last Result' = $ReplStatus.LastReplicationResult
}
}
}
Else {
#creates a custom object to store information about any domain controller where replication data could not be retrieved
Write-Log "Unable to get replication status for $($DC.HostName)" -level Error
$results += [pscustomobject] @{
'Source DC' = $DC.Hostname.ToUpper()
'Partner DC' = "N/A"
'Direction' = "N/A"
'Type' = "N/A"
'Last Attempt' = "N/A"
'Last Success' = "N/A"
'Last Result' = "N/A"
}
}
}
#Start checking for outdated log files to purge
Write-Log "Cleaning out outdated Log files..."
#Define the log path
$logPath = 'c:\dataloop\ADHealthCheck\'
#Do the actual check based on the log path defined above
$checkLogPath = Get-ChildItem -Path $logPath -Recurse
#Performs check against the log path and returns any files where the last modified date is greater than 14 days
$retentionPeriod = $checkLogPath | Where {$_.LastWriteTime -lt (Get-Date).AddDays(-14)}
foreach ($file in $retentionPeriod) {
if ($retentionPeriod) {
Write-Log "Deleting file $file since it is older than 14 days" -Level Info
#Sets the current working directory to the log path
Set-Location $logPath
#Deletes any files where the modified date is greater than 14 days
Remove-Item $file -Force
}
else {
Write-Log "There were no files older than two weeks. Nothing to delete at this time" -Level Info
}
}
#Check to see if any of the results contain failure
$failedChecks = $results | Where-object{$_.'Last Result' -ne 0}
#Evaluate $failedChecks as a boolean. If there are no failed checks Else can be assumed that everything is fine.
If ($failedChecks) {
Write-Log "These domain controllers have replication errors. Please review them..." -Level Error
$error = $failedChecks | select 'Source DC','Partner DC','Direction' | ft -AutoSize | Out-String
Write-Log $error -Level Error
ExitWithCode -exitcode 2
}
Else {
Write-Log "There were no replication issues found" -Level Info
ExitWithCode -exitcode 0
}
}
}
Get-ADHealthCheck
There doesn't appear to be any problems with the script. When I run it locally on a server to test, everything works. It creates the correct log file with the right name in the right directory. I check the log messages and it all checks out.
The problem is when I try and port the script as a plugin to Dataloop/Outlyer and set it to run on specific servers, the script itself outputs the correct status to Dataloop but if I then remote into a server running the script and check my log file, it is logging all error messages even though the commands ran successfully.
Has anyone seen issues like this where a script runs and reports correctly locally but when triggered by an agent, it logs all the wrong info? I've reached out to Dataloop's support as well but figured I'd check here as well.