.
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Calculate hash for Set-Association function
|
||||
|
||||
.VERSION
|
||||
7.1.4
|
||||
|
||||
.DATE
|
||||
24.02.2026
|
||||
|
||||
.COPYRIGHT
|
||||
(c) 2014—2026 Team Sophia
|
||||
|
||||
.LINK
|
||||
https://github.com/farag2/Sophia-Script-for-Windows
|
||||
#>
|
||||
function Get-Hash
|
||||
{
|
||||
[CmdletBinding()]
|
||||
[OutputType([string])]
|
||||
Param
|
||||
(
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 0
|
||||
)]
|
||||
[string]
|
||||
$ProgId,
|
||||
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 1
|
||||
)]
|
||||
[string]
|
||||
$Extension,
|
||||
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 2
|
||||
)]
|
||||
[string]
|
||||
$SubKey
|
||||
)
|
||||
|
||||
$Signature = @{
|
||||
Namespace = "WinAPI"
|
||||
Name = "PatentHash"
|
||||
Language = "CSharp"
|
||||
CompilerParameters = $CompilerParameters
|
||||
MemberDefinition = @"
|
||||
public static uint[] WordSwap(byte[] a, int sz, byte[] md5)
|
||||
{
|
||||
if (sz < 2 || (sz & 1) == 1)
|
||||
{
|
||||
throw new ArgumentException(String.Format("Invalid input size: {0}", sz), "sz");
|
||||
}
|
||||
|
||||
unchecked
|
||||
{
|
||||
uint o1 = 0;
|
||||
uint o2 = 0;
|
||||
int ta = 0;
|
||||
int ts = sz;
|
||||
int ti = ((sz - 2) >> 1) + 1;
|
||||
|
||||
uint c0 = (BitConverter.ToUInt32(md5, 0) | 1) + 0x69FB0000;
|
||||
uint c1 = (BitConverter.ToUInt32(md5, 4) | 1) + 0x13DB0000;
|
||||
|
||||
for (uint i = (uint)ti; i > 0; i--)
|
||||
{
|
||||
uint n = BitConverter.ToUInt32(a, ta) + o1;
|
||||
ta += 8;
|
||||
ts -= 2;
|
||||
|
||||
uint v1 = 0x79F8A395 * (n * c0 - 0x10FA9605 * (n >> 16)) + 0x689B6B9F * ((n * c0 - 0x10FA9605 * (n >> 16)) >> 16);
|
||||
uint v2 = 0xEA970001 * v1 - 0x3C101569 * (v1 >> 16);
|
||||
uint v3 = BitConverter.ToUInt32(a, ta - 4) + v2;
|
||||
uint v4 = v3 * c1 - 0x3CE8EC25 * (v3 >> 16);
|
||||
uint v5 = 0x59C3AF2D * v4 - 0x2232E0F1 * (v4 >> 16);
|
||||
|
||||
o1 = 0x1EC90001 * v5 + 0x35BD1EC9 * (v5 >> 16);
|
||||
o2 += o1 + v2;
|
||||
}
|
||||
|
||||
if (ts == 1)
|
||||
{
|
||||
uint n = BitConverter.ToUInt32(a, ta) + o1;
|
||||
|
||||
uint v1 = n * c0 - 0x10FA9605 * (n >> 16);
|
||||
uint v2 = 0xEA970001 * (0x79F8A395 * v1 + 0x689B6B9F * (v1 >> 16)) - 0x3C101569 * ((0x79F8A395 * v1 + 0x689B6B9F * (v1 >> 16)) >> 16);
|
||||
uint v3 = v2 * c1 - 0x3CE8EC25 * (v2 >> 16);
|
||||
|
||||
o1 = 0x1EC90001 * (0x59C3AF2D * v3 - 0x2232E0F1 * (v3 >> 16)) + 0x35BD1EC9 * ((0x59C3AF2D * v3 - 0x2232E0F1 * (v3 >> 16)) >> 16);
|
||||
o2 += o1 + v2;
|
||||
}
|
||||
|
||||
uint[] ret = new uint[2];
|
||||
ret[0] = o1;
|
||||
ret[1] = o2;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public static uint[] Reversible(byte[] a, int sz, byte[] md5)
|
||||
{
|
||||
if (sz < 2 || (sz & 1) == 1)
|
||||
{
|
||||
throw new ArgumentException(String.Format("Invalid input size: {0}", sz), "sz");
|
||||
}
|
||||
|
||||
unchecked
|
||||
{
|
||||
uint o1 = 0;
|
||||
uint o2 = 0;
|
||||
int ta = 0;
|
||||
int ts = sz;
|
||||
int ti = ((sz - 2) >> 1) + 1;
|
||||
|
||||
uint c0 = BitConverter.ToUInt32(md5, 0) | 1;
|
||||
uint c1 = BitConverter.ToUInt32(md5, 4) | 1;
|
||||
|
||||
for (uint i = (uint)ti; i > 0; i--)
|
||||
{
|
||||
uint n = (BitConverter.ToUInt32(a, ta) + o1) * c0;
|
||||
n = 0xB1110000 * n - 0x30674EEF * (n >> 16);
|
||||
ta += 8;
|
||||
ts -= 2;
|
||||
|
||||
uint v1 = 0x5B9F0000 * n - 0x78F7A461 * (n >> 16);
|
||||
uint v2 = 0x1D830000 * (0x12CEB96D * (v1 >> 16) - 0x46930000 * v1) + 0x257E1D83 * ((0x12CEB96D * (v1 >> 16) - 0x46930000 * v1) >> 16);
|
||||
uint v3 = BitConverter.ToUInt32(a, ta - 4) + v2;
|
||||
|
||||
uint v4 = 0x16F50000 * c1 * v3 - 0x5D8BE90B * (c1 * v3 >> 16);
|
||||
uint v5 = 0x2B890000 * (0x96FF0000 * v4 - 0x2C7C6901 * (v4 >> 16)) + 0x7C932B89 * ((0x96FF0000 * v4 - 0x2C7C6901 * (v4 >> 16)) >> 16);
|
||||
|
||||
o1 = 0x9F690000 * v5 - 0x405B6097 * (v5 >> 16);
|
||||
o2 += o1 + v2;
|
||||
}
|
||||
|
||||
if (ts == 1)
|
||||
{
|
||||
uint n = BitConverter.ToUInt32(a, ta) + o1;
|
||||
|
||||
uint v1 = 0xB1110000 * c0 * n - 0x30674EEF * ((c0 * n) >> 16);
|
||||
uint v2 = 0x5B9F0000 * v1 - 0x78F7A461 * (v1 >> 16);
|
||||
uint v3 = 0x1D830000 * (0x12CEB96D * (v2 >> 16) - 0x46930000 * v2) + 0x257E1D83 * ((0x12CEB96D * (v2 >> 16) - 0x46930000 * v2) >> 16);
|
||||
uint v4 = 0x16F50000 * c1 * v3 - 0x5D8BE90B * ((c1 * v3) >> 16);
|
||||
uint v5 = 0x96FF0000 * v4 - 0x2C7C6901 * (v4 >> 16);
|
||||
o1 = 0x9F690000 * (0x2B890000 * v5 + 0x7C932B89 * (v5 >> 16)) - 0x405B6097 * ((0x2B890000 * v5 + 0x7C932B89 * (v5 >> 16)) >> 16);
|
||||
o2 += o1 + v2;
|
||||
}
|
||||
|
||||
uint[] ret = new uint[2];
|
||||
ret[0] = o1;
|
||||
ret[1] = o2;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public static long MakeLong(uint left, uint right)
|
||||
{
|
||||
return (long)left << 32 | (long)right;
|
||||
}
|
||||
"@
|
||||
}
|
||||
|
||||
if (-not ("WinAPI.PatentHash" -as [type]))
|
||||
{
|
||||
Add-Type @Signature
|
||||
}
|
||||
|
||||
function Get-KeyLastWriteTime ($SubKey)
|
||||
{
|
||||
$LastModified = [WinAPI.Action]::GetLastModified([Microsoft.Win32.RegistryHive]::CurrentUser,$SubKey)
|
||||
$FileTime = ([DateTime]::New($LastModified.Year, $LastModified.Month, $LastModified.Day, $LastModified.Hour, $LastModified.Minute, 0, $LastModified.Kind)).ToFileTime()
|
||||
|
||||
return [string]::Format("{0:x8}{1:x8}", $FileTime -shr 32, $FileTime -band [uint32]::MaxValue)
|
||||
}
|
||||
|
||||
function Get-DataArray
|
||||
{
|
||||
[OutputType([array])]
|
||||
|
||||
# Secret static string stored in %SystemRoot%\SysWOW64\%SystemRoot%\System32\shell32.dll
|
||||
$userExperience = "User Choice set via Windows User Experience {D18B6DD5-6124-4341-9318-804003BAFA0B}"
|
||||
# Get user SID
|
||||
$userSID = (Get-CimInstance -ClassName Win32_UserAccount | Where-Object -FilterScript {$_.Name -eq $env:USERNAME}).SID
|
||||
$KeyLastWriteTime = Get-KeyLastWriteTime -SubKey $SubKey
|
||||
$baseInfo = ("{0}{1}{2}{3}{4}" -f $Extension, $userSID, $ProgId, $KeyLastWriteTime, $userExperience).ToLowerInvariant()
|
||||
$StringToUTF16LEArray = [System.Collections.ArrayList]@([System.Text.Encoding]::Unicode.GetBytes($baseInfo))
|
||||
$StringToUTF16LEArray += (0,0)
|
||||
|
||||
return $StringToUTF16LEArray
|
||||
}
|
||||
|
||||
function Get-PatentHash
|
||||
{
|
||||
[OutputType([string])]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[byte[]]
|
||||
$Array,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[byte[]]
|
||||
$MD5
|
||||
)
|
||||
|
||||
$Size = $Array.Count
|
||||
$ShiftedSize = ($Size -shr 2) - ($Size -shr 2 -band 1) * 1
|
||||
|
||||
[uint32[]]$Array1 = [WinAPI.PatentHash]::WordSwap($Array, [int]$ShiftedSize, $MD5)
|
||||
[uint32[]]$Array2 = [WinAPI.PatentHash]::Reversible($Array, [int]$ShiftedSize, $MD5)
|
||||
|
||||
$Ret = [WinAPI.PatentHash]::MakeLong($Array1[1] -bxor $Array2[1], $Array1[0] -bxor $Array2[0])
|
||||
|
||||
return [System.Convert]::ToBase64String([System.BitConverter]::GetBytes([Int64]$Ret))
|
||||
}
|
||||
|
||||
$DataArray = Get-DataArray
|
||||
$DataMD5 = [System.Security.Cryptography.HashAlgorithm]::Create("MD5").ComputeHash($DataArray)
|
||||
$Hash = Get-PatentHash -Array $DataArray -MD5 $DataMD5
|
||||
|
||||
return $Hash
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,204 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Post actions
|
||||
|
||||
.VERSION
|
||||
7.1.4
|
||||
|
||||
.DATE
|
||||
24.02.2026
|
||||
|
||||
.COPYRIGHT
|
||||
(c) 2014—2026 Team Sophia
|
||||
|
||||
.LINK
|
||||
https://github.com/farag2/Sophia-Script-for-Windows
|
||||
#>
|
||||
function PostActions
|
||||
{
|
||||
#region Refresh Environment
|
||||
$Signature = @{
|
||||
Namespace = "WinAPI"
|
||||
Name = "UpdateEnvironment"
|
||||
Language = "CSharp"
|
||||
CompilerOptions = $CompilerOptions
|
||||
MemberDefinition = @"
|
||||
private static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff);
|
||||
private const int WM_SETTINGCHANGE = 0x1a;
|
||||
private const int SMTO_ABORTIFHUNG = 0x0002;
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = false)]
|
||||
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
|
||||
private static extern IntPtr SendMessageTimeout(IntPtr hWnd, int Msg, IntPtr wParam, string lParam, int fuFlags, int uTimeout, IntPtr lpdwResult);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
|
||||
static extern bool SendNotifyMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam);
|
||||
|
||||
public static void Refresh()
|
||||
{
|
||||
// Update desktop icons
|
||||
SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
|
||||
|
||||
// Update environment variables
|
||||
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, null, SMTO_ABORTIFHUNG, 100, IntPtr.Zero);
|
||||
|
||||
// Update taskbar
|
||||
SendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, "TraySettings");
|
||||
}
|
||||
|
||||
private static readonly IntPtr hWnd = new IntPtr(65535);
|
||||
private const int Msg = 273;
|
||||
// Virtual key ID of the F5 in File Explorer
|
||||
private static readonly UIntPtr UIntPtr = new UIntPtr(41504);
|
||||
|
||||
[DllImport("user32.dll", SetLastError=true)]
|
||||
public static extern int PostMessageW(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam);
|
||||
|
||||
public static void PostMessage()
|
||||
{
|
||||
// Simulate pressing F5 to refresh the desktop
|
||||
PostMessageW(hWnd, Msg, UIntPtr, IntPtr.Zero);
|
||||
}
|
||||
"@
|
||||
}
|
||||
if (-not ("WinAPI.UpdateEnvironment" -as [type]))
|
||||
{
|
||||
Add-Type @Signature
|
||||
}
|
||||
|
||||
# Simulate pressing F5 to refresh the desktop
|
||||
[WinAPI.UpdateEnvironment]::PostMessage()
|
||||
|
||||
# Refresh desktop icons, environment variables, taskbar
|
||||
[WinAPI.UpdateEnvironment]::Refresh()
|
||||
|
||||
# Restart Start menu
|
||||
Stop-Process -Name StartMenuExperienceHost -Force -ErrorAction Ignore
|
||||
#endregion Refresh Environment
|
||||
|
||||
#region Other actions
|
||||
# Kill all explorer instances in case "launch folder windows in a separate process" enabled
|
||||
Get-Process -Name explorer | Stop-Process -Force
|
||||
Start-Sleep -Seconds 3
|
||||
|
||||
# Restoring closed folders
|
||||
if (Get-Variable -Name OpenedFolder -ErrorAction Ignore)
|
||||
{
|
||||
foreach ($Global:OpenedFolder in $Global:OpenedFolders)
|
||||
{
|
||||
if (Test-Path -Path $Global:OpenedFolder)
|
||||
{
|
||||
Start-Process -FilePath "$env:SystemRoot\explorer.exe" -ArgumentList $Global:OpenedFolder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Checking whether any of scheduled tasks were created. Unless open Task Scheduler
|
||||
if ($Global:ScheduledTasks)
|
||||
{
|
||||
# Find and close taskschd.msc by its argument
|
||||
$taskschd_Process_ID = (Get-CimInstance -ClassName CIM_Process | Where-Object -FilterScript {$_.Name -eq "mmc.exe"} | Where-Object -FilterScript {
|
||||
$_.CommandLine -match "taskschd.msc"
|
||||
}).Handle
|
||||
# We have to check before executing due to "Set-StrictMode -Version Latest"
|
||||
if ($taskschd_Process_ID)
|
||||
{
|
||||
Get-Process -Id $taskschd_Process_ID | Stop-Process -Force
|
||||
}
|
||||
|
||||
# Open Task Scheduler
|
||||
Start-Process -FilePath taskschd.msc
|
||||
|
||||
$Global:ScheduledTasks = $false
|
||||
}
|
||||
|
||||
# Apply policies found in registry to re-build database database because gpedit.msc relies in its own database
|
||||
if (Test-Path -Path "$env:TEMP\LGPO.txt")
|
||||
{
|
||||
& "$PSScriptRoot\..\..\Binaries\LGPO.exe" /t "$env:TEMP\LGPO.txt"
|
||||
& "$env:SystemRoot\System32\gpupdate.exe" /force
|
||||
}
|
||||
|
||||
# PowerShell 5.1 (7.5 too) interprets 8.3 file name literally, if an environment variable contains a non-Latin word
|
||||
# https://github.com/PowerShell/PowerShell/issues/21070
|
||||
Get-ChildItem -Path "$env:TEMP\LGPO.txt" -Force -ErrorAction Ignore | Remove-Item -Force -ErrorAction Ignore
|
||||
#endregion Other actions
|
||||
|
||||
#region Toast notifications
|
||||
# Enable notifications
|
||||
Remove-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\PushNotifications -Name ToastEnabled -Force -ErrorAction Ignore
|
||||
Remove-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Windows.ActionCenter.SmartOptOut -Name Enable -Force -ErrorAction Ignore
|
||||
Remove-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\Sophia -Name ShowBanner, ShowInActionCenter, Enabled -Force -ErrorAction Ignore
|
||||
Remove-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\SystemSettings\AccountNotifications -Name EnableAccountNotifications -Force -ErrorAction Ignore
|
||||
Remove-ItemProperty -Path HKCU:\Software\Policies\Microsoft\Windows\Explorer, HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer -Name DisableNotificationCenter -Force -ErrorAction Ignore
|
||||
Remove-ItemProperty -Path HKCU:\Software\Policies\Microsoft\Windows\CurrentVersion\PushNotifications -Name NoToastApplicationNotification -Force -ErrorAction Ignore
|
||||
Set-Policy -Scope Computer -Path SOFTWARE\Policies\Microsoft\Windows\Explorer -Name DisableNotificationCenter -Type CLEAR
|
||||
Set-Policy -Scope User -Path Software\Policies\Microsoft\Windows\Explorer -Name DisableNotificationCenter -Type CLEAR
|
||||
|
||||
if (-not (Test-Path -Path Registry::HKEY_CLASSES_ROOT\AppUserModelId\Sophia))
|
||||
{
|
||||
New-Item -Path Registry::HKEY_CLASSES_ROOT\AppUserModelId\Sophia -Force
|
||||
}
|
||||
# Register app
|
||||
New-ItemProperty -Path Registry::HKEY_CLASSES_ROOT\AppUserModelId\Sophia -Name DisplayName -Value Sophia -PropertyType String -Force
|
||||
# Determines whether the app can be seen in Settings where the user can turn notifications on or off
|
||||
New-ItemProperty -Path Registry::HKEY_CLASSES_ROOT\AppUserModelId\Sophia -Name ShowInSettings -Value 0 -PropertyType DWord -Force
|
||||
|
||||
# Call toast notification
|
||||
Add-Type -AssemblyName "$PSScriptRoot\..\..\Binaries\WinRT.Runtime.dll"
|
||||
Add-Type -AssemblyName "$PSScriptRoot\..\..\Binaries\Microsoft.Windows.SDK.NET.dll"
|
||||
|
||||
[xml]$ToastTemplate = @"
|
||||
<toast duration="Long" scenario="reminder">
|
||||
<visual>
|
||||
<binding template="ToastGeneric">
|
||||
<text>$($Localization.ThankfulToastTitle)</text>
|
||||
<text>$($Localization.DonateToastTitle)</text>
|
||||
</binding>
|
||||
</visual>
|
||||
<audio src="ms-winsoundevent:notification.default" />
|
||||
<actions>
|
||||
<action content="Ko-fi" arguments="https://ko-fi.com/farag" activationType="protocol"/>
|
||||
<action content="Boosty" arguments="https://boosty.to/teamsophia" activationType="protocol"/>
|
||||
</actions>
|
||||
</toast>
|
||||
"@
|
||||
|
||||
$ToastXml = [Windows.Data.Xml.Dom.XmlDocument]::New()
|
||||
$ToastXml.LoadXml($ToastTemplate.OuterXml)
|
||||
|
||||
$ToastMessage = [Windows.UI.Notifications.ToastNotification]::New($ToastXML)
|
||||
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier("Sophia").Show($ToastMessage)
|
||||
#endregion Toast notifications
|
||||
|
||||
Write-Verbose -Message "https://t.me/sophia_chat" -Verbose
|
||||
Write-Verbose -Message "https://t.me/sophianews" -Verbose
|
||||
Write-Verbose -Message "https://discord.gg/sSryhaEv79" -Verbose
|
||||
Write-Information -MessageData "" -InformationAction Continue
|
||||
Write-Verbose -Message "https://ko-fi.com/farag" -Verbose
|
||||
Write-Verbose -Message "https://boosty.to/teamsophia" -Verbose
|
||||
Write-Information -MessageData "" -InformationAction Continue
|
||||
|
||||
if ($Global:Error)
|
||||
{
|
||||
($Global:Error | ForEach-Object -Process {
|
||||
# Some errors may have the Windows nature and don't have a path to any of the module's files
|
||||
$ErrorInFile = if ($_.InvocationInfo.PSCommandPath)
|
||||
{
|
||||
Split-Path -Path $_.InvocationInfo.PSCommandPath -Leaf
|
||||
}
|
||||
|
||||
[PSCustomObject]@{
|
||||
$Localization.ErrorsLine = $_.InvocationInfo.ScriptLineNumber
|
||||
# Extract the localized "File" string from %SystemRoot%\System32\shell32.dll
|
||||
"$([WinAPI.GetStrings]::GetString(4130))" = $ErrorInFile
|
||||
$Localization.ErrorsMessage = $_.Exception.Message
|
||||
}
|
||||
} | Sort-Object -Property $Localization.ErrorsLine | Format-Table -AutoSize -Wrap | Out-String).Trim()
|
||||
}
|
||||
|
||||
Write-Information -MessageData "" -InformationAction Continue
|
||||
Write-Warning -Message $Localization.RestartWarning
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Redirect user folders to a new location
|
||||
|
||||
.EXAMPLE
|
||||
Set-KnownFolderPath -KnownFolder Desktop -Path "$env:SystemDrive:\Desktop"
|
||||
#>
|
||||
function Global:Set-KnownFolderPath
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet("Desktop", "Documents", "Downloads", "Music", "Pictures", "Videos")]
|
||||
[string]
|
||||
$KnownFolder,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
|
||||
$KnownFolders = @{
|
||||
"Desktop" = @("B4BFCC3A-DB2C-424C-B029-7FE99A87C641")
|
||||
"Documents" = @("FDD39AD0-238F-46AF-ADB4-6C85480369C7", "f42ee2d3-909f-4907-8871-4c22fc0bf756")
|
||||
"Downloads" = @("374DE290-123F-4565-9164-39C4925E467B", "7d83ee9b-2244-4e70-b1f5-5404642af1e4")
|
||||
"Music" = @("4BD8D571-6D19-48D3-BE97-422220080E43", "a0c69a99-21c8-4671-8703-7934162fcf1d")
|
||||
"Pictures" = @("33E28130-4E1E-4676-835A-98395C3BC3BB", "0ddd015d-b06c-45d5-8c4c-f59713854639")
|
||||
"Videos" = @("18989B1D-99B5-455B-841C-AB7C74E4DDFC", "35286a68-3c57-41a1-bbb1-0eae73d76c95")
|
||||
}
|
||||
|
||||
$Signature = @{
|
||||
Namespace = "WinAPI"
|
||||
Name = "KnownFolders"
|
||||
Language = "CSharp"
|
||||
CompilerParameters = $CompilerParameters
|
||||
MemberDefinition = @"
|
||||
[DllImport("shell32.dll")]
|
||||
public extern static int SHSetKnownFolderPath(ref Guid folderId, uint flags, IntPtr token, [MarshalAs(UnmanagedType.LPWStr)] string path);
|
||||
"@
|
||||
}
|
||||
if (-not ("WinAPI.KnownFolders" -as [type]))
|
||||
{
|
||||
Add-Type @Signature
|
||||
}
|
||||
|
||||
foreach ($GUID in $KnownFolders[$KnownFolder])
|
||||
{
|
||||
[WinAPI.KnownFolders]::SHSetKnownFolderPath([ref]$GUID, 0, 0, $Path)
|
||||
}
|
||||
(Get-Item -Path $Path -Force).Attributes = "ReadOnly"
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Create pre-configured text files for LGPO.exe tool
|
||||
|
||||
.EXAMPLE Set AllowTelemetry to 0 for all users in gpedit.msc snap-in
|
||||
Set-Policy -Scope Computer -Path SOFTWARE\Policies\Microsoft\Windows\DataCollection -Name AllowTelemetry -Type DWORD -Value 0
|
||||
|
||||
.EXAMPLE Set DisableSearchBoxSuggestions to 0 for current user in gpedit.msc snap-in
|
||||
Set-Policy -Scope User -Path Software\Policies\Microsoft\Windows\Explorer -Name DisableSearchBoxSuggestions -Type DWORD -Value 1
|
||||
|
||||
.EXAMPLE Set DisableNotificationCenter value to "Not configured" in gpedit.msc snap-in
|
||||
Set-Policy -Scope Computer -Path SOFTWARE\Policies\Microsoft\Windows\Explorer -Name DisableNotificationCenter -Type CLEAR
|
||||
|
||||
.NOTES
|
||||
https://techcommunity.microsoft.com/t5/microsoft-security-baselines/lgpo-exe-local-group-policy-object-utility-v1-0/ba-p/701045
|
||||
|
||||
.VERSION
|
||||
7.1.4
|
||||
|
||||
.DATE
|
||||
24.02.2026
|
||||
|
||||
.COPYRIGHT
|
||||
(c) 2014—2026 Team Sophia
|
||||
|
||||
.LINK
|
||||
https://github.com/farag2/Sophia-Script-for-Windows
|
||||
#>
|
||||
function Global:Set-Policy
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 1
|
||||
)]
|
||||
[string]
|
||||
[ValidateSet("Computer", "User")]
|
||||
$Scope,
|
||||
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 2
|
||||
)]
|
||||
[string]
|
||||
$Path,
|
||||
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 3
|
||||
)]
|
||||
[string]
|
||||
$Name,
|
||||
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 4
|
||||
)]
|
||||
[ValidateSet("DWORD", "SZ", "EXSZ", "CLEAR")]
|
||||
[string]
|
||||
$Type,
|
||||
|
||||
[Parameter(
|
||||
Mandatory = $false,
|
||||
Position = 5
|
||||
)]
|
||||
$Value
|
||||
)
|
||||
|
||||
if (-not (Test-Path -Path "$env:SystemRoot\System32\gpedit.msc"))
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
switch ($Type)
|
||||
{
|
||||
"CLEAR"
|
||||
{
|
||||
$Policy = @"
|
||||
$Scope
|
||||
$($Path)
|
||||
$($Name)
|
||||
$($Type)`n
|
||||
"@
|
||||
}
|
||||
default
|
||||
{
|
||||
$Policy = @"
|
||||
$Scope
|
||||
$($Path)
|
||||
$($Name)
|
||||
$($Type):$($Value)`n
|
||||
"@
|
||||
}
|
||||
}
|
||||
|
||||
# Save in UTF8 without BOM
|
||||
Add-Content -Path "$env:TEMP\LGPO.txt" -Value $Policy -Encoding Default -Force
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Change the location of the each user folder using SHSetKnownFolderPath function
|
||||
|
||||
.EXAMPLE
|
||||
Set-UserShellFolder -UserFolder Desktop -Path "$env:SystemDrive:\Desktop"
|
||||
|
||||
.LINK
|
||||
https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
|
||||
|
||||
.NOTES
|
||||
User files or folders won't be moved to a new location
|
||||
#>
|
||||
function Global:Set-UserShellFolder
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet("Desktop", "Documents", "Downloads", "Music", "Pictures", "Videos")]
|
||||
[string]
|
||||
$UserFolder,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]
|
||||
$Path
|
||||
)
|
||||
|
||||
# Get current user folder path
|
||||
$CurrentUserFolderPath = Get-ItemPropertyValue -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" -Name $UserFolderRegistry[$UserFolder]
|
||||
if ($CurrentUserFolder -ne $Path)
|
||||
{
|
||||
if (-not (Test-Path -Path $Path))
|
||||
{
|
||||
New-Item -Path $Path -ItemType Directory -Force
|
||||
}
|
||||
|
||||
Remove-Item -Path "$CurrentUserFolderPath\desktop.ini" -Force -ErrorAction Ignore
|
||||
|
||||
# Redirect user folder to a new location
|
||||
Set-KnownFolderPath -KnownFolder $UserFolder -Path $Path
|
||||
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" -Name $UserFolderGUIDs[$UserFolder] -PropertyType ExpandString -Value $Path -Force
|
||||
|
||||
# Save desktop.ini in the UTF-16 LE encoding
|
||||
Set-Content -Path "$Path\desktop.ini" -Value $DesktopINI[$UserFolder] -Encoding Unicode -Force
|
||||
(Get-Item -Path "$Path\desktop.ini" -Force).Attributes = "Hidden", "System", "Archive"
|
||||
(Get-Item -Path "$Path\desktop.ini" -Force).Refresh()
|
||||
|
||||
# Warn user is some files left in an old folder
|
||||
if ((Get-ChildItem -Path $CurrentUserFolderPath -ErrorAction Ignore | Measure-Object).Count -ne 0)
|
||||
{
|
||||
Write-Warning -Message ($Localization.UserShellFolderNotEmpty -f $CurrentUserFolderPath)
|
||||
Write-Error -Message ($Localization.UserShellFolderNotEmpty -f $CurrentUserFolderPath) -ErrorAction SilentlyContinue
|
||||
Write-Information -MessageData "" -InformationAction Continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
"Show menu" function with the up/down arrow keys and enter key to make a selection
|
||||
|
||||
.PARAMETER Menu
|
||||
Array of items to choose from
|
||||
|
||||
.PARAMETER Default
|
||||
Default selected item in array
|
||||
|
||||
.PARAMETER AddSkip
|
||||
Add localized extracted "Skip" string from %SystemRoot%\System32\shell32.dll
|
||||
|
||||
.EXAMPLE
|
||||
Show-Menu -Menu @($Item1, $Item2) -Default 1
|
||||
|
||||
.LINK
|
||||
https://qna.habr.com/answer?answer_id=1522379
|
||||
https://github.com/ryandunton/InteractivePSMenu
|
||||
#>
|
||||
function Global:Show-Menu
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[array]
|
||||
$Menu,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[int]
|
||||
$Default,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]
|
||||
$AddSkip
|
||||
)
|
||||
|
||||
Write-Information -MessageData "" -InformationAction Continue
|
||||
|
||||
# Add "Please use the arrow keys 🠕 and 🠗 on your keyboard to select your answer" to menu
|
||||
$Menu += $Localization.KeyboardArrows -f [System.Char]::ConvertFromUtf32(0x2191), [System.Char]::ConvertFromUtf32(0x2193)
|
||||
|
||||
if ($AddSkip)
|
||||
{
|
||||
# Extract the localized "Skip" string from %SystemRoot%\System32\shell32.dll
|
||||
$Menu += [WinAPI.GetStrings]::GetString(16956)
|
||||
}
|
||||
|
||||
$i = 0
|
||||
while ($i -lt $Menu.Count)
|
||||
{
|
||||
$i++
|
||||
Write-Host -Object ""
|
||||
}
|
||||
|
||||
$SelectedValueIndex = [Math]::Max([Math]::Min($Default, $Menu.Count), 0)
|
||||
|
||||
do
|
||||
{
|
||||
[Console]::SetCursorPosition(0, [Console]::CursorTop - $Menu.Count)
|
||||
|
||||
for ($i = 0; $i -lt $Menu.Count; $i++)
|
||||
{
|
||||
if ($i -eq $SelectedValueIndex)
|
||||
{
|
||||
Write-Host -Object "[>] $($Menu[$i])" -NoNewline
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Host -Object "[ ] $($Menu[$i])" -NoNewline
|
||||
}
|
||||
|
||||
Write-Host -Object ""
|
||||
}
|
||||
|
||||
$Key = [Console]::ReadKey()
|
||||
switch ($Key.Key)
|
||||
{
|
||||
"UpArrow"
|
||||
{
|
||||
$SelectedValueIndex = [Math]::Max(0, $SelectedValueIndex - 1)
|
||||
}
|
||||
"DownArrow"
|
||||
{
|
||||
$SelectedValueIndex = [Math]::Min($Menu.Count - 1, $SelectedValueIndex + 1)
|
||||
}
|
||||
"Enter"
|
||||
{
|
||||
return $Menu[$SelectedValueIndex]
|
||||
}
|
||||
}
|
||||
}
|
||||
while ($Key.Key -notin ([ConsoleKey]::Escape, [ConsoleKey]::Enter))
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Write registry keys for Set-Association function
|
||||
|
||||
.VERSION
|
||||
7.1.4
|
||||
|
||||
.DATE
|
||||
24.02.2026
|
||||
|
||||
.COPYRIGHT
|
||||
(c) 2014—2026 Team Sophia
|
||||
|
||||
.LINK
|
||||
https://github.com/farag2/Sophia-Script-for-Windows
|
||||
#>
|
||||
function Global:Write-AdditionalKeys
|
||||
{
|
||||
Param
|
||||
(
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 0
|
||||
)]
|
||||
[string]
|
||||
$ProgId,
|
||||
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 1
|
||||
)]
|
||||
[string]
|
||||
$Extension
|
||||
)
|
||||
|
||||
# If there is a ProgId extension, overwrite it to the configured value by default
|
||||
# We have to use GetValue() due to "Set-StrictMode -Version Latest"
|
||||
if ([Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Classes\$Extension", "", $null))
|
||||
{
|
||||
if (-not (Test-Path -Path Registry::HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\FileAssociations\ProgIds))
|
||||
{
|
||||
New-Item -Path Registry::HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\FileAssociations\ProgIds -Force
|
||||
}
|
||||
New-ItemProperty -Path Registry::HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\FileAssociations\ProgIds -Name "_$($Extension)" -PropertyType DWord -Value 1 -Force
|
||||
}
|
||||
|
||||
# Setting 'NoOpenWith' for all registered the extension ProgIDs
|
||||
# We have to check everything due to "Set-StrictMode -Version Latest"
|
||||
if (Get-Item -Path "Registry::HKEY_CLASSES_ROOT\$Extension\OpenWithProgids" -ErrorAction Ignore)
|
||||
{
|
||||
[psobject]$OpenSubkey = (Get-Item -Path "Registry::HKEY_CLASSES_ROOT\$Extension\OpenWithProgids" -ErrorAction Ignore).Property
|
||||
if ($OpenSubkey)
|
||||
{
|
||||
foreach ($AppxProgID in ($OpenSubkey | Where-Object -FilterScript {$_ -match "AppX"}))
|
||||
{
|
||||
# If an app is installed
|
||||
if (Get-ItemPropertyValue -Path "HKCU:\Software\Classes\$AppxProgID\Shell\open" -Name PackageId)
|
||||
{
|
||||
# If the specified ProgId is equal to UWP installed ProgId
|
||||
if ($ProgId -eq $AppxProgID)
|
||||
{
|
||||
# Remove association limitations for this UWP apps
|
||||
Remove-ItemProperty -Path "HKCU:\Software\Classes\$AppxProgID" -Name NoOpenWith, NoStaticDefaultVerb -Force -ErrorAction Ignore
|
||||
}
|
||||
else
|
||||
{
|
||||
New-ItemProperty -Path "HKCU:\Software\Classes\$AppxProgID" -Name NoOpenWith -PropertyType String -Value "" -Force
|
||||
}
|
||||
|
||||
$Global:RegisteredProgIDs += $AppxProgID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# We have to use GetValue() due to "Set-StrictMode -Version Latest"
|
||||
if ([Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\KindMap", $Extension, $null))
|
||||
{
|
||||
$picture = (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\KindMap -Name $Extension -ErrorAction Ignore).$Extension
|
||||
}
|
||||
# We have to use GetValue() due to "Set-StrictMode -Version Latest"
|
||||
if ([Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PBrush\CLSID", "", $null))
|
||||
{
|
||||
$PBrush = (Get-ItemProperty -Path HKLM:\SOFTWARE\Classes\PBrush\CLSID -Name "(default)" -ErrorAction Ignore)."(default)"
|
||||
}
|
||||
|
||||
# We have to check everything due to "Set-StrictMode -Version Latest"
|
||||
if (Get-Variable -Name picture -ErrorAction Ignore)
|
||||
{
|
||||
if (($picture -eq "picture") -and $PBrush)
|
||||
{
|
||||
New-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\ApplicationAssociationToasts -Name "PBrush_$($Extension)" -PropertyType DWord -Value 0 -Force
|
||||
}
|
||||
}
|
||||
|
||||
# We have to use GetValue() due to "Set-StrictMode -Version Latest"
|
||||
if (([Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\KindMap", $Extension, $null)) -eq "picture")
|
||||
{
|
||||
$Global:RegisteredProgIDs += "PBrush"
|
||||
}
|
||||
|
||||
if ($Extension.Contains("."))
|
||||
{
|
||||
[string]$Associations = "FileAssociations"
|
||||
}
|
||||
else
|
||||
{
|
||||
[string]$Associations = "UrlAssociations"
|
||||
}
|
||||
|
||||
foreach ($Item in @((Get-Item -Path "HKLM:\SOFTWARE\RegisteredApplications").Property))
|
||||
{
|
||||
$Subkey = (Get-ItemProperty -Path "HKLM:\SOFTWARE\RegisteredApplications" -Name $Item -ErrorAction Ignore).$Item
|
||||
if ($Subkey)
|
||||
{
|
||||
if (Test-Path -Path "HKLM:\$Subkey\$Associations")
|
||||
{
|
||||
$isProgID = [Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\$Subkey\$Associations", $Extension, $null)
|
||||
if ($isProgID)
|
||||
{
|
||||
$Global:RegisteredProgIDs += $isProgID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Clear-Variable -Name UserRegisteredProgIDs -Force -ErrorAction Ignore
|
||||
[array]$UserRegisteredProgIDs = @()
|
||||
|
||||
foreach ($Item in (Get-Item -Path "HKCU:\Software\RegisteredApplications").Property)
|
||||
{
|
||||
$Subkey = (Get-ItemProperty -Path "HKCU:\Software\RegisteredApplications" -Name $Item -ErrorAction Ignore).$Item
|
||||
if ($Subkey)
|
||||
{
|
||||
if (Test-Path -Path "HKCU:\$Subkey\$Associations")
|
||||
{
|
||||
$isProgID = [Microsoft.Win32.Registry]::GetValue("HKEY_CURRENT_USER\$Subkey\$Associations", $Extension, $null)
|
||||
if ($isProgID)
|
||||
{
|
||||
$UserRegisteredProgIDs += $isProgID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$UserRegisteredProgIDs = ($Global:RegisteredProgIDs + $UserRegisteredProgIDs | Sort-Object -Unique)
|
||||
foreach ($UserProgID in $UserRegisteredProgIDs)
|
||||
{
|
||||
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\ApplicationAssociationToasts" -Name "$($UserProgID)_$($Extension)" -PropertyType DWord -Value 0 -Force
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Write registry keys for extensions for Set-Association function
|
||||
|
||||
.VERSION
|
||||
7.1.4
|
||||
|
||||
.DATE
|
||||
24.02.2026
|
||||
|
||||
.COPYRIGHT
|
||||
(c) 2014—2026 Team Sophia
|
||||
|
||||
.LINK
|
||||
https://github.com/farag2/Sophia-Script-for-Windows
|
||||
#>
|
||||
function Global:Write-ExtensionKeys
|
||||
{
|
||||
Param
|
||||
(
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 0
|
||||
)]
|
||||
[string]
|
||||
$ProgId,
|
||||
|
||||
[Parameter(
|
||||
Mandatory = $true,
|
||||
Position = 1
|
||||
)]
|
||||
[string]
|
||||
$Extension
|
||||
)
|
||||
|
||||
# We have to use GetValue() due to "Set-StrictMode -Version Latest"
|
||||
$OrigProgID = [Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Classes\$Extension", "", $null)
|
||||
if ($OrigProgID)
|
||||
{
|
||||
# Save ProgIds history with extensions or protocols for the system ProgId
|
||||
$Global:RegisteredProgIDs += $OrigProgID
|
||||
}
|
||||
|
||||
# We have to use GetValue() due to "Set-StrictMode -Version Latest"
|
||||
if ([Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Classes\$Extension", "", $null) -ne "")
|
||||
{
|
||||
# Save possible ProgIds history with extension
|
||||
New-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\ApplicationAssociationToasts -Name "$($ProgID)_$($Extension)" -PropertyType DWord -Value 0 -Force
|
||||
}
|
||||
|
||||
$Name = "{0}_$($Extension)" -f (Split-Path -Path $ProgId -Leaf)
|
||||
New-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\ApplicationAssociationToasts -Name $Name -PropertyType DWord -Value 0 -Force
|
||||
|
||||
if ("$($ProgID)_$($Extension)" -ne $Name)
|
||||
{
|
||||
New-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\ApplicationAssociationToasts -Name "$($ProgID)_$($Extension)" -PropertyType DWord -Value 0 -Force
|
||||
}
|
||||
|
||||
# If ProgId doesn't exist set the specified ProgId for the extensions
|
||||
# We have to use GetValue() due to "Set-StrictMode -Version Latest"
|
||||
if (-not [Microsoft.Win32.Registry]::GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Classes\$Extension", "", $null))
|
||||
{
|
||||
if (-not (Test-Path -Path "HKCU:\Software\Classes\$Extension"))
|
||||
{
|
||||
New-Item -Path "HKCU:\Software\Classes\$Extension" -Force
|
||||
}
|
||||
New-ItemProperty -Path "HKCU:\Software\Classes\$Extension" -Name "(default)" -PropertyType String -Value $ProgId -Force
|
||||
}
|
||||
|
||||
# Set the specified ProgId in the possible options for the assignment
|
||||
if (-not (Test-Path -Path "HKCU:\Software\Classes\$Extension\OpenWithProgids"))
|
||||
{
|
||||
New-Item -Path "HKCU:\Software\Classes\$Extension\OpenWithProgids" -Force
|
||||
}
|
||||
New-ItemProperty -Path "HKCU:\Software\Classes\$Extension\OpenWithProgids" -Name $ProgId -PropertyType None -Value ([byte[]]@()) -Force
|
||||
|
||||
# Set the system ProgId to the extension parameters for File Explorer to the possible options for the assignment, and if absent set the specified ProgId
|
||||
# We have to use GetValue() due to "Set-StrictMode -Version Latest"
|
||||
if ($OrigProgID)
|
||||
{
|
||||
if (-not (Test-Path -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\OpenWithProgids"))
|
||||
{
|
||||
New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\OpenWithProgids" -Force
|
||||
}
|
||||
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\OpenWithProgids" -Name $OrigProgID -PropertyType None -Value ([byte[]]@()) -Force
|
||||
}
|
||||
|
||||
if (-not (Test-Path -Path "HKCU:\Software\Classes\$Extension\OpenWithProgids"))
|
||||
{
|
||||
New-Item -Path "HKCU:\Software\Classes\$Extension\OpenWithProgids" -Force
|
||||
}
|
||||
New-ItemProperty -Path "HKCU:\Software\Classes\$Extension\OpenWithProgids" -Name $ProgID -PropertyType None -Value ([byte[]]@()) -Force
|
||||
|
||||
# A small pause added to complete all operations, unless sometimes PowerShell has not time to clear reguistry permissions
|
||||
Start-Sleep -Seconds 1
|
||||
|
||||
# Removing the UserChoice key
|
||||
[WinAPI.Action]::DeleteKey([Microsoft.Win32.RegistryHive]::CurrentUser, "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice")
|
||||
Remove-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice" -Force -ErrorAction Ignore
|
||||
|
||||
# Setting parameters in UserChoice. The key is being autocreated
|
||||
if (-not (Test-Path -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice"))
|
||||
{
|
||||
New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice" -Force
|
||||
}
|
||||
|
||||
# We need to remove DENY permission set for user before setting a value
|
||||
if (@(".pdf", "http", "https") -contains $Extension)
|
||||
{
|
||||
# https://powertoe.wordpress.com/2010/08/28/controlling-registry-acl-permissions-with-powershell/
|
||||
$Key = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice",[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::ChangePermissions)
|
||||
$ACL = $key.GetAccessControl()
|
||||
$Principal = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
|
||||
# https://learn.microsoft.com/en-us/dotnet/api/system.security.accesscontrol.filesystemrights
|
||||
$Rule = New-Object -TypeName System.Security.AccessControl.RegistryAccessRule -ArgumentList ($Principal,"FullControl","Deny")
|
||||
$ACL.RemoveAccessRule($Rule)
|
||||
$Key.SetAccessControl($ACL)
|
||||
|
||||
# We need to use here an approach with "-Command & {}" as there's a variable inside
|
||||
& "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell_temp.exe" -Command "& {New-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice' -Name ProgId -PropertyType String -Value $ProgID -Force}"
|
||||
}
|
||||
else
|
||||
{
|
||||
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice" -Name ProgId -PropertyType String -Value $ProgID -Force
|
||||
}
|
||||
|
||||
# Getting a hash based on the time of the section's last modification. After creating and setting the first parameter
|
||||
$ProgHash = Get-Hash -ProgId $ProgId -Extension $Extension -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice"
|
||||
|
||||
if (-not (Test-Path -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice"))
|
||||
{
|
||||
New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice" -Force
|
||||
}
|
||||
|
||||
if (@(".pdf", "http", "https") -contains $Extension)
|
||||
{
|
||||
# We need to use here an approach with "-Command & {}" as there's a variable inside
|
||||
& "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell_temp.exe" -Command "& {New-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice' -Name Hash -PropertyType String -Value $ProgHash -Force}"
|
||||
}
|
||||
else
|
||||
{
|
||||
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice" -Name Hash -PropertyType String -Value $ProgHash -Force
|
||||
}
|
||||
|
||||
# Setting a block on changing the UserChoice section
|
||||
# We have to use OpenSubKey() due to "Set-StrictMode -Version Latest"
|
||||
$OpenSubKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice", "ReadWriteSubTree", "TakeOwnership")
|
||||
if ($OpenSubKey)
|
||||
{
|
||||
$Acl = [System.Security.AccessControl.RegistrySecurity]::new()
|
||||
# Get current user SID
|
||||
$UserSID = (Get-CimInstance -ClassName Win32_UserAccount | Where-Object -FilterScript {$_.Name -eq $env:USERNAME}).SID
|
||||
$Acl.SetSecurityDescriptorSddlForm("O:$UserSID`G:$UserSID`D:AI(D;;DC;;;$UserSID)")
|
||||
$OpenSubKey.SetAccessControl($Acl)
|
||||
$OpenSubKey.Close()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user