fix: audit hardening 2.1.10-SAC — gitignore, SAC TLS warn, Exchange safety
- Extend .gitignore for local settings, logs, spool, backups - Log CRITICAL when SacTlsSkipVerify is enabled (Login_Monitor + Sac-Client) - Exchange-MailSecurity: -WhatIf dry-run, scan safety warnings, v1.6.8 - Remove legacy Watchdog_RDP_Monitor.ps1 and Install-ScheduledTasks.ps1 - Add scripts for GitHub sanitize mirror push workflow
This commit is contained in:
+6
-1
@@ -1,3 +1,8 @@
|
|||||||
.cursor/
|
.cursor/
|
||||||
tools/*.log
|
tools/*.log
|
||||||
*.log
|
*.log
|
||||||
|
*.bak
|
||||||
|
Logs/
|
||||||
|
sac-spool/
|
||||||
|
login_monitor.settings.ps1
|
||||||
|
exchange_monitor.settings.ps1
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Exchange Mail Security — руководство
|
# Exchange Mail Security — руководство
|
||||||
|
|
||||||
Скрипт **`Exchange-MailSecurity.ps1`** предназначен **только для сервера Microsoft Exchange** с Exchange Management Shell (EMS). Не устанавливается на все компьютеры домена через GPO RDP-монитора.
|
Скрипт **`Exchange-MailSecurity.ps1`** предназначен **только для сервера Microsoft Exchange** с Exchange Management Shell (EMS). Не устанавливается на все компьютеры домена через GPO RDP-монитора.
|
||||||
|
|
||||||
@@ -68,6 +68,16 @@
|
|||||||
- Каналы: **Telegram** и/или **Email** (модуль **`Notify-Common.ps1`**).
|
- Каналы: **Telegram** и/или **Email** (модуль **`Notify-Common.ps1`**).
|
||||||
- Пересылка: **`$AlertOnlyOnNewForwardingFindings = $true`** — алерт при **новой** находке (`Logs\exchange_forwarding_baseline.json`).
|
- Пересылка: **`$AlertOnlyOnNewForwardingFindings = $true`** — алерт при **новой** находке (`Logs\exchange_forwarding_baseline.json`).
|
||||||
- **Первый скан:** **`$SuppressAlertsOnFirstBaselineRun = $true`** (по умолчанию) — существующие пересылки **только в baseline**, без всплеска алертов; одна **сводка** (`$SendInboxScanSummary`).
|
- **Первый скан:** **`$SuppressAlertsOnFirstBaselineRun = $true`** (по умолчанию) — существующие пересылки **только в baseline**, без всплеска алертов; одна **сводка** (`$SendInboxScanSummary`).
|
||||||
|
|
||||||
|
### Dry-run перед первым Inbox-сканом
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "\\dc.contoso.local\NETLOGON\RDP-login-monitor\Exchange-MailSecurity.ps1" -Mode Inbox -WhatIf
|
||||||
|
```
|
||||||
|
|
||||||
|
`-WhatIf` подключает EMS, считает объём (`Get-Mailbox` / VIP-фильтр), **не вызывает** `Get-InboxRule`, не шлёт уведомления и не пишет baseline. Рекомендуется перед `-InstallTasks` и первым ночным `-Mode Inbox`.
|
||||||
|
|
||||||
|
При полном скане без VIP скрипт пишет **WARN** в лог; проблемные ящики — в **`$SkipInboxScanMailboxes`**.
|
||||||
- Далее — алерт только при **новых** или **изменённых** пересылках (в т.ч. включили ранее отключённое правило).
|
- Далее — алерт только при **новых** или **изменённых** пересылках (в т.ч. включили ранее отключённое правило).
|
||||||
- **`$NotifyWhenForwardingScanClean = $false`** — не слать «всё чисто» при нуле находок.
|
- **`$NotifyWhenForwardingScanClean = $false`** — не слать «всё чисто» при нуле находок.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Мониторинг Exchange: очереди транспорта, пересылка на внешние адреса (Inbox rules + mailbox forwarding + transport rules).
|
Мониторинг Exchange: очереди транспорта, пересылка на внешние адреса (Inbox rules + mailbox forwarding + transport rules).
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
@@ -10,12 +10,13 @@
|
|||||||
Опционально: exchange_monitor.settings.ps1 в том же каталоге (секреты, whitelist).
|
Опционально: exchange_monitor.settings.ps1 в том же каталоге (секреты, whitelist).
|
||||||
#>
|
#>
|
||||||
|
|
||||||
[CmdletBinding()]
|
[CmdletBinding(SupportsShouldProcess = $true)]
|
||||||
param(
|
param(
|
||||||
[ValidateSet('Queues', 'Inbox', 'Watchdog')]
|
[ValidateSet('Queues', 'Inbox', 'Watchdog')]
|
||||||
[string]$Mode = 'Queues',
|
[string]$Mode = 'Queues',
|
||||||
[switch]$InstallTasks,
|
[switch]$InstallTasks,
|
||||||
[switch]$Watchdog
|
[switch]$Watchdog,
|
||||||
|
[switch]$WhatIf
|
||||||
)
|
)
|
||||||
|
|
||||||
Set-StrictMode -Version Latest
|
Set-StrictMode -Version Latest
|
||||||
@@ -25,7 +26,7 @@ $ErrorActionPreference = 'Stop'
|
|||||||
# КОНФИГУРАЦИЯ
|
# КОНФИГУРАЦИЯ
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|
||||||
$ScriptVersion = '1.6.7'
|
$ScriptVersion = '1.6.8'
|
||||||
$script:InstallRoot = [System.IO.Path]::GetFullPath("$env:ProgramData\RDP-login-monitor")
|
$script:InstallRoot = [System.IO.Path]::GetFullPath("$env:ProgramData\RDP-login-monitor")
|
||||||
$script:CanonicalScriptName = 'Exchange-MailSecurity.ps1'
|
$script:CanonicalScriptName = 'Exchange-MailSecurity.ps1'
|
||||||
$LogFile = Join-Path $script:InstallRoot 'Logs\exchange_mail_security.log'
|
$LogFile = Join-Path $script:InstallRoot 'Logs\exchange_mail_security.log'
|
||||||
@@ -100,6 +101,18 @@ if (Test-Path -LiteralPath $SettingsFile) {
|
|||||||
. $SettingsFile
|
. $SettingsFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Write-ExchangeScanSafetyWarnings {
|
||||||
|
if (-not $SuppressAlertsOnFirstBaselineRun) {
|
||||||
|
Write-ExchLog 'WARN: SuppressAlertsOnFirstBaselineRun=$false — первый Inbox-скан может разослать алерты по всем уже существующим пересылкам.'
|
||||||
|
}
|
||||||
|
if (-not $VipMailboxesOnly -and $MaxMailboxesPerRun -le 0 -and $ScanInboxRules) {
|
||||||
|
Write-ExchLog 'WARN: полный скан Inbox rules по всем ящикам (VipMailboxesOnly=$false). Рекомендуется пилот: VipMailboxesOnly=$true или -Mode Inbox -WhatIf.'
|
||||||
|
}
|
||||||
|
if (@($SkipInboxScanMailboxes | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }).Count -eq 0) {
|
||||||
|
Write-ExchLog 'TIP: добавьте проблемные ящики в $SkipInboxScanMailboxes, если Get-InboxRule падает (corrupt rule store).'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Write-NotifyLog {
|
function Write-NotifyLog {
|
||||||
param([string]$Message)
|
param([string]$Message)
|
||||||
Write-ExchLog $Message
|
Write-ExchLog $Message
|
||||||
@@ -235,6 +248,7 @@ if ($InstallTasks) {
|
|||||||
Send-ExchangeInstallNotification
|
Send-ExchangeInstallNotification
|
||||||
Write-ExchLog 'InstallTasks: install notification sent'
|
Write-ExchLog 'InstallTasks: install notification sent'
|
||||||
}
|
}
|
||||||
|
Write-ExchLog 'InstallTasks: перед первым ночным Inbox-сканом выполните: Exchange-MailSecurity.ps1 -Mode Inbox -WhatIf'
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,6 +532,15 @@ function Invoke-ExchangeQueueScan {
|
|||||||
Write-ExchLog "Queues: threshold MessageCount > $QueueMessageCountThreshold"
|
Write-ExchLog "Queues: threshold MessageCount > $QueueMessageCountThreshold"
|
||||||
|
|
||||||
$queues = @(Get-Queue -ErrorAction Stop)
|
$queues = @(Get-Queue -ErrorAction Stop)
|
||||||
|
if ($WhatIf) {
|
||||||
|
$hot = @($queues | Where-Object { $_.MessageCount -gt $QueueMessageCountThreshold })
|
||||||
|
Write-ExchLog "WhatIf: queues total=$($queues.Count), above threshold=$($hot.Count) — alerts skipped"
|
||||||
|
foreach ($q in $hot) {
|
||||||
|
Write-ExchLog "WhatIf: would alert queue=$($q.Identity) messages=$($q.MessageCount)"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
$hot = @($queues | Where-Object { $_.MessageCount -gt $QueueMessageCountThreshold })
|
$hot = @($queues | Where-Object { $_.MessageCount -gt $QueueMessageCountThreshold })
|
||||||
$state = Get-QueueAlertState
|
$state = Get-QueueAlertState
|
||||||
$now = Get-Date
|
$now = Get-Date
|
||||||
@@ -760,6 +783,20 @@ function Send-ExchangeInboxScanSummary {
|
|||||||
function Invoke-ExchangeInboxAndForwardingScan {
|
function Invoke-ExchangeInboxAndForwardingScan {
|
||||||
$scopeLabel = Get-ExchangeInboxScanScopeLabel
|
$scopeLabel = Get-ExchangeInboxScanScopeLabel
|
||||||
Write-ExchLog "Inbox/Forwarding scan v$ScriptVersion; scope: $scopeLabel; notify: $(Get-NotifyChainHuman)"
|
Write-ExchLog "Inbox/Forwarding scan v$ScriptVersion; scope: $scopeLabel; notify: $(Get-NotifyChainHuman)"
|
||||||
|
if ($WhatIf) {
|
||||||
|
$null = Import-ExchangeManagementShell
|
||||||
|
$internalDomains = Get-InternalAcceptedDomainNames
|
||||||
|
Write-ExchLog "WhatIf: accepted domains: $(@($internalDomains) -join ', ')"
|
||||||
|
$mailboxCount = 0
|
||||||
|
if ($ScanInboxRules) {
|
||||||
|
$mailboxes = @(Get-MailboxListForScan)
|
||||||
|
$mailboxCount = $mailboxes.Count
|
||||||
|
Write-ExchLog "WhatIf: would scan $mailboxCount mailboxes ($scopeLabel); Get-InboxRule not called"
|
||||||
|
}
|
||||||
|
Write-ExchLog "WhatIf: ScanMailboxForwarding=$ScanMailboxForwarding ScanTransportRules=$ScanTransportRules — no alerts, no baseline write"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
$null = Import-ExchangeManagementShell
|
$null = Import-ExchangeManagementShell
|
||||||
$internalDomains = Get-InternalAcceptedDomainNames
|
$internalDomains = Get-InternalAcceptedDomainNames
|
||||||
Write-ExchLog "Accepted domains (internal): $(@($internalDomains) -join ', ')"
|
Write-ExchLog "Accepted domains (internal): $(@($internalDomains) -join ', ')"
|
||||||
@@ -879,7 +916,8 @@ if (-not (Test-RunningElevated)) {
|
|||||||
Write-ExchLog 'WARNING: not running elevated - EMS/tasks may fail.'
|
Write-ExchLog 'WARNING: not running elevated - EMS/tasks may fail.'
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-ExchLog "=== Exchange-MailSecurity v$ScriptVersion Mode=$Mode ==="
|
Write-ExchLog "=== Exchange-MailSecurity v$ScriptVersion Mode=$Mode$(if ($WhatIf) { ' WhatIf' }) ==="
|
||||||
|
Write-ExchangeScanSafetyWarnings
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch ($Mode) {
|
switch ($Mode) {
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
#Requires -RunAsAdministrator
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Регистрирует в Планировщике заданий основной монитор и watchdog (как в README).
|
|
||||||
.DESCRIPTION
|
|
||||||
Запускайте из повышенной PowerShell. Пути по умолчанию — D:\Soft\.
|
|
||||||
Watchdog использует Watchdog_RDP_Monitor.ps1 из репозитория (проверка процесса и heartbeat).
|
|
||||||
#>
|
|
||||||
[CmdletBinding()]
|
|
||||||
param(
|
|
||||||
[string]$InstallRoot = "D:\Soft",
|
|
||||||
[string]$MainTaskName = "RDP Login Monitor",
|
|
||||||
[string]$WatchdogTaskName = "RDP Login Monitor Watchdog",
|
|
||||||
[int]$WatchdogRepeatMinutes = 5,
|
|
||||||
[int]$MainStartupRandomDelayMinutes = 1,
|
|
||||||
[int]$WatchdogStartupRandomDelayMinutes = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
Set-StrictMode -Version Latest
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
|
|
||||||
$LoginScriptPath = Join-Path $InstallRoot "Login_Monitor.ps1"
|
|
||||||
$WatchdogScriptPath = Join-Path $InstallRoot "Watchdog_RDP_Monitor.ps1"
|
|
||||||
$LogsDir = Join-Path $InstallRoot "Logs"
|
|
||||||
|
|
||||||
if (-not (Test-Path -LiteralPath $LoginScriptPath)) {
|
|
||||||
throw "Не найден основной скрипт: $LoginScriptPath"
|
|
||||||
}
|
|
||||||
if (-not (Test-Path -LiteralPath $WatchdogScriptPath)) {
|
|
||||||
throw "Не найден watchdog: $WatchdogScriptPath"
|
|
||||||
}
|
|
||||||
if (-not (Test-Path -LiteralPath $LogsDir)) {
|
|
||||||
New-Item -ItemType Directory -Path $LogsDir -Force | Out-Null
|
|
||||||
}
|
|
||||||
|
|
||||||
$principal = New-ScheduledTaskPrincipal `
|
|
||||||
-UserId "NT AUTHORITY\SYSTEM" `
|
|
||||||
-LogonType ServiceAccount `
|
|
||||||
-RunLevel Highest
|
|
||||||
|
|
||||||
# --- Задание 1: основной монитор ---
|
|
||||||
$mainArgs = "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$LoginScriptPath`""
|
|
||||||
$mainAction = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument $mainArgs
|
|
||||||
$mainTrigger = New-ScheduledTaskTrigger -AtStartup -RandomDelay (New-TimeSpan -Minutes $MainStartupRandomDelayMinutes)
|
|
||||||
$mainSettings = New-ScheduledTaskSettingsSet `
|
|
||||||
-AllowStartIfOnBatteries `
|
|
||||||
-DontStopIfGoingOnBatteries `
|
|
||||||
-StartWhenAvailable `
|
|
||||||
-MultipleInstances IgnoreNew `
|
|
||||||
-ExecutionTimeLimit ([TimeSpan]::Zero)
|
|
||||||
|
|
||||||
Register-ScheduledTask `
|
|
||||||
-TaskName $MainTaskName `
|
|
||||||
-Action $mainAction `
|
|
||||||
-Trigger $mainTrigger `
|
|
||||||
-Principal $principal `
|
|
||||||
-Settings $mainSettings `
|
|
||||||
-Force | Out-Null
|
|
||||||
|
|
||||||
Write-Host "Создано задание: $MainTaskName" -ForegroundColor Cyan
|
|
||||||
|
|
||||||
# --- Задание 2: watchdog (старт + периодический запуск, как в README) ---
|
|
||||||
$wdArgs = "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$WatchdogScriptPath`""
|
|
||||||
$wdAction = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument $wdArgs
|
|
||||||
$wdTriggerStartup = New-ScheduledTaskTrigger -AtStartup -RandomDelay (New-TimeSpan -Minutes $WatchdogStartupRandomDelayMinutes)
|
|
||||||
$repeatDuration = New-TimeSpan -Days 3650
|
|
||||||
$anchor = (Get-Date).AddMinutes([Math]::Max(3, $WatchdogRepeatMinutes))
|
|
||||||
$wdTriggerRepeat = New-ScheduledTaskTrigger -Once -At $anchor `
|
|
||||||
-RepetitionInterval (New-TimeSpan -Minutes $WatchdogRepeatMinutes) `
|
|
||||||
-RepetitionDuration $repeatDuration
|
|
||||||
|
|
||||||
$wdSettings = New-ScheduledTaskSettingsSet `
|
|
||||||
-AllowStartIfOnBatteries `
|
|
||||||
-DontStopIfGoingOnBatteries `
|
|
||||||
-StartWhenAvailable `
|
|
||||||
-MultipleInstances IgnoreNew
|
|
||||||
|
|
||||||
Register-ScheduledTask `
|
|
||||||
-TaskName $WatchdogTaskName `
|
|
||||||
-Action $wdAction `
|
|
||||||
-Trigger @($wdTriggerStartup, $wdTriggerRepeat) `
|
|
||||||
-Principal $principal `
|
|
||||||
-Settings $wdSettings `
|
|
||||||
-Force | Out-Null
|
|
||||||
|
|
||||||
Write-Host "Создано задание: $WatchdogTaskName (триггеры: при старте ОС и каждые $WatchdogRepeatMinutes мин.)" -ForegroundColor Cyan
|
|
||||||
Write-Host "Готово. При необходимости сразу запустите: Start-ScheduledTask -TaskName '$MainTaskName'" -ForegroundColor Green
|
|
||||||
+5
-2
@@ -1,4 +1,4 @@
|
|||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Мониторинг логинов/попыток входа с уведомлениями в Telegram
|
Мониторинг логинов/попыток входа с уведомлениями в Telegram
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
@@ -90,7 +90,7 @@ $script:SkipLogDetailLimit = 15
|
|||||||
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
|
# строки ниже, если правки «мелкие» и вы не хотите менять отображаемую версию в логах).
|
||||||
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
|
# Рекомендация: при значимых релизах меняйте и $ScriptVersion, и version.txt одинаково; при только
|
||||||
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
|
# исправлениях на шаре — достаточно поднять patch в version.txt (например 1.3.0.1).
|
||||||
$ScriptVersion = "2.1.9-SAC"
|
$ScriptVersion = "2.1.10-SAC"
|
||||||
|
|
||||||
# Логи (все под InstallRoot)
|
# Логи (все под InstallRoot)
|
||||||
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
$LogFile = Join-Path $script:InstallRoot "Logs\login_monitor.log"
|
||||||
@@ -1140,6 +1140,9 @@ if (-not (Test-Administrator)) {
|
|||||||
Write-Log "Скрипт запущен с правами администратора, версия $ScriptVersion"
|
Write-Log "Скрипт запущен с правами администратора, версия $ScriptVersion"
|
||||||
if ($script:LoginMonitorSettingsLoaded) {
|
if ($script:LoginMonitorSettingsLoaded) {
|
||||||
Write-Log "Настройки: login_monitor.settings.ps1 загружен."
|
Write-Log "Настройки: login_monitor.settings.ps1 загружен."
|
||||||
|
if ($SacTlsSkipVerify) {
|
||||||
|
Write-Log 'CRITICAL: SacTlsSkipVerify=$true — проверка TLS для SAC отключена (риск MITM). Только для краткого отладочного окна в lab.'
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Write-Log "Предупреждение: login_monitor.settings.ps1 не найден — Telegram/SMTP/4740 не настроены (скопируйте login_monitor.settings.example.ps1)."
|
Write-Log "Предупреждение: login_monitor.settings.ps1 не найден — Telegram/SMTP/4740 не настроены (скопируйте login_monitor.settings.example.ps1)."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# RDP Login Monitor
|
# RDP Login Monitor
|
||||||
|
|
||||||
**Версия:** `2.1.5-SAC` (`$ScriptVersion` + `version.txt`)
|
**Версия:** `2.1.10-SAC` (`$ScriptVersion` + `version.txt`)
|
||||||
|
|
||||||
PowerShell-мониторинг Windows: RDP/RDS, RD Gateway, WinRM, admin share, блокировки УЗ, heartbeat, отчёты.
|
PowerShell-мониторинг Windows: RDP/RDS, RD Gateway, WinRM, admin share, блокировки УЗ, heartbeat, отчёты.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -92,7 +92,7 @@ For domain deployment from a share you do not configure the scheduler on clients
|
|||||||
|
|
||||||
- **`-SkipScheduledTaskMaintenance`**: during normal monitor startup, skip verification/recreation of scheduled tasks (if you manage tasks only via **`-InstallTasks`** or manually).
|
- **`-SkipScheduledTaskMaintenance`**: during normal monitor startup, skip verification/recreation of scheduled tasks (if you manage tasks only via **`-InstallTasks`** or manually).
|
||||||
- **`Install-DeployScheduledTask.ps1`** — helper to run **`Deploy-LoginMonitor.ps1`** from a share on a schedule (see **[DEPLOY.md](DEPLOY.md)**).
|
- **`Install-DeployScheduledTask.ps1`** — helper to run **`Deploy-LoginMonitor.ps1`** from a share on a schedule (see **[DEPLOY.md](DEPLOY.md)**).
|
||||||
- **`Watchdog_RDP_Monitor.ps1`** and **`Install-ScheduledTasks.ps1`** — **alternate** layout with a separate watchdog script and default paths under **`D:\Soft`**. For new installs, prefer the built-in **`-Watchdog`** in **`Login_Monitor.ps1`** and tasks **`RDP-Login-Monitor`** / **`RDP-Login-Monitor-Watchdog`**.
|
- Watchdog is built into **`Login_Monitor.ps1`** (`-Watchdog`); scheduled tasks **`RDP-Login-Monitor`** / **`RDP-Login-Monitor-Watchdog`** are registered by **`-InstallTasks`**.
|
||||||
- **`ignore.lst.example`** in the repo is a template for **`ignore.lst`** to suppress selected Security notifications (see section 7).
|
- **`ignore.lst.example`** in the repo is a template for **`ignore.lst`** to suppress selected Security notifications (see section 7).
|
||||||
- **`login_monitor.settings.example.ps1`** — template for **`login_monitor.settings.ps1`** (Telegram, SMTP, 4740, local IP exclusions). Deploy may create `login_monitor.settings.ps1` from the example on first install.
|
- **`login_monitor.settings.example.ps1`** — template for **`login_monitor.settings.ps1`** (Telegram, SMTP, 4740, local IP exclusions). Deploy may create `login_monitor.settings.ps1` from the example on first install.
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Клиент Security Alert Center для RDP-login-monitor.
|
Клиент Security Alert Center для RDP-login-monitor.
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
@@ -420,6 +420,7 @@ function Test-SacShouldAttemptSend {
|
|||||||
function Invoke-SacTlsPrep {
|
function Invoke-SacTlsPrep {
|
||||||
if (-not $SacTlsSkipVerify) { return }
|
if (-not $SacTlsSkipVerify) { return }
|
||||||
if (-not $script:SacTlsCallbackRegistered) {
|
if (-not $script:SacTlsCallbackRegistered) {
|
||||||
|
Write-SacLog 'CRITICAL: SacTlsSkipVerify=$true — TLS certificate validation disabled for SAC (MITM risk). Use only for short-lived lab debugging.'
|
||||||
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
|
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
|
||||||
$script:SacTlsCallbackRegistered = $true
|
$script:SacTlsCallbackRegistered = $true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Watchdog для Login_Monitor.ps1
|
|
||||||
.DESCRIPTION
|
|
||||||
Проверяет, запущен ли основной скрипт Login_Monitor.ps1.
|
|
||||||
Если нет — запускает его и пишет лог.
|
|
||||||
Дополнительно проверяет heartbeat-файл и перезапускает скрипт, если heartbeat "протух".
|
|
||||||
#>
|
|
||||||
|
|
||||||
[CmdletBinding()]
|
|
||||||
param(
|
|
||||||
[string]$MainScriptPath = "D:\Soft\Login_Monitor.ps1",
|
|
||||||
[string]$HeartbeatFile = "D:\Soft\Logs\last_heartbeat.txt",
|
|
||||||
[int]$HeartbeatStaleMinutes = 90,
|
|
||||||
[string]$WatchdogLog = "D:\Soft\Logs\watchdog.log"
|
|
||||||
)
|
|
||||||
|
|
||||||
Set-StrictMode -Version Latest
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
|
|
||||||
$script:Utf8BomEncoding = New-Object System.Text.UTF8Encoding $true
|
|
||||||
$script:WatchdogLogBomChecked = $false
|
|
||||||
|
|
||||||
function Ensure-FileStartsWithUtf8Bom {
|
|
||||||
param([Parameter(Mandatory = $true)][string]$Path)
|
|
||||||
if (-not (Test-Path -LiteralPath $Path)) { return }
|
|
||||||
$bytes = [System.IO.File]::ReadAllBytes($Path)
|
|
||||||
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) { return }
|
|
||||||
$bom = [byte[]](0xEF, 0xBB, 0xBF)
|
|
||||||
$combined = New-Object byte[] ($bom.Length + $bytes.Length)
|
|
||||||
[Buffer]::BlockCopy($bom, 0, $combined, 0, $bom.Length)
|
|
||||||
if ($bytes.Length -gt 0) {
|
|
||||||
[Buffer]::BlockCopy($bytes, 0, $combined, $bom.Length, $bytes.Length)
|
|
||||||
}
|
|
||||||
[System.IO.File]::WriteAllBytes($Path, $combined)
|
|
||||||
}
|
|
||||||
|
|
||||||
function Write-WatchdogLog {
|
|
||||||
param([string]$Message)
|
|
||||||
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
||||||
$line = "$ts - $Message" + [Environment]::NewLine
|
|
||||||
$dir = Split-Path -Parent $WatchdogLog
|
|
||||||
if ($dir -and -not (Test-Path $dir)) {
|
|
||||||
New-Item -ItemType Directory -Path $dir -Force | Out-Null
|
|
||||||
}
|
|
||||||
if (-not $script:WatchdogLogBomChecked) {
|
|
||||||
Ensure-FileStartsWithUtf8Bom -Path $WatchdogLog
|
|
||||||
$script:WatchdogLogBomChecked = $true
|
|
||||||
}
|
|
||||||
[System.IO.File]::AppendAllText($WatchdogLog, $line, $script:Utf8BomEncoding)
|
|
||||||
}
|
|
||||||
|
|
||||||
function Get-MainScriptProcesses {
|
|
||||||
try {
|
|
||||||
$procs = Get-CimInstance Win32_Process -Filter "Name = 'powershell.exe' OR Name = 'pwsh.exe'" -ErrorAction Stop
|
|
||||||
return $procs | Where-Object { $_.CommandLine -and ($_.CommandLine -like "*$MainScriptPath*") }
|
|
||||||
} catch {
|
|
||||||
Write-WatchdogLog "Ошибка проверки процессов: $($_.Exception.Message)"
|
|
||||||
return @()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Start-MainScript {
|
|
||||||
if (-not (Test-Path $MainScriptPath)) {
|
|
||||||
Write-WatchdogLog "Основной скрипт не найден: $MainScriptPath"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
$args = "-NoProfile -ExecutionPolicy Bypass -File `"$MainScriptPath`""
|
|
||||||
Start-Process -FilePath "powershell.exe" -ArgumentList $args -WindowStyle Hidden | Out-Null
|
|
||||||
Write-WatchdogLog "Основной скрипт запущен: $MainScriptPath"
|
|
||||||
}
|
|
||||||
|
|
||||||
function Stop-MainScript {
|
|
||||||
$procs = Get-MainScriptProcesses
|
|
||||||
foreach ($p in $procs) {
|
|
||||||
try {
|
|
||||||
Stop-Process -Id $p.ProcessId -Force -ErrorAction Stop
|
|
||||||
Write-WatchdogLog "Остановлен зависший экземпляр PID=$($p.ProcessId)"
|
|
||||||
} catch {
|
|
||||||
Write-WatchdogLog "Ошибка остановки PID=$($p.ProcessId): $($_.Exception.Message)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Is-HeartbeatStale {
|
|
||||||
if (-not (Test-Path $HeartbeatFile)) {
|
|
||||||
Write-WatchdogLog "Heartbeat файл отсутствует: $HeartbeatFile"
|
|
||||||
return $true
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
$raw = (Get-Content $HeartbeatFile -ErrorAction Stop | Select-Object -First 1).Trim()
|
|
||||||
if (-not $raw) { return $true }
|
|
||||||
$hb = [datetime]::ParseExact($raw, "dd.MM.yyyy HH:mm:ss", $null)
|
|
||||||
$age = (Get-Date) - $hb
|
|
||||||
return ($age.TotalMinutes -gt $HeartbeatStaleMinutes)
|
|
||||||
} catch {
|
|
||||||
Write-WatchdogLog "Ошибка чтения heartbeat: $($_.Exception.Message)"
|
|
||||||
return $true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$running = Get-MainScriptProcesses
|
|
||||||
if (-not $running -or $running.Count -eq 0) {
|
|
||||||
Write-WatchdogLog "Основной скрипт не запущен, выполняю старт."
|
|
||||||
Start-MainScript
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Is-HeartbeatStale) {
|
|
||||||
Write-WatchdogLog "Heartbeat устарел, перезапускаю основной скрипт."
|
|
||||||
Stop-MainScript
|
|
||||||
Start-Sleep -Seconds 2
|
|
||||||
Start-MainScript
|
|
||||||
} else {
|
|
||||||
Write-WatchdogLog "Проверка пройдена: процесс запущен, heartbeat свежий."
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Push sanitized main to GitHub without leaving secrets on local main (kalinamall workflow).
|
||||||
|
# Usage: .\scripts\Push-GitHubMirror.ps1
|
||||||
|
param(
|
||||||
|
[string]$Remote = 'github',
|
||||||
|
[string]$Branch = 'main'
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$Root = Split-Path -Parent $PSScriptRoot
|
||||||
|
Set-Location $Root
|
||||||
|
|
||||||
|
git remote get-url $Remote 2>$null | Out-Null
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "remote not configured: $Remote"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((git status --porcelain)) {
|
||||||
|
throw 'working tree not clean; commit or stash first'
|
||||||
|
}
|
||||||
|
|
||||||
|
$before = (git rev-parse HEAD).Trim()
|
||||||
|
Write-Output "local HEAD before GitHub push: $before"
|
||||||
|
|
||||||
|
& "$PSScriptRoot\Sanitize-ForGitHub.ps1"
|
||||||
|
& "$PSScriptRoot\Rewrite-GitHostUrls.ps1" -Target github
|
||||||
|
& "$PSScriptRoot\Test-NoSecretsForGitHub.ps1"
|
||||||
|
|
||||||
|
$status = git status --porcelain
|
||||||
|
if (-not $status) {
|
||||||
|
Write-Output 'no changes after sanitize; pushing current HEAD to GitHub'
|
||||||
|
git push $Remote $Branch
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
git add -A
|
||||||
|
git commit -m "chore(github): sanitize secrets and sync public mirror URLs"
|
||||||
|
git push --force-with-lease $Remote $Branch
|
||||||
|
git reset --hard $before
|
||||||
|
Write-Output "pushed $Remote/$Branch (force-with-lease mirror); local main restored to $before (production/kalinamall)"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Push main to a mirror remote with host-specific doc URLs, without leaving URL churn on main.
|
# Push main to a mirror remote with host-specific doc URLs, without leaving URL churn on main.
|
||||||
# Usage: .\scripts\Push-Mirror.ps1 github|kalinamall|papatramp
|
# Usage: .\scripts\Push-Mirror.ps1 github|kalinamall|papatramp
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)]
|
[Parameter(Mandatory = $true)]
|
||||||
@@ -11,7 +11,7 @@ $Root = Split-Path -Parent $PSScriptRoot
|
|||||||
Set-Location $Root
|
Set-Location $Root
|
||||||
|
|
||||||
$remote = switch ($Target) {
|
$remote = switch ($Target) {
|
||||||
'github' { 'origin' }
|
'github' { 'github' }
|
||||||
'kalinamall' { 'kalinamall' }
|
'kalinamall' { 'kalinamall' }
|
||||||
'papatramp' { 'papatramp' }
|
'papatramp' { 'papatramp' }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
# Replace production-only values with public-safe placeholders (GitHub mirror).
|
||||||
|
# Usage: .\scripts\Sanitize-ForGitHub.ps1
|
||||||
|
# Reversible: production copies live on kalinamall/papatramp; restore via git reset --hard.
|
||||||
|
param(
|
||||||
|
[switch]$WhatIf
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$Root = Split-Path -Parent $PSScriptRoot
|
||||||
|
Set-Location $Root
|
||||||
|
|
||||||
|
function Set-TrackedFileText {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)][string]$RelativePath,
|
||||||
|
[Parameter(Mandatory = $true)][string]$Content
|
||||||
|
)
|
||||||
|
$path = Join-Path $Root $RelativePath
|
||||||
|
if ($WhatIf) {
|
||||||
|
Write-Output "WhatIf: would write $RelativePath"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$utf8Bom = New-Object System.Text.UTF8Encoding $true
|
||||||
|
[System.IO.File]::WriteAllText($path, $Content.TrimEnd() + "`r`n", $utf8Bom)
|
||||||
|
Write-Output "sanitized: $RelativePath"
|
||||||
|
}
|
||||||
|
|
||||||
|
$loginSettings = @'
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Локальные настройки Login_Monitor.ps1
|
||||||
|
.DESCRIPTION
|
||||||
|
Скопируйте в C:\ProgramData\RDP-login-monitor\login_monitor.settings.ps1
|
||||||
|
и при необходимости отредактируйте. Deploy-LoginMonitor.ps1 не перезаписывает settings,
|
||||||
|
если SAC уже настроен (UseSAC не off и задан SacApiKey). При первой установке или апгрейде
|
||||||
|
с версии без SAC (нет Sac-Client.ps1 / пустой ключ) example копируется поверх с резервной .bak.
|
||||||
|
#>
|
||||||
|
|
||||||
|
# --- Telegram (или DPAPI Base64 через Encrypt-DpapiForRdpMonitor.ps1) ---
|
||||||
|
$TelegramBotToken = 'YOUR_BOT_TOKEN'
|
||||||
|
$TelegramChatID = 'YOUR_CHAT_ID'
|
||||||
|
# $TelegramBotTokenProtectedB64 = ''
|
||||||
|
# $TelegramChatIDProtectedB64 = ''
|
||||||
|
|
||||||
|
# --- Email (опционально) ---
|
||||||
|
$NotifyOrder = 'tg'
|
||||||
|
# $MailSmtpHost = 'smtp.example.com'
|
||||||
|
# $MailSmtpPort = 587
|
||||||
|
# $MailSmtpUser = ''
|
||||||
|
# $MailSmtpPassword = ''
|
||||||
|
# $MailFrom = 'monitor@example.com'
|
||||||
|
# $MailTo = 'admin@example.com'
|
||||||
|
# $MailSmtpStartTls = $true
|
||||||
|
# $MailSmtpSsl = $false
|
||||||
|
# $MailSmtpPasswordProtectedB64 = ''
|
||||||
|
|
||||||
|
# --- Подпись сервера в Telegram и SAC (host.display_name); пусто = $env:COMPUTERNAME ---
|
||||||
|
# $ServerDisplayName = 'RDP-Server-01'
|
||||||
|
# --- Явный IPv4 хоста для SAC (опционально; иначе автоопределение) ---
|
||||||
|
# $ServerIPv4 = '192.168.1.10'
|
||||||
|
|
||||||
|
# --- Security Alert Center (SAC) ---
|
||||||
|
# off | exclusive | dual | fallback — см. security-alert-center/docs/agent-integration.md
|
||||||
|
$UseSAC = 'fallback'
|
||||||
|
$SacUrl = 'https://sac.example.com'
|
||||||
|
$SacApiKey = 'sac_CHANGE_ME'
|
||||||
|
$SacSpoolDir = 'C:\ProgramData\RDP-login-monitor\sac-spool'
|
||||||
|
$SacTimeoutSec = 45
|
||||||
|
$SacSpoolFlushMaxFiles = 50
|
||||||
|
$SacSpoolMaxAgeHours = 72
|
||||||
|
# $SacTlsSkipVerify = $false
|
||||||
|
# $SacFallbackFailures = 5
|
||||||
|
# $false = не слать report.daily.rdp с агента (суточный отчёт только из SAC)
|
||||||
|
# В settings.ps1 используйте 1/0 или $true/$false — не пишите голое false без $
|
||||||
|
$DailyReportEnabled = 1
|
||||||
|
|
||||||
|
# --- Heartbeat SAC (agent.heartbeat): интервал в секундах; 14400 = 4 ч ---
|
||||||
|
$HeartbeatInterval = 14400
|
||||||
|
# Оповещение, если last_heartbeat.txt не обновлялся > множитель × интервал (2 × 4 ч = 8 ч)
|
||||||
|
$HeartbeatStaleAlertMultiplier = 2
|
||||||
|
# Poll SAC на команды qwinsta/logoff (сек); см. security-alert-center/docs/agent-control-plane.md
|
||||||
|
# $SacCommandPollIntervalSec = 60
|
||||||
|
|
||||||
|
# Окно (мин): LastBootUpTime + System 41/1074/6005/6008/6009 → «старт после перезагрузки ОС»
|
||||||
|
$StartupRebootDetectMinutes = 5
|
||||||
|
|
||||||
|
# --- Инвентаризация железа/ПО для SAC (agent.inventory, раз в 12 ч) ---
|
||||||
|
$GetInventory = $true
|
||||||
|
|
||||||
|
# --- RDS Shadow Control + WinRM inbound (Enter-PSSession), severity warning ---
|
||||||
|
# $EnableRcm1149Monitoring = 1 # RCM Operational 1149 (RDP auth; workstation + RDS server)
|
||||||
|
# $EnableRcmShadowControlMonitoring = 1 # RCM Operational 20506/20507/20510
|
||||||
|
# $EnableWinRmInboundMonitoring = 1 # WinRM Operational 91 (+ correlate Security 4624)
|
||||||
|
# $EnableAdminShareMonitoring = 1 # Security 5140 C$/ADMIN$ (audit File Share)
|
||||||
|
# $WinRmIgnoreLocalSource = 1 # ::1, 127.0.0.1, fe80 (шум Exchange/локальный WinRM)
|
||||||
|
# $WinRmIgnoreMachineAccounts = 1 # учётки, оканчивающиеся на $
|
||||||
|
# $WinRmExchangeStrictMode = 1 # Exchange: user в Event 91 обязателен; 4624 только LogonProcess WinRM
|
||||||
|
# HealthMailbox* уже в ExcludedUserPatterns скрипта
|
||||||
|
# Проверка: powershell -File Login_Monitor.ps1 -CheckSac
|
||||||
|
|
||||||
|
# --- Узкое исключение шумовых сетевых логонов (LogonType=3, Advapi) ---
|
||||||
|
$IgnoreAdvapiNetworkLogonSourceIps = @(
|
||||||
|
'192.168.1.10'
|
||||||
|
)
|
||||||
|
# --- Exchange noise filter: 4624 + LogonType=3 + IP='-' (часто Outlook/почтовые клиенты) ---
|
||||||
|
# Включайте на почтовом сервере, если нужен только полезный интерактивный сигнал.
|
||||||
|
${Ignore4624-LT3-EmptyIP-Event} = $false
|
||||||
|
|
||||||
|
# --- Ротация login_monitor.log и хранение бэкапов (Logs\Backup\LoginLog_*.bak) ---
|
||||||
|
# $LogRotationHour = 0
|
||||||
|
# $LogRotationMinute = 0
|
||||||
|
$MaxBackupDays = 31
|
||||||
|
|
||||||
|
# --- Блокировка учётной записи AD (4740) + IP из IIS ActiveSync ---
|
||||||
|
# Мониторинг включается только на КД с именем $LockoutMonitorDomainController.
|
||||||
|
$LockoutMonitorDomainController = 'dc01.contoso.local'
|
||||||
|
$NetBiosDomainName = 'CONTOSO'
|
||||||
|
$ExchangeIisLogPath = '\\mail.contoso.local\c$\inetpub\logs\LogFiles\W3SVC1'
|
||||||
|
$ExchangeServerHostForIisExclude = ''
|
||||||
|
$ExchangeIisLogTailLines = 5000
|
||||||
|
$ExchangeIisLogMinutesBeforeLockout = 30
|
||||||
|
'@
|
||||||
|
|
||||||
|
Set-TrackedFileText -RelativePath 'login_monitor.settings.example.ps1' -Content $loginSettings
|
||||||
|
|
||||||
|
$exchangeSettingsPath = Join-Path $Root 'exchange_monitor.settings.example.ps1'
|
||||||
|
if (Test-Path -LiteralPath $exchangeSettingsPath) {
|
||||||
|
$ex = Get-Content -LiteralPath $exchangeSettingsPath -Raw
|
||||||
|
$ex = $ex -replace 'kalinamall\.ru', 'example.com'
|
||||||
|
$ex = $ex -replace 'fifth\.example\.com', 'mail.contoso.local'
|
||||||
|
$ex = $ex -replace 'k\.selezneva@example\.com', 'broken-mailbox@example.com'
|
||||||
|
Set-TrackedFileText -RelativePath 'exchange_monitor.settings.example.ps1' -Content $ex
|
||||||
|
}
|
||||||
|
|
||||||
|
$updatePath = Join-Path $Root 'update-rdp-monitor.ps1'
|
||||||
|
if (Test-Path -LiteralPath $updatePath) {
|
||||||
|
$upd = Get-Content -LiteralPath $updatePath -Raw
|
||||||
|
$upd = $upd -replace "Posle fetch: vsegda reset --hard na kalinamall/main \(bez merge\), zatem clean -fd\.",
|
||||||
|
'Posle fetch: reset --hard na upstream/main (bez merge), zatem clean -fd.'
|
||||||
|
$upd = $upd -replace "\\\\b26\\NETLOGON\\RDP-login-monitor", '\\dc.contoso.local\NETLOGON\RDP-login-monitor'
|
||||||
|
$upd = $upd -replace "https://git\.kalinamall\.ru/PapaTramp/RDP-login-monitor\.git",
|
||||||
|
'https://github.com/PTah/RDP-login-monitor.git'
|
||||||
|
Set-TrackedFileText -RelativePath 'update-rdp-monitor.ps1' -Content $upd
|
||||||
|
}
|
||||||
|
|
||||||
|
$netlogonDoc = Join-Path $Root 'Docs/deploy-netlogon-publish.md'
|
||||||
|
if (Test-Path -LiteralPath $netlogonDoc) {
|
||||||
|
$doc = Get-Content -LiteralPath $netlogonDoc -Raw
|
||||||
|
$doc = $doc -replace 'K6A-DC3', 'dc01.corp.example.com'
|
||||||
|
$doc = $doc -replace '\\\\b26\\', '\\dc.contoso.local\'
|
||||||
|
$doc = $doc -replace "https://git\.kalinamall\.ru/PapaTramp/RDP-login-monitor\.git",
|
||||||
|
'https://git.example.com/org/RDP-login-monitor.git'
|
||||||
|
Set-TrackedFileText -RelativePath 'Docs/deploy-netlogon-publish.md' -Content $doc
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output 'Sanitize-ForGitHub: done'
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# Fail if tracked text still contains production-only markers (run before GitHub push).
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$Root = Split-Path -Parent $PSScriptRoot
|
||||||
|
Set-Location $Root
|
||||||
|
|
||||||
|
$patterns = @(
|
||||||
|
'8239219522',
|
||||||
|
'sac_UkOsAT',
|
||||||
|
'2843230',
|
||||||
|
'sac\.kalinamall\.ru',
|
||||||
|
'\\\\b26\\',
|
||||||
|
'K6A-DC3',
|
||||||
|
'fifth\.kalinamall',
|
||||||
|
'192\.168\.160\.57',
|
||||||
|
'kalinamall\.ru',
|
||||||
|
'git\.kalinamall\.ru',
|
||||||
|
'git\.papatramp\.ru',
|
||||||
|
'\d{8,12}:[A-Za-z0-9_-]{20,}'
|
||||||
|
)
|
||||||
|
|
||||||
|
$extensions = @('*.md', '*.ps1', '*.example', '*.txt', '*.json', '*.yml', '*.yaml')
|
||||||
|
$files = git ls-files $extensions 2>$null | Where-Object { $_ -and (Test-Path $_) }
|
||||||
|
|
||||||
|
$hits = @()
|
||||||
|
foreach ($file in $files) {
|
||||||
|
if ($file -like 'scripts/Rewrite-GitHostUrls.ps1') { continue }
|
||||||
|
if ($file -like 'scripts/Push-PrivateMirror.ps1') { continue }
|
||||||
|
if ($file -like 'scripts/Sanitize-ForGitHub.ps1') { continue }
|
||||||
|
if ($file -like 'scripts/Test-NoSecretsForGitHub.ps1') { continue }
|
||||||
|
if ($file -like 'scripts/Push-GitHubMirror.ps1') { continue }
|
||||||
|
|
||||||
|
$text = Get-Content -LiteralPath $file -Raw -ErrorAction SilentlyContinue
|
||||||
|
if ([string]::IsNullOrEmpty($text)) { continue }
|
||||||
|
|
||||||
|
foreach ($pat in $patterns) {
|
||||||
|
if ($text -match $pat) {
|
||||||
|
$hits += "${file}: matches /$pat/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($hits.Count -gt 0) {
|
||||||
|
Write-Error ("GitHub secret scan failed:`n" + ($hits -join "`n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "GitHub secret scan: OK ($($files.Count) files)"
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
2.1.9-SAC
|
2.1.10-SAC
|
||||||
|
|||||||
Reference in New Issue
Block a user