Merge origin/main into main
This commit is contained in:
@@ -6,6 +6,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizTalkCheckmkPulse", "src\
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizTalkCheckmkPulse.Tests", "tests\BizTalkCheckmkPulse.Tests\BizTalkCheckmkPulse.Tests.csproj", "{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizTalkCheckmkPulse.Setup", "src\BizTalkCheckmkPulse.Setup\BizTalkCheckmkPulse.Setup.csproj", "{764AC43A-26D8-43C1-9121-13FC8A9CC8B1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizTalkCheckmkPulse.Packager", "src\BizTalkCheckmkPulse.Packager\BizTalkCheckmkPulse.Packager.csproj", "{B35A04E0-253B-4CEB-9033-F5109F3B9F82}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -20,6 +24,14 @@ Global
|
||||
{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E219C45A-CC95-4F45-9B6F-8244CBAEE35A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{764AC43A-26D8-43C1-9121-13FC8A9CC8B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{764AC43A-26D8-43C1-9121-13FC8A9CC8B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{764AC43A-26D8-43C1-9121-13FC8A9CC8B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{764AC43A-26D8-43C1-9121-13FC8A9CC8B1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B35A04E0-253B-4CEB-9033-F5109F3B9F82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B35A04E0-253B-4CEB-9033-F5109F3B9F82}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B35A04E0-253B-4CEB-9033-F5109F3B9F82}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B35A04E0-253B-4CEB-9033-F5109F3B9F82}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
+26
-40
@@ -16,7 +16,7 @@ Verbindliche Randbedingungen:
|
||||
- Der Agentpfad fuehrt niemals WMI- oder SQL-Abfragen aus.
|
||||
- Fehler muessen als gueltige Checkmk-`UNKNOWN`-Services sichtbar werden.
|
||||
- Schreiben und Lesen duerfen nie einen halben Snapshot exponieren.
|
||||
- Laufzeitcode benoetigt keine PowerShell und keine BizTalk-DLL-Referenz.
|
||||
- Installation und Laufzeit benoetigen keine PowerShell und keine BizTalk-DLL-Referenz.
|
||||
- Installation, ACL und Scheduled Task muessen reproduzierbar sein.
|
||||
|
||||
## 2. Ausloeser der Architekturanderung
|
||||
@@ -377,29 +377,30 @@ scripts\test-release.cmd
|
||||
scripts\package-release.cmd
|
||||
```
|
||||
|
||||
Der Release-Build der Visual-Studio-2019-Solution baut Anwendung, grafischen
|
||||
Installer und Packaging-Werkzeug. Danach liegen der Paketordner
|
||||
`artifacts\BizTalkCheckmkPulse-Setup` und das direkt transportierbare
|
||||
`artifacts\BizTalkCheckmkPulse-Setup.zip` bereit.
|
||||
|
||||
### 8.2 Normales Servicekonto
|
||||
|
||||
```powershell
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk' `
|
||||
-EnvironmentName ACC
|
||||
```
|
||||
Das ZIP wird auf dem Zielserver vollstaendig entpackt. Danach `Setup.exe` als
|
||||
Administrator starten, Konto im Format `DOMAIN\Benutzer` (zum Beispiel
|
||||
`BEW\t231bizmon`), Kennwort und Umgebung eintragen und die Installation
|
||||
starten.
|
||||
|
||||
Der Installer muss als lokaler Administrator laufen. Er vergibt keine
|
||||
AD-/BizTalk-/SQL-Rechte; diese bleiben getrennte administrative Freigaben.
|
||||
|
||||
Der installierte Task selbst laeuft mit `RunLevel Limited`. Der Installer fragt
|
||||
das Kennwort mit `Get-Credential` ab; es wird nicht in Config oder Log
|
||||
Der installierte Task selbst laeuft mit `RunLevel Limited`. Der Installer
|
||||
uebergibt das Kennwort direkt an die Windows-Task-Scheduler-COM-Schnittstelle;
|
||||
es wird weder in einer Prozesskommandozeile noch in Config oder Log
|
||||
geschrieben. Das Konto benoetigt `Log on as a batch job`.
|
||||
|
||||
### 8.3 Optionales gMSA
|
||||
|
||||
```powershell
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk$' `
|
||||
-Gmsa `
|
||||
-EnvironmentName ACC
|
||||
```
|
||||
Im Installer die gMSA-Checkbox aktivieren und ein auf `$` endendes Konto wie
|
||||
`BEW\svc_biztalk_cmk$` eingeben. Ein Kennwort wird dann nicht abgefragt.
|
||||
|
||||
### 8.4 Checkmk
|
||||
|
||||
@@ -451,12 +452,12 @@ aelter als `LogRetentionDays`.
|
||||
|
||||
### 10.1 Grundpruefung
|
||||
|
||||
```powershell
|
||||
Get-ScheduledTaskInfo -TaskName 'BizTalk Checkmk Pulse Provider'
|
||||
Get-Item "$env:ProgramData\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot"
|
||||
Get-Content "$env:ProgramData\BizTalkCheckmkPulse\logs\*.log" -Tail 100
|
||||
& "$env:ProgramFiles\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume
|
||||
& "C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump
|
||||
```cmd
|
||||
schtasks.exe /query /tn "BizTalk Checkmk Pulse Provider" /v /fo list
|
||||
dir "%ProgramData%\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot"
|
||||
type "%ProgramData%\BizTalkCheckmkPulse\logs\biztalk-checkmk-pulse-*.log"
|
||||
"%ProgramFiles%\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume
|
||||
"C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump
|
||||
```
|
||||
|
||||
### 10.2 Kein Snapshot
|
||||
@@ -615,32 +616,17 @@ Erst nach ACC-Abnahme erfolgt der gestufte Rollout nach DEV/TST/PRD.
|
||||
|
||||
## 13. Deinstallation und Rollback
|
||||
|
||||
```powershell
|
||||
.\Uninstall-BizTalkCheckmkPulse.ps1
|
||||
```
|
||||
|
||||
`-KeepRuntimeData` erhaelt Logs und Snapshot. Das Skript entfernt Task,
|
||||
Wrapper und Programmdateien, aber keine AD-Gruppenmitgliedschaft. Die
|
||||
Berechtigung wird separat nach Change-Verfahren entzogen.
|
||||
`Setup.exe` aus dem entpackten Paket erneut starten und **Deinstallieren**
|
||||
waehlen. Der Installer entfernt Task, Wrapper und Programmdateien, behaelt
|
||||
Logs und Snapshot aber absichtlich bei. Die AD-Gruppenmitgliedschaft wird
|
||||
nicht geaendert und separat nach Change-Verfahren entzogen.
|
||||
|
||||
Rollback auf die alte direkte `LocalSystem`-Architektur ist nicht empfohlen.
|
||||
Falls kurzfristig notwendig, muss Security die Maschinenkonto-Berechtigung
|
||||
explizit freigeben; der Checkmk-Agentdienst selbst darf nicht auf das
|
||||
Collector-Konto umgestellt werden.
|
||||
|
||||
## 14. Transport per certutil
|
||||
|
||||
Die Source-Uebergabe besteht aus ZIP plus Base64-TXT:
|
||||
|
||||
```cmd
|
||||
certutil -decode <datei>.zip.b64.txt <datei>.zip
|
||||
certutil -hashfile <datei>.zip SHA256
|
||||
tar -xf <datei>.zip
|
||||
```
|
||||
|
||||
ZIP und Base64 werden erst nach dem Git-Commit aus genau diesem Commit erzeugt.
|
||||
|
||||
## 15. Referenzen
|
||||
## 14. Referenzen
|
||||
|
||||
- https://learn.microsoft.com/en-us/biztalk/core/managing-biztalk-server-security
|
||||
- https://learn.microsoft.com/en-us/biztalk/core/windows-groups-and-user-accounts-in-biztalk-server
|
||||
|
||||
@@ -164,22 +164,29 @@ scripts\test-release.cmd
|
||||
scripts\package-release.cmd
|
||||
```
|
||||
|
||||
Das Paket wird unter `artifacts\BizTalkCheckmkPulse-deploy` erzeugt:
|
||||
Jeder Release-Build der Solution erzeugt automatisch den fertigen Paketordner
|
||||
und das transportierbare ZIP:
|
||||
|
||||
```text
|
||||
BizTalkCheckmkPulse-deploy\
|
||||
Install-BizTalkCheckmkPulse.ps1
|
||||
Uninstall-BizTalkCheckmkPulse.ps1
|
||||
biztalk_checkmk_pulse.cmd
|
||||
application\
|
||||
BizTalkCheckmkPulse.exe
|
||||
BizTalkCheckmkPulse.exe.config
|
||||
artifacts\
|
||||
BizTalkCheckmkPulse-Setup.zip
|
||||
BizTalkCheckmkPulse-Setup\
|
||||
Setup.exe
|
||||
INSTALLATION.md
|
||||
biztalk_checkmk_pulse.cmd
|
||||
application\
|
||||
BizTalkCheckmkPulse.exe
|
||||
BizTalkCheckmkPulse.exe.config
|
||||
```
|
||||
|
||||
Das Packaging-Projekt ist Teil von `BizTalkCheckmkPulse.sln`. Ein normaler
|
||||
`Release`-Build in Visual Studio 2019 genuegt daher; ein separates
|
||||
PowerShell-/WiX-/MSI-Tooling wird nicht benoetigt.
|
||||
|
||||
Format-Self-Test ohne WMI, SQL oder Event Log:
|
||||
|
||||
```cmd
|
||||
artifacts\BizTalkCheckmkPulse-deploy\application\BizTalkCheckmkPulse.exe --self-test
|
||||
artifacts\BizTalkCheckmkPulse-Setup\application\BizTalkCheckmkPulse.exe --self-test
|
||||
```
|
||||
|
||||
Erwartet werden exakt neun `OK`-Zeilen. Die Regressionstests pruefen
|
||||
@@ -191,16 +198,7 @@ Windows-/BizTalk-Laufzeitvalidierung.
|
||||
## Berechtigung vorbereiten
|
||||
|
||||
Die exakte Read-Only-Gruppe wird in der BizTalk Administration Console unter
|
||||
den Eigenschaften der BizTalk-Gruppe abgelesen. Ein bereits berechtigtes Konto
|
||||
kann sie alternativ ermitteln:
|
||||
|
||||
```powershell
|
||||
Get-CimInstance `
|
||||
-Namespace root/MicrosoftBizTalkServer `
|
||||
-ClassName MSBTS_GroupSetting |
|
||||
Select-Object Name, BizTalkReadOnlyUserGroup, BizTalkOperatorGroup,
|
||||
MgmtDbServerName, MgmtDbName
|
||||
```
|
||||
den Eigenschaften der BizTalk-Gruppe abgelesen.
|
||||
|
||||
Ein AD-Administrator nimmt das neue Provider-Konto in
|
||||
`BizTalkReadOnlyUserGroup` auf. Nach AD-Replikation muss das Servicekonto durch
|
||||
@@ -215,22 +213,23 @@ fuer das Provider-Konto.
|
||||
|
||||
## Installation mit normalem Servicekonto
|
||||
|
||||
```powershell
|
||||
Set-Location C:\Temp\BizTalkCheckmkPulse-deploy
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk' `
|
||||
-EnvironmentName ACC
|
||||
```
|
||||
1. `BizTalkCheckmkPulse-Setup.zip` auf dem Zielserver vollstaendig entpacken.
|
||||
2. `Setup.exe` starten und die UAC-Abfrage bestaetigen.
|
||||
3. Collector-Konto, zum Beispiel `BEW\t231bizmon`, Kennwort und Umgebung
|
||||
eingeben.
|
||||
4. **Installieren / aktualisieren** waehlen.
|
||||
|
||||
Der Installer fragt das Kennwort ueber `Get-Credential` ab und speichert es
|
||||
durch die Windows-Aufgabenplanung. Das Kennwort steht weder in der
|
||||
Konfigurationsdatei noch in den Logs.
|
||||
Der Installer uebergibt das Kennwort direkt ueber die Windows-Task-Scheduler-
|
||||
COM-Schnittstelle. Es steht weder in einer Prozesskommandozeile noch in der
|
||||
Konfigurationsdatei oder in Logs. Der Backslash in `DOMAIN\Benutzer` wird als
|
||||
normaler Bestandteil des Kontonamens verarbeitet.
|
||||
|
||||
Wenn das Kennwort rotiert oder ablaeuft, muss es im Scheduled Task aktualisiert
|
||||
werden. Bis dahin wird der Snapshot nach 180 Sekunden stale und Checkmk zeigt
|
||||
alle neun Services als `UNKNOWN`.
|
||||
werden. Dazu `Setup.exe` mit dem neuen Kennwort erneut ausfuehren. Bis dahin
|
||||
wird der Snapshot nach 180 Sekunden stale und Checkmk zeigt alle acht Services
|
||||
als `UNKNOWN`.
|
||||
|
||||
Ein gMSA kann weiterhin optional mit `-Gmsa` installiert werden; die
|
||||
Ein gMSA kann ueber die Checkbox ohne Kennworteingabe installiert werden; die
|
||||
produktive Standardbeschreibung geht vom normalen Servicekonto aus.
|
||||
|
||||
Der Installer:
|
||||
@@ -245,48 +244,34 @@ Der Installer:
|
||||
`IgnoreNew`, fuenf Minuten Laufzeitlimit und zwei Wiederholungen,
|
||||
6. fuehrt den Self-Test aus und startet den Provider einmalig.
|
||||
|
||||
PowerShell wird nur fuer Installation und Betriebsdiagnose verwendet. Der
|
||||
minuetliche Provider und der Checkmk-Consumer sind .NET-/CMD-Laufzeitcode und
|
||||
haengen nicht von der PowerShell Execution Policy ab.
|
||||
Installation, Update, Deinstallation und Laufzeit verwenden keine PowerShell.
|
||||
|
||||
## Verifikation auf dem Server
|
||||
|
||||
Task und letzter Lauf:
|
||||
|
||||
```powershell
|
||||
Get-ScheduledTask -TaskName 'BizTalk Checkmk Pulse Provider' |
|
||||
Select-Object TaskName, State
|
||||
Get-ScheduledTaskInfo -TaskName 'BizTalk Checkmk Pulse Provider' |
|
||||
Select-Object LastRunTime, LastTaskResult, NextRunTime
|
||||
```cmd
|
||||
schtasks.exe /query /tn "BizTalk Checkmk Pulse Provider" /v /fo list
|
||||
```
|
||||
|
||||
Provider-Log:
|
||||
|
||||
```powershell
|
||||
Get-ChildItem "$env:ProgramData\BizTalkCheckmkPulse\logs" |
|
||||
Sort-Object LastWriteTime -Descending |
|
||||
Select-Object -First 3 Name, Length, LastWriteTime
|
||||
|
||||
Get-Content `
|
||||
"$env:ProgramData\BizTalkCheckmkPulse\logs\biztalk-checkmk-pulse-*.log" `
|
||||
-Tail 100
|
||||
```cmd
|
||||
dir /o-d "%ProgramData%\BizTalkCheckmkPulse\logs"
|
||||
type "%ProgramData%\BizTalkCheckmkPulse\logs\biztalk-checkmk-pulse-*.log"
|
||||
```
|
||||
|
||||
Snapshot und Consumer:
|
||||
|
||||
```powershell
|
||||
Get-Item `
|
||||
"$env:ProgramData\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot" |
|
||||
Select-Object FullName, Length, LastWriteTimeUtc
|
||||
|
||||
& "$env:ProgramFiles\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume
|
||||
```cmd
|
||||
dir "%ProgramData%\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot"
|
||||
"%ProgramFiles%\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume
|
||||
```
|
||||
|
||||
Verbindlicher Test im echten `LocalSystem`-Kontext:
|
||||
|
||||
```powershell
|
||||
& "C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump |
|
||||
Select-String -Pattern "BizTalk|UNKNOWN|Snapshot|Permission" -Context 0,1
|
||||
```cmd
|
||||
"C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump
|
||||
```
|
||||
|
||||
Danach in Checkmk eine Service Discovery ausfuehren, die neun Services
|
||||
@@ -386,33 +371,12 @@ Ausfuehrliche Betriebs- und Architekturdetails stehen in
|
||||
|
||||
## Deinstallation
|
||||
|
||||
```powershell
|
||||
.\Uninstall-BizTalkCheckmkPulse.ps1
|
||||
```
|
||||
|
||||
Das Skript fragt vor dem Entfernen. Mit `-KeepRuntimeData` bleiben Snapshot und
|
||||
Logs erhalten:
|
||||
|
||||
```powershell
|
||||
.\Uninstall-BizTalkCheckmkPulse.ps1 -KeepRuntimeData
|
||||
```
|
||||
`Setup.exe` erneut starten und **Deinstallieren** waehlen. Snapshot und Logs
|
||||
bleiben dabei unter `%ProgramData%\BizTalkCheckmkPulse` erhalten.
|
||||
|
||||
Die AD-Gruppenmitgliedschaft des Provider-Kontos wird bewusst nicht automatisch
|
||||
geaendert und muss separat durch AD-/BizTalk-Administration entfernt werden.
|
||||
|
||||
## Certutil-Transport
|
||||
|
||||
Zu jeder Uebergabe wird ein Source-ZIP und eine certutil-kompatible
|
||||
Base64-Textdatei erzeugt. Auf Windows:
|
||||
|
||||
```cmd
|
||||
certutil -decode biztalk-checkmk-pulse-source-<datum>-<commit>.zip.b64.txt biztalk-checkmk-pulse-source.zip
|
||||
certutil -hashfile biztalk-checkmk-pulse-source.zip SHA256
|
||||
tar -xf biztalk-checkmk-pulse-source.zip
|
||||
```
|
||||
|
||||
Die konkrete Datei und SHA-256-Summe werden bei der Uebergabe genannt.
|
||||
|
||||
## Quellen
|
||||
|
||||
- Microsoft: BizTalk `MSBTS_GroupSetting.BizTalkReadOnlyUserGroup`
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Installation auf dem BizTalk-Server
|
||||
|
||||
1. `BizTalkCheckmkPulse-Setup.zip` vollstaendig in ein lokales Verzeichnis entpacken.
|
||||
2. `Setup.exe` als lokaler Administrator starten und die UAC-Abfrage bestaetigen.
|
||||
3. Das Collector-Konto im Format `DOMAIN\Benutzer` eingeben, zum Beispiel
|
||||
`BEW\t231bizmon`.
|
||||
4. Kennwort und Umgebung eingeben und **Installieren / aktualisieren** waehlen.
|
||||
5. Im Aufgabenplaner den Task `BizTalk Checkmk Pulse Provider` und danach den
|
||||
Checkmk-Agent-Dump kontrollieren.
|
||||
|
||||
PowerShell wird fuer Installation, Update, Deinstallation und Laufzeit nicht
|
||||
benoetigt. Das Kennwort wird direkt an die Windows-Aufgabenplanung uebergeben
|
||||
und weder in einer Datei noch in einer Prozesskommandozeile abgelegt.
|
||||
|
||||
Der Installer vergibt keine AD-, BizTalk- oder SQL-Berechtigungen. Das Konto
|
||||
muss separat Mitglied der fuer die BizTalk-Gruppe konfigurierten Read-Only-
|
||||
Gruppe sein und lokal das Recht `Log on as a batch job` besitzen.
|
||||
|
||||
Bei einer Deinstallation bleiben Snapshot und Logs absichtlich unter
|
||||
`%ProgramData%\BizTalkCheckmkPulse` erhalten. Sie koennen nach der
|
||||
Betriebsfreigabe manuell entfernt werden.
|
||||
@@ -1,171 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$CollectorAccount,
|
||||
|
||||
[switch]$Gmsa,
|
||||
|
||||
[ValidateSet("", "ACC", "DEV", "TST", "PRD")]
|
||||
[string]$EnvironmentName = "",
|
||||
|
||||
[string]$InstallDirectory = "$env:ProgramFiles\BizTalkCheckmkPulse",
|
||||
|
||||
[string]$CheckmkLocalDirectory = "$env:ProgramData\checkmk\agent\local"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version 2.0
|
||||
|
||||
$taskName = "BizTalk Checkmk Pulse Provider"
|
||||
$runtimeRoot = Join-Path $env:ProgramData "BizTalkCheckmkPulse"
|
||||
$dataDirectory = Join-Path $runtimeRoot "data"
|
||||
$logDirectory = Join-Path $runtimeRoot "logs"
|
||||
$sourceApplication = Join-Path $PSScriptRoot "application"
|
||||
$sourceWrapper = Join-Path $PSScriptRoot "biztalk_checkmk_pulse.cmd"
|
||||
$targetExe = Join-Path $InstallDirectory "BizTalkCheckmkPulse.exe"
|
||||
$targetConfig = "$targetExe.config"
|
||||
$targetWrapper = Join-Path $CheckmkLocalDirectory "biztalk_checkmk_pulse.cmd"
|
||||
|
||||
function Assert-Administrator {
|
||||
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
|
||||
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
throw "Die Installation muss in einer administrativen Windows PowerShell ausgefuehrt werden."
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-Icacls {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path,
|
||||
[Parameter(Mandatory = $true)][string[]]$Arguments
|
||||
)
|
||||
|
||||
& icacls.exe $Path @Arguments | Out-Host
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "icacls ist fuer '$Path' mit Exitcode $LASTEXITCODE fehlgeschlagen."
|
||||
}
|
||||
}
|
||||
|
||||
Assert-Administrator
|
||||
|
||||
if (-not (Test-Path -LiteralPath $sourceApplication -PathType Container)) {
|
||||
throw "Quellverzeichnis fehlt: $sourceApplication"
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $sourceWrapper -PathType Leaf)) {
|
||||
throw "Checkmk-Wrapper fehlt: $sourceWrapper"
|
||||
}
|
||||
|
||||
if ($Gmsa -and -not $CollectorAccount.EndsWith('$')) {
|
||||
throw "Ein gMSA-Kontoname muss mit '$' enden, z.B. DOMAIN\svc_biztalk_cmk$."
|
||||
}
|
||||
|
||||
Write-Host "Installiere Programmdateien nach $InstallDirectory ..."
|
||||
New-Item -ItemType Directory -Path $InstallDirectory -Force | Out-Null
|
||||
Copy-Item -Path (Join-Path $sourceApplication "*") -Destination $InstallDirectory -Force
|
||||
|
||||
[xml]$configuration = Get-Content -LiteralPath $targetConfig
|
||||
$environmentSetting = $configuration.configuration.appSettings.add |
|
||||
Where-Object { $_.key -eq "EnvironmentName" } |
|
||||
Select-Object -First 1
|
||||
if ($null -eq $environmentSetting) {
|
||||
throw "EnvironmentName fehlt in $targetConfig."
|
||||
}
|
||||
$environmentSetting.value = $EnvironmentName
|
||||
$configuration.Save($targetConfig)
|
||||
|
||||
Write-Host "Erzeuge Runtime-Verzeichnisse und Least-Privilege-ACLs ..."
|
||||
New-Item -ItemType Directory -Path $runtimeRoot, $dataDirectory, $logDirectory -Force | Out-Null
|
||||
|
||||
# Runtime-Root: Provider lesen, SYSTEM lesen, lokale Administratoren verwalten.
|
||||
Invoke-Icacls -Path $runtimeRoot -Arguments @(
|
||||
"/inheritance:r",
|
||||
"/grant:r",
|
||||
"*S-1-5-18:(OI)(CI)(RX)",
|
||||
"*S-1-5-32-544:(OI)(CI)(F)",
|
||||
"${CollectorAccount}:(OI)(CI)(RX)"
|
||||
)
|
||||
|
||||
# Daten: ausschliesslich Provider schreibt, LocalSystem liest den Snapshot.
|
||||
Invoke-Icacls -Path $dataDirectory -Arguments @(
|
||||
"/inheritance:r",
|
||||
"/grant:r",
|
||||
"*S-1-5-18:(OI)(CI)(RX)",
|
||||
"*S-1-5-32-544:(OI)(CI)(F)",
|
||||
"${CollectorAccount}:(OI)(CI)(M)"
|
||||
)
|
||||
|
||||
# Logs: Provider und LocalSystem-Consumer duerfen getrennte Diagnosezeilen anhaengen.
|
||||
Invoke-Icacls -Path $logDirectory -Arguments @(
|
||||
"/inheritance:r",
|
||||
"/grant:r",
|
||||
"*S-1-5-18:(OI)(CI)(M)",
|
||||
"*S-1-5-32-544:(OI)(CI)(F)",
|
||||
"${CollectorAccount}:(OI)(CI)(M)"
|
||||
)
|
||||
|
||||
Write-Host "Installiere Checkmk Local Check nach $CheckmkLocalDirectory ..."
|
||||
New-Item -ItemType Directory -Path $CheckmkLocalDirectory -Force | Out-Null
|
||||
Copy-Item -LiteralPath $sourceWrapper -Destination $targetWrapper -Force
|
||||
|
||||
Write-Host "Registriere Scheduled Task '$taskName' ..."
|
||||
$action = New-ScheduledTaskAction `
|
||||
-Execute $targetExe `
|
||||
-Argument "--collect" `
|
||||
-WorkingDirectory $InstallDirectory
|
||||
$trigger = New-ScheduledTaskTrigger `
|
||||
-Once `
|
||||
-At (Get-Date).AddMinutes(1) `
|
||||
-RepetitionInterval (New-TimeSpan -Minutes 1)
|
||||
$settings = New-ScheduledTaskSettingsSet `
|
||||
-MultipleInstances IgnoreNew `
|
||||
-ExecutionTimeLimit (New-TimeSpan -Minutes 5) `
|
||||
-StartWhenAvailable `
|
||||
-RestartCount 2 `
|
||||
-RestartInterval (New-TimeSpan -Minutes 1)
|
||||
|
||||
if ($Gmsa) {
|
||||
$principal = New-ScheduledTaskPrincipal `
|
||||
-UserId $CollectorAccount `
|
||||
-LogonType Password `
|
||||
-RunLevel Limited
|
||||
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal
|
||||
Register-ScheduledTask -TaskName $taskName -InputObject $task -Force | Out-Null
|
||||
}
|
||||
else {
|
||||
$credential = Get-Credential `
|
||||
-UserName $CollectorAccount `
|
||||
-Message "Kennwort fuer das dedizierte BizTalk-Monitoringkonto eingeben"
|
||||
if ($credential.UserName -ne $CollectorAccount) {
|
||||
throw "Das eingegebene Konto stimmt nicht mit CollectorAccount ueberein."
|
||||
}
|
||||
|
||||
$principal = New-ScheduledTaskPrincipal `
|
||||
-UserId $CollectorAccount `
|
||||
-LogonType Password `
|
||||
-RunLevel Limited
|
||||
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal
|
||||
Register-ScheduledTask `
|
||||
-TaskName $taskName `
|
||||
-InputObject $task `
|
||||
-User $CollectorAccount `
|
||||
-Password $credential.GetNetworkCredential().Password `
|
||||
-Force | Out-Null
|
||||
}
|
||||
|
||||
Write-Host "Fuehre formatseitigen Self-Test aus ..."
|
||||
$selfTest = & $targetExe --self-test
|
||||
if ($LASTEXITCODE -ne 0 -or @($selfTest).Count -ne 9) {
|
||||
throw "Self-Test fehlgeschlagen. Erwartet wurden neun Checkmk-Zeilen."
|
||||
}
|
||||
|
||||
Write-Host "Starte den Provider einmalig ..."
|
||||
Start-ScheduledTask -TaskName $taskName
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Installation abgeschlossen."
|
||||
Write-Host "Naechste Pruefungen:"
|
||||
Write-Host " Get-ScheduledTaskInfo -TaskName '$taskName'"
|
||||
Write-Host " Get-Content '$logDirectory\biztalk-checkmk-pulse-*.log' -Tail 50"
|
||||
Write-Host " & '$targetExe' --consume"
|
||||
Write-Host " & 'C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe' dump"
|
||||
@@ -1,30 +0,0 @@
|
||||
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "High")]
|
||||
param(
|
||||
[string]$InstallDirectory = "$env:ProgramFiles\BizTalkCheckmkPulse",
|
||||
[string]$CheckmkLocalDirectory = "$env:ProgramData\checkmk\agent\local",
|
||||
[switch]$KeepRuntimeData
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$taskName = "BizTalk Checkmk Pulse Provider"
|
||||
$runtimeRoot = Join-Path $env:ProgramData "BizTalkCheckmkPulse"
|
||||
$wrapper = Join-Path $CheckmkLocalDirectory "biztalk_checkmk_pulse.cmd"
|
||||
|
||||
if ($PSCmdlet.ShouldProcess($taskName, "Scheduled Task entfernen")) {
|
||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
}
|
||||
if (Test-Path -LiteralPath $wrapper) {
|
||||
if ($PSCmdlet.ShouldProcess($wrapper, "Checkmk Local Check entfernen")) {
|
||||
Remove-Item -LiteralPath $wrapper -Force
|
||||
}
|
||||
}
|
||||
if (Test-Path -LiteralPath $InstallDirectory) {
|
||||
if ($PSCmdlet.ShouldProcess($InstallDirectory, "Programmdateien entfernen")) {
|
||||
Remove-Item -LiteralPath $InstallDirectory -Recurse -Force
|
||||
}
|
||||
}
|
||||
if (-not $KeepRuntimeData -and (Test-Path -LiteralPath $runtimeRoot)) {
|
||||
if ($PSCmdlet.ShouldProcess($runtimeRoot, "Snapshot und Logs entfernen")) {
|
||||
Remove-Item -LiteralPath $runtimeRoot -Recurse -Force
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ set "BASE=%ProgramFiles%\BizTalkCheckmkPulse"
|
||||
set "EXE=%BASE%\BizTalkCheckmkPulse.exe"
|
||||
|
||||
if not exist "%EXE%" (
|
||||
echo 3 "BizTalk Platform" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Install-BizTalkCheckmkPulse.ps1 erneut als Administrator ausfuehren und danach cmk-agent-ctl.exe dump erneut ausfuehren.
|
||||
echo 3 "BizTalk Platform" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Setup.exe erneut als Administrator ausfuehren und danach cmk-agent-ctl.exe dump erneut ausfuehren.
|
||||
echo 3 "BizTalk SQL Access" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
echo 3 "BizTalk Suspended Instances" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
echo 3 "BizTalk Host Instances" - BizTalkCheckmkPulse.exe fehlt unter %BASE%. Massnahme: Deployment-Paket und Dateirechte pruefen.
|
||||
|
||||
@@ -37,15 +37,10 @@ Bevorzugte Rolle fuer BizTalk Server 2020:
|
||||
BizTalk Server Read Only Users
|
||||
SQL-Datenbankrolle: BTS_READONLY_USERS
|
||||
|
||||
Die exakt konfigurierte Gruppe mit einem bereits berechtigten Konto ermitteln:
|
||||
|
||||
Get-CimInstance -Namespace root/MicrosoftBizTalkServer `
|
||||
-ClassName MSBTS_GroupSetting |
|
||||
Select-Object Name, BizTalkReadOnlyUserGroup, BizTalkOperatorGroup,
|
||||
MgmtDbServerName, MgmtDbName
|
||||
|
||||
Das Provider-Konto durch AD-Administration in BizTalkReadOnlyUserGroup
|
||||
aufnehmen. Nicht vom Standardnamen ausgehen.
|
||||
Die exakt konfigurierte Gruppe in den Eigenschaften der BizTalk-Gruppe in der
|
||||
BizTalk Administration Console ablesen. Das Provider-Konto durch
|
||||
AD-Administration in BizTalkReadOnlyUserGroup aufnehmen. Nicht vom
|
||||
Standardnamen ausgehen.
|
||||
|
||||
Die Operator-Gruppe ist nur eine begruendungspflichtige Eskalation, falls eine
|
||||
konkret benoetigte WMI-Klasse trotz bestaetigter Read-Only-Zuordnung und neuem
|
||||
@@ -64,28 +59,19 @@ NICHT DURCHFUEHREN
|
||||
INSTALLATION
|
||||
============
|
||||
|
||||
Normales Servicekonto:
|
||||
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk' `
|
||||
-EnvironmentName ACC
|
||||
BizTalkCheckmkPulse-Setup.zip vollstaendig entpacken und Setup.exe als
|
||||
Administrator starten. Konto im Format DOMAIN\Benutzer (zum Beispiel
|
||||
BEW\t231bizmon), Kennwort und Umgebung eingeben. PowerShell wird nicht
|
||||
benoetigt.
|
||||
|
||||
VERIFIKATION
|
||||
============
|
||||
|
||||
Get-ScheduledTaskInfo -TaskName 'BizTalk Checkmk Pulse Provider'
|
||||
|
||||
Get-Content `
|
||||
"$env:ProgramData\BizTalkCheckmkPulse\logs\*.log" `
|
||||
-Tail 100
|
||||
|
||||
Get-Item `
|
||||
"$env:ProgramData\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot"
|
||||
|
||||
& "$env:ProgramFiles\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume
|
||||
|
||||
& "C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump |
|
||||
Select-String -Pattern "BizTalk|UNKNOWN|Permission|snapshot" -Context 0,1
|
||||
schtasks.exe /query /tn "BizTalk Checkmk Pulse Provider" /v /fo list
|
||||
dir "%ProgramData%\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot"
|
||||
type "%ProgramData%\BizTalkCheckmkPulse\logs\biztalk-checkmk-pulse-*.log"
|
||||
"%ProgramFiles%\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume
|
||||
"C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump
|
||||
|
||||
ERWARTET
|
||||
========
|
||||
|
||||
+13
-17
@@ -15,13 +15,10 @@ Provider-Konto und publiziert einen validierbaren Snapshot.
|
||||
|
||||
## Installation
|
||||
|
||||
Normales Servicekonto:
|
||||
|
||||
```powershell
|
||||
.\Install-BizTalkCheckmkPulse.ps1 `
|
||||
-CollectorAccount 'BEW\svc_biztalk_cmk' `
|
||||
-EnvironmentName ACC
|
||||
```
|
||||
`BizTalkCheckmkPulse-Setup.zip` vollstaendig entpacken, `Setup.exe` als
|
||||
Administrator starten und Konto, Kennwort sowie Umgebung eingeben. Konten wie
|
||||
`BEW\t231bizmon` werden direkt im Windows-Format `DOMAIN\Benutzer` verarbeitet.
|
||||
Der Installer benoetigt keine PowerShell.
|
||||
|
||||
Der Installer legt den Local Check hier ab:
|
||||
|
||||
@@ -44,15 +41,14 @@ Verzoegerung zum minuetlichen Provider.
|
||||
|
||||
Aktive Agentkonfiguration pruefen:
|
||||
|
||||
```powershell
|
||||
& "C:\Program Files (x86)\checkmk\service\check_mk_agent.exe" showconfig local
|
||||
```cmd
|
||||
"C:\Program Files (x86)\checkmk\service\check_mk_agent.exe" showconfig local
|
||||
```
|
||||
|
||||
Verbindlicher Agent-Dump:
|
||||
|
||||
```powershell
|
||||
& "C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump |
|
||||
Select-String -Pattern "BizTalk|UNKNOWN|snapshot|Permission" -Context 0,1
|
||||
```cmd
|
||||
"C:\Program Files (x86)\checkmk\service\cmk-agent-ctl.exe" dump
|
||||
```
|
||||
|
||||
## Service Discovery
|
||||
@@ -95,11 +91,11 @@ Installationsautomation die klarere Variante.
|
||||
|
||||
## Healthchecks
|
||||
|
||||
```powershell
|
||||
Get-ScheduledTaskInfo -TaskName 'BizTalk Checkmk Pulse Provider'
|
||||
Get-Item "$env:ProgramData\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot"
|
||||
Get-Content "$env:ProgramData\BizTalkCheckmkPulse\logs\*.log" -Tail 50
|
||||
& "$env:ProgramFiles\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume
|
||||
```cmd
|
||||
schtasks.exe /query /tn "BizTalk Checkmk Pulse Provider" /v /fo list
|
||||
dir "%ProgramData%\BizTalkCheckmkPulse\data\biztalk-checkmk-pulse.snapshot"
|
||||
type "%ProgramData%\BizTalkCheckmkPulse\logs\biztalk-checkmk-pulse-*.log"
|
||||
"%ProgramFiles%\BizTalkCheckmkPulse\BizTalkCheckmkPulse.exe" --consume
|
||||
```
|
||||
|
||||
Soll:
|
||||
|
||||
@@ -7,5 +7,5 @@ if errorlevel 1 (
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
msbuild BizTalkCheckmkPulse.sln /p:Configuration=Release /p:Platform="Any CPU" /m:1 /v:minimal
|
||||
msbuild "%~dp0..\BizTalkCheckmkPulse.sln" /p:Configuration=Release /p:Platform="Any CPU" /m:1 /v:minimal
|
||||
exit /b %ERRORLEVEL%
|
||||
|
||||
@@ -4,18 +4,6 @@ setlocal
|
||||
call "%~dp0build-release.cmd"
|
||||
if errorlevel 1 exit /b 1
|
||||
|
||||
set "ROOT=%~dp0.."
|
||||
set "OUT=%ROOT%\artifacts\BizTalkCheckmkPulse-deploy"
|
||||
set "APP=%OUT%\application"
|
||||
|
||||
if exist "%OUT%" rmdir /s /q "%OUT%"
|
||||
mkdir "%APP%"
|
||||
|
||||
copy "%ROOT%\deployment\checkmk\biztalk_checkmk_pulse.cmd" "%OUT%\" >nul
|
||||
copy "%ROOT%\deployment\Install-BizTalkCheckmkPulse.ps1" "%OUT%\" >nul
|
||||
copy "%ROOT%\deployment\Uninstall-BizTalkCheckmkPulse.ps1" "%OUT%\" >nul
|
||||
copy "%ROOT%\src\BizTalkCheckmkPulse\bin\Release\BizTalkCheckmkPulse.exe" "%APP%\" >nul
|
||||
copy "%ROOT%\src\BizTalkCheckmkPulse\bin\Release\BizTalkCheckmkPulse.exe.config" "%APP%\" >nul
|
||||
|
||||
echo Deployment package written to %OUT%
|
||||
echo Install package written to artifacts\BizTalkCheckmkPulse-Setup
|
||||
echo Install ZIP written to artifacts\BizTalkCheckmkPulse-Setup.zip
|
||||
exit /b 0
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" Condition="false" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{B35A04E0-253B-4CEB-9033-F5109F3B9F82}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>BizTalkCheckmkPulse.Packager</RootNamespace>
|
||||
<AssemblyName>BizTalkCheckmkPulse.Packager</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BizTalkCheckmkPulse\BizTalkCheckmkPulse.csproj">
|
||||
<Project>{A4D4D050-9EA7-4A71-B510-7D9D699B9F38}</Project>
|
||||
<Name>BizTalkCheckmkPulse</Name>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\BizTalkCheckmkPulse.Setup\BizTalkCheckmkPulse.Setup.csproj">
|
||||
<Project>{764AC43A-26D8-43C1-9121-13FC8A9CC8B1}</Project>
|
||||
<Name>BizTalkCheckmkPulse.Setup</Name>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="CreateInstallPackage" AfterTargets="Build" Condition=" '$(Configuration)' == 'Release' ">
|
||||
<Exec Command=""$(TargetPath)" "$(MSBuildProjectDirectory)\..\.." "$(Configuration)"" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace BizTalkCheckmkPulse.Packager
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static int Main(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (args.Length != 2) throw new ArgumentException("Usage: BizTalkCheckmkPulse.Packager.exe <repository-root> <configuration>");
|
||||
var root = Path.GetFullPath(args[0]);
|
||||
var configuration = args[1];
|
||||
var artifacts = Path.Combine(root, "artifacts");
|
||||
var package = Path.Combine(artifacts, "BizTalkCheckmkPulse-Setup");
|
||||
var application = Path.Combine(package, "application");
|
||||
var zip = Path.Combine(artifacts, "BizTalkCheckmkPulse-Setup.zip");
|
||||
|
||||
if (Directory.Exists(package)) Directory.Delete(package, true);
|
||||
Directory.CreateDirectory(application);
|
||||
|
||||
Copy(
|
||||
Path.Combine(root, "src", "BizTalkCheckmkPulse.Setup", "bin", configuration, "BizTalkCheckmkPulse.Setup.exe"),
|
||||
Path.Combine(package, "Setup.exe"));
|
||||
Copy(
|
||||
Path.Combine(root, "src", "BizTalkCheckmkPulse", "bin", configuration, "BizTalkCheckmkPulse.exe"),
|
||||
Path.Combine(application, "BizTalkCheckmkPulse.exe"));
|
||||
Copy(
|
||||
Path.Combine(root, "src", "BizTalkCheckmkPulse", "bin", configuration, "BizTalkCheckmkPulse.exe.config"),
|
||||
Path.Combine(application, "BizTalkCheckmkPulse.exe.config"));
|
||||
Copy(
|
||||
Path.Combine(root, "deployment", "checkmk", "biztalk_checkmk_pulse.cmd"),
|
||||
Path.Combine(package, "biztalk_checkmk_pulse.cmd"));
|
||||
Copy(
|
||||
Path.Combine(root, "deployment", "INSTALLATION.md"),
|
||||
Path.Combine(package, "INSTALLATION.md"));
|
||||
|
||||
if (File.Exists(zip)) File.Delete(zip);
|
||||
ZipFile.CreateFromDirectory(package, zip, CompressionLevel.Optimal, false);
|
||||
Console.WriteLine("Install package: " + package);
|
||||
Console.WriteLine("Install ZIP: " + zip);
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Error.WriteLine("Packaging failed: " + ex.Message);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void Copy(string source, string target)
|
||||
{
|
||||
if (!File.Exists(source)) throw new FileNotFoundException("Required package file missing: " + source, source);
|
||||
File.Copy(source, target, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" Condition="false" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{764AC43A-26D8-43C1-9121-13FC8A9CC8B1}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>BizTalkCheckmkPulse.Setup</RootNamespace>
|
||||
<AssemblyName>BizTalkCheckmkPulse.Setup</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Security" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="InstallerEngine.cs" />
|
||||
<Compile Include="MainForm.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="TaskSchedulerService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.manifest" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
using System.Xml;
|
||||
|
||||
namespace BizTalkCheckmkPulse.Setup
|
||||
{
|
||||
internal sealed class InstallerEngine
|
||||
{
|
||||
internal const string TaskName = "BizTalk Checkmk Pulse Provider";
|
||||
private readonly string packageDirectory;
|
||||
private readonly string installDirectory;
|
||||
private readonly string runtimeDirectory;
|
||||
private readonly string checkmkLocalDirectory;
|
||||
|
||||
public InstallerEngine(string packageDirectory)
|
||||
{
|
||||
this.packageDirectory = Path.GetFullPath(packageDirectory);
|
||||
installDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "BizTalkCheckmkPulse");
|
||||
runtimeDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "BizTalkCheckmkPulse");
|
||||
checkmkLocalDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "checkmk", "agent", "local");
|
||||
}
|
||||
|
||||
public void Install(string account, string password, bool isGmsa, string environmentName, Action<string> report)
|
||||
{
|
||||
Validate(account, password, isGmsa, environmentName);
|
||||
var accountSid = (SecurityIdentifier)new NTAccount(account).Translate(typeof(SecurityIdentifier));
|
||||
report("Konto aufgeloest: " + account + " (" + accountSid.Value + ")");
|
||||
|
||||
var sourceApplication = Path.Combine(packageDirectory, "application");
|
||||
var sourceExe = Path.Combine(sourceApplication, "BizTalkCheckmkPulse.exe");
|
||||
var sourceConfig = sourceExe + ".config";
|
||||
var sourceWrapper = Path.Combine(packageDirectory, "biztalk_checkmk_pulse.cmd");
|
||||
RequireFile(sourceExe);
|
||||
RequireFile(sourceConfig);
|
||||
RequireFile(sourceWrapper);
|
||||
|
||||
// Ein laufender Provider kann die installierte EXE waehrend eines Updates sperren.
|
||||
new TaskSchedulerService().DeleteIfExists(TaskName);
|
||||
report("Vorhandener Scheduled Task angehalten beziehungsweise fuer das Update entfernt.");
|
||||
|
||||
Directory.CreateDirectory(installDirectory);
|
||||
var targetExe = Path.Combine(installDirectory, "BizTalkCheckmkPulse.exe");
|
||||
var targetConfig = targetExe + ".config";
|
||||
File.Copy(sourceExe, targetExe, true);
|
||||
File.Copy(sourceConfig, targetConfig, true);
|
||||
SetEnvironment(targetConfig, environmentName);
|
||||
report("Programmdateien installiert: " + installDirectory);
|
||||
|
||||
var dataDirectory = Path.Combine(runtimeDirectory, "data");
|
||||
var logDirectory = Path.Combine(runtimeDirectory, "logs");
|
||||
Directory.CreateDirectory(runtimeDirectory);
|
||||
Directory.CreateDirectory(dataDirectory);
|
||||
Directory.CreateDirectory(logDirectory);
|
||||
|
||||
ApplyDirectoryAcl(installDirectory, accountSid, FileSystemRights.ReadAndExecute, FileSystemRights.ReadAndExecute);
|
||||
ApplyDirectoryAcl(runtimeDirectory, accountSid, FileSystemRights.ReadAndExecute, FileSystemRights.ReadAndExecute);
|
||||
ApplyDirectoryAcl(dataDirectory, accountSid, FileSystemRights.Modify, FileSystemRights.ReadAndExecute);
|
||||
ApplyDirectoryAcl(logDirectory, accountSid, FileSystemRights.Modify, FileSystemRights.Modify);
|
||||
report("Least-Privilege-Verzeichnisrechte gesetzt.");
|
||||
|
||||
Directory.CreateDirectory(checkmkLocalDirectory);
|
||||
File.Copy(sourceWrapper, Path.Combine(checkmkLocalDirectory, "biztalk_checkmk_pulse.cmd"), true);
|
||||
report("Checkmk Local Check installiert: " + checkmkLocalDirectory);
|
||||
|
||||
RunSelfTest(targetExe);
|
||||
report("Self-Test erfolgreich: acht Checkmk-Services.");
|
||||
|
||||
new TaskSchedulerService().RegisterAndStart(
|
||||
TaskName,
|
||||
targetExe,
|
||||
installDirectory,
|
||||
account,
|
||||
isGmsa ? null : password,
|
||||
isGmsa);
|
||||
report("Scheduled Task registriert: " + TaskName);
|
||||
}
|
||||
|
||||
public void Uninstall(bool keepRuntimeData, Action<string> report)
|
||||
{
|
||||
new TaskSchedulerService().DeleteIfExists(TaskName);
|
||||
report("Scheduled Task entfernt.");
|
||||
|
||||
var wrapper = Path.Combine(checkmkLocalDirectory, "biztalk_checkmk_pulse.cmd");
|
||||
if (File.Exists(wrapper)) File.Delete(wrapper);
|
||||
if (Directory.Exists(installDirectory)) Directory.Delete(installDirectory, true);
|
||||
if (!keepRuntimeData && Directory.Exists(runtimeDirectory)) Directory.Delete(runtimeDirectory, true);
|
||||
}
|
||||
|
||||
private static void Validate(string account, string password, bool isGmsa, string environmentName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(account)) throw new ArgumentException("Collector-Konto fehlt.");
|
||||
if (account.IndexOf('\\') <= 0 || account.EndsWith("\\", StringComparison.Ordinal))
|
||||
throw new ArgumentException(@"Collector-Konto im Format DOMAIN\Benutzer eingeben, z.B. BEW\t231bizmon.");
|
||||
if (isGmsa && !account.EndsWith("$", StringComparison.Ordinal))
|
||||
throw new ArgumentException(@"Ein gMSA-Konto muss mit '$' enden, z.B. BEW\svc_biztalk_cmk$.");
|
||||
if (!isGmsa && string.IsNullOrEmpty(password)) throw new ArgumentException("Kennwort fehlt.");
|
||||
if (!new[] { "", "ACC", "DEV", "TST", "PRD" }.Contains(environmentName))
|
||||
throw new ArgumentException("Ungueltige Umgebung.");
|
||||
}
|
||||
|
||||
private static void RequireFile(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
throw new FileNotFoundException("Installationspaket ist unvollstaendig. Datei fehlt: " + path, path);
|
||||
}
|
||||
|
||||
private static void SetEnvironment(string configPath, string environmentName)
|
||||
{
|
||||
var document = new XmlDocument { PreserveWhitespace = true };
|
||||
document.Load(configPath);
|
||||
var setting = document.SelectSingleNode("/configuration/appSettings/add[@key='EnvironmentName']") as XmlElement;
|
||||
if (setting == null) throw new InvalidDataException("EnvironmentName fehlt in " + configPath + ".");
|
||||
setting.SetAttribute("value", environmentName);
|
||||
document.Save(configPath);
|
||||
}
|
||||
|
||||
private static void ApplyDirectoryAcl(
|
||||
string path,
|
||||
SecurityIdentifier collectorSid,
|
||||
FileSystemRights collectorRights,
|
||||
FileSystemRights systemRights)
|
||||
{
|
||||
var inheritance = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
|
||||
var security = new DirectorySecurity();
|
||||
security.SetAccessRuleProtection(true, false);
|
||||
security.AddAccessRule(new FileSystemAccessRule(
|
||||
new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null),
|
||||
FileSystemRights.FullControl,
|
||||
inheritance,
|
||||
PropagationFlags.None,
|
||||
AccessControlType.Allow));
|
||||
security.AddAccessRule(new FileSystemAccessRule(
|
||||
new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null),
|
||||
systemRights,
|
||||
inheritance,
|
||||
PropagationFlags.None,
|
||||
AccessControlType.Allow));
|
||||
security.AddAccessRule(new FileSystemAccessRule(
|
||||
collectorSid,
|
||||
collectorRights,
|
||||
inheritance,
|
||||
PropagationFlags.None,
|
||||
AccessControlType.Allow));
|
||||
new DirectoryInfo(path).SetAccessControl(security);
|
||||
}
|
||||
|
||||
private static void RunSelfTest(string executable)
|
||||
{
|
||||
var start = new ProcessStartInfo(executable, "--self-test")
|
||||
{
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
};
|
||||
using (var process = Process.Start(start))
|
||||
{
|
||||
if (process == null) throw new InvalidOperationException("Self-Test konnte nicht gestartet werden.");
|
||||
var output = process.StandardOutput.ReadToEnd();
|
||||
var error = process.StandardError.ReadToEnd();
|
||||
if (!process.WaitForExit(30000))
|
||||
{
|
||||
process.Kill();
|
||||
throw new InvalidOperationException("Self-Test hat das Zeitlimit ueberschritten.");
|
||||
}
|
||||
var lines = output.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (process.ExitCode != 0 || lines.Length != 8 || lines.Any(x => !x.StartsWith("0 ", StringComparison.Ordinal)))
|
||||
throw new InvalidOperationException("Self-Test fehlgeschlagen. Exitcode=" + process.ExitCode + ", Zeilen=" + lines.Length + ". " + error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BizTalkCheckmkPulse.Setup
|
||||
{
|
||||
internal sealed class MainForm : Form
|
||||
{
|
||||
private readonly InstallerEngine engine;
|
||||
private readonly TextBox account = new TextBox();
|
||||
private readonly TextBox password = new TextBox();
|
||||
private readonly ComboBox environment = new ComboBox();
|
||||
private readonly CheckBox gmsa = new CheckBox();
|
||||
private readonly Button install = new Button();
|
||||
private readonly Button uninstall = new Button();
|
||||
private readonly TextBox status = new TextBox();
|
||||
|
||||
public MainForm(InstallerEngine engine)
|
||||
{
|
||||
this.engine = engine;
|
||||
Text = "BizTalk Checkmk Pulse Setup";
|
||||
ClientSize = new Size(650, 485);
|
||||
MinimumSize = new Size(666, 524);
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Font = new Font("Segoe UI", 9F);
|
||||
|
||||
var title = new Label
|
||||
{
|
||||
AutoSize = true,
|
||||
Font = new Font(Font.FontFamily, 15F, FontStyle.Bold),
|
||||
Location = new Point(20, 18),
|
||||
Text = "BizTalk Checkmk Pulse installieren"
|
||||
};
|
||||
var description = new Label
|
||||
{
|
||||
AutoSize = false,
|
||||
Location = new Point(22, 58),
|
||||
Size = new Size(605, 48),
|
||||
Text = "Installiert Anwendung, Checkmk Local Check, sichere Verzeichnisrechte und den minuetlichen Scheduled Task. PowerShell wird nicht verwendet."
|
||||
};
|
||||
|
||||
AddLabel("Collector-Konto", 22, 120);
|
||||
account.Location = new Point(190, 116);
|
||||
account.Size = new Size(420, 23);
|
||||
account.Text = @"BEW\t231bizmon";
|
||||
|
||||
AddLabel("Kennwort", 22, 158);
|
||||
password.Location = new Point(190, 154);
|
||||
password.Size = new Size(420, 23);
|
||||
password.UseSystemPasswordChar = true;
|
||||
|
||||
AddLabel("Umgebung", 22, 196);
|
||||
environment.Location = new Point(190, 192);
|
||||
environment.Size = new Size(160, 23);
|
||||
environment.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
environment.Items.AddRange(new object[] { "(keine)", "ACC", "DEV", "TST", "PRD" });
|
||||
environment.SelectedIndex = 0;
|
||||
|
||||
gmsa.Location = new Point(190, 229);
|
||||
gmsa.Size = new Size(420, 24);
|
||||
gmsa.Text = "Konto ist ein gMSA (kein Kennwort erforderlich)";
|
||||
gmsa.CheckedChanged += delegate
|
||||
{
|
||||
password.Enabled = !gmsa.Checked;
|
||||
if (gmsa.Checked) password.Clear();
|
||||
};
|
||||
|
||||
install.Location = new Point(190, 267);
|
||||
install.Size = new Size(200, 34);
|
||||
install.Text = "Installieren / aktualisieren";
|
||||
install.Click += async delegate { await InstallAsync(); };
|
||||
|
||||
uninstall.Location = new Point(410, 267);
|
||||
uninstall.Size = new Size(200, 34);
|
||||
uninstall.Text = "Deinstallieren";
|
||||
uninstall.Click += async delegate { await UninstallAsync(); };
|
||||
|
||||
status.Location = new Point(22, 320);
|
||||
status.Size = new Size(588, 135);
|
||||
status.Multiline = true;
|
||||
status.ReadOnly = true;
|
||||
status.ScrollBars = ScrollBars.Vertical;
|
||||
status.Text = "Bereit. Setup.exe muss aus dem vollstaendig entpackten Installationspaket gestartet werden.";
|
||||
|
||||
Controls.AddRange(new Control[]
|
||||
{
|
||||
title, description, account, password, environment, gmsa, install, uninstall, status
|
||||
});
|
||||
AcceptButton = install;
|
||||
}
|
||||
|
||||
private void AddLabel(string text, int left, int top)
|
||||
{
|
||||
Controls.Add(new Label { AutoSize = true, Location = new Point(left, top), Text = text });
|
||||
}
|
||||
|
||||
private async Task InstallAsync()
|
||||
{
|
||||
var collectorAccount = account.Text.Trim();
|
||||
var collectorPassword = password.Text;
|
||||
var environmentName = environment.SelectedIndex <= 0 ? string.Empty : environment.SelectedItem.ToString();
|
||||
var collectorIsGmsa = gmsa.Checked;
|
||||
|
||||
SetBusy(true, "Installation laeuft ...");
|
||||
try
|
||||
{
|
||||
await Task.Run(() => engine.Install(
|
||||
collectorAccount,
|
||||
collectorPassword,
|
||||
collectorIsGmsa,
|
||||
environmentName,
|
||||
Report));
|
||||
password.Clear();
|
||||
Report("Installation abgeschlossen. Der Provider-Task wurde einmalig gestartet.");
|
||||
MessageBox.Show(this, "Installation erfolgreich abgeschlossen.", Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
password.Clear();
|
||||
Report("FEHLER: " + ex.Message);
|
||||
MessageBox.Show(this, ex.Message, "Installation fehlgeschlagen", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SetBusy(false, null);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UninstallAsync()
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
this,
|
||||
"Scheduled Task, Checkmk-Wrapper und Programmdateien entfernen? Snapshot und Logs bleiben erhalten.",
|
||||
"Deinstallation bestaetigen",
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Warning);
|
||||
if (result != DialogResult.Yes) return;
|
||||
|
||||
SetBusy(true, "Deinstallation laeuft ...");
|
||||
try
|
||||
{
|
||||
await Task.Run(() => engine.Uninstall(true, Report));
|
||||
Report("Deinstallation abgeschlossen. Runtime-Daten wurden beibehalten.");
|
||||
MessageBox.Show(this, "Deinstallation erfolgreich abgeschlossen.", Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Report("FEHLER: " + ex.Message);
|
||||
MessageBox.Show(this, ex.Message, "Deinstallation fehlgeschlagen", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SetBusy(false, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetBusy(bool busy, string message)
|
||||
{
|
||||
install.Enabled = !busy;
|
||||
uninstall.Enabled = !busy;
|
||||
account.Enabled = !busy;
|
||||
environment.Enabled = !busy;
|
||||
gmsa.Enabled = !busy;
|
||||
password.Enabled = !busy && !gmsa.Checked;
|
||||
UseWaitCursor = busy;
|
||||
if (message != null) Report(message);
|
||||
}
|
||||
|
||||
private void Report(string message)
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
BeginInvoke(new Action<string>(Report), message);
|
||||
return;
|
||||
}
|
||||
|
||||
status.AppendText(Environment.NewLine + DateTime.Now.ToString("HH:mm:ss") + " " + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BizTalkCheckmkPulse.Setup
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
[STAThread]
|
||||
private static void Main()
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new MainForm(new InstallerEngine(AppDomain.CurrentDomain.BaseDirectory)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizTalkCheckmkPulse.Setup
|
||||
{
|
||||
internal sealed class TaskSchedulerService
|
||||
{
|
||||
private const int TaskCreateOrUpdate = 6;
|
||||
private const int TaskLogonPassword = 1;
|
||||
private const int TaskTriggerTime = 1;
|
||||
private const int TaskActionExecute = 0;
|
||||
private const int TaskInstancesIgnoreNew = 2;
|
||||
|
||||
public void RegisterAndStart(
|
||||
string taskName,
|
||||
string executable,
|
||||
string workingDirectory,
|
||||
string account,
|
||||
string password,
|
||||
bool isGmsa)
|
||||
{
|
||||
dynamic service = null;
|
||||
dynamic root = null;
|
||||
dynamic definition = null;
|
||||
dynamic registeredTask = null;
|
||||
try
|
||||
{
|
||||
var schedulerType = Type.GetTypeFromProgID("Schedule.Service", true);
|
||||
service = Activator.CreateInstance(schedulerType);
|
||||
service.Connect();
|
||||
root = service.GetFolder("\\");
|
||||
definition = service.NewTask(0);
|
||||
|
||||
definition.RegistrationInfo.Description = "Collects BizTalk monitoring data for the Checkmk local check.";
|
||||
definition.Principal.UserId = account;
|
||||
// Auch gMSA werden als Password-Logon registriert. Nur das Kennwort
|
||||
// bleibt leer; TASK_LOGON_SERVICE_ACCOUNT ist ausschliesslich fuer
|
||||
// LocalSystem, LocalService und NetworkService vorgesehen.
|
||||
definition.Principal.LogonType = TaskLogonPassword;
|
||||
definition.Principal.RunLevel = 0;
|
||||
|
||||
definition.Settings.Enabled = true;
|
||||
definition.Settings.StartWhenAvailable = true;
|
||||
definition.Settings.MultipleInstances = TaskInstancesIgnoreNew;
|
||||
definition.Settings.ExecutionTimeLimit = "PT5M";
|
||||
definition.Settings.RestartCount = 2;
|
||||
definition.Settings.RestartInterval = "PT1M";
|
||||
definition.Settings.DisallowStartIfOnBatteries = false;
|
||||
definition.Settings.StopIfGoingOnBatteries = false;
|
||||
|
||||
dynamic trigger = definition.Triggers.Create(TaskTriggerTime);
|
||||
trigger.StartBoundary = DateTime.Now.AddMinutes(1).ToString("s");
|
||||
trigger.Enabled = true;
|
||||
trigger.Repetition.Interval = "PT1M";
|
||||
|
||||
dynamic action = definition.Actions.Create(TaskActionExecute);
|
||||
action.Path = executable;
|
||||
action.Arguments = "--collect";
|
||||
action.WorkingDirectory = workingDirectory;
|
||||
|
||||
registeredTask = root.RegisterTaskDefinition(
|
||||
taskName,
|
||||
definition,
|
||||
TaskCreateOrUpdate,
|
||||
account,
|
||||
isGmsa ? null : password,
|
||||
TaskLogonPassword,
|
||||
null);
|
||||
registeredTask.Run(null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Release(registeredTask);
|
||||
Release(definition);
|
||||
Release(root);
|
||||
Release(service);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteIfExists(string taskName)
|
||||
{
|
||||
dynamic service = null;
|
||||
dynamic root = null;
|
||||
dynamic task = null;
|
||||
try
|
||||
{
|
||||
var schedulerType = Type.GetTypeFromProgID("Schedule.Service", true);
|
||||
service = Activator.CreateInstance(schedulerType);
|
||||
service.Connect();
|
||||
root = service.GetFolder("\\");
|
||||
try
|
||||
{
|
||||
task = root.GetTask(taskName);
|
||||
try
|
||||
{
|
||||
task.Stop(0);
|
||||
}
|
||||
catch (COMException)
|
||||
{
|
||||
// Ein nicht laufender Task muss vor dem Loeschen nicht gestoppt werden.
|
||||
}
|
||||
root.DeleteTask(taskName, 0);
|
||||
}
|
||||
catch (COMException ex)
|
||||
{
|
||||
const int FileNotFound = unchecked((int)0x80070002);
|
||||
if (ex.ErrorCode != FileNotFound) throw;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Release(task);
|
||||
Release(root);
|
||||
Release(service);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Release(object value)
|
||||
{
|
||||
if (value != null && Marshal.IsComObject(value)) Marshal.FinalReleaseComObject(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="BizTalkCheckmkPulse.Setup" />
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
Reference in New Issue
Block a user