PI Services

Le blog des collaborateurs de PI Services

PowerShell - Vérifier si une mise à jour Windows (KB) est installée sur les contrôleurs de domaine d'une forêt Active Directory

#Informations récupérées : Nom du contrôleur de domaine (DC), domaine Active Directory (AD) d'appartenance, OS, présence ou non des KB recherchées, date d'installation des KB

#Prérequis : l'utilisateur qui lance le script doit pouvoir requêter en remote PowerShell Administrator l'ensemble des DC de la forêt

#Paramètre obligatoire qui doit contenir la liste des KB à récupérer
#Par exemple pour appeler le script avec une liste de KB : .\Get-DomainControllerKB.ps1 -DCHotFixIDs KB5022511, KB4589208
Param
( 	
	[Parameter(Mandatory=$true)]
    [array]$DCHotFixIDs
)

#Importe le module Active Directory qui contient des commandes utilisées dans le script
Import-Module ActiveDirectory

#Permet de récupérer les noms de tous les domaines dans la forêt AD
$Domains = Get-ADForest | Select-Object Domains
$Domains = $Domains.Domains

#Créer un tableau qui contiendra l'ensemble des statuts des KB des DC de chaque domaine de la forêt
$Array = @()

#Parcours chaque domaine AD de la forêt et récupére la liste des DC
foreach ($Domain in $Domains)
{
	#Récupére l'ensemble des DC du domaine AD actuellement requêté
	$DCs = Get-ADDomainController -Server $Domain -Filter * | Select-Object Name, HostName, OperatingSystem

	#Parcours chaque DC du domaine AD actuellement requêté
    foreach ($DC in $DCs)
    {
		#Vérifie pour chaque KB si elle est présente sur le DC actuellement requêté
		foreach ($DCHotFixID in $DCHotFixIDs)
		{
			#Créer un objet PowerShell qui contiendra les informations sur la KB actuellement requêtée du DC actuellement requêté
			$Line = New-Object PSObject

			#Ajoute à l'objet PowerShell précédemment crée, le nom du DC actuellement requêté
			$Line | Add-Member -MemberType NoteProperty -Name "DomainController" -Value $DC.HostName

			#Ajoute à l'objet PowerShell précédemment crée, le domaine AD d'appartenence du DC actuellement requêté
			$Line | Add-Member -MemberType NoteProperty -Name "Domain" -Value $Domain

			#Ajoute à l'objet PowerShell précédemment crée, le système d'exploitation du DC actuellement requêté
			$Line | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $DC.OperatingSystem

			#Ajoute à l'objet PowerShell précédemment crée, le numéro de la KB actuellement requêté du DC actuellement requêté
			$Line | Add-Member -MemberType NoteProperty -Name "HotFixIDSearched" -Value $DCHotFixID

			#Commande qui va vérifier si la KB actuellement requêtée est présente sur le DC actuellement requêté
			$HotFixObject = Get-HotFix -ComputerName $DC.HostName -ID $DCHotFixID -ErrorAction SilentlyContinue | Select-Object Description, HotFixID, InstalledBy, InstalledOn

			#Si la KB actuellement requêtée est PRESENTE sur le DC actuellement requêté, ajoute les informations relatives à son installation dans l'objet PowerShell précédemment créé
			if ($HotFixObject)
			{
				#Ajoute à l'objet PowerShell précédemment crée, le statut présent ou absent de la KB actuellement requêtée du DC actuellement requêté
				$Line | Add-Member -MemberType NoteProperty -Name "KBIsInstalled" -Value "Success"

				#Ajoute à l'objet PowerShell précédemment crée, le nom de l'utilisateur qui a réalisé l'installation de la KB actuellement requêtée du DC actuellement requêté
				$Line | Add-Member -MemberType NoteProperty -Name "HotFixInstalledBy" -Value $HotFixObject.InstalledBy

				#Ajoute à l'objet PowerShell précédemment crée, la date d'installation, arrondi au jour prêt, de la KB actuellement requêtée du DC actuellement requêté
				$Line | Add-Member -MemberType NoteProperty -Name "HotFixInstalledOn" -Value $HotFixObject.InstalledOn

				#Ajoute à l'objet PowerShell précédemment crée, le type de KB actuellement requêté du DC actuellement requêté
				$Line | Add-Member -MemberType NoteProperty -Name "HotFixDescription" -Value $HotFixObject.Description

				#Supprime les valeurs des variables propres à la KB actuellement requêté du DC actuellement requêté
				Clear-Variable HotFixObject
			}

			#Si la KB actuellement requêtée est ABSENTE sur le DC actuellement requêté, ajoute des valeurs Fail ou NULL pour ses informations dans l'objet PowerShell précédemment créé
			else
			{
				$Line | Add-Member -MemberType NoteProperty -Name "KBIsInstalled" -Value "Fail"
				$Line | Add-Member -MemberType NoteProperty -Name "HotFixInstalledBy" -Value "NULL"
				$Line | Add-Member -MemberType NoteProperty -Name "HotFixInstalledOn" -Value "NULL"
				$Line | Add-Member -MemberType NoteProperty -Name "HotFixDescription" -Value "NULL"
			}

			#Ajoute à la variable globale qui contient l'ensemble des statuts des KB des DC de chaque domaine, l'objet PowerShell précédemment crée lors de l'itération courante
			$Array += $Line

			#Supprime les valeurs des variables propres à la KB actuellement requêtée du DC actuellement requêté
			Clear-Variable DCHotFixID, Line
		}

		#Supprime les valeurs des variables propres au DC actuellement requêté
        Clear-Variable DC
    }

	#Supprime les valeurs des variables propres au domaine actuellement requêté
    Clear-Variable Domain, DCs
}

#Affiche sous forme de liste l'ensemble des KB requêtées des DC de chaque domaine avec leurs status
$Array

<#Exemple d'affichage
DomainController  : DC01.customer.intern
Domain            : customer.intern
OperatingSystem   : Windows Server 2022 Standard
HotFixIDSearched  : KB5022511
KBIsInstalled     : Fail
HotFixInstalledBy : NULL
HotFixInstalledOn : NULL
HotFixDescription : NULL

DomainController  : DC01.customer.intern
Domain            : staff.nsi.dir
OperatingSystem   : Windows Server 2022 Standard
HotFixIDSearched  : KB4589208
KBIsInstalled     : Fail
HotFixInstalledBy : NULL
HotFixInstalledOn : NULL
HotFixDescription : NULL

DomainController  : DC02.technical.intern
Domain            : technical.intern
OperatingSystem   : Windows Server 2019 Standard
HotFixIDSearched  : KB5022511
KBIsInstalled     : Success
HotFixInstalledBy : NT AUTHORITY\SYSTEM
HotFixInstalledOn : 15/02/2023 00:00:00
HotFixDescription : Update

