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


 

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

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

 

 

 

 

 

 

 

 

 

 

 

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):

 

Module Powershell SecretStore - Exemple avec API Crowdstrike

SecretStore est un module Powershell permettant de facilement stocker et gérér des Credentials.

Dans l’exemple ci-dessous nous le mettons en place et l’utilisons pour demander, dans cet exemple, un token d’acces au cloud de l’EDR Crowdstrike.

NB : Le module SecretStore requiert l’installation du module SecretManagement

Comme tout module Powershell, si ils ne peut pas être directement téléchargé en ligne sur un repository avec la commande Install-Module, il est possible de le(s) récupérer sur Github ou encore sur Powershell Galery

(https://www.powershellgallery.com/packages/Microsoft.PowerShell.SecretStore)

(https://www.powershellgallery.com/packages/Microsoft.PowerShell.SecretManagement)

Une fois les module décompressé et stocké dans un des dossier contenant en standard des modules (ex : «C:\Program Files\WindowsPowerShell\Modules»)

NB : Si le module n’est pas stocké dans un chemin déclaré dans la variable $env:PSModulePath, son chemin complet devra être renseigné lors de l’import. Ceci peut être problématique aussi après l’import, dans le cadre de certaines commandes du module. Pour cela il est préférable qu’il soit stocké dans un chemin reconnu par la variable $env:PSModulePath

NB : Pour qu’un module soit correctement reconnu par Powershell, le nom du dossier le contenant doit être identique au nom du fichier psd1 ou psm1 :

 C:\Program Files\WindowsPowerShell\Modules \microsoft.powershell.secretstore

Dans une fenêtre powershell, exécuter Import-module en spécifiant le chemin d’accès aux fichiers indiqué ci-dessous

*****

Import-module microsoft.powershell.secretmanagement

Import-module microsoft.powershell.secretstore

*****

Par défaut le module SecretStore requiert un password pour accéder a chaque au coffre-fort de mot passe. La commande suivante permet de spécifier que l’authentification ne sera pas demandée , uniquement pour l’utilisation actuel (CurrentUser)

 

Set-SecretStoreConfiguration -Scope CurrentUser -Authentication None -Interaction None

La commande demande un password qui ne sera pas redemandé

La commande suivante permet de créer le coffre-fort (vault). Indiquer un nom explicite pour l’usage de ce coffre. (La commande requiert d’indiquer le module SecretStore)

Register-SecretVault -ModuleName microsoft.powershell.secretstore -Name MyVault

A présent que le coffre est créé, nous allons y stocker les informations requise, dans cet exemple, pour récupérer un token Crowdstrike.

Dans une variable de type hashtable ($ApiClient) On renseigne le Client Id, Le Client Secret, et le Hostname (url de l’api). On ‘range’  ($ApiClient) dans le coffre MYVault. (Set-secret)

$ApiClient = @{
    ClientId     = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    ClientSecret = ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    Hostname     = 'https://api.eu-1.crowdstrike.com'
}

Set-Secret -Name MyApiClient -Secret $ApiClient -Vault MyVault

On peut tester a présent que le credential peut être récupéré :

Get-Secret -Name MyApiClient -Vault MyVault -AsPlainText

Et dans notre exemple, on peut maintenant récupérer notre token Crowdstrike

Get-Secret -Name MyApiClient -Vault MyVault -AsPlainText | ForEach-Object { Request-FalconToken @_ }

Notre token doit etre valable

$(Test-FalconToken).token

Les cmdlets du module PSFalcon peuvent maintenant être exécutées, par exemple :

Get-FalconHost -All -Detailed

NB : Les modules powershell SecretStore et SecretManagement peuvent même etre supprimé (Remove-Module). Le coffre crée sera toujours accessible par le compte l’ayant crée.

Crowdstrike EDR - Scan de machines cibles

L’EDR Crowdstrike integre bien sur une fonction de scan de machines cibles, a la demande ou planifiés.

Aller sur le lien Endpoint security/On-demand scans

Cliquer Create a scan

Sélectionner Now ou In the future pour planifier un scan

Laisser coché l’option «Limit how long this scan runs» pour limiter la durée du scan. NB : La durée de 2 heures par défaut pourra être adapté au vu de la durée observée en moyenne dans le résultat final du/des scans.

Sélectionner une ou plusieurs et/ou des groupes de machines (la selection dans le champs affiche automatiquement les éléments)

Inscrire un ou plusieurs chemin a scanner (1 par ligne)

Inscrire éventuellement un ou plusieurs chemin a exclure

Le champ «Exclusions to test against above pattern» peut être utilisé pour tester les exclusions.

Dans l’exemple ci-dessus, on veut scanner le lecteur D:\, en excluant tout le contenu (*) de D:\App1

(la coche et la couleur du test effectué  valide le fait que la syntaxe de l’exclusion est correcte. Au contraire, par exemple  ne sera pas exclu)

Le bouton  peut être utilisé pour charger une liste d’exclusion en respectant une ligne par exclusion.

Renseigner une description explicite

Laisser par défaut la niveau de détection et de prévention a Moderate

Pour information la description des niveau de détection est la suivante :

Level

Description

Disabled

Disable all detections or preventions.

Cautious

Detect or prevent only when our machine learning system has high confidence that something is malicious.

Moderate

Detect or prevent when our machine learning system has moderate confidence that something is malicious. We recommend this setting for most use cases. This setting also detects and prevents activity that would be detected or prevented by Cautious.

Aggressive

Detect or prevent when our machine learning system has low confidence that something is malicious. This setting also detects and prevents activity that would be detected or prevented by Moderate and Cautious.

Extra Aggressive

Detect or prevent when our machine learning system has the lowest confidence that something is malicious. This setting also detects and prevents activity that would be detected or prevented by Aggressive, Moderate, and Cautious. 

 

 

Selectionner un niveau maximum de consommation CPU a utiliser (par defaut Low up to 25%)

Décocher Show notifications to end user si vous ne voulez pas que l’utilisateur connecté sur la machine reçoive une notification de Scan (le paramètre Pause duration permet d’autoriser l’utilisateur connecté à reporter le scan pour une durée donnée)

Cliquer Create Scan

 

Le scan apparait dans la liste et passez en état Completed lorsque le scan est fini.

Un clic sur le scan permet d’avoir le détail

Cliquer sur See full details pour afficher les détails complets

Dans notre exemple, la machine cible est bien dans les «Hosts without detection»

Le lien  permet d’accéder si besoin a des éléments de diagnostique/remédiation, dans le cas d’une machine ou des détections ont été remontées :

 

 

 

 

Power BI - Dax - Exemple d'utilisation de OR (II) dans un Filtre

Problématique: Nous voulons a travers une requete Dax compter un nombre de machines possedant une application 'MyApp' dans une table nommée MY_HOSTS_AND_APPS

Mais une partie des machines n'a pas cette info renseignée dans la colonne [AppName]. Cette info est inscrite sous la forme d'un texte libre dans une autre colonne [HostUsage]

Il est possible dans ce cas d'utiliser un OR (preferer l'alias '||') dans la clause FILTER.

On compte donc (DISTINCTCOUNT), les HostName où [AppName] est égale a "MyApp" ou bien (||) la chaine "MyApp" est presente dans [HostUsage]  (SEARCH)

 

WithMyApp = 
VAR Result = CALCULATE(
    DISTINCTCOUNT(MY_HOSTS_AND_APPS[HostName]),
        FILTER(MY_HOSTS_AND_APPS,MY_HOSTS_AND_APPS[AppName]="MyApp"
        ||
        SEARCH("MyApp",MY_HOSTS_AND_APPS[HostUsage],1,0)
        )               
)
RETURN(
    IF (Result=BLANK(),0,Result))

 

 

Script - Exemple de recherche d'ancien fichier de log dans une arborescence de dossier

Le script ci-dessous propose de rechercher dans une liste de dossiers specifiques (expression regulière FolderPattern) des fichiers de logs plus ou moins anciens, selon un seuil prédéfini (TimeDelta), ajoute un statut au tableau selon le cas rencontré, et exporte le resultat en fichier csv.

 

##############################################
### CHECK OLD LOG FILES ###
##############################################


<# 

    .SYNOPSIS 
        VERIFICATION DE LA PRESENCE ET DE L'ANCIENNETE DU LOG LE PLUS RECENT DANS UNE LISTE DE DOSSIER; 
        UN TABLEAU DES DOSSIERS DONT LE LOG LE PLUS RECENT EST PLUS ANCIEN QUE J-$TimeDelta EST AFFICHE ET EXPORTE EN FICHIER CSV.  

    .PARAMETER  
        RootFolder : Chemin du dossier racine
        TimeDelta : Seuil d'ancienneté du fichier de log le plus recent
        FolderPattern: Expression reguliere pour selectionner des noms de sous dossier
        

 
    .EXAMPLE 
     .\Check_Old_Log_Folders.ps1 -RootFolder "C:\MyRootFolder" -TimeDelta 15
#>




[CmdletBinding()]
param(
[Parameter(Mandatory,HelpMessage="Chemin du dossier racine")]
$RootFolder,

[Parameter(Mandatory,HelpMessage="Seuil d'ancienneté du fichier de log le plus recent")]
$TimeDelta,

[Parameter(HelpMessage="Expression reguliere pour selectionner des noms de sous dossier")]
[regex]$FolderPattern = "^(SRV|DEV).*"

)



# Date du jour - TimeDelta
$DateTimeMinus = (get-date).AddDays(-$TimeDelta)

# Verification que RootFolder existe 
if (!(Test-Path -Path $RootFolder))
    {
    write-host -B White -F Red "UNABLE TO FIND $RootFolder - CHECK PATH - END OF SCRIPT"
    EXIT 1
    }


# Creation d'un PSobject pour stocker les futurs valeurs LogFolder,LastLog et Status
$FileTab = @()

# Recuperation des noms de dossier
$Folders = Get-ChildItem -Path $RootFolder -Directory | Where-Object {$_.Name -match $FolderPattern}


# Pour chacun des dossier on cherche le dernier fichier modifié
$Folders | foreach {


$LogFolder = $_.Name
$LastLog = Get-ChildItem -Path $_.FullName | select -Last 1 -Property LastWriteTime -ExpandProperty LastWriteTime

# Si le dossier est vide (pas de Lastlog) le status est KO
 if (!$LastLog) {$status = "KO - DOSSIER VIDE"}

# Si LastLog est plus ancien ou plus recent que $DateTimeMinus  
 switch($LastLog)
    {
        
        {$LastLog -lt $DateTimeMinus} {$status = "KO - OLDER THAN $DateTimeMinus"}
        {$LastLog -gt $DateTimeMinus} {$status = "OK - NEWER THAN $DateTimeMinus"}
        default {$status = "UNKNOWN"}
    }


# remplissage du tableau
$FileTab += New-Object -TypeName psobject -Property @{LogFolder=$LogFolder;LastLog=$LastLog;Status=$status}

}


# Affiche le tableau $FileTab des dossiers dont le fichier le plus recent est plus ancien que $TimeDelta ou pour lequel il n'y a pas de log
Write-Host -F red -B White "LOG FOLDERS DONT LE FICHIER DE LOG LE PLUS RECENT EST PLUS ANCIEN QUE J $TimeDelta OU POUR LESQUELS IL N'EXISTE PAS DE LOG (DOSSIER VIDE)"
$KOFiles = $FileTab | Where-Object {$_.status -like 'KO*'} | select LogFolder,LastLog,Status | Sort LastLog
$KOFiles | ft -AutoSize


# Export CSV du tableau en supprimant les caractere '"'
$KOFilesCSV = $KOFiles | ConvertTo-Csv -Delimiter "," -NoTypeInformation | ForEach {$_.replace('"','')}


# Export du fichier CSV
$KOFilesCSV | Out-File "$($pwd.ProviderPath)\OldLogFolders.csv" -Force
write-host -F Blue -B White "Old Log Folders CSV File Exported as $($pwd.ProviderPath)\OldLogFolders.csv"


# Ouverture du fichier CSV
notepad.exe "$($pwd.ProviderPath)\OldLogFolders.csv"

 

Scripting - Exemple de la recuperation de la date de modification du password d'un compte AD

Problématique:  Récuperer et rendre lisible un timestamp représentant la date de modification du password d'un compte AD, renvoyé par l'outil Dsquery (https://ss64.com/nt/dsquery.html)

 

$user = "johndoe"
$domain = "mydomain.com"

# Executer la commande dsquery pour recuperer l'attribut pwdLastSet
$obj = dsquery * -filter "samaccountname=$user" -attr displayName pwdLastSet -d $domain

# Decouper $obj pour ne recuperer que la chaine correspondant au timestamp
$TimeStamp = $($obj[1] -split " ") | Where-Object {$_ -match '^\d+$'}

# Convertir le timestamp en date avec l'outil w32tm.exe
w32tm.exe /ntte $TimeStamp



Script - Crowdstrike - Exemple d'utilisation du module PSFalcon

Falcon Crowdsrike est l'un des antivirus next generation (EDR) les plus en vue et les plus performants du marché.  Le script ci-dessous propose un exemple de requetage de l'API de Crowdstrike via l'utilisation du module Powershell PSFalcon (https://www.powershellgallery.com/packages/PSFalcon)

L'acces et l'utilisation de l'Api Crowdstrike requiert bien sur un abonnement Crowdstrike (https://www.crowdstrike.com/)

Le script utilisant pour l'acces a l'API, une clé d'encryptage (AES.key), un fichier contenant le SecID (SecID.txt), et un fichier contenant la passphrase (pass.txt), il est necessaire de recreer ces éléments avec le contexte de l'abonnement auquel on se connecte (SecID).

Le script interroge l'API pour recuperer des éléments tel que les hotes, les comportements (Behaviors), les detections, les incidents.

 

QueryCrowdstrike.ps1 (11,62 kb)

 

##############################################
### QUERY CROWDSTRIKE WITH PSFALCON MODULE ###
##############################################


<# 

    .SYNOPSIS 
        INTERROGATION D'UN TENANT FALCON CROWDSTRIKE VIA L'UTILISATION DU MODULE POWERSHELL PSFALCON
        NB: LES DONNEES SONT EXTRAITES SOUS FORME D'UN FICHIERS CSV 

    .PARAMETER  
        ClientID : Client ID crowdstrike
        Pass : Password du compte d'acces a l'API
        
        ExportFolder : Dossier d'export du fichier CSV
        LogFolder : Chemin du dossier où creer le log du script

 
    .EXAMPLE 
     .\QueryCrowdstrike.ps1 -CloudUrl "https://api.eu-1.crowdstrike.com"  -ClientID <clientid> -Pass <pass> -ExportFolder ./ -LogFolder ./
#>


[CmdletBinding()]
param(
[Parameter(Mandatory,HelpMessage="Cloud URL")]
$CloudUrl,

[Parameter(HelpMessage="Client ID crowdstrike")]
$ClientID,

[Parameter(HelpMessage="Password du compte d'acces a l'API")]
$Pass,

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

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

[Parameter(Mandatory,HelpMessage="Chemin de la clé utilisée pour l'encryption du CID et de la passphrase")] 
$KeyFile = "D:\MyFolder\CROWDSTRIKE\AES.key",

[Parameter(Mandatory,HelpMessage="Chemin du fichier contenant le SecID du client")] 
$SecIDFile = "D:\MyFolder\CROWDSTRIKE\SecID.txt",

[Parameter(Mandatory,HelpMessage="Chemin du fichier contenant la passphrase")] 
$PassFile = "D:\MyFolder\CROWDSTRIKE\Pass.txt"


)


# TO RENEW KEY FILE USED FOR CLIENT ID AND PASSPHRASE ENCRYPTION
<#
    # Generate Key File
    $Key = New-Object Byte[] 16   # You can use 16, 24, or 32 for AES
    [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
    $Key | out-file $KeyFile

#>


# TO RENEW SECID ENCRYPTION, EXECUTE THE CODE BETWEEN <# #>

<#
    # Create secure string object
    $SecIDFile = "D:\MyFolder\CROWDSTRIKE\SecID.txt"
    $Key = Get-Content $KeyFile
    $SecID = read-host  -Prompt "Enter client SecID" -AsSecureString
    $SecID | ConvertFrom-SecureString -key $Key | Out-File $SecIDFile

#>


# TO RENEW PASSPHRASE ENCRYPTION, EXECUTE THE CODE BETWEEN <# #>

<#
    # Create secure string object
    $PassFile = "D:\MyFolder\CROWDSTRIKE\Pass.txt"
    $Key = Get-Content $KeyFile
    $Pass = read-host  -Prompt "Enter client PassPhrase" -AsSecureString
    $Pass | ConvertFrom-SecureString -key $Key | Out-File $PassFile

#>






# OTHER VARIABLES
# Script Name
$ScriptName = "QueryCrowdstrike.ps1"
# LogName = ScriptName without extension
$Log = $ScriptName.Split('.')[0]


# FUNCTIONS


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 
    } 
} 



            




# Requis si l'import du module echoue en en renvoyant plusieurs messages 'Unable to find [System.Net.Http.(...)*]' 
Add-Type -AssemblyName System.Net.Http 

# Import Module
Import-Module -Name D:\MyFolder\CROWDSTRIKE\Powershell_Module\psfalcon-master\PSFalcon.psm1



$Key = Get-Content $KeyFile

# Get file content and Decrypt ClientID
$ClientID = Get-Content $SecIDFile | ConvertTo-SecureString -Key $key
$ClientID = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ClientID))

