WindowsMize - PowerShell script to automate and customize the configuration of Windows


My Computer

System One

  • OS
    Windows 11 2H25
    Computer type
    PC/Desktop
    Manufacturer/Model
    DIY
    CPU
    AMD 9900X
    Motherboard
    MSI X870E Carbon
    Memory
    64 GB
    Graphics Card(s)
    AMD 9070 XT
    Sound Card
    built-in
    Monitor(s) Displays
    Dell 24"
    Hard Drives
    Sabrent 1 TB NVMe, 4 x SSD (need to check models), 4 x 3.5" HDD, 8-16 TB, all WD
    PSU
    Seasonic 850
    Case
    Fractal Design North XL (which I likw)
    Cooling
    Corsair AIO for CPU, fans for case
    Keyboard
    Das Keyboard 4
    Mouse
    Corsair M65 (white)
    Internet Speed
    1 TB download
    Browser
    Firefox
    Antivirus
    Bitdefender
    Other Info
    Also have Lenovo T14S laptop (me) and Lenovo Slim 71 (wife)
@garlin
thank you, really appreciated.

@x509
I don't understand your post as you quoted only the 'keep in mind ...'
Did you want to quote the whole OAT's post?
which can be resumed by the second sentence:
"However, your script is not adapted to the target audience; the end user."

With the new version of the project, I think it is now adapted to everyone ?
(Except for users that want/prefer a GUI)

I also made a short usage note at the top of WindowsMize.ps1
Code:
#==============================================================================
#                                    Usage
#==============================================================================
#region usage

<#
  To don't run a function, comment it (i.e. Add the "#" character before it).
  e.g. #Disable-PowerShellTelemetry
  To run a function, uncomment it (i.e. Remove the "#" character before it).
  e.g. Disable-PowerShellTelemetry

  Mostly all functions have a '-State' and/or '-GPO' parameters.
  Example:
  # Bing Search in Start Menu
  #---------------------------------------
  # State: Disabled | Enabled (default)
  # GPO: Disabled | NotConfigured
  Set-StartMenuBingSearch -State 'Disabled' -GPO 'Disabled'

  The 2 comments below the title are the accepted values for the parameters.
  Change the parameters value according to your preferences.
  e.g.
  Set-StartMenuBingSearch -State 'Enabled' -GPO 'NotConfigured'
#>

#endregion usage

It's minimal but clear enought in my opinion.
It is not enought ?
 

My Computer

System One

  • OS
    .
More feedback to improve the user experience:
1. Don't refer to "PowerShell Core", instead use the friendly name PowerShell 7.

2. Add "--accept-package-agreements --accept-source-agreements" to the winget command line.

3. Write a short batch file which does GitHub steps 2-6 for the squeamish. You want to keep the original explanations for transparency, but then allow casual users to just "run this batch as Admin after you've extracted the ZIP file".
 

My Computer

System One

  • OS
    Windows 7
done.
I added two files:
- Download_WindowsMize.ps1 (which also extract the archive).
- Run_WindowsMize.bat (which also install PowerShell 7.

thanks again for your feedback.
 

My Computer

System One

  • OS
    .
@garlin
thank you, really appreciated.

@x509
I don't understand your post as you quoted only the 'keep in mind ...'
Did you want to quote the whole OAT's post?

No I wanted to +1 the point about comments not being meant as criticism.

The various comments in this group are about people who want to help you to improve upon and make more useful to a broader audience your work on this script. A ginormous effort, to quote myself.
 

My Computer

System One

  • OS
    Windows 11 2H25
    Computer type
    PC/Desktop
    Manufacturer/Model
    DIY
    CPU
    AMD 9900X
    Motherboard
    MSI X870E Carbon
    Memory
    64 GB
    Graphics Card(s)
    AMD 9070 XT
    Sound Card
    built-in
    Monitor(s) Displays
    Dell 24"
    Hard Drives
    Sabrent 1 TB NVMe, 4 x SSD (need to check models), 4 x 3.5" HDD, 8-16 TB, all WD
    PSU
    Seasonic 850
    Case
    Fractal Design North XL (which I likw)
    Cooling
    Corsair AIO for CPU, fans for case
    Keyboard
    Das Keyboard 4
    Mouse
    Corsair M65 (white)
    Internet Speed
    1 TB download
    Browser
    Firefox
    Antivirus
    Bitdefender
    Other Info
    Also have Lenovo T14S laptop (me) and Lenovo Slim 71 (wife)
No I wanted to +1 the point about comments not being meant as criticism.
oh, ok. You didnt miss quoted then ^^
I agree that they are not criticism. I don't take them negatively.

In fact, I like negative feedbacks. As you said, it helps to improve.
In this specific case, to improve my project. :)
 

My Computer

System One

  • OS
    .
Hello everyone.

A quick update.
From my latest message, here are the main improvements:

- The README is much more detailed (and also prettier) than the previous version.
It now includes every tweaks/settings that the script can do.​

- The main script has been split into several smaller scripts, which are grouped by category.
Make it easier and faster to customize specific setting.​
Make it also easier to run only specific tweaks/settings.​

- A new "no comment" version of the script has been added: WindowsMize.mini.ps1
Intended for those who prefer a one file with all the settings.​

- And of course, new settings and overall improvements.




@SM03
I've noticed on a few tutorials that you were looking for registry entries about Windows UWP apps.

You might be interrested by the following powershell functions:
Set-UwpAppSetting.ps1
Set-MicrosoftStoreSetting.ps1

There is also other files to automate Photos, Snipping Tool and Notepad.




Could a moderator please edit the first post of this thread with the following content.
It would be really appreciated.

Code:
[CENTER][IMG width="80%"]https://raw.githubusercontent.com/agadiffe/WindowsMize/main/img/WindowsMizeHeader.png[/IMG]
[B]Automate and customize the configuration of Windows.
Debloat, minimize telemetry, apps installation, general settings, and more.[/B][/CENTER]

Hi everyone.

I would like to share with you the PowerShell script I made to automate the configuration of Windows.

It's not just about debloating Windows and minimizing telemetry.
It's also about automating every settings (in a reasonable way :)).

None of the available online scripts met my expectations, so I created my own.

[HEADING=2]🎯 Purpose[/HEADING]
[LIST=1]
[*] Install Windows (semi-unattended) + updates.
[*] Run the script.
[*] Finish some customization.
[/LIST]

[HEADING=2]📝 Characteristics[/HEADING]
[LIST]
[*] Fully non-interactive script: make sure to review everything before running it.
[*] Designed for Windows 11 (most tweaks/settings also work on Windows 10).
[*] Works on both Administrator and Standard account.
[/LIST]

[HEADING=2]💫 Features[/HEADING]
[LIST]
[*] 🖥️ Windows settings
[*] 📁 File Explorer
[*] ⌛ System Properties
[*] ⚡ Power options
[*] 🌐 Network
[*] 📊 Telemetry
[*] 🛠️ Tweaks
[*] 💿 Applications
[*] 💾 RamDisk
[*] ⚙️ Services & Scheduled Tasks
[/LIST]

See the Github README for the detailed list of all tweaks/settings.

[HEADING=2]📌 Link[/HEADING]
https://github.com/agadiffe/WindowsMize
 

My Computer

System One

  • OS
    .
You should really try to inject (Get-Date).ToFileTime() into the UWP reg value's timestamp, instead of leaving them unchanged.
 

My Computer

System One

  • OS
    Windows 7
Hello everyone.

A quick update.
From my latest message, here are the main improvements:

- The README is much more detailed (and also prettier) than the previous version.
It now includes every tweaks/settings that the script can do.​

- The main script has been split into several smaller scripts, which are grouped by category.
Make it easier and faster to customize specific setting.​
Make it also easier to run only specific tweaks/settings.​

- A new "no comment" version of the script has been added: WindowsMize.mini.ps1
Intended for those who prefer a one file with all the settings.​

- And of course, new settings and overall improvements.




@SM03
I've noticed on a few tutorials that you were looking for registry entries about Windows UWP apps.

You might be interrested by the following powershell functions:
Set-UwpAppSetting.ps1
Set-MicrosoftStoreSetting.ps1

There is also other files to automate Photos, Snipping Tool and Notepad.




Could a moderator please edit the first post of this thread with the following content.
It would be really appreciated.

Code:
[CENTER][IMG width="80%"]https://raw.githubusercontent.com/agadiffe/WindowsMize/main/img/WindowsMizeHeader.png[/IMG]
[B]Automate and customize the configuration of Windows.
Debloat, minimize telemetry, apps installation, general settings, and more.[/B][/CENTER]

Hi everyone.

I would like to share with you the PowerShell script I made to automate the configuration of Windows.

It's not just about debloating Windows and minimizing telemetry.
It's also about automating every settings (in a reasonable way :)).

None of the available online scripts met my expectations, so I created my own.

[HEADING=2]🎯 Purpose[/HEADING]
[LIST=1]
[*] Install Windows (semi-unattended) + updates.
[*] Run the script.
[*] Finish some customization.
[/LIST]

[HEADING=2]📝 Characteristics[/HEADING]
[LIST]
[*] Fully non-interactive script: make sure to review everything before running it.
[*] Designed for Windows 11 (most tweaks/settings also work on Windows 10).
[*] Works on both Administrator and Standard account.
[/LIST]

[HEADING=2]💫 Features[/HEADING]
[LIST]
[*] 🖥️ Windows settings
[*] 📁 File Explorer
[*] ⌛ System Properties
[*] ⚡ Power options
[*] 🌐 Network
[*] 📊 Telemetry
[*] 🛠️ Tweaks
[*] 💿 Applications
[*] 💾 RamDisk
[*] ⚙️ Services & Scheduled Tasks
[/LIST]

See the Github README for the detailed list of all tweaks/settings.

[HEADING=2]📌 Link[/HEADING]
https://github.com/agadiffe/WindowsMize
Hey @agadiffe, thanks for tagging.

What's the first Set-UwpAppSetting.ps1 script for? Can you list its functionalities? A clear README/instruction file would be appreciated.