DomainController  : DC02.technical.intern
Domain            : technical.intern
OperatingSystem   : Windows Server 2019 Standard
HotFixIDSearched  : KB4589208
KBIsInstalled     : Success
HotFixInstalledBy : NT AUTHORITY\SYSTEM
HotFixInstalledOn : 28/01/2021 00:00:00
HotFixDescription : Update
#>

 

PowerShell - Récupérer la configuration système des contrôleurs de domaine d'une forêt Active Directory

#Informations récupérées : Nom du contrôleur de domaine, domaine AD, adresse IP, OS, CPU, taille du disque C, taille restante du disque C, RAM
#Evolution du script : certains attributs non utilisés sont récupérés pour pouvoir éventuellement augmenter le nombre d'informations récupéré 

#Prérequis 1 : l'utilisateur qui lance ce script doit pouvoir requêter les bases WMI de tout les contrôleurs de domaine (DC) de la forêt
#Prérequis 2 : le script suppose qu'un seul adapteur réseau de chaque DC posséde une ou plusieurs adresses IP
#Prérequis 3 : le script suppose que le système d'exploitation de chaque DC est installé sur C:

#Importe le module Active Directory qui contient des commandes utilisées dans le script
Import-Module ActiveDirectory

#Permet de récupérer le nom des domaines de la forêt de façon dynamique
$Domains = Get-ADForest | Select-Object Domains
$Domains = $Domains.Domains

#Créer un tableau qui contiendra l'ensemble des DC de tout les domaines de la forêt
$DCToGetConfiguration = @()

#Parcours un par un chaque domaine de la forêt
foreach ($Domain in $Domains)
{
	#Pour chaque domaine de la forêt, récupére l'ensemble des DC du domaine
	$DomainControllersFromCurrentDomain = (Get-ADDomainController -Server $Domain -Filter * | Select-Object HostName, Domain, IPv4Address).HostName

	#Pour chaque domaine de la forêt, ajoute l'ensemble des DC du domaine à l'ensemble des DC de la forêt
	$DCToGetConfiguration += $DomainControllersFromCurrentDomain
}

#Créer un tableau qui contiendra chaque DC de la forêt avec sa configuration
$Array = @()

#Parcours un par un chaque DC de chaque domaine de la forêt, récupéré précédemment
foreach ($ServerToGetConfiguration in $DCToGetConfiguration)
{
	#Créer un objet PowerShell qui contiendra la configuration du DC actuellement requêté
    $Line = New-Object PSObject

	#Ajoute à l'objet PowerShell précédemment crée, le nom du DC actuellement requêté
    $Line | Add-Member -MemberType NoteProperty -Name "HostName" -Value $ServerToGetConfiguration

	#Récupére le domaine AD d'appartenance du DC actuellement requêté
	$WMIComputerSystemObject = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ServerToGetConfiguration | Select-Object Name, Domain

	#Ajoute à l'objet PowerShell précédemment crée, le domaine AD d'appartenance du DC actuellement requêté
	$Line | Add-Member -MemberType NoteProperty -Name "Domain" -Value $WMIComputerSystemObject.Domain

	#Récupére l'adresse IP du DC actuellement requêté
	$WMINetworkAdapterConfigurationObjects = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $ServerToGetConfiguration | Select-Object PSComputerName, IPAddress, IPSubnet, DefaultIPGateway, DNSServerSearchOrder

	#La commande Get-WmiObject -Class Win32_NetworkAdapterConfiguration récupére les adaptateurs réseaux, certains d'entre eux ne comportent pas de carte réseau
	#La boucle suivante ne permet de récupérer que la carte réseau qui contient une adresse IP
	#Cette portion du script ne marchera pas si plusieurs cartes réseaux contiennent chacune une IP
	foreach ($NetworkAdapterConfigurationObject in $WMINetworkAdapterConfigurationObjects)
	{
		if ($NetworkAdapterConfigurationObject.IPAddress)
		{
			$Line | Add-Member -MemberType NoteProperty -Name "IPAddress" -Value ([string]($NetworkAdapterConfigurationObject.IPAddress))
		}
	}

	#Récupére le système d'exploitation du DC actuellement requêté
	$WMIOperatingSystemObject = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ServerToGetConfiguration | Select-Object PSComputerName, Caption, BuildNumber

	#Ajoute à l'objet PowerShell précédemment crée, système d'exploitation du DC actuellement requêté
	$Line | Add-Member -MemberType NoteProperty -Name "OperatingSystem" -Value $WMIOperatingSystemObject.Caption
	
	#Récupére les CPU du DC actuellement requêté
    $WMIProcessorObjects = Get-WmiObject -Class Win32_Processor -ComputerName $ServerToGetConfiguration | Select-Object PSComputerName, Name, MaxClockSpeed, Manufacturer, NumberOfCores, NumberOfEnabledCore, NumberOfLogicalProcessors

	#Boucle qui va additioner l'ensemble des CPU du DC requêté pour obtenir le nombre total de CPU
	$CPUNumbers = 0
	foreach ($WMIProcessorObject in  $WMIProcessorObjects)
	{
		$CPUNumbers += 1
	}

	#Ajoute à l'objet PowerShell précédemment crée, le nombre total de CPU du DC actuellement requêté
	$Line | Add-Member -MemberType NoteProperty -Name "CPU_total" -Value $CPUNumbers

	#Récupére l'espace disque du DC actuellement requêté
	$WMILogicalDiskObjects = Get-WMIObject -Class Win32_LogicalDisk -ComputerName $ServerToGetConfiguration | Select-Object PSComputerName, DeviceID, FileSystem, MaximumComponentLength, Size, FreeSpace

	#Boucle qui va parcourir chaque disque du DC requêté et ajoute à l'objet PowerShell précédemment crée, l'espace disque total et restant de C: et l'affiche en GB
	foreach ($WMILogicalDiskObject in $WMILogicalDiskObjects)
	{
		if ($WMILogicalDiskObject.DeviceID -eq "C:")
		{
			$Line | Add-Member -MemberType NoteProperty -Name "Disk_size(GB)" -Value ([math]::truncate(($WMILogicalDiskObject.Size)/1GB))
			$Line | Add-Member -MemberType NoteProperty -Name "Disk_free(GB)" -Value ([math]::truncate(($WMILogicalDiskObject.FreeSpace)/1GB))
		}
	}

	#Récupére les RAM du DC actuellement requêté
	$WMIPhysicalMemoryObjects = Get-WmiObject -Class Win32_PhysicalMemory -ComputerName $ServerToGetConfiguration | Select-Object PSComputerName, BankLabel, Capacity, Manufacturer

	#Boucle qui va additionner l'ensemble des RAM du DC requêté pour obtenir le nombre total de RAM
	$RAMnumbers = 0 
	foreach ($WMIPhysicalMemoryObject in $WMIPhysicalMemoryObjects)
	{
		$RAMnumbers += $WMIPhysicalMemoryObject.Capacity
	}
	
	#Ajoute à l'objet PowerShell précédemment crée, le nombre total de RAM du DC actuellement requêté
	$Line | Add-Member -MemberType NoteProperty -Name "Memory(MB)" -Value ([math]::truncate(($RAMnumbers)/1MB))

	#Ajoute à la variable globale qui contient l'ensemble des configuration des DC, l'objet PowerShell précédemment crée de l'itération courante
	$Array += $Line

	#Supprime les valeurs des variables propres au DC actuellement requêté
	Clear-Variable Line, WMIComputerSystemObject, WMINetworkAdapterConfigurationObjects, WMIOperatingSystemObject, CPUNumbers, WMILogicalDiskObjects, WMIPhysicalMemoryObject
}