# Get file content and Decrypt Pass
$Pass = Get-Content $PassFile | ConvertTo-SecureString -Key $key
$Pass = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Pass))







# Query for Falcon Token
try
    {
    Request-FalconToken -ClientId $ClientID -ClientSecret $Pass -Hostname $CloudUrl
    }
catch
    {
    $Message = "Error during Request-FalconToken - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }


# Test if Test-FalconToken return True
if ($(Test-FalconToken).token -eq $true)  
      {
      $Message = "Token is valid - OK"
      write-host -F Green $Message
      Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
      }
Else
    {
    $Message = "Problem with Token - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }




# GET DATA

#region Falcon Hosts 

# Get Falcon Hosts (exemple option -filter:  –Filter "hostname:'SRV'")
try
    {
    $FalconHosts = Get-FalconHost -All -Detailed
    #$FalconHosts | select hostname,os_version,agent_version,status | ft -AutoSize
    }
catch
    {
    $Message = "Problem during Get-FalconHost - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }


# Convert To CSV
 try
    {
    $FalconHostsCSV = $($FalconHosts | select `
        hostname,
        os_version,
        platform_name,
        status,
        agent_version,
        config_id_base,
        config_id_build,
        @{Name='First_Seen';Expression={[datetime]::ParseExact($_.first_seen.Replace('T','').Replace('Z',''),'yyyy-MM-ddHH:mm:ss',$null)}},
        @{Name='Last_Seen';Expression={[datetime]::ParseExact($_.last_seen.Replace('T','').Replace('Z',''),'yyyy-MM-ddHH:mm:ss',$null)}},
        reduced_functionality_mode | ConvertTo-Csv -Delimiter ',' -NoTypeInformation).Replace('"','')
    
    # Display CSV File
    $FalconHostsCSV
    }
catch
    {
    $Message = "Error during convert to CSV file for FalconHosts - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }

# Export CSV
 try
    {   
    $FalconHostsCSV | Out-File -FilePath "$ExportFolder`/FalconHosts.csv" -Force
    }
catch
    {
    $Message = "Error during export of CSV file for FalconHosts - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }


#endregion Falcon Hosts 







#region Falcon Detection




#Get-FalconDetection
write-host "FALCON DETECTION EVENTS" -B White -f Blue
try
    {
    $FalconDetection = Get-FalconDetection -Detailed -All  
    $FalconDetection | sort created_timestamp -Descending
    }
catch
    {
    $Message = "Error during Get-FalconDetection - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }


# Convert To CSV
 try
    {
    $FalconDetectionCSV = $($FalconDetection | select `
    detection_id,
    @{Name='Detection_Creation_Date';Expression={[datetime]::ParseExact($_[0].created_timestamp.split('.')[0].Replace('T',''),'yyyy-MM-ddHH:mm:ss',$null)}},
    @{Name='HostName';Expression={$_.device.hostname}},
    @{Name='HostIP';Expression={$_.device.local_ip}},
    @{Name='DeviceID';Expression={$_.device.device_id}},
    @{Name='BehaviorID';Expression={$_.Behaviors.Behavior_id}},
    @{Name='Behavior_FileName';Expression={$_.Behaviors.filename}},
    @{Name='Behavior_FilePath';Expression={$_.Behaviors.filepath}},
    @{Name='Behavior_cmdline';Expression={$_.Behaviors.cmdline}},
    status,
    max_severity_displayname,
    email_sent | ConvertTo-Csv -Delimiter ',' -NoTypeInformation).Replace('"','')
    }
catch
    {
    $Message = "Error during convert to CSV file for FalconDetection - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }

# Export CSV
 try
    {   
    $FalconDetectionCSV | Out-File -FilePath "$ExportFolder`/FalconDetection.csv"
    }
catch
    {
    $Message = "Error during export of CSV file for FalconDetection - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }




#endregion Falcon Detection




#region Falcon Behavior

# Get-FalconBehavior (NB: Transform TimeStamp to more readable format with [datetime]::ParseExact)
write-host "FALCON BEHAVIOR EVENTS" -B White -f Blue

try
    {
    $FalconBehavior = Get-FalconBehavior | foreach {Get-FalconBehavior -Ids $_} | Select -property  behavior_id,display_name,objective,@{Name='BehaviorDate';Expression={[datetime]::ParseExact($_.timestamp.Replace('T','').replace('Z',''),'yyyy-MM-ddHH:mm:ss',$null)}},cmdline,filepath,user_name,incident_id,tactic_id,tactic,technique_id,technique | sort BehaviorDate -Descending
    $FalconBehavior
    }
catch
    {
    $Message = "Error during Get-FalconBehavior - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }


# Convert To CSV
 try
    {
    $FalconBehaviorCSV = $($FalconBehavior | select BehaviorDate,cmdline,filepath,user_name | ConvertTo-Csv -Delimiter ';' -NoTypeInformation).Replace('"','')
    }
catch
    {
    $Message = "Error during convert to CSV file for FalconBehavior - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }

# Export CSV
 try
    {   
    $FalconBehaviorCSV | Out-File -FilePath "$ExportFolder`/FalconBehavior.csv"
    }
catch
    {
    $Message = "Error during export of CSV file for FalconBehavior - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }



#endregion Falcon Behavior





#region Falcon Incident

write-host "FALCON INCIDENTS EVENTS" -B White -f Blue
try
    {
    $FalconIncidents= Get-FalconIncident -Detailed -All  
    $FalconIncidents | sort created -Descending
    }
catch
    {
    $Message = "Error during Get-FalconIncident - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }


# Convert To CSV
 try
    {
    $FalconIncidentsCSV = $($FalconIncidents | select `
    incident_id,
    @{Name='Creation_Date';Expression={[datetime]::ParseExact($_.created.Replace('T','').Replace('Z',''),'yyyy-MM-ddHH:mm:ss',$null)}},
    state,
    email_state  | ConvertTo-Csv -Delimiter ',' -NoTypeInformation).Replace('"','')



        

    }
catch
    {
    $Message = "Error during convert to CSV file for FalconIncident - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }

# Export CSV
 try
    {   
    $FalconIncidentsCSV | Out-File -FilePath "$ExportFolder`/FalconIncidents.csv"
    }
catch
    {
    $Message = "Error during export of CSV file for FalconIncidents - END OF SCRIPT"
    write-host -F Red $Message
    Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
    EXIT 1
    }




#endregion Falcon Incident

 

Power BI Desktop - Exemple d'extraction et utilisation d'une date issue d'un champ texte

Problématique :  Un champ texte apparenté au contenu d’un log, melange de texte et de chiffre, contiens une date que l’on veut récupérer.

 

  • On veut récupérer la date de création (Creation Date) et la mettre dans une nouvelle colonne
  • On remarque que la date est situé entre deux chaines de delimitation : ‘Creation Date : "’ et ‘"’

De ce fait on selectionne la colonne et dans le menu ‘Add Column’ on clique sur Extract/Text Between Delimiters

 

Dans le champ ‘Start delimiter’ on renseigne notre premiere chaine (ici Creation Date : ") (NB : attention aux espaces)

Dans le champ ‘End delimiter’ on renseigne notre deuxième chaine (ici ")

On valide.

Une colonne est crée automatiquement au format chaine (ABC) a la fin du tableau avec le nom ‘Text Between Delimiters’

On fait un clic droit sur la colonne et on selectionne Change Type\Date/Time/Timezone

Attention. Dans cet exemple la conversion fonctionne car le système detecte que le pattern de la chaine est de type Date/Time/Timezone.  Dans d’autres cas il peut être nécessaire de tester d’autres format et/ou bien de sélectionner a l’origine, une portion differente de texte dans la colonne d’origine.

La conversion est OK :

Il ne reste plus qu’a renommer la colonne de manière plus explicite. (Ex : Custo_Creation_Date)