Suppression massive de pilotes d’imprimante

Par moment, nous trouvons des architectures qui n’ont pas spécifié de politique de gestion des imprimantes et surtout de l’installation des drivers. Ce type d’environnement arrive souvent avec des problématiques de fiabilités des impressions. Nous allons présenter un cas pratique de sécurisation et de nettoyage d’un de ces conventionnement.

Etat des lieux

Liste des pilotes

Etats des pilotes

Voici donc, une ferme Citrix XenApp 4.5 R05, windows 2003 SP2 contenant 90 serveurs et 250 CCU. Un rapide check des stratégies Citrix nous apprend que le client aura toutes ses imprimantes de remonter sur le serveur et que celui-ci utilisera le pilote universel si le pilote natif n’est pas disponible. Les serveurs hébergent tout de même énormément de pilote d’imprimantes… Une vérification des stratégies ActiveDirectory s’impose donc! Première surprise, pas de restriction d’installation des pilotes d’impressions pour TS. Donc les admins ont pollué un serveur à chaque nouvelle connexion TS. Seconde surprise, les membres du pilotage de l’application ont aussi des accès TS à ces serveurs _ nous pouvons même ajouter quelques fuites de credential pour faire bonne mesure… Autant estimer qu’un grand nombre de pilote d’imprimante bancales ont été installé par TS sur cette ferme.

Corrections apportés aux paramétrages

Rapidement, nous avons linké une GPO pour bloquer l’installation des pilotes via TS. Ensuite, il faut s’atteler au nettoyage de pilotes d’impression. Heureusement, il existe une liste de pilote d’imprimante validés comme fonctionnant avec l’application et citrix. Nous utilisons donc cette information pour actualiser la stratégies d’impression :

  • Seule l’imprimante par défaut du client est remonté
  • Seul l’UPD est utilisé pour remonter les imprimantes
  • La liste des imprimantes validées est considéré comme une white list

Effectivement l’UPD masque la white list. L’avantage est qu’en maintenant cette white list, quand nous aurons une demande pour utiliser un/des pilotes particuliers, nous n’auront qu’à modifier configuration UPD pour ne l’utiliser que si le pilote natif n’est pas disponible.

