Comme vu dans l'article Powershell - Chiffrer un mot de passe la santé de votre équipe de sécurité a été préservé car vos mots de passe sont désormais chiffrés dans vos scripts. Un mot de passe chiffré c'est bien mais comment le déchiffrer pour pouvoir l'utiliser ?
La fonction de déchiffrement
function Get-SecureStringFromEncryptedFile #Fonction qu'il faudra appeler pour déchiffrer le mot de passe
{
[CmdletBinding()] #Déclaration des paramètres qu'il faudra fournir à la fonction pour qu'elle puisse s'exécuter
Param
(
[Parameter(Mandatory=$true)] #Indique que ce paramètre est obligatoire
[ValidateNotNullOrEmpty()] #Indique que ce champ ne peut pas être vide ou null
[string]$Name, #Paramètre qui attend le nom de l'utilisateur, il est utilisé pour créer un credential object
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$PwdPath #Paramètre qui attend le chemin complet du fichier qui contient le mot de passe chiffré
)
Begin
{
$Return = @{} #Tableau de retour qui contient le mot de passe sous forme de secure string et le credential object généré à partir du nom du compte de service et de son mot de passe
}
Process
{
$PwdSecureString = Get-Content $PwdPath | ConvertTo-SecureString #Récupére le mot de passe chiffré depuis le fichier txt fourni et le convertit en secure string
$Return.pwdSecureString = $PwdSecureString #Attribution de la secure string générée dans la variable de sortie de la fonction
$Credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Name, $PwdSecureString #Génére un credential object à partir de l'utilisateur et de son mot de passe
$Return.credentials = $Credentials #Attribution du credential object générée dans la variable de sortie de la fonction
Return $Return #Retourne le mot de passe ainsi que la secure string en sortie de la fonction
}
}
Exemple d'utilisation de la fonction de déchiffrement
. .\Get-SecureStringFromEncryptedFile_article.ps1 #Permet de déclarer (dot source) la fonction de chiffrement pour qu'elle puisse être utilisée
$Password = Get-SecureStringFromEncryptedFile -Name "Svc-test-01" -PwdPath "D:\A_folder\Svc-test-01_encrypted_password.txt" #Appelle de la fonction de déchiffrement et lui passe en paramètre le nom de l'utilisateur le chemin complet du fichier qui contient le mot de passe chiffré
#Le mot de passe sous forme de secure string est conservé dans la propriété pwdSecurestring, on peut y accéder comme ceci $Password.pwdSecureString
#Le credential object qui contient le jeu d'identifiant nom d'utilisateur et mot de passe est conservé sous forme de credential object dans la propriété credentials, on peut y accéder comme ceci $Password.credentials
$Credentials = $Password.Credentials #Attribution du credential object à la variable $Credentials
Get-ADUser -Identity "Toto" -Credential $Credentials #Utilisation de la cmdlet Get-ADUser avec le credential object précédemment généré
Remarque : lorsque le fichier est généré, une combinaison du compte utilisateur et du compte machine est utilisée. Cela implique que le mot de passe ne peut être déchiffré que par l'utilisateur qui l'a chiffré et sur la machine sur laquelle le chiffrement a eu lieu.
À moins que votre but ne soit d'essayer de causer une crise cardiaque à votre équipe sécurité et d'entre autres faciliter le travail des hackers, il est conseillé de conserver les mots de passe dans les scripts chiffrés.
La fonction de chiffrement
function New-EncryptedPasswordFile #Fonction qu'il faudra appeler pour générer un fichier txt qui contiendra le mot de passe chiffré
{
[CmdletBinding()] #Déclaration des paramètres qu'il faudra fournir à la fonction pour qu'elle puisse s'exécuter
Param
(
[Parameter(Mandatory=$true)] #Indique que ce paramètre est obligatoire
[ValidateNotNullOrEmpty()] #Indique que ce champ ne peut pas être vide ou null
[string]$User, #Paramètre qui attend le nom de l'utilisateur, il n'est utilisé que pour le nom du txt de sortie ainsi n'importe quelle valeur peut être renseigné
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[securestring]$Password #Paramètre qui attend une secure string,
)
Process
{
$EncryptedPasswordPath = $PSScriptRoot + "\" + $User + "_encrypted_password.txt" #Génére dynamiquement le chemin complet du txt qui contiendra le mot de passe chiffré
$Password | ConvertFrom-SecureString | Out-File $EncryptedPasswordPath #Génére le txt qui contient le mot de passe chiffré
}
}
Exemple d'utilisation de la fonction de chiffrement
Le script suivant appelle la fonction de chiffrement lorsque lui-même est appelé
. .\New-EncryptedPasswordFile_article.ps1 #Permet de déclarer (dot source) la fonction de chiffrement pour qu'elle puisse être utilisée
New-EncryptedPasswordFile -User "Svc-test-01" #Appelle de la fonction de chiffrement et lui fournit volontairement uniquement le nom de l'utilisateur
#Le mot de passe sera demandé sous forme de secure string
Appel du script précédent
PS D:\A_folder> .\Call_me_maybe.ps1 #Appel du script précédent qui contient l'appelle de la fonction de chiffrement
cmdlet New-EncryptedPasswordFile at command pipeline position 1
Supply values for the following parameters: #La saisie du mot de passe sous forme de secure string est demandé
Password: ****
Le résultat
Le mot de passe contenu dans le fichier txt généré est chiffré
Remarque : lorsque le fichier est généré, une combinaison du compte utilisateur et du compte machine est utilisée. Cela implique que le mot de passe ne peut être déchiffré que par l'utilisateur qui l'a chiffré et sur la machine sur laquelle le chiffrement a eu lieu.
Si un jour vous souhaitez faire un état des lieux de ce qui est déjà en place en terme de partage, voici quelques liges de Powershell qui permettent de sortir la liste des OneDrive ayant un partage avec un invité.
Prenez soin de remplacer l'url de connexion au portail d'admin Sharepoint.
# Connect to Sharepoint Online
Connect-SPOService -Url https://MonTenant-admin.sharepoint.com/
# Collect all Sharepoint Sites and filter on OneDrive
$AllOneDrive = Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Url -like '-my.sharepoint.com/personal/'"
# Define variabes
$ArrayOneDriveMembers = @()
$SortOneDrive = $AllOneDrive | sort Url
$SortOneDrive | foreach {
$OneDriveUrl = $_.Url
$OneDriveOwner = $_.Owner
$OneDriveStorageQuota = $_."Storage Quota"
$OneDriveTitle = $_.Title
# Get the list of members for the current OneDrive
Try {
$OneDriveMembers = Get-SPOUser -Site $OneDriveUrl -ErrorAction stop
}
Catch {
Write-Output "$OneDriveUrl;$OneDriveTitle" | Add-Content C:\temp\Onedriveerrors.txt
}
# Define a new variable
$OneDriveExternal = $OneDriveMembers.where({$_.Usertype -eq "Guest"})
# Check if the new variable is empty, if not collect logs
If ($OneDriveExternal.count -ne 0) {
# Display some informations
Write-Host "External Users are present in $OneDriveTitle" -ForegroundColor Green
$OneDriveExternal.count
# Store Data
$OneDriveExternal | foreach {
$DisplayName = $_.DisplayName
$LoginName = $_.LoginName
$ArrayOneDriveMembers += New-Object psobject -Property @{
OneDriveUrl = $OneDriveUrl
OneDriveOwner = $OneDriveOwner
OneDriveStorageQuota = $OneDriveStorageQuota
OneDriveTitle = $OneDriveTitle
DisplayName = $DisplayName
LoginName = $LoginName
}
# Release Variables
$DisplayName = $null
$LoginName = $null
}
}
# Release variables
$OneDriveUrl = $null
$OneDriveOwner = $null
$OneDriveStorageQuota = $null
$OneDriveTitle = $null
$OneDriveMembers = $null
}
$ArrayOneDriveMembers | Export-Csv c:\temp\ExternalOneDriveMembers.csv -Encoding UTF8 -Delimiter ";" -NoTypeInformation
Lorsque vous synchronisez vos utilisateurs via "Azure AD Connect", que vos utilisateurs sont dans différents pays et que vous utilisez l'audioconférence dans Teams, il semblerait logique que vos utilisateurs se voient attribuer un numéro "locale", plutôt qu'un numéro "Français".
Pour ce faire il est important de définir le lieu d'utilisation (Usage Location) dans Azure Active Directory, il est donc important de remplir l'attribut "Country" dans votre Active Directory OnPremise.
La construction est basé sur deux lettres, vous pourrez trouver la correspondance des pays et des lettres dans le lien ci-dessous:
Attention : Vous devrez utiliser les deux lettres en majuscule de la colonne "Language Culture Name"
https://docs.microsoft.com/en-us/previous-versions/commerce-server/ee825488(v=cs.20)?redirectedfrom=MSDN
Vous pouvez fixer cet attribut à l'aide de Powershell via la commande ci-dessous (en prenant soin de remplacer "Mathieu" par le nom de votre utilisateur) :
Get-ADUser Mathieu | Set-ADUser -Replace @{‘Country’=”US”}
Ou alors en important un fichier csv pour une modification en masse, exemple de code ci-dessous.
# Import Csv and Set PreferredLanguage Attribute for each user
Import-csv C:\Temp\ToFixed.csv | foreach {
$SamAccountName = $_.SamAccountName
$Attribute = $_.Attribute
Try {
# Modifying PreferredLanguage Attribute
Set-ADUser -Identity $SamAccountName -Replace @{‘Country’=$Attribute} -ErrorAction Stop
}
Catch {
$SamAccountName | Add-Content C:\temp\ErrorUsageLocation.txt
}
# Release
$SamAccountName = $null
$Attribute = $null
}
Lorsque vous synchronisez vos utilisateurs via "Azure Ad Connect" et, que vous avez des utilisateurs dans différents pays, la langue par défaut pour chacun des utilisateurs dépend d'un attribut de votre Active Directory OnPremise, cet attribut est le "preferredLanguage".
Il devra être construit en suivant la nomenclature "Language Culture Name" du lien ci-dessous :
https://docs.microsoft.com/en-us/previous-versions/commerce-server/ee825488(v=cs.20)?redirectedfrom=MSDN
Vous pouvez fixer cet attribut à l'aide de Powershell via la commande ci-dessous (en prenant soin de remplacer "Mathieu" par le nom de votre utilisateur) :
Get-ADUser Mathieu | Set-ADUser -Replace @{‘preferredLanguage’=”en-US”}
Ou alors en important un fichier csv pour une modification en masse, exemple de code ci-dessous.
# Import Csv and Set PreferredLanguage Attribute for each user
Import-csv C:\Temp\ToFixed.csv | foreach {
$SamAccountName = $_.SamAccountName
$Attribute = $_.Attribute
Try {
# Modifying PreferredLanguage Attribute
Set-ADUser -Identity $SamAccountName -Replace @{‘preferredLanguage’=$Attribute} -ErrorAction Stop
}
Catch {
$SamAccountName | Add-Content C:\temp\ErrorPreferredLanguage.txt
}
# Release
$SamAccountName = $null
$Attribute = $null
}