PI Services

Le blog des collaborateurs de PI Services

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

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

 

 

 

 

 

 

 

 

 

 

 

MECM : Variables d'environnement OSD peuvent contenir des mots de passe en clair

Besoin :

Durant l'OSD, j'ai remarqué quand je fais F8 pour ouvrir l'invite de commande, je peux exporter une liste de variable d'environnement de la TS qui contiennent des valeurs non masquées, y compris des mots de passe. Ces deux variables par exemple ne sont pas masqués :

  • "OSDLocalAdminPassword" : contient le mot de passe du compte admin local qui est mis sur la machine en cours d'installation
  • "_SMSTSReserved1-000" et "_SMSTSReserved2-000" : contiennent le Username et Password du compte ConfigMgr Nework Access (NAA)

Le besoin est d'éviter de laisser ces deux variables visibles.

Solution :

Arrêter d'utiliser le compte Network Access et le supprimer de la configuration. Depuis ConfigMgr 1902, cela n'est plus nécessaire dans presque tous les scénarios tant que vous activez le enhanced HTTP.

Pour l’administrateur local, une réponse similaire. Les systèmes de production ne doivent pas avoir ce compte activé et vous devez autoriser Windows à configurer un mot de passe aléatoire pour celui-ci.

Intune : Intégration manuelle du Hash ID avec le mode Online

Besoin :

Intégrer manuellement le Hash ID d'un device Autopilot dans Intune sans passer par la clé USB et le fichier csv.

 

Solution :

Ceci est possible en utilisant le mode Online du script PowerShell "Get-WindowsAutopilotInfo.ps1".

Une fois Windows est démarré et que vous êtes sur la page OOBE (Out Of the Box Experience) et connectés à Internet, il faut taper Shift + F10 pour ouvrir l'invite de commande ensuite dérouler les commandes PowerShell suivantes :

> Powershell

> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -force

> Install-Script Get-WindowsAutopilotInfo

    --> Choisir Yes  pour confirmer l'installation du script

> Get-WindowsAutopilotInfo.ps1 -Online -Assign -GroupTag "CompanyGroupTag"

    --> Quand invité à se connecter à Intune,  utilisez un compte d'administration ayant le droit d'import de device Autopilot

 

Active directory : problème d'authentification par smartcard

Un de nos clients utilise des cartes à puce pour s'authentifier sur les postes de travail et depuis quelques mois, un problème apparemment aléatoire se produit : lorsque certaines cartes sont associées à certains comptes Active Directory, l'authentification ne fonctionne pas (erreur "invalid credentials" lors d'une tentative d'ouverture de session Windows).

Les mêmes cartes associées à d'autres comptes ne posent cependant aucun problème, et réciproquement.

