SCCM/SMS & PowerShell: Introduction (2/3)

juin 6, 2011
Pour cette seconde partie, je vais vous proposer un script permettant de déplacer les collections entre sous collections.
La console SCCM ne nous permet pas de réaliser ce type d’opération, voilà pourquoi ce script peut être des plus intéressants.

A. Petit rappel concernant les collections

En SCCM, la notion de collection est très importante, Elle vous permet de grouper des ressources ensembles suivant un ensemble de critères communs.

Via la console, il est possible de lier une collection comme étant enfant d’une autre. Je dis bien lié car une collection reste un objet “neutre” possédant un ensemble de pointeurs hiérarchique indiquant le lien de parenté.

B. Les sous-collections

Prenons l’exemple suivant:

  • Je crée une collection Ma_Collection_1. Par défaut elle sera placée en dessous du noeud portant le nom de Collections qui est le noeud parent le plus élevé. Son nom interne est COLROOT.
  • Je crée ensuite une seconde collection Ma_Collection_2 également sous le noeud Collections.

SCCM-Collection4

  • Je décide ensuite de rendre Ma_Collection_2 enfant de Ma_Collection_1, Je le fait en cliquant sur Ma_Collection_1 –> New –> Link To Collection et je choisis Ma_Collection_2.

SCCM-Collection5

SCCM-Collection6

SCCM-Collection7

Vous constatez que Ma_Collection_2 est maintenant une sous-collection de Ma_Collection_1 mais reste également une sous-collection de Collections.

Ce petit exemple tente à délontrer qu’une collection peut avoir plusieurs liens hiérarchiques sans modifier l’objet en lui-même.

A partit de cet exemple, on peut en déduire qu’un objet Collection contient un ensemble d’objets SubCollection. C’est presque ca Smile En réalité, un lien de parenté entre collections se fait par la création d’un objet SMS_CollectToSubCollect.

Cet objet possède les propriétés suivantes;

  • parentCollectionID
  • subCollectionID

Il suffit de donner l’ID de la collection parent à la première méthode et de donner l’ID de la collection enfant à la seconde méthode.

C. En Powershell, cela donne ceci

Voici la fonction qui permet de créer une relation entre 2 collections via l’utilisation de l’objet SMS_CollectToSubCollect:

Function ImportCollections($collData, $parentCollID) {
foreach ($elem in $collData){
$elemID = $elem.CollectionID
$oSubColl = $conSCCM.CreateInstance("SMS_CollectToSubCollect")
$oSubColl["parentCollectionID"].StringValue = $parentCollID
$oSubColl["subCollectionID"].StringValue = $elemID
$oSubColl.Put()
Write-Host "Collection $elemID imported into $parentCollID"
}
Write-Host "SubCollections imported into Parent Collection: " $collData.Length "item(s)" -ForegroundColor Green
}

Vu que le but du programme est de déplacer une collection et non de multiplier ses liens hiérarchiques, voici la fonction que j’utilise pour supprimer le lien précédent:

Function DeleteObsoleteCollections($collData,[string]$oSc, [String]$oldPColl){
$smsSiteCode = "root\SMS\Site_" + $oSc
foreach ($elem in $collData){
$elemID = $elem.CollectionID
$subCollObs = Get-WmiObject -namespace $smsSiteCode -query "select * from SMS_CollectToSubCollect where parentCollectionID = '$oldPColl' and subCollectionID = '$elemID'"
$subCollObs.Delete()
Write-Host "Collection $elemID deleted from $oldPColl"
}
Write-Host "Subcollection deleted from Parent Collection: " $collData.Length "item(s)" -ForegroundColor Green
}

Voici le programme complet. Il a pour but de permettre un déplacement de dépendance hiérarchique entre collections.

Son fonctionnement est relativement simple, je réalise un export des collections dans un fichier csv.

Je traite le fichier manuellement pour seul les collections désirées soient traitées.