#Affiche sous forme de liste l'ensemble des DC avec leurs configurations
$Array

<#Exemple d'affichage
HostName        : DC01.customer.intern
Domain          : customer.intern
IPAddress       : 192.168.1.50
OperatingSystem : Microsoft Windows Server 2019 Standard
CPU_total       : 4
Disk_size(GB)   : 50
Disk_free(GB)   : 30
Memory(MB)      : 16384

HostName        : DC02.technical.intern
Domain          : technical.intern
IPAddress       : 192.168.1.51
OperatingSystem : Microsoft Windows Server 2022 Standard
CPU_total       : 4
Disk_size(GB)   : 100
Disk_free(GB)   : 60
Memory(MB)      : 16384
#>

 

Azure AD - Déployer le passwordless avec Microsoft Authenticator

Une présentation du passwordless a été faite dans ce post : Azure AD - Présentation du passwordless

Microsoft Authenticator est un logiciel pratique qui permet à la fois de faire du l'authentification multifacteur, mais également de faire du passwordless. Cet article explique comment préparer son environnement pour pouvoir se connecter en passwordless avec Microsoft Authenticator.

Les configurations ci-après sont réalisées avec un compte Global Administrator (GA).

Désactiver le MFA historique

La méthode moderne de faire du MFA est via l'accès conditionnel Azure, il est nécessaire de désactiver le MFA historique pour éviter d'avoir des conflits.

Se connecter successivement à portal.azure.com > Cliquer sur l'icône des 3 traits horizontaux > Azure Active Directory > Users >  Per-user MFA

Pour chaque utilisateur qui doit pouvoir faire du passwordless, il faut désactiver le MFA

 

Combiner les informations de sécurité SSPR et MFA

Les étapes sont décrites dans l'article : Azure - Combiner les informations de sécurité SSPR et MFA

 

(Optionnel) Activer le MFA via accès conditionnel Azure

Active le MFA n'est pas obligatoire pour l'authentification via Microsoft Authenticator mais, est fortement recommandé.

Pour créer un nouvel accès conditionnel Azure ou conditional access (CA), se connecter successivement à portal.azure.com > Cliquer sur l'icône des 3 traits horizontaux > Azure Active Directory > Security > Policies > New policy

 

Dans Users choisir les utilisateurs qui doivent faire du passwordless, attention de toujours garder quelques comptes de bris de glace qui ne sont pas concernés par la politique

Dans Cloud apps or actions, cocher All cloud apps

Dans Conditions, uniquement, s'il faut exclure certains utilisateurs en se basant sur des critères prédéfinis

Dans Enable policy choisir On

 

Dans Grant, cocher Grant access et Require multifactor authenticator puis cliquer sur Select

Enfin cliquer sur Create

Dorénavant, les utilisateurs configurés dans la CA devront s'authentifier en MFA. Lors de la première connexion, il leur sera demandé d'enregistrer des facteurs d'authentifications, Microsoft Authenticator étant plus que recommandé sans quoi l'authentification passwordless ne pourra pas se faire.

 

Identifier les domaines fédérés et planifier la migration de l'authentification vers Azure

Dans le cas où l'environnement disposerait d'une ferme ADFS, les domaines fédérés ne peuvent pas être utilisés pour faire du passwordless.

En fonction de comment est gérer l'authentification des utilisateurs OnPremises versus Azure, les actions à réaliser peuvent être plus ou moins chronophages.

Se référer à la documentation Microsoft : Migrate from federation to cloud authentication

Il est donc nécessaire de réaliser cette transition de l'authentification vers le cloud Azure pour pouvoir faire du passwordless.

 

Configurer l'authentification passwordless via Microsoft Authenticator

Se connecter successivement à portal.azure.com > Cliquer sur l'icône des 3 traits horizontaux > Azure Active Directory > Security > Authentication Methods > Microsoft Authenticator

Dans Enable and Target, activer Enable

Dans Include, choisir Select groups puis choisir le groupe qui contient les utilisateurs qu'il faut déployer passwordless, ici le groupe s'appelle Passwordless-test
Dans Authentication mode choisir Any, any inclut la possibilité de faire du passwordless

Cliquer sur Save

 

Cela conclut la configuration de l'authentification passwordless via Microsoft Authenticator

 

Configuration par l'utilisateur final la possibilité de faire de l'authentification passwordless avec Microsoft Authenticator

Chaque utilisateur souhaitant s'authentifier en passwordless doit activer l'option dans son application Microsoft Authenticator

Une fois sur le compte d'entreprise, cliquer sur Enable phone sign-in

Azure AD - Présentation du passwordless

L'importance du passwordless

Posséder une bonne stratégie de mot de passe demeure essentiel, mais ne permet pas de s'affranchir du maillon le plus à risque de la chaîne d'authentification à savoir l'utilisateur. Cet utilisateur peut être invité de façon frauduleuse à fournir ses identifiants de connexions à un pirate informatique, c'est ce que l'on appelle le phising.

Le passwordless consiste à fournir à l'utilisateur des méthodes d'authentifications qui ne se reposent pas sur l'utilisation d'un mot de passe.

Augmenter la sécurité est souvent lié à plus de contraintes, c'est le cas par exemple pour le MFA ou multi-factor authentification qui nécessite une étape supplémentaire lors de la connexion.

Le passwordless, en outre de fournir un meilleur niveau de sécurité que le MFA traditionnel permet de réduire directement ou indirectement ces impératifs lourds de connexion lourd intrinséque au MFA

Un autre avantage du passwordless Azure est sa liberté d'implémentation, il est possible d'autoriser les utilisateurs à utiliser en conjonction leurs identifiants standards et le passwordless. Cela permet en termes de déploiement d'avoir une meilleure adhésion des utilisateurs au passwordless et d'identifier en amont les éventuels problèmes avant de restreindre l'utilisation des mots de passe.

 