La seule autre indication dont nous disposons au moment de commencer les investigations est un évènement 4771 généré dans le journal Security des contrôleurs de domaine. Il indique une erreur 0x42, qui se traduit par KRB_ERR_CERTIFICATE_MISMATCH (et non pas KRB_AP_ERR_USER_TO_USER_REQUIRED comme une première recherche nous l'avait fait penser, nous entraînant sur une fausse piste!)

Dernière information pertinente : les certificats présents sur ces cartes à puce ne contiennent pas l'UPN du compte qui les utilise pour ouvrir une session. Il s'agit de certificats génériques, fournis par une entité tierce.

Il est donc nécessaire de peupler la propriété LDAP altSecurityIdentities pour lier le compte Active Directory d'un utilisateur à une smartcard.

Première vérification évidente : les comptes utilisateurs contiennent bien une référence au certificat présent dans la smartcard dans cette propriété altSecurityIdentities.

Il s'agit plus précisément de leur propriété RFC822, autrement dit un identifiant au format adresse email.

L'erreur "Certificate Mismatch" ne semble donc pas être pertinente ici, mais une nouvelle recherche permet de trouver une note récente de Microsoft ( https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-winerrata/85d75079-92de-47e6-a1c1-7e4fd7f27a10 ) qui indique que depuis la mise à jour mensuelle de Mai 2022, les informations utilisées pour remplir la propriété altSecurityIdentities sont divisées en deux catégories "forte" et "faible"; que l'adresse RFC822 fait partie des "faibles" et que lors de l'utilisation d'une information "faible", l'erreur Certificate Mismatch "peut" être présente.

On progresse donc, mais il nous reste à comprendre quelles sont les conditions exactes pour obtenir cette erreur puisque par ailleurs la majorité des comptes fonctionne avec la majorité des cartes à puce sans problème, en utilisant le même identifiant RFC822 "faible".

Un nouvel événement (id 40 dans le journal System des contrôleurs de domaine) nous met la puce à l'oreille :

The Key Distribution Center (KDC) encountered a user certificate that was valid but could not be mapped to a user in a strong way (such as via explicit mapping, key trust mapping, or a SID). The certificate also predated the user it mapped to, so it was rejected

Il confirme clairement ce dont nous nous doutions déjà, à savoir que le certificat est valide mais pas associé au compte AD de façon sûre.

Mais il indique également un élément supplémentaire : s'il a été rejeté, c'est parce qu'en plus la date d'émission du certificat est antérieure à la date de création du compte.

Il s’agit d’un blocage destiné à permettre l’évolution progressive de la configuration de vos altSecurityIdentities : en effet, Microsoft indique que toutes les authentifications par certificat lié par une association « faible » échouera à partir de Mai 2023 (cf. KB5014754: Certificate-based authentication changes on Windows domain controllers - Microsoft Support ), et ce blocage permet donc d’éviter de créer des associations qui poseront problème après quelques mois seulement.

Deux solutions sont alors disponibles : 

· Regénérer le certificat de façon à ce qu’il contienne l’extension SID (introduite également lors de la mise à jour de Mai 2022), mais cette solution ne fonctionne que pour les certificats signés par une PKI Microsoft et dont les informations sont récupérées dans l’AD et non pas fournies dans la requête

· Changer les altSecurityIdentities de façon à établir une association forte.

Dans notre contexte, seule la seconde solution est possible puisque les certificats sont fournis par une entité tierce. 

Le format recommandé par Microsoft pour établir une liaison forte est le suivant : X509:<I>IssuerName<SR>1234567890

Il contient le nom de l’autorité de certification (au format Distinguished Name) ainsi que le numéro de série du certificat.

Attention : ces deux informations doivent être indiquées « à l’envers ». Par exemple, si le DN de l’autorité émettrice est CN=CONTOSO-DC-CA, DC=contoso, DC=com et le numéro de série du certificat est 2B 3C F4, alors le champ altSecurityIdentities doit contenir la chaine suivante : X509:<I>DC=com,DC=contoso,CN=CONTOSO-DC-CA<SR>F43C2B

Une fois cette modification effectuée, la connexion à l’aide de la smartcard fonctionne enfin !

PowerBI - Coloration conditionnel - Exemple avancé

Derrière le terme un peu technique "Coloration conditionnel" se cache simplement le fait, dans un dashboard PowerBI d'afficher un changement de couleur dans le champ d'un tableau, en fonction de condition.

En plus des fonctions natives de mise en forme dans PowerBI Desktop, il est possible de creer une mesure (code DAX) , avec des conditions, que l'on va utiliser pour afficher une valeur dans un champ. Et cette valeur peut etre un code couleur.

Dans l'exemple du code ci-dessous, on a une application "MyApp" pour laquelle, dans PowerBI nous avons trois datasets (deux correspondrait par exemple a deux tables de la base de donnée associée a "MyApp", et un troisième qui est une connexion vers un outil qui reference la criticité de mes machines (ex: outil de gestion des asset ou cmdb)):

- MyAppAgents, qui contiens des infos sur les agents de mon application

MyAppVersions, qui contiens un historique des numeros de version de mon application

-  MyServers qui est donc la table qui liste la criticité des mes serveurs.

Objectif: On veux dans un dashboard, colorer un champ en rouge ou jaune (exemple, le nom du serveur), pour lequel la version ((MyAppAgents[MyApp_agent_version]) serai differente de la dernière version, ET dont le serveur serait un serveur de Production ou de test.

 

Color_MyApp_agent = 

   VAR Result1 = SELECTEDVALUE(MyAppAgents[MyApp_agent_version])
   VAR Result2 = SELECTEDVALUE(MyAppVersions[MyApp_Last_version_available])
   VAR Result3 = SELECTEDVALUE(MyServers[Server_Criticity])

-- SI MyApp_agent EST DIFFERENT DE MyApp_Last_version_available ET SI Server_Criticity = "PROD" alors on renvoi "CRITICAL"
   VAR Critical = IF(AND(Result1<>Result2, Result3="PROD"),"CRITICAL")
   
-- SI MyApp_agent EST DIFFERENT DE MyApp_Last_version_available ET SI Server_Criticity <> "TEST" alors on renvoi "WARNING"  
   VAR Warning = IF(AND(Result1<>Result2, Result3<>"TEST"),"WARNING")
   
-- SI MyApp_agent EST EGALE A MyApp_Last_version_available   
   VAR OK = IF(Result1=Result2,"OK")

   
 -- SELON LE CAS ON RENVOI UN CODE COULEUR DIFFERENT
RETURN
SWITCH(
True(),
 Critical="CRITICAL" , "#FEA19E",
Warning="WARNING" , "#F9FF28",
 OK="OK" , "#96FF93" 
)

 

On crée donc une mesure (measure) dans laquelle on va coller le code ci-dessus

Apres validation la mesure apparait dans le dataset ou elle a été crée

On selectionne ensuite le champ que l'on veut colorer puis Conditional formatting/Background color

 

On selectionne Format by "Field Value", et on va venir selectionner notre mesure (Color_MyApp_agent)

 

Apres validation, Les valeurs de la colonne seront formatée selon la condition rencontrée (Les code couleurs '#FEA19E' peuvent bien sur etre modifié dans le code pour choisir une autre coloration):

 

Azure - Utiliser la localisation GPS avec l'accès conditionnel Azure

L'accès conditionnel d'Azure ou Conditional Access (CA) est un service Azure qui permet d'autoriser les connexions vers des applications ou services Azure selon des conditions tels que la plage IP publique d'accès, le type de device ou le niveau de risque de l'utilisateur. Avec la popularisation des VPN, il est difficile de réellement restreindre les connexions depuis un pays donné. Une fonctionnalité récente sortie en 2021 permet dorénavant de demander les coordonnés GPS d'un utilisateur lorsqu'une CA est configurée.

 

Prérequis pour utiliser la localisation GPS avec l'accès conditionnel Azure

  • Chaque utilisateur qui utilise un accès conditionnel doit avoir une licence Azure AD Premium P1
  • Le compte qui configure l'accès conditionnel doit avoir un de ces rôles : Security Administrator, Conditional Access Administrator ou Global Administrator
  • Les utilisateurs doivent avoir l'application Microsoft Authenticator installée et configurée avec leur compte Azure AD

Créer un emplacement nommé basé sur la localisation GPS

Un emplacement nommé ou name location est un groupement d'IP ou de pays qui sera consommé par une CA pour appliquer une restriction d'accès.

1. Se connecter au tenant Azure AD via le lien portal.azure.com avec le compte qui a les privilèges requis pour configurer une CA

2. Cliquer sur Azure AD > Security > Named locations > + Countries location

3. Dans la blade (fenêtre Azure) qui s'est ouverte :

  • Dans le champs Name choisir un nom à donner à cette named location
  • Dans le deuxième champs dont la valeur par défaut est Determine location by IP address (IPv4 only) choisir Determine location by GPS coordinates

4. Il est possible de cocher l'option Include unknown countries/regions, cela permet d'inclure les plages IP qui n'appartiennent à aucun pays et les IPv6 qui ne sont pas incluses par défaut.

5. Dans cet exemple, on souhaite configurer la named location en France, scroller jusqu'à trouver France et cocher la checkbox associée puis cliquer sur Create

 

Créer un accès conditionnel basé sur la localisation GPS

1. Se connecter au tenant Azure AD via le lien portal.azure.com avec le compte qui a les privilèges requis pour configurer une CA

2. Cliquer sur Azure AD > Security > Conditional Access > Policies > + New policy

3. Dans le champs Name entrer le nom de la CA puis cliquer successivement sur Conditions > Locations > Configure > Include > Selected locations

4. Dans la blade qui est apparue à droite, entrer le nom de la named location précédemment entrée et cocher la checkox associé puis cliquer sur Select

5. Il est ensuite possible d'utiliser les différentes options pour choisir les éléments qui doivent être bloqués, par exemple :

  • Users or workload identites permet de choisir si la CA doit s'appliquer à l'ensemble des utilisateur ou à un groupe d'utilisateur spécifique
  • Cloud apps or actions permet de choisir l'application Azure à conditionner
  • Grant permet de configurer la CA en tant qu'autorisation ou réfutation

6. Une fois les éléments de configuration de la CA choisis, il est possible de la configurer en Report-only pour ne pas qu'elle s'applique réellement, mais pour pouvoir avoir un aperçu de ses effets au travers des Sign-in logs des utilisateurs.