pub const LIBRARY: &str = "# SPDX-License-Identifier: Apache-2.0\n#\n# Isoloom\'s configuration library for Windows: one function per step kind of the configuration\n# model. A recipe dot-sources it, then calls one function per step, in order. Each function\n# ensures a state behind its guard: a second apply changes nothing. Every change writes\n# `isoloom: changed <what>` and marks the file $env:ISOLOOM_CHANGED names (when set), which a\n# later service step reads to restart its service. A failure throws `isoloom: <why>`.\n\n[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12\n\n# Reports a change: its line, and the mark the restart rule reads.\nfunction Write-IsoloomChange {\n param([Parameter(Mandatory)][string] $What)\n Write-Output \"isoloom: changed $What\"\n if ($env:ISOLOOM_CHANGED) {\n New-Item -ItemType Directory -Force -Path (Split-Path -Parent $env:ISOLOOM_CHANGED) | Out-Null\n Set-Content -LiteralPath $env:ISOLOOM_CHANGED -Value \'changed\'\n }\n}\n\n# Whether an earlier step changed something during this apply: a service restarts then.\nfunction Test-IsoloomRestartDue {\n return [bool]($env:ISOLOOM_CHANGED -and (Test-Path -LiteralPath $env:ISOLOOM_CHANGED))\n}\n\n# The SHA-256 of a file, in lowercase hex.\nfunction Get-IsoloomHash {\n param([Parameter(Mandatory)][string] $Path)\n return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()\n}\n\n# The packages step: each Windows feature installed (a server\'s role or feature, or a client\'s\n# optional feature).\nfunction Install-IsoloomFeature {\n param([Parameter(Mandatory)][string[]] $Name)\n $server = [bool](Get-Command -Name Get-WindowsFeature -ErrorAction SilentlyContinue)\n foreach ($feature in $Name) {\n if ($server) {\n if ((Get-WindowsFeature -Name $feature).Installed) { continue }\n $result = Install-WindowsFeature -Name $feature -IncludeManagementTools\n if (-not $result.Success) { throw \"isoloom: installing the feature $feature failed\" }\n } else {\n if ((Get-WindowsOptionalFeature -Online -FeatureName $feature).State -eq \'Enabled\') { continue }\n Enable-WindowsOptionalFeature -Online -FeatureName $feature -All -NoRestart | Out-Null\n }\n Write-IsoloomChange -What \"feature $feature\"\n }\n}\n\n# A file at To with From\'s content (To written when it differs).\nfunction Copy-IsoloomFile {\n param([Parameter(Mandatory)][string] $From, [Parameter(Mandatory)][string] $To)\n if ((Test-Path -LiteralPath $To -PathType Leaf) -and ((Get-IsoloomHash -Path $From) -eq (Get-IsoloomHash -Path $To))) {\n return\n }\n $parent = Split-Path -Parent $To\n if ($parent) { New-Item -ItemType Directory -Force -Path $parent | Out-Null }\n Copy-Item -LiteralPath $From -Destination $To -Force\n Write-IsoloomChange -What $To\n}\n\n# The copy step: From (from the current folder) at To; a folder puts what it holds into To.\nfunction Copy-IsoloomItem {\n param([Parameter(Mandatory)][string] $From, [Parameter(Mandatory)][string] $To)\n if (-not (Test-Path -LiteralPath $From -PathType Container)) {\n Copy-IsoloomFile -From $From -To $To\n return\n }\n $root = (Resolve-Path -LiteralPath $From).Path.TrimEnd(\'\\\', \'/\')\n if (-not (Test-Path -LiteralPath $To -PathType Container)) {\n New-Item -ItemType Directory -Force -Path $To | Out-Null\n Write-IsoloomChange -What $To\n }\n foreach ($entry in Get-ChildItem -LiteralPath $root -Recurse -Force) {\n $target = Join-Path -Path $To -ChildPath $entry.FullName.Substring($root.Length).TrimStart(\'\\\', \'/\')\n if ($entry.PSIsContainer) {\n if (Test-Path -LiteralPath $target -PathType Container) { continue }\n New-Item -ItemType Directory -Force -Path $target | Out-Null\n Write-IsoloomChange -What $target\n } else {\n Copy-IsoloomFile -From $entry.FullName -To $target\n }\n }\n}\n\n# The template step: the file Isoloom filled in (its bytes, in base64) at To.\nfunction Install-IsoloomTemplate {\n param([Parameter(Mandatory)][string] $To, [Parameter(Mandatory)][AllowEmptyString()][string] $Base64)\n $temporary = [IO.Path]::GetTempFileName()\n try {\n [IO.File]::WriteAllBytes($temporary, [Convert]::FromBase64String($Base64))\n Copy-IsoloomFile -From $temporary -To $To\n } finally {\n Remove-Item -LiteralPath $temporary -Force -ErrorAction SilentlyContinue\n }\n}\n\n# The file step: Path made a folder, absent, or a download of Url pinned by Sha256.\nfunction Install-IsoloomFile {\n param(\n [Parameter(Mandatory)][string] $Path,\n [Parameter(Mandatory)][ValidateSet(\'directory\', \'absent\', \'download\')][string] $State,\n [string] $Url,\n [string] $Sha256\n )\n switch ($State) {\n \'directory\' {\n if (Test-Path -LiteralPath $Path -PathType Container) { return }\n New-Item -ItemType Directory -Force -Path $Path | Out-Null\n }\n \'absent\' {\n if (-not (Test-Path -LiteralPath $Path)) { return }\n Remove-Item -LiteralPath $Path -Recurse -Force\n }\n \'download\' {\n if ((Test-Path -LiteralPath $Path -PathType Leaf) -and ((Get-IsoloomHash -Path $Path) -eq $Sha256)) { return }\n $parent = Split-Path -Parent $Path\n if ($parent) { New-Item -ItemType Directory -Force -Path $parent | Out-Null }\n $temporary = \"$Path.isoloom-download\"\n Invoke-WebRequest -UseBasicParsing -Uri $Url -OutFile $temporary\n $got = Get-IsoloomHash -Path $temporary\n if ($got -ne $Sha256) {\n Remove-Item -LiteralPath $temporary -Force\n throw \"isoloom: $Url has SHA-256 $got, not ${Sha256}: the file changed upstream, or the pin is wrong\"\n }\n Move-Item -LiteralPath $temporary -Destination $Path -Force\n }\n }\n Write-IsoloomChange -What $Path\n}\n\n# A password as a SecureString, built a character at a time.\nfunction ConvertTo-IsoloomSecure {\n param([Parameter(Mandatory)][string] $Phrase)\n $secure = New-Object -TypeName System.Security.SecureString\n foreach ($character in $Phrase.ToCharArray()) { $secure.AppendChar($character) }\n return $secure\n}\n\n# Whether local user Name\'s password is Phrase.\nfunction Test-IsoloomPhrase {\n param([Parameter(Mandatory)][string] $Name, [Parameter(Mandatory)][string] $Phrase)\n Add-Type -AssemblyName System.DirectoryServices.AccountManagement\n $machine = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList \'Machine\'\n try { return $machine.ValidateCredentials($Name, $Phrase) } finally { $machine.Dispose() }\n}\n\n# Local user Name is a member of local group Group.\nfunction Add-IsoloomMember {\n param([Parameter(Mandatory)][string] $Group, [Parameter(Mandatory)][string] $Name)\n $members = Get-LocalGroupMember -Group $Group | ForEach-Object { ($_.Name -split \'\\\\\')[-1] }\n if ($members -contains $Name) { return }\n Add-LocalGroupMember -Group $Group -Member $Name\n Write-IsoloomChange -What \"$Name in $Group\"\n}\n\n# The user step: local user Name, with its password (Phrase, when given) and in Groups.\nfunction Add-IsoloomUser {\n param([Parameter(Mandatory)][string] $Name, [string] $Phrase, [string[]] $Groups = @())\n if (-not (Get-LocalUser -Name $Name -ErrorAction SilentlyContinue)) {\n if ($Phrase) {\n New-LocalUser -Name $Name -Password (ConvertTo-IsoloomSecure -Phrase $Phrase) -PasswordNeverExpires | Out-Null\n } else {\n New-LocalUser -Name $Name -NoPassword | Out-Null\n }\n Write-IsoloomChange -What \"user $Name\"\n } elseif ($Phrase -and -not (Test-IsoloomPhrase -Name $Name -Phrase $Phrase)) {\n Set-LocalUser -Name $Name -Password (ConvertTo-IsoloomSecure -Phrase $Phrase)\n Write-IsoloomChange -What \"password of $Name\"\n }\n foreach ($group in $Groups) { Add-IsoloomMember -Group $group -Name $Name }\n}\n\n# The group step: local group Name.\nfunction Add-IsoloomGroup {\n param([Parameter(Mandatory)][string] $Name)\n if (Get-LocalGroup -Name $Name -ErrorAction SilentlyContinue) { return }\n New-LocalGroup -Name $Name | Out-Null\n Write-IsoloomChange -What \"group $Name\"\n}\n\n# A service Isoloom defines: a startup task (as SYSTEM) running Run (a program and its\n# arguments) in Directory, registered again when it changed.\nfunction Register-IsoloomTask {\n param([Parameter(Mandatory)][string] $Name, [Parameter(Mandatory)][string[]] $Run, [string] $Directory)\n $arguments = ($Run | Select-Object -Skip 1 | ForEach-Object { \'\"\' + ($_ -replace \'\"\', \'\\\"\') + \'\"\' }) -join \' \'\n $settings = @{ Execute = $Run[0] }\n if ($arguments) { $settings.Argument = $arguments }\n if ($Directory) { $settings.WorkingDirectory = $Directory }\n $action = New-ScheduledTaskAction @settings\n $task = Get-ScheduledTask -TaskName \"isoloom-$Name\" -ErrorAction SilentlyContinue\n $same = $task -and $task.Actions[0].Execute -eq $action.Execute -and $task.Actions[0].Arguments -eq $action.Arguments -and\n $task.Actions[0].WorkingDirectory -eq $action.WorkingDirectory\n if ($same) { return }\n $trigger = New-ScheduledTaskTrigger -AtStartup\n Register-ScheduledTask -TaskName \"isoloom-$Name\" -Action $action -Trigger $trigger -User \'SYSTEM\' -RunLevel Highest -Force | Out-Null\n Write-IsoloomChange -What \"task isoloom-$Name\"\n}\n\n# The service step for a service Isoloom defines: its startup task enabled and running, or\n# disabled and stopped.\nfunction Register-IsoloomTaskState {\n param([Parameter(Mandatory)][string] $Name, [Parameter(Mandatory)][bool] $Enabled)\n $task = Get-ScheduledTask -TaskName \"isoloom-$Name\"\n if (-not $Enabled) {\n if ($task.State -eq \'Running\') { Stop-ScheduledTask -TaskName \"isoloom-$Name\"; Write-IsoloomChange -What \"isoloom-$Name stopped\" }\n if ($task.State -ne \'Disabled\') { Disable-ScheduledTask -TaskName \"isoloom-$Name\" | Out-Null; Write-IsoloomChange -What \"isoloom-$Name disabled\" }\n return\n }\n if ($task.State -eq \'Disabled\') { Enable-ScheduledTask -TaskName \"isoloom-$Name\" | Out-Null; Write-IsoloomChange -What \"isoloom-$Name enabled\" }\n if ((Get-ScheduledTask -TaskName \"isoloom-$Name\").State -ne \'Running\') {\n Start-ScheduledTask -TaskName \"isoloom-$Name\"\n Write-IsoloomChange -What \"isoloom-$Name started\"\n } elseif (Test-IsoloomRestartDue) {\n Stop-ScheduledTask -TaskName \"isoloom-$Name\"\n Start-ScheduledTask -TaskName \"isoloom-$Name\"\n Write-Output \"isoloom: restarted isoloom-$Name\"\n }\n}\n\n# The service step: Windows service Name started automatically and running (restarted when an\n# earlier step changed something), or disabled and stopped.\nfunction Register-IsoloomService {\n param([Parameter(Mandatory)][string] $Name, [Parameter(Mandatory)][bool] $Enabled)\n $service = Get-Service -Name $Name -ErrorAction SilentlyContinue\n if (-not $service) { throw \"isoloom: no Windows service ${Name}: install what provides it in an earlier step\" }\n if (-not $Enabled) {\n if ($service.StartType -ne \'Disabled\') { Set-Service -Name $Name -StartupType Disabled; Write-IsoloomChange -What \"$Name disabled\" }\n if ($service.Status -ne \'Stopped\') { Stop-Service -Name $Name -Force; Write-IsoloomChange -What \"$Name stopped\" }\n return\n }\n if ($service.StartType -ne \'Automatic\') { Set-Service -Name $Name -StartupType Automatic; Write-IsoloomChange -What \"$Name enabled\" }\n if ($service.Status -ne \'Running\') {\n Start-Service -Name $Name\n Write-IsoloomChange -What \"$Name started\"\n } elseif (Test-IsoloomRestartDue) {\n Restart-Service -Name $Name -Force\n Write-Output \"isoloom: restarted $Name\"\n }\n}\n\n# The command step: Run (a script block\'s text) after its guard, unless the guard says it\n# already ran: Creates (a path whose existence says so) or Unless (a check that succeeds).\nfunction Invoke-IsoloomCommand {\n param([Parameter(Mandatory)][string] $Run, [string] $Creates, [string] $Unless)\n if ($Creates -and (Test-Path -LiteralPath $Creates)) { return }\n if ($Unless -and (Test-IsoloomScript -Text $Unless)) { return }\n if (-not (Test-IsoloomScript -Text $Run -Loud)) { throw \"isoloom: the command failed: $Run\" }\n Write-IsoloomChange -What \'command\'\n}\n\n# Whether script Text succeeds: no error, and a native program\'s exit code 0. Its output is\n# shown with Loud, else dropped.\nfunction Test-IsoloomScript {\n param([Parameter(Mandatory)][string] $Text, [switch] $Loud)\n Set-Variable -Name LASTEXITCODE -Scope Global -Value 0\n try {\n if ($Loud) { & ([scriptblock]::Create($Text)) } else { & ([scriptblock]::Create($Text)) | Out-Null }\n } catch {\n if ($Loud) { Write-Error -Message $_ -ErrorAction Continue }\n return $false\n }\n return (Get-Variable -Name LASTEXITCODE -Scope Global -ValueOnly) -eq 0\n}\n\n# The firewall step: Port (with Protocol) open in Windows Firewall.\nfunction Enable-IsoloomFirewallPort {\n param([Parameter(Mandatory)][int] $Port, [Parameter(Mandatory)][ValidateSet(\'TCP\', \'UDP\')][string] $Protocol)\n $name = \"isoloom-$Port-$Protocol\"\n if (Get-NetFirewallRule -Name $name -ErrorAction SilentlyContinue) { return }\n New-NetFirewallRule -Name $name -DisplayName \"Isoloom $Port/$Protocol\" -Direction Inbound -Action Allow -Protocol $Protocol -LocalPort $Port | Out-Null\n Write-IsoloomChange -What \"firewall $Port/$Protocol\"\n}\n";Expand description
The library, as Isoloom ships it.