En raison d’une mise à jour Windows distribuée par Microsoft dans la nuit du 12 août 2026, le mode de démarrage automatique avec l’utilisateur SiteKiosk ne fonctionne plus correctement.
Cause
Le problème est dû aux restrictions de permissions appliquées par SiteKiosk au compte utilisateur SiteKiosk. Ces restrictions empêchent la mise à jour Windows d’effectuer correctement et intégralement toutes les étapes requises pour le compte utilisateur concerné. Par conséquent, le fichier NTUSER.DAT ne peut pas être chargé et le démarrage automatique est bloqué.
Mise à jour du 19 août 2026 :
Avec la nouvelle version 9.10.10010 du client SiteKiosk Classic, le correctif est désormais inclus par défaut.
Mise à jour du 17 août 2026 :
Avec la nouvelle version 1.10.341.0 du Client SiteKiosk Online, ce correctif est désormais disponible par défaut.
Solution de contournement mise à jour
Mise à jour du 17 août 2026 :
Nous avons révisé la solution de contournement précédente et mettons à disposition un nouveau script PowerShell.
Important :
Dans la mesure du possible, privilégiez l’installation via l’installateur SiteKiosk actuel, le correctif y étant déjà inclus par défaut. Si l’utilisation de l’installateur n’est pas possible dans un cas particulier, la solution de contournement mise à jour ci-dessous peut être appliquée à la place.
Le script mis à jour doit être exécuté à nouveau après chaque nouvelle installation de SiteKiosk.
Comme solution de contournement temporaire, nous recommandons d’exécuter le script PowerShell ci-dessous sur un ordinateur concerné dans une session PowerShell disposant de droits d’administrateur.
Le nouveau script remplace le correctif précédemment publié et prend en compte des scénarios supplémentaires lors de la réparation du profil utilisateur SiteKiosk. Notre équipe de développement continue de travailler sur une solution définitive. Nous vous informerons de toute nouvelle modification dès que de nouvelles informations seront disponibles.
Veuillez vous assurer que l’utilisateur SiteKiosk est complètement déconnecté avant d’exécuter le script.
Procédure pour SiteKiosk Online
Mise à jour du 17 août 2026 :
Avec la nouvelle version 1.10.341.0 du Client SiteKiosk Online, ce correctif est désormais disponible par défaut.
12 août 2026
Par souci de transparence : le 12 août 2026, nous avons déployé automatiquement un script simplifié sur tous les clients connectés à ce moment-là.
Alternativement, la solution peut être appliquée à distance pour chaque client individuellement, par exemple via le Recovery Shell d’un client concerné :
Monitoring > [Client] > Administration > Recovery Shell
Procédure pour SiteKiosk Classic Windows
Mise à jour du 19 août 2026 :
Avec la nouvelle version 9.10.10010 du client SiteKiosk Classic, le correctif est désormais inclus par défaut.
Important :
Dans la mesure du possible, nous recommandons d’effectuer l’installation à l’aide du programme d’installation SiteKiosk actuel, car le correctif y est déjà inclus par défaut. Si l’utilisation du programme d’installation n’est pas possible dans un cas particulier, la solution de contournement mise à jour du 17 août 2026, indiquée ci-dessous, peut être appliquée à la place.
Avec SiteKiosk Classic Windows, le script doit être exécuté localement à l’aide d’un compte administrateur :
1. Commencez par désactiver le verrouillage du clavier. Instructions: Unlocking the keyboard lock
2. Connectez-vous ensuite au système à l’aide d’un compte administrateur.
3. Lancez PowerShell ISE avec des droits administrateur et exécutez le script.
PowerShell script
[CmdletBinding(DefaultParameterSetName = 'Automatic', SupportsShouldProcess)]
param(
[Parameter(Mandatory, ParameterSetName = 'Explicit', Position = 0)]
[Alias('Account')]
[ValidateNotNullOrEmpty()]
[string] $UserName,
[Parameter(ParameterSetName = 'Explicit', Position = 1)]
[AllowEmptyString()]
[string] $Domain,
[Parameter()]
[Alias('LogFile')]
[ValidateNotNullOrEmpty()]
[string] $LogPath,
[Parameter()]
[switch] $Restart
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$siteKioskSettingsPath = 'SOFTWARE\PROVISIO\SiteKiosk'
$installerSettingsPath = 'SOFTWARE\PROVISIO\{A1625B78-854F-4AB7-B99D-A52EF6E94C8A}'
$classicSecurityWizardPath = 'SOFTWARE\PROVISIO\SecurityWizard'
$requiredFileRights = [System.Security.AccessControl.FileSystemRights] (
[System.Security.AccessControl.FileSystemRights]::ReadAttributes -bor
[System.Security.AccessControl.FileSystemRights]::ReadData -bor
[System.Security.AccessControl.FileSystemRights]::ReadExtendedAttributes -bor
[System.Security.AccessControl.FileSystemRights]::ReadPermissions -bor
[System.Security.AccessControl.FileSystemRights]::WriteData -bor
[System.Security.AccessControl.FileSystemRights]::AppendData -bor
[System.Security.AccessControl.FileSystemRights]::WriteAttributes -bor
[System.Security.AccessControl.FileSystemRights]::WriteExtendedAttributes -bor
[System.Security.AccessControl.FileSystemRights]::Delete -bor
[System.Security.AccessControl.FileSystemRights]::Synchronize
)
$requiredDirectoryRights = (
[System.Security.AccessControl.FileSystemRights]::CreateFiles
)
$repairLogPath = $null
$repairLogEncoding = [System.Text.UTF8Encoding]::new($false)
$repairErrorWasLogged = $false
function Initialize-RepairLog {
if ([string]::IsNullOrWhiteSpace($LogPath)) {
return
}
try {
$candidatePath = if ([System.IO.Path]::IsPathRooted($LogPath)) {
$LogPath
}
else {
Join-Path -Path (Get-Location).ProviderPath -ChildPath $LogPath
}
$script:repairLogPath = [System.IO.Path]::GetFullPath($candidatePath)
$parentPath = [System.IO.Path]::GetDirectoryName($script:repairLogPath)
if (
-not [string]::IsNullOrWhiteSpace($parentPath) -and
-not [System.IO.Directory]::Exists($parentPath)
) {
[void] [System.IO.Directory]::CreateDirectory($parentPath)
}
[System.IO.File]::AppendAllText(
$script:repairLogPath,
"`r`n$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff zzz') " +
"[INFO] Repair started by '$([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)'.`r`n",
$script:repairLogEncoding
)
}
catch {
throw "Unable to initialize the log file '$LogPath': $($_.Exception.Message)"
}
}
function Write-RepairLog {
param(
[Parameter(Mandatory)]
[ValidateSet('INFO', 'WARN', 'ERROR')]
[string] $Level,
[AllowNull()]
[AllowEmptyString()]
[object] $Message
)
if ([string]::IsNullOrWhiteSpace($script:repairLogPath)) {
return
}
$text = if ($null -eq $Message) { '' } else { [string] $Message }
$lines = [System.Text.RegularExpressions.Regex]::Split($text, '\r?\n')
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss.fff zzz'
$logText = ($lines | ForEach-Object {
"$timestamp [$Level] $_"
}) -join "`r`n"
[System.IO.File]::AppendAllText(
$script:repairLogPath,
$logText + "`r`n",
$script:repairLogEncoding
)
}
function Write-RepairHost {
param(
[AllowNull()]
[AllowEmptyString()]
[object] $Message
)
Write-RepairLog -Level INFO -Message $Message
Write-Host $Message
}
function Write-RepairWarning {
param(
[AllowNull()]
[AllowEmptyString()]
[object] $Message
)
Write-RepairLog -Level WARN -Message $Message
Write-Warning $Message
}
function Write-RepairError {
param(
[AllowNull()]
[AllowEmptyString()]
[object] $Message
)
$script:repairErrorWasLogged = $true
Write-RepairLog -Level ERROR -Message $Message
Write-Error $Message -ErrorAction Continue
}
function Get-RegistryViews {
if ([Environment]::Is64BitOperatingSystem) {
[Microsoft.Win32.RegistryView]::Registry64
}
[Microsoft.Win32.RegistryView]::Registry32
}
function Test-EnabledRegistryValue {
param(
[AllowNull()]
[object] $Value
)
$text = [Convert]::ToString($Value)
return (
[string]::Equals(
$text,
'true',
[StringComparison]::InvariantCultureIgnoreCase
) -or
$text -eq '1'
)
}
function Get-RegistryUser {
param(
[Parameter(Mandatory)]
[Microsoft.Win32.RegistryView] $RegistryView,
[Parameter(Mandatory)]
[string] $RegistryPath,
[Parameter(Mandatory)]
[string] $UserNameValue,
[Parameter(Mandatory)]
[string] $DomainValue,
[Parameter(Mandatory)]
[string] $Source,
[switch] $RequireInstallerCreatedUser
)
$baseKey = $null
$registryKey = $null
try {
$baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey(
[Microsoft.Win32.RegistryHive]::LocalMachine,
$RegistryView
)
$registryKey = $baseKey.OpenSubKey($RegistryPath, $false)
if ($null -eq $registryKey) {
return
}
if (
$RequireInstallerCreatedUser -and
-not (Test-EnabledRegistryValue `
-Value $registryKey.GetValue('CREATESITEKIOSKUSER'))
) {
return
}
$userName = $registryKey.GetValue($UserNameValue) -as [string]
$domain = $registryKey.GetValue($DomainValue) -as [string]
if ([string]::IsNullOrWhiteSpace($userName)) {
return
}
[PSCustomObject]@{
UserName = $userName
Domain = $domain
Source = $Source
}
}
finally {
if ($null -ne $registryKey) {
$registryKey.Dispose()
}
if ($null -ne $baseKey) {
$baseKey.Dispose()
}
}
}
function ConvertTo-ResolvedUser {
param(
[Parameter(Mandatory)]
[PSCustomObject] $Candidate,
[switch] $IgnoreResolutionFailure
)
$candidateSid = $Candidate.PSObject.Properties['Sid']
if (
$null -ne $candidateSid -and
-not [string]::IsNullOrWhiteSpace($candidateSid.Value)
) {
try {
$securityIdentifier = [System.Security.Principal.SecurityIdentifier]::new(
$candidateSid.Value
)
$resolvedAccount = $securityIdentifier.Translate(
[System.Security.Principal.NTAccount]
).Value
}
catch {
$message = (
"The SID '$($candidateSid.Value)' from " +
"'$($Candidate.Source)' could not be resolved: " +
$_.Exception.Message
)
if ($IgnoreResolutionFailure) {
Write-RepairWarning $message
return
}
throw $message
}
$separator = $resolvedAccount.IndexOf('\')
$resolvedDomain = if ($separator -ge 0) {
$resolvedAccount.Substring(0, $separator)
}
else {
''
}
$resolvedUserName = if ($separator -ge 0) {
$resolvedAccount.Substring($separator + 1)
}
else {
$resolvedAccount
}
return [PSCustomObject]@{
UserName = $resolvedUserName
Domain = $resolvedDomain
Sid = $securityIdentifier.Value
Sources = @($Candidate.Source)
}
}
$userName = $Candidate.UserName.Trim()
$domain = $Candidate.Domain
$qualifiedSeparator = $userName.IndexOf('\')
if ($qualifiedSeparator -ge 0) {
if (-not [string]::IsNullOrWhiteSpace($domain)) {
throw (
"The account '$userName' is already qualified. " +
'Do not specify Domain as well.'
)
}
$domain = $userName.Substring(0, $qualifiedSeparator)
$userName = $userName.Substring($qualifiedSeparator + 1)
if ([string]::IsNullOrWhiteSpace($userName)) {
throw "The qualified account name does not contain a user name."
}
}
if (
[string]::IsNullOrWhiteSpace($domain) -or
$domain -eq '.'
) {
$domain = $env:COMPUTERNAME
}
$ntAccount = if ($userName.Contains('@')) {
[System.Security.Principal.NTAccount]::new($userName)
}
else {
[System.Security.Principal.NTAccount]::new($domain, $userName)
}
try {
$securityIdentifier = $ntAccount.Translate(
[System.Security.Principal.SecurityIdentifier]
)
$resolvedAccount = $securityIdentifier.Translate(
[System.Security.Principal.NTAccount]
).Value
}
catch {
$message = (
"The account '$domain\$userName' from " +
"'$($Candidate.Source)' could not be resolved: " +
$_.Exception.Message
)
if ($IgnoreResolutionFailure) {
Write-RepairWarning $message
return
}
throw $message
}
$separator = $resolvedAccount.IndexOf('\')
return [PSCustomObject]@{
UserName = if ($separator -ge 0) {
$resolvedAccount.Substring($separator + 1)
}
else {
$resolvedAccount
}
Domain = if ($separator -ge 0) {
$resolvedAccount.Substring(0, $separator)
}
else {
''
}
Sid = $securityIdentifier.Value
Sources = @($Candidate.Source)
}
}
function Test-RunningElevated {
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [System.Security.Principal.WindowsPrincipal]::new($identity)
return $principal.IsInRole(
[System.Security.Principal.WindowsBuiltInRole]::Administrator
)
}
function Get-RegistrySidUser {
param(
[Parameter(Mandatory)]
[Microsoft.Win32.RegistryView] $RegistryView,
[Parameter(Mandatory)]
[string] $RegistryPath,
[Parameter(Mandatory)]
[string] $SidValue,
[Parameter(Mandatory)]
[string] $Source
)
$baseKey = $null
$registryKey = $null
try {
$baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey(
[Microsoft.Win32.RegistryHive]::LocalMachine,
$RegistryView
)
$registryKey = $baseKey.OpenSubKey($RegistryPath, $false)
if ($null -eq $registryKey) {
return
}
$sid = $registryKey.GetValue($SidValue) -as [string]
if ([string]::IsNullOrWhiteSpace($sid)) {
return
}
[PSCustomObject]@{
Sid = $sid
Source = $Source
}
}
finally {
if ($null -ne $registryKey) {
$registryKey.Dispose()
}
if ($null -ne $baseKey) {
$baseKey.Dispose()
}
}
}
function Get-SiteKioskUsers {
$candidates = @(
foreach ($registryView in Get-RegistryViews) {
Get-RegistryUser `
-RegistryView $registryView `
-RegistryPath $siteKioskSettingsPath `
-UserNameValue 'UserName' `
-DomainValue 'Domain' `
-Source 'Currently configured SiteKiosk Online user'
Get-RegistryUser `
-RegistryView $registryView `
-RegistryPath $installerSettingsPath `
-UserNameValue 'SITEKIOSKUSERNAME' `
-DomainValue 'SITEKIOSKUSERDOMAIN' `
-Source 'SiteKiosk Online user created by the installer' `
-RequireInstallerCreatedUser
}
# SiteKiosk Classic is a 32-bit application and stores the SID of its
# restricted user directly in this registry view.
Get-RegistrySidUser `
-RegistryView ([Microsoft.Win32.RegistryView]::Registry32) `
-RegistryPath $classicSecurityWizardPath `
-SidValue 'RestrictedUser' `
-Source 'Restricted SiteKiosk Classic user'
# The Classic installer always creates this local account. Keep it as a
# separate candidate because the administrator may later configure a
# different restricted user while the installer-created profile remains.
[PSCustomObject]@{
UserName = 'SiteKiosk'
Domain = '.'
Source = 'SiteKiosk Classic user created by the installer'
}
)
$usersBySid = @{}
foreach ($candidate in $candidates) {
$user = ConvertTo-ResolvedUser `
-Candidate $candidate `
-IgnoreResolutionFailure
if ($null -eq $user) {
continue
}
if (-not $usersBySid.ContainsKey($user.Sid)) {
$usersBySid[$user.Sid] = $user
}
else {
$existing = $usersBySid[$user.Sid]
if ($existing.Sources -notcontains $candidate.Source) {
$existing.Sources += $candidate.Source
}
}
}
return @($usersBySid.Values)
}
function Get-OrRepairProfilePath {
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)]
[string] $Sid,
[Parameter(Mandatory)]
[string] $AccountName
)
# ProfileList is operating-system state. On a 64-bit system the native
# 64-bit view is authoritative, regardless of which SiteKiosk edition
# supplied the user account information.
$registryView = if ([Environment]::Is64BitOperatingSystem) {
[Microsoft.Win32.RegistryView]::Registry64
}
else {
[Microsoft.Win32.RegistryView]::Registry32
}
$profileListPath = (
'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
)
$baseKey = $null
$profileListKey = $null
$profileKey = $null
$backupKey = $null
try {
$baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey(
[Microsoft.Win32.RegistryHive]::LocalMachine,
$registryView
)
$profileListKey = $baseKey.OpenSubKey($profileListPath, $true)
if ($null -eq $profileListKey) {
throw 'The Windows ProfileList registry key could not be opened.'
}
$profileKey = $profileListKey.OpenSubKey($Sid, $false)
$backupKey = $profileListKey.OpenSubKey("$Sid.bak", $false)
if ($null -ne $profileKey -and $null -ne $backupKey) {
throw (
"Both ProfileList entries '$Sid' and '$Sid.bak' exist. " +
'This state is ambiguous and was not modified.'
)
}
$sourceKey = if ($null -ne $profileKey) {
$profileKey
}
else {
$backupKey
}
if ($null -eq $sourceKey) {
# The account may never have had a profile.
return $null
}
$rawPath = $sourceKey.GetValue(
'ProfileImagePath',
$null,
[Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames
) -as [string]
if ([string]::IsNullOrWhiteSpace($rawPath)) {
throw (
"The ProfileList entry for $Sid does not contain " +
'a ProfileImagePath value.'
)
}
$profilePath = [Environment]::ExpandEnvironmentVariables($rawPath)
if (-not [System.IO.Path]::IsPathRooted($profilePath)) {
throw (
"The ProfileList entry for $Sid contains a non-absolute " +
"ProfileImagePath: $profilePath"
)
}
if ($null -ne $profileKey) {
return $profilePath
}
if (-not (Test-Path -LiteralPath $profilePath -PathType Container)) {
throw (
"The .bak entry for $Sid refers to a missing profile " +
"directory: $profilePath. This script cannot repair this " +
'problem. Wait for a newer SiteKiosk installer that can ' +
'create the required user profile.'
)
}
if (-not (Test-Path -LiteralPath (Join-Path $profilePath 'NTUSER.DAT') -PathType Leaf)) {
throw (
"The .bak entry for $Sid refers to '$profilePath', but " +
'NTUSER.DAT is missing. The registration was not restored.'
)
}
if ($backupKey.SubKeyCount -ne 0) {
throw (
"The ProfileList .bak entry for $Sid contains unexpected " +
'subkeys. The registration was not restored automatically.'
)
}
$normalizedProfilePath = (
[System.IO.Path]::GetFullPath($profilePath)
).TrimEnd('\')
foreach ($otherKeyName in $profileListKey.GetSubKeyNames()) {
if (
$otherKeyName -ieq $Sid -or
$otherKeyName -ieq "$Sid.bak"
) {
continue
}
$otherKey = $null
try {
$otherKey = $profileListKey.OpenSubKey($otherKeyName, $false)
if ($null -eq $otherKey) {
continue
}
$otherRawPath = $otherKey.GetValue(
'ProfileImagePath',
$null,
[Microsoft.Win32.RegistryValueOptions]::
DoNotExpandEnvironmentNames
) -as [string]
if ([string]::IsNullOrWhiteSpace($otherRawPath)) {
continue
}
$otherProfilePath = [System.IO.Path]::GetFullPath(
[Environment]::ExpandEnvironmentVariables($otherRawPath)
).TrimEnd('\')
if (
[string]::Equals(
$normalizedProfilePath,
$otherProfilePath,
[StringComparison]::OrdinalIgnoreCase
)
) {
throw (
"ProfileList entry '$otherKeyName' also refers to " +
"'$profilePath'. The .bak entry was not restored."
)
}
}
finally {
if ($null -ne $otherKey) {
$otherKey.Dispose()
}
}
}
$profileIsLoaded = Test-Path -LiteralPath "Registry::HKEY_USERS\$Sid"
if ($profileIsLoaded -and -not $WhatIfPreference) {
throw (
"The profile of '$AccountName' is currently loaded. " +
'Sign out the user before restoring its ProfileList entry.'
)
}
if ($profileIsLoaded) {
Write-RepairWarning (
"The profile of '$AccountName' is currently loaded. " +
'WhatIf will only preview the ProfileList repair.'
)
}
$registryTarget = (
"HKLM:\$profileListPath\$Sid.bak"
)
if (
$PSCmdlet.ShouldProcess(
$registryTarget,
"Restore the regular ProfileList entry for $AccountName"
)
) {
if (Test-Path -LiteralPath "Registry::HKEY_USERS\$Sid") {
throw (
"The profile of '$AccountName' was loaded while the " +
'repair was being prepared. Sign out the user and try again.'
)
}
$lateProfileKey = $null
try {
$lateProfileKey = $profileListKey.OpenSubKey($Sid, $false)
if ($null -ne $lateProfileKey) {
throw (
"A regular ProfileList entry for $Sid appeared while " +
'the repair was being prepared. Nothing was modified.'
)
}
}
finally {
if ($null -ne $lateProfileKey) {
$lateProfileKey.Dispose()
}
}
Write-RepairHost (
"Restoring ProfileList entry: $Sid.bak -> $Sid"
)
$newProfileKey = $null
$destinationCreated = $false
try {
$newProfileKey = $profileListKey.CreateSubKey($Sid)
if ($null -eq $newProfileKey) {
throw "Unable to create the ProfileList entry for $Sid."
}
$destinationCreated = $true
foreach ($valueName in $backupKey.GetValueNames()) {
$value = $backupKey.GetValue(
$valueName,
$null,
[Microsoft.Win32.RegistryValueOptions]::
DoNotExpandEnvironmentNames
)
$valueKind = $backupKey.GetValueKind($valueName)
$newProfileKey.SetValue($valueName, $value, $valueKind)
}
$newProfileKey.SetValue(
'State',
0,
[Microsoft.Win32.RegistryValueKind]::DWord
)
$newProfileKey.SetValue(
'RefCount',
0,
[Microsoft.Win32.RegistryValueKind]::DWord
)
$newProfileKey.Flush()
$restoredRawPath = $newProfileKey.GetValue(
'ProfileImagePath',
$null,
[Microsoft.Win32.RegistryValueOptions]::
DoNotExpandEnvironmentNames
) -as [string]
if (-not [string]::Equals(
$rawPath,
$restoredRawPath,
[StringComparison]::OrdinalIgnoreCase
)) {
throw 'The restored ProfileImagePath could not be verified.'
}
$newProfileKey.Dispose()
$newProfileKey = $null
$backupKey.Dispose()
$backupKey = $null
$profileListKey.DeleteSubKeyTree("$Sid.bak", $false)
}
catch {
if ($null -ne $newProfileKey) {
$newProfileKey.Dispose()
$newProfileKey = $null
}
if ($destinationCreated) {
try {
$profileListKey.DeleteSubKeyTree($Sid, $false)
}
catch {
Write-RepairWarning (
"Rollback of the new ProfileList entry '$Sid' " +
'also failed. Inspect ProfileList manually.'
)
}
}
throw
}
}
return $profilePath
}
finally {
if ($null -ne $backupKey) {
$backupKey.Dispose()
}
if ($null -ne $profileKey) {
$profileKey.Dispose()
}
if ($null -ne $profileListKey) {
$profileListKey.Dispose()
}
if ($null -ne $baseKey) {
$baseKey.Dispose()
}
}
}
function Repair-DirectFileInheritance {
param(
[Parameter(Mandatory)]
[string] $Path,
[Parameter(Mandatory)]
[System.Security.Principal.SecurityIdentifier] $SecurityIdentifier
)
$security = [System.IO.Directory]::GetAccessControl(
$Path,
[System.Security.AccessControl.AccessControlSections]::Access
)
$rules = @(
$security.GetAccessRules(
$true,
$false,
[System.Security.Principal.SecurityIdentifier]
) | Where-Object {
$_.IdentityReference -eq $SecurityIdentifier -and
-not $_.IsInherited
}
)
$requiredMask = [int] $script:requiredFileRights
$requiredDirectoryMask = [int] $script:requiredDirectoryRights
$changed = $false
foreach ($rule in $rules) {
$appliesToFiles = (
$rule.InheritanceFlags -band
[System.Security.AccessControl.InheritanceFlags]::ObjectInherit
) -ne 0
$appliesToDirectory = (
$rule.PropagationFlags -band
[System.Security.AccessControl.PropagationFlags]::InheritOnly
) -eq 0
if (
$rule.AccessControlType -ne
[System.Security.AccessControl.AccessControlType]::Deny
) {
continue
}
$conflictingFileMask = if ($appliesToFiles) {
([int] $rule.FileSystemRights) -band $requiredMask
}
else {
0
}
$conflictingDirectoryMask = if ($appliesToDirectory) {
([int] $rule.FileSystemRights) -band $requiredDirectoryMask
}
else {
0
}
$conflictingMask = (
$conflictingFileMask -bor $conflictingDirectoryMask
)
if ($conflictingMask -eq 0) {
continue
}
[void] $security.RemoveAccessRuleSpecific($rule)
$remainingMask = (
[int] $rule.FileSystemRights
) -band (-bnot $requiredMask)
if ($remainingMask -ne 0) {
$security.AddAccessRule(
[System.Security.AccessControl.FileSystemAccessRule]::new(
$SecurityIdentifier,
[System.Security.AccessControl.FileSystemRights] $remainingMask,
$rule.InheritanceFlags,
$rule.PropagationFlags,
[System.Security.AccessControl.AccessControlType]::Deny
)
)
}
$directoryOnlyMask = if ($appliesToDirectory) {
$conflictingFileMask -band (-bnot $requiredDirectoryMask)
}
else {
0
}
if ($directoryOnlyMask -ne 0) {
$security.AddAccessRule(
[System.Security.AccessControl.FileSystemAccessRule]::new(
$SecurityIdentifier,
[System.Security.AccessControl.FileSystemRights] $directoryOnlyMask,
[System.Security.AccessControl.AccessControlType]::Deny
)
)
}
$childDirectoryMask = if (
($rule.InheritanceFlags -band
[System.Security.AccessControl.InheritanceFlags]::ContainerInherit
) -ne 0
) {
$conflictingMask
}
else {
0
}
if (
$childDirectoryMask -ne 0
) {
$childPropagation = (
[System.Security.AccessControl.PropagationFlags]::InheritOnly -bor
($rule.PropagationFlags -band
[System.Security.AccessControl.PropagationFlags]::NoPropagateInherit
)
)
$security.AddAccessRule(
[System.Security.AccessControl.FileSystemAccessRule]::new(
$SecurityIdentifier,
[System.Security.AccessControl.FileSystemRights] $childDirectoryMask,
[System.Security.AccessControl.InheritanceFlags]::ContainerInherit,
$childPropagation,
[System.Security.AccessControl.AccessControlType]::Deny
)
)
}
$changed = $true
}
$allowedMask = 0
foreach ($rule in $rules) {
$isDirectFileRule = (
$rule.AccessControlType -eq
[System.Security.AccessControl.AccessControlType]::Allow -and
($rule.InheritanceFlags -band
[System.Security.AccessControl.InheritanceFlags]::ObjectInherit
) -ne 0 -and
($rule.InheritanceFlags -band
[System.Security.AccessControl.InheritanceFlags]::ContainerInherit
) -eq 0 -and
($rule.PropagationFlags -band
[System.Security.AccessControl.PropagationFlags]::InheritOnly
) -ne 0 -and
($rule.PropagationFlags -band
[System.Security.AccessControl.PropagationFlags]::NoPropagateInherit
) -ne 0
)
if ($isDirectFileRule) {
$allowedMask = $allowedMask -bor [int] $rule.FileSystemRights
}
}
$missingMask = $requiredMask -band (-bnot $allowedMask)
if ($missingMask -ne 0) {
# ObjectInherit without ContainerInherit targets files only;
# NoPropagateInherit limits the rule to this directory level.
$security.AddAccessRule(
[System.Security.AccessControl.FileSystemAccessRule]::new(
$SecurityIdentifier,
[System.Security.AccessControl.FileSystemRights] $missingMask,
[System.Security.AccessControl.InheritanceFlags]::ObjectInherit,
(
[System.Security.AccessControl.PropagationFlags]::InheritOnly -bor
[System.Security.AccessControl.PropagationFlags]::NoPropagateInherit
),
[System.Security.AccessControl.AccessControlType]::Allow
)
)
$changed = $true
}
$allowedDirectoryMask = 0
foreach ($rule in $rules) {
$appliesToDirectory = (
$rule.PropagationFlags -band
[System.Security.AccessControl.PropagationFlags]::InheritOnly
) -eq 0
if (
$rule.AccessControlType -eq
[System.Security.AccessControl.AccessControlType]::Allow -and
$appliesToDirectory
) {
$allowedDirectoryMask = (
$allowedDirectoryMask -bor [int] $rule.FileSystemRights
)
}
}
$missingDirectoryMask = (
$requiredDirectoryMask -band (-bnot $allowedDirectoryMask)
)
if ($missingDirectoryMask -ne 0) {
$security.AddAccessRule(
[System.Security.AccessControl.FileSystemAccessRule]::new(
$SecurityIdentifier,
[System.Security.AccessControl.FileSystemRights] $missingDirectoryMask,
[System.Security.AccessControl.AccessControlType]::Allow
)
)
$changed = $true
}
if ($changed) {
[System.IO.Directory]::SetAccessControl($Path, $security)
}
}
function Repair-ProfileFile {
param(
[Parameter(Mandatory)]
[System.IO.FileInfo] $File,
[Parameter(Mandatory)]
[System.Security.Principal.SecurityIdentifier] $SecurityIdentifier
)
if (
($File.Attributes -band [System.IO.FileAttributes]::ReadOnly) -ne 0
) {
$File.Attributes = (
$File.Attributes -band (-bnot [System.IO.FileAttributes]::ReadOnly)
)
}
$security = [System.IO.File]::GetAccessControl(
$File.FullName,
[System.Security.AccessControl.AccessControlSections]::Access
)
$explicitRules = @(
$security.GetAccessRules(
$true,
$false,
[System.Security.Principal.SecurityIdentifier]
) | Where-Object {
$_.IdentityReference -eq $SecurityIdentifier -and
-not $_.IsInherited
}
)
$requiredMask = [int] $script:requiredFileRights
$changed = $false
foreach ($rule in $explicitRules) {
if (
$rule.AccessControlType -ne
[System.Security.AccessControl.AccessControlType]::Deny
) {
continue
}
$conflictingMask = ([int] $rule.FileSystemRights) -band $requiredMask
if ($conflictingMask -eq 0) {
continue
}
[void] $security.RemoveAccessRuleSpecific($rule)
$remainingMask = (
[int] $rule.FileSystemRights
) -band (-bnot $requiredMask)
if ($remainingMask -ne 0) {
$security.AddAccessRule(
[System.Security.AccessControl.FileSystemAccessRule]::new(
$SecurityIdentifier,
[System.Security.AccessControl.FileSystemRights] $remainingMask,
$rule.AccessControlType
)
)
}
$changed = $true
}
$allowedMask = 0
$allowRules = $security.GetAccessRules(
$true,
$true,
[System.Security.Principal.SecurityIdentifier]
) | Where-Object {
$_.IdentityReference -eq $SecurityIdentifier -and
$_.AccessControlType -eq
[System.Security.AccessControl.AccessControlType]::Allow
}
foreach ($rule in $allowRules) {
$allowedMask = $allowedMask -bor [int] $rule.FileSystemRights
}
$missingMask = $requiredMask -band (-bnot $allowedMask)
if ($missingMask -ne 0) {
$security.AddAccessRule(
[System.Security.AccessControl.FileSystemAccessRule]::new(
$SecurityIdentifier,
[System.Security.AccessControl.FileSystemRights] $missingMask,
[System.Security.AccessControl.AccessControlType]::Allow
)
)
$changed = $true
}
if ($changed) {
[System.IO.File]::SetAccessControl($File.FullName, $security)
}
}
function Repair-SiteKioskProfile {
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)]
[PSCustomObject] $User
)
Write-RepairHost ''
Write-RepairHost '----------------------------------------'
Write-RepairHost "Sources: $($User.Sources -join ', ')"
Write-RepairHost "User: $($User.Domain)\$($User.UserName)"
Write-RepairHost "SID: $($User.Sid)"
$profilePath = Get-OrRepairProfilePath `
-Sid $User.Sid `
-AccountName "$($User.Domain)\$($User.UserName)"
if ([string]::IsNullOrWhiteSpace($profilePath)) {
throw (
'No user profile exists for this account yet. This script cannot ' +
'repair this problem. Wait for a newer SiteKiosk installer that ' +
'can create the required user profile.'
)
}
Write-RepairHost "Profile: $profilePath"
if (-not (Test-Path -LiteralPath $profilePath -PathType Container)) {
throw (
"The registered user profile does not exist: $profilePath. " +
'This script cannot repair this problem. Wait for a newer ' +
'SiteKiosk installer that can create the required user profile.'
)
}
if (
(Test-Path -LiteralPath "Registry::HKEY_USERS\$($User.Sid)") -and
-not $WhatIfPreference
) {
throw (
"The profile of '$($User.Domain)\$($User.UserName)' " +
'is currently loaded. Sign out the user and run the ' +
'script again.'
)
}
if (Test-Path -LiteralPath "Registry::HKEY_USERS\$($User.Sid)") {
Write-RepairWarning (
"The profile of '$($User.Domain)\$($User.UserName)' is " +
'currently loaded. WhatIf will only preview the repair.'
)
}
$locations = @(
$profilePath,
(Join-Path $profilePath 'AppData\Local\Microsoft\Windows')
)
$files = foreach ($location in $locations) {
if (Test-Path -LiteralPath $location -PathType Container) {
Get-ChildItem `
-LiteralPath $location `
-Force `
-File
}
}
$files = @($files | Sort-Object FullName -Unique)
# NTUSER.DAT and UsrClass.dat may not exist yet. Repair all files that are
# present without treating missing profile hive files as an error.
$securityIdentifier = [System.Security.Principal.SecurityIdentifier]::new(
$User.Sid
)
foreach ($location in $locations) {
if (-not (Test-Path -LiteralPath $location -PathType Container)) {
continue
}
if (
$PSCmdlet.ShouldProcess(
$location,
'Repair access inheritance for direct profile files'
)
) {
Write-RepairHost "Repairing direct-file inheritance: $location"
Repair-DirectFileInheritance `
-Path $location `
-SecurityIdentifier $securityIdentifier
}
}
foreach ($file in $files) {
if (
$PSCmdlet.ShouldProcess(
$file.FullName,
'Repair user profile permissions'
)
) {
Write-RepairHost "Repairing: $($file.FullName)"
Repair-ProfileFile `
-File $file `
-SecurityIdentifier $securityIdentifier
}
}
}
Initialize-RepairLog
if (-not [string]::IsNullOrWhiteSpace($repairLogPath)) {
Write-RepairHost "Log file: $repairLogPath"
}
try {
if (-not (Test-RunningElevated)) {
throw (
'Administrator privileges are required. Open PowerShell with ' +
'"Run as administrator" and execute the script again.'
)
}
$users = @(
if ($PSCmdlet.ParameterSetName -eq 'Explicit') {
ConvertTo-ResolvedUser -Candidate ([PSCustomObject]@{
UserName = $UserName
Domain = $Domain
Source = 'Explicitly specified user'
})
}
else {
Get-SiteKioskUsers
}
)
if ($users.Count -eq 0) {
if ($PSCmdlet.ParameterSetName -eq 'Explicit') {
throw "The specified account '$Domain\$UserName' was not found."
}
else {
throw (
'No configured SiteKiosk Online user, installer-created SiteKiosk Online ' +
'user, restricted SiteKiosk Classic user, or installer-created ' +
'SiteKiosk Classic user was found.'
)
}
}
$failedUsers = @()
foreach ($user in $users) {
try {
Repair-SiteKioskProfile -User $user
}
catch {
$failedUsers += $user
Write-RepairError (
"The repair failed for '$($user.Domain)\$($user.UserName)': " +
$_.Exception.Message
)
}
}
if ($failedUsers.Count -gt 0) {
throw (
"The repair failed for $($failedUsers.Count) user profile(s)."
)
}
Write-RepairHost ''
Write-RepairHost 'All requested user profiles have been processed.'
if ($Restart) {
$computerName = if ([string]::IsNullOrWhiteSpace($env:COMPUTERNAME)) {
'the local computer'
}
else {
$env:COMPUTERNAME
}
if ($PSCmdlet.ShouldProcess($computerName, 'Restart computer')) {
Write-RepairHost "Restarting computer '$computerName'."
Restart-Computer -Force -Confirm:$false
}
else {
Write-RepairHost "The requested restart of '$computerName' was not performed."
}
}
}
catch {
if (-not $script:repairErrorWasLogged) {
Write-RepairLog -Level ERROR -Message $_.Exception.ToString()
}
throw
}
Redémarrez ensuite l’ordinateur :
#PowerShell Command Restart-Computer -Force
Contact
Pour toute question supplémentaire, veuillez contacter notre équipe d’assistance au +49 (251) 846924-24 ou à l’adresse support-europe@sitekiosk.com.