Apprendre à vérifier l’état du stockage USB avec un script PowerShell est un élément essentiel de la sécurité des terminaux pour les professionnels de l’informatique et les fournisseurs de services gérés (MSP). L’utilisation non autorisée de clés USB peut entraîner des fuites de données, l’intrusion de logiciels malveillants ou des violations de la législation. Le fait de savoir si le stockage USB est activé ou désactivé sur les appareils donne aux administrateurs une visibilité et un contrôle essentiels. L’un des moyens d’automatiser cette visibilité est d’utiliser un script PowerShell conçu pour auditer l’état du stockage USB. Cet article présente un script PowerShell de qualité professionnelle qui fait exactement cela, et qui s’intègre parfaitement à NinjaOne via des champs personnalisés.
Contexte
Le contrôle de l’utilisation des périphériques USB est souvent assuré par la stratégie de groupe, les modifications du registre ou de la configuration des services. Cependant, il n’est pas pratique d’auditer manuellement ces paramètres sur des centaines ou des milliers de machines. Le script PowerShell présenté ici a été conçu pour automatiser l’évaluation de l’accès au stockage USB, avec la fonctionnalité supplémentaire de mettre à jour les champs personnalisés de NinjaOne avec le résultat.
Qu’il s’agisse de déployer de nouvelles politiques de sécurité, de répondre à un audit de conformité ou simplement d’assurer une configuration de base, ce script permet de s’assurer que les restrictions USB sont appliquées avec précision. Pour les entreprises MSP, la possibilité d’écrire ces informations dans l’inventaire des appareils de NinjaOne permet de créer des rapports et des alertes évolutifs.
Le script
#Requires -Version 5.1
<#
.SYNOPSIS
Checks if the workstation currently allows access to USB storage devices and optionally saves the results to a custom field.
.DESCRIPTION
Checks if the workstation currently allows access to USB storage devices and optionally saves the results to a custom field.
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
-CustomField "usbStorageStatus"
Checking if the USB Mass Storage Driver service is enabled.
Checking if the USB Mass Storage Driver is disabled via the registry.
Checking if USB is disabled via group policy.
USB is currently disabled.
Attempting to set Custom Field 'usbStorageStatus'.
Successfully set Custom Field 'usbStorageStatus'!
.NOTES
Minimum OS Architecture Supported: Windows 10
Release Notes: Initial Release
#>
[CmdletBinding()]
param (
[Parameter()]
[String]$CustomField
)
begin {
if ($env:customFieldName -and $env:customFieldName -notlike "null") { $CustomField = $env:customFieldName }
if ($CustomField) {
$CustomField = $CustomField.Trim()
}
function Set-NinjaProperty {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True)]
[String]$Name,
[Parameter()]
[String]$Type,
[Parameter(Mandatory = $True, ValueFromPipeline = $True)]
$Value,
[Parameter()]
[String]$DocumentName,
[Parameter()]
[Switch]$Piped
)
# Remove the non-breaking space character
if ($Type -eq "WYSIWYG") {
$Value = $Value -replace 'Â ', ' '
}
# Measure the number of characters in the provided value
$Characters = $Value | ConvertTo-Json | Measure-Object -Character | Select-Object -ExpandProperty Characters
# Throw an error if the value exceeds the character limit of 200,000 characters
if ($Piped -and $Characters -ge 200000) {
throw [System.ArgumentOutOfRangeException]::New("Character limit exceeded: the value is greater than or equal to 200,000 characters.")
}
if (!$Piped -and $Characters -ge 45000) {
throw [System.ArgumentOutOfRangeException]::New("Character limit exceeded: the value is greater than or equal to 45,000 characters.")
}
# Initialize a hashtable for additional documentation parameters
$DocumentationParams = @{}
# If a document name is provided, add it to the documentation parameters
if ($DocumentName) { $DocumentationParams["DocumentName"] = $DocumentName }
# Define a list of valid field types
$ValidFields = "Attachment", "Checkbox", "Date", "Date or Date Time", "Decimal", "Dropdown", "Email", "Integer", "IP Address", "MultiLine", "MultiSelect", "Phone", "Secure", "Text", "Time", "URL", "WYSIWYG"
# Warn the user if the provided type is not valid
if ($Type -and $ValidFields -notcontains $Type) { Write-Warning "$Type is an invalid type. Please check here for valid types: https://ninjarmm.zendesk.com/hc/en-us/articles/16973443979789-Command-Line-Interface-CLI-Supported-Fields-and-Functionality" }
# Define types that require options to be retrieved
$NeedsOptions = "Dropdown"
# If the property is being set in a document or field and the type needs options, retrieve them
if ($DocumentName) {
if ($NeedsOptions -contains $Type) {
$NinjaPropertyOptions = Ninja-Property-Docs-Options -AttributeName $Name @DocumentationParams 2>&1
}
}
else {
if ($NeedsOptions -contains $Type) {
$NinjaPropertyOptions = Ninja-Property-Options -Name $Name 2>&1
}
}
# Throw an error if there was an issue retrieving the property options
if ($NinjaPropertyOptions.Exception) { throw $NinjaPropertyOptions }
# Process the property value based on its type
switch ($Type) {
"Checkbox" {
# Convert the value to a boolean for Checkbox type
$NinjaValue = [System.Convert]::ToBoolean($Value)
}
"Date or Date Time" {
# Convert the value to a Unix timestamp for Date or Date Time type
$Date = (Get-Date $Value).ToUniversalTime()
$TimeSpan = New-TimeSpan (Get-Date "1970-01-01 00:00:00") $Date
$NinjaValue = $TimeSpan.TotalSeconds
}
"Dropdown" {
# Convert the dropdown value to its corresponding GUID
$Options = $NinjaPropertyOptions -replace '=', ',' | ConvertFrom-Csv -Header "GUID", "Name"
$Selection = $Options | Where-Object { $_.Name -eq $Value } | Select-Object -ExpandProperty GUID
# Throw an error if the value is not present in the dropdown options
if (!($Selection)) {
throw [System.ArgumentOutOfRangeException]::New("Value is not present in dropdown options.")
}
$NinjaValue = $Selection
}
default {
# For other types, use the value as is
$NinjaValue = $Value
}
}
# Set the property value in the document if a document name is provided
if ($DocumentName) {
$CustomField = Ninja-Property-Docs-Set -AttributeName $Name -AttributeValue $NinjaValue @DocumentationParams 2>&1
}
else {
try {
# Otherwise, set the standard property value
if ($Piped) {
$CustomField = $NinjaValue | Ninja-Property-Set-Piped -Name $Name 2>&1
}
else {
$CustomField = Ninja-Property-Set -Name $Name -Value $NinjaValue 2>&1
}
}
catch {
Write-Host -Object "[Error] Failed to set custom field."
throw $_.Exception.Message
}
}
# Throw an error if setting the property failed
if ($CustomField.Exception) {
throw $CustomField
}
}
function Test-IsElevated {
$id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$p = New-Object System.Security.Principal.WindowsPrincipal($id)
$p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
}
if (!$ExitCode) {
$ExitCode = 0
}
}
process {
# Check if the script is running with elevated (Administrator) privileges.
if (!(Test-IsElevated)) {
Write-Host -Object "[Error] Access Denied. Please run with Administrator privileges."
exit 1
}
# Notify that the script is checking if the USB Mass Storage Driver service is enabled.
Write-Host -Object "Checking if the USB Mass Storage Driver service is enabled."
try {
$USBService = Get-Service -Name "USBStor" -ErrorAction Stop
}
catch {
Write-Host -Object "[Error] $($_.Exception.Message)"
$ExitCode = 1
}
# If the USB Mass Storage Driver service was not found, print an error message and exit.
if (!$USBService) {
Write-Host -Object "[Error] Accessing the 'USB Mass Storage Driver' service status."
if ($CustomField) {
try {
Write-Host -Object "Attempting to set Custom Field '$CustomField'."
Set-NinjaProperty -Name $CustomField -Value "Unable to Determine"
Write-Host -Object "Successfully set Custom Field '$CustomField'!"
}
catch {
Write-Host "[Error] $($_.Exception.Message)"
}
}
exit 1
}
# Notify that the script is checking if the USB Mass Storage Driver is disabled via the registry.
Write-Host -Object "Checking if the USB Mass Storage Driver is disabled via the registry."
# Check if the registry path for the USB Mass Storage Driver exists.
if (!(Test-Path -Path "Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\USBSTOR")) {
Write-Host -Object "[Error] The 'USB Mass Storage Driver' Service is missing it's registry key."
if ($CustomField) {
try {
Write-Host -Object "Attempting to set Custom Field '$CustomField'."
Set-NinjaProperty -Name $CustomField -Value "Unable to Determine"
Write-Host -Object "Successfully set Custom Field '$CustomField'!"
}
catch {
Write-Host "[Error] $($_.Exception.Message)"
}
}
exit 1
}
# Get the registry value for the USB Mass Storage Driver service start type.
$USBRegKey = Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\USBSTOR" -Name "Start" | Select-Object -ExpandProperty Start
# Notify that the script is checking if USB is disabled via group policy.
Write-Host -Object "Checking if USB is disabled via group policy."
# Check if the group policy registry path for removable usb devices exists.
if (Test-Path -Path "Registry::HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\RemovableStorageDevices\{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}" -ErrorAction SilentlyContinue) {
$USBPolicyRegKey = Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\RemovableStorageDevices\{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}"
# If all group policy settings deny read, write, and execute access, set the USB policy status to "Disabled".
if ($USBPolicyRegKey.Deny_Read -eq 1 -and $USBPolicyRegKey.Deny_Write -eq 1 -and $USBPolicyRegKey.Deny_Execute -eq 1) {
$USBPolicy = "Disabled"
}
}
# Check if the group policy registry path for all removable storage devices exists.
if (Test-Path -Path "Registry::HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\RemovableStorageDevices" -ErrorAction SilentlyContinue) {
$USBPolicyRegKey = Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\RemovableStorageDevices"
# If group olicy is set to deny all removable devices, set the USB policy status to "Disabled".
if ($USBPolicyRegKey.Deny_All -eq 1) {
$USBPolicy = "Disabled"
}
}
try {
# If the USB service is disabled, the registry value indicates it is disabled, or the group policy disables it, set the custom field to "Disabled".
if ($USBService.StartType -eq "Disabled" -or $USBRegKey -eq 4 -or $USBPolicy -eq "Disabled") {
Write-Host -Object "`nUSB is currently disabled.`n"
if ($CustomField) {
Write-Host -Object "Attempting to set Custom Field '$CustomField'."
Set-NinjaProperty -Name $CustomField -Value "Disabled"
Write-Host -Object "Successfully set Custom Field '$CustomField'!"
}
}
else {
# If none of the conditions indicate the USB is disabled, set the custom field to "Enabled".
Write-Host -Object "`nUSB is currently enabled.`n"
if ($CustomField) {
Write-Host -Object "Attempting to set Custom Field '$CustomField'."
Set-NinjaProperty -Name $CustomField -Value "Enabled"
Write-Host -Object "Successfully set Custom Field '$CustomField'!"
}
}
}
catch {
# Catch any exceptions that occur and print an error message.
Write-Host "[Error] $($_.Exception.Message)"
$ExitCode = 1
}
# Exit the script with the appropriate exit code.
exit $ExitCode
}
end {
}
Description détaillée
Ce script effectue trois contrôles principaux et définit éventuellement un champ personnalisé NinjaOne pour refléter l’état de la clé USB :
Vérifier l’état du service USB
Le script commence par vérifier si le service USBStor (USB Mass Storage Driver) est activé :
powershell
CopyEdit
$USBService = Get-Service -Name « USBStor »
- Si le service est absent ou désactivé, le stockage USB est probablement bloqué.
Vérifier les paramètres du registre
Il vérifie ensuite la valeur du registre sous :
sql
CopyEdit
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\USBSTOR
- Une valeur de démarrage de 4 signifie que le service est désactivé.
Vérifier les paramètres de la stratégie de groupe
Enfin, il examine les clés de registre basées sur la stratégie de groupe :
CopyEdit
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\RemovableStorageDevices
- Des GUID spécifiques et des clés telles que Deny_All, Deny_Read, Deny_Write et Deny_Execute sont vérifiés pour déterminer si des restrictions basées sur une politique sont en place.
- Intégration de champs personnalisés
Si le paramètre -CustomField est fourni, le script utilise la fonction Set-NinjaProperty pour définir le champ personnalisé NinjaOne de l’appareil avec l’une des valeurs suivantes :- Activé (Enabled)
- Désactivé (Disabled)
- Impossible à déterminer (Unable to Determine)
Cas d’utilisation potentiels (Potential Use Cases)
Étude de cas : Audit de conformité de la sécurité USB
Un fournisseur de services gérés (MSP) est en train d’effectuer l’onboarding un nouveau client dans le secteur de la santé. La conformité HIPAA exige que le stockage USB soit désactivé sur tous les terminaux. Le technicien utilise ce script pour auditer toutes les machines Windows 10 via NinjaOne. Chaque appareil est automatiquement marqué avec le statut USB dans un champ personnalisé appelé usbStorageStatus. Un rapport est généré dans NinjaOne, indiquant les appareils non conformes, ce qui permet d’y remédier rapidement.
Comparaisons
Méthodes alternatives :
- Audit de la stratégie de groupe: Inspecter manuellement les paramètres via gpedit.msc. Prend du temps et n’est pas faisable a grande échelle.
- Logiciel de protection des terminaux: Des outils tels que Symantec ou CrowdStrike surveillent souvent l’USB, mais manquent d’une intégration simple avec les outils RMM pour la visibilité.
- Vérifications manuelles du registre: Fiable, mais nécessite des connaissances approfondies et une capacité de script pour évoluer.
En comparaison, le script PowerShell offre une approche rapide, cohérente et automatisable, particulièrement précieuse lorsqu’il est intégré aux champs personnalisés de NinjaOne pour un suivi centralisé.
Questions fréquentes
Q : Le script nécessite-t-il des privilèges d’administrateur ?
Oui, le script vérifie l’élévation à l’aide de Test-IsElevated et se termine par une erreur s’il n’est pas exécuté en tant qu’administrateur.
Q : Quelles sont les versions du système d’exploitation prises en charge ?
Le système d’exploitation minimum pris en charge est Windows 10, tel qu’indiqué dans les notes du script.
Q : Que se passe-t-il si le service USBStor ou des clés de registre sont manquants ?
Le script marque le résultat comme étant « Impossible à déterminer » (Unable to Determine) et se termine en toute sécurité.
Q : Est-il compatible avec d’autres outils RMM ?
Le script a été conçu en tenant compte de l’intégration avec NinjaOne. Cependant, la logique de vérification USB peut être réutilisée pour d’autres systèmes.
Implications
Les politiques USB mal configurées constituent un point faible courant en matière de sécurité. Si le script trouve que la fonction USB est activée sur des appareils sensibles, cela peut signifier un manque de conformité ou un vecteur d’attaque potentiel. Inversement, le fait de signaler régulièrement des cas d’invalidité au sein d’une flotte confirme l’efficacité des politiques de sécurité.
Du point de vue de la continuité des activités, l’identification des terminaux dont les paramètres USB sont inconnus ou mal configurés permet d’éviter l’exfiltration de données et d’améliorer la préparation à la réponse aux incidents.
Recommandations
- Utiliser comme tâche planifiée : Exécutez ce script chaque semaine dans le cadre de votre processus d’audit standard des appareils.
- Intégration avec les rapports NinjaOne : Créez des rapports autour du champ usbStorageStatus pour surveiller et alerter sur les changements.
- Associer à la remédiation : Créez des scripts d’accompagnement pour désactiver automatiquement l’USB si la conformité n’est pas respectée.
- Contrôle de version : Documentez et versionnez votre script pour les pistes d’audit et la maintenance.
Conclusion
Pour les MSP et les départements informatiques, la possibilité de vérifier l’état du stockage USB avec PowerShell est un atout majeur. Ce script détermine non seulement l’activation de l’USB à travers plusieurs méthodes (service, registre et stratégie de groupe), mais écrit également les résultats directement dans NinjaOne pour un suivi à grande échelle et évolutif. En intégrant la validation des politiques de sécurité dans votre outil RMM, vous renforcez la conformité, réduisez les tâches manuelles et obtenez des informations exploitables.