diff --git a/scripts/TargetedSaclPlanning.ps1 b/scripts/TargetedSaclPlanning.ps1 index 09723f6b..2835669e 100644 --- a/scripts/TargetedSaclPlanning.ps1 +++ b/scripts/TargetedSaclPlanning.ps1 @@ -29,7 +29,8 @@ function Get-WelaSaclUserInventory { } $path = $null; $message = '' try { - $rawPath = [string](Get-ItemProperty -LiteralPath $key.PSPath -Name ProfileImagePath -ErrorAction Stop).ProfileImagePath + $profileKey = Get-Item -LiteralPath $key.PSPath -ErrorAction Stop + $rawPath = [string]$profileKey.GetValue('ProfileImagePath', $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) $path = Expand-WelaSaclProfilePath $rawPath } catch { $path = $null; $message = "Profile path unavailable: $($_.Exception.Message)" @@ -38,7 +39,8 @@ function Get-WelaSaclUserInventory { $users.Add([pscustomobject]@{ Sid = $sid; ProfilePath = $path; HiveLoaded = $loaded.ContainsKey($sid); Diagnostic = $message }) $loaded.Remove($sid) } - $default = Expand-WelaSaclProfilePath ([string](Get-ItemProperty -LiteralPath $profileRoot -Name Default -ErrorAction Stop).Default) + $profileListKey = Get-Item -LiteralPath $profileRoot -ErrorAction Stop + $default = Expand-WelaSaclProfilePath ([string]$profileListKey.GetValue('Default', $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)) $users.Add([pscustomobject]@{ Sid = 'Default'; ProfilePath = $default; HiveLoaded = $false; Diagnostic = 'Future-user template; hive is not loaded by planning.' }) } catch { $diagnostics.Add("Profile inventory incomplete: $($_.Exception.Message)") } foreach ($sid in $loaded.Keys) { diff --git a/tests/TargetedSaclPlanning.Tests.ps1 b/tests/TargetedSaclPlanning.Tests.ps1 index 406f30e9..7dc3fe4e 100644 --- a/tests/TargetedSaclPlanning.Tests.ps1 +++ b/tests/TargetedSaclPlanning.Tests.ps1 @@ -84,12 +84,15 @@ function Get-ChildItem { [pscustomobject]@{PSChildName='S-1-5-21-1';PSPath='Registry::profile-one'} } $script:profilePath = $null -function Get-ItemProperty { - param($LiteralPath,$Name,$ErrorAction) - if ($Name -eq 'Default') { return [pscustomobject]@{Default='C:\Users\Default'} } +$script:profileKey = [pscustomobject]@{} +$script:profileKey | Add-Member ScriptMethod GetValue { + param($Name,$Default,$Options) + if ($Options -ne [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) { throw 'ProfileList read must preserve unexpanded tokens.' } + if ($Name -eq 'Default') { return 'C:\Users\Default' } if ($null -eq $script:profilePath) { throw 'Profile path denied' } - [pscustomobject]@{ProfileImagePath=$script:profilePath} + return $script:profilePath } +function Get-Item { param($LiteralPath,[switch]$Force,$ErrorAction) return $script:profileKey } $inventory = Get-WelaSaclUserInventory Assert (-not $inventory.Complete -and $inventory.Diagnostics.Count -gt 0 -and $inventory.Users[0].ProfilePath -eq $null) 'Unreadable per-user profile path must not yield complete inventory.' $script:profilePath = '%USERPROFILE%\AnotherProfile' @@ -97,7 +100,7 @@ $inventory = Get-WelaSaclUserInventory Assert (-not $inventory.Complete -and $inventory.Users[0].ProfilePath -eq $null) 'ProfileList must not expand operator USERPROFILE for another user.' $script:profilePath = 'C:\Users\One' Assert (Get-WelaSaclUserInventory).Complete 'Known absolute profiles and Default form a complete inventory.' -Remove-Item Function:Get-ChildItem, Function:Get-ItemProperty +Remove-Item Function:Get-ChildItem # Guard mapped drives and every ancestor before any descendants or ACL read. $script:accessed = @(); $script:aclCalls = 0; $script:remoteDrive = $false function Get-PSDrive { param($Name,$PSProvider,$ErrorAction) [pscustomobject]@{Root='C:\';DisplayRoot=$(if ($script:remoteDrive) {'\\server\share'} else {$null})} }