COMMENT CRÉER UNE WHITE LIST ?
La white list se crée dans la CMC, clic droit sur Imprimantes > Pilote d’imprimantes, puis clic sur liste de compatibilité. Une fenêtre s’affiche, il faut y renseigner tous les noms de pilotes de noter liste. Dans la stratégie Citrix, installation automatique des pilotes d’impression, il faut sélectionner n’autorisé que les pilotes appartenant à la liste de compatibilité. (http://support.citrix.com/proddocs/topic/xenapp6-w2k8-admin/ps-printing-drivers-compatibility-lists-all.html )

Préparation de la désinstallation massive

Afin d’éviter les désagrément possible du à une mauvaise manipulation ou un oubli, il ne reste plus qu’à désinstaller tous les pilotes qui ne sont pas dans notre white list des serveurs. Cependant, il n’est pas vraiment souhaitable de nettoyer manuellement 90 serveurs. Heureusement pour nous, nous avons PowerShell et le script fournit par microsoft prndriver.vbs qui vont nous permettre d’automatiser le nettoyage des serveurs. Le script va récupérer une liste d’imprimante autorisé, vérifier les drivers installés sur chaque serveur de la ferme et désinstaller ceux qui n’appartiennent pas à notre liste.

UN SCRIPT
La syntaxe du script est :

clean_printdriver.ps1 [-FilePath chemindufichier] [-ServerName NomduServeur] [-XACompatibilityList] [-WhatIf]

Nous pouvons donc spécifier de 3 façon notre liste, soit depuis le fichier spécifié via -FilePath, soit depuis la liste des pilotes installés sur le serveur spécifié par -ServerName et sinon, nous utilisons la liste de compatibilité de la ferme. L’option -WhatIf liste les actions qui seraient effectuées.

GERER LES PILOTES EN LIGNE DE COMMANDE
prndrvr.vbs est un script dédié à la gestion des pilotes en ligne de commande.
Pour récupérer la liste des pilotes (entre autres) sur un serveur

prndrvr.vbs -l -s SERVERNAME [| find "Nom du pilote" ]

La partie entre crochet n’est pas obligatoire mais le script étant très volubile !

Pour désinstaller un pilote

prndrvr.vbs -d -m NomduPilote -s SERVERNAME

CITRIX ET POWERSHELL

Citrix nous fournit une quantité importante de cmdlet pour gérer les fermes. On peut les lister toutes en utilisant “Get-Command”

 PS > Get-Command -Module citrix* | % { $_.name }
Add-XAAdministratorPrivilege
Add-XAApplicationAccount
Add-XAApplicationFileType
Add-XAApplicationServer
Add-XASessionPrinter
Clear-XAConfigurationLog
Connect-XASession
Copy-XAApplication
Copy-XAFolder
Disable-XAAdministrator
Disable-XAApplication
Disable-XAPolicy
Disable-XAServerLogOn
Disconnect-XASession
Enable-XAAdministrator
Enable-XAApplication
Enable-XAPolicy
Enable-XAServerLogOn
Get-XAAccount
Get-XAAccountAuthority
Get-XAAdministrator
Get-XAAdministratorFolder
Get-XAAdministratorPrivilege
Get-XAApplication
Get-XAApplicationIcon
Get-XAApplicationParameter
Get-XAApplicationReport
Get-XAApplicationServerBinding
Get-XAAppliedPolicy
Get-XAAutoReplicatedPrinterDriver
Get-XAClientModule
Get-XAClientPrinter
Get-XAConfigurationLog
Get-XAFarm
Get-XAFarmConfiguration
Get-XAFileType
Get-XAFolder
Get-XAHmrTest
Get-XAIconStream
Get-XALoadEvaluator
Get-XAMemoryOptimization
Get-XAOfflineLicense
Get-XAPolicy
Get-XAPolicyConfiguration
Get-XAPolicyFilter
Get-XAPrinter
Get-XAPrinterDriver
Get-XAPrinterDriverCompatibility
Get-XAPrinterDriverMapping
Get-XAPrintServer
Get-XAProfileApplication
Get-XAResultantPolicy
Get-XAServer
Get-XAServerConfiguration
Get-XAServerCounter
Get-XAServerHotfix
Get-XAServerLoad
Get-XASession
Get-XASessionCounter
Get-XASessionPrinter
Get-XASessionProcess
Get-XAStreamingSession
Get-XAVirtualIPRange
Get-XAZone
Import-XALegacyApplication
Import-XAPrintServer
Move-XAApplication
Move-XAFolder
Move-XAServer
New-XAAdministrator
New-XAApplication
New-XAAutoReplicatedPrinterDriver
New-XAClientPrinter
New-XAFolder
New-XAHmrTest
New-XAIcaFile
New-XALoadEvaluator
New-XAPolicy
New-XAPrinterDriverCompatibility
New-XAPrinterDriverMapping
New-XAVirtualIPRange
Remove-XAAdministrator
Remove-XAAdministratorPrivilege
Remove-XAApplication
Remove-XAApplicationAccount
Remove-XAApplicationFileType
Remove-XAApplicationServer
Remove-XAAutoReplicatedPrinterDriver
Remove-XAClientPrinter
Remove-XAFolder
Remove-XAHmrTest
Remove-XALoadEvaluator
Remove-XAPolicy
Remove-XAPrinterDriverCompatibility
Remove-XAPrinterDriverMapping
Remove-XAPrintServer
Remove-XAServer
Remove-XASessionPrinter
Remove-XAVirtualIPRange
Rename-XAApplication
Rename-XAFolder
Rename-XAHmrTest
Rename-XALoadEvaluator
Rename-XAPolicy
Rename-XAZone
Replicate-XAPrinterDriver
Reset-XAClientPrinter
Reset-XAServerLoadEvaluator
Send-XASessionMessage
Set-XAAdministrator
Set-XAAdministratorFolder
Set-XAApplication
Set-XAApplicationServerBinding
Set-XAFarmConfiguration
Set-XAHmrTest
Set-XALoadEvaluator
Set-XAPolicy
Set-XAPolicyConfiguration
Set-XAPolicyFilter
Set-XAPrinterDriverCompatibility
Set-XAPrinterDriverMapping
Set-XAServerConfiguration
Set-XAServerEdition
Set-XAServerLoadEvaluator
Set-XAServerZone
Set-XASessionCounter
Set-XASessionPrinter
Stop-XASession
Stop-XASessionProcess
Test-XAConfigurationLog
Test-XALicenseServer
Update-XAFileType
Update-XAPrinter

Pour récupérer la liste des serveur de la ferme Citix, nous pouvons utiliser le cmdlet Get-XAServer qui nous retourne un tableau d’objet “XAServer”. Pour connaitre les membres d’un objet Powershell, il suffit de les envoyer dans le cmdlet Get-Member.

PS > $tmp = Get-XaServeur
PS > $tmp[0] | get-member | %{ $_.Name }
Equals
GetHashCode
GetType
ToString
CitrixEdition
CitrixEditionString
CitrixInstallDate
CitrixInstallPath
CitrixProductName
CitrixServicePack
CitrixVersion
ElectionPreference
FolderPath
IcaPortNumber
IPAddresses
Is64Bit
LogOnsEnabled
OSServicePack
OSVersion
RdpPortNumber
ServerName
SessionCount
VirtualIPInUse
ZoneName

Le membre ServerName est tout indiqué pour nous aider.

Dans le même esprit, on peut récupérer le contenu de la lise de compatiblité en utilisant Get-XAPrinterDriverCompatibility, qui retourne une collection de XAPrinterDriverCompatibility. Cependant ce qui nous intéresse c’est le champs driverName et non pas l’objet complet. On peut facilement extraire cette information en utilisant un foreach ou mieux la syntaxe courte “%”

$aDrivers = get-XacompatibilityList | foreach {$_.DriverNAme}
$aDrivers = get-XACompatibilityList | %{$_.DriverNAme}

RASSEMBLONS LE TOUT

Dès le début du script, et c’est une obligation, nous spécifions les paramètres que nos acceptons avec la commande Param. A l’invocation du script powershell s’occupera de remplir les variables suivant les arguments passés.

Param(
[string]$FilePath,
[string]$ServerName,
[switch]$XACompatibilityList,
[switch]$WhatIf,
[switch]$h
)

Avant de charger le module Citrix dans PowerShell, nous assurons que ce n’est pas le déjà le cas.

if ((Get-PSSnapin -Name Citrix* -ErrorAction SilentlyContinue) -eq $null){
Add-PSSnapin Citrix*
}

Nous pouvons vérifier l’existence d’une variable avec le cmdlet Test-Path variable:NomdelaVariable

If( (Test-Path variable:FilePath) -and ($FilePath.length -gt 0 )){
$aPilotes = Get-Content $FilePath
}elseif( (Test-Path variable:ServerName) -and ($ServerName.length -gt 0)){
#le retour de la commande prefixe les pilote par Nom du pilote et les postfixe avec ,version,envl
echo "cmd /c " $sCmdList.REPLACE("SERVERNAME", $ServerName)
$aPilotes = cmd /c $sCmdList.REPLACE("SERVERNAME", $ServerName) | % { $_.substring("Nom du pilote ".length, $_.IndexOf(",") - "Nom du pilote ".length )}
}elseif($XACompatibilityList) {
$aPilotes = Get-XAPrinterDriverCompatibility | % {$_.DriverName}
}else{
Print-Help
}

Voici à quoi ressemble le script complet.

#Definition des paramètres
Param(
	[string]$FilePath,
	[string]$ServerName,
    [switch]$XACompatibilityList,
    [switch]$WhatIf,
	[switch]$h
)

if ((Get-PSSnapin -Name Citrix* -ErrorAction SilentlyContinue) -eq $null){
    Add-PSSnapin Citrix*
}

#Definition des Lignes de commandes

$sCmdList = "cscript c:\windows\system32\prndrvr.vbs -l -s SERVERNAME | find `"Nom du pilote`""
$sCmdSupp = "cscript c:\windows\system32\prndrvr.vbs -d -s SERVERNAME -m `"PILOTE`" "

#Creation du tableau avec la liste des pilotes autorisés (liste blance)

function Print-Help(){
	echo "clean_printerdriver.ps1 [-FilePath pathtodriverlist] [-ServerName SERVER] [-XACompatibilityList] [-WhatIf]
    will remove driver not in specified file, not installed on the specified server or not in farm compatibility list
clean_printerdriver.ps1 -h 
	display this message"
	Exit 0
}

if($h){
	Print-Help
}

#echo "`$FilePath $FilePath, `$ServerName $ServerName, `$WhatIf $WhatIf" 
#Test-Path variable:FilePath

#Chargement de la WhiteList de pilotes

If( (Test-Path variable:FilePath) -and ($FilePath.length -gt 0 )){
	$aPilotes = Get-Content $FilePath
}elseif( (Test-Path variable:ServerName) -and ($ServerName.length -gt 0)){
    #le retour de la commande prefixe les pilote par Nom du pilote et les postfixe avec ,version,envl
    echo "cmd /c " $sCmdList.REPLACE("SERVERNAME", $ServerName)
	$aPilotes = cmd /c $sCmdList.REPLACE("SERVERNAME", $ServerName)  | % { $_.substring("Nom du pilote ".length, $_.IndexOf(",") - "Nom du pilote ".length )}
}elseif($XACompatibilityList) {
    $aPilotes = Get-XAPrinterDriverCompatibility | % {$_.DriverName}
}else{
	Print-Help
}


$aServers = Get-XAServer	#Gets the XA servers in the farm
foreach( $oServer in $aServers){
    if($whatIf){ echo "Travail sur $oServer"}
	$aResultat = cmd /c $sCmdList.REPLACE("SERVERNAME", $oServer.ServerName)

    foreach( $sLine in $aResultat){
        $sBackup = $sLine
        #Les lignes Commencent par "Nom du pilote "
		if($sLine){
			$sLine = $sLine.substring("Nom du pilote ".length, $sLine.IndexOf(",") - "Nom du pilote ".length )
			if( $aPilotes -notcontains $sLine ){
                If( $WhatIf ){
                    echo "Supression du pilote : $sLine"
					$aPilote = $sBackup.split(',')
					$cmd = $sCmdSupp.REPLACE("SERVERNAME", $oServer.ServerName).Replace("PILOTE", $sLine )
                    echo "$cmd -v $($aPilote[1]) -e `"$($aPilote[2])`""
                }else{	
					$aPilote = $sBackup.split(',')
					$cmd = $sCmdSupp.REPLACE("SERVERNAME", $oServer.ServerName).Replace("PILOTE", $sLine )
                    $sCmd = "$cmd -v $($aPilote[1]) -e `"$($aPilote[2])`""
					echo $sCmd
                    $result = cmd /c $sCmd
					echo $result
                }
			}else{
				If($WhatIf){
					echo "Ne rien faire pour : $sLine"
				}
			}
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *