Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #region Configuration
- $ConfigPath = "C:\Program Files (x86)\ScreenConnect\web.config"
- $LogPath = "C:\Logs\ScreenConnect-MachineKeyRotation"
- $LogFile = "$LogPath\KeyRotation_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
- $DisableOutOfHours = $true
- $OutofHoursStart = 20 # 8pm
- $OutofHoursEnd = 8 # 8am
- #region Logging Function
- function Write-Log {
- param (
- [string]$Message,
- [ValidateSet("INFO", "WARN", "ERROR", "SUCCESS")]
- [string]$Level = "INFO"
- )
- $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
- $LogEntry = "[$Timestamp] [$Level] $Message"
- # Write to screen with colour
- switch ($Level) {
- "INFO" { Write-Host $LogEntry -ForegroundColor Cyan }
- "WARN" { Write-Host $LogEntry -ForegroundColor Yellow }
- "ERROR" { Write-Host $LogEntry -ForegroundColor Red }
- "SUCCESS" { Write-Host $LogEntry -ForegroundColor Green }
- }
- # Write to log file
- Add-Content -Path $LogFile -Value $LogEntry
- }
- #endregion
- #region Ensure Log Directory Exists
- if (-not (Test-Path $LogPath)) {
- New-Item -ItemType Directory -Path $LogPath -Force | Out-Null
- Write-Log "Created log directory: $LogPath"
- }
- #endregion
- # Check if $DisableOutOfHours is enabled and the current time is outside business hours. If so shutdown (and disable) the SC services and exit gracefully.
- $currentHour = (Get-Date).Hour
- $services = Get-Service -Name "ScreenConnect*"
- if ($DisableOutOfHours -and ($currentHour -ge $OutofHoursStart -or $currentHour -lt $OutofHoursEnd)) {
- Write-Log "Out of hours detected. Stopping ScreenConnect services."
- Write-Host "Out of hours detected. Stopping ScreenConnect services."
- foreach ($svc in $services) {
- if ($svc.Status -ne "Stopped") {
- Write-Log "Stopping service: $svc.Name"
- Stop-Service -Name $svc.Name -Force
- }
- Write-Log "Disabling service: $svc.Name"
- Set-Service -Name $svc.Name -StartupType Disabled
- }
- return
- }
- else {
- Write-Log "Business hours detected. Ensuring ScreenConnect services are running."
- Write-Host "Business hours detected. Ensuring ScreenConnect services are running."
- foreach ($svc in $services) {
- Write-Log "Enabling service: $svc.Name"
- Set-Service -Name $svc.Name -StartupType Automatic
- if ($svc.Status -ne "Running") {
- Write-Log "Starting service: $svc.Name"
- Start-Service -Name $svc.Name
- }
- }
- }
- # If not out of business hours, start the rotation process, which will also stop and start the services as part of the procedure.
- Write-Log "=========================================="
- Write-Log " ScreenConnect MachineKey Rotation Start"
- Write-Log "=========================================="
- Write-Log "Config path: $ConfigPath"
- Write-Log "Log file: $LogFile"
- function Generate-MachineKey {
- [CmdletBinding()]
- param (
- [ValidateSet("AES", "DES", "3DES")]
- [string]$DecryptionAlgorithm = "AES",
- [ValidateSet("HMACSHA256", "HMACSHA384", "HMACSHA512")]
- [string]$ValidationAlgorithm = "HMACSHA256"
- )
- function Convert-BytesToHex {
- param ([byte[]]$Bytes)
- $builder = New-Object System.Text.StringBuilder
- foreach ($b in $Bytes) {
- [void]$builder.AppendFormat("{0:X2}", $b)
- }
- return $builder.ToString()
- }
- #region Decryption Key
- switch ($DecryptionAlgorithm) {
- "AES" { $crypto = [System.Security.Cryptography.Aes]::Create() }
- "DES" { $crypto = [System.Security.Cryptography.DES]::Create() }
- "3DES" { $crypto = [System.Security.Cryptography.TripleDES]::Create() }
- }
- $crypto.GenerateKey()
- $DecryptionKey = Convert-BytesToHex -Bytes $crypto.Key
- $crypto.Dispose()
- #endregion
- #region Validation Key
- switch ($ValidationAlgorithm) {
- "HMACSHA256" { $hmac = [System.Security.Cryptography.HMACSHA256]::new() }
- "HMACSHA384" { $hmac = [System.Security.Cryptography.HMACSHA384]::new() }
- "HMACSHA512" { $hmac = [System.Security.Cryptography.HMACSHA512]::new() }
- }
- $ValidationKey = Convert-BytesToHex -Bytes $hmac.Key
- $hmac.Dispose()
- #endregion
- return @{
- DecryptionKey = $DecryptionKey
- ValidationKey = $ValidationKey
- }
- }
- #region Read Old Keys
- Write-Log "------------------------------------------"
- Write-Log "Reading existing keys from config..."
- try {
- [xml]$xml = Get-Content $ConfigPath -ErrorAction Stop
- $machineKey = $xml.configuration.'system.web'.machineKey
- $OldValidationKey = $machineKey.validationKey
- $OldDecryptionKey = $machineKey.decryptionKey
- Write-Log "Old ValidationKey : $OldValidationKey"
- Write-Log "Old DecryptionKey : $OldDecryptionKey"
- } catch {
- Write-Log "Failed to read config file: $_" -Level "ERROR"
- exit 1
- }
- #endregion
- #region Generate New Keys
- Write-Log "------------------------------------------"
- Write-Log "Generating new machine keys..."
- try {
- $NewKeys = Generate-MachineKey
- $NewValidationKey = $NewKeys.ValidationKey
- $NewDecryptionKey = $NewKeys.DecryptionKey
- Write-Log "New ValidationKey : $NewValidationKey" -Level "SUCCESS"
- Write-Log "New DecryptionKey : $NewDecryptionKey" -Level "SUCCESS"
- } catch {
- Write-Log "Failed to generate new keys: $_" -Level "ERROR"
- exit 1
- }
- #endregion
- #region Stop Services
- Write-Log "------------------------------------------"
- Write-Log "Stopping ScreenConnect services..."
- try {
- Get-Service -Name "ScreenConnect*" | ForEach-Object {
- Write-Log "Stopping service: $($_.Name) (current status: $($_.Status))"
- }
- Get-Service -Name "ScreenConnect*" | Stop-Service -Force -ErrorAction SilentlyContinue
- Start-Sleep -Seconds 5
- while (Get-Service -Name "ScreenConnect*" | Where-Object { $_.Status -ne 'Stopped' }) {
- Write-Log "Waiting for services to stop..." -Level "WARN"
- Start-Sleep -Seconds 1
- }
- Write-Log "All ScreenConnect services stopped." -Level "SUCCESS"
- } catch {
- Write-Log "Error stopping services: $_" -Level "ERROR"
- exit 1
- }
- #endregion
- #region Update Config
- Write-Log "------------------------------------------"
- Write-Log "Updating web.config with new keys..."
- try {
- $machineKey.validationKey = $NewValidationKey
- $machineKey.decryptionKey = $NewDecryptionKey
- $xml.Save($ConfigPath)
- Write-Log "web.config saved successfully." -Level "SUCCESS"
- } catch {
- Write-Log "Failed to save web.config: $_" -Level "ERROR"
- exit 1
- }
- #endregion
- #region verfiy Config Update
- Write-Log "------------------------------------------"
- Write-Log "Verifying config update..."
- try {
- [xml]$verifyXml = Get-Content $ConfigPath -ErrorAction Stop
- $verifyMachineKey = $verifyXml.configuration.'system.web'.machineKey
- if ($verifyMachineKey.validationKey -eq $NewValidationKey -and $verifyMachineKey.decryptionKey -eq $NewDecryptionKey) {
- Write-Log "Config verification successful. Keys updated correctly." -Level "SUCCESS"
- } else {
- Write-Log "Config verification failed. Keys do not match expected values." -Level "ERROR"
- exit 1
- }
- } catch {
- Write-Log "Failed to verify config update: $_" -Level "ERROR"
- exit 1
- }
- #endregion
- #region Start Services
- Write-Log "------------------------------------------"
- Write-Log "Starting ScreenConnect services..."
- try {
- Get-Service -Name "ScreenConnect*" | Start-Service -ErrorAction SilentlyContinue
- Start-Sleep -Seconds 5
- while (Get-Service -Name "ScreenConnect*" | Where-Object { $_.Status -ne 'Running' }) {
- Write-Log "Waiting for services to start..." -Level "WARN"
- Start-Sleep -Seconds 1
- }
- Get-Service -Name "ScreenConnect*" | ForEach-Object {
- Write-Log "Service running: $($_.Name) (status: $($_.Status))" -Level "SUCCESS"
- }
- } catch {
- Write-Log "Error starting services: $_" -Level "ERROR"
- exit 1
- }
- #endregion
- Write-Log "=========================================="
- Write-Log " MachineKey rotation completed successfully"
- Write-Log "=========================================="
Advertisement