Debido a una actualización de Windows distribuida por Microsoft durante la noche del 12 de agosto de 2026, el modo de inicio automático con el usuario de SiteKiosk ya no funciona correctamente.
Causa
El problema se debe a las restricciones de permisos aplicadas por SiteKiosk a la cuenta de usuario de SiteKiosk. Estas restricciones impiden que la actualización de Windows complete correctamente y en su totalidad todos los pasos necesarios para la cuenta de usuario afectada. Como consecuencia, no se puede cargar NTUSER.DAT y el inicio automático queda bloqueado.
Actualización del 17 de agosto de 2026:
Con la nueva versión 1.10.341.0 del Cliente SiteKiosk Online, esta corrección ya está disponible de forma predeterminada.
Solución alternativa actualizada
Actualización del 17 de agosto de 2026:
Hemos revisado la solución alternativa anterior y ponemos a disposición un nuevo script de PowerShell.
Importante:
Siempre que sea posible, recomendamos instalar a través del instalador actual de SiteKiosk, ya que la corrección ya está incluida en él de forma predeterminada. Si en un caso concreto no es posible utilizar el instalador, puede aplicarse en su lugar la solución provisional actualizada que se indica a continuación.
El script actualizado debe ejecutarse de nuevo después de cada nueva instalación de SiteKiosk.
Como solución alternativa temporal, recomendamos ejecutar el siguiente script de PowerShell en un equipo afectado, dentro de una sesión de PowerShell con privilegios de administrador.
El nuevo script sustituye al hotfix publicado anteriormente y tiene en cuenta escenarios adicionales al reparar el perfil de usuario de SiteKiosk. Nuestro equipo de desarrollo continúa trabajando en una solución definitiva. Informaremos sobre cualquier cambio adicional tan pronto como haya nueva información disponible.
Asegúrese de que el usuario de SiteKiosk haya cerrado sesión por completo antes de ejecutar el script.
Procedimiento para SiteKiosk Online
Actualización del 17 de agosto de 2026:
Con la nueva versión 1.10.341.0 del Cliente SiteKiosk Online, esta corrección ya está disponible de forma predeterminada.
12 de agosto de 2026
Por motivos de transparencia: el 12 de agosto de 2026 distribuimos de forma automática un script simplificado a todos los clientes conectados en ese momento.
Alternativamente, la solución puede aplicarse de forma remota para cada cliente de forma individual, por ejemplo a través de la Recovery Shell de un cliente afectado:
Monitoring > [Client] > Administration > Recovery Shell
Procedimiento para SiteKiosk Classic Windows
Actualización del 19 de agosto de 2026:
Con la nueva versión 9.10.10010 del cliente SiteKiosk Classic, la corrección ya está incluida de forma predeterminada.
Importante:
Siempre que sea posible, recomendamos realizar la instalación mediante el instalador actual de SiteKiosk, ya que la corrección ya está incluida de forma predeterminada. Si en un caso concreto no es posible utilizar el instalador, puede aplicarse como alternativa la solución temporal actualizada del 17 de agosto de 2026 que se indica a continuación.
Con SiteKiosk Classic Windows, el script debe ejecutarse localmente utilizando una cuenta de administrador:
1. Primero, desbloquee el bloqueo del teclado. Instructions: Unlocking the keyboard lock
2. A continuación, inicie sesión en el sistema utilizando una cuenta de administrador.
3. Inicie PowerShell ISE con permisos administrativos y ejecute el 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
}
A continuación, reinicie el equipo:
#PowerShell Command Restart-Computer -Force
Contacto
Si tiene alguna otra pregunta, póngase en contacto con nuestro equipo de soporte en el +49 (251) 846924-24 o en support-europe@sitekiosk.com.