Le script ci-dessous requete la base SQL de SCCM pour lister et exporter en CSV, les points de distribution SCCM
########################################################################################################
### REQUETE LA BASE SQL DE SCCM POUR OBTENIR LA LISTE DES POINTS DE DISTRIBUTION SCCM.
### EXPORT DES RESULTAT EN FICHIER CSV #####
########################################################################################################
# AUTHOR: CJOURDAN
<#
.SYNOPSIS
REQUETE LA BASE SQL DE SCCM POUR OBTENIR LA LISTE DES POINTS DE DISTRIBUTION SCCM
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_SCCM_Distribution_Points.ps1 -SQLInstance SQLSCCM\SCCM -SQLDB CM_BIM -ExportFolder C:\MyExport -LogFolder C:\MyLogs
#>
[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= $("/* --- ALL SCCM DISTRIBUTION POINTS --- */
Declare @UserSIDs As Varchar(25);
Set @UserSIDs = 'Disabled'
SELECT DISTINCT
dp.ServerName AS Distribution_Point
from fn_rbac_SystemResourceList(@UserSIDs) as sys
join fn_rbac_DistributionPointInfo(@UserSIDs) as dp
on sys.NALPath = dp.NALPath
where sys.RoleName = 'SMS Distribution Point'
"),
[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_SCCM_Distribution_Points.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 SCCM DP
$AllSCCMDP = $Result | ConvertTo-Csv -Delimiter ';' -NoTypeInformation | foreach {$_.replace('"','')}
$AllSCCMDP
# EXPORTS TO TXT FILES
$AllSCCMDP | Out-File -FilePath "$ExportFolder\All_SCCMDP.txt" -Force
# DISPLAY SUCCESS
$Message = "--- EXECUTION OK ---"
Write-Host -F Green $Message
Write-Log -Message $Message -LogPath $LogFolder -LogName $Log
Besoin :
Supprimer en masse des devices Autopilot d'un tenant source (Intune) pour pouvoir les migrer vers un tenant cible.
N.B : Un device Autopilot qu'on intègre dans Intune en utilisant son Hash ID ne peut pas co-exister dans deux tenants.
Solution :
1- Extraire les numéros de série des devices Autopilot à supprimer depuis Intune et les mettre dans un fichier texte nommé "Autopilot_Device_SN_list.txt" et le placer sous "c:\Windows\Temp".
2- Exécuter le script PowerShell ci-dessous afin de supprimer des devices Autopilot :
#STEP 1: Install WindowsAutopilotIntune Powershell module (if required, need ot run PowerShell as admin)
Install-module WindowsAutopilotIntune -Force -AllowClobber
#STEP 2: Install WindowsAutopilotIntune Powershell module
Import-module WindowsAutopilotIntune
#STEP 3: Connect to Microsoft Graph
Connect-MgGraph -scopes "Group.ReadWrite.All, Device.ReadWrite.All, DeviceManagementManagedDevices.ReadWrite.All, DeviceManagementServiceConfig.ReadWrite.All, GroupMember.ReadWrite.All"
#STEP 4: Get the Autopilot devices Serial Numbers in a variable $DeviceSNs
$DeviceSNs = Get-Content "C:\Windows\Temp\Autopilot_Device_SN_list.txt"
$Counter = 0
#STEP 5: Delete the Autopilot devices based on serial number list
foreach ($DeviceSN in $DeviceSNs)
{
$Counter++
#Get Autopilot device ID
$DeviceID = (Get-AutopilotDevice -serial $DeviceSN).id
#Get current device information
$CurrentDevice = Get-AutopilotDevice -id $DeviceID
Write-host "Working on device $DeviceSN" -ForegroundColor Cyan
#Delete device from Intune Windows Autopilot devices
try
{
Remove-AutopilotDevice -id $DeviceID
Write-host "- Device $DeviceSN is deleted" -ForegroundColor Green
}
catch{
$ErrorMessage = $_.Exception.message; Write-Host $ErrorMessage -ForegroundColor Red
}
#Counter for PowerShell execution progress
Write-Progress -Activity "Processing $($Counter) of $($DeviceSNs.count)" -CurrentOperation $DeviceSN -PercentComplete (($Counter / $DeviceSNs.count) * 100)
Start-Sleep -Milliseconds 200
}
N.B : le chemin vers le fichier texte qui contient les numéros de série des devices Autopilot "C:\Windows\Temp\Autopilot_Device_SN_list.txt" peut être modifié.
Besoin :
On ne peut pas identifier simplement les noms de groupes qui sont membres du groupe local "Administrateurs" sur une machine joint à l'Azure AD.
Si on fait Windows+R et on tape "lusrmgr.msc" pour afficher les utilisateurs et groupes locaux d'une machine, on souhaite par exemple afficher les membres du groupe Administrateurs, on n'aura pas les noms des groupes membres mais plutôt leurs SID.
Ces SID doivent être convertis en GUID pour pouvoir chercher les noms des groupes dans Azure AD.
Solution :
J'ai utilisé ce script PowerShell pour convertir le SID en GUID :
function Convert-AzureAdSidToObjectId {
<#
.SYNOPSIS
Convert a Azure AD SID to Object ID
.DESCRIPTION
Converts an Azure AD SID to Object ID.
Author: Oliver Kieselbach (oliverkieselbach.com)
The script is provided "AS IS" with no warranties.
.PARAMETER ObjectID
The SID to convert
#>
param([String] $Sid)
$text = $sid.Replace('S-1-12-1-', '')
$array = [UInt32[]]$text.Split('-')
$bytes = New-Object 'Byte[]' 16
[Buffer]::BlockCopy($array, 0, $bytes, 0, 16)
[Guid]$guid = $bytes
return $guid
}
$sid = "S-1-12-1-1943430372-1249052806-2496021943-3034400218"
$objectId = Convert-AzureAdSidToObjectId -Sid $sid
Write-Output $objectId
# Output:
# Guid
# ----
# 73d664e4-0886-4a73-b745-c694da45ddb4
N.B : Il faut renseigner le SID dans la variable $sid pour que le script retourne son GUID
Dans un précédent article j'expliquais comment réaliser un hard match (https://blog.piservices.fr/post/2021/04/01/o365-realiser-un-hard-match).
J'ai récemment eu à me servir de nouveau des cmdlets et ces dernières ne fonctionnaient pas correctement, il est possible de le faire via API Graph, mais les commande Azure AD permettent encore de le faire si besoin.
# Get GUID for User
$User = Get-ADUser jdupont | select ObjectGUID,UserPrincipalName
$Upn = $User.UserPrincipalName
$Guid = $User.ObjectGUID.Guid
# Convert GUID to ImmutableID
$ImmutableId = [System.Convert]::ToBase64String(([GUID]($User.ObjectGUID)).tobytearray())
# Connect Azure AD
Connect-AzureAD
# Retrieve my user
$User = Get-AzureADUser -SearchString "jdupont @mydomain.com"
# Set ImmutableID to user
Set-AzureADUser -ObjectId $User.ObjectID -ImmutableId $ImmutableId
Microsoft a ajouté la prise en charge de l'envoi à partir d'une adresse mail en alias dans Office 365/Microsoft 365. Toutefois, la fonctionnalité Envoyer en tant qu'alias ne fonctionnera que pour les boîtes aux lettres Exchange Online et ne fonctionnera pas pour les boîtes aux lettres Exchange Onpremise.
Cet article explique comment activer la fonctionnalité Envoyer depuis un alias dans un tenant Microsoft O365 et comment envoyer des e-mails en tant qu'alias dans Outlook et Outlook sur le Web. Le paramètre s’applique à l’ensemble du tenant. Il n’y a aucun moyen de restreindre la possibilité l'envoi des e-mails à partir d’alias vers certaines boîtes aux lettres.
Activer l'option SendFromAliasEnabled dans O365
- Se connecter à Exchange Online PowerShell:
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName 'UPNO365'
- Une fois connecté, exécuter la commande ci-dessous pour vérifier l'état actuel de l'option SendFromAliasEnabled
Get-OrganizationConfig | Format-Table SendFromAliasEnabled
Puis exécuter la commande:
Set-OrganizationConfig -SendFromAliasEnabled $True
Activer l’envoi à partir d’un alias dans le centre d’administration Exchange
Vous pouvez également activer cette option à partir du Centre d’administration Exchange:
- Se connecter au centre d’administration Exchange.
- Cliquer sur Paramètres > Flux de messagerie.
- Cocher la case Activer l’envoi à partir d’alias.
- Cliquer sur Enregistrer.
Envoyer à partir d’un alias dans Outlook
Pour envoyer à partir d’une adresse d’alias dans Outlook:
- Démarrer l’application Outlook puis cliquer sur Nouvel e-mail.
- Cliquer sur Options > de Cela affichera le champ De dans Outlook.
- Cliquer sur À partir de > autre adresse e-mail....puis renseigner l’adresse de l’alias et cliquez sur OK.
Envoyer à partir d’un alias dans Outlook sur le web
Pour envoyer à partir d’un alias dans Outlook sur le web:
- Se connecter à Outlook sur le web.
- Cliquer sur Nouveau message > ... > montrer à partir de Cela affichera le champ De dans Outlook web
- Cliquer sur À partir de > autre adresse e-mail... et renseigner l’adresse de l’alias.
Sous ce titre, le cas de l'utilisation du Widget Powershell Grid dans la console Monitoring de SCOM pour afficher certaines alertes spécifiques.
On commence par creer une vue Dashboard
On choisit le template Grid Layout
On nomme le dashboard
On selectionne 1 cell
Cliquer Create
Cliquer "Click to add widget"
Selectionner Powershell Grid Widget
Nommer le widget, par exemple avec le meme nom que le dashboard
Copier coller le script suivant dans le champ Script
# Get SCOM Alert Related to Discovery and Monitoring Error
$Alerts = Get-SCOMAlert -Criteria "ResolutionState <> 255 AND Name matches '.*(Discovery|Monitoring) (failed|error).*'" #| select name,MonitoringObjectDisplayName,MonitoringObjectPath,LastModified,Description | ft -AutoSize
foreach ($alert in $Alerts)
{
$AlertName = $alert.name
$AlertLastModified = $alert.lastmodified
$MonObjDisplayName = $alert.MonitoringObjectDisplayName.ToString()
$MonObjPath = $alert.MonitoringObjectPath.ToString()
$AlertDesc = $alert.Description.ToString()
$dataObject = $ScriptContext.CreateInstance('xsd://foo!bar/baz')
#Create an ID used for sorting the output - Must be a string value - Used to sort the grid
$dataObject['Id'] = $MonObjDisplayName
$dataObject['name'] = $AlertName
$dataObject['MonitoringPath'] = $MonObjPath
$dataObject['LastModified'] = $AlertLastModified
$dataObject['Description'] = $AlertDesc
# Add the data object to be displayed in the dashboard
$ScriptContext.ReturnCollection.Add($dataObject)
}
Dans ce script on recupere les alertes dont le nom correspond a des erreur de Discovery ou Monitoring.
Ne pas hesiter a faire évoluer les critères pour inclures d'autres cas propre a votre environnement.
Get-SCOMAlert -Criteria "ResolutionState <> 255 AND Name matches '.*(Discovery|Monitoring) (failed|error).*'"
Cliquer Create
Cliquer Close
La liste des alertes s'affiche
L'authentification multifacteur (MFA) est une méthode d'authentification permettant de renforcer la sécurité de votre mot de passe: L'utilisateur devra définir une seconde méthode d'authentification afin de se connecter à son compte : le mot de passe seul ne suffira plus. Par exemple, l'utilisateur devra saisir son mot de passe puis un code reçu par SMS (en guise de second facteur d'authentification).
Au fil du temps, l'utilisateur peut perdre ou remplacer son dispositif d'authentification ou passer à un nouveau numéro de téléphone mobile. Il est donc nécessaire d'Exiger la réinscription du MFA ce qui fera en sorte que lorsque l'utilisateur se connectera la prochaine fois, il lui sera demandé de configurer une nouvelle méthode d'authentification MFA.
Les étapes ci-dessous permettent de réinitialiser l’authentification multifacteur d’un compte utilisateur dans Azure AD. Les actions doivent être faite en tant qu'administrateur doté du rôle d'administrateur d'authentification ou d'administrateur global:
-
Se connecter sur https://portal.azure.com ,dans la zone de recherche, rechercher Azure Active Directory puis cliquer sur Users
-
Une liste de Tous les utilisateurs apparaît, renseigner le nom ou l’adresse mail du compte pour qui réinitialiser le MFA puis sélectionner le
- La page Profil de l'utilisateur sélectionné apparaît, sélectionner Méthode d'Authentification
- Dans la page Méthodes d’authentification, supprimer toutes les méthodes d’authentification enregistrées
- Cliquer par la suite sur Exiger une réinscription de l’authentification multifacteur
Note: Si l'appareil de l'utilisateur a été perdu ou volé, cliquer également sur Révoquer les sessions MFA. Cela réinitialise les détails MFA de l'utilisateur qui doit désormais réenregistrer ses méthodes MFA lors de sa prochaine connexion.
Vous pouvez vous rendre compte que votre mot de passe administrateur est expiré lorsque vous essayez de vous connecter en RDP sur le domaine en ayant le message suivant: "This user account's password has expired. The password must change in order to logon. Please update the password or contact your system administrator or technical support."
Les étapes ci-dessous s'appliquent si vous n’avez pas activé l’authentification au niveau du réseau (NLA) sur vos serveurs auxquels vous essayez de vous connecter via RDP.
Pour changer votre mot de passe procéder comme suit :
1. Créez un paramètre de connexion RDP: Exécuter mstsc --> puis enregistrez la connexion
2. Enregistrez-la connexion par exemple sous le nom "ChangePassword.rdp" puis cliquez droit sur le fichier pour l'ouvrir avec bloc-notes et ajoutez à la fin (en dernière ligne) cette ligne: enablecredsspsupport:i:0
3. Maintenant, réessayez: vous accéderez à l'écran de connexion qui vous permettra de renouveler/remplacer le mot de passe de connexion.
Après avoir modifié le mot de passe, vous recevez une confirmation du changement
4. Lorsque vous avez terminé, supprimez le fichier "ChangePassword.rdp"
Ne pas utiliser ce fichier sauf si vous êtes obligé de changer à nouveau votre mot de passe car la désactivation du CredSSP diminue la sécurité des connexions RDP.
Besoin :
On souhaite identifier le SID d'un groupe Azure AD mais l'attribut n'existe pas.
Solution :
J'ai utilisé ce script PowerShell pour convertir le GUID en SID :
function Convert-AzureAdObjectIdToSid {
<#
.SYNOPSIS
Convert an Azure AD Object ID to SID
.DESCRIPTION
Converts an Azure AD Object ID to a SID.
Author: Oliver Kieselbach (oliverkieselbach.com)
The script is provided "AS IS" with no warranties.
.PARAMETER ObjectID
The Object ID to convert
#>
param([String] $ObjectId)
$bytes = [Guid]::Parse($ObjectId).ToByteArray()
$array = New-Object 'UInt32[]' 4
[Buffer]::BlockCopy($bytes, 0, $array, 0, 16)
$sid = "S-1-12-1-$array".Replace(' ', '-')
return $sid
}
$objectId = "73d664e4-0886-4a73-b745-c694da45ddb4"
$sid = Convert-AzureAdObjectIdToSid -ObjectId $objectId
Write-Output $sid
# Output:
# S-1-12-1-1943430372-1249052806-2496021943-3034400218
N.B : il faut renseigner le GUID dans la variable $objectId pour que le script retourne son SID
Dans toute annuaire Active Directory il existe une mauvaise pratique, celle dont je voudrais vous parler aujourd'hui est la non expiration des mots de passe pour un / des comptes du domaine.
Pourquoi ?
Il existe plusieurs arguments au fait qu'un mot de passe qui n'expire jamais est une mauvaise pratique, je mettrais en avant ici les deux qui me posent le plus problème:
- Tout d'abord un mot de passe qui n'expire jamais a plus de chance d'être "découvert" dans des attaques de type brute force; si on se concentre sur ces comptes en particulier, le fait qu'il n'y ai pas de rotation de mot de passe, laisse une plus grande période de temps à l'attaquant pour le découvrir.
- Si le compte est compromis, l'attaquant a par définition un accès "constant" au SI, puisque tant que la rotation du mot de passe n'aura pas lieu, ce dernier conservera son accès.
Que faire ?
Bien qu'il ne soit pas une bonne pratique d'autoriser la non expiration des mots de passe, je les croise tous le jours dans tout Active Directory, avec toujours "une bonne raison" de l'avoir fait.
En revanche, même s'il n'est pas possible de s'en séparer, il est tout de même bon de mettre en oeuvre quelques bonne pratiques lorsque l'on est dans cette situation :
- Lister les comptes dont le mot de passe n'expire jamais.
- Documenter la cause de cette configuration.
- Documenter leur emploi (raison d'utilisation, application dans lesquelles ils sont utilisés, machines sur lesquelles ils sont utilisés).
- Documenter la date du dernier changement de mot de passe (même si elle peut être retrouvée dans l'AD).
- Documenter une procédure de changement de mot de passe (documentation applicative, processus de dépendance...).
- Indiquer une personne / équipe en mesure de pouvoir réaliser le changement de mot de passe (il se peut qu'il y ai des développeurs, prestataires externes, éditeurs qui se servent de ce mot de passe).
- Réaliser une rotation du mot de passe manuellement.
Lister les comptes avec Powershell.
# Variables
$RootFolder = "C:\Temp"
$Workefolder = "$RootFolder\NeverExpires"
$LogFolder = "$RootFolder\Logs"
$LogFile = "$LogFolder\NeverExpires.txt"
$AllFolders = $RootFolder, $Workefolder, $LogFolder
# Check and create if needed
foreach ($Folder in $AllFolders) {
If (!(Test-Path $Folder)) {
Try {
New-Item $Folder -ItemType Directory -ErrorAction Stop
}
Catch {
Write-Warning $($_)
}
}
}
# Import module
Try {
Import-Module ActiveDirectory -ErrorAction Stop
}
Catch {
Write-Output "Failed to import module ActiveDirectory" | Add-Content $LogFile
Exit
}
# Get Active Directory users that have a password that never expires
Try {
$AllEnabledUsers = Get-ADUser -Filter {Enabled -eq $true} -Properties PasswordNeverExpires -ErrorAction Stop
$PasswordNeverExpires = $AllEnabledUsers.Where({$_.PasswordNeverExpires -ne $false})
}
Catch {
Write-Output "Failed to collect users" | Add-Content $LogFile
}
# Export result
$PasswordNeverExpires | Export-Csv "$Workefolder\PasswordNeverExpires.csv" -Delimiter ";" -Encoding UTF8