Les solutions pour faire du passwodless via Azure

  • L'application Microsoft Authenticator, disponible sur Android et iOS, prisée pour l'authentification MFA, permet également de faire du passwordless. Concrètement, lorsqu'un utilisateur tente de se connecter à une application, son mot de passe ne lui sera pas demandé, mais une notification apparaîtra dans son application Microsoft Authenticator.

 

  • Windows Hello for Business, une solution implémentée dans les systèmes d'exploitation Windows 10 et postérieur, propose à l'utilisateur d'utiliser un code PIN ou des informations biométriques pour se connecter. Le code PIN à l'instar du mot de passe traditionnel ne peut pas être utilisé sur un autre équipement que le PC sur lequel il a été configuré et n'est pas transmis à un autre équipement ou application.

 

  • Une clé de sécurité FIDO2, aussi courament appelée token, est un équipement physique qui s'apparente à une clé USB, l'utilisateur lorsqu'il veut se connecter doit brancher sa clé FIDO2 à son PC et entrer le code PIN pour débloquer la clé.

 

Passwodless vs MFA

L'augmentation des attaques informatiques sur les dernières années à pousser les entreprises à améliorer la sécurité de leur système d'information. Nombreuses d'entre elles ont donc décidé d'implémenter du MFA ou multi-factor authentification.
Le MFA dans son implémentation la plus fréquente consiste à demander en plus du jeu identifiant et mot de passe pour l'authentification d'un utilisateur, un deuxième moyen à l'utilisateur de prouver son identité, par exemple un code d'authentification reçu par SMS.

L'obtention de certifications demande l'implémentation de solutions de MFA, on est donc en droit de se demander si le passwordless est de l'authentification MFA ?

Le MFA consiste à utiliser à minima 2 des 3 éléments suivants :

  • Ce que je sais, par exemple un mot de passe ou un code PIN
  • Ce que je possède, par exemple une clé FIDO2 ou un téléphone portable
  • Ce que je suis, ce qui est lié a de la biométrie, par exemple un iris, un visage ou une empreinte

 

L'application Microsoft Authenticator utilise donc les facteurs : ce que je sais et ce que je posséde

Windows Hello For Business, utilise donc une combinaison des 3 facteurs en fonction de l'authentification choisie. Dans le cas de l'utilisation du code PIN, un argument serait que seul le facteur ce que je sais entre en jeu, cependant le PC qui est utilisé pour l'authentification du passwordless doit être enregistrée dans le tenant Azure de l'organisation. Le PC peut donc être considéré de facto comme le facteur ce que je posséde.

La clé de sécurité FIDO2 utilise donc les 2 facteurs : ce que je sais et ce que je possède

 

Le périmètre d'application du passwordless

Le passordless Azure comme son nom l'indique est fondamentalment lié à Azure, il est donc nécessaire que l'application qui demande à l'utilisateur de s'authentifier soit compatible avec les méthodes d'authentification fortes d'Azure.

Pour la connexion aux portails Azure et Office 365, c'est nativement le cas.

Pour l'ouverture d'une session Windows, des pré-requis doivent être satisfaits et des configurations réalisées

Pour les applications tierces ou développées en interne, l'authentification doit supporter des méthodes d'authentification modernes Azure tel que le SSO

 

Pour aller plus loin

Définir sa stratégie de déploiement passwordless : Article officiel de Microsoft

[Exchange Hybride] Automapping Mappage automatique ne fonctionne pas comme prévu

Le Mappage automatique permet à Outlook d’ouvrir automatiquement toutes les boîtes aux lettres auxquelles un utilisateur a les droits d'accès complet (le mappage automatique fonctionne uniquement pour les utilisateurs individuels disposant des autorisations appropriées et ne fonctionne pour aucun type de groupe.)

La fonctionnalité d’auto-mappage automatique de boîte aux lettres est NON prise en charge dans les environnements hybrides. Au début, les migrations Exchange hybrides ne prenaient en charge aucune sorte d’autorisations de boîte aux lettres entre forêts. Après quelques années, Microsoft a rendu possible le fonctionnement des autorisations d'accès complet.

Lorsque les autorisations d'accès complet sont attribuées avant le déplacement --> Tout continue de fonctionner. Toutefois, la configuration des autorisations d’accès complet après la migration d’une boîte aux lettres ne configurera pas le mappage automatique. Il ne s'agit pas d'un problème  d'autorisations mais plutôt au niveau des attributs de mappage automatique.

Les deux attributs Active Directory qui doivent être mis à jour pour que le mappage automatique fonctionne sont : msExchDelegateListLink (La boîte aux lettres autorisée) et  msExchDelegateListBL (Utilisateur bénéficiant des autorisations)

1. Ajouter tout d'abord des autorisations permettant à un user Online d’accéder à la boîte aux lettres onpremise. Cela se fait avec l’applet de commande Add-MailboxPermission dans Exchange Online. 

PS C:\>Add-MailboxPermission -Identity sales@contoso.com -Utilisateur nathan@contoso.com -AccessRights FullAccess -InheritanceType All

2. Exécuter par la suite la commande Set-ADUser Onprem. 

PS C:\>Set-ADUser -Identity nathan@mcsmlab.com -Add@ {msExchDelegateListLink/BL=sales@contoso.com}

Une fois que ces actions ont été effectuées, AAD Connect synchronisera tous les attributs appropriés dans Azure AD et le mappage automatique fonctionnera comme prévu.

Script - Powershell et SCCM Query pour determiner des listes de roles applicatifs

Le script ci-dessous utilise une requete SQL SCCM issue d'un precedent post, enrichie d'une autre vue, pour determiner, a partir du resultat de la requete, des roles applicatifs de serveurs, et en generer des listes de serveurs correspondants.

D'autres roles peuvent etre ajouté dans la section "Sous-Regroupements", pour enrichir les listes de roles.

NB: La variable $Result qui est le resultat direct de la requete SQL contiens tout les éléments (exe, add-remove-program, services), par serveur, permettant de determiner d'autres roles.

 

########################################################################################################
### REQUETE LA BASE SQL DE SCCM POUR OBTENIR LA LISTE DES APPLICATIONS ET EXECUTABLES DES ASSETS SERVEURS.
### EN FONCTION DES RESULTATS, GENERATION DE LISTES DE SERVEURS PAR ROLES APPLICATIFS (IIS,SQL ...).
### EXPORT DES RESULTAT EN FICHIER CSV  #####
######################################################################################################## 