Je réimporte ensuite le fichier avec le nom de la collection parent qui servira de point hiérarchique aux collections enfants se trouvant dans le fichier.

E. Exemple complet

#=========================================================================
#
#NAME: PS-SCCMCollToSubColl
#
#VERSION: 1.0
#AUTHOR: Malfroidt Olivier
#DATE: 20/05/2011
#
#COMMENT:
#
#=========================================================================

#*****************
#Arguments
#*****************
param ([string]$mode, [string]$file, [string]$sccmSrv, [string]$siteCode, [String]$parentColl, [String]$oldParentColl)

#*****************
#Assemblies
#*****************
[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Microsoft Configuration Manager\AdminUI\bin\adminui.wqlqueryengine.dll")
[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Microsoft Configuration Manager\AdminUI\bin\microsoft.configurationmanagement.managementprovider.dll")

#*****************
#Variables
#*****************
$conSCCM = $null
$importedQueries = @()

#*****************
#Functions
#*****************

#*************
#HelpMessage
#*************

Function HelpMsg()
{
$helpText=@"

Name: PS-SCCMCollToSubColl - v1.0 Release

Usage:
PS-SCCMCollToSubColl -mode [IMPORT | EXPORT] -file [filename] [-sccmSrv [server name] -siteCode [SCCM site code] -parentColl [Parent Collection] -oldParentColl [Old Parent Collection]]

Options:
Mandatory
-mode [IMPORT | EXPORT]: Specify if you want import Collections to SCCM or export data from SMS
-file [Filename]: Desination file if you export data and Source file if you import data.
-sccmSrv [ServerName]: In case of Export mode, you must specify the SCCM Server name.
-siteCode [SMS Site code]: In case of Export mode, you must specify the SCCM Site code.
-parentColl [SCCM Parent Colllection]: New Parent Collection ID
-oldParentColl [Old Parent Collection]: Old Parent Collection ID
Exemples:
Export:
PS-SCCMCollToSubColl -mode EXPORT -file "
D:\Temp\Export.csv" -sccmSrv SERVERNAME -siteCode "00A"
Import:
PS-SCCMCollToSubColl -mode IMPORT -file "
D:\Temp\Export.csv" -sccmSrv SERVERNAME -siteCode "00A" -parentColl "00A0000D" -oldParentColl "COLLROOT"
"
@
$helpText
exit
}

Function ConnectionSCCM(){
$nameValues = New-Object -TypeName microsoft.configurationmanagement.managementprovider.SmsNamedValuesDictionary
$script:conSCCM = New-Object -TypeName microsoft.configurationmanagement.managementprovider.WqlQueryEngine.WqlConnectionManager -ArgumentList $nameValues
$script:conSCCM.Connect([system.Net.dns]::GetHostName().ToUpper())
}

Function CloseConnSCCM(){
$script:conSCCM.Close()
}

Function ImportCollections($collData, $parentCollID) {
foreach ($elem in $collData){
$elemID = $elem.CollectionID
$oSubColl = $conSCCM.CreateInstance("SMS_CollectToSubCollect")
$oSubColl["parentCollectionID"].StringValue = $parentCollID
$oSubColl["subCollectionID"].StringValue = $elemID
$oSubColl.Put()
Write-Host "Collection $elemID imported into $parentCollID"
}
Write-Host "SubCollections imported into Parent Collection: " $collData.Length "item(s)" -ForegroundColor Green
}

Function DeleteObsoleteCollections($collData,[string]$oSc, [String]$oldPColl){
$smsSiteCode = "root\SMS\Site_" + $oSc
foreach ($elem in $collData){
$elemID = $elem.CollectionID
$subCollObs = Get-WmiObject -namespace $smsSiteCode -query "select * from SMS_CollectToSubCollect where parentCollectionID = '$oldPColl' and subCollectionID = '$elemID'"
$subCollObs.Delete()
Write-Host "Collection $elemID deleted from $oldPColl"
}
Write-Host "Subcollection deleted from Parent Collection: " $collData.Length "item(s)" -ForegroundColor Green
}

Function ExportCollections ([string]$oSrv, [string]$oSc, [string]$oFile) {
$smsSiteCode = "root\SMS\Site_" + $oSc
$oCollSccm = Get-WmiObject -ComputerName $oSrv -Namespace $smsSiteCode -Query "select * from SMS_Collection"
$oCollSccm | select-object Name, CollectionID | Export-Csv $oFile -Delimiter ";"
write-host "Collections exported from SCCM: " $oCollSccm.Length "item(s)"
}

#*****************
#Main
#*****************

try{
if (($mode -ne "") -and ($file -ne "")) {
switch ($mode.ToUpper()){
"IMPORT" {
if ($parentColl -ne ""){
Write-Host "SubCollections move into SCCM: Job start" -ForegroundColor Blue
$importedCollection = import-csv $file -Delimiter ";"
ConnectionSCCM
ImportCollections $importedCollection  $parentColl
DeleteObsoleteCollections $importedCollection $siteCode $oldParentColl
CloseConnSCCM
Write-Host "SubCollections move into SCCM: Job done" -ForegroundColor Blue
}Else{
Write-Host "IMPORT ERROR: Incorrect arguments provided" -ForegroundColor Red
HelpMsg
}
}
"EXPORT" {
if (($sccmSrv -ne "") -and ($siteCode -ne "")) {
Write-Host "Collections export from SCCM: Job start" -ForegroundColor Blue
ExportCollections $sccmSrv  $siteCode $file
Write-Host "Collections export from SCCM: Job done" -ForegroundColor Blue
} else {
Write-Host "EXPORT ERROR: Incorrect arguments provided" -ForegroundColor Red
HelpMsg
}
}
Default {
HelpMsg
}
}
}else{
Write-Host "GENERAL ERROR: Incorrect arguments provided" -ForegroundColor Red
HelpMsg
}
}catch {
Write-Host -ForegroundColor Red "CRITICAL ERROR: " $Error[0]
}

Source: http://msdn.microsoft.com/en-us/library/cc143948.aspx

Enjoy !!!

0

SCCM/SMS & PowerShell: Introduction (1/3)

avril 11, 2011
images Scripter autour de SCCM/SMS n’est pas chose facile. On trouve sur internet quelques scripts VBS mais la documentation reste assez pauvre.
Concernant Powershell, c’est encore plus vrai car il n’existe que très peu d’exemples concrèts.

Je vais donc essayer de combler ce manque ne vous proposant un exemple concrèt: automatiser l’export des objects Query en provenance de SMS et les réimporter dans SCCM.

Je vais vous montrer comment utiliser à la fois les objects de type WMI et les objects en provenance des librairies SCCM.

A. Par où commencer?

Dans un premier temps, il faut se procurer le SDK de SCCM: System Center Configuration Manager 2007 Software Development Kit (SDK) v4.0

Cette documentation est votre seul véritable aide. Elle est fournie d’exemples de tout type et le plus intéressant est qu’ils sont écrits en C# et Vb.net.

Comme Powershell est un language pure .Net, il est très facile de porter les exemples.

B. Première étape: Chargement des librairies SCCM dans notre script PowerShell

Pour pouvoir controller SCCM au travers de Powershell, il va falloir utiliser les objects mis à notre disposition dans les librairies adéquates:

  • adminui.wqlqueryengine.dll
  • microsoft.configurationmanagement.managementprovider.dll

Vous les trouverez dans le répertoire d’installation de SCCM: C:\Program Files (x86)\Microsoft Configuration Manager\AdminUI\bin

Pour pouvoir les charger en Powershell, il faut les charger à partir de la méthode LoadFrom du name space System.Reflection.Assembly.

Ce qui nous donne ceci:

[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Microsoft Configuration Manager\AdminUI\bin\adminui.wqlqueryengine.dll")
[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Microsoft Configuration Manager\AdminUI\bin\microsoft.configurationmanagement.managementprovider.dll")

C. Seconde étape: Récupérer les objects Query de notre environement SMS

Pour ce faire, nous allons utiliser une connection et des objects de type WMI, ce qui nous évitera de trop nous compliquer la tâche et de cette manière vous aurez également un exemple de ce type de connection.

Toute la magie de cette connection se situe dans cette ligne de commande:

Get-WmiObject -ComputerName $oSrv -Namespace $smsSiteCode -Query "select * from SMS_Query"

ComputerName: Nom du server SMS

NameSpace: Localisation des objects SMS en WMI (ex: root\SMS\Site_001)

Query: Query de type WQL vous permettant de récupérer les objets dont vous avez besoin.

Voici une fonction vous permettant de récuperer l’ensemble des objects Query et de les exporter dans un fichier CSV.

Function ExportQuery ([string]$oSrv, [string]$oSc, [string]$oFile) {
$smsSiteCode = "root\SMS\Site_" + $oSc
$oQuerySms = Get-WmiObject -ComputerName $oSrv -Namespace $smsSiteCode -Query "select * from SMS_Query"
$oQuerySms | select-object Name, Comments, QueryID, TargetClassName, Expression | Export-Csv $oFile -Delimiter ";"
write-host "Queries exported from SMS: " $oQuerySms.Length "item(s)"
}

D. Troisième étape: Importer notre fichier CSV dans SCCM

Le fait d’avoir précédement charger les librairies SCCM dans notre script PowerShell va nous permettre maintenant de les utiliser.

Nous allons dans un premier temps nous connecter à SCCM:

Function ConnectionSCCM(){
$nameValues = New-Object -TypeName microsoft.configurationmanagement.managementprovider.SmsNamedValuesDictionary
$script:conSCCM = New-Object -TypeName microsoft.configurationmanagement.managementprovider.WqlQueryEngine.WqlConnectionManager -ArgumentList $nameValues
$script:conSCCM.Connect([system.Net.dns]::GetHostName().ToUpper())
}

Nous allons ensuite lire notre fichier CSV et importer chaque query dans SCCM

Function ImportQuery($collData) {
foreach ($elem in $collData){
# Query Creation
$oQuery = $script:conSCCM.CreateInstance("SMS_Query")

# Populate Data
$oQuery["Comments"].StringValue = $elem.Comments.ToString()
$oQuery["Expression"].StringValue = $elem.Expression.ToString()
$oQuery["LimitToCollectionID"].StringValue = $elem.LimitToCollectionID
$oQuery["Name"].StringValue = $elem.Name.ToString()
$oQuery["TargetClassName"].StringValue = $elem.TargetClassName.ToString()
$oQuery.put()
$oQuery.Get()
write-host "SCCM: New query ID: " $oQuery["QueryID"].StringValue
}
Write-Host "Queries imported to SCCM: " $collData.Length "item(s)"
}

E. Exemple complet

Ce script doit être exécuté à partir du server SCCM. Si vous voulez l’utiliser à partir d’une station de management, assurez vous des points suivants:

  • Les librairies se trouvent également sur la station de management
  • Votre compte utilisateur à les droits suffisants pour accéder aux informations de SCCM et SMS.
#=========================================================================
#
#NAME: PS-QueryMigrator
#
#VERSION: 1.0
#AUTHOR: Malfroidt Olivier
#DATE: 05/04/2011
#
#COMMENT:
#
#=========================================================================

#*****************
#Arguments
#*****************
param ([string]$mode, [string]$file, [string]$smsSrv, [string]$siteCode)

#*****************
#Assemblies
#*****************
[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Microsoft Configuration Manager\AdminUI\bin\adminui.wqlqueryengine.dll")
[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Microsoft Configuration Manager\AdminUI\bin\microsoft.configurationmanagement.managementprovider.dll")

#*****************
#Variables
#*****************
$conSCCM = $null
$importedQueries = @()

#*****************
#Functions
#*****************

#*************
#HelpMessage
#*************

Function HelpMsg()
{
$helpText=@"

Name: PS-QueryMigrator - v1.0 Release

Usage:
PS-QueryMigrator -mode [IMPORT | EXPORT] -file [filename] [-smsSrv [server name] -siteCode [SMS site code]]

Options:
Mandatory
-mode [IMPORT | EXPORT]: Specify if you want import data to SCCM or export data from SMS
-file [Filename]: Desination file if you export data and Source file if you import data.
Optionnal
-smsSrv [ServerName]: In case of Export mode, you must specify the SMS Server name.
-siteCode [SMS Site code]: In case of Export mode, you must specify the SMS Site code.

"
@
$helpText
exit
}

Function ConnectionSCCM(){
$nameValues = New-Object -TypeName microsoft.configurationmanagement.managementprovider.SmsNamedValuesDictionary
$script:conSCCM = New-Object -TypeName microsoft.configurationmanagement.managementprovider.WqlQueryEngine.WqlConnectionManager -ArgumentList $nameValues
$script:conSCCM.Connect([system.Net.dns]::GetHostName().ToUpper())
}

Function CloseConnSCCM(){
$script:conSCCM.Close()
}

Function ConnectionSMS(){

}

Function ImportQuery($collData) {
foreach ($elem in $collData){
# Query Creation
$oQuery = $script:conSCCM.CreateInstance("SMS_Query")

# Populate Data
$oQuery["Comments"].StringValue = $elem.Comments.ToString()
$oQuery["Expression"].StringValue = $elem.Expression.ToString()
$oQuery["LimitToCollectionID"].StringValue = $elem.LimitToCollectionID
$oQuery["Name"].StringValue = $elem.Name.ToString()
$oQuery["TargetClassName"].StringValue = $elem.TargetClassName.ToString()
$oQuery.put()
$oQuery.Get()
write-host "SCCM: New query ID: " $oQuery["QueryID"].StringValue
}
Write-Host "Queries imported to SCCM: " $collData.Length "item(s)"
}

Function ExportQuery ([string]$oSrv, [string]$oSc, [string]$oFile) {
$smsSiteCode = "root\SMS\Site_" + $oSc
$oQuerySms = Get-WmiObject -ComputerName $oSrv -Namespace $smsSiteCode -Query "select * from SMS_Query"
$oQuerySms | select-object Name, Comments, QueryID, TargetClassName, Expression | Export-Csv $oFile -Delimiter ";"
write-host "Queries exported from SMS: " $oQuerySms.Length "item(s)"
}

#*****************
#Main
#*****************

try{
if (($mode -ne "") -and ($file -ne "")) {
switch ($mode.ToUpper()){
"IMPORT" {
Write-Host "Queries import to SCCM: Job start"
$importedQueries = import-csv $file -Delimiter ";"
ConnectionSCCM
ImportQuery $importedQueries
CloseConnSCCM
Write-Host "Queries import to SCCM: Job done"
}
"EXPORT" {
if (($smsSrv -ne "") -and ($siteCode -ne "")) {
Write-Host "Queries export from SMS: Job start"
ExportQuery $smsSrv  $siteCode $file
Write-Host "Queries export from SMS: Job done"
} else {
Write-Host "EXPORT ERROR: Incorrect arguments provided" -ForegroundColor Red
HelpMsg
}
}
Default {
HelpMsg
}
}
}else{
Write-Host "GENERAL ERROR: Incorrect arguments provided" -ForegroundColor Red
HelpMsg
}

}catch {
Write-Host -ForegroundColor Red "CRITICAL ERROR: " $Error[0]
}

F. Conclusion

Cet exemple peut facilement être adapté pour travailler avec d’autres objects tel que les collections, advertisments, reports, packages, ….

Le SDK vous sera d’une aide précieuse pour connaitres les objets, méthodes et propriétés nécessaires pour réaliser votre script.

Enjoy !!!

0