Add AD scripts and stage import instructions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
68
STAGE-IMPORT-INSTRUCTIONS.md
Normal file
68
STAGE-IMPORT-INSTRUCTIONS.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Stage TXT Import Task
|
||||
# Date: 2026-03-28
|
||||
# Context: CTONWTXT.BAT now uploads C:\STAGE\*.TXT from DOS machines to T:\STAGE\%MACHINE%\
|
||||
|
||||
## What happened
|
||||
|
||||
1. CTONWTXT.BAT was never being called -- fixed, now called from CTONW.BAT on every boot
|
||||
2. Destination changed from broken X: (Novell serve.sys check) to T:\STAGE\%MACHINE%\
|
||||
3. DOS 6.22 can't MD on existing dirs without error, so dirs are pre-created on NAS
|
||||
4. All TS-* machine folders pre-created under /data/test/STAGE/ on D2TESTNAS
|
||||
|
||||
## What needs to run
|
||||
|
||||
Save the script below as C:\Shares\testdatadb\import-all-stage.js and run it:
|
||||
|
||||
cd C:\Shares\testdatadb
|
||||
node import-all-stage.js
|
||||
|
||||
## What it does
|
||||
|
||||
- Scans \\D2TESTNAS\test\STAGE\TS-*\*.TXT (~8,100 files across 10 machines)
|
||||
- Parses each TXT datasheet (Date, Model, SN)
|
||||
- Decodes hex-prefix serial numbers for 8.3 filename encoding:
|
||||
- Letter prefix = hex digit: A=10, B=11, C=12, ..., H=17, etc.
|
||||
- Example: H8236-12.TXT has SN: 178236-12 inside the file
|
||||
- Example: A819-1.TXT has SN: A819-1 inside -> decoded to 10819-1
|
||||
- The SN line inside H-prefix files already has the full numeric serial
|
||||
- The SN line inside A-prefix files still has the encoded serial
|
||||
- Cross-references against testdata.db by (serial_number, model_number)
|
||||
- Inserts MISSING records as log_type='SHT' with test_station from folder name
|
||||
- Copies ALL files to X:\For_Web\{decoded_serial}.TXT (the web share)
|
||||
|
||||
## Machines with data
|
||||
|
||||
TS-4L: 3,082 files (largest)
|
||||
TS-4R: 2,741 files
|
||||
TS-1R: 509 files
|
||||
TS-8R: 478 files
|
||||
TS-3R: 435 files
|
||||
TS-11R: 325 files
|
||||
TS-8L: 285 files
|
||||
TS-11L: 248 files
|
||||
TS-27: 10 files (already imported this session)
|
||||
TS-1L: 1 file
|
||||
|
||||
## Serial number encoding (8.3 filename scheme)
|
||||
|
||||
The QuickBASIC ATE software encodes long serial numbers to fit DOS 8.3 filenames.
|
||||
The first two digits get replaced with a hex letter if the serial is too long:
|
||||
|
||||
178236-12 -> H8236-12.TXT (17 -> H, which is char code 72, 72-55=17)
|
||||
10819-1 -> A819-1.TXT (10 -> A, which is char code 65, 65-55=10)
|
||||
|
||||
Decode: letter.charCodeAt(0) - 55 = numeric prefix
|
||||
Only applies if filename starts with [A-Z] followed by digits.
|
||||
|
||||
## TS-27 already done
|
||||
|
||||
10 files from TS-27 were already imported earlier this session into the DB as SHT records.
|
||||
The import script uses INSERT OR REPLACE so re-running is safe.
|
||||
|
||||
## Previous CTONWTXT.BAT issues (resolved)
|
||||
|
||||
- v1.0: Never called, checked for Novell serve.sys, used X: drive parameter
|
||||
- v2.0: Called from CTONW, but used mixed-case "Stage" path -> failed on DOS
|
||||
- v2.1: All uppercase STAGE, but had MD commands that fail on existing dirs
|
||||
- v2.2: Same issue
|
||||
- v2.3: Removed MD entirely, dirs pre-created on NAS. CURRENT VERSION.
|
||||
88
scripts/Configure-TranscriptLogging.ps1
Normal file
88
scripts/Configure-TranscriptLogging.ps1
Normal file
@@ -0,0 +1,88 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Configures PowerShell transcript logging for remote sessions.
|
||||
|
||||
.DESCRIPTION
|
||||
Enables comprehensive transcript logging via registry settings,
|
||||
creates the logging directory with proper permissions, and sets up
|
||||
automatic log rotation.
|
||||
|
||||
.NOTES
|
||||
Author: ClaudeTools Automation
|
||||
Version: 1.0
|
||||
Run as Administrator
|
||||
#>
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$transcriptPath = "C:\ClaudeTools\Logs\Transcripts"
|
||||
|
||||
Write-Host "Configuring PowerShell Transcript Logging..." -ForegroundColor Cyan
|
||||
|
||||
# Create transcript directory
|
||||
if (-not (Test-Path $transcriptPath)) {
|
||||
New-Item -ItemType Directory -Path $transcriptPath -Force | Out-Null
|
||||
Write-Host "Created transcript directory: $transcriptPath" -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Set permissions on transcript directory
|
||||
# Administrators: Full Control, SYSTEM: Full Control, Remote Management Users: Read/Write
|
||||
$acl = Get-Acl $transcriptPath
|
||||
$acl.SetAccessRuleProtection($true, $false) # Disable inheritance
|
||||
|
||||
# Add Administrators - Full Control
|
||||
$adminRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
|
||||
"Administrators", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
|
||||
)
|
||||
$acl.AddAccessRule($adminRule)
|
||||
|
||||
# Add SYSTEM - Full Control
|
||||
$systemRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
|
||||
"SYSTEM", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
|
||||
)
|
||||
$acl.AddAccessRule($systemRule)
|
||||
|
||||
# Add Remote Management Users - Modify (so they can write transcripts)
|
||||
$rmRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
|
||||
"Remote Management Users", "Modify", "ContainerInherit,ObjectInherit", "None", "Allow"
|
||||
)
|
||||
$acl.AddAccessRule($rmRule)
|
||||
|
||||
Set-Acl $transcriptPath $acl
|
||||
Write-Host "Set permissions on transcript directory" -ForegroundColor Green
|
||||
|
||||
# Configure PowerShell transcript logging via registry
|
||||
$psPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription"
|
||||
|
||||
if (-not (Test-Path $psPath)) {
|
||||
New-Item -Path $psPath -Force | Out-Null
|
||||
}
|
||||
|
||||
# Enable transcription
|
||||
Set-ItemProperty -Path $psPath -Name "EnableTranscripting" -Value 1 -Type DWord
|
||||
Set-ItemProperty -Path $psPath -Name "EnableInvocationHeader" -Value 1 -Type DWord
|
||||
Set-ItemProperty -Path $psPath -Name "OutputDirectory" -Value $transcriptPath -Type String
|
||||
|
||||
Write-Host "Enabled PowerShell transcription via registry" -ForegroundColor Green
|
||||
|
||||
# Also enable module logging for additional audit trail
|
||||
$modulePath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging"
|
||||
if (-not (Test-Path $modulePath)) {
|
||||
New-Item -Path $modulePath -Force | Out-Null
|
||||
}
|
||||
Set-ItemProperty -Path $modulePath -Name "EnableModuleLogging" -Value 1 -Type DWord
|
||||
|
||||
# Enable script block logging
|
||||
$scriptPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
|
||||
if (-not (Test-Path $scriptPath)) {
|
||||
New-Item -Path $scriptPath -Force | Out-Null
|
||||
}
|
||||
Set-ItemProperty -Path $scriptPath -Name "EnableScriptBlockLogging" -Value 1 -Type DWord
|
||||
|
||||
Write-Host "Enabled module and script block logging" -ForegroundColor Green
|
||||
|
||||
Write-Host "`nTranscript logging configuration complete!" -ForegroundColor Green
|
||||
Write-Host "Transcripts will be saved to: $transcriptPath"
|
||||
|
||||
# Display current settings
|
||||
Write-Host "`n--- Current Settings ---" -ForegroundColor Yellow
|
||||
Get-ItemProperty -Path $psPath | Select-Object EnableTranscripting, EnableInvocationHeader, OutputDirectory
|
||||
87
scripts/Get-ADComputerReport.ps1
Normal file
87
scripts/Get-ADComputerReport.ps1
Normal file
@@ -0,0 +1,87 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Generates a report of all Active Directory computers.
|
||||
|
||||
.DESCRIPTION
|
||||
This script queries Active Directory for all computer accounts and exports
|
||||
key properties including name, operating system, last logon, and OU location.
|
||||
|
||||
.PARAMETER OutputPath
|
||||
Optional. Path to export CSV report. If not specified, outputs to console.
|
||||
|
||||
.PARAMETER OperatingSystem
|
||||
Optional. Filter by operating system (e.g., "Windows Server*", "*Windows 10*").
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-ADComputerReport.ps1
|
||||
Lists all computers to console.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-ADComputerReport.ps1 -OperatingSystem "Windows Server*" -OutputPath "C:\ClaudeTools\Logs\servers.csv"
|
||||
Exports all Windows Server computers to CSV.
|
||||
|
||||
.NOTES
|
||||
Author: ClaudeTools Automation
|
||||
Version: 1.0
|
||||
Requires: ActiveDirectory PowerShell module
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$OutputPath,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$OperatingSystem = "*"
|
||||
)
|
||||
|
||||
# Import AD module
|
||||
Import-Module ActiveDirectory -ErrorAction Stop
|
||||
|
||||
Write-Host "Querying Active Directory computers..." -ForegroundColor Cyan
|
||||
|
||||
# Get computers with properties
|
||||
$computers = Get-ADComputer -Filter "OperatingSystem -like '$OperatingSystem'" -Properties `
|
||||
OperatingSystem,
|
||||
OperatingSystemVersion,
|
||||
LastLogonDate,
|
||||
Created,
|
||||
Enabled,
|
||||
IPv4Address,
|
||||
Description,
|
||||
DistinguishedName |
|
||||
Select-Object `
|
||||
@{N='Name';E={$_.Name}},
|
||||
@{N='OperatingSystem';E={$_.OperatingSystem}},
|
||||
@{N='OSVersion';E={$_.OperatingSystemVersion}},
|
||||
@{N='Enabled';E={$_.Enabled}},
|
||||
@{N='IPv4Address';E={$_.IPv4Address}},
|
||||
@{N='LastLogon';E={$_.LastLogonDate}},
|
||||
@{N='Created';E={$_.Created}},
|
||||
@{N='OU';E={($_.DistinguishedName -split ',',2)[1]}},
|
||||
@{N='Description';E={$_.Description}}
|
||||
|
||||
$computerCount = ($computers | Measure-Object).Count
|
||||
Write-Host "Found $computerCount computers." -ForegroundColor Green
|
||||
|
||||
if ($OutputPath) {
|
||||
$computers | Export-Csv -Path $OutputPath -NoTypeInformation
|
||||
Write-Host "Report exported to: $OutputPath" -ForegroundColor Green
|
||||
} else {
|
||||
$computers | Format-Table -AutoSize
|
||||
}
|
||||
|
||||
# Summary by OS
|
||||
Write-Host "`n--- Operating System Summary ---" -ForegroundColor Yellow
|
||||
$computers | Group-Object OperatingSystem | Sort-Object Count -Descending |
|
||||
Format-Table @{N='Operating System';E={$_.Name}}, Count -AutoSize
|
||||
|
||||
# Summary by status
|
||||
$enabledCount = ($computers | Where-Object { $_.Enabled -eq $true } | Measure-Object).Count
|
||||
$disabledCount = ($computers | Where-Object { $_.Enabled -eq $false } | Measure-Object).Count
|
||||
Write-Host "Enabled: $enabledCount | Disabled: $disabledCount"
|
||||
|
||||
# Stale computers (no logon in 90 days)
|
||||
$staleDate = (Get-Date).AddDays(-90)
|
||||
$staleCount = ($computers | Where-Object { $_.LastLogon -lt $staleDate -or $null -eq $_.LastLogon } | Measure-Object).Count
|
||||
Write-Host "Stale (no logon 90+ days): $staleCount" -ForegroundColor $(if ($staleCount -gt 0) { 'Yellow' } else { 'Green' })
|
||||
92
scripts/Get-ADUserReport.ps1
Normal file
92
scripts/Get-ADUserReport.ps1
Normal file
@@ -0,0 +1,92 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Generates a report of all Active Directory users with key properties.
|
||||
|
||||
.DESCRIPTION
|
||||
This script queries Active Directory for all user accounts and exports
|
||||
key properties including name, email, last logon, account status, and group memberships.
|
||||
|
||||
.PARAMETER OutputPath
|
||||
Optional. Path to export CSV report. If not specified, outputs to console.
|
||||
|
||||
.PARAMETER IncludeDisabled
|
||||
Switch to include disabled accounts in the report.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-ADUserReport.ps1
|
||||
Lists all enabled users to console.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-ADUserReport.ps1 -OutputPath "C:\ClaudeTools\Logs\users.csv" -IncludeDisabled
|
||||
Exports all users (including disabled) to CSV file.
|
||||
|
||||
.NOTES
|
||||
Author: ClaudeTools Automation
|
||||
Version: 1.0
|
||||
Requires: ActiveDirectory PowerShell module
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$OutputPath,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$IncludeDisabled
|
||||
)
|
||||
|
||||
# Import AD module
|
||||
Import-Module ActiveDirectory -ErrorAction Stop
|
||||
|
||||
Write-Host "Querying Active Directory users..." -ForegroundColor Cyan
|
||||
|
||||
# Build filter
|
||||
$filter = if ($IncludeDisabled) { "*" } else { "Enabled -eq 'True'" }
|
||||
|
||||
# Get users with properties
|
||||
$users = Get-ADUser -Filter $filter -Properties `
|
||||
DisplayName,
|
||||
EmailAddress,
|
||||
Department,
|
||||
Title,
|
||||
Manager,
|
||||
LastLogonDate,
|
||||
PasswordLastSet,
|
||||
PasswordNeverExpires,
|
||||
Enabled,
|
||||
Created,
|
||||
MemberOf,
|
||||
Description |
|
||||
Select-Object `
|
||||
@{N='SamAccountName';E={$_.SamAccountName}},
|
||||
@{N='DisplayName';E={$_.DisplayName}},
|
||||
@{N='Email';E={$_.EmailAddress}},
|
||||
@{N='Department';E={$_.Department}},
|
||||
@{N='Title';E={$_.Title}},
|
||||
@{N='Enabled';E={$_.Enabled}},
|
||||
@{N='LastLogon';E={$_.LastLogonDate}},
|
||||
@{N='PasswordLastSet';E={$_.PasswordLastSet}},
|
||||
@{N='PasswordNeverExpires';E={$_.PasswordNeverExpires}},
|
||||
@{N='Created';E={$_.Created}},
|
||||
@{N='GroupCount';E={($_.MemberOf | Measure-Object).Count}},
|
||||
@{N='Description';E={$_.Description}}
|
||||
|
||||
$userCount = ($users | Measure-Object).Count
|
||||
Write-Host "Found $userCount users." -ForegroundColor Green
|
||||
|
||||
if ($OutputPath) {
|
||||
$users | Export-Csv -Path $OutputPath -NoTypeInformation
|
||||
Write-Host "Report exported to: $OutputPath" -ForegroundColor Green
|
||||
} else {
|
||||
$users | Format-Table -AutoSize
|
||||
}
|
||||
|
||||
# Summary statistics
|
||||
Write-Host "`n--- Summary ---" -ForegroundColor Yellow
|
||||
Write-Host "Total Users: $userCount"
|
||||
$enabledCount = ($users | Where-Object { $_.Enabled -eq $true } | Measure-Object).Count
|
||||
$disabledCount = ($users | Where-Object { $_.Enabled -eq $false } | Measure-Object).Count
|
||||
Write-Host "Enabled: $enabledCount"
|
||||
Write-Host "Disabled: $disabledCount"
|
||||
$neverExpire = ($users | Where-Object { $_.PasswordNeverExpires -eq $true } | Measure-Object).Count
|
||||
Write-Host "Password Never Expires: $neverExpire"
|
||||
111
scripts/Get-GPOStatus.ps1
Normal file
111
scripts/Get-GPOStatus.ps1
Normal file
@@ -0,0 +1,111 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Reports on Group Policy Object status and replication.
|
||||
|
||||
.DESCRIPTION
|
||||
This script checks all GPOs in the domain and reports their status,
|
||||
including version information, links, and replication status between
|
||||
AD and SYSVOL.
|
||||
|
||||
.PARAMETER OutputPath
|
||||
Optional. Path to export CSV report. If not specified, outputs to console.
|
||||
|
||||
.PARAMETER CheckReplication
|
||||
Switch to perform detailed replication check between AD and SYSVOL.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-GPOStatus.ps1
|
||||
Lists all GPOs with basic status.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-GPOStatus.ps1 -CheckReplication -OutputPath "C:\ClaudeTools\Logs\gpo-status.csv"
|
||||
Full replication check with CSV export.
|
||||
|
||||
.NOTES
|
||||
Author: ClaudeTools Automation
|
||||
Version: 1.0
|
||||
Requires: GroupPolicy PowerShell module
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$OutputPath,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$CheckReplication
|
||||
)
|
||||
|
||||
# Import required modules
|
||||
Import-Module GroupPolicy -ErrorAction Stop
|
||||
Import-Module ActiveDirectory -ErrorAction Stop
|
||||
|
||||
Write-Host "Querying Group Policy Objects..." -ForegroundColor Cyan
|
||||
|
||||
# Get all GPOs
|
||||
$gpos = Get-GPO -All | Select-Object `
|
||||
@{N='Name';E={$_.DisplayName}},
|
||||
@{N='ID';E={$_.Id}},
|
||||
@{N='Status';E={$_.GpoStatus}},
|
||||
@{N='CreationTime';E={$_.CreationTime}},
|
||||
@{N='ModificationTime';E={$_.ModificationTime}},
|
||||
@{N='UserVersion';E={$_.User.DSVersion}},
|
||||
@{N='ComputerVersion';E={$_.Computer.DSVersion}},
|
||||
@{N='WMIFilter';E={$_.WmiFilter.Name}}
|
||||
|
||||
$gpoCount = ($gpos | Measure-Object).Count
|
||||
Write-Host "Found $gpoCount GPOs." -ForegroundColor Green
|
||||
|
||||
# Check GPO links
|
||||
Write-Host "`nChecking GPO links..." -ForegroundColor Cyan
|
||||
$gpoLinks = @()
|
||||
foreach ($gpo in (Get-GPO -All)) {
|
||||
$report = [xml](Get-GPOReport -Guid $gpo.Id -ReportType Xml)
|
||||
$links = $report.GPO.LinksTo.SOMPath
|
||||
|
||||
$gpoLinks += [PSCustomObject]@{
|
||||
Name = $gpo.DisplayName
|
||||
LinkCount = if ($links) { ($links | Measure-Object).Count } else { 0 }
|
||||
Links = if ($links) { $links -join "; " } else { "Not Linked" }
|
||||
}
|
||||
}
|
||||
|
||||
if ($CheckReplication) {
|
||||
Write-Host "`nChecking SYSVOL replication status..." -ForegroundColor Cyan
|
||||
|
||||
$domain = (Get-ADDomain).DNSRoot
|
||||
$dcs = Get-ADDomainController -Filter *
|
||||
|
||||
foreach ($dc in $dcs) {
|
||||
Write-Host " Checking $($dc.HostName)..." -ForegroundColor Gray
|
||||
$sysvolPath = "\\$($dc.HostName)\SYSVOL\$domain\Policies"
|
||||
|
||||
if (Test-Path $sysvolPath) {
|
||||
$sysvolGPOs = Get-ChildItem $sysvolPath -Directory | Where-Object { $_.Name -match '^{' }
|
||||
Write-Host " SYSVOL GPO count: $($sysvolGPOs.Count)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " Unable to access SYSVOL" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Output results
|
||||
if ($OutputPath) {
|
||||
$gpos | Export-Csv -Path $OutputPath -NoTypeInformation
|
||||
Write-Host "`nReport exported to: $OutputPath" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "`n--- GPO List ---" -ForegroundColor Yellow
|
||||
$gpos | Format-Table Name, Status, ModificationTime, UserVersion, ComputerVersion -AutoSize
|
||||
|
||||
Write-Host "`n--- GPO Links ---" -ForegroundColor Yellow
|
||||
$gpoLinks | Format-Table Name, LinkCount, Links -AutoSize
|
||||
}
|
||||
|
||||
# Summary
|
||||
Write-Host "`n--- Summary ---" -ForegroundColor Yellow
|
||||
Write-Host "Total GPOs: $gpoCount"
|
||||
$unlinked = ($gpoLinks | Where-Object { $_.LinkCount -eq 0 } | Measure-Object).Count
|
||||
Write-Host "Unlinked GPOs: $unlinked" -ForegroundColor $(if ($unlinked -gt 0) { 'Yellow' } else { 'Green' })
|
||||
|
||||
$disabled = ($gpos | Where-Object { $_.Status -ne 'AllSettingsEnabled' } | Measure-Object).Count
|
||||
Write-Host "Disabled/Partial GPOs: $disabled" -ForegroundColor $(if ($disabled -gt 0) { 'Yellow' } else { 'Green' })
|
||||
173
scripts/Get-ReplicationHealth.ps1
Normal file
173
scripts/Get-ReplicationHealth.ps1
Normal file
@@ -0,0 +1,173 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks Active Directory replication health across domain controllers.
|
||||
|
||||
.DESCRIPTION
|
||||
This script performs comprehensive AD replication health checks including
|
||||
replication status, partner connectivity, and identifies any replication failures.
|
||||
|
||||
.PARAMETER OutputPath
|
||||
Optional. Path to export results. If not specified, outputs to console.
|
||||
|
||||
.PARAMETER Detailed
|
||||
Switch to show detailed replication information per DC.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-ReplicationHealth.ps1
|
||||
Basic replication health check.
|
||||
|
||||
.EXAMPLE
|
||||
.\Get-ReplicationHealth.ps1 -Detailed -OutputPath "C:\ClaudeTools\Logs\repl-health.txt"
|
||||
Detailed check with output to file.
|
||||
|
||||
.NOTES
|
||||
Author: ClaudeTools Automation
|
||||
Version: 1.0
|
||||
Requires: ActiveDirectory PowerShell module, repadmin.exe
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$OutputPath,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[switch]$Detailed
|
||||
)
|
||||
|
||||
# Import AD module
|
||||
Import-Module ActiveDirectory -ErrorAction Stop
|
||||
|
||||
$output = @()
|
||||
$output += "=" * 60
|
||||
$output += "AD REPLICATION HEALTH REPORT"
|
||||
$output += "Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
|
||||
$output += "=" * 60
|
||||
|
||||
Write-Host "Checking AD Replication Health..." -ForegroundColor Cyan
|
||||
|
||||
# Get all DCs
|
||||
$dcs = Get-ADDomainController -Filter *
|
||||
$output += "`nDomain Controllers Found: $($dcs.Count)"
|
||||
|
||||
foreach ($dc in $dcs) {
|
||||
$output += "`n--- $($dc.HostName) ---"
|
||||
Write-Host "Checking $($dc.HostName)..." -ForegroundColor Gray
|
||||
}
|
||||
|
||||
# Check replication summary using repadmin
|
||||
$output += "`n" + "=" * 60
|
||||
$output += "REPLICATION SUMMARY (repadmin /replsummary)"
|
||||
$output += "=" * 60
|
||||
|
||||
try {
|
||||
$replSummary = repadmin /replsummary 2>&1
|
||||
$output += $replSummary
|
||||
Write-Host "Replication summary retrieved." -ForegroundColor Green
|
||||
} catch {
|
||||
$output += "ERROR: Unable to run repadmin /replsummary"
|
||||
Write-Host "Error running repadmin" -ForegroundColor Red
|
||||
}
|
||||
|
||||
# Check for replication failures
|
||||
$output += "`n" + "=" * 60
|
||||
$output += "REPLICATION FAILURES (repadmin /showrepl * /errorsonly)"
|
||||
$output += "=" * 60
|
||||
|
||||
try {
|
||||
$replErrors = repadmin /showrepl * /errorsonly 2>&1
|
||||
if ($replErrors -match "error" -or $replErrors -match "fail") {
|
||||
$output += $replErrors
|
||||
Write-Host "Replication ERRORS detected!" -ForegroundColor Red
|
||||
} else {
|
||||
$output += "No replication errors detected."
|
||||
Write-Host "No replication errors." -ForegroundColor Green
|
||||
}
|
||||
} catch {
|
||||
$output += "ERROR: Unable to check replication errors"
|
||||
}
|
||||
|
||||
# Queue length
|
||||
$output += "`n" + "=" * 60
|
||||
$output += "REPLICATION QUEUE (repadmin /queue)"
|
||||
$output += "=" * 60
|
||||
|
||||
try {
|
||||
$replQueue = repadmin /queue 2>&1
|
||||
$output += $replQueue
|
||||
} catch {
|
||||
$output += "ERROR: Unable to check replication queue"
|
||||
}
|
||||
|
||||
if ($Detailed) {
|
||||
$output += "`n" + "=" * 60
|
||||
$output += "DETAILED REPLICATION STATUS (repadmin /showrepl)"
|
||||
$output += "=" * 60
|
||||
|
||||
try {
|
||||
$replDetail = repadmin /showrepl 2>&1
|
||||
$output += $replDetail
|
||||
} catch {
|
||||
$output += "ERROR: Unable to get detailed replication status"
|
||||
}
|
||||
|
||||
# DFSR Health (if applicable)
|
||||
$output += "`n" + "=" * 60
|
||||
$output += "DFSR SYSVOL REPLICATION STATUS"
|
||||
$output += "=" * 60
|
||||
|
||||
try {
|
||||
$dfsrStatus = Get-DfsrMember -ErrorAction SilentlyContinue
|
||||
if ($dfsrStatus) {
|
||||
$output += "DFSR Members:"
|
||||
foreach ($member in $dfsrStatus) {
|
||||
$output += " - $($member.ComputerName): $($member.DomainName)"
|
||||
}
|
||||
} else {
|
||||
$output += "DFSR not configured or FRS in use."
|
||||
}
|
||||
} catch {
|
||||
$output += "Unable to query DFSR status (may be using FRS)"
|
||||
}
|
||||
}
|
||||
|
||||
# AD Database health
|
||||
$output += "`n" + "=" * 60
|
||||
$output += "AD DATABASE INTEGRITY"
|
||||
$output += "=" * 60
|
||||
|
||||
$adDb = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" -ErrorAction SilentlyContinue
|
||||
if ($adDb) {
|
||||
$dbPath = $adDb.'DSA Database file'
|
||||
$logPath = $adDb.'Database log files path'
|
||||
$output += "Database Path: $dbPath"
|
||||
$output += "Log Path: $logPath"
|
||||
|
||||
if (Test-Path $dbPath) {
|
||||
$dbSize = (Get-Item $dbPath).Length / 1MB
|
||||
$output += "Database Size: $([math]::Round($dbSize, 2)) MB"
|
||||
}
|
||||
}
|
||||
|
||||
# Final summary
|
||||
$output += "`n" + "=" * 60
|
||||
$output += "HEALTH CHECK COMPLETE"
|
||||
$output += "=" * 60
|
||||
|
||||
# Output results
|
||||
if ($OutputPath) {
|
||||
$output | Out-File -FilePath $OutputPath -Encoding UTF8
|
||||
Write-Host "`nReport saved to: $OutputPath" -ForegroundColor Green
|
||||
} else {
|
||||
$output | ForEach-Object { Write-Host $_ }
|
||||
}
|
||||
|
||||
# Quick status summary
|
||||
Write-Host "`n--- Quick Status ---" -ForegroundColor Yellow
|
||||
Write-Host "Domain Controllers: $($dcs.Count)"
|
||||
$errorMatch = $replErrors -match "error|fail"
|
||||
if ($errorMatch) {
|
||||
Write-Host "Replication Status: ERRORS DETECTED" -ForegroundColor Red
|
||||
} else {
|
||||
Write-Host "Replication Status: HEALTHY" -ForegroundColor Green
|
||||
}
|
||||
107
scripts/Invoke-LogRotation.ps1
Normal file
107
scripts/Invoke-LogRotation.ps1
Normal file
@@ -0,0 +1,107 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Rotates and cleans up old log files.
|
||||
|
||||
.DESCRIPTION
|
||||
Removes transcript and log files older than the specified retention period.
|
||||
Designed to run as a scheduled task daily.
|
||||
|
||||
.PARAMETER RetentionDays
|
||||
Number of days to retain log files. Default is 30.
|
||||
|
||||
.PARAMETER LogPath
|
||||
Path to the logs directory. Default is C:\ClaudeTools\Logs.
|
||||
|
||||
.PARAMETER WhatIf
|
||||
Shows what would be deleted without actually deleting.
|
||||
|
||||
.EXAMPLE
|
||||
.\Invoke-LogRotation.ps1
|
||||
Removes logs older than 30 days.
|
||||
|
||||
.EXAMPLE
|
||||
.\Invoke-LogRotation.ps1 -RetentionDays 14 -WhatIf
|
||||
Shows what would be deleted with 14-day retention.
|
||||
|
||||
.NOTES
|
||||
Author: ClaudeTools Automation
|
||||
Version: 1.0
|
||||
#>
|
||||
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[int]$RetentionDays = 30,
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$LogPath = "C:\ClaudeTools\Logs"
|
||||
)
|
||||
|
||||
$rotationLog = Join-Path $LogPath "rotation.log"
|
||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
|
||||
function Write-Log {
|
||||
param([string]$Message)
|
||||
$logEntry = "[$timestamp] $Message"
|
||||
Add-Content -Path $rotationLog -Value $logEntry
|
||||
Write-Host $logEntry
|
||||
}
|
||||
|
||||
Write-Log "=== Log Rotation Started ==="
|
||||
Write-Log "Retention Period: $RetentionDays days"
|
||||
Write-Log "Log Path: $LogPath"
|
||||
|
||||
$cutoffDate = (Get-Date).AddDays(-$RetentionDays)
|
||||
$totalDeleted = 0
|
||||
$totalSizeFreed = 0
|
||||
|
||||
# Find and delete old files
|
||||
$oldFiles = Get-ChildItem -Path $LogPath -Recurse -File |
|
||||
Where-Object { $_.LastWriteTime -lt $cutoffDate -and $_.Name -ne "rotation.log" }
|
||||
|
||||
$fileCount = ($oldFiles | Measure-Object).Count
|
||||
Write-Log "Found $fileCount files older than $RetentionDays days"
|
||||
|
||||
foreach ($file in $oldFiles) {
|
||||
$fileSize = $file.Length
|
||||
$filePath = $file.FullName
|
||||
|
||||
if ($PSCmdlet.ShouldProcess($filePath, "Delete")) {
|
||||
try {
|
||||
Remove-Item $filePath -Force
|
||||
$totalDeleted++
|
||||
$totalSizeFreed += $fileSize
|
||||
Write-Log "Deleted: $filePath ($([math]::Round($fileSize/1KB, 2)) KB)"
|
||||
} catch {
|
||||
Write-Log "ERROR deleting $filePath : $_"
|
||||
}
|
||||
} else {
|
||||
Write-Log "WhatIf: Would delete $filePath ($([math]::Round($fileSize/1KB, 2)) KB)"
|
||||
}
|
||||
}
|
||||
|
||||
# Delete empty subdirectories
|
||||
$emptyDirs = Get-ChildItem -Path $LogPath -Directory -Recurse |
|
||||
Where-Object { (Get-ChildItem $_.FullName -Force).Count -eq 0 }
|
||||
|
||||
foreach ($dir in $emptyDirs) {
|
||||
if ($PSCmdlet.ShouldProcess($dir.FullName, "Remove empty directory")) {
|
||||
try {
|
||||
Remove-Item $dir.FullName -Force
|
||||
Write-Log "Removed empty directory: $($dir.FullName)"
|
||||
} catch {
|
||||
Write-Log "ERROR removing directory $($dir.FullName) : $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Summary
|
||||
$sizeMB = [math]::Round($totalSizeFreed / 1MB, 2)
|
||||
Write-Log "=== Rotation Complete ==="
|
||||
Write-Log "Files Deleted: $totalDeleted"
|
||||
Write-Log "Space Freed: $sizeMB MB"
|
||||
|
||||
# Show current disk usage
|
||||
$currentSize = (Get-ChildItem -Path $LogPath -Recurse -File | Measure-Object -Property Length -Sum).Sum
|
||||
$currentSizeMB = [math]::Round($currentSize / 1MB, 2)
|
||||
Write-Log "Current Log Directory Size: $currentSizeMB MB"
|
||||
Reference in New Issue
Block a user