Powershell : obtention des liens des GPO

Si la console gpmc.msc permet de parcourir toutes les GPO ainsi que leurs liens, cela n’est pas directement possible avec Powershell et la commande Get-GPO qui ne retournera que les informations de base de la GPO.

Afin de pouvoir obtenir les liens dans Powershell, il faut ruser un peu ; dans les deux scripts Powershell suivants, j’ai donc utilisé une technique de sioux consistant à réaliser un rapport au format XML de la GPO (grâce à Get-GPOReport) et à parcourir ledit fichier XML pour y identifier les liens grâce aux balises <LinksTo>.

Ce premier script liste toutes les GPO qui n’ont aucun lien, activé ou non :

Write-Host "Unlinked GPO listing script"
 Write-Host "==========================="
 Write-Host "Working… Please wait.`r`n"
 $GPOlist = Get-GPO -all
 foreach($GPO in $GPOList){
     [xml]$xmlreport = Get-GPOReport -Guid $GPO.Id -Report xml
     if($xmlreport.GPO.LinksTo.Count -eq 0){ Write-Host $GPO.DisplayName ; $count+=1}
 }
 Write-Host "`r`nUnlinked GPO count:"$count
 Write-Host "GPO parsed:"$gpolist.Length
 Write-Host "Done."

Ce deuxième script attend en paramètre le nom d’une GPO et retourne dans la console Powershell les objets auxquels cette GPO est liée. Par exemple, on appellera le script ainsi : .\win_gpolinks.ps1 -gpo « SRV-2016-Security-V3 »

Param([string]$gpoinput)
 $gpo = Get-GPO $gpoinput
 [xml]$report = Get-GPOReport -Guid $gpo.Id -Report xml
 foreach($link in $report.GPO.LinksTo){
     Write-Host $link.SOMPath
 }

A noter qu’il est nécessaire d’avoir les RSAT d’installés sur la station (si ce n’est pas un DC) depuis laquelle le script est exécuté ; il peut également être nécessaire d’appeler Import-Module GroupPolicy pour exécuter les cmdlets Get-GPO et Get-GPOReport.

Exchange et Powershell : usage des databases

Ce script renvoie le nombre de boîtes aux lettres stockées dans une database Exchange ainsi que sa taille.

Le script peut s’appeler avec le nom de la database en paramètre ; si aucun paramètre n’est spécifié, alors le script parcourt toutes les databases.

Par exemple, pour récupérer les informations sur la database DBEXCHFR1, il suffira d’appeler le script de cette manière :

.\exch_dbusage.ps1 -db dbexchfr1

Le script est téléchargeable dans une version commentée.

Param([string]$db)
if($db -eq $null) { $mbxdbs = Get-MailboxDatabase -status | select Name,DatabaseSize }
else { $mbxdbs = Get-MailboxDatabase -status | select Name,DatabaseSize | Where-Object { $_.Name -eq $db } }
foreach($mbxdb in $mbxdbs){
$mbxindb = Get-Mailbox | Where-Object { $_.Database -eq $mbxdb.Name }
Write-Host "Database"$mbxdb.Name
Write-Host "Number of mailboxes on that database:"$mbxindb.Count
Write-Host "Size:"$mbxdb.DatabaseSize`r`n
}

Powershell : extraction des mots de passe BitLocker

Comme j’en avais parlé il y a presque un an déjà dans ce billet, il est possible de configurer BitLocker pour qu’il stocke les mots de passe des volumes chiffrés dans l’ActiveDirectory, en lien avec l’objet Ordinateur correspondant.

BitLocker stocke dans l’ActiveDirectory un objet de type msFVE-RecoveryInformation ; l’objet Ordinateur est donc le père. On peut retrouver toutes les informations en ouvrant un ADSI Edit et en allant sur l’objet Ordinateur :

Les différents mots de passe ont pour canonical name une concaténation de leur date de création et de différentes propriétés.

