function Set-Association { [CmdletBinding()] param ( [Parameter( Position = 0, Mandatory = $true )] [ValidateScript({Test-Path -Path $_})] [String] $ProgramPath, [Parameter( Position = 1, Mandatory = $true )] [String] $Extension, [Parameter( Position = 3, Mandatory = $false )] [String] $Icon ) $ProgId = "Applications\" + (Get-Item -Path $ProgramPath).BaseName + $Extension 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 if (-not (Test-Path -Path "HKCU:\SOFTWARE\Classes\$ProgId\shell\open\command")) { New-Item -Path "HKCU:\SOFTWARE\Classes\$ProgId\shell\open\command" -Force } New-ItemProperty -Path "HKCU:\SOFTWARE\Classes\$ProgId\shell\open\command" -Name "(Default)" -PropertyType String -Value "`"$ProgramPath`" `"%1`"" -Force function Set-FTA { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $ProgId, [Parameter(Mandatory = $true)] [String] $Extension, [String] $Icon ) function local:Set-Icon { param ( [Parameter( Position = 0, Mandatory = $true )] [String] $ProgId, [Parameter( Position = 1, Mandatory = $true )] [String] $Icon ) if (-not (Test-Path -Path "HKCU:\SOFTWARE\Classes\$ProgId\DefaultIcon")) { New-Item -Path "HKCU:\SOFTWARE\Classes\$ProgId\DefaultIcon" -Force } New-ItemProperty -Path "HKCU:\SOFTWARE\Classes\$ProgId\DefaultIcon" -Name "(Default)" -PropertyType String -Value $Icon -Force } function local:Write-ExtensionKeys { param ( [Parameter( Position = 0, Mandatory = $true )] [String] $ProgId, [Parameter( Position = 1, Mandatory = $true )] [String] $Extension, [Parameter( Position = 2, Mandatory = $true )] [String] $ProgHash ) function local:Remove-UserChoiceKey { param ( [Parameter( Position = 0, Mandatory = $true )] [String] $Key ) $Signature = @{ Namespace = "Registry" Name = "Utils" Language = "CSharp" MemberDefinition = @" [DllImport("advapi32.dll", SetLastError = true)] private static extern int RegOpenKeyEx(UIntPtr hKey, string subKey, int ulOptions, int samDesired, out UIntPtr hkResult); [DllImport("advapi32.dll", SetLastError=true, CharSet = CharSet.Unicode)] private static extern uint RegDeleteKey(UIntPtr hKey, string subKey); public static void DeleteKey(string key) { UIntPtr hKey = UIntPtr.Zero; RegOpenKeyEx((UIntPtr)0x80000001u, key, 0, 0x20019, out hKey); RegDeleteKey((UIntPtr)0x80000001u, key); } "@ } if (-not ("Registry.Utils" -as [type])) { Add-Type @Signature } [Registry.Utils]::DeleteKey($Key) } Remove-UserChoiceKey -Key "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 } New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice" -Name Hash -PropertyType String -Value $ProgHash -Force New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$Extension\UserChoice" -Name ProgId -PropertyType String -Value $ProgId -Force } function local:Get-HexDateTime { [OutputType([string])] $now = [DateTime]::Now $dateTime = [DateTime]::New($now.Year, $now.Month, $now.Day, $now.Hour, $now.Minute, 0) $fileTime = $dateTime.ToFileTime() $hi = ($fileTime -shr 32) $low = ($fileTime -band 0xFFFFFFFFL) $dateTimeHex = ($hi.ToString("X8") + $low.ToString("X8")).ToLower() return $dateTimeHex } function Get-Hash { [CmdletBinding()] param ( [Parameter( Position = 0, Mandatory = $true )] [string] $BaseInfo ) function local:Get-ShiftRight { [CmdletBinding()] param ( [Parameter( Position = 0, Mandatory = $true )] [long] $iValue, [Parameter( Position = 1, Mandatory = $true )] [int] $iCount ) if ($iValue -band 0x80000000) { return (($iValue -shr $iCount) -bxor 0xFFFF0000) } else { return ($iValue -shr $iCount) } } function local:Get-Long { [CmdletBinding()] param ( [Parameter( Position = 0, Mandatory = $true )] [byte[]] $Bytes, [Parameter(Position = 1)] [int] $Index = 0 ) return ([BitConverter]::ToInt32($Bytes, $Index)) } function local:Convert-Int32 { param ( [Parameter( Position = 0, Mandatory = $true )] $Value ) [byte[]]$bytes = [BitConverter]::GetBytes($Value) return [BitConverter]::ToInt32($bytes, 0) } [byte[]]$bytesBaseInfo = [System.Text.Encoding]::Unicode.GetBytes($baseInfo) $bytesBaseInfo += 0x00, 0x00 $MD5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider [byte[]]$bytesMD5 = $MD5.ComputeHash($bytesBaseInfo) $lengthBase = ($baseInfo.Length * 2) + 2 $length = (($lengthBase -band 4) -le 1) + (Get-ShiftRight -iValue $lengthBase -iCount 2) - 1 $base64Hash = "" if ($length -gt 1) { $Map = @{ PDATA = 0 CACHE = 0 COUNTER = 0 INDEX = 0 MD51 = 0 MD52 = 0 OUTHASH1 = 0 OUTHASH2 = 0 R0 = 0 R1 = @(0, 0) R2 = @(0, 0) R3 = 0 R4 = @(0, 0) R5 = @(0, 0) R6 = @(0, 0) R7 = @(0, 0) } $Map.CACHE = 0 $Map.OUTHASH1 = 0 $Map.PDATA = 0 $Map.MD51 = (((Get-Long -Bytes $bytesMD5) -bor 1) + 0x69FB0000L) $Map.MD52 = ((Get-Long -Bytes $bytesMD5 -Index 4) -bor 1) + 0x13DB0000L $Map.INDEX = Get-ShiftRight -iValue ($length - 2) -iCount 1 $Map.COUNTER = $Map.INDEX + 1 while ($Map.COUNTER) { $Map.R0 = Convert-Int32 -Value ((Get-Long -Bytes $bytesBaseInfo -Index $Map.PDATA) + [long]$Map.OUTHASH1) $Map.R1[0] = Convert-Int32 -Value (Get-Long -Bytes $bytesBaseInfo -Index ($Map.PDATA + 4)) $Map.PDATA = $Map.PDATA + 8 $Map.R2[0] = Convert-Int32 -Value (($Map.R0 * ([long]$Map.MD51)) - (0x10FA9605L * ((Get-ShiftRight -iValue $Map.R0 -iCount 16)))) $Map.R2[1] = Convert-Int32 -Value ((0x79F8A395L * ([long]$Map.R2[0])) + (0x689B6B9FL * (Get-ShiftRight -iValue $Map.R2[0] -iCount 16))) $Map.R3 = Convert-Int32 -Value ((0xEA970001L * $Map.R2[1]) - (0x3C101569L * (Get-ShiftRight -iValue $Map.R2[1] -iCount 16) )) $Map.R4[0] = Convert-Int32 -Value ($Map.R3 + $Map.R1[0]) $Map.R5[0] = Convert-Int32 -Value ($Map.CACHE + $Map.R3) $Map.R6[0] = Convert-Int32 -Value (($Map.R4[0] * [long]$Map.MD52) - (0x3CE8EC25L * (Get-ShiftRight -iValue $Map.R4[0] -iCount 16))) $Map.R6[1] = Convert-Int32 -Value ((0x59C3AF2DL * $Map.R6[0]) - (0x2232E0F1L * (Get-ShiftRight -iValue $Map.R6[0] -iCount 16))) $Map.OUTHASH1 = Convert-Int32 -Value ((0x1EC90001L * $Map.R6[1]) + (0x35BD1EC9L * (Get-ShiftRight -iValue $Map.R6[1] -iCount 16))) $Map.OUTHASH2 = Convert-Int32 -Value ([long]$Map.R5[0] + [long]$Map.OUTHASH1) $Map.CACHE = ([long]$Map.OUTHASH2) $Map.COUNTER = $Map.COUNTER - 1 } [byte[]] $outHash = @(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) [byte[]] $buffer = [BitConverter]::GetBytes($Map.OUTHASH1) $buffer.CopyTo($outHash, 0) $buffer = [BitConverter]::GetBytes($Map.OUTHASH2) $buffer.CopyTo($outHash, 4) $Map = @{ PDATA = 0 CACHE = 0 COUNTER = 0 INDEX = 0 MD51 = 0 MD52 = 0 OUTHASH1 = 0 OUTHASH2 = 0 R0 = 0 R1 = @(0, 0) R2 = @(0, 0) R3 = 0 R4 = @(0, 0) R5 = @(0, 0) R6 = @(0, 0) R7 = @(0, 0) } $Map.CACHE = 0 $Map.OUTHASH1 = 0 $Map.PDATA = 0 $Map.MD51 = ((Get-Long -Bytes $bytesMD5) -bor 1) $Map.MD52 = ((Get-Long -Bytes $bytesMD5 4) -bor 1) $Map.INDEX = Get-ShiftRight -iValue ($length - 2) -iCount 1 $Map.COUNTER = $Map.INDEX + 1 while ($Map.COUNTER) { $Map.R0 = Convert-Int32 -Value ((Get-Long -Bytes $bytesBaseInfo -Index $Map.PDATA) + ([long]$Map.OUTHASH1)) $Map.PDATA = $Map.PDATA + 8 $Map.R1[0] = Convert-Int32 -Value ($Map.R0 * [long]$Map.MD51) $Map.R1[1] = Convert-Int32 -Value ((0xB1110000L * $Map.R1[0]) - (0x30674EEFL * (Get-ShiftRight -iValue $Map.R1[0] -iCount 16))) $Map.R2[0] = Convert-Int32 -Value ((0x5B9F0000L * $Map.R1[1]) - (0x78F7A461L * (Get-ShiftRight -iValue $Map.R1[1] -iCount 16))) $Map.R2[1] = Convert-Int32 -Value ((0x12CEB96DL * (Get-ShiftRight -iValue $Map.R2[0] 16)) - (0x46930000L * $Map.R2[0])) $Map.R3 = Convert-Int32 -Value ((0x1D830000L * $Map.R2[1]) + (0x257E1D83L * (Get-ShiftRight -iValue $Map.R2[1] -iCount 16))) $Map.R4[0] = Convert-Int32 -Value ([long]$Map.MD52 * ([long]$Map.R3 + (Get-Long -Bytes $bytesBaseInfo -Index ($Map.PDATA - 4)))) $Map.R4[1] = Convert-Int32 -Value ((0x16F50000L * $Map.R4[0]) - (0x5D8BE90BL * (Get-ShiftRight -iValue $Map.R4[0] -iCount 16))) $Map.R5[0] = Convert-Int32 -Value ((0x96FF0000L * $Map.R4[1]) - (0x2C7C6901L * (Get-ShiftRight -iValue $Map.R4[1] -iCount 16))) $Map.R5[1] = Convert-Int32 -Value ((0x2B890000L * $Map.R5[0]) + (0x7C932B89L * (Get-ShiftRight -iValue $Map.R5[0] -iCount 16))) $Map.OUTHASH1 = Convert-Int32 -Value ((0x9F690000L * $Map.R5[1]) - (0x405B6097L * (Get-ShiftRight -iValue ($Map.R5[1]) -iCount 16))) $Map.OUTHASH2 = Convert-Int32 -Value ([long]$Map.OUTHASH1 + $Map.CACHE + $Map.R3) $Map.CACHE = ([long]$Map.OUTHASH2) $Map.COUNTER = $Map.COUNTER - 1 } $buffer = [BitConverter]::GetBytes($Map.OUTHASH1) $buffer.CopyTo($outHash, 8) $buffer = [BitConverter]::GetBytes($Map.OUTHASH2) $buffer.CopyTo($outHash, 12) [byte[]]$outHashBase = @(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) $hashValue1 = ((Get-Long -Bytes $outHash -Index 8) -bxor (Get-Long -Bytes $outHash)) $hashValue2 = ((Get-Long -Bytes $outHash 12) -bxor (Get-Long -Bytes $outHash -Index 4)) $buffer = [BitConverter]::GetBytes($hashValue1) $buffer.CopyTo($outHashBase, 0) $buffer = [BitConverter]::GetBytes($hashValue2) $buffer.CopyTo($outHashBase, 4) $base64Hash = [Convert]::ToBase64String($outHashBase) } return $base64Hash } # Get current user SID $userSid = (Get-CimInstance -ClassName Win32_UserAccount | Where-Object -FilterScript {$_.Name -eq $env:USERNAME}).SID # Secret static string from %SystemRoot%\SysWOW64\shell32.dll $userExperience = "User Choice set via Windows User Experience {D18B6DD5-6124-4341-9318-804003BAFA0B}" $userDateTime = Get-HexDateTime $baseInfo = "$Extension$userSid$ProgId$userDateTime$userExperience".ToLower() $ProgHash = Get-Hash -BaseInfo $baseInfo #Handle Extension Write-ExtensionKeys -ProgId $ProgId -Extension $Extension -ProgHash $ProgHash if ($Icon) { Set-Icon -ProgId $ProgId -Icon $Icon } } Set-FTA -ProgId $ProgId -Extension $Extension -Icon $Icon } cls Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .cfg -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .ini -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .js -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .json -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .log -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .nfo -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .ps1 -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .psd1 -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .psm1 -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .txt -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .xml -Icon "C:\Program Files\Notepad++\notepad++.exe,0" Set-Association -ProgramPath "C:\Program Files\Notepad++\notepad++.exe" -Extension .psm1 -Icon "C:\Program Files\Notepad++\notepad++.exe,0" $UpdateExplorer = @{ Namespace = "WinAPI" Name = "UpdateExplorer" Language = "CSharp" MemberDefinition = @" private static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff); private const int WM_SETTINGCHANGE = 0x1a; private const int SMTO_ABORTIFHUNG = 0x0002; [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)] static extern bool SendNotifyMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam); [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("shell32.dll", CharSet = CharSet.Auto, SetLastError = false)] private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2); 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"); } "@ } if (-not ("WinAPI.UpdateExplorer" -as [type])) { Add-Type @UpdateExplorer } # Refresh desktop icons, environment variables, taskbar [WinAPI.UpdateExplorer]::Refresh()