121 lines
6.9 KiB
PowerShell
121 lines
6.9 KiB
PowerShell
# DeployCenter - Découverte et génération des profils de réponses Windows.
|
|
# Les profils PSD1 restent des fichiers de données ; les réponses sont construites comme XML.
|
|
|
|
function Get-DeployCenterUnattendProfileNames {
|
|
[CmdletBinding()]
|
|
param([Parameter(Mandatory=$true)][string]$ProfilesRoot)
|
|
|
|
if (-not (Test-Path -LiteralPath $ProfilesRoot -PathType Container)) { return @() }
|
|
$names = @()
|
|
foreach ($file in (Get-ChildItem -LiteralPath $ProfilesRoot -Filter '*.psd1' -File -ErrorAction SilentlyContinue)) {
|
|
if ($file.BaseName -match '^[A-Za-z0-9_-]+$') { $names += $file.BaseName }
|
|
}
|
|
return @($names | Sort-Object -Unique)
|
|
}
|
|
|
|
function Import-DeployCenterUnattendProfile {
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory=$true)][string]$ProfilesRoot,
|
|
[Parameter(Mandatory=$true)][string]$ProfileName
|
|
)
|
|
|
|
if ($ProfileName -notmatch '^[A-Za-z0-9_-]+$') { throw "Nom de profil Unattend invalide : $ProfileName" }
|
|
$path = Join-Path $ProfilesRoot ($ProfileName + '.psd1')
|
|
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { throw "Profil Unattend introuvable : $ProfileName" }
|
|
$profile = Import-PowerShellDataFile -LiteralPath $path
|
|
foreach ($key in @('Id','Name','Description','Target','Template','ComputerName','LocalAccount')) {
|
|
if (-not $profile.ContainsKey($key)) { throw ('Le profil Unattend {0} ne contient pas la cle {1}.' -f $ProfileName, $key) }
|
|
}
|
|
if ([string]$profile.Id -ne $ProfileName) { throw ('L identifiant du profil Unattend {0} ne correspond pas au nom du fichier.' -f $ProfileName) }
|
|
if ([string]$profile.Target -notin @('Workstation', 'Server')) { throw ('La propriete Target du profil Unattend {0} doit etre Workstation ou Server.' -f $ProfileName) }
|
|
if ([string]$profile.Template -notmatch '^[A-Za-z0-9_-]+\.xml$') { throw ('Nom de template XML invalide dans le profil {0}.' -f $ProfileName) }
|
|
$templatesRoot = Join-Path (Split-Path -Parent $ProfilesRoot) 'Templates'
|
|
$templatePath = Join-Path $templatesRoot ([string]$profile.Template)
|
|
if (-not (Test-Path -LiteralPath $templatePath -PathType Leaf)) { throw "Template XML introuvable pour le profil '$ProfileName' : $templatePath" }
|
|
if (-not [string]$profile.Name -or [string]::IsNullOrWhiteSpace([string]$profile.Name)) { throw ('Le profil Unattend {0} doit definir un nom affichable.' -f $ProfileName) }
|
|
$profile.TemplatePath = $templatePath
|
|
return $profile
|
|
}
|
|
|
|
function Test-DeployCenterUnattendConfiguration {
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Profile,
|
|
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Configuration,
|
|
[Parameter(Mandatory=$true)][string]$HostName
|
|
)
|
|
|
|
if ($Profile.ComputerName -and $HostName -notmatch '^(?=.*[A-Za-z])[A-Za-z0-9](?:[A-Za-z0-9-]{0,13}[A-Za-z0-9])?$') {
|
|
throw 'Le nom de machine doit respecter les règles NetBIOS et ne pas dépasser 15 caractères.'
|
|
}
|
|
if ($Profile.LocalAccount) {
|
|
$accountName = [string]$Configuration.UnattendAdminName
|
|
$displayName = [string]$Configuration.UnattendAdminDisplayName
|
|
$groupName = [string]$Configuration.UnattendAdminGroup
|
|
$passwordBase64 = [string]$Configuration.UnattendAdminPasswordBase64
|
|
if ($accountName -notmatch '^[^"/\[\]:;|=,+*?<>\\]{1,20}$') { throw 'Le paramètre [Unattend] AdminName doit contenir de 1 à 20 caractères et éviter les caractères interdits par Windows.' }
|
|
if ([string]::IsNullOrWhiteSpace($displayName)) { throw 'Le paramètre [Unattend] AdminDisplayName ne peut pas être vide.' }
|
|
if ([string]::IsNullOrWhiteSpace($groupName)) { throw 'Le paramètre [Unattend] AdminGroup ne peut pas être vide.' }
|
|
if ([string]::IsNullOrWhiteSpace($passwordBase64)) { throw 'Le paramètre [Unattend] AdminPasswordBase64 est requis pour ce profil.' }
|
|
try {
|
|
$passwordBytes = [Convert]::FromBase64String($passwordBase64)
|
|
if ($passwordBytes.Length -eq 0 -or ($passwordBytes.Length % 2) -ne 0 -or
|
|
[string]::IsNullOrEmpty([Text.Encoding]::Unicode.GetString($passwordBytes))) {
|
|
throw 'Format UTF-16LE Base64 invalide.'
|
|
}
|
|
} catch {
|
|
throw 'Le paramètre [Unattend] AdminPasswordBase64 doit être un mot de passe UTF-16LE encodé en Base64.'
|
|
}
|
|
}
|
|
}
|
|
|
|
function New-DeployCenterUnattendXml {
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Profile,
|
|
[Parameter(Mandatory=$true)][System.Collections.IDictionary]$Configuration,
|
|
[Parameter(Mandatory=$true)][string]$HostName,
|
|
[Parameter(Mandatory=$true)][string]$Architecture
|
|
)
|
|
|
|
Test-DeployCenterUnattendConfiguration -Profile $Profile -Configuration $Configuration -HostName $HostName
|
|
$document = New-Object System.Xml.XmlDocument
|
|
$document.PreserveWhitespace = $true
|
|
$document.Load([string]$Profile.TemplatePath)
|
|
$namespaces = New-Object System.Xml.XmlNamespaceManager($document.NameTable)
|
|
$namespaces.AddNamespace('u', 'urn:schemas-microsoft-com:unattend')
|
|
$namespaces.AddNamespace('wcm', 'http://schemas.microsoft.com/WMIConfig/2002/State')
|
|
|
|
$processorArchitecture = switch -Regex ($Architecture.ToLowerInvariant()) {
|
|
'arm64' { 'arm64'; break }
|
|
'x86|32' { 'x86'; break }
|
|
default { 'amd64' }
|
|
}
|
|
foreach ($component in $document.SelectNodes('//u:component', $namespaces)) {
|
|
$component.SetAttribute('processorArchitecture', $processorArchitecture)
|
|
}
|
|
if ($Profile.ComputerName) {
|
|
$node = $document.SelectSingleNode('/u:unattend/u:settings[@pass="specialize"]/u:component[@name="Microsoft-Windows-Shell-Setup"]/u:ComputerName', $namespaces)
|
|
if ($null -eq $node) { throw ('Le template du profil {0} ne definit pas le noeud ComputerName dans specialize.' -f $Profile.Id) }
|
|
$node.InnerText = $HostName
|
|
}
|
|
if ($Profile.LocalAccount) {
|
|
$values = @{
|
|
Name = [string]$Configuration.UnattendAdminName
|
|
DisplayName = [string]$Configuration.UnattendAdminDisplayName
|
|
Group = [string]$Configuration.UnattendAdminGroup
|
|
Password = [string]$Configuration.UnattendAdminPasswordBase64
|
|
}
|
|
foreach ($name in $values.Keys) {
|
|
$field = if ($name -eq 'Password') { 'Password/u:Value' } else { $name }
|
|
$node = $document.SelectSingleNode("/u:unattend/u:settings[@pass='oobeSystem']/u:component[@name='Microsoft-Windows-Shell-Setup']/u:UserAccounts/u:LocalAccounts/u:LocalAccount/u:$field", $namespaces)
|
|
if ($null -eq $node) { throw ('Le template du profil {0} ne definit pas le champ de compte {1}.' -f $Profile.Id, $name) }
|
|
$node.InnerText = $values[$name]
|
|
}
|
|
}
|
|
return $document.OuterXml
|
|
}
|
|
|
|
Export-ModuleMember -Function Get-DeployCenterUnattendProfileNames, Import-DeployCenterUnattendProfile, Test-DeployCenterUnattendConfiguration, New-DeployCenterUnattendXml
|