and for 2nd Set-MicrosoftStoreSetting.ps1,
I am actually looking for MS store settings to import/add/integrate inside Windows ISO (WIM) with the help of NTLite, to automate windows installation process, so let me know, how to use this script you share in that context.
 

My Computers

System One System Two

  • OS
    Windows 11 Pro Latest Retail Build
    Computer type
    PC/Desktop
    Manufacturer/Model
    Gaming-Rig (Intel 13th Gen based Self-Assembled)
    CPU
    Intel 13th Gen i5-13600KF
    Motherboard
    MSI PRO Z790-A WIFI DDR5
    Memory
    G-Skill Trident Z5 RGB 32GB Kit (F5-7200J3445G16GX2-TZ5RK) @7200 MT/s CL34
    Graphics Card(s)
    Nvidia GeForce RTX 4060 Ti 16GB OC
    Sound Card
    Motherboard Realtek UDA DTS Audio
    Monitor(s) Displays
    Hisense 43" 4K QLED
    Screen Resolution
    4096 * 2160 (4K)
    Hard Drives
    1. SSD1: NVME PCI-e Gen4x4 Kingstone KC3000 [500 GB]
    2. SSD2: NVME PCI-e Gen4x4 Adata XPG S70 Blade [1 TB]
    3. HDD 1: Seagate BarraCuda 4TB 5400 RPM
    4. HDD 2: Seagate SkyHawk 4TB 7200 RPM
    PSU
    Deepcool 750W Gold Full Modular
    Case
    Deepcool CH510 MESH DIGITAL
    Cooling
    Deepcool AK400 Zero Dark Edition CPU Cooler + 5x Arctic Chassis 120mm PWM PST CO Pressure-Optimized Fans
    Keyboard
    Razer Cynosa V2 RGB Gaming Keyboard
    Mouse
    Logitech G304 LIGHTSPEED Wireless Gaming Mouse
    Internet Speed
    100 Mbps Fiber Broadband
    Browser
    Chrome+Firefox (Latest always)
    Antivirus
    Eset Security Ultimate (Latest)
    Other Info
    My Gaming Configurations
  • Operating System
    Windows 11 Pro Latest Build
    Computer type
    PC/Desktop
    Manufacturer/Model
    Work Desktop (Intel 12th Gen based Self-Assembled)
    CPU
    Intel 12th Gen i5-12400
    Motherboard
    MSI MAG B760 Tomahawk WIFI
    Memory
    Crucial Ballistix DDR4 32GB [16x2 Dual Channel] @3600 CL:16
    Graphics card(s)
    Integrated Intel UHD 720 iGPU
    Sound Card
    Motherboard Realtek UDA DTS Audio
    Monitor(s) Displays
    Sony Bravia 32" LED TV
    Screen Resolution
    1920 * 1080 (Full HD)
    Hard Drives
    1. SSD: NVME M.2 2280 Gen3x4 WD Blue SN570 250GB
    2. HDD: WD Blue 1TB @5400
    PSU
    Cooler Master MWE V2 750W Gold Fully Modular
    Case
    Cooler Master MasterBox MB540 ARGB
    Cooling
    Intel Stock CPU Cooler FAN+ 5x Arctic Chassis 120mm PWM PST CO Pressure-Optimized Fans
    Keyboard
    Logitech K295 Wireless M&K Combo
    Mouse
    Logitech K295 Wireless M&K Combo
    Internet Speed
    100 Mbps Optical Fiber Broadband
    Browser
    Google+Firefox (Latest)
    Antivirus
    Eset Security Ultimate (Latest)
    Other Info
    My Workbench Configuration
SM03 said:
What's the first Set-UwpAppSetting.ps1 script for?

Set-UwpAppSetting.ps1 contains the main function to customize UWP app settings.
It stop the app (if running), creates a temporary .reg file, load settings.dat into the regedit, import the settings (the .reg file), and unload settings.dat.

example:
Code:
# on: 1 (default) | off: 0
$VideoAutoplayReg = @{
    Name  = 'VideoAutoplay'
    Value = '0'
    Type  = '5f5e10b'
}
Set-UwpAppSetting -Name 'MicrosoftStore' -Setting $VideoAutoplayReg

You can use the already existing functions (e.g. Set-MicrosoftStoreSetting) to customize the UWP apps.

Here are the related file to use those functions: apps_settings.ps1 - UWP apps settings
If you prefer a more condensed code: WindowsMize.mini.ps1 - UWP apps settings


SM03 said:
I am actually looking for MS store settings to import/add/integrate inside Windows ISO (WIM) with the help of NTLite

I've never used NTLite, but I think there is a section like "run script once on first-logon", or something.
You can use the entire script or extract only the functions you need and make a single .ps1 file.

If you prefer the one file method, here are the functions:
Code:
enum State
{
    Disabled = 0
    Enabled  = 1
}

enum GpoState
{
    Disabled = 0
    Enabled  = 1
    NotConfigured
}

class UwpRegistryKeyEntry
{
    [string] $Path
    [string] $Name
    [string] $Value
    [string] $Type
}

class RegistryEntry
{
    [bool] $SkipKey
    [bool] $RemoveKey
    [string] $Hive
    [string] $Path
    [RegistryKeyEntry[]] $Entries
}

class RegistryKeyEntry
{
    [bool] $RemoveEntry
    [string] $Name
    [string] $Value
    [string] $Type
}

function Get-LoggedOnUserUsername
{
    [CmdletBinding()]
    param ()

    process
    {
        $ComputerInfo = Get-CimInstance -ClassName 'Win32_ComputerSystem' -Verbose:$false
        $Username = $ComputerInfo.UserName | Split-Path -Leaf

        if (-not $Username)
        {
            Write-Error -Message 'Error to get the UserName of current logged-on user.'
            exit
        }
        $Username
    }
}

function Get-LoggedOnUserSID
{
    [CmdletBinding()]
    param ()

    process
    {
        (Get-LocalUser -Name (Get-LoggedOnUserUsername)).SID.Value
    }
}

function Get-LoggedOnUserEnvVariable
{
    [CmdletBinding()]
    param ()

    process
    {
        $UserSID = Get-LoggedOnUserSID
        $LoggedUserEnvRegPath = "Registry::HKEY_USERS\$UserSID\Volatile Environment"
        $EnvVariable = Get-ItemProperty -Path $LoggedUserEnvRegPath | Select-Object -Property '*' -Exclude 'PS*'
        $EnvVariable
    }
}

function Test-FileLock
{
    <#
    .EXAMPLE
        PS> $FilePath = "C:\Users\User\AppData\Local\Packages\Microsoft.WindowsStore_8wekyb3d8bbwe\Settings\settings.dat"
        PS> Test-FileLock -FilePath $FilePath
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [string] $FilePath
    )

    process
    {
        if (-not (Test-Path -Path $FilePath))
        {
            $IsLocked = $false
        }
        else
        {
            try
            {
                $FileStream = [System.IO.File]::Open($FilePath, 'Open', 'ReadWrite', 'None')
                $FileStream.Close()
                $IsLocked = $false
            }
            catch
            {
                $IsLocked = $true
            }
        }
        $IsLocked
    }
}