<# 

    .SYNOPSIS 
        REQUETE LA BASE SQL DE SCCM POUR OBTENIR LA LISTE DES APPLICATIONS ET EXECUTABLES DES ASSETS SERVEURS.
        EN FONCTION DES RESULTATS, GENERATION DE LISTES DE SERVEURS PAR ROLES APPLICATIFS (IIS,SQL ...).
        EXPORT DU RESULTAT EN FICHIER CSV.

    .PARAMETER  
        SQLInstance : Instance SQL
        SQLDB : Instance SQL
        SQLQuery : Requete SQL
        ExportFolder : Dossier d'export du fichier CSV
        LogFolder : Chemin du dossier où creer le log du script

 
    .EXAMPLE 
     .\SCCM_Roles_And_Apps.ps1 -SQLInstance MyServer -SQLDB CM_BIM -ExportFolder D:\ExportCSV -LogFolder D:\ExportCSV
#>


[CmdletBinding()]
param(
[Parameter(Mandatory=$true,HelpMessage="Instance SQL")]
[string]$SQLInstance,

[Parameter(Mandatory=$true,HelpMessage="Base SQL")]
[string]$SQLDB,

[Parameter(Mandatory=$false,HelpMessage="Requete SQL")] 
[string]$SQLQuery= $("/* --- SERVER SOFTWARES, EXECUTABLES, AND SERVICES(NT) INVENTORY ---  
 NB: UNION ENTRE LES VUES:
	 [v_GS_INSTALLED_SOFTWARE_CATEGORIZED] 
	 [v_GS_INSTALLED_EXECUTABLE]
	 [v_ADD_REMOVE_PROGRAMS]
	 [v_GS_SERVICE]

	       
 NB: DES COLONNES SONT CREES ET POSITIONNEE A NULL POUR POUVOIR EFFECTUER LE UNION. (Meme nombre de colonnes) 

L'UNION ENTRE LES VUES EST REGROUPEE DANS UNE TABLE 'TAB' (CLAUSE 'WITH').
LA REQUETE FINALE EST EXECUTEE SUR LA TABLE 'TAB'


v_GS_INSTALLED_SOFTWARE_CATEGORIZED
Répertorie des informations sur les applications logicielles installées sur Configuration Manager clients trouvés via Asset Intelligence. 
Cette vue contient les informations contenues dans le v_GS_INSTALLED_SOFTWARE afficher et joint plusieurs autres tables pour fournir des détails supplémentaires sur les logiciels installés.

v_GS_INSTALLED_EXECUTABLE
Répertorie des informations sur les fichiers exécutables de l’application logicielle installée sur Configuration Manager clients trouvés via Asset Intelligence.

[v_ADD_REMOVE_PROGRAMS]
Combination of 32 and 64 bit programs data in 'Add Remove Programs'

[v_GS_SERVICE]
Services NT des Machines Windows

*/



DECLARE @CollectionID as Varchar(8)
SET @CollectionID = 'SMS00001' --Specify the collection ID
;


WITH TAB (
ResourceID
,ProductCode
,Machine_Name
,OS_Name
,Publisher
,NormalizedPublisher
,ExecutableName
,ServiceName
,ServicePath
,Service_Description
,Service_StartMode
,Service_StartName
,ProductName
,AddRemove_Name
,NormalizedName
,FamilyName
,CategoryName
,ProductVersion
,InstallDate
,Soft_Autostart
,EXE_FilePath
,EXE_Description
,EXE_FileVersion
)

AS (




SELECT 
SYST.ResourceID,
UPPER(SOFT.ProductCode0) as ProductCode,
SYST.Name0 as Machine_Name,

-- OS Info --
OS.Caption0 as OS_Name,

-- SOFT INFO --
SOFT.Publisher0 as Publisher
,SOFT.NormalizedPublisher
,NULL as ExecutableName
,NULL as ServiceName
,NULL as ServicePath
,NULL as Service_StartMode
,NULL as Service_StartName
,NULL as Service_Description
,SOFT.ProductName0 as ProductName
,NULL as AddRemove_Name,
SOFT.NormalizedName,
SOFT.FamilyName,
SOFT.CategoryName,
SOFT.ProductVersion0 as ProductVersion,


SOFT.InstallDate0 as InstallDate,


CASE 
	WHEN AUTOSTART_SOFT.Product0 IS NULL THEN 'NO'
	ELSE 'YES'
	END as Soft_Autostart,

NULL as EXE_FilePath,
NULL as EXE_Description,
NULL as EXE_FileVersion


FROM [dbo].[v_GS_INSTALLED_SOFTWARE_CATEGORIZED] SOFT
FULL JOIN v_R_System SYST on SYST.ResourceID = SOFT.ResourceID
FULL JOIN [dbo].[v_GS_OPERATING_SYSTEM] OS on OS.ResourceID = SYST.ResourceID
FULL JOIN [dbo].[v_GS_AUTOSTART_SOFTWARE] AUTOSTART_SOFT on AUTOSTART_SOFT.Product0 = SOFT.ProductName0   -- TO MAKE RELATION WITH AUTO-START SOFTWARE
FULL JOIN v_FullCollectionMembership on (v_FullCollectionMembership.ResourceID = SYST.ResourceID)

WHERE v_FullCollectionMembership.CollectionID = @CollectionID


  
UNION 
 

SELECT 
  

SYST.ResourceID,
UPPER(EXE.ProductCode0) as ProductCode,
SYST.Name0 as 'Machine Name'

-- OS Info --
,OS.Caption0 as OS_Name

,EXE.Publisher0 as Publisher
,NULL as NormalizedPublisher
,EXE.ExecutableName0 as ExecutableName
,NULL as ServiceName
,NULL as ServicePath
,NULL as Service_StartMode
,NULL as Service_StartName
,NULL as Service_Description
,EXE.Product0 as ProductName
,NULL as AddRemove_Name
,NULL as NormalizedName
,NULL as FamilyName
,NULL as CategoryName 
,EXE.ProductVersion0 AS ProductVersion
,NULL as InstallDate
,NULL as Soft_Autostart

,EXE.InstalledFilePath0 as EXE_FilePath
,EXE.Description0 as EXE_Description
,EXE.FileVersion0 AS EXE_FileVersion


FROM [dbo].[v_GS_INSTALLED_EXECUTABLE] EXE
  
  FULL JOIN v_R_System SYST on SYST.ResourceID = EXE.ResourceID
  FULL JOIN [dbo].[v_GS_OPERATING_SYSTEM] OS on OS.ResourceID = SYST.ResourceID
  FULL JOIN v_FullCollectionMembership on (v_FullCollectionMembership.ResourceID = SYST.ResourceID)
  --FULL JOIN [dbo].[v_GS_SERVICE] SERVICE_NT on SERVICE_NT.ResourceID = SYST.ResourceID
 
 WHERE v_FullCollectionMembership.CollectionID = @CollectionID
 
  
  
UNION


SELECT
ARP.ResourceID
,UPPER(ARP.ProdID0) as ProductCode
,SYST.Name0 as 'Machine Name'
-- OS Info --
,OS.Caption0 as OS_Name
,ARP.Publisher0 as Publisher
,NULL as NormalizedPublisher
,NULL as ExecutableName
,NULL as ServiceName
,NULL as ServicePath
,NULL as Service_StartMode
,NULL as Service_StartName
,NULL as Service_Description
,NULL as ProductName
,ARP.DisplayName0 as AddRemove_Name
,NULL as NormalizedName
,NULL as FamilyName
,NULL as CategoryName 
,ARP.Version0 AS ProductVersion 

,CASE
WHEN ISDATE(ARP.InstallDate0) <> 0 THEN CONVERT(date,ARP.InstallDate0)
WHEN ISDATE(ARP.InstallDate0) = 0 THEN NULL
END AS InstallDate

,NULL as Soft_Autostart
,NULL as EXE_FilePath
,NULL as EXE_Description
,NULL as EXE_FileVersion

FROM [dbo].[v_ADD_REMOVE_PROGRAMS] ARP
FULL JOIN v_R_System SYST on SYST.ResourceID = ARP.ResourceID  
FULL JOIN v_FullCollectionMembership on (v_FullCollectionMembership.ResourceID = SYST.ResourceID)
--FULL JOIN [dbo].[v_GS_SERVICE] SERVICE_NT on SERVICE_NT.ResourceID = SYST.ResourceID
INNER JOIN [dbo].[v_GS_OPERATING_SYSTEM] OS on OS.ResourceID = SYST.ResourceID  

WHERE v_FullCollectionMembership.CollectionID = @CollectionID 


UNION 
 

SELECT 

SERVICE_NT.ResourceID,
NULL as ProductCode,
SYST.Name0 as 'Machine Name'

-- OS Info --
,OS.Caption0 as OS_Name

,NULL as Publisher
,NULL as NormalizedPublisher
,NULL as ExecutableName
,SERVICE_NT.Name0 as ServiceName
,SERVICE_NT.PathName0 as ServicePath
,SERVICE_NT.Description0 as Service_Description
,SERVICE_NT.StartMode0 as Service_StartMode
,SERVICE_NT.StartName0 as Service_StartName
,NULL as ProductName
,NULL as AddRemove_Name
,NULL as NormalizedName
,NULL as FamilyName
,NULL as CategoryName 
,NULL as ProductVersion
,NULL as InstallDate
,NULL as Soft_Autostart
,NULL as EXE_FilePath
,NULL as EXE_Description
,NULL AS FileVersion


FROM [dbo].[v_GS_SERVICE] as SERVICE_NT
  
  FULL JOIN v_R_System SYST on SYST.ResourceID = SERVICE_NT.ResourceID
  FULL JOIN [dbo].[v_GS_OPERATING_SYSTEM] OS on OS.ResourceID = SYST.ResourceID
  FULL JOIN v_FullCollectionMembership on (v_FullCollectionMembership.ResourceID = SYST.ResourceID)
 
 WHERE v_FullCollectionMembership.CollectionID = @CollectionID

 
  
  ) 
  

 
 SELECT  DISTINCT 

TAB.ResourceID
,TAB.Machine_Name
,TAB.OS_Name

/*-- EXEMPLES DE COLONNE CUSTOM SELON DES VALEURS
,CASE

	WHEN (TAB.ServiceName = 'W3SVC' and TAB.Service_StartMode = 'Auto') THEN 'YES'
	ELSE NULL
	END AS 'IS_IIS'
	
,CASE

	WHEN (TAB.AddRemove_Name like 'SQL Server%Database Engine Services') THEN 'YES'
	ELSE NULL
	END AS 'IS_MSSQL_DBENGINE'  


,CASE

	WHEN (TAB.AddRemove_Name like 'SQL Server%Reporting Services') THEN 'YES'
	ELSE NULL
	END AS 'IS_MSSQL_RS'  
*/

,TAB.Publisher
,TAB.NormalizedPublisher
,TAB.ExecutableName
,TAB.ServiceName
,TAB.ServicePath
,TAB.Service_Description
,TAB.Service_StartMode
,TAB.Service_StartName
,TAB.ProductName
,TAB.ProductCode
,TAB.AddRemove_Name
,TAB.NormalizedName
,TAB.FamilyName
,TAB.CategoryName





,CASE
	
	WHEN TAB.ProductVersion like '[0-9][.][0-9][.][0-9][-]%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '[0-9][.][0-9][.][0-9][a-z]' THEN SUBSTRING(TAB.ProductVersion,0,5)
	WHEN TAB.ProductVersion like '[0-9][.][0-9][.][0-9][a-z]%' THEN SUBSTRING(TAB.ProductVersion,0,5)
	WHEN TAB.ProductVersion like '[0-9][.][0-9][.][0-9][0-9][0-9][0-9][a-z]%' THEN SUBSTRING(TAB.ProductVersion,0,5)
	WHEN TAB.ProductVersion like '[0-9][.][0-9][.][0-9][.]%[a-z]%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '[0-9][0-9][.][0-9][.]%[a-z]%' AND TAB.EXE_FileVersion IS NOT NULL THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '[0-9][0-9][.][0-9][0-9][.][a-z]%' AND TAB.EXE_FileVersion IS NULL THEN SUBSTRING(TAB.ProductVersion,0,5)
	WHEN TAB.ProductVersion like '[0-9][.][0-9][0-9][.][a-zA-Z]%' AND TAB.EXE_FileVersion IS NULL THEN SUBSTRING(TAB.ProductVersion,0,4)
	WHEN TAB.ProductVersion like '[0-9][.][0-9][0-9][.][0-9][0-9][0-9][.][0-9]%[0-9][0-9][.][0-9][0-9]%)' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '[0-9][.][0-9][0-9][.][0-9][0-9][0-9][0-9][.][0-9][0-9][0-9]%[0-9][0-9][.][0-9][0-9]%)' THEN TAB.EXE_FileVersion
	
	WHEN TAB.ProductVersion = 'Unidentified build' THEN NULL
	WHEN TAB.ProductVersion like '%.FR' THEN REPLACE(TAB.ProductVersion,'.FR','')
	WHEN TAB.ProductVersion like '%.RR' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%Release%' THEN REPLACE(TAB.ProductVersion,'Release','')
	WHEN TAB.ProductVersion like '%bet%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%build%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%Eagle%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%Impala%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%Summer%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%sum%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like 'S%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%c40%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%b5%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%59d%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%ffbc%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%2d6%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%7d7%' THEN TAB.EXE_FileVersion
	
	WHEN TAB.ProductVersion like '%Unversioned%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%rd_store_sdk%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion like '%[/]%' THEN SUBSTRING(TAB.ProductVersion,LEN(SUBSTRING(TAB.ProductVersion,0,LEN(TAB.ProductVersion) - CHARINDEX(' ',TAB.ProductVersion)+1))+1, LEN(TAB.ProductVersion) - LEN(SUBSTRING(TAB.ProductVersion,0,LEN(TAB.ProductVersion) - CHARINDEX(' ',TAB.ProductVersion))))
	WHEN TAB.ProductVersion like '%BLD%' THEN SUBSTRING(TAB.ProductVersion,0,5)
	WHEN TAB.ProductVersion like '%PQ%' THEN TAB.EXE_FileVersion
	WHEN TAB.ProductVersion = 'sonicmf.exe' THEN NULL
	WHEN TAB.ProductVersion = 'Unidentified build' THEN NULL
	WHEN TAB.ProductVersion like '%A%' THEN REPLACE(TAB.ProductVersion,'A','')
	WHEN TAB.ProductVersion like 'xxx%' THEN NULL
	WHEN TAB.ProductVersion like '%c' THEN REPLACE(TAB.ProductVersion,'c','')
	WHEN TAB.ProductVersion like '%k' THEN REPLACE(TAB.ProductVersion,'k','')
	WHEN TAB.ProductVersion like '%g' THEN REPLACE(TAB.ProductVersion,'g','')
	WHEN TAB.ProductVersion like '%.windows%' THEN SUBSTRING(TAB.ProductVersion,0,6)
	WHEN TAB.ProductVersion like '%beta%' THEN REPLACE(TAB.ProductVersion,'beta','')
	WHEN TAB.ProductVersion like '%Release%' THEN REPLACE(TAB.ProductVersion,'Release','')
	WHEN TAB.ProductVersion like '%NotilusWeb%' THEN REPLACE(TAB.ProductVersion,'NotilusWeb','')
	WHEN TAB.ProductVersion like '%WUG%' THEN REPLACE(TAB.ProductVersion,'WUG','')
	WHEN TAB.ProductVersion like '%[ ]%' THEN REPLACE(TAB.ProductVersion,' ','')
	
	WHEN TAB.EXE_Description = 'Windows Admin Center Windows Service' THEN TAB.EXE_FileVersion
	WHEN TAB.EXE_Description like '%ServiceHub.Host.CLR%' THEN TAB.EXE_FileVersion
	WHEN TAB.EXE_Description like '%Microsoft.ServiceHub.Controller%' THEN TAB.EXE_FileVersion
	WHEN TAB.EXE_Description like '%Microsoft Mashup%' THEN TAB.EXE_FileVersion
	WHEN TAB.EXE_Description like '%Element programu Soneta%' THEN TAB.EXE_FileVersion

		
	
	
	ELSE TAB.ProductVersion
	END AS ProductVersion


,TAB.InstallDate
,TAB.Soft_Autostart
,TAB.EXE_FilePath
,TAB.EXE_Description


,CASE
	
	WHEN TAB.EXE_FileVersion like '%build%' THEN NULL
	WHEN TAB.EXE_FileVersion like '%beta%' THEN REPLACE(TAB.EXE_FileVersion,'beta','')
	WHEN TAB.EXE_FileVersion like '%Release%' THEN REPLACE(TAB.EXE_FileVersion,'Release','')
	WHEN TAB.EXE_FileVersion like '%[ ]%' THEN REPLACE(TAB.EXE_FileVersion,' ','')
	--WHEN TAB.EXE_FileVersion like '%[,]%' THEN REPLACE(TAB.EXE_FileVersion,',','.')
	WHEN TAB.EXE_FileVersion like '%[ ]%' THEN SUBSTRING(TAB.EXE_FileVersion,0, LEN(TAB.EXE_FileVersion) - LEN(SUBSTRING(TAB.EXE_FileVersion,0,LEN(TAB.EXE_FileVersion) - CHARINDEX(' ',TAB.EXE_FileVersion))))
	WHEN TAB.EXE_FileVersion = 'sonicmf.exe' THEN NULL
	WHEN TAB.EXE_FileVersion like '%A%' THEN REPLACE(TAB.EXE_FileVersion,'A','')
	WHEN TAB.EXE_FileVersion like 'x%' THEN NULL
	WHEN TAB.EXE_FileVersion like '%c' THEN REPLACE(TAB.EXE_FileVersion,'c','')
	WHEN TAB.EXE_FileVersion like '%g' THEN REPLACE(TAB.EXE_FileVersion,'g','')
	WHEN TAB.EXE_FileVersion like '%WUG%' THEN REPLACE(TAB.EXE_FileVersion,'WUG','')
	
	
	ELSE TAB.EXE_FileVersion
	END AS EXE_FileVersion

 
 FROM  TAB
 
 WHERE TAB.OS_Name like '%Server%' -- UNIQUEMENT LES OS SERVEURS

"),


[Parameter(Mandatory=$true,HelpMessage="Dossier d'export du fichier CSV")]
[string]$ExportFolder,

[Parameter(Mandatory=$true,HelpMessage="Chemin du dossier où creer le log du script")] 
[string]$LogFolder

)


# SCRIPT NAME
$ScriptName = "SCCM_Roles_And_Apps.ps1"


# LogName = ScriptName without extension
$Log = $ScriptName.Split('.')[0]


### FUNCTIONS

# Function Write-Log



function Write-Log 
{ 
    <# 
    .SYNOPSIS 
        This function creates or appends a line to a log file. 
 
    .PARAMETER  Message 
        The message parameter is the log message you'd like to record to the log file. 
 
    .EXAMPLE 
        PS C:\> Write-Log -Message 'Value1' 
        This example shows how to call the Write-Log function with named parameters. 
    #> 
    [CmdletBinding()] 
    param ( 
        [Parameter(Mandatory)] 
        [string]$Message,
        [Parameter(Mandatory)] 
        [string]$LogPath, 
        [Parameter(Mandatory)] 
        [string]$LogName
        
    ) 
     
    try 
    { 
        $DateTime = Get-Date -Format ‘MM-dd-yy HH:mm:ss’ 
        Add-Content -Value "$DateTime # $Message" -Path "$LogPath\$LogName.log" 
    } 
    catch 
    { 
        Write-Error $_.Exception.Message 
    } 
} 


Function GetSQLData {

<# 
    .SYNOPSIS 
        This function query SQL Database and get Data 
 
    .PARAMETER  
        SQLInstance: Instance SQL.
        SQLDB: Base SQL.
        SQLQuery: Requete SQL.

 
    .EXAMPLE 
        GetSQLData -SQLInstance "MyInstance" -SQLDB "MyDB" -SQLQuery "Select * from MyView"
    #> 


[CmdletBinding()] 
    Param( 
        [Parameter(Mandatory=$false)] 
        [string[]] 
        $SQLInstance,
        [Parameter(Mandatory=$false)] 
        [string[]] 
        $SQLDB,
        [Parameter(Mandatory=$false)] 
        [string[]] 
        $SQLQuery
        
        )

$connectionString = "Data Source=$SQLInstance;"+"Integrated Security=SSPI;"+"Initial Catalog=$SQLDB"

$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
$command = new-object system.data.sqlclient.sqlcommand($SQLQuery,$connection)
$connection.Open()

$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataSet) | Out-Null

$connection.Close()
$dataSet.Tables

}






