La gestion des environnements utilisateurs Windows à grande échelle est un exercice d’équilibre permanent pour les professionnels de l’informatique et les fournisseurs de services gérés (MSP). Des configurations apparemment mineures, comme la visibilité des fichiers et dossiers cachés, peuvent avoir un impact significatif sur la convivialité, le dépannage et même la sécurité. L’automatisation de ce type de configuration sur plusieurs terminaux permet de maintenir la cohérence et l’efficacité. Cet article explique comment activer ou désactiver l’affichage des fichiers et dossiers cachés avec PowerShell, soit par utilisateur, soit pour l’ensemble du système.
Contexte
L’Explorateur Windows cache par défaut certains fichiers système et utilisateur afin de les protéger contre les modifications accidentelles. Cependant, les techniciens ont souvent besoin d’exposer ces fichiers pour dépanner, configurer ou auditer les appareils. Plutôt que de cliquer manuellement sur les options de dossier ou les stratégies de groupe, PowerShell offre une alternative simplifiée. Le script proposé facilite ce processus avec souplesse : il peut appliquer les paramètres à l’utilisateur actuel ou à tous les utilisateurs de l’appareil, en fonction du contexte d’exécution.
Cette capacité est particulièrement précieuse dans les environnements gérés par des plateformes RMM comme NinjaOne, où l’uniformité et le contrôle sont essentiels.
Le script
#Requires -Version 5.1
<#
.SYNOPSIS
Enable or disable the viewing of hidden files and folders for all users (when run as 'System') or just the current user (when run as 'Current Logged On User').
.DESCRIPTION
Enable or disable the viewing of hidden files and folders for all users (when run as 'System') or just the current user (when run as 'Current Logged On User').
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).
.EXAMPLE
-Action "Enable"
Enabling 'Show hidden files and folders' for all users.
Enabling 'Show hidden files and folders' for user 'tuser'.
Registry::HKEY_USERS\S-1-5-21-2311417250-918970610-4221123468-1001\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Hidden changed from 1 to 1
Enabling 'Show hidden files and folders' for user 'Administrator'.
Registry::HKEY_USERS\S-1-5-21-2311417250-918970610-4221123468-500\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\Hidden changed from 2 to 1
Finished enabling 'Show hidden files and folders'.
WARNING: You may need to restart Explorer.exe for the script to take effect immediately.
PARAMETER: -Action "ReplaceMeWithYourDesiredAction"
Specify whether you would like to disable or enable the viewing of hidden files or folders. Valid actions are 'Enable' or 'Disable'.
PARAMETER: -RestartExplorer
You may need to restart explorer.exe for this script to take effect immediately. Use this switch to do so upon completion.
.NOTES
Minimum OS Architecture Supported: Windows 10, Windows Server 2016
Release Notes: Initial Release
#>
[CmdletBinding()]
param (
[Parameter()]
[String]$Action,
[Parameter()]
[Switch]$RestartExplorer = [System.Convert]::ToBoolean($env:restartExplorer)
)
begin {
# Check if the environment variable 'action' is set and is not null
if ($env:action -and $env:action -notlike "null") { $Action = $env:action }
# If $Action has a value, trim any leading or trailing whitespace
if ($Action) {
$Action = $Action.Trim()
}
# If $Action is empty or null after trimming, display an error message indicating that an action must be specified
if (!$Action) {
Write-Host -Object "[Error] You must specify an action."
exit 1
}
# Define a list of valid actions: "Enable" and "Disable"
$ValidActions = "Enable", "Disable"
# Check if the value of $Action is not one of the valid actions
if ($ValidActions -notcontains $Action) {
Write-Host -Object "[Error] Invalid action '$Action' provided. Please specify either 'Enable' or 'Disable'."
exit 1
}
function Get-UserHives {
param (
[Parameter()]
[ValidateSet('AzureAD', 'DomainAndLocal', 'All')]
[String]$Type = "All",
[Parameter()]
[String[]]$ExcludedUsers,
[Parameter()]
[switch]$IncludeDefault
)
# Define the SID patterns to match based on the selected user type
$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}$" }
}
# Retrieve user profile information based on the defined patterns
$UserProfiles = Foreach ($Pattern in $Patterns) {
try {
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*" -ErrorAction Stop |
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 } }
}
catch {
Write-Host -Object "[Error] $($_.Exception.Message)"
}
}
# If the IncludeDefault switch is set, add the Default profile to the results
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"
# Exclude users specified in the ExcludedUsers list
$DefaultProfile | Where-Object { $ExcludedUsers -notcontains $_.Username }
}
}
# Return the list of user profiles, excluding any specified in the ExcludedUsers list
$UserProfiles | Where-Object { $ExcludedUsers -notcontains $_.Username }
}
function Set-RegKey {
param (
$Path,
$Name,
$Value,
[ValidateSet("DWord", "QWord", "String", "ExpandedString", "Binary", "MultiString", "Unknown")]
$PropertyType = "DWord"
)
# Check if the specified registry path exists
if (!(Test-Path -Path $Path)) {
try {
# If the path does not exist, create it
New-Item -Path $Path -Force -ErrorAction Stop | Out-Null
}
catch {
# If there is an error creating the path, output an error message and exit
Write-Host "[Error] Unable to create the registry path $Path for $Name. Please see the error below!"
Write-Host "[Error] $($_.Exception.Message)"
exit 1
}
}
# Check if the registry key already exists at the specified path
if (Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue) {
# Retrieve the current value of the registry key
$CurrentValue = (Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue).$Name
try {
# Update the registry key with the new value
Set-ItemProperty -Path $Path -Name $Name -Value $Value -Force -Confirm:$false -ErrorAction Stop | Out-Null
}
catch {
# If there is an error setting the key, output an error message and exit
Write-Host "[Error] Unable to set registry key for $Name at $Path. Please see the error below!"
Write-Host "[Error] $($_.Exception.Message)"
exit 1
}
# Output the change made to the registry key
Write-Host "$Path\$Name changed from $CurrentValue to $((Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue).$Name)"
}
else {
try {
# If the registry key does not exist, create it with the specified value and property type
New-ItemProperty -Path $Path -Name $Name -Value $Value -PropertyType $PropertyType -Force -Confirm:$false -ErrorAction Stop | Out-Null
}
catch {
# If there is an error creating the key, output an error message and exit
Write-Host "[Error] Unable to set registry key for $Name at $Path. Please see the error below!"
Write-Host "[Error] $($_.Exception.Message)"
exit 1
}
# Output the creation of the new registry key
Write-Host "Set $Path\$Name to $((Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue).$Name)"
}
}
function Test-IsSystem {
# Get the current Windows identity of the user running the script
$id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
# Check if the current identity's name matches "NT AUTHORITY*"
# or if the identity represents the SYSTEM account
return $id.Name -like "NT AUTHORITY*" -or $id.IsSystem
}
if (!$ExitCode) {
$ExitCode = 0
}
}
process {
# Retrieve all user profile registry hives (including system profiles).
$UserProfiles = Get-UserHives -Type "All"
# Check if the script is not running as the system account.
if (!(Test-IsSystem)) {
# Depending on the value of $Action, display the corresponding message for the current user.
switch ($Action) {
"Enable" { Write-Host -Object "Enabling 'Show hidden files and folders' for the current user." }
"Disable" { Write-Host -Object "Disabling 'Show hidden files and folders' for the current user." }
}
# Filter user profiles to only include the current user's SID.
try {
$UserProfiles = $UserProfiles | Where-Object { $_.SID -match "$([System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value)" }
}
catch {
# If an error occurs (e.g., failed to retrieve the current user's SID), display an error and exit.
Write-Host -Object "[Error] Failed to get current user's SID."
Write-Host -Object "[Error] $($_.Exception.Message)"
exit 1
}
}
else {
# If running as the system account, display a message for all users depending on the value of $Action.
switch ($Action) {
"Enable" { Write-Host -Object "Enabling 'Show hidden files and folders' for all users." }
"Disable" { Write-Host -Object "Disabling 'Show hidden files and folders' for all users." }
}
}
# Create a list to track which user profiles had their NTuser.dat loaded.
$ProfileWasLoaded = New-Object System.Collections.Generic.List[object]
# Check if any user profiles were retrieved.
if (!$UserProfiles) {
Write-Host -Object "[Error] No user profiles found."
exit 1
}
# Iterate through each user profile.
ForEach ($UserProfile in $UserProfiles) {
# Check if the NTuser.dat file (the user's registry hive) is not already loaded for the user.
If (!(Test-Path -Path Registry::HKEY_USERS\$($UserProfile.SID) -ErrorAction SilentlyContinue)) {
# Load the user's NTuser.dat into the registry under HKEY_USERS using reg.exe.
Start-Process -FilePath "cmd.exe" -ArgumentList "/C reg.exe LOAD HKU\$($UserProfile.SID) `"$($UserProfile.UserHive)`"" -Wait -WindowStyle Hidden
# Add the profile to the list of loaded profiles for later unloading.
$ProfileWasLoaded.Add($UserProfile)
}
}
# Set the appropriate registry value for hidden files based on the $Action.
switch ($Action) {
"Enable" { $HiddenFilesValue = 1 }
"Disable" { $HiddenFilesValue = 2 }
}
# Iterate through each user profile to apply the registry change.
ForEach ($UserProfile in $UserProfiles) {
$CurrentHiddenFilesOption = Get-ItemProperty -Path "Registry::HKEY_USERS\$($UserProfile.SID)\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty "Hidden"
# If the requested action has already been applied, display a message indicating the action has already been applied for the user.
if ($HiddenFilesValue -eq $CurrentHiddenFilesOption) {
switch ($Action) {
"Enable" { Write-Host -Object "`n'Show hidden files and folders' is already enabled for user '$($UserProfile.Username)'." }
"Disable" { Write-Host -Object "`n'Show hidden files and folders' is already disabled for user '$($UserProfile.Username)'." }
}
continue
}
# Display a message indicating the action being applied for the user.
switch ($Action) {
"Enable" { Write-Host -Object "`nEnabling 'Show hidden files and folders' for user '$($UserProfile.Username)'." }
"Disable" { Write-Host -Object "`nDisabling 'Show hidden files and folders' for user '$($UserProfile.Username)'." }
}
# Modify the registry key to set the visibility of hidden files and folders for the user.
Set-RegKey -Path "Registry::HKEY_USERS\$($UserProfile.SID)\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "Hidden" -Value $HiddenFilesValue
}
# Display a final message indicating that the process is complete.
switch ($Action) {
"Enable" { Write-Host -Object "`nFinished enabling 'Show hidden files and folders'." }
"Disable" { Write-Host -Object "`nFinished disabling 'Show hidden files and folders'." }
}
# Unload NTuser.dat for any profiles that were loaded earlier.
if ($ProfileWasLoaded.Count -gt 0) {
ForEach ($UserProfile in $ProfileWasLoaded) {
# Unload NTuser.dat
[gc]::Collect()
Start-Sleep 1
Start-Process -FilePath "cmd.exe" -ArgumentList "/C reg.exe UNLOAD HKU\$($UserProfile.SID)" -Wait -WindowStyle Hidden | Out-Null
}
}
# Check if the $RestartExplorer flag is set
if ($RestartExplorer) {
# Display a message indicating that Explorer.exe is being restarted
Write-Host "`nRestarting Explorer.exe as requested."
try {
# Stop all instances of Explorer
if (Test-IsSystem) {
Get-Process -Name "explorer" | Stop-Process -Force -ErrorAction Stop
}
else {
Get-Process -Name "explorer" | Where-Object { $_.SI -eq (Get-Process -PID $PID).SessionId } | Stop-Process -Force -ErrorAction Stop
}
}
catch {
Write-Host -Object "[Error] Failed to stop explorer.exe"
Write-Host -Object "[Error] $($_.Exception.Message)"
$ExitCode = 1
}
# Pause for 1 second to ensure processes have fully stopped before restarting
Start-Sleep -Seconds 1
# If not running as the System account and Explorer.exe is not already running, start a new instance
if (!(Test-IsSystem) -and !(Get-Process -Name "explorer" -ErrorAction SilentlyContinue)) {
try {
Start-Process -FilePath "$env:SystemRoot\explorer.exe" -Wait -ErrorAction Stop
}
catch {
Write-Host -Object "[Error] Failed to start explorer.exe"
Write-Host -Object "[Error] $($_.Exception.Message)"
$ExitCode = 1
}
}
}
else {
# If $RestartExplorer is not set, warn the user that they may need to manually restart Explorer.exe
Write-Host -Object ""
Write-Warning -Message "You may need to restart Explorer.exe for the script to take effect immediately."
}
# Exit the script with the predefined $ExitCode.
exit $ExitCode
}
end {
}
Description détaillée
Le script fonctionne en plusieurs étapes :
- Traitement des entrées
Il accepte un paramètre -Action (Enable ou Disable) et un commutateur facultatif -RestartExplorer. Ceux-ci peuvent être transmis directement ou par l’intermédiaire de variables d’environnement, ce qui permet de mettre en place des pipelines d’automatisation. - Validation et préparation
Il vérifie le paramètre d’action et prépare les fonctions d’aide :- Get-UserHives : Récupère toutes les ruches (hive) du registre utilisateur (chargées ou non).
- Set-RegKey : Modifie le registre pour refléter les préférences en matière de fichiers cachés.
- Test-IsSystem : Vérifie si le script est exécuté en tant que SYSTÈME.
- Détection de profil
S’il est exécuté en tant que SYSTÈME (par exemple, via NinjaOne ou le planificateur de tâches), le script cible tous les utilisateurs. Dans le cas contraire, il modifie les paramètres pour uniquement pour l’utilisateur actuel. - Chargement de ruche
Pour les profils d’utilisateur non chargés, il monte temporairement les fichiers NTUSER.DAT dans HKEY_USERS à l’aide de reg.exe. - Modification du registre
Pour chaque profil :- Il vérifie les paramètres actuels (caché sous HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced)
- Si la valeur diffère de celle souhaitée (1 pour Afficher, 2 pour Cacher), il met à jour la clé.
- Nettoyage et finalisation
Les ruches chargées sont déchargées afin d’éviter la persistance des poignées de registre. Si l’option -RestartExplorer est spécifiée, le script s’arrête et (re)démarre explorer.exe pour que les modifications s’appliquent immédiatement.
Cas d’utilisation potentiels
Étude de cas : Standardiser la visibilité pour le personnel du service d’assistance
L’équipe d’un service d’assistance prend régulièrement en charge un large éventail d’applications, dont certaines stockent des journaux dans des dossiers cachés. Pour réduire les temps d’appel et les clics répétitifs, l’administrateur informatique déploie ce script sur tous les postes de travail des techniciens avec le paramètre -Action « Enable » via NinjaOne. Cela garantit la visibilité des fichiers essentiels dans tous les profils, améliorant ainsi l’efficacité opérationnelle sans modifier la stratégie de groupe.
Par ailleurs, un fournisseur de services gérés (MSP) peut utiliser l’action « Disable » pour les machines en contact avec les clients afin de renforcer leur sécurité en masquant les fichiers système sensibles.
Comparaisons
Cette approche PowerShell offre plusieurs avantages par rapport aux méthodes traditionnelles :
| Méthode | Avantages | Inconvénients |
| Stratégie de groupe (GPO) | Mise en œuvre à l’échelle de l’entreprise | Nécessite Active Directory, manque de nuances en fonction de l’utilisateur |
| Configuration manuelle de l’interface graphique | Simple pour une utilisation individuelle | Non évolutif |
| PowerShell (ce script) | Scriptable, flexible, spécifique à l’utilisateur | Nécessite un contexte d’administration pour les opérations SYSTÈME |
Contrairement à la stratégie de groupe, ce script fonctionne sans dépendance de domaine et peut cibler à la fois les utilisateurs locaux et ceux d’AzureAD. Il s’adapte également aux systèmes dont les profils ne sont pas chargés, ce que les modifications de l’interface graphique ne peuvent pas faire si l’utilisateur n’est pas connecté.
FAQ
Q : Ce script fonctionnera-t-il pour les utilisateurs distants qui ne se sont pas encore connectés ?
Oui, il peut s’appliquer à des profils non chargés en accédant directement au fichier NTUSER.DAT.
Q : La modification s’applique-t-elle immédiatement ?
Pas nécessairement. Explorer peut mettre en cache les paramètres d’affichage des dossiers. Utilisez -RestartExplorer pour forcer l’application immédiate.
Q : Que se passe-t-il si je réexécute le script ?
Si le paramètre correspond déjà à l’état souhaité, le script n’applique pas les modifications et indique qu’il a déjà été défini.
Q : Puis-je l’utiliser dans une tâche planifiée de NinjaOne ?
Absolument. Il suffit de s’assurer qu’il est exécuté avec les privilèges SYSTÈME pour que tous les utilisateurs soient pris en compte.
Implications
Du point de vue de la sécurité, le masquage des fichiers permet de protéger les composants sensibles du système d’exploitation. L’activation de la visibilité sur l’ensemble du système peut accroître les risques pour les utilisateurs, en particulier sur les terminaux partagés ou publics. Les administrateurs informatiques doivent trouver un équilibre entre la facilité d’utilisation et le respect des règles. Inversement, la désactivation de la visibilité peut renforcer le durcissement des terminaux et réduire les manipulations accidentelles par les utilisateurs finaux.
Recommandations
- Testez dans un environnement d’essai avant de procéder à un déploiement massif.
- Toujours inclure la journalisation lors de l’exécution par l’automatisation pour capturer les résultats.
- Utilisez -RestartExplorer avec prudence, en particulier sur les systèmes multi-utilisateurs, car le redémarrage de l’explorateur peut perturber les flux de travail.
- Envisagez d’intégrer ce script aux stratégies d’automatisation de NinjaOne pour renforcer la normalisation dans le cadre de l’intégration des appareils.
Conclusion
La gestion de la visibilité des fichiers est un aspect mineur mais significatif de l’hygiène des terminaux. Ce script PowerShell permet aux professionnels de l’informatique de contrôler avec précision un paramètre souvent négligé, mais qui joue un rôle essentiel dans les flux de travail d’assistance et les configurations de sécurité.
Lorsqu’il est associé à NinjaOne ce script devient un puissant outil d’automatisation. Qu’il s’agisse de pousser cette configuration sur des centaines de terminaux ou de personnaliser la visibilité par rôle, les fonctions d’automatisation et de planification des scripts de NinjaOne garantissent une exécution constante avec un minimum de frais généraux.