La gestione del browser predefinito per più profili utente in un sistema Windows può essere un compito difficile, soprattutto in ambienti aziendali dove la coerenza e la conformità sono fondamentali. Automatizzando questo processo con uno script PowerShell si semplifica il compito, assicurando che ogni utente del sistema abbia la stessa esperienza di navigazione.
Questo articolo esplorerà uno script PowerShell progettato per impostare un browser predefinito per tutti gli utenti su un computer Windows, fornendo ai professionisti IT e ai Managed Service Provider (MSP) un potente strumento per mantenere il controllo sui propri ambienti.
Background
In un ambiente IT, in particolare nelle aziende o negli MSP, è fondamentale mantenere un’esperienza utente coerente. Quando si tratta di più utenti su un singolo computer o su una rete, l’impostazione manuale del browser predefinito per ogni profilo può richiedere molto lavoro ed essere soggetta a errori. Uno script PowerShell che automatizzi questo processo non solo fa risparmiare tempo, ma garantisce anche l’uniformità, che può essere essenziale per la conformità e il supporto agli utenti.
Questo specifico script è una versione modificata di uno script di Danysys, progettato per cambiare il browser predefinito per tutti gli utenti aggiornando le chiavi di registro. Lo script è altamente adattabile e supporta i browser più diffusi come Mozilla Firefox, Google Chrome e Microsoft Edge. Utilizzando lo script, gli amministratori IT possono garantire che tutti gli utenti abbiano il browser corretto impostato come predefinito, indipendentemente dal numero di profili o dallo stato del sistema.
Lo script per impostare un browser predefinito:
#Requires -Version 5.1 <# .SYNOPSIS Sets the default browser for all users. .DESCRIPTION Sets the default browser for all users. .EXAMPLE -Browser "Mozilla Firefox" -RestartExplorer Setting default browser of Mozilla Firefox for Administrator. Setting Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice\Hash changed from 2q7+uVxu0/A= to FKcuHm4FMN4= Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice\ProgId changed from ChromeHTML to FirefoxURL-308046B0AF4A39CB Setting Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice\Hash changed from zR3ANZC6jVI= to clMyDtJdxck= Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice\ProgId changed from ChromeHTML to FirefoxURL-308046B0AF4A39CB Setting Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\htm\UserChoice\Hash changed from IQfza9L6Tfw= to t8+HFkmUAd0= Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\htm\UserChoice\ProgId changed from ChromeHTML to FirefoxHTML-308046B0AF4A39CB Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.htm\UserChoice\Hash changed from IQfza9L6Tfw= to t8+HFkmUAd0= Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.htm\UserChoice\ProgId changed from ChromeHTML to FirefoxHTML-308046B0AF4A39CB Setting Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\html\UserChoice\Hash changed from 7CcRlkLW3ik= to q0Eix6jwLFg= Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\html\UserChoice\ProgId changed from ChromeHTML to FirefoxHTML-308046B0AF4A39CB Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice\Hash changed from 7CcRlkLW3ik= to q0Eix6jwLFg= Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice\ProgId changed from ChromeHTML to FirefoxHTML-308046B0AF4A39CB Setting Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\xhtml\UserChoice\Hash changed from IC7TXk1anlM= to y2gIOuiaLb0= Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\xhtml\UserChoice\ProgId changed from ChromeHTML to FirefoxHTML-308046B0AF4A39CB Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xhtml\UserChoice\Hash changed from IC7TXk1anlM= to y2gIOuiaLb0= Registry::HKEY_USERS\S-1-5-21-528047445-1317477324-4168425688-500\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.xhtml\UserChoice\ProgId changed from ChromeHTML to FirefoxHTML-308046B0AF4A39CB Restarting Explorer.exe PARAMETER: -Browser "Mozilla Firefox" Set the default browser to either "Mozilla Firefox", "Google Chrome" or "Microsoft Edge". PARAMETER: -Restart Explorer Restarts Explorer.exe so that the desktop icons for .html files refresh immediately. LICENSE: Modified version from: https://github.com/DanysysTeam/PS-SFTA/blob/22a32292e576afc976a1167d92b50741ef523066/SFTA.ps1 This script incorporates the `Get-HexDateTime` and `Get-Hash` functions from Danysys, without which it would not be possible. LICENSE: https://github.com/DanysysTeam/PS-SFTA/blob/22a32292e576afc976a1167d92b50741ef523066/SFTA.ps1 MIT License Copyright (c) 2022 Danysys. <danysys.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .OUTPUTS None .NOTES Minimum OS Architecture Supported: Windows 10+ Release Notes: Initial Release By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use. Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA). #> [CmdletBinding()] param ( [Parameter()] [String]$Browser, [Parameter()] [Switch]$RestartExplorer = [System.Convert]::ToBoolean($env:restartExplorer) ) begin { if ($env:browser -and $env:browser -notlike "null") { $Browser = $env:browser } # If no browser is selected, terminate with an error message. if (-not $Browser) { Write-Host "[Error] Please select at least one browser!" Exit 1 } # Test if running as Administrator function Test-IsElevated { $id = [System.Security.Principal.WindowsIdentity]::GetCurrent() $p = New-Object System.Security.Principal.WindowsPrincipal($id) $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) } # Test if running as System function Test-IsSystem { $id = [System.Security.Principal.WindowsIdentity]::GetCurrent() return $id.Name -like "NT AUTHORITY*" -or $id.IsSystem } function Get-HexDateTime { # This function was created by DanySys at https://github.com/DanysysTeam/PS-SFTA [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) ($hi.ToString("X8") + $low.ToString("X8")).ToLower() } function Get-Hash { # This function was created by DanySys at https://github.com/DanysysTeam/PS-SFTA [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) { Write-Output (( $iValue -shr $iCount) -bxor 0xFFFF0000) } else { Write-Output ($iValue -shr $iCount) } } function local:Get-Long { [CmdletBinding()] param ( [Parameter( Position = 0, Mandatory = $true)] [byte[]] $Bytes, [Parameter( Position = 1)] [int] $Index = 0 ) Write-Output ([BitConverter]::ToInt32($Bytes, $Index)) } function local:Convert-Int32 { param ( [Parameter( Position = 0, Mandatory = $true)] [long] $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 $lengthBase 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 $bytesMD5) -bor 1) + 0x69FB0000L) $map.MD52 = ((Get-Long $bytesMD5 4) -bor 1) + 0x13DB0000L $map.INDEX = Get-ShiftRight ($length - 2) 1 $map.COUNTER = $map.INDEX + 1 while ($map.COUNTER) { $map.R0 = Convert-Int32 ((Get-Long $bytesBaseInfo $map.PDATA) + [long]$map.OUTHASH1) $map.R1[0] = Convert-Int32 (Get-Long $bytesBaseInfo ($map.PDATA + 4)) $map.PDATA = $map.PDATA + 8 $map.R2[0] = Convert-Int32 (($map.R0 * ([long]$map.MD51)) - (0x10FA9605L * ((Get-ShiftRight $map.R0 16)))) $map.R2[1] = Convert-Int32 ((0x79F8A395L * ([long]$map.R2[0])) + (0x689B6B9FL * (Get-ShiftRight $map.R2[0] 16))) $map.R3 = Convert-Int32 ((0xEA970001L * $map.R2[1]) - (0x3C101569L * (Get-ShiftRight $map.R2[1] 16) )) $map.R4[0] = Convert-Int32 ($map.R3 + $map.R1[0]) $map.R5[0] = Convert-Int32 ($map.CACHE + $map.R3) $map.R6[0] = Convert-Int32 (($map.R4[0] * [long]$map.MD52) - (0x3CE8EC25L * (Get-ShiftRight $map.R4[0] 16))) $map.R6[1] = Convert-Int32 ((0x59C3AF2DL * $map.R6[0]) - (0x2232E0F1L * (Get-ShiftRight $map.R6[0] 16))) $map.OUTHASH1 = Convert-Int32 ((0x1EC90001L * $map.R6[1]) + (0x35BD1EC9L * (Get-ShiftRight $map.R6[1] 16))) $map.OUTHASH2 = Convert-Int32 ([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 $bytesMD5) -bor 1) $map.MD52 = ((Get-Long $bytesMD5 4) -bor 1) $map.INDEX = Get-ShiftRight ($length - 2) 1 $map.COUNTER = $map.INDEX + 1 while ($map.COUNTER) { $map.R0 = Convert-Int32 ((Get-Long $bytesBaseInfo $map.PDATA) + ([long]$map.OUTHASH1)) $map.PDATA = $map.PDATA + 8 $map.R1[0] = Convert-Int32 ($map.R0 * [long]$map.MD51) $map.R1[1] = Convert-Int32 ((0xB1110000L * $map.R1[0]) - (0x30674EEFL * (Get-ShiftRight $map.R1[0] 16))) $map.R2[0] = Convert-Int32 ((0x5B9F0000L * $map.R1[1]) - (0x78F7A461L * (Get-ShiftRight $map.R1[1] 16))) $map.R2[1] = Convert-Int32 ((0x12CEB96DL * (Get-ShiftRight $map.R2[0] 16)) - (0x46930000L * $map.R2[0])) $map.R3 = Convert-Int32 ((0x1D830000L * $map.R2[1]) + (0x257E1D83L * (Get-ShiftRight $map.R2[1] 16))) $map.R4[0] = Convert-Int32 ([long]$map.MD52 * ([long]$map.R3 + (Get-Long $bytesBaseInfo ($map.PDATA - 4)))) $map.R4[1] = Convert-Int32 ((0x16F50000L * $map.R4[0]) - (0x5D8BE90BL * (Get-ShiftRight $map.R4[0] 16))) $map.R5[0] = Convert-Int32 ((0x96FF0000L * $map.R4[1]) - (0x2C7C6901L * (Get-ShiftRight $map.R4[1] 16))) $map.R5[1] = Convert-Int32 ((0x2B890000L * $map.R5[0]) + (0x7C932B89L * (Get-ShiftRight $map.R5[0] 16))) $map.OUTHASH1 = Convert-Int32 ((0x9F690000L * $map.R5[1]) - (0x405B6097L * (Get-ShiftRight ($map.R5[1]) 16))) $map.OUTHASH2 = Convert-Int32 ([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 $outHash 8) -bxor (Get-Long $outHash)) $hashValue2 = ((Get-Long $outHash 12) -bxor (Get-Long $outHash 4)) $buffer = [BitConverter]::GetBytes($hashValue1) $buffer.CopyTo($outHashBase, 0) $buffer = [BitConverter]::GetBytes($hashValue2) $buffer.CopyTo($outHashBase, 4) $base64Hash = [Convert]::ToBase64String($outHashBase) } $base64Hash } # Helper function for setting registry keys function Set-RegKey { param ( $Path, $Name, $Value, [ValidateSet("DWord", "QWord", "String", "ExpandedString", "Binary", "MultiString", "Unknown")] $PropertyType = "DWord" ) if (-not $(Test-Path -Path $Path)) { # Check if path does not exist and create the path New-Item -Path $Path -Force | Out-Null } if ((Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue)) { # Update property and print out what it was changed from and changed to $CurrentValue = (Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue).$Name try { Set-ItemProperty -Path $Path -Name $Name -Value $Value -Force -Confirm:$false -ErrorAction Stop | Out-Null } catch { Write-Host "[Error] Unable to set registry key for $Name at $Path please see below error!" Write-Host "[Error] $($_.Exception.Message)" exit 1 } Write-Host "$Path\$Name changed from $CurrentValue to $($(Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue).$Name)" } else { # Create property with value try { New-ItemProperty -Path $Path -Name $Name -Value $Value -PropertyType $PropertyType -Force -Confirm:$false -ErrorAction Stop | Out-Null } catch { Write-Host "[Error] Unable to set registry key for $Name at $Path please see below error!" Write-Host "[Error] $($_.Exception.Message)" exit 1 } Write-Host "Set $Path\$Name to $($(Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue).$Name)" } } # Retrieves all accounts on a system. function Get-UserHives { param ( [Parameter()] [ValidateSet('AzureAD', 'DomainAndLocal', 'All')] [String]$Type = "All", [Parameter()] [String[]]$ExcludedUsers, [Parameter()] [switch]$IncludeDefault ) # User account SID's follow a particular patter depending on if they're azure AD or a Domain account or a local "workgroup" account. $Patterns = switch ($Type) { "AzureAD" { "S-1-12-1-(\d+-?){4}$" } "DomainAndLocal" { "S-1-5-21-(\d+-?){4}$" } "All" { "S-1-12-1-(\d+-?){4}$" ; "S-1-5-21-(\d+-?){4}$" } } # We'll need the NTuser.dat file to load each users registry hive. So we grab it if their account sid matches the above pattern. $UserProfiles = Foreach ($Pattern in $Patterns) { Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*" | Where-Object { $_.PSChildName -match $Pattern } | Select-Object @{Name = "SID"; Expression = { $_.PSChildName } }, @{Name = "UserName"; Expression = { "$($_.ProfileImagePath | Split-Path -Leaf)" } }, @{Name = "UserHive"; Expression = { "$($_.ProfileImagePath)\NTuser.dat" } }, @{Name = "Path"; Expression = { $_.ProfileImagePath } } } # There are some situations where grabbing the .Default user's info is needed. switch ($IncludeDefault) { $True { $DefaultProfile = "" | Select-Object UserName, SID, UserHive, Path $DefaultProfile.UserName = "Default" $DefaultProfile.SID = "DefaultProfile" $DefaultProfile.Userhive = "$env:SystemDrive\Users\Default\NTUSER.DAT" $DefaultProfile.Path = "C:\Users\Default" $DefaultProfile | Where-Object { $ExcludedUsers -notcontains $_.UserName } } } $UserProfiles | Where-Object { $ExcludedUsers -notcontains $_.UserName } } # This is used to check that the browser is installed. function Find-UninstallKey { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $True)] [String]$DisplayName, [Parameter()] [Switch]$UninstallString ) process { $UninstallList = New-Object System.Collections.Generic.List[Object] $Result = Get-ChildItem -Path Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Get-ItemProperty | Where-Object { $_.DisplayName -like "*$DisplayName*" } if ($Result) { $UninstallList.Add($Result) } $Result = Get-ChildItem -Path Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Get-ItemProperty | Where-Object { $_.DisplayName -like "*$DisplayName*" } if ($Result) { $UninstallList.Add($Result) } # Programs don't always have an uninstall string listed here so to account for that I made this optional. if ($UninstallString) { $UninstallList | Select-Object -ExpandProperty UninstallString -ErrorAction SilentlyContinue } else { $UninstallList } } } } process { if (-not (Test-IsElevated)) { Write-Host "[Error] Access Denied. Please run with Administrator privileges." exit 1 } # Protocols and file associations to set $Protocols = "http", "https" $Files = "htm", "html", "xhtml" # Handlers for each product switch ($Browser) { "Google Chrome" { $DisplayName = "Chrome" $urlID = "ChromeHTML" $htmlID = "ChromeHTML" } "Microsoft Edge" { $DisplayName = "Edge" $urlID = "MSEdgeHTM" $htmlID = "MSEdgeHTM" } "Mozilla Firefox" { $DisplayName = "Firefox" $urlID = "FirefoxURL-308046B0AF4A39CB" $htmlID = "FirefoxHTML-308046B0AF4A39CB" } default { Write-Host "[Error] Only the following browsers can be made the default. 'Google Chrome','Microsoft Edge' or 'Mozilla Firefox'." exit 1 } } if (-not (Find-UninstallKey -DisplayName "$DisplayName")) { Write-Host "[Error] $Browser is not installed. Please ensure it's installed System-Wide prior to running this script." exit 1 } $UserProfiles = Get-UserHives -Type "All" # Loop through each profile on the machine Foreach ($UserProfile in $UserProfiles) { # Load User ntuser.dat if it's not already loaded If (($ProfileWasLoaded = Test-Path Registry::HKEY_USERS\$($UserProfile.SID)) -eq $false) { Start-Process -FilePath "cmd.exe" -ArgumentList "/C reg.exe LOAD HKU\$($UserProfile.SID) `"$($UserProfile.UserHive)`"" -Wait -WindowStyle Hidden } # The hex date and user experience don't really change $userExperience = "User Choice set via Windows User Experience {D18B6DD5-6124-4341-9318-804003BAFA0B}" $hexDateTime = Get-HexDateTime Write-Host "`nSetting default browser of $Browser for $($UserProfile.UserName)." # Set protocol association registry keys $Protocols | ForEach-Object { Write-Host "Setting " $Protocol = $_ $ToBeHashed = "$Protocol$($UserProfile.SID)$urlID$hexDateTime$userExperience".ToLower() $Hash = Get-Hash -BaseInfo $ToBeHashed Set-RegKey -Path "Registry::HKEY_USERS\$($UserProfile.SID)\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\$Protocol\UserChoice" -Name "Hash" -Value $Hash -PropertyType String Set-RegKey -Path "Registry::HKEY_USERS\$($UserProfile.SID)\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\$Protocol\UserChoice" -Name "ProgId" -Value $urlID -PropertyType String } # Set file association registry keys $Files | ForEach-Object { Write-Host "Setting " $File = $_ $ToBeHashed = ".$File$($UserProfile.SID)$htmlID$hexDateTime$userExperience".ToLower() $Hash = Get-Hash -BaseInfo $ToBeHashed Set-RegKey -Path "Registry::HKEY_USERS\$($UserProfile.SID)\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\$File\UserChoice" -Name "Hash" -Value $Hash -PropertyType String Set-RegKey -Path "Registry::HKEY_USERS\$($UserProfile.SID)\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\$File\UserChoice" -Name "ProgId" -Value $htmlID -PropertyType String Set-RegKey -Path "Registry::HKEY_USERS\$($UserProfile.SID)\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.$File\UserChoice" -Name "Hash" -Value $Hash -PropertyType String Set-RegKey -Path "Registry::HKEY_USERS\$($UserProfile.SID)\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.$File\UserChoice" -Name "ProgId" -Value $htmlID -PropertyType String } # Unload NTuser.dat If ($ProfileWasLoaded -eq $false) { [gc]::Collect() Start-Sleep 1 Start-Process -FilePath "cmd.exe" -ArgumentList "/C reg.exe UNLOAD HKU\$($UserProfile.SID)" -Wait -WindowStyle Hidden | Out-Null } } # Restart explorer if requested if ($RestartExplorer) { Write-Host "`nRestarting Explorer.exe as requested." # Stop all instances of Explorer Get-Process explorer | Stop-Process -Force Start-Sleep -Seconds 1 # Restart Explorer if not running as System and Explorer is not already running if (!(Test-IsSystem) -and !(Get-Process -Name "explorer")) { Start-Process explorer.exe } } } end { }
Accedi a oltre 700 script nel Dojo NinjaOne
Analisi dettagliata
Lo script funziona interagendo con il registro di Windows, in particolare prendendo di mira gli hive del registro specifici dell’utente che memorizzano le impostazioni predefinite delle applicazioni. Ecco una descrizione passo per passo di come funziona lo script:
1. Inizializzazione dello script:
- Lo script inizia verificando se viene eseguito con privilegi elevati (accesso come amministratore). In caso contrario, lo script si interrompe, garantendo che solo il personale autorizzato possa apportare modifiche a livello di sistema.
2. Gestione dei parametri:
- Vengono accettati due parametri: il browser da impostare come predefinito e uno switch per riavviare il processo Explorer.exe. Il parametro del browser accetta “Mozilla Firefox”, “Google Chrome” o “Microsoft Edge” e sceglie come impostazione predefinita quella della variabile d’ambiente, se non viene fornita direttamente.
3. Convalida del browser:
- Prima di procedere, lo script controlla se il browser specificato è installato sul sistema cercando nel registro di sistema la sua chiave di disinstallazione. Se il browser non è installato, lo script mostra un messaggio di errore.
4. Gestione dei profili:
- Lo script recupera un elenco di tutti i profili utente presenti sul computer esaminando il registro di sistema alla ricerca di impostazioni specifiche dell’utente. Identifica il SID (Security Identifier) di ogni utente e carica l’hive del registro di sistema per modificare le impostazioni predefinite del browser.
5. Impostazione del protocollo e delle associazioni di file predefiniti:
- Per ogni profilo utente, lo script modifica il registro per impostare il browser selezionato come gestore predefinito per i tipi di file HTTP, HTTPS, HTM, HTML e XHTML. Ciò comporta la generazione di un hash univoco per le impostazioni, per garantire che siano riconosciute da Windows come valide e sicure.
6. Riavviare Explorer (facoltativo):
- Se si utilizza l’opzione -RestartExplorer, lo script si interrompe e riavvia il processo Explorer.exe. Questo passaggio è necessario per applicare immediatamente le modifiche e aggiornare le icone del desktop associate ai tipi di file interessati.
Casi d’uso potenziali
Immagina un amministratore IT che gestisce una grande rete aziendale con centinaia di utenti. L’azienda ha recentemente scelto Firefox come browser predefinito grazie alle sue migliori caratteristiche di sicurezza.
Invece di impostare manualmente Firefox come browser predefinito sul profilo di ogni utente, l’amministratore può eseguire questo script in tutta la rete, assicurando che ogni utente, indipendentemente dalla frequenza di accesso o dallo stato del profilo, utilizzi Firefox per impostazione predefinita. In questo modo non solo si risparmia tempo, ma si riduce anche la probabilità di errori da parte degli utenti o di non conformità alle policy aziendali.
Confronti
Sebbene questo script PowerShell offra un approccio semplificato, esistono altri metodi per ottenere lo stesso risultato, come l’utilizzo dei Criteri di gruppo o la distribuzione di uno strumento di gestione dei software. I Criteri di gruppo offrono un modo più centralizzato per applicare le impostazioni del browser, ma possono essere complessi da configurare e potrebbero non coprire tutti gli scenari, specialmente con i profili specifici dell’utente.
Gli strumenti di gestione dei software, invece, spesso comportano costi aggiuntivi e richiedono una curva di apprendimento. Questo script raggiunge un equilibrio offrendo una soluzione personalizzabile e senza costi che si integra direttamente nell’ambiente Windows esistente.
Domande frequenti
D: Questo script può essere utilizzato su sistemi con versioni di Windows precedenti a Windows 10?
R: Lo script è progettato per Windows 10 e versioni successive. Utilizza strutture di registro e protocolli specifici che potrebbero non essere disponibili nelle versioni precedenti di Windows.
D: Cosa succede se un utente installa un nuovo browser dopo l’esecuzione dello script?
R: Se viene installato un nuovo browser dopo l’esecuzione dello script, questo potrebbe tentare di impostarsi come predefinito. In questi casi, eseguendo nuovamente lo script si riapplicheranno le impostazioni desiderate.
D: È possibile modificare lo script per includere altri browser non elencati nei parametri?
R: Sì, lo script può essere adattato per supportare altri browser aggiungendo i rispettivi identificatori di protocollo e di gestore di file.
Implicazioni
Utilizzando questo script, i professionisti IT possono imporre la coerenza del browser in tutti i profili utente, un aspetto importante per la sicurezza e la conformità. Tuttavia, gli amministratori devono essere consapevoli delle potenziali implicazioni, come l’annullamento delle preferenze degli utenti e la necessità di assicurarsi che tutti i browser necessari siano installati a livello di sistema prima di eseguire lo script.
Raccomandazioni
- Testa in ambiente controllato: Prima di distribuire questo script su un’intera rete, è consigliabile testarlo in un ambiente controllato per assicurarti che si comporti come previsto.
- Assicurati che tutti i browser siano installati: Controlla che il browser predefinito selezionato sia installato su tutti i sistemi in cui verrà eseguito lo script.
- Considera la comunicazione con gli utenti: Informa gli utenti della modifica, in particolare se le preferenze predefinite del browser verranno ignorate.
Considerazioni finali
Per i professionisti IT e gli MSP, la gestione efficiente degli ambienti utente è fondamentale. Questo script PowerShell offre una soluzione efficace per standardizzare il browser predefinito per tutti i profili utente di un sistema Windows. Sebbene NinjaOne fornisca strumenti completi per la gestione degli endpoint, tra cui la distribuzione dei software e la gestione dei profili utente, questo script può essere un eccellente complemento, offrendo un controllo dettagliato sulle impostazioni del browser.