# EXECUTE Query ($SQLQuery)
    Write-Log -Message "Execution of GetSQLData on $SQLDB" -LogPath $LogFolder -LogName $Log
    $Result = 
    Try {
        GetSQLData -SQLInstance $SQLInstance -SQLDB $SQLDB -SQLQuery $SQLQuery
        }
    Catch
        {
        $Message = "ERROR DURING EXECUTION OF QUERY"
        Write-Host -F Red $Message
        Write-Log -Message "$Message - $($Error[0].Exception)" -LogPath $LogFolder -LogName $Log
        Exit 1
        }


########################################
# SOUS-REGROUPEMENTS
########################################


# All IIS
$AllIIS = $Result.rows.Where({$_.ServiceName -eq 'W3SVC' -and $_.Service_StartMode -eq 'Auto'}) | select Machine_Name | group Machine_Name | select name -ExpandProperty name

# All SQLDBEngine
$AllSQLDBEngine = $Result.rows.Where({$_.AddRemove_Name -like 'SQL Server*' -and $_.AddRemove_Name -like  '*Database Engine Services'}) | select Machine_Name | group Machine_Name | select name -ExpandProperty name

# All SQL Reporting Services
$AllSQLRS = $Result.rows.Where({$_.AddRemove_Name -like 'SQL Server*'`
    -and $_.AddRemove_Name -like  '*Reporting Services'`
    -and $_.AddRemove_Name -notlike '*Management Studio*'`
    -and $_.AddRemove_Name -notlike '*Data Tools*'`
        
    }) | select Machine_Name | group Machine_Name | select name -ExpandProperty name