Dans les propriétés de l’objet, on retrouve donc l’attribut msFVE-RecoveryPassword que je vais récupérer dans le script Powershell ci-dessous ; ce script génère la liste de tous les objets Ordinateur et leurs objets msFVE-RecoveryInformation associés pour ensuite écrire le contenu dans un fichier CSV. Ainsi, ce script permet de réaliser une copie de sauvegarde des mots de passe et de ce qui est nécessaire pour déverrouiller les disques chiffrés des stations jointes au domaine. Naturellement, on prendra soin de bien protéger ce fichier et son accès. Le script est téléchargeable dans une version commentée à la fin de l’article.

Requires -RunAsAdministrator
 Add-Type -AssemblyName System.Windows.Forms
 $fileExpl = New-Object System.Windows.Forms.SaveFileDialog
 $fileExpl.ValidateNames = $true
 $fileExpl.CreatePrompt = $false
 $fileExpl.OverwritePrompt = $true
 $fileExpl.RestoreDirectory = $false
 $fileExpl.InitialDirectory = "$env:userprofile"
 Write-Host "WARNING : This script will extract from your ActiveDirectory all the BitLocker recovery keys and passwords. This is CRITICAL DATA as you would not want unauthorized users to be able to unlock the protected drives. Please ensure the exported data is stored somewhere safe." -Foreground "Red"
 Write-Host "Please press ENTER to start."
 Read-Host
 $global:tempfile = "$env:temp\temp-bl.csv"
 if(Test-Path $tempfile){ Remove-Item $tempfile }
 $dump = "ComputerName,DistinguishedName,msFVE-RecoveryPassword"
 Add-Content -Value $dump -path $tempfile
 $complist = Get-AdComputer -Filter *
 foreach($comp in $complist){
     $BLInfo = Get-AdObject -Filter 'objectClass -eq "msFVE-RecoveryInformation"' -SearchBase $comp.DistinguishedName -Properties 'msFVE-RecoveryPassword'
     foreach($BL in $BLInfo){
         $dn =$BL.DistinguishedName
         $dump = $comp.Name+","+"'"+$dn+"'"+","+$BL.'msFVE-RecoveryPassword'
         Add-Content -Value $dump -Path $tempfile
     }
 }
 $fileExpl.DefaultExt = "csv"
 $fileExpl.Filter = "Comma-separated values file (.csv)|.csv"
 $fileExpl.Title = "Export data to CSV file"
 $fileExpl.Filename = ""
 $fileExpl.ShowDialog() | out-null
 if ($fileExpl.Filename -ne "") {
     Copy-Item $global:tempfile -Destination $fileExpl.Filename
     if ($?){ Remove-Item $global:tempfile ; Write-Host "Data exported to"$fileExpl.Filename }
     else { Write-Host "Couldn't save the CSV file to the specified location." ; Remove-Item $global:tempfile }
 }
 else { Remove-Item $global:tempfile ; Write-Host "Data export aborted." }

Ce fichier CSV peut ensuite être importé dans Excel par exemple, en le convertissant :

Exchange et Powershell : duplication de mailbox

Ayant remis un peu les mains sur Exchange, j’ai dû réaliser la création de multiples Equipment Mailbox ; voilà qui était donc une excellente idée de départ pour mon tout premier script Powershell pour Exchange.

Ce script permet donc de dupliquer une mailbox existante vers une autre, en gardant la quasi-totalité de ses propriétés et privilèges accordés. Ensuite, le script gère les paramètres propres aux réservations, mais il est bien évidemment possible de mettre cette portion en commentaire.

