# wDayzManager v0.9 # Copyright (c) 2024 Vladislav Salikov aka W0LF aka 'dreamforce' # https://github.com/dreamforceinc # Required module: PSIni # Installation: Install-Module -Name PsIni [CmdletBinding()] Param ( [Alias("Init")] [int]$param0 = $(throw "ERROR!!! Required parameter '-Init' is missing!"), [Alias("Update")] [int]$param1 = $(throw "ERROR!!! Required parameter '-Update' is missing!") ) [bool]$init = $param0 [bool]$update = $param1 ######################################################################### [ CONFIG ] ########################################################################## [bool]$noDelete = $false # For tests - don't delete logs ################################################################ [ !!! DON'T EDIT BELOW !!! ] ################################################################# [string]$myName = "wDayzManager" [string]$myVersion = "v0.9" [string]$iniFile = $myName + ".ini" [string]$steamScript = $myName + ".txt" $Error.Clear() if (($init -eq $true) -and ($update -eq $true)) { Write-Error "Only one parameter is accepted - either 'Init' or 'Update'." Exit } function Init { New-Item -ItemType File -Path $iniFile -Value "; $($iniFile)" | Out-Null if (!$?) { Exit } $content = " [Config] serverLocation=Z:\Servers\DayzServer profilesLocation=profiles steamCMD=Z:\SteamCMD steamUser=SupaMegaGamer appidGame=221100 appidServer=223350 rotateLogs=1 daysAmount=7 becLocation=bec rotatedLogsFolderName=RotatedLogs atFolderName=VPPAdminTools ; Server updating settings: ; D = Daily - Updates are checked daily at the hours specified in parameter 'updateHour' (0 - 23). In this case, parameter 'updateDay' is ignored. ; W = Weekly - Updates are checked weekly at the hours specified in parameter 'updateHour' (0 - 23). Parameter 'updateDay' specifies the day of the week (0 - 6, 0 = Sunday). ; M = Monthly - Updates are checked monthly at the hours specified in parameter 'updateHour' (0 - 23). Parameter 'updateDay' specifies the day of the month (1 - 31. Be careful with February!). ; Any other value disables the updates. updatePeriod=W updateDay=1 updateHour=4 [ClientMods] @CF=1559212036 @Namalsk_Island=2288339650 @Namalsk_Survival=2288336145 [ServerMods] [Server-1] serverPort=2302 serverConfig=serverDZ.cfg serverExeName=DayZServer_x64.exe serverCPU=2 startupClientMods=@CF;@Namalsk_Island;@Namalsk_Survival startupServerMods= additionalParams= -name=Server ; Mission name for Namalsk Mod ; This is the name of the Namalsk mod mission. It can be 'Hardcore' or 'Regular', i.e. the names of folders in the '@Namalsk_Survival\Extras\' directory. ; If you are not using Namalsk mod, this parameter is ignored. namalskMission=Hardcore [Server-2] serverPort=2402 serverConfig=serverDZ.cfg serverExeName=DayZServer_x64.exe serverCPU=2 startupClientMods=@CF startupServerMods= additionalParams= -name=Server -AdminLog -FilePatching namalskMission= " Add-Content -Path $iniFile -Value $content -Encoding ASCII $content = $null Exit } if ($init) { Init ; Exit } if (-not (Test-Path -Path $iniFile)) { Write-Warning "Can't find file '$iniFile'. You probably need to run the bat-script with the '/I' parameter." Exit } $date = Get-Date [int]$currentDayOfWeek = ([datetime]$date).DayOfWeek [int]$currentDay = ([datetime]$date).Day [int]$currentHour = ([datetime]$date).Hour $date2 = Get-Date -Format 's' | ForEach-Object { $_ -replace 'T', ' ' } Write-Host "$($date2) Starting $($myName) $($myVersion) script" $ini = $config = $servers = $clientMods = $serverMods = $steamProcess = $null $modNI = $modNS = $namalskMission = $pathNamalskMission = $null $dayzProcess = $becProcess = $instance = $profilesLocation = $null $becLocation = $rotatedLogsFolderName = $atFolderName = $serverLocation = $null $steamCMD = $steamUser = $appidServer = $appidGame = $rotateLogs = $daysAmount = $null $serverPort = $serverConfig = $serverExeName = $serverCPU = $null $startupClientMods = $startupServerMods = $startupMods = $startupParams = $null $serverProfile = $additionalParams = $dayzArguments = $dayz = $bec = $becArguments = $null $logsName = $atLogsLocation = $becLogsLocation = $rotatedLogsLocation = $null $currentPath = Get-Location $ini = (Get-IniContent -FilePath $iniFile) $config = $ini.Config [string]$serverLocation = $config.serverLocation [string]$profilesLocation = $config.profilesLocation [string]$becLocation = $config.becLocation [string]$steamCMD = $config.steamCMD [string]$steamUser = $config.steamUser [int]$appidGame = $config.appidGame [int]$appidServer = $config.appidServer [int]$updateDay = $config.updateDay [int]$updateHour = $config.updateHour [string]$updatePeriod = $config.updatePeriod [bool]$rotateLogs = [int]$config.rotateLogs $clientMods = New-Object 'Collections.Generic.List[Tuple[string,string]]' foreach ($mod in $ini.ClientMods.GetEnumerator()) { if ($mod.Key -notlike "Comment*" ) { $clientMods.Add([Tuple]::Create($mod.Key, $mod.Value)) } } $serverMods = New-Object 'Collections.Generic.List[Tuple[string,string]]' foreach ($mod in $ini.ServerMods.GetEnumerator()) { if ($mod.Key -notlike "Comment*" ) { $serverMods.Add([Tuple]::Create($mod.Key, $mod.Value)) } } switch ($updatePeriod) { D { if ($currentHour -eq $updateHour) { $update = $true } } W { if (($currentDayOfWeek -eq $updateDay) -and ($currentHour -eq $updateHour)) { $update = $true } } M { if (($currentDay -eq $updateDay) -and ($currentHour -eq $updateHour)) { $update = $true } } default { $update = $false } } Write-Host "Init = $($init), Update = $($update), noDelete = $($noDelete)" if ($update) { if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Write-Warning "You do not have Administrator rights to run this script!`nPlease re-run this script as an Administrator!" Exit } Write-Host "Start updating server..." if (-not (Test-Path $steamCMD)) { Write-Error "Can't find folder '$steamCMD'!" Exit } # Making Steam script $arr = @() $arr += "@NoPromptForPassword 1" $arr += "@ShutdownOnFailedCommand 1" $arr += "force_install_dir `"$($serverLocation)`"" $arr += "login $($steamUser)" $arr += "app_update $($appidServer) validate" $clientMods | ForEach-Object { $arr += "workshop_download_item $($appidGame) $($_.Item2) validate" } $serverMods | ForEach-Object { $arr += "workshop_download_item $($appidGame) $($_.Item2) validate" } $arr += "quit" # Saving Steam script "// $($steamScript) - Steam script" | Out-File -FilePath "$($currentPath)\$($steamScript)" -Encoding ASCII $arr | Out-File -FilePath "$($currentPath)\$($steamScript)" -Encoding ASCII -Append # Run Steam script Write-Host "Run Steam script from `"$($currentPath)\$($steamScript)`"" $steamProcess = Start-Process -FilePath "$($steamCMD)\steamcmd.exe" -ArgumentList "+runscript $($currentPath)\$($steamScript) +quit" -PassThru -Wait -NoNewWindow if ($steamProcess.ExitCode -ne 0) { Write-Error "$_ failed with error code $($steamProcess.ExitCode)" Exit } Write-Host # Making symbolic links to mods and copying mod's keys Write-Host "Making symbolic links to mods:" $clientMods | ForEach-Object { New-Item -ItemType SymbolicLink -Path "$($serverLocation)\$($_.Item1)" -Target "$($serverLocation)\steamapps\workshop\content\$($appidGame)\$($_.Item2)" -Force Copy-Item -Path "$($serverLocation)\$($_.Item1)\Keys\*.bikey" -Destination "$($serverLocation)\keys\" -Force -ErrorAction SilentlyContinue } $serverMods | ForEach-Object { New-Item -ItemType SymbolicLink -Path "$($serverLocation)\$($_.Item1)" -Target "$($serverLocation)\steamapps\workshop\content\$($appidGame)\$($_.Item2)" -Force Copy-Item -Path "$($serverLocation)\$($_.Item1)\Keys\*.bikey" -Destination "$($serverLocation)\keys\" -Force -ErrorAction SilentlyContinue } Write-Host # Patching Namalsk [bool]$isNamalskIslandPresent = $false [bool]$isNamalskSurvivalPresent = $false $clientMods.Item1 | ForEach-Object { if ($_ -like "*namalsk*" -and $_ -like "*island*") { $isNamalskIslandPresent = $true $modNI = $_ Write-Host "Patching Namalsk Island server meta.cpp file ..." $whatFind_NI = "2288339650" $replaceWith_NI = "2289456201" $content = Get-Content -Path "$($serverLocation)\$($modNI)\meta.cpp" $content = $content -replace $whatFind_NI, $replaceWith_NI Set-Content -Path "$($serverLocation)\$($modNI)\meta.cpp" -Value $content } if ($_ -like "*namalsk*" -and $_ -like "*survival*") { $isNamalskSurvivalPresent = $true $modNS = $_ Write-Host "Patching Namalsk Survival server meta.cpp file ..." $whatFind_NS = "2288336145" $replaceWith_NS = "2289461232" $content = Get-Content -Path "$($serverLocation)\$($modNS)\meta.cpp" $content = $content -replace $whatFind_NS, $replaceWith_NS Set-Content -Path "$($serverLocation)\$($modNS)\meta.cpp" -Value $content } } # # Customizing servers # # Overwriting default messages.xml from Namalsk by custom file # if (Test-Path -Path "$($serverLocation)\.customs") { # Copy-Item -Path "$($serverLocation)\.customs\messages.xml" -Destination "$($serverLocation)\mpmissions\$($nPath2)\db\" # } Write-Host "End of updating server." } Write-Host if ($rotateLogs) { $daysAmount = [Math]::Abs($config.daysAmount) if (-not ([string]::IsNullOrEmpty($config.rotatedLogsFolderName))) { $rotatedLogsFolderName = $config.rotatedLogsFolderName Write-Host "Removing old wDayzManager logs..." $fileList = $null $fileList = Get-ChildItem -Path $currentPath\Logs\*.log -Recurse | Where-Object { $_.LastWriteTime.Date -lt $date.AddDays( -2) } # Write-Host $fileList -Separator "`n" foreach ($file in $fileList) { Remove-Item -Path $file Write-Host "Removed $($file)!" } Write-Host "Total: $($fileList.Count)" Write-Host } else { Write-Error "The 'rotatedLogsFolderName' parameter not set!" Exit } } # Checks for BEC location if (-not ([string]::IsNullOrEmpty($becLocation))) { if (-not [System.IO.Path]::IsPathRooted($becLocation)) { $becLocation = "$($serverLocation)\$($becLocation)" } $becLocation = [System.IO.Path]::GetFullPath($becLocation) $becFolderName = Split-Path -Path $becLocation -Leaf if (-not (Test-Path -Path "$($becLocation)\")) { New-Item -ItemType Directory -Path "$($becLocation)\" | Out-Null New-Item -ItemType Directory -Path "$($becLocation)\Config\" | Out-Null New-Item -ItemType Directory -Path "$($becLocation)\Log\" | Out-Null } } # Checks for AdminTool folder name if (-not ([string]::IsNullOrEmpty($config.atFolderName))) { $atFolderName = $config.atFolderName } $servers += $ini.Keys.Where({ $_ -Match "^[Ss]erver[\s_-]?[0-9]+$" }) $processID = 0 $dayzProcess = [Object[]]::new($servers.Count) $dayzArguments = @() if ($becLocation) { $becProcess = [Object[]]::new($servers.Count) } foreach ($srv in $servers) { $instance = ${srv} $serverPort = $ini.${srv}.serverPort $serverConfig = $ini.${srv}.serverConfig $serverExeName = $ini.${srv}.serverExeName $serverCPU = $ini.${srv}.serverCPU $startupClientMods = $ini.${srv}.startupClientMods $startupServerMods = $ini.${srv}.startupServerMods $additionalParams = $ini.${srv}.additionalParams $cm = $startupClientMods -Split ';' if ($cm -contains $modNS) { $namalskMission = $ini.${srv}.namalskMission if (($namalskMission -eq "regular") -or ($namalskMission -eq "hardcore")) { $pathNamalskMission = "$($namalskMission)\$($namalskMission).namalsk" $namalskMission += ".namalsk" if (-not (Test-Path -Path "$($serverLocation)\mpmissions\$($namalskMission)\")) { Write-Host "Copying $($namalskMission)..." Copy-Item -Path "$($serverLocation)\$($modNS)\Extras\$($pathNamalskMission)\" -Destination "$($serverLocation)\mpmissions\" -Recurse -Force } } else { Write-Error "Error in Namalsk mission definition: '$($namalskMission)'" Exit } } # Checks for profile location if ([System.IO.Path]::IsPathRooted($profilesLocation)) { $serverProfile = "$($profilesLocation)\$($instance)" } else { $serverProfile = "$($serverLocation)\$($profilesLocation)\$($instance)" } $serverProfile = [System.IO.Path]::GetFullPath($serverProfile) # Checks for server's config file is exist and copy it to profile location if not if (-not (Test-Path -Path "$($serverProfile)\")) { New-Item -ItemType Directory -Path "$($serverProfile)\" | Out-Null Copy-Item -Path "$($serverLocation)\serverDZ.cfg" -Destination "$($serverProfile)\$($serverConfig)" -ErrorAction Stop } else { if (-not (Test-Path -Path "$($serverProfile)\$($serverConfig)")) { Copy-Item -Path "$($serverLocation)\serverDZ.cfg" -Destination "$($serverProfile)\$($serverConfig)" -ErrorAction Stop } } $startupMods = @("`"-mod=$($startupClientMods)`"", "`"-serverMod=$($startupServerMods)`"") $startupParams = @("`"-profiles=$($serverProfile)`"", "`"-config=$($serverProfile)\$($serverConfig)`"", "-port=$($serverPort)", "-cpuCount=$($serverCPU)") $dayzArguments = $startupParams + $startupMods + $additionalParams $dayz = "`"$($serverLocation)\$($serverExeName)`"" if ($becLocation) { if (-not (Test-Path -Path "$($becLocation)\Config\$($instance).cfg")) { New-Item -ItemType File -Path "$($becLocation)\Config\$($instance).cfg" | Out-Null Write-Warning "Please make shure the config file `"$($instance).cfg`" in `"$($becLocation)\Config\`" folder is valid!" Exit } if (-not (Test-Path -Path "$($serverProfile)\BattlEye\")) { Write-Host "Creating new folder: `"$($serverProfile)\BattlEye\`"" New-Item -ItemType Directory -Path "$($serverProfile)\BattlEye\" | Out-Null } if (-not (Test-Path -Path "$($serverProfile)\BattlEye\bans.txt")) { Write-Host "Copying file from `"$($serverLocation)\ban.txt`" to `"$($serverProfile)\BattlEye\bans.txt`"" Copy-Item -Path "$($serverLocation)\ban.txt" -Destination "$($serverProfile)\BattlEye\bans.txt" -ErrorAction Stop } if (-not (Test-Path -Path "$($serverProfile)\BattlEye\BEServer_x64*.cfg")) { Write-Host "Creating new file: `"$($serverProfile)\BattlEye\BEServer_x64.cfg`"" New-Item -ItemType File -Path "$($serverProfile)\BattlEye\BEServer_x64.cfg" | Out-Null if (!$?) { Exit } [int]$rconPort = [int]$serverPort + 5 $content = "RConPassword ChangeMe123`r`nRConPort $($rconPort)`r`nRestrictRCon 0" Add-Content -Path "$($serverProfile)\BattlEye\BEServer_x64.cfg" -Value $content -Encoding ASCII $content = $null } $bec = "`"$($becLocation)\bec.exe`"" $becArguments = "-f `"$($instance).cfg`" --dsc" } # Rotate logs if ($rotateLogs) { if ($rotatedLogsFolderName) { $rotatedLogsLocation = "$($serverProfile)\$($rotatedLogsFolderName)" } if ($becLocation) { $becLogsLocation = "$($becLocation)\Log\$($instance)" } if ($atFolderName) { $atLogsLocation = "$($serverProfile)\$($atFolderName)" $logsName = Get-ChildItem -Path $atLogsLocation -Directory -Filter "Log*" $atLogsLocation += '\' + $logsName } If (-not (Test-Path -PathType Container $rotatedLogsLocation)) { New-Item -ItemType Directory -Path $rotatedLogsLocation | Out-Null Write-Host "Created new folder: $($rotatedLogsLocation)" } if ($noDelete) { $destDelDir = "$($rotatedLogsLocation)\DeletedLogs" If (-not (Test-Path -PathType Container $destDelDir)) { New-Item -ItemType Directory -Path $destDelDir | Out-Null Write-Host "Created new folder: $($destDelDir)" } } #region ### DayZ Game ### Write-Host "Rotating DAYZ logs..." $fileList = $null $fileList = Get-Item -Path $serverProfile\*.rpt, $serverProfile\*.log, $serverProfile\*.adm, $serverProfile\*.mdmp | Where-Object { $_.LastWriteTime.Date -lt $date.Date } # Write-Host $fileList -Separator "`n" Write-Host "Moving DayZ logs to $($rotatedLogsLocation):" foreach ($file in $fileList) { Move-Item -Path $file -Destination $rotatedLogsLocation -Force Write-Host "Moved $($file) to $($rotatedLogsLocation)" } Write-Host "Total: $($fileList.Count)" $fileList = Get-Item -Path $rotatedLogsLocation\*.rpt, $rotatedLogsLocation\*.log, $rotatedLogsLocation\*.adm, $rotatedLogsLocation\*.mdmp | Where-Object { $_.LastWriteTime -lt $date.AddDays( - ($daysAmount)) } # Write-Host $fileList -Separator "`n" Write-Host "Removing DayZ logs:" foreach ($file in $fileList) { if ($noDelete) { Move-Item -Path $file -Destination $destDelDir -Force Write-Host "Moved $($file) to $($destDelDir)" } else { Remove-Item -Path $file Write-Host "Removed $($file)!" } } Write-Host "Total: $($fileList.Count)" Write-Host #endregion #region ### BEC ### if ($becLocation) { $becDestDir = "$($rotatedLogsLocation)\$($becFolderName)" If (-not (Test-Path -PathType Container $becDestDir)) { New-Item -ItemType Directory -Path $becDestDir | Out-Null Write-Host "Created new folder: $($becDestDir)" } Write-Host "Rotating BEC logs..." $fileList = $null $fileList = Get-ChildItem -Path $becLogsLocation\*.log -Recurse | Where-Object { $_.LastWriteTime.Date -lt $date.Date } # Write-Host $fileList -Separator "`n" Write-Host "Moving BEC logs to $($becDestDir):" foreach ($file in $fileList) { Move-Item -Path $file -Destination $becDestDir -Force Write-Host "Moved $($file) to $($becDestDir)" } Write-Host "Total: $($fileList.Count)" $fileList = Get-Item -Path $becDestDir\*.log | Where-Object { $_.LastWriteTime -lt $date.AddDays( - ($daysAmount)) } # Write-Host $fileList -Separator "`n" Write-Host "Removing BEC logs:" foreach ($file in $fileList) { if ($noDelete) { Move-Item -Path $file -Destination $destDelDir -Force Write-Host "Moved $($file) to $($destDelDir)" } else { Remove-Item -Path $file Write-Host "Removed $($file)!" } } Write-Host "Total: $($fileList.Count)" Write-Host } #endregion #region ### Admin Tool ### if ($atLogsLocation) { $atDestDir = "$($rotatedLogsLocation)\$($atFolderName)" If (-not (Test-Path -PathType Container $atDestDir)) { New-Item -ItemType Directory -Path $atDestDir | Out-Null Write-Host "Created new folder: $($atDestDir)" } Write-Host "Rotating AdminTool logs..." $fileList = $null $fileList = Get-ChildItem -Path $atLogsLocation\*.txt, $atLogsLocation\*.log -Recurse | Where-Object { $_.LastWriteTime.Date -lt $date.Date } # Write-Host $fileList -Separator "`n" Write-Host "Moving AdminTool logs to $($atDestDir):" foreach ($file in $fileList) { Move-Item -Path $file -Destination $atDestDir -Force Write-Host "Moved $($file) to $($atDestDir)" } Write-Host "Total: $($fileList.Count)" $fileList = Get-Item -Path $atDestDir\*.txt, $atDestDir\*.log | Where-Object { $_.LastWriteTime -lt $date.AddDays( - ($daysAmount)) } # Write-Host $fileList -Separator "`n" Write-Host "Removing AdminTool logs:" foreach ($file in $fileList) { if ($noDelete) { Move-Item -Path $file -Destination $destDelDir -Force Write-Host "Moved $($file) to $($destDelDir)" } else { Remove-Item -Path $file Write-Host "Removed $($file)!" } } Write-Host "Total: $($fileList.Count)" Write-Host } #endregion } # Write-Host " instance: $($instance)" # Write-Host " serverProfile: $($serverProfile)" # Write-Host " serverPort: $($serverPort)" # Write-Host " serverConfig: $($serverConfig)" # Write-Host " serverExeName: $($serverExeName)" # Write-Host " serverCPU: $($serverCPU)" # Write-Host " startupClientMods: $($startupClientMods)" # Write-Host " startupServerMods: $($startupServerMods)" # Write-Host " startupMods: $($startupMods)" # Write-Host " startupParams: $($startupParams)" # Write-Host " additionalParams: $($additionalParams)" # Write-Host " pathNamalskMission: $($pathNamalskMission)" # Write-Host " namalskMission: $($namalskMission)" # Write-Host # Write-Host " dayz: $($dayz)" # Write-Host " dayzArguments: $($dayzArguments)" # Write-Host # Write-Host " becLocation: $($becLocation)" # Write-Host " bec: $($bec)" # Write-Host " becArguments: $($becArguments)" # Write-Host # Write-Host " atFolderName: $($atFolderName)" # Write-Host # Write-Host " atLogsLocation: $($atLogsLocation)" # Write-Host " becLogsLocation: $($becLogsLocation)" # Write-Host # Write-Host " rotateLogs: $($rotateLogs)" # Write-Host " destDelDir: $($destDelDir)" # Write-Host " becDestDir: $($becDestDir)" # Write-Host " atDestDir: $($atDestDir)" # Write-Host # Write-Host "rotatedLogsFolderName: $($rotatedLogsFolderName)" # Write-Host " rotatedLogsLocation: $($rotatedLogsLocation)" # Write-Host " daysAmount: $($daysAmount)" # Write-Host " noDelete: $($noDelete)" # Starting servers Set-Location -Path "$($serverLocation)" $dayzProcess[$processID] = Start-Process -FilePath $dayz -ArgumentList $dayzArguments -PassThru # Write-Host "Start-Process -FilePath $($dayz) -ArgumentList $($dayzArguments) -PassThru" # $dayzProcess[$processID] # Starting BEC if ($becLocation) { Set-Location -Path "$($becLocation)" $becProcess[$processID] = Start-Process -FilePath $bec -ArgumentList $becArguments -PassThru # Write-Host "Start-Process -FilePath $($bec) -ArgumentList $($becArguments) -PassThru" # $becProcess[$processID] } $processID++ Write-Host Start-Sleep -Seconds 1 } Write-Host "End of wDayzManager script"