# All Citrix Servers
$AllCitrixSrv = $Result.rows.Where({$_.ServiceName -eq 'BrokerAgent' -or $_.ServiceName -eq 'CitrixStorefront' }) | select Machine_Name | group Machine_Name | select name -ExpandProperty name


# All Apache Tomcat Servers
$AllTomcatSrv = $Result.rows.Where({$_.AddRemove_Name -like 'Apache Tomcat*'}) | select Machine_Name | group Machine_Name | select name -ExpandProperty name




# EXPORTS TO TXT FILES

$AllIIS | sort |  Out-File -FilePath "$ExportFolder\All_IIS.txt" -Force

$AllSQLDBEngine | sort |  Out-File -FilePath "$ExportFolder\AllSQLDBEngine.txt" -Force

$AllSQLRS | sort |  Out-File -FilePath "$ExportFolder\AllSQLRS.txt" -Force

$AllCitrixSrv | sort |  Out-File -FilePath "$ExportFolder\AllCitrixSrv.txt" -Force




# DISPLAY SUCCESS
$Message = "--- EXECUTION OK ---"
Write-Host -F Green $Message
Write-Log -Message $Message -LogPath $LogFolder -LogName $Log


 

MECM : Erreur lors de la réinstallation du Reporting Services Point

Erreur :