Write-Host "Equipment Mailbox Duplication Script"
 Write-Host "====================================`r`n"
 $srcmbxname = Read-Host "Source Equipment Mailbox Name or Alias"
 $srcmbx = Get-Mailbox $srcmbxname -ErrorAction Stop
 $srccal = Get-CalendarProcessing $srcmbxname -ErrorAction Stop
 $srcperm = Get-MailboxPermission $srcmbxname
 $newmbxname = Read-Host "New Equipment Mailbox Name"
 $newmbxalias = Read-Host "New Equipment Mailbox Alias"
 $newmbxaddr = Read-Host "New Equipment Mailbox Address"
 Write-Host "Creating the new mailbox…"
 New-Mailbox -Name $newmbxname -Alias $newmbxalias -UserPrincipalName $newmbxaddr -SamAccountName $newmbxalias -OrganizationalUnit $srcmbx.OrganizationalUnit -Equipment -ErrorAction Stop
 Write-Host "Copying basic mailbox properties."
 Set-Mailbox $newmbxalias -UseDatabaseRetentionDefaults $srcmbx.UseDatabaseRetentionDefaults -RetainDeletedItemsUntilBackup $srcmbx.RetainDeletedItemsUntilBackup -GrantSendOnBehalfTo $srcmbx.GrantSendOnBehalfTo -DeliverToMailboxAndForward $srcmbx.DeliverToMailboxAndForward -LitigationHoldEnabled $srcmbx.LitigationHoldEnabled -SingleItemRecoveryEnabled $srcmbx.SingleItemRecoveryEnabled -RetentionHoldEnabled $srcmbx.RetentionHoldEnabled -CalendarRepairDisabled $srcmbx.CalendarRepairDisabled -MessageTrackingReadStatusEnabled $srcmbx.MessageTrackingReadStatusEnabled -RetainDeletedItemsFor $srcmbx.RetainDeletedItemsFor -RecipientLimits $srcmbx.RecipientLimits -AntispamBypassEnabled $srcmbx.AntispamBypassEnabled -CalendarVersionStoreDisabled $srcmbx.CalendarVersionStoreDisabled -HiddenFromAddressListsEnabled $srcmbx.HiddenFromAddressListsEnabled -MaxSendSize $srcmbx.MaxSendSize -MaxReceiveSize $srcmbx.MaxReceiveSize -EmailAddressPolicyEnabled $srcmbx.EmailAddressPolicyEnabled -RequireSenderAuthenticationEnabled $srcmbx.RequireSenderAuthenticationEnabled -SendModerationNotifications $srcmbx.SendModerationNotifications -ExternalOofOptions $srcmbx.ExternalOofOptions -ProhibitSendQuota $srcmbx.ProhibitSendQuota -ProhibitSendReceiveQuota $srcmbx.ProhibitSendReceiveQuota -DowngradeHighPriorityMessagesEnabled $srcmbx.DowngradeHighPriorityMessagesEnabled -UseDatabaseQuotaDefaults $srcmbx.UseDatabaseQuotaDefaults -IssueWarningQuota $srcmbx.IssueWarningQuota -RemoteRecipientType $srcmbx.RemoteRecipientType -AuditEnabled $srcmbx.AuditEnabled -AuditLogAgeLimit $srcmbx.AuditLogAgeLimit -AuditAdmin $srcmbx.AuditAdmin -AuditDelegate $srcmbx.AuditDelegate -AuditOwner $srcmbx.AuditOwner -AcceptMessagesOnlyFromDLMembers $srcmbx.AcceptMessagesOnlyFromDLMembers -ArbitrationMailbox $srcmbx.ArbitrationMailbox -BypassModerationFromSendersOrMembers $srcmbx.BypassModerationFromSendersOrMembers -CustomAttribute1 $srcmbx.CustomAttribute1 -CustomAttribute2 $srcmbx.CustomAttribute2 -CustomAttribute3 $srcmbx.CustomAttribute3 -CustomAttribute4 $srcmbx.CustomAttribute4 -CustomAttribute5 $srcmbx.CustomAttribute5 -CustomAttribute6 $srcmbx.CustomAttribute6 -CustomAttribute7 $srcmbx.CustomAttribute7 -CustomAttribute8 $srcmbx.CustomAttribute8 -CustomAttribute9 $srcmbx.CustomAttribute9 -CustomAttribute10 $srcmbx.CustomAttribute10 -CustomAttribute11 $srcmbx.CustomAttribute11 -CustomAttribute12 $srcmbx.CustomAttribute12 -CustomAttribute13 $srcmbx.CustomAttribute13 -CustomAttribute14 $srcmbx.CustomAttribute14 -CustomAttribute15 $srcmbx.CustomAttribute15 -ExtensionCustomAttribute1 $srcmbx.ExtensionCustomAttribute1 -ExtensionCustomAttribute2 $srcmbx.ExtensionCustomAttribute2 -ExtensionCustomAttribute3 $srcmbx.ExtensionCustomAttribute3 -ExtensionCustomAttribute4 $srcmbx.ExtensionCustomAttribute4 -ExtensionCustomAttribute5 $srcmbx.ExtensionCustomAttribute5 -ModeratedBy $srcmbx.ModeratedBy -ModerationEnabled $srcmbx.ModerationEnabled -RejectMessagesFromDLMembers $srcmbx.RejectMessagesFromDLMembers -SimpleDisplayName $srcmbx.SimpleDisplayName -MailTip $srcmbx.MailTip -MailTipTranslations $srcmbx.MailTipTranslations -ErrorAction Stop
 Write-Host "Done. Now copying calendar processing properties."
 Set-CalendarProcessing -Identity $newmbxalias -AutomateProcessing $srccal.AutomateProcessing -AllowConflicts $srccal.AllowConflicts -BookingWindowInDays $srccal.BookingWindowInDays -MaximumDurationInMinutes $srccal.MaximumDurationInMinutes -AllowRecurringMeetings $srccal.AllowRecurringMeetings -EnforceSchedulingHorizon $srccal.EnforceSchedulingHorizon -ScheduleOnlyDuringWorkHours $srccal.ScheduleOnlyDuringWorkHours -ConflictPercentageAllowed $srccal.ConflictPercentageAllowed -MaximumConflictInstances $srccal.MaximumConflictInstances -ForwardRequestsToDelegates $srccal.ForwardRequestsToDelegates -DeleteAttachments $srccal.DeleteAttachments -DeleteComments $srccal.DeleteComments -RemovePrivateProperty $srccal.RemovePrivateProperty -DeleteSubject $srccal.DeleteSubject -AddOrganizerToSubject $srccal.AddOrganizerToSubject -DeleteNonCalendarItems $srccal.DeleteNonCalendarItems -TentativePendingApproval $srccal.TentativePendingApproval -EnableResponseDetails $srccal.EnableResponseDetails -OrganizerInfo $srccal.OrganizerInfo -ResourceDelegates $srccal.ResourceDelegates -RequestOutOfPolicy $srccal.RequestOutOfPolicy -AllRequestOutOfPolicy $srccal.AllRequestOutOfPolicy -BookInPolicy $srccal.BookInPolicy -AllBookInPolicy $srccal.AllBookInPolicy -RequestInPolicy $srccal.RequestInPolicy -AllRequestInPolicy $srccal.AllRequestInPolicy -AddAdditionalResponse $srccal.AddAdditionalResponse -AdditionalResponse $srccal.AdditionalResponse -RemoveOldMeetingMessages $srccal.RemoveOldMeetingMessages -AddNewRequestsTentatively $srccal.AddNewRequestsTentatively -ProcessExternalMeetingMessages $srccal.ProcessExternalMeetingMessages -RemoveForwardedMeetingNotifications $srccal.RemoveForwardedMeetingNotifications -ErrorAction Stop
 Write-Host "Done. Now setting up permissions."
 foreach($perm in $srcperm){
     if($perm.Deny.IsPresent -eq $false) { Add-MailboxPermission -Identity $newmbxalias -User $perm.User -AccessRights $perm.AccessRights }
     else { Add-MailboxPermission -Identity $newmbxalias -User $perm.User -AccessRights $perm.AccessRights -Deny }
 }
 Write-Host "All done. Successfully created mailbox"$newmbxalias

Le script est téléchargeable dans une version commentée.