function Set-UwpAppRegistryEntry
{
    <#
    .EXAMPLE
        PS> $FilePath = "C:\Users\<User>\AppData\Local\Packages\Microsoft.Windows.Photos_8wekyb3d8bbwe\Settings\settings.dat"
        PS> $PhotosTheme = '[
              {
                "Name"  : "AppBackgroundRequestedTheme",
                "Value" : "2",
                "Type"  : "5f5e104"
              }
            ]' | ConvertFrom-Json
        PS> $PhotosTheme | Set-UwpAppRegistryEntry -FilePath $FilePath
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [UwpRegistryKeyEntry] $InputObject,

        [Parameter(Mandatory)]
        [string] $FilePath
    )

    begin
    {
        $AppSettingsRegPath = 'HKEY_USERS\APP_SETTINGS'
        $RegContent = "Windows Registry Editor Version 5.00`n"
    }

    process
    {
        $Value = $InputObject.Value
        $Value = switch ($InputObject.Type)
        {
            '5f5e10b' { ([int]$Value | Format-Hex -Count 1).HexBytes }
            '5f5e10c' { [string]($Value | Format-Hex -Encoding 'unicode').HexBytes + ' 00 00' }
            '5f5e104' { ([int]$Value | Format-Hex).HexBytes }
            '5f5e105' { ([uint]$Value | Format-Hex).HexBytes }
            '5f5e106' { ([int64]$Value | Format-Hex).HexBytes }
        }

        $Value = $Value -replace '\s+', ','
        $Timestamp = ((Get-Date).ToFileTime() | Format-Hex).HexBytes.Replace(' ', ',')
        $RegKey = $InputObject.Path ? $InputObject.Path : 'LocalState'

        $RegContent += "`n[$AppSettingsRegPath\$RegKey]
            ""$($InputObject.Name)""=hex($($InputObject.Type)):$Value,$Timestamp`n" -replace '(?m)^ *'
    }

    end
    {
        $SettingRegFilePath = "$env:TEMP\uwp_app_settings.reg"

        Write-Verbose -Message $RegContent
        $RegContent | Out-File -FilePath $SettingRegFilePath

        reg.exe LOAD $AppSettingsRegPath $FilePath | Out-Null
        # 'reg.exe import' writes its output on success to stderr ...
        reg.exe IMPORT $SettingRegFilePath 2>&1 | Out-Null
        reg.exe UNLOAD $AppSettingsRegPath | Out-Null

        Remove-Item -Path $SettingRegFilePath
    }
}

function Set-UwpAppSetting
{
    <#
    .EXAMPLE
        PS> Set-UwpAppSetting -Name 'MicrosoftStore' -Setting $MicrosoftStoreSettings
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [ValidateSet('MicrosoftStore', 'WindowsNotepad', 'WindowsPhotos', 'WindowsSnippingTool')]
        [string] $Name,

        [Parameter(Mandatory)]
        [UwpRegistryKeyEntry[]] $Setting
    )

    process
    {
        $AppxPathName, $ProcessName = switch ($Name)
        {
            'MicrosoftStore'      { 'Microsoft.WindowsStore_8wekyb3d8bbwe',   'WinStore.App' }
            'WindowsNotepad'      { 'Microsoft.WindowsNotepad_8wekyb3d8bbwe', 'Notepad' }
            'WindowsPhotos'       { 'Microsoft.Windows.Photos_8wekyb3d8bbwe', 'Photos' }
            'WindowsSnippingTool' { 'Microsoft.ScreenSketch_8wekyb3d8bbwe',   'SnippingTool' }
        }

        $AppxPath = "$((Get-LoggedOnUserEnvVariable).LOCALAPPDATA)\Packages\$AppxPathName"
        $AppxSettingsFilePath = "$AppxPath\Settings\settings.dat"

        if (Test-Path -Path $AppxSettingsFilePath)
        {
            # The app could be open or running in background.
            Stop-Process -Name $ProcessName -Force -ErrorAction 'SilentlyContinue'
            Start-Sleep -Seconds 0.25

            $MaxRetries = 10
            $RetryCount = 0

            while ((Test-FileLock -FilePath $AppxSettingsFilePath) -and $RetryCount -lt $MaxRetries)
            {
                Start-Sleep -Seconds 0.25
                $RetryCount++
            }

            if ($RetryCount -eq $MaxRetries)
            {
                Write-Error -Message "$Name settings.dat file is still locked after the maximum retries."
            }
            else
            {
                Write-Verbose -Message "Setting $Name settings ..."
                $Setting | Set-UwpAppRegistryEntry -FilePath $AppxSettingsFilePath
            }
        }
        else
        {
            Write-Verbose -Message "$Name is not installed (settings.dat not found)"
        }
    }
}

function Set-RegistryEntry
{
    <#
    .EXAMPLE
        PS> $Foo = @{
                Hive    = 'HKEY_LOCAL_MACHINE'
                Path    = 'SOFTWARE\FooApp\Config'
                Entries = @(
                    @{
                        Name  = 'Enabled'
                        Value = '1'
                        Type  = 'DWord'
                    }
                    @{
                        RemoveEntry = $true
                        Name  = 'Autostart'
                        Value = '1'
                        Type  = 'DWord'
                    }
                )
            }
        PS> Set-RegistryEntry -InputObject $Foo

    .EXAMPLE
        PS> $Bar = '[
                {
                    "SkipKey" : true,
                    "Hive"    : "HKEY_LOCAL_MACHINE",
                    "Path"    : "SOFTWARE\\BarApp\\Config",
                    "Entries" : [
                        {
                            "Name"  : "Enabled",
                            "Value" : "1",
                            "Type"  : "DWord"
                        }
                    ]
                },
                {
                    "RemoveKey" : true,
                    "Hive"    : "HKEY_LOCAL_MACHINE",
                    "Path"    : "SOFTWARE\\BarApp\\Config",
                    "Entries" : [
                        {
                            "Name"  : "Autostart",
                            "Value" : "1",
                            "Type"  : "DWord"
                        }
                    ]
                }
            ]' | ConvertFrom-Json
        PS> $FooBar = @(
                $Foo
                $Bar
            )
        PS> $FooBar | Set-RegistryEntry
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [RegistryEntry] $InputObject
    )

    begin
    {
        $UserSID = Get-LoggedOnUserSID
    }

    process
    {
        if ($InputObject.SkipKey)
        {
            return
        }

        $RegistryPath = ($InputObject.Hive + '\' + $InputObject.Path) -replace '\\+', '\'
        $RegistryPathOriginal = $RegistryPath

        if ($RegistryPath -match '^(?:HKCU|HKEY_CURRENT_USER)')
        {
            $RegistryPath = $RegistryPath -ireplace '^(?:HKCU|HKEY_CURRENT_USER)', "HKEY_USERS\$UserSID"
        }

        $RegistryPath = "Registry::$RegistryPath"
        if ($InputObject.RemoveKey)
        {
            Write-Verbose -Message "  Removing key: $RegistryPathOriginal"
            Remove-Item -Recurse -Path $RegistryPath -ErrorAction 'SilentlyContinue'
        }
        else
        {
            Write-Verbose -Message "  Setting key: $RegistryPathOriginal"

            if (-not (Test-Path -Path $RegistryPath))
            {
                New-Item -Path $RegistryPath -Force | Out-Null
            }

            foreach ($Entry in $InputObject.Entries)
            {
                if ($Entry.RemoveEntry)
                {
                    Write-Verbose -Message "       remove: '$($Entry.Name)'"
                    Remove-ItemProperty -Path $RegistryPath -Name $Entry.Name -ErrorAction 'SilentlyContinue'
                }
                else
                {
                    $RegistryEntryData = @{
                        Path  = $RegistryPath
                        Name  = $Entry.Name
                        Value = $Entry.Value
                        Type  = $Entry.Type
                    }
                    if ($Entry.Type -eq 'Binary')
                    {
                        $RegistryEntryData.Value = $Entry.Value -eq '' ? $null : $Entry.Value -split '\s+'
                    }
                    Write-Verbose -Message "          set: '$($Entry.Name)' to '$($Entry.Value)' ($($Entry.Type))"
                    Set-ItemProperty @RegistryEntryData | Out-Null
                }
            }
        }
    }
}

function Write-InsufficientParameterCount
{
    [CmdletBinding()]
    param ()

    process
    {
        'Insufficient number of parameters were provided.'
    }
}

function Set-MicrosoftStoreSetting
{
    <#
    .EXAMPLE
        PS> Set-MicrosoftStoreSetting -AutoAppsUpdates 'Enabled' -VideoAutoplay 'Disabled'
    #>

    [CmdletBinding(PositionalBinding = $false)]
    param
    (
        [state] $AutoAppUpdates,
        [GpoState] $AutoAppUpdatesGPO,
        [state] $AppInstallNotifications,
        [state] $VideoAutoplay,
        [state] $PersonalizedExperiences
    )

    process
    {
        if (-not $PSBoundParameters.Keys.Count)
        {
            Write-Error -Message (Write-InsufficientParameterCount)
            return
        }

        $MicrosoftStoreSettings = [System.Collections.ArrayList]::new()

        switch ($PSBoundParameters.Keys)
        {
            'AutoAppUpdates'
            {
                # settings.dat registry key: UpdateAppsAutomatically (5f5e10b).
                # Applied only when Microsoft Store is launched.

                # on: 4 (default) | off: 2
                $AutoAppUpdatesReg = @(
                    @{
                        Hive    = 'HKEY_LOCAL_MACHINE'
                        Path    = 'SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsStore\WindowsUpdate'
                        Entries = @(
                            @{
                                Name  = 'AutoDownload'
                                Value = $AutoAppUpdates -eq 'Enabled' ? '4' : '2'
                                Type  = 'DWord'
                            }
                        )
                    }
                    @{
                        Hive    = 'HKEY_LOCAL_MACHINE'
                        Path    = 'SOFTWARE\Microsoft\Windows\CurrentVersion\InstallService\State'
                        Entries = @(
                            @{
                                Name  = 'AutoUpdatePauseEndTime'
                                Value = (Get-Date).AddDays(7).ToString('yyyy-MM-ddTHH:mm:ssK')
                                Type  = 'String'
                            }
                        )
                    }
                )
                Write-Verbose -Message "Setting 'Microsoft Store - Auto App Updates' to '$AutoAppUpdates' ..."
                $AutoAppUpdatesReg | Set-RegistryEntry
            }
            'AutoAppUpdatesGPO'
            {
                # gpo\ computer config > administrative tpl > windows components > store
                #   turn off automatic download and install of updates
                # not configured: delete (default) | on: 4 | off: 2
                $AutoAppUpdatesRegGPO = @{
                    Hive    = 'HKEY_LOCAL_MACHINE'
                    Path    = 'SOFTWARE\Policies\Microsoft\WindowsStore'
                    Entries = @(
                        @{
                            RemoveEntry = $AutoAppUpdatesGPO -eq 'NotConfigured'
                            Name  = 'AutoDownload'
                            Value = $AutoAppUpdatesGPO -eq 'Enabled' ? '4' : '2'
                            Type  = 'DWord'
                        }
                    )
                }

                Write-Verbose -Message "Setting 'Microsoft Store - Auto App Updates (GPO)' to '$AutoAppUpdatesGPO' ..."
                Set-RegistryEntry -InputObject $AutoAppUpdatesRegGPO
            }
            'AppInstallNotifications'
            {
                # on: 1 (default) | off: 0
                $AppInstallNotificationsReg = @{
                    Name  = 'EnableAppInstallNotifications'
                    Value = $AppInstallNotifications -eq 'Enabled' ? '1' : '0'
                    Type  = '5f5e10b'
                }
                $MicrosoftStoreSettings.Add([PSCustomObject]$AppInstallNotificationsReg) | Out-Null
            }
            'VideoAutoplay'
            {
                # on: 1 (default) | off: 0
                $VideoAutoplayReg = @{
                    Name  = 'VideoAutoplay'
                    Value = $VideoAutoplay -eq 'Enabled' ? '1' : '0'
                    Type  = '5f5e10b'
                }
                $MicrosoftStoreSettings.Add([PSCustomObject]$VideoAutoplayReg) | Out-Null
            }
            'PersonalizedExperiences'
            {
                # on: 1 (default) | off: 0
                $PersonalizedExperiencesReg = @{
                    Path  = 'LocalState\PersistentSettings'
                    Name  = 'PersonalizationEnabled'
                    Value = $PersonalizedExperiences -eq 'Enabled' ? '1' : '0'
                    Type  = '5f5e10b'
                }
                $MicrosoftStoreSettings.Add([PSCustomObject]$PersonalizedExperiencesReg) | Out-Null
            }
        }

        if ($MicrosoftStoreSettings.Count)
        {
            Set-UwpAppSetting -Name 'MicrosoftStore' -Setting $MicrosoftStoreSettings
        }
    }
}

function Test-UWPAppFilePath
{
    <#
    .EXAMPLE
        PS> Test-UWPAppFilePath -Name 'MicrosoftStore' -Timeout 30
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [ValidateSet('MicrosoftStore', 'WindowsNotepad', 'WindowsPhotos', 'WindowsSnippingTool')]
        [string] $Name,

        [ValidateRange('NonNegative')]
        [int] $Timeout = 30
    )

    process
    {
        $Result = $true

        $AppxPathName = switch ($Name)
        {
            'MicrosoftStore'      { 'Microsoft.WindowsStore_8wekyb3d8bbwe' }
            'WindowsNotepad'      { 'Microsoft.WindowsNotepad_8wekyb3d8bbwe' }
            'WindowsPhotos'       { 'Microsoft.Windows.Photos_8wekyb3d8bbwe' }
            'WindowsSnippingTool' { 'Microsoft.ScreenSketch_8wekyb3d8bbwe' }
        }

        $AppxPath = "$((Get-LoggedOnUserEnvVariable).LOCALAPPDATA)\Packages\$AppxPathName"
        $AppxSettingsFilePath = "$AppxPath\Settings\settings.dat"

        $MaxRetries = $Timeout / 2
        $RetryCount = 0

        while (-not (Test-Path -Path $AppxSettingsFilePath) -and $RetryCount -lt $MaxRetries)
        {
            Start-Sleep -Seconds 2
            $RetryCount++
        }

        if ($RetryCount -eq $MaxRetries)
        {
            Write-Error -Message "$Name settings.dat file not found."
            $Result = $false
        }
        $Result
    }
}

#==============================================================================
#                               Microsoft Store
#==============================================================================

if (Test-UWPAppFilePath -Name 'MicrosoftStore' -Timeout 30)
{
    # --- App updates (default: Enabled)
    Set-MicrosoftStoreSetting -AutoAppUpdates 'Enabled' -AutoAppUpdatesGPO 'NotConfigured'

    # --- Notifications for app installations (default: Enabled)
    Set-MicrosoftStoreSetting -AppInstallNotifications 'Enabled'

    # --- Video autoplay (default: Enabled)
    Set-MicrosoftStoreSetting -VideoAutoplay 'Disabled'

    # --- Personalized experiences (default: Enabled)
    Set-MicrosoftStoreSetting -PersonalizedExperiences 'Disabled'
}

This is only for MS Store, if you need other apps settings, copy/paste their related functions as well.
These functions requires Powershell 7 that you must install before running the script.

If you perform an offline installation, you need to incorporate the .msi installer into your ISO.
Releases · PowerShell/PowerShell: e.g. PowerShell-7.5.3-win-x64.msi

Another method would be to manually create the reg file and import them as @garlin shows you in Enable or Disable Video Autoplay in Microsoft Store app in Windows 11.

My script have the same timing-related problem if you use NTLite.
If settings.dat doesn't exist, it will do nothing.

To solve this problem, I've added (only in this post) the Test-UWPAppFilePath function to test if the file exist.
e.g. Test-UWPAppFilePath -Name 'MicrosoftStore' -Timeout 30
The timeout is in seconds.
30 seconds should be enought. Increase it if it doesn't work.

Originally I've tagged you to give you the names of the registry keys ^^.
But here you are, the code inside the spoiler tag should accomplish what you want.
Don't forget to install Powershell 7 and run the script with pwsh.exe (not with powershell.exe).

@Brink
Do you have 1 min to update the OP please ?
The new content is in the spoiler tag at the end of the post 27.
 

My Computer

System One

  • OS
    .
The part of your script code that gets the user name and SID can be simplified somewhat.
Powershell:
try {
    $userName = [Environment]::UserName
    if ($userName) {
        Write-Host "Current User Name: $userName"
        $userSID = [System.Security.Principal.NTAccount]::New($userName).Translate([System.Security.Principal.SecurityIdentifier]).Value
        if ($userSID) {
            Write-Host "Current User SID: $userSID"
        } else {
            Write-Error "Error: failed to get the Current User SID"
        }
    } else {
        Write-Error "Error: failed to get the Current User Name"
    }
} catch {
    Write-Error $_.Exception.Message
}
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
    Antivirus
    What's an antivirus?
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
I need 2 functions. Sometimes I only need the username.

I have a lot of error handling and I try to avoid try/catch statements.
I could probably improve some area where it is needed.

$userName = [Environment]::UserName
[Environment]::UserName cannot be used, because if you run the script on a standard account within an elevated powershell, it will return the username of the admin's account.
The same applies if you run the script as NT AUTHORITY\SYSTEM, you will get the wrong username.

And not only the username, you will get all the properties of the Admin's account.
- HKEY_CURRENT_USER' will point to the Admin's HIVE.
- 'Environment variables' & 'Shell Folders paths' are the Admin's values.
etc...

$userSID = [System.Security.Principal.NTAccount]::New($userName).Translate([System.Security.Principal.SecurityIdentifier]).Value
I don't know if it is better or not than (Get-LocalUser -Name (Get-LoggedOnUserUsername)).SID.Value
First method use .Net method and the second pure Powershell.
I added it to my notes to do more research about that.



Thank you for your feedback. It's always interesting to see others code.
 

My Computer

System One

  • OS
    .
If a standard user launches PowerShell and clicks “Yes” on a UAC prompt to run as admin, the process runs elevated.
However, [Environment]::UserName still returns the standard user’s name, because the environment block is inherited from the launching user.

To get the actual security context (i.e., the account under which the process is running), use:
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name

The $env:UserName environment variable could potentially be overwritten before your Get-LoggedOnUserUsername returns its value. (E.g., with $env:UserName = "FakeUser".) This variable reflects the launching context, not necessarily the execution context. It is static—it doesn’t update if the process impersonates another user or switches tokens. [System.Security.Principal.WindowsIdentity]::GetCurrent().Name is far more resilient—it queries the actual token of the running thread, and, that’s what matters in elevated, impersonated, or sandboxed scenarios.

Get-LocalUser only works for local accounts—not domain users. (Get-LocalUser -Name (Get-LoggedOnUserUsername)).SID.Value breaks in domain environments, remote sessions, or elevated contexts where the user isn’t a local account.

You can leave out the excess error handling if that's what you want. PowerShell is based entirely on .NET so, there exists no such thing as "pure PowerShell".

P.S., here is a good explanation of the difference between $env:UserName and [Environment]::UserName.

P.P.S., if you want to know who launched the elevated script, use:
Powershell:
$ownerInfo = Get-WmiObject Win32_Process -Filter "ProcessId = $PID" | ForEach-Object {
    $owner = $_.GetOwner()
    "$($owner.Domain)\$($owner.User)"
}
This gives you the actual originator of the PowerShell process—domain or local, elevated or not.
Your Get-LoggedOnUserUsername works only if someone is interactively logged in. It fails in:
  • Remote sessions
  • Headless servers
  • Multi-user environments
  • Fast User Switching
Also, it assumes the returned name is a local account, which leads to the next fragility. I.e., your Get-LoggedOnUserSID only works for local accounts. If the user is domain-joined, this throws. Also, it assumes the username from WMI matches a local account name—which is not guaranteed. Your Get-LoggedOnUserEnvVariable uses a path that is invalid if the SID resolution failed (e.g., domain user), and, registry hives may not be loaded for non-interactive users. I don't know if any of these problems/limitations could potentially affect the reliability of your script, as I haven't looked at it beyond this trio of functions you wrote, which is clever in intent but fragile in execution. It tries to reconstruct the logged-on user's identity and environment by querying WMI, local user SID, and registry paths. However, it’s built on assumptions that don’t hold in elevated or domain contexts.
 
Last edited:

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
    Antivirus
    What's an antivirus?
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
If a standard user launches PowerShell and clicks “Yes” on a UAC prompt to run as admin, the process runs elevated.
However, [Environment]::UserName still returns the standard user’s name, because the environment block is inherited from the launching user.

To get the actual security context (i.e., the account under which the process is running), use:
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name

The $env:UserName environment variable could potentially be overwritten before your Get-LoggedOnUserUsername returns its value. (E.g., with $env:UserName = "FakeUser".) This variable reflects the launching context, not necessarily the execution context. It is static—it doesn’t update if the process impersonates another user or switches tokens. [System.Security.Principal.WindowsIdentity]::GetCurrent().Name is far more resilient—it queries the actual token of the running thread, and, that’s what matters in elevated, impersonated, or sandboxed scenarios.

I already tried all of these methods before making my function.
For the overwrite of $env:UserName, it's not a problem as I don't use it.

On my VM, User is the admin account, Standard_test is (spoiler xd) a standard account.
When logged-in with the standard account, on an elevated Powershell session:
Code:
PowerShell 7.5.3
PS C:\Users\User> $env:UserName
User
PS C:\Users\User> [Environment]::UserName
User
PS C:\Users\User> [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
DESKTOP-JQ8U93N\User
PS C:\Users\User> (Get-CimInstance -ClassName 'Win32_ComputerSystem').UserName
DESKTOP-JQ8U93N\Standard_test
PS C:\Users\User>


Get-LocalUser only works for local accounts—not domain users. (Get-LocalUser -Name (Get-LoggedOnUserUsername)).SID.Value breaks in domain environments, remote sessions, or elevated contexts where the user isn’t a local account.
Yeah, I need to fix that. I will use the [System.Security.Principal.NTAccount] class as you suggested.


PowerShell is based entirely on .NET so, there exists no such thing as "pure PowerShell".
😂 Haha, yeah I know. But you understood me, I was talking about Powershell cmdlet.


P.P.S., if you want to know who launched the elevated script, use:
Code:
$ownerInfo = Get-WmiObject Win32_Process -Filter "ProcessId = $PID" | ForEach-Object {
    $owner = $_.GetOwner()
    "$($owner.Domain)\$($owner.User)"
}
This gives you the actual originator of the PowerShell process—domain or local, elevated or not.
Code:
ForEach-Object: Method invocation failed because [Deserialized.System.Management.ManagementObject#root\cimv2\Win32_Process] does not contain a method named 'GetOwner'.

Already tried this method, it doesn't retrieve the correct username either.
Code:
PS C:\Users\User> Get-CimInstance 'Win32_Process' -Filter "ProcessId = $PID" |
>>     ForEach-Object -Process {
>>         $Owner = Invoke-CimMethod -InputObject $_ -MethodName 'GetOwner'
>>         "$($Owner.Domain)\$($Owner.User)"
>>     }
DESKTOP-JQ8U93N\User

A slight modification make it work:
Code:
PS C:\Users\User> $ProcessInfo = Get-CimInstance -ClassName 'Win32_Process' -Filter "name='explorer.exe'"
PS C:\Users\User> $Username = (Invoke-CimMethod -InputObject $ProcessInfo -MethodName 'GetOwner' | Select-Object -First 1).User
PS C:\Users\User> $Username
Standard_test
However, it assumes an interactively logged-in user. So does my current function.


Your Get-LoggedOnUserUsername works only if someone is interactively logged in. It fails in:
  • Remote sessions
  • Headless servers
  • Multi-user environments
  • Fast User Switching

I made extensive searches before picking that solution, but maybe not enough.
It's the only one (or the PID explorer + GetOwner) that works with a standard account on an elevated Powershell session.

I will run some tests regarding the remote session with a non-interactively logged-in user.
The script wasn't intended for this use case, but it would be great if it works.


Also, it assumes the returned name is a local account, which leads to the next fragility. I.e., your Get-LoggedOnUserSID only works for local accounts. If the user is domain-joined, this throws. Also, it assumes the username from WMI matches a local account name—which is not guaranteed. Your Get-LoggedOnUserEnvVariable uses a path that is invalid if the SID resolution failed (e.g., domain user),
I guess that this part will be fixed with the use of the [System.Security.Principal.NTAccount] class.
If SID retrieval fails, nothing will work. ^^
Because I use $UserSID = Get-LoggedOnUserSID in the Set-RegistryEntry function to make it work on standard account.


and, registry hives may not be loaded for non-interactive users.
If the registry hive is not loaded, nothing will work either.
I will try to fix that.


However, it’s built on assumptions that don’t hold in elevated or domain contexts.
It does work in an elevated context, I tested it with a standard account on an elevated Powershell session. oO
When you say "that don’t hold in elevated or domain contexts", I suppose it is only in a non-interactive context, right (assuming the SID is fixed) ?

Thank you for your time. I will fix what I can.
 

My Computer

System One

  • OS
    .
Set-UwpAppSetting.ps1 contains the main function to customize UWP app settings.
It stop the app (if running), creates a temporary .reg file, load settings.dat into the regedit, import the settings (the .reg file), and unload settings.dat.

example:
Code:
# on: 1 (default) | off: 0
$VideoAutoplayReg = @{
    Name  = 'VideoAutoplay'
    Value = '0'
    Type  = '5f5e10b'
}
Set-UwpAppSetting -Name 'MicrosoftStore' -Setting $VideoAutoplayReg

You can use the already existing functions (e.g. Set-MicrosoftStoreSetting) to customize the UWP apps.

Here are the related file to use those functions: apps_settings.ps1 - UWP apps settings
If you prefer a more condensed code: WindowsMize.mini.ps1 - UWP apps settings




I've never used NTLite, but I think there is a section like "run script once on first-logon", or something.
You can use the entire script or extract only the functions you need and make a single .ps1 file.

If you prefer the one file method, here are the functions:
Code:
enum State
{
    Disabled = 0
    Enabled  = 1
}

enum GpoState
{
    Disabled = 0
    Enabled  = 1
    NotConfigured
}

class UwpRegistryKeyEntry
{
    [string] $Path
    [string] $Name
    [string] $Value
    [string] $Type
}

class RegistryEntry
{
    [bool] $SkipKey
    [bool] $RemoveKey
    [string] $Hive
    [string] $Path
    [RegistryKeyEntry[]] $Entries
}

class RegistryKeyEntry
{
    [bool] $RemoveEntry
    [string] $Name
    [string] $Value
    [string] $Type
}

function Get-LoggedOnUserUsername
{
    [CmdletBinding()]
    param ()

    process
    {
        $ComputerInfo = Get-CimInstance -ClassName 'Win32_ComputerSystem' -Verbose:$false
        $Username = $ComputerInfo.UserName | Split-Path -Leaf

        if (-not $Username)
        {
            Write-Error -Message 'Error to get the UserName of current logged-on user.'
            exit
        }
        $Username
    }
}

function Get-LoggedOnUserSID
{
    [CmdletBinding()]
    param ()

    process
    {
        (Get-LocalUser -Name (Get-LoggedOnUserUsername)).SID.Value
    }
}

function Get-LoggedOnUserEnvVariable
{
    [CmdletBinding()]
    param ()

    process
    {
        $UserSID = Get-LoggedOnUserSID
        $LoggedUserEnvRegPath = "Registry::HKEY_USERS\$UserSID\Volatile Environment"
        $EnvVariable = Get-ItemProperty -Path $LoggedUserEnvRegPath | Select-Object -Property '*' -Exclude 'PS*'
        $EnvVariable
    }
}

function Test-FileLock
{
    <#
    .EXAMPLE
        PS> $FilePath = "C:\Users\User\AppData\Local\Packages\Microsoft.WindowsStore_8wekyb3d8bbwe\Settings\settings.dat"
        PS> Test-FileLock -FilePath $FilePath
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [string] $FilePath
    )

    process
    {
        if (-not (Test-Path -Path $FilePath))
        {
            $IsLocked = $false
        }
        else
        {
            try
            {
                $FileStream = [System.IO.File]::Open($FilePath, 'Open', 'ReadWrite', 'None')
                $FileStream.Close()
                $IsLocked = $false
            }
            catch
            {
                $IsLocked = $true
            }
        }
        $IsLocked
    }
}

function Set-UwpAppRegistryEntry
{
    <#
    .EXAMPLE
        PS> $FilePath = "C:\Users\<User>\AppData\Local\Packages\Microsoft.Windows.Photos_8wekyb3d8bbwe\Settings\settings.dat"
        PS> $PhotosTheme = '[
              {
                "Name"  : "AppBackgroundRequestedTheme",
                "Value" : "2",
                "Type"  : "5f5e104"
              }
            ]' | ConvertFrom-Json
        PS> $PhotosTheme | Set-UwpAppRegistryEntry -FilePath $FilePath
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [UwpRegistryKeyEntry] $InputObject,

        [Parameter(Mandatory)]
        [string] $FilePath
    )

    begin
    {
        $AppSettingsRegPath = 'HKEY_USERS\APP_SETTINGS'
        $RegContent = "Windows Registry Editor Version 5.00`n"
    }

    process
    {
        $Value = $InputObject.Value
        $Value = switch ($InputObject.Type)
        {
            '5f5e10b' { ([int]$Value | Format-Hex -Count 1).HexBytes }
            '5f5e10c' { [string]($Value | Format-Hex -Encoding 'unicode').HexBytes + ' 00 00' }
            '5f5e104' { ([int]$Value | Format-Hex).HexBytes }
            '5f5e105' { ([uint]$Value | Format-Hex).HexBytes }
            '5f5e106' { ([int64]$Value | Format-Hex).HexBytes }
        }

        $Value = $Value -replace '\s+', ','
        $Timestamp = ((Get-Date).ToFileTime() | Format-Hex).HexBytes.Replace(' ', ',')
        $RegKey = $InputObject.Path ? $InputObject.Path : 'LocalState'

        $RegContent += "`n[$AppSettingsRegPath\$RegKey]
            ""$($InputObject.Name)""=hex($($InputObject.Type)):$Value,$Timestamp`n" -replace '(?m)^ *'
    }

    end
    {
        $SettingRegFilePath = "$env:TEMP\uwp_app_settings.reg"

        Write-Verbose -Message $RegContent
        $RegContent | Out-File -FilePath $SettingRegFilePath

        reg.exe LOAD $AppSettingsRegPath $FilePath | Out-Null
        # 'reg.exe import' writes its output on success to stderr ...
        reg.exe IMPORT $SettingRegFilePath 2>&1 | Out-Null
        reg.exe UNLOAD $AppSettingsRegPath | Out-Null

        Remove-Item -Path $SettingRegFilePath
    }
}

function Set-UwpAppSetting
{
    <#
    .EXAMPLE
        PS> Set-UwpAppSetting -Name 'MicrosoftStore' -Setting $MicrosoftStoreSettings
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [ValidateSet('MicrosoftStore', 'WindowsNotepad', 'WindowsPhotos', 'WindowsSnippingTool')]
        [string] $Name,

        [Parameter(Mandatory)]
        [UwpRegistryKeyEntry[]] $Setting
    )

    process
    {
        $AppxPathName, $ProcessName = switch ($Name)
        {
            'MicrosoftStore'      { 'Microsoft.WindowsStore_8wekyb3d8bbwe',   'WinStore.App' }
            'WindowsNotepad'      { 'Microsoft.WindowsNotepad_8wekyb3d8bbwe', 'Notepad' }
            'WindowsPhotos'       { 'Microsoft.Windows.Photos_8wekyb3d8bbwe', 'Photos' }
            'WindowsSnippingTool' { 'Microsoft.ScreenSketch_8wekyb3d8bbwe',   'SnippingTool' }
        }

        $AppxPath = "$((Get-LoggedOnUserEnvVariable).LOCALAPPDATA)\Packages\$AppxPathName"
        $AppxSettingsFilePath = "$AppxPath\Settings\settings.dat"

        if (Test-Path -Path $AppxSettingsFilePath)
        {
            # The app could be open or running in background.
            Stop-Process -Name $ProcessName -Force -ErrorAction 'SilentlyContinue'
            Start-Sleep -Seconds 0.25

            $MaxRetries = 10
            $RetryCount = 0

            while ((Test-FileLock -FilePath $AppxSettingsFilePath) -and $RetryCount -lt $MaxRetries)
            {
                Start-Sleep -Seconds 0.25
                $RetryCount++
            }

            if ($RetryCount -eq $MaxRetries)
            {
                Write-Error -Message "$Name settings.dat file is still locked after the maximum retries."
            }
            else
            {
                Write-Verbose -Message "Setting $Name settings ..."
                $Setting | Set-UwpAppRegistryEntry -FilePath $AppxSettingsFilePath
            }
        }
        else
        {
            Write-Verbose -Message "$Name is not installed (settings.dat not found)"
        }
    }
}

function Set-RegistryEntry
{
    <#
    .EXAMPLE
        PS> $Foo = @{
                Hive    = 'HKEY_LOCAL_MACHINE'
                Path    = 'SOFTWARE\FooApp\Config'
                Entries = @(
                    @{
                        Name  = 'Enabled'
                        Value = '1'
                        Type  = 'DWord'
                    }
                    @{
                        RemoveEntry = $true
                        Name  = 'Autostart'
                        Value = '1'
                        Type  = 'DWord'
                    }
                )
            }
        PS> Set-RegistryEntry -InputObject $Foo

    .EXAMPLE
        PS> $Bar = '[
                {
                    "SkipKey" : true,
                    "Hive"    : "HKEY_LOCAL_MACHINE",
                    "Path"    : "SOFTWARE\\BarApp\\Config",
                    "Entries" : [
                        {
                            "Name"  : "Enabled",
                            "Value" : "1",
                            "Type"  : "DWord"
                        }
                    ]
                },
                {
                    "RemoveKey" : true,
                    "Hive"    : "HKEY_LOCAL_MACHINE",
                    "Path"    : "SOFTWARE\\BarApp\\Config",
                    "Entries" : [
                        {
                            "Name"  : "Autostart",
                            "Value" : "1",
                            "Type"  : "DWord"
                        }
                    ]
                }
            ]' | ConvertFrom-Json
        PS> $FooBar = @(
                $Foo
                $Bar
            )
        PS> $FooBar | Set-RegistryEntry
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory, ValueFromPipeline)]
        [RegistryEntry] $InputObject
    )

    begin
    {
        $UserSID = Get-LoggedOnUserSID
    }

    process
    {
        if ($InputObject.SkipKey)
        {
            return
        }

        $RegistryPath = ($InputObject.Hive + '\' + $InputObject.Path) -replace '\\+', '\'
        $RegistryPathOriginal = $RegistryPath

        if ($RegistryPath -match '^(?:HKCU|HKEY_CURRENT_USER)')
        {
            $RegistryPath = $RegistryPath -ireplace '^(?:HKCU|HKEY_CURRENT_USER)', "HKEY_USERS\$UserSID"
        }

        $RegistryPath = "Registry::$RegistryPath"
        if ($InputObject.RemoveKey)
        {
            Write-Verbose -Message "  Removing key: $RegistryPathOriginal"
            Remove-Item -Recurse -Path $RegistryPath -ErrorAction 'SilentlyContinue'
        }
        else
        {
            Write-Verbose -Message "  Setting key: $RegistryPathOriginal"

            if (-not (Test-Path -Path $RegistryPath))
            {
                New-Item -Path $RegistryPath -Force | Out-Null
            }

            foreach ($Entry in $InputObject.Entries)
            {
                if ($Entry.RemoveEntry)
                {
                    Write-Verbose -Message "       remove: '$($Entry.Name)'"
                    Remove-ItemProperty -Path $RegistryPath -Name $Entry.Name -ErrorAction 'SilentlyContinue'
                }
                else
                {
                    $RegistryEntryData = @{
                        Path  = $RegistryPath
                        Name  = $Entry.Name
                        Value = $Entry.Value
                        Type  = $Entry.Type
                    }
                    if ($Entry.Type -eq 'Binary')
                    {
                        $RegistryEntryData.Value = $Entry.Value -eq '' ? $null : $Entry.Value -split '\s+'
                    }
                    Write-Verbose -Message "          set: '$($Entry.Name)' to '$($Entry.Value)' ($($Entry.Type))"
                    Set-ItemProperty @RegistryEntryData | Out-Null
                }
            }
        }
    }
}

function Write-InsufficientParameterCount
{
    [CmdletBinding()]
    param ()

    process
    {
        'Insufficient number of parameters were provided.'
    }
}

function Set-MicrosoftStoreSetting
{
    <#
    .EXAMPLE
        PS> Set-MicrosoftStoreSetting -AutoAppsUpdates 'Enabled' -VideoAutoplay 'Disabled'
    #>

    [CmdletBinding(PositionalBinding = $false)]
    param
    (
        [state] $AutoAppUpdates,
        [GpoState] $AutoAppUpdatesGPO,
        [state] $AppInstallNotifications,
        [state] $VideoAutoplay,
        [state] $PersonalizedExperiences
    )

    process
    {
        if (-not $PSBoundParameters.Keys.Count)
        {
            Write-Error -Message (Write-InsufficientParameterCount)
            return
        }

        $MicrosoftStoreSettings = [System.Collections.ArrayList]::new()

        switch ($PSBoundParameters.Keys)
        {
            'AutoAppUpdates'
            {
                # settings.dat registry key: UpdateAppsAutomatically (5f5e10b).
                # Applied only when Microsoft Store is launched.

                # on: 4 (default) | off: 2
                $AutoAppUpdatesReg = @(
                    @{
                        Hive    = 'HKEY_LOCAL_MACHINE'
                        Path    = 'SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsStore\WindowsUpdate'
                        Entries = @(
                            @{
                                Name  = 'AutoDownload'
                                Value = $AutoAppUpdates -eq 'Enabled' ? '4' : '2'
                                Type  = 'DWord'
                            }
                        )
                    }
                    @{
                        Hive    = 'HKEY_LOCAL_MACHINE'
                        Path    = 'SOFTWARE\Microsoft\Windows\CurrentVersion\InstallService\State'
                        Entries = @(
                            @{
                                Name  = 'AutoUpdatePauseEndTime'
                                Value = (Get-Date).AddDays(7).ToString('yyyy-MM-ddTHH:mm:ssK')
                                Type  = 'String'
                            }
                        )
                    }
                )
                Write-Verbose -Message "Setting 'Microsoft Store - Auto App Updates' to '$AutoAppUpdates' ..."
                $AutoAppUpdatesReg | Set-RegistryEntry
            }
            'AutoAppUpdatesGPO'
            {
                # gpo\ computer config > administrative tpl > windows components > store
                #   turn off automatic download and install of updates
                # not configured: delete (default) | on: 4 | off: 2
                $AutoAppUpdatesRegGPO = @{
                    Hive    = 'HKEY_LOCAL_MACHINE'
                    Path    = 'SOFTWARE\Policies\Microsoft\WindowsStore'
                    Entries = @(
                        @{
                            RemoveEntry = $AutoAppUpdatesGPO -eq 'NotConfigured'
                            Name  = 'AutoDownload'
                            Value = $AutoAppUpdatesGPO -eq 'Enabled' ? '4' : '2'
                            Type  = 'DWord'
                        }
                    )
                }

                Write-Verbose -Message "Setting 'Microsoft Store - Auto App Updates (GPO)' to '$AutoAppUpdatesGPO' ..."
                Set-RegistryEntry -InputObject $AutoAppUpdatesRegGPO
            }
            'AppInstallNotifications'
            {
                # on: 1 (default) | off: 0
                $AppInstallNotificationsReg = @{
                    Name  = 'EnableAppInstallNotifications'
                    Value = $AppInstallNotifications -eq 'Enabled' ? '1' : '0'
                    Type  = '5f5e10b'
                }
                $MicrosoftStoreSettings.Add([PSCustomObject]$AppInstallNotificationsReg) | Out-Null
            }
            'VideoAutoplay'
            {
                # on: 1 (default) | off: 0
                $VideoAutoplayReg = @{
                    Name  = 'VideoAutoplay'
                    Value = $VideoAutoplay -eq 'Enabled' ? '1' : '0'
                    Type  = '5f5e10b'
                }
                $MicrosoftStoreSettings.Add([PSCustomObject]$VideoAutoplayReg) | Out-Null
            }
            'PersonalizedExperiences'
            {
                # on: 1 (default) | off: 0
                $PersonalizedExperiencesReg = @{
                    Path  = 'LocalState\PersistentSettings'
                    Name  = 'PersonalizationEnabled'
                    Value = $PersonalizedExperiences -eq 'Enabled' ? '1' : '0'
                    Type  = '5f5e10b'
                }
                $MicrosoftStoreSettings.Add([PSCustomObject]$PersonalizedExperiencesReg) | Out-Null
            }
        }

        if ($MicrosoftStoreSettings.Count)
        {
            Set-UwpAppSetting -Name 'MicrosoftStore' -Setting $MicrosoftStoreSettings
        }
    }
}

function Test-UWPAppFilePath
{
    <#
    .EXAMPLE
        PS> Test-UWPAppFilePath -Name 'MicrosoftStore' -Timeout 30
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [ValidateSet('MicrosoftStore', 'WindowsNotepad', 'WindowsPhotos', 'WindowsSnippingTool')]
        [string] $Name,

        [ValidateRange('NonNegative')]
        [int] $Timeout = 30
    )

    process
    {
        $Result = $true

        $AppxPathName = switch ($Name)
        {
            'MicrosoftStore'      { 'Microsoft.WindowsStore_8wekyb3d8bbwe' }
            'WindowsNotepad'      { 'Microsoft.WindowsNotepad_8wekyb3d8bbwe' }
            'WindowsPhotos'       { 'Microsoft.Windows.Photos_8wekyb3d8bbwe' }
            'WindowsSnippingTool' { 'Microsoft.ScreenSketch_8wekyb3d8bbwe' }
        }

        $AppxPath = "$((Get-LoggedOnUserEnvVariable).LOCALAPPDATA)\Packages\$AppxPathName"
        $AppxSettingsFilePath = "$AppxPath\Settings\settings.dat"

        $MaxRetries = $Timeout / 2
        $RetryCount = 0

        while (-not (Test-Path -Path $AppxSettingsFilePath) -and $RetryCount -lt $MaxRetries)
        {
            Start-Sleep -Seconds 2
            $RetryCount++
        }

        if ($RetryCount -eq $MaxRetries)
        {
            Write-Error -Message "$Name settings.dat file not found."
            $Result = $false
        }
        $Result
    }
}

#==============================================================================
#                               Microsoft Store
#==============================================================================

if (Test-UWPAppFilePath -Name 'MicrosoftStore' -Timeout 30)
{
    # --- App updates (default: Enabled)
    Set-MicrosoftStoreSetting -AutoAppUpdates 'Enabled' -AutoAppUpdatesGPO 'NotConfigured'

    # --- Notifications for app installations (default: Enabled)
    Set-MicrosoftStoreSetting -AppInstallNotifications 'Enabled'

    # --- Video autoplay (default: Enabled)
    Set-MicrosoftStoreSetting -VideoAutoplay 'Disabled'

    # --- Personalized experiences (default: Enabled)
    Set-MicrosoftStoreSetting -PersonalizedExperiences 'Disabled'
}

This is only for MS Store, if you need other apps settings, copy/paste their related functions as well.
These functions requires Powershell 7 that you must install before running the script.

If you perform an offline installation, you need to incorporate the .msi installer into your ISO.
Releases · PowerShell/PowerShell: e.g. PowerShell-7.5.3-win-x64.msi

Another method would be to manually create the reg file and import them as @garlin shows you in Enable or Disable Video Autoplay in Microsoft Store app in Windows 11.

My script have the same timing-related problem if you use NTLite.
If settings.dat doesn't exist, it will do nothing.

To solve this problem, I've added (only in this post) the Test-UWPAppFilePath function to test if the file exist.
e.g. Test-UWPAppFilePath -Name 'MicrosoftStore' -Timeout 30
The timeout is in seconds.
30 seconds should be enought. Increase it if it doesn't work.

Originally I've tagged you to give you the names of the registry keys ^^.
But here you are, the code inside the spoiler tag should accomplish what you want.
Don't forget to install Powershell 7 and run the script with pwsh.exe (not with powershell.exe).

@Brink
Do you have 1 min to update the OP please ?
The new content is in the spoiler tag at the end of the post 27.
@agadiffe
I need to consult with you regarding this script & NTL integration
and as I don't wanna clutter this thread here for my personal interest so checked your profile for PM, but since you limit who can view your profile, so I can't.

If you don't mind, could you drop me a PM so that we can continue over there?
 

My Computers

System One System Two

  • OS
    Windows 11 Pro Latest Retail Build
    Computer type
    PC/Desktop
    Manufacturer/Model
    Gaming-Rig (Intel 13th Gen based Self-Assembled)
    CPU
    Intel 13th Gen i5-13600KF
    Motherboard
    MSI PRO Z790-A WIFI DDR5
    Memory
    G-Skill Trident Z5 RGB 32GB Kit (F5-7200J3445G16GX2-TZ5RK) @7200 MT/s CL34
    Graphics Card(s)
    Nvidia GeForce RTX 4060 Ti 16GB OC
    Sound Card
    Motherboard Realtek UDA DTS Audio
    Monitor(s) Displays
    Hisense 43" 4K QLED
    Screen Resolution
    4096 * 2160 (4K)
    Hard Drives
    1. SSD1: NVME PCI-e Gen4x4 Kingstone KC3000 [500 GB]
    2. SSD2: NVME PCI-e Gen4x4 Adata XPG S70 Blade [1 TB]
    3. HDD 1: Seagate BarraCuda 4TB 5400 RPM
    4. HDD 2: Seagate SkyHawk 4TB 7200 RPM
    PSU
    Deepcool 750W Gold Full Modular
    Case
    Deepcool CH510 MESH DIGITAL
    Cooling
    Deepcool AK400 Zero Dark Edition CPU Cooler + 5x Arctic Chassis 120mm PWM PST CO Pressure-Optimized Fans
    Keyboard
    Razer Cynosa V2 RGB Gaming Keyboard
    Mouse
    Logitech G304 LIGHTSPEED Wireless Gaming Mouse
    Internet Speed
    100 Mbps Fiber Broadband
    Browser
    Chrome+Firefox (Latest always)
    Antivirus
    Eset Security Ultimate (Latest)
    Other Info
    My Gaming Configurations
  • Operating System
    Windows 11 Pro Latest Build
    Computer type
    PC/Desktop
    Manufacturer/Model
    Work Desktop (Intel 12th Gen based Self-Assembled)
    CPU
    Intel 12th Gen i5-12400
    Motherboard
    MSI MAG B760 Tomahawk WIFI
    Memory
    Crucial Ballistix DDR4 32GB [16x2 Dual Channel] @3600 CL:16
    Graphics card(s)
    Integrated Intel UHD 720 iGPU
    Sound Card
    Motherboard Realtek UDA DTS Audio
    Monitor(s) Displays
    Sony Bravia 32" LED TV
    Screen Resolution
    1920 * 1080 (Full HD)
    Hard Drives
    1. SSD: NVME M.2 2280 Gen3x4 WD Blue SN570 250GB
    2. HDD: WD Blue 1TB @5400
    PSU
    Cooler Master MWE V2 750W Gold Fully Modular
    Case
    Cooler Master MasterBox MB540 ARGB
    Cooling
    Intel Stock CPU Cooler FAN+ 5x Arctic Chassis 120mm PWM PST CO Pressure-Optimized Fans
    Keyboard
    Logitech K295 Wireless M&K Combo
    Mouse
    Logitech K295 Wireless M&K Combo
    Internet Speed
    100 Mbps Optical Fiber Broadband
    Browser
    Google+Firefox (Latest)
    Antivirus
    Eset Security Ultimate (Latest)
    Other Info
    My Workbench Configuration
If you’re running inside a VM and logging in directly as the admin account, then of course $env:UserName and [Environment]::UserName will return the admin—because that’s the interactive session user, not a standard user elevating via UAC.

Run this in an elevated command window outside the VM:
net user TestUser /add P@ssword123 runas /user:TestUser "powershell.exe"
Next, in the PowerShell window that opens, run this:
Powershell:
Write-Host "Environment UserName: $env:UserName"
Write-Host "Environment Domain: $env:UserDomain"
Write-Host "Token Identity: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)"

$ownerInfo = Get-WmiObject Win32_Process -Filter "ProcessId = $PID" | ForEach-Object {
    $owner = $_.GetOwner()
    "$($owner.Domain)\$($owner.User)"
}
Write-Host "Process Owner: $ownerInfo"
This will show:
  • $env:UserName ➜ launching user
  • WindowsIdentity ➜ execution token (admin if elevated)
  • Process Owner ➜ who launched the process (should match $env:UserName)
Next, open an elevated PowerShell inside the VM like you said you did, and use it to run the script code above. If all three return the admin, then you didn’t launch from a standard user—you launched from admin directly. If you want the standard user who launched the elevated PowerShell, only the process owner via WMI will give you that. Everything else reflects either the environment or the token—not the origin.
(You can run net user TestUser /delete in an elevated command window—once you convinced yourself that you’ve seen the truth.)

As for the error you got with GetOwner(), This happened simply because you changed Get-WmiObject to Get-CimInstance.

It does work in an elevated context
Sure—in your test setup. But that doesn’t mean it’s robust across all elevated contexts. Your trio of functions relies on:
  1. Win32_ComputerSystem.UserName ➜ assumes a single interactive user.
  2. Get-LocalUser ➜ assumes the user is a local account.
  3. Registry access via SID ➜ assumes the SID is valid and the hive is loaded.
These assumptions can break in:
  • Domain environments: Get-LocalUser fails for domain users.
  • Fast User Switching: Win32_ComputerSystem.UserName may return the wrong session.
  • Remote sessions: WMI may return null or stale data.
  • Elevated contexts launched via service or scheduled task: no interactive user, no loaded hive.
  • Multi-user RDP: multiple sessions, multiple explorer.exe owners.
I suppose it is only in a non-interactive context
Not quite. The fragility isn’t limited to non-interactive contexts—it’s about how elevation and identity are resolved.
Even in interactive sessions:
  • If the user is domain-joined, Get-LocalUser fails.
  • If elevation is via runas or a service, WMI may return misleading data.
  • If the registry hive isn’t loaded (e.g., user logged off), HKEY_USERS\$SID is inaccessible.

What’s bulletproof?​

Querying explorer.exe ownership via WMI or CIM is the most reliable way to identify the interactive user who launched the elevated session. It works across:
  • Local and domain accounts
  • Interactive and elevated contexts
  • UAC elevation
  • Mixed environments
Powershell:
function Get-ProcessOwner {
    param([string]$ProcessName)

    try {
        $proc = Get-WmiObject Win32_Process -Filter "Name = '$ProcessName'" | Select-Object -First 1
        if (-not $proc) {
            Write-Error "Process '$ProcessName' not found."
            return $null
        }

        $owner = $proc.GetOwner()
        if (-not $owner.User) {
            Write-Warning "Owner of '$ProcessName' could not be resolved — SID may be orphaned or deleted."
            return $null
        }

        return "$($owner.Domain)\$($owner.User)"
    } catch {
        Write-Error "Failed to resolve owner of '$ProcessName': $($_.Exception.Message)"
        return $null
    }
}

# Identity layers
$envUser     = "$env:UserDomain\$env:UserName"
$tokenUser   = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$processUser = Get-ProcessOwner -ProcessName "powershell.exe"
$shellUser   = Get-ProcessOwner -ProcessName "explorer.exe"

Write-Host "Environment Block: $envUser"
Write-Host "Execution Token: $tokenUser"
if ($processUser) { Write-Host "PowerShell Owner: $processUser" }
if ($shellUser)   { Write-Host "Explorer.exe Owner: $shellUser" }

# Elevation detection
if ($shellUser -and ($tokenUser -ne $shellUser)) {
    Write-Host "Elevated context detected — launched by: $shellUser"
} elseif ($shellUser) {
    Write-Host "No elevation — running as: $tokenUser"
} else {
    Write-Warning "Unable to determine elevation status — explorer.exe owner not resolved."
}
 
Last edited:

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
    Antivirus
    What's an antivirus?
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    30Mbit/s up, 500Mbit/s down
    Browser
    FF
I need to consult with you regarding this script & NTL integration
As I said, I have never used NTLite.

But what you want to do is:
In NTLite, go to the Post-Setup page and add a new command:
Code:
pwsh.exe -NoProfile -ExecutionPolicy Bypass -File MyScript.ps1
-ExecutionPolicy Bypass is not necessary with Powershell 7, but doesn't hurt to have it.

If you perform an online installation, add the command to install Powershell 7.
If it is an offline installation, include the .msi installater file and install it.
Code:
msiexec.exe /i PowerShell-7.5.3-win-x64.msi /qn

There are a lot of resources on internet to help you with NTLite.
You can look at their forum and/or documentation.
NTLite Forums

As there is a lot of online contents about NTLite, AI tools should be good to answer your questions. :)
example: Perplexity or ChatGPT or another one (Copilot, Gemini, Grok).

If you still struggle, the best option is to open a new post on NTLite forum as it is a NTLite question.
 

My Computer

System One

  • OS
    .
If you’re running inside a VM and logging in directly as the admin account, then of course $env:UserName and [Environment]::UserName will return the admin—because that’s the interactive session user, not a standard user elevating via UAC.
Seriously ? Of course I was logged-in as a standard user on the VM ...


Run this in an elevated command window outside the VM:
Code:
net user TestUser /add P@ssword123
runas /user:TestUser "powershell.exe"
Next, in the PowerShell window that opens, run this:
Code:
Write-Host "Environment UserName: $env:UserName"
Write-Host "Environment Domain: $env:UserDomain"
Write-Host "Token Identity: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)"

$ownerInfo = Get-WmiObject Win32_Process -Filter "ProcessId = $PID" | ForEach-Object {
    $owner = $_.GetOwner()
    "$($owner.Domain)\$($owner.User)"
}
Write-Host "Process Owner: $ownerInfo"
Code:
PS C:\Users\Admin_Bare_Metal> runas /user:SUser "powershell.exe"
Enter the password for SUser:
Attempting to start powershell.exe as user "DESKTOP-ABCDE42\SUser" ...
Code:
PS C:\WINDOWS\system32> $env:UserName
SUser
PS C:\WINDOWS\system32> [Environment]::UserName
SUser
PS C:\WINDOWS\system32> [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
DESKTOP-ABCDE42\SUser
PS C:\WINDOWS\system32> (Get-CimInstance -ClassName 'Win32_ComputerSystem').UserName
DESKTOP-ABCDE42\Admin_Bare_Metal
PS C:\WINDOWS\system32> (Get-WmiObject Win32_Process -Filter "ProcessId = $PID").GetOwner().User
SUser
This is the expected values as this is not an elevated session and we used runas.
I don't see the point of that test ...

When I'm logged-in with the standard account "SUser", here are the results from an elevated Powershell session:
Code:
PS C:\Users\Admin_Bare_Metal> $env:UserName
Admin_Bare_Metal
PS C:\Users\Admin_Bare_Metal> [Environment]::UserName
Admin_Bare_Metal
PS C:\Users\Admin_Bare_Metal> [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
DESKTOP-ABCDE42\Admin_Bare_Metal
PS C:\Users\Admin_Bare_Metal> (Get-CimInstance -ClassName 'Win32_ComputerSystem').UserName
DESKTOP-ABCDE42\SUser
PS C:\Users\Admin_Bare_Metal> (Get-WmiObject Win32_Process -Filter "ProcessId = $PID").GetOwner().User
Admin_Bare_Metal
It doesn't matter if it's in a VM or a bare metal machine, the results are the same.


Next, open an elevated PowerShell inside the VM like you said you did
If you don't trust me when I post something, I see no point to continue this discussion ...


If all three return the admin, then you didn’t launch from a standard user—you launched from admin directly. If you want the standard user who launched the elevated PowerShell, only the process owner via WMI will give you that. Everything else reflects either the environment or the token—not the origin.
(You can run net user TestUser /delete in an elevated command window—once you convinced yourself that you’ve seen the truth.)
What are the results of those commands if you test it yourself in an elevated session on a standard account ?
I think that you need to be convinced of the actual behavior.


As for the error you got with GetOwner(), This happened simply because you changed Get-WmiObject to Get-CimInstance.
I have not.
Actually, the code you posted works only with "Windows Powershell", it fails with "Powershell 7".
With "Powershell 7" we need to use Get-CimInstance and Invoke-CimMethod, and it also works with "Windows Powershell".
Beside, Get-WmiObject is deprecated and has been superseded by Get-CimInstance.


Sure—in your test setup. But that doesn’t mean it’s robust across all elevated contexts. Your trio of functions relies on:
  1. Win32_ComputerSystem.UserName ➜ assumes a single interactive user.
  2. Get-LocalUser ➜ assumes the user is a local account.
  3. Registry access via SID ➜ assumes the SID is valid and the hive is loaded.
These assumptions can break in:
  • Domain environments: Get-LocalUser fails for domain users.
  • Fast User Switching: Win32_ComputerSystem.UserName may return the wrong session.
  • Remote sessions: WMI may return null or stale data.
  • Elevated contexts launched via service or scheduled task: no interactive user, no loaded hive.
  • Multi-user RDP: multiple sessions, multiple explorer.exe owners.
The Get-LocalUser issue will be fixed by the .Net class as we previously discussed.
I will find a way if the hive is not loaded.
If there is no interactive user, there are not much I can do except allowing to manually enter or via a parameter the username.

You can't use runas as you cannot have an elevated prompt with it, and my script requires admin rights.
Even with:
Code:
Start-Process powershell.exe -Credential DESKTOP-ABCDE42\SUser -ArgumentList '-NoProfile -Command & { Start-Process powershell.exe -Verb RunAs}'
It will act as if you launched a Powershell session with the Admin account you are logged-in with.

Win32_ComputerSystem.UserName does work with multiple users logged-in (assuming the user has a GUI).
I think it should work for RDP even if multiple users are logged in.
Not sure about Remote session.


What’s bulletproof?​

Querying explorer.exe ownership via WMI or CIM is the most reliable way to identify the interactive user who launched the elevated session.
It is more reliable.
But if you have multiple users logged-in you can't tell who launched the script. And quser is not available on home edition.
For now, (Get-CimInstance -ClassName 'Win32_ComputerSystem').UserName is the best (only ?) option I have.
Code:
PS C:\Users\Admin> (Get-CimInstance Win32_Process -Filter 'name = "explorer.exe"' | Invoke-CimMethod -MethodName GetOwner).User
Admin
SUser


Thank you again. You pointed out some issues that I will fix.
i.e. The SID and the not loaded hive.
 

My Computer

System One

  • OS
    .
Hi everyone.
I want to share with you all the PowerShell script I made to automate the configuration of Windows.
Not only debloating Windows and minimizing telemetry, but automating every settings (in a reasonable way).

None of the scripts available online met my expectations, so I made my own.

WindowsMizeHeader.png

Automate and customize the configuration of Windows.
Debloat, minimize telemetry, apps installation, general settings, and more.


Hi everyone.

I would like to share with you the PowerShell script I made to automate the configuration of Windows.

It's not just about debloating Windows and minimizing telemetry.
It's also about automating every settings (in a reasonable way :)).

None of the available online scripts met my expectations, so I created my own.

🎯 Purpose​

  1. Install Windows (semi-unattended) + updates.
  2. Run the script.
  3. Finish some customization.

📝 Characteristics​

  • Fully non-interactive script: make sure to review everything before running it.
  • Designed for Windows 11 (most tweaks/settings also work on Windows 10).
  • Works on both Administrator and Standard account.

💫 Features​

  • 🖥️ Windows settings
  • 📁 File Explorer
  • ⌛ System Properties
  • ⚡ Power options
  • 🌐 Network
  • 📊 Telemetry
  • 🛠️ Tweaks
  • 💿 Applications
  • 💾 RamDisk
  • ⚙️ Services & Scheduled Tasks

See the Github README for the detailed list of all tweaks/settings.

📌 Link​

RAM Disk? I assume you're using a 3rd-party app for that? Would be nice if MS included the option to create RAM disks!
 

My Computer

System One

  • OS
    Windows 11 Pro 25H2 (RP channel)
    Computer type
    PC/Desktop
    Manufacturer/Model
    MSI
    CPU
    AMD Ryzen 7 9800X3D 8-core
    Motherboard
    MEG X870E Godlike
    Memory
    64GB Corsair Titanium 6000/CL30
    Graphics Card(s)
    MSI Suprim 5080 SOC
    Sound Card
    Soundblaster AE-9
    Monitor(s) Displays
    ASUS TUF Gaming VG289Q
    Screen Resolution
    3840x2160
    Hard Drives
    Samsung 9100 Pro 4TB (gen 5 x4, system drive/games)
    Samsung 990 Pro 2TB
    Samsung 980 Pro 2TB
    Samsung 870 Evo 4TB
    Samsung 870 Evo 2TB
    Samsung T9 4TB
    PSU
    Seasonic PX-2200
    Case
    Bequiet! Dark Base Pro 901
    Cooling
    Noctua NH-D15S Chromax black
    Keyboard
    Logitech G915 X (wired)
    Mouse
    Logitech G903 with PowerPlay charger
    Internet Speed
    900Mb/sec
    Browser
    Microsoft Edge
    Antivirus
    Windows Defender
Back
Top Bottom