J'ai décidé de réinstaller le rôle Reporting de MECM.

Dans le log "srsrpsetup.log" je vois ça :

Deleting \\?\L:\SMS_SRSRP, FAILED, Win32 Error = 2

Cannot delete old installation directory L:\SMS_SRSRP. Error Code=2. Installation will continue.

Fatal MSI Error - srsrp.msi could not be installed.

 

Solution :

  1. Désinstaller manuellement srsrp en utilisant le srsrp.msi --> faire un clic droit sur le msi et choisir l'option désinstaller
  2. Redémarrer le composant "MECM SMS_SITE_COMPONENT_MANAGER" qui va essayer une réinstallation de srsrp.msi

MECM : Utiliser CMPivot pour filtrer un EventID spécifique sur un regroupement de machines

Besoin :

Filtrer un EventID spécifique pour un intervalle de temps bien défini sur un regroupement de machines.

 

Solution :

Cela est possible en utilisant CMPivot de MECM.

CMPivot permet de sortir toutes les occurrences d'un EventID sur une période définie sur le regroupement de machines souhaitée.

Ci-dessous une requête CMPivot pour filtrer l'EventID 1034 de type Application sur une période de 365 jours :

EventLog('Application',365d) | where EventID == 1034

Compactage de l'.ost

Contexte : Le fichier de donnée Outlook atteint sa masse critique et a pour conséquence des lenteurs et bugs dès l'ouverture de la messagerie.

 

Pour réduire le poids du fichier .ost sans avoir à télécharger à nouveau la BAL en supprimant ce fichier.

Ouvrir Outlook >Fichier >paramètre de compte >sélection de la boite >paramètres supplémentaires >paramètre du fichier de donnée Outlook >bouton Compresser

Modifier

Paramètres supplémentaires

Compresser

 
 

 

Windows Admin Center – Analyseur de Performance (Perfmon)

Windows Admin center propose bien sur entre autres l’accès a l’analyseur de performance (Perfmon) de la machine gérée à distance.

 

Par défaut, aucun compteur n’est affiché

Cliquer sur «Espace de travail vide »

Enregistrer avant tout l’espace de travail qui contiendra les compteurs

Donner un nom explicite et enregistrer l’espace de travail

 

Ajouter un compteur

Dans cet exemple on ajoute : Processor / _Total / % Processor Time et l’on sélectionne le style de graphique «Ligne ».

Il est possible d’afficher aussi le style Min-Max :

Ou carte thermique :

Ajoutez d’autres compteurs et forme d’affichage en fonction des besoins.

Pensez a enregistrer en écrasant la version précédente

Il est également possible de télécharger l’espace de travail au format JSON:

  

Ci-dessous le fichier JSON obtenu.

On peut voir que sa modification peut être assez facilement automatisé afin d’ajouter d’autres compteurs (object,instances,instancename,type)

Enfin, en cas de suppression sur la machine concernée on plus pratiquement pour obtenir le même espace de travail sur une autre machine, il est possible de charger le fichier JSON :

Glissez le fichier dans la fenêtre

Cliquez Envoyer

Cliquez sur l’espace de travail pour l’afficher

*********************************************************