PI Services

Le blog des collaborateurs de PI Services

MEM / Intune : Configurer Google Chrome à l'aide de l'ingestion ADMX

La configuration des paramètres de stratégie de Microsoft Edge dans Microsoft Intune peut être gérée par le profil de modèles d'administration déjà intégré.

Si vous souhaitez gérer les paramètres de stratégie de Google Chrome dans Microsoft Intune, ils ne sont actuellement pas disponible dans les modèle d'administration. Dans ce cas, la solution est de configurer Google Chrome avec des paramètres personnalisés pour les appareils Windows 10 et versions ultérieures dans Intune.

La configuration se passe en deux étapes :

1. Ingérer le fichier ADMX Google Chrome dans Intune

Pour ingérer le fichier ADMX, procédez comme suit :

- Téléchargez les modèles ADMX Chrome

- Connectez-vous au portail Microsoft Azure

- Accédez à Intune puis Périphériques puis Profils de configuration

- Dans la barre de commandes supérieure, sélectionnez + Créer profil

Sélectionnez un profil personnalisé (Custom) ensuite cliquez sur créer et choisissez un nom dans le menu suivant.

Dans la configuration des paramètres OMA-URI, saisissez le texte suivant :

  • Nom
    Google Chrome ADMX ingestion
  • Description
    Saisir une description (facultatif)
  • OMA-URI
    ./Device/Vendor/MSFT/Policy/ConfigOperations/ADMXInstall/Chrome/Policy/ChromeAdmx
  • Type de données
    Chaîne (à sélectionner dans la liste déroulante)

Une fois que vous avez sélectionné Chaîne, un champ de texte intitulé Valeur s'affiche en bas. Vous allez trouver le contenu de ce champ texte dans le fichier chrome.admx qui se trouve dans le fichier .zip que vous avez déjà téléchargé (modèles ADMX Chrome) sous le chemin suivant : Configuration/admx/chrome.admx.

Cliquez sur Save.

2. Définir une stratégie à l'aide d'un OMA-URI personnalisé dans Intune

Sur le même profil, on peut ajouter des OMA-URI personnalisé pour définir des stratégies de Google Chrome.

Pour ajouter des paramètres de stratégie Google Chrome, vous devez ouvrir le profil déjà créé pour ingérer l'ADMX, ensuite cliquer sur Propriétés, puis sur Modifier les Paramètres de configuration.

Dans cet exemple, nous allons ajouter un paramètre OMA-URI personnalisé afin d'autoriser les Popup dans Chrome pour "piservices.fr".

Dans le menu suivant, cliquez sur Ajouter

Dans le menu suivant, indiquez les informations suivantes :

  • Nom
    CHROME Allow Popup
  • Description
    Saisir une description (facultatif)
  • OMA-URI
    ./Device/Vendor/MSFT/Policy/Config/Chrome~Policy~googlechrome~ContentSettings/PopupsAllowedForUrls
  • Type de données
    Chaîne (à sélectionner dans la liste déroulante)
  • Valeur

    <enabled/>

    <data id="PopupsAllowedForUrlsDesc" value="1&#xF000;[*.]piservices.fr"/>a

Cliquez sur Save.

 

Sources :

Gérer le navigateur Chrome avec Microsoft Intune - Aide Google Chrome Enterprise

Configurer Microsoft Edge à l’aide de Gestion des périphériques mobiles | Microsoft Docs

Script - Invoquer un update d'un agent Trend OSC a distance

Le script ci-dessous propose d'utiliser a distance la commande "PccNTMon.exe -u" sur un agent Trend OSC pour invoquer une mise a jour, en direction de son serveur OSC de rattachement.

 

#### RemoteInvokeTrendOSCAgentUpdate.ps1: REMOTELY INITIATE AN UPDATE OF A TREND OSC AGENT ####

## COMMENT: The script execute command through PSSession and open a RDP window to allow interactive use of "OSCAgentExe -u" ###

param(
# Target Computer
$Computer = "MyTarget",
# Cred
$Cred = $(Get-Credential -Credential "MyAccount"),
# OSC Agent Folder
$OSCAgentFolder = "C:\Program Files (x86)\Trend Micro\OfficeScan Client\",
# OSC Client Process
$OSCClientProc = "PccNTMon"
)


# OSC Agent Exe
$OSCAgentExe = "$OSCAgentFolder$OSCClientProc`.exe"


# FUNCTIONS
function Set-WindowState {
	
	[CmdletBinding(DefaultParameterSetName = 'InputObject')]
	param(
		[Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
		[Object[]] $InputObject,

		[Parameter(Position = 1)]
		[ValidateSet('FORCEMINIMIZE', 'HIDE', 'MAXIMIZE', 'MINIMIZE', 'RESTORE',
					 'SHOW', 'SHOWDEFAULT', 'SHOWMAXIMIZED', 'SHOWMINIMIZED',
					 'SHOWMINNOACTIVE', 'SHOWNA', 'SHOWNOACTIVATE', 'SHOWNORMAL')]
		[string] $State = 'SHOW'
	)

	Begin {
		$WindowStates = @{
			'FORCEMINIMIZE'		= 11
			'HIDE'				= 0
			'MAXIMIZE'			= 3
			'MINIMIZE'			= 6
			'RESTORE'			= 9
			'SHOW'				= 5
			'SHOWDEFAULT'		= 10
			'SHOWMAXIMIZED'		= 3
			'SHOWMINIMIZED'		= 2
			'SHOWMINNOACTIVE'	= 7
			'SHOWNA'			= 8
			'SHOWNOACTIVATE'	= 4
			'SHOWNORMAL'		= 1
		}

		$Win32ShowWindowAsync = Add-Type -MemberDefinition @'
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
'@ -Name "Win32ShowWindowAsync" -Namespace Win32Functions -PassThru

		if (!$global:MainWindowHandles) {
			$global:MainWindowHandles = @{ }
		}
	}

	Process {
		foreach ($process in $InputObject) {
			if ($process.MainWindowHandle -eq 0) {
				if ($global:MainWindowHandles.ContainsKey($process.Id)) {
					$handle = $global:MainWindowHandles[$process.Id]
				} else {
					Write-Error "Main Window handle is '0'"
					continue
				}
			} else {
				$global:handle = $process.MainWindowHandle
			}

			$Win32ShowWindowAsync::ShowWindowAsync($handle, $WindowStates[$State]) | Out-Null
			Write-Verbose ("Set Window State '{1} on '{0}'" -f $handle, $State)
		}
	}
}




# FOR EACH COMPUTER
foreach ($Comp in $Computer) {


# Create PSSession
try
{
New-PSSession -ComputerName $Comp -Credential $Cred -Name "PSSession_$Comp" -ErrorAction Stop
}
catch
{
write-host -F Red "Error during New-PSSession `n $($Error[0].Exception)"
exit 1 
}


# Get PSsession
$RemoteSession = Get-PSSession -Name "PSSession_$Comp"


# Open RDP Session (needed because the invoke update is interactive)
cmdkey /generic:TERMSRV/$Comp /user:($Cred.UserName) /pass:($Cred.GetNetworkCredential().Password)

mstsc /v:$Comp /w:50 /h:50

Write-Host "Wait for 10 sec..."
Start-Sleep -Seconds 10


# Get the RDP process Id to kill it at the end
$ProcId = (Get-Process mstsc | Where-Object {$_.MainWindowTitle -like "*$Comp*"}).Id


# Minimize RDP Window
(Get-Process mstsc | Where-Object {$_.MainWindowTitle -like "*$Comp*"}) | foreach {Set-WindowState $_ HIDE}


Write-Host "Wait for 10 sec..."
Start-Sleep -Seconds 10



# Invoke Update
write-host "Invoking update..."
Invoke-Command -Session $RemoteSession -ScriptBlock {Start-Process -FilePath $Using:OSCAgentExe -ArgumentList "-u"} 


        # Wait while update (see for update of ofcscan.ini file)
        do {
            Write-Host "Wait while update..."
           }

        until

           (
            (Invoke-Command -Session $RemoteSession -ScriptBlock {Get-ChildItem -Path "$Using:OSCAgentFolder`ofcscan.ini" | Where-Object {$_.LastWriteTime -gt $(get-date).AddMinutes(-15)}})
           )


Write-Host "Wait for 10 sec..."
Start-Sleep -Seconds 10



# Close RDP Session
write-host "Logoff RDP Session on $Comp..."
Invoke-Command -Session $RemoteSession -ScriptBlock {`
    $CredUser = $($Using:Cred.UserName)
    $sessions = quser | Where-Object {$_ -match $CredUser} ; 
    $sessionIds = ($sessions -split ' +')[2] ; 
    Write-Host "Found $(@($sessionIds).Count) user login(s) on computer.";
    $sessionIds | ForEach-Object {Write-Host "Logging off session id [$($_)]..." ; logoff $_}
     
     }


# Close RDP Session Disconnect Window by killing process
Get-Process -Id $ProcId | stop-process


}

# Remove Pssession
Get-PSSession | Remove-PSSession

 

Active Directory – Comment afficher la clé de récupération Bitlocker

Lorsque Bitlocker est activé sur le poste de travail / ordinateur portable de votre entreprise, vous devez disposer d’une solution pour obtenir la clé de récupération du disque dur. Dans certains cas, Bitlocker peut demander à l’utilisateur la clé de récupération s’il détecte un comportement spécifique tel que des modifications de partition.

Si vous n'avez pas la solution MBAM (Microsoft BitLocker Administration and Monitoring) en place pour centraliser la gestion de Bitlocker, la solution la plus simple consiste à utiliser soit la console Utilisateurs et ordinateurs Active Directory soit la console de modification ADSI.

Cela ne peut être possible que si vous définissez dans la GPO de stocker la clé de récupération dans Active Directory.

Utilisation de la console Utilisateurs et ordinateurs Active Directory:

Pour utiliser la console Utilisateurs et ordinateurs Active Directory, il faut installer un plug-in pour afficher les informations de clé de récupération Bitlocker. Il est intégré dans les fonctionnalités depuis Windows Server 2008.

Après l’installation, fermez et ouvrez à nouveau Utilisateurs et ordinateurs Active Directory.

Un nouvel onglet est maintenant disponible sur l’objet ordinateur : Bitlocker Recovery

Utilisation de la console de modification ADSI:

Pour afficher la clé de récupération Bitlocker depuis la console de modification ADSI, il suffit d'ouvrir cette dernière avec un compte qui a les droits et chercher le nom d'ordinateur sous l'unité d'organisation cible.

Cliquez sur le nom d'ordinateur concerné, puis double-cliquez sur le dernier objet du volet droit  

Ensuite, cherchez l'attribut msFVE-RecoveryPassword pour avoir la valeur de la clé de récupération Bitlocker

Droits de délégation nécessaire pour afficher la clé de récupération Bitlocker:

Pour visualiser la clé de récupération Bitlocker, il faut avoir des droits administrateur de domaine. Sinon si vous souhaitez donner les droits nécessaires pour afficher ces informations à quelqu'un qui n'est pas administrateur de domaine, il faut lui déléguer certains droits sur l'unité d'organisation ciblée.

  • Faites un clic droit sur l’unité d’organisation ciblée et sélectionnez Delegate Control...
  • Ajoutez des groupes qui doivent afficher la clé de récupération

  • Sélectionnez Create a custom task to delegate

  • Choisissez Only the following objects in the folder: et cochez "msFVE-RecoveryInformation objects"
 

  • Donnez le contrôle total sur cet objet

Sources:

https://www.manishbangia.com/how-to-get-bitlocker-recovery-password-from-active-directory/#jp-carousel-3904 
http://www.alexandreviot.net/2015/06/10/active-directory-how-to-display-bitlocker-recovery-key/ 

Powershell : Supprimer les KB "Declined"

Quand on veut faire du ménage sur son WSUS et également dans la base de ce dernier, il peut s'avérer utile de supprimer les KB dont le statut est "IsDeclied".

Pour réaliser cela rien de plus simple que quelques lignes de Powershell et de la patience (beaucoup de patience si ça fait longtemps que cela n'a pas été fait).

Connexion

# Define Server Name
$WsusServer = "Mon-Server-WSUS"
# Define connection port
$WsusPort = "8530"

# Initiate Connection
[void][reflection.assembly]::loadwithpartialname("microsoft.updateservices.administration")
$Wsus = [microsoft.updateservices.administration.adminproxy]::getupdateserver($WsusServer,$false,$WsusPort)

# Verifying connection (Should be return the name of the wsus server)
$Wsus.name

 

Définition des Updates à supprimer

# List All Kb in WSUS database
$AllKb = $Wsus.GetUpdates()

# Filter on "IsDeclined" status
$IsDeclined = $AllKb.Where({$_.IsDeclined -eq $True})

 

Suppression des KB

# Delete KB
$IsDeclined | foreach {
    # Define Current Id
    $Id = $_.Id
    Try {
        $Wsus.DeleteUpdate($Id.UpdateId.ToString())
        }
    Catch {
        Write-Warning $($_)
        }
    # Release variable
    $Id = $null
    }

Cette commande est un peu longue mais si elle est exécutée régulièrement, la purge dure moins longtemps.

Powershell : Change the owner of my AD objects

Comme évoqué dans l'article  "Powershell : Who's the owner of my AD objects", il est possible que votre AD contienne des objets dont le propriétaire ne soit aucun des suivants :

  • "Enterprise Admins"
  • "Domain Admins"
  • "Administrators"

Afin de remettre "Domain Admins" comme propriétaire des objets, nous utiliserons Powershell pour chacun des types d'objets.

Attention : La variable $NoGood est issue des scripts du précédent article, pensez à vérifier ce qu'elle retourne au préalable.

Unités d'organisation

# Organizational Units
$NoGood | foreach {
    # Current OU
    $DistinguishedName = $_.DistinguishedName

    # Change Owner
    Try {
        # Define Target
        $TargetObject = Get-ADOrganizationalUnit -Identity $DistinguishedName
        $AdsiTarget = [adsi]"LDAP://$($TargetObject.DistinguishedName)"

        # Set new Owner
        $NewOwner = New-Object System.Security.Principal.NTAccount("DOMAINXXX", "Domain Admins")
        $AdsiTarget.PSBase.ObjectSecurity.SetOwner($NewOwner)
        $AdsiTarget.PSBase.CommitChanges()
        }
    Catch {
         Write-Warning $($_)
         $DistinguishedName
        }

    # Release variable
    $DistinguishedName = $null
    }

Les groupes

# Group
$NoGood | foreach {
    # Current Group
    $SamAccountName = $_.SamAccountName

    # Change Owner
    Try {
        # Define Target
        $TargetObject = Get-ADGroup $SamAccountName
        $AdsiTarget = [adsi]"LDAP://$($TargetObject.DistinguishedName)"

        # Set new Owner
        $NewOwner = New-Object System.Security.Principal.NTAccount("DOMAINXXX", "Domain Admins")
        $AdsiTarget.PSBase.ObjectSecurity.SetOwner($NewOwner)
        $AdsiTarget.PSBase.CommitChanges()
        }
    Catch {
        Write-Warning $($_)
        $SamAccountName
        }
    
    # Release variable
    $SamAccountName = $null
    }

Les utilisateurs

# Users
$NoGood | foreach {
    # Current User
    $SamAccountName = $_.SamAccountName

    # Change Owner
    Try {
        # Define Target
        $TargetObject = Get-ADUser $SamAccountName
        $AdsiTarget = [adsi]"LDAP://$($TargetObject.DistinguishedName)"

        # Set new Owner
        $NewOwner = New-Object System.Security.Principal.NTAccount("DOMAINXXX", "Domain Admins")
        $AdsiTarget.PSBase.ObjectSecurity.SetOwner($NewOwner)
        $AdsiTarget.PSBase.CommitChanges()
        }
    Catch {
        Write-Warning $($_)
        $SamAccountName
        }
    
    # Release variable
    $SamAccountName = $null
    }

 

Les ordinateurs

# Computers
$NoGood | foreach {
    # Current  Computer
    $SamAccountName = $_.SamAccountName

    # Change Owner
    Try {
        # Define Target
        $TargetObject = Get-ADComputer $SamAccountName
        $AdsiTarget = [adsi]"LDAP://$($TargetObject.DistinguishedName)"

        # Set new Owner
        $NewOwner = New-Object System.Security.Principal.NTAccount("DOMAINXXX", "Domain Admins")
        $AdsiTarget.PSBase.ObjectSecurity.SetOwner($NewOwner)
        $AdsiTarget.PSBase.CommitChanges()
        }
    Catch {
        Write-Warning $($_)
        $SamAccountName
        }

    # Release variable
    $SamAccountName = $null
    }

 

O365 : Forcer le changement de mot de passe

Il arrive dans certain cas de figure que nous souhaitions forcer le changement de mot de passe des comptes O365.

S'il s'agit d'un seul utilisateur voici la commande :

Set-MsolUserPassword -UserPrincipalName jdupont@mondomaine.com -ForceChangePasswordOnly $true -ForceChangePassword $true

Prenez soin de modifier le Userprincipalname de la commande sous peine d'obtenir une erreur.

 

En revanche si l'on veut forcer l'intégralité de la société à changer de mot de passe cela va nécessiter quelques lignes de plus.

# Variables
$LogFolder = "C:\temp"
$LogFile = "$LogFolder\LogO365_Reset.txt"
$LogFileError = "$LogFolder\LogO365_Reset_Error.txt"

# check
If (!(Test-Path $LogFolder)) {
    New-Item $LogFolder -ItemType Directory
    }

# Exceptions
$FilteredUsers = "Userprincipalname1", "Userprincipalname2", "Userprincipalname3" # Ajouter les UPN à ne pas reset (exemple  le compte Admin du Tenant)

# Connect to O365
Connect-MsolService

# Get users
$AllUsers = Get-MsolUser -MaxResults 10000 | select UserPrincipalName

# Force to change Password
$AllUsers | foreach {
    $UPN = $_.UserPrincipalName
    If ($FilteredUsers -eq $UPN) {
        Write-Host "Do not reset Password For $UPN because we had filtered him" | Add-Content $LogFile
        }
    Else {
        Try {
            Set-MsolUserPassword -UserPrincipalName $UPN -ForceChangePasswordOnly $true -ForceChangePassword $true
            Write-Output "Succesfully reset Password For $UPN" | Add-Content $LogFile
            }
        Catch {
            $Date = Get-Date
            Write-Warning "At $Date the following Error Appear $($_)" | Add-Content $LogFileError
            }
        }
    }

 

Bon courage au service IT pour le nombre d'appel qu'il va recevoir. 

 

O365 : Réaliser un hard match

 

Comme expliqué dans l'article précédent "O365 : Soft Match (SMTP) et Hard Match (ImmutableID)" le Hard Match intervient lorsque le Soft Match n'a pas fonctionné.

Les étapes à suivre sont les suivantes:

  1. Récupérer le GUID du compte dans l'Active Direcotry
  2. Convertir ce dernier en ImmutableID
  3. Appliqué cet ImmutableID au compte Azure Active Directory
  4. Relancer une synchronisation via Ad connect 

Voici donc les commandes pour cela.

# 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 MsolService
Connect-Msolservice

# Set ImmutableID to msoluser
Set-MsolUser -UserPrincipalName $Upn -ImmutableId $ImmutableId

 

Et voila, vous n'avez plus qu'a relancer une Synchor AD Connect via la commande suivante.

Start-ADSyncSyncCycle -PolicyType Delta

 

 

Powershell : Who's the owner of my AD objects

Lors de la création d'un objet Active Directory, un propriétaire est inscrit dans l'attribut "Security Descriptor" ce dernier dépend de "qui" a créé le compte.

 

  • Dans un AD sans délégation de droits d'administration.

Si l'utilisateur qui créé l'objet est membre du groupe :

  • "Enterprise Admins" et "Domain Admins" : Le propriétaire sera le groupe "Domain Admins"
  • "Domain Admins" : Le propriétaire sera le groupe "Domain Admins"

  • "Enterprise Admins" : Le propriétaire sera le groupe "Enterprise Admins"

  • Dans un AD avec délégation de droits d'administration.

Lorsque l'on délègue les droits de création d'objets dans Active Directory, le compte utilisé pour créer des objets sera définit comme propriétaire de ces derniers.

Si par exemple je délègue la création d'objets de type "Users" au groupe "SG-Users-Management" et que le membre "Thomas DUPONT" créé un utilisateur, ce dernier sera propriétaire de l'objet utilisateur.

Si demain "Thomas DUPONT" n'est plus membre du groupe (pour n'importe quelle raison), il ne sera plus en mesure de créer / Modifier / Supprimer d'utilisateurs (jusque la tout va bien c'est ce que l'on désire), MAIS (et oui il y en a toujours un) ce ne sera pas vrai pour tous les objets créés par "Thomas DUPONT" précédemment.

Pourquoi ?

Et bien simplement parce que ne l'oublions "Thomas DUPONT" est le propriétaire des objets qu'il a créé, par conséquent il possède par défaut le droit de lecture et modification de l'objet.

Et donc ?

Ne l'oublions pas, le droit "Modify" permet de gérer les autorisations sur un objet, par conséquent il est donc possible pour "Thomas DUPONT" de se donner un droit "Full Control" sur ces objets.

Mais alors comment on identifie ces objets ?

Voici comment vérifier qui est le propriétaire des objets présents dans Active Directory.

  • Dans Active Directory Users and Computers

Comme nous l'avons vu plus haut il est possible via la console Active Directory Users and Computers de voir qui est le propriétaire d'un objet en passant par l'onglet "Security" puis "Advanced", mais bon pour un objet à la limite mais on va pas passer tous les objets à la main, c'est la qu'entre en jeu la seconde solution "Powershell".

  • Avec powershell

 Avec Powershell, il suffit d'utiliser la commande "Get-Aduser" et de récupérer la propriété "nTSecurityDescriptor

$User = Get-ADUser mlemoine -Properties nTSecurityDescriptor

 Ok, mais on en fais quoi de ça me direz vous, c'est pas faux ça nous aide pas trop, alors complétons la commande comme suivant :

$User = Get-ADUser mlemoine -Properties nTSecurityDescriptor
$User.nTSecurityDescriptor.owner

C'est déjà mieux, mais si on vérifiait tout l'AD.

# Create Array
$Array = @()

# Collect AD infos
$Domain = Get-ADDomain | select -ExpandProperty NetBIOSName
$AllUsers = Get-ADUser -Filter * -Properties nTSecurityDescriptor

# Store Info
$AllUsers | foreach {
    $DistinguishedName = $_.DistinguishedName
    $GivenName = $_.GivenName
    $Name = $_.Name
    $ObjectClass = $_.ObjectClass
    $ObjectGUID = $_.ObjectGUID
    $SamAccountName = $_.SamAccountName
    $SID = $_.SID
    $Surname = $_.Surname
    $UserPrincipalName = $_.UserPrincipalName
    $nTSecurityDescriptor = $_.nTSecurityDescriptor
    
    
    $Array += New-Object psobject -Property @{
        DistinguishedName = $DistinguishedName
        GivenName = $GivenName
        Name = $Name
        Owner = $nTSecurityDescriptor.owner
        ObjectClass = $ObjectClass
        ObjectGUID = $ObjectGUID
        SamAccountName = $SamAccountName
        SID = $SID
        Surname = $Surname
        UserPrincipalName = $UserPrincipalName
        }
    
    $DistinguishedName = $null
    $GivenName = $null
    $Name = $null
    $nTSecurityDescriptor = $null
    $ObjectClass = $null
    $ObjectGUID = $null
    $SamAccountName = $null
    $SID = $null
    $Surname = $null
    $UserPrincipalName = $null
    $CurrentUser = $null
    $nTSecurityDescriptor = $null
    }

Bon maintenant qu'on a stocké les donnés, il faudrait les exploiter :

# How many Accounts were returns ?
Write-Host $Array.Count -ForegroundColor Yellow

# How many Accounts need to be reviewed ?
$NoGood = $Array.Where({(($_.Owner -ne "$Domain\Domain Admins") -and ($_.Owner -ne "$Domain\Enterprise Admins") -and ($_.Owner -ne "BUILTIN\Administrators"))})
Write-Host $NoGood.count -ForegroundColor Cyan

Apparement j'ai 12 comptes sur les 6031 de mon AD qui n'ont pas "Domain Admins", "Enterprise Admins" ou "Administrators" comme Owner, voyons voir cela.

$NoGood | ft Name,Owner

Ah, attention on voit bien que qu'il y a des objets liés à Exchange, je vais donc ajouter un filtre.

$Filter = $NoGood.Where({$_.Name -notlike "HealthMailbox*"})

Et voilà, je n'ai plus qu'un objet, super.

Il est possible d'appliquer la même mécanique aux éléments ci-dessous en modifiant la requête :

  • Unités d'Organisation
  • Groupes
  • Ordinateurs

 Unités d'Organisation

# Create Array
$Array = @()

# Collect AD infos
$Domain = Get-ADDomain | select -ExpandProperty NetBIOSName
$AllOU = Get-ADOrganizationalUnit -Filter * -Properties nTSecurityDescriptor

# Store Info
$AllOU | foreach {
    $City = $_.City
    $Country = $_.Country
    $DistinguishedName = $_.DistinguishedName
    $ManagedBy = $_.ManagedBy
    $Name = $_.Name
    $nTSecurityDescriptor = $_.nTSecurityDescriptor
    
    
    $Array += New-Object psobject -Property @{
        City = $City
        Country = $Country
        DistinguishedName = $DistinguishedName
        ManagedBy = $ManagedBy
        Name = $Name
        Owner = $nTSecurityDescriptor.owner
        }
    
    $City = $null
    $Country = $null
    $DistinguishedName = $null
    $ManagedBy = $null
    $Name = $null
    $nTSecurityDescriptor = $null
    }

# How many Accounts were returns ?
Write-Host $Array.Count -ForegroundColor Yellow

# How many Accounts need to be reviewed ?
$NoGood = $Array.Where({(($_.Owner -ne "$Domain\Domain Admins") -and ($_.Owner -ne "$Domain\Enterprise Admins") -and ($_.Owner -ne "BUILTIN\Administrators"))})
Write-Host $NoGood.count -ForegroundColor Cyan

 

Groupes

# Create Array
$Array = @()

# Collect AD infos
$Domain = Get-ADDomain | select -ExpandProperty NetBIOSName
$AllGroups = Get-ADGroup -Filter * -Properties nTSecurityDescriptor

# Store Info
$AllGroups | foreach {
    $DistinguishedName = $_.DistinguishedName
    $GroupCategory = $_.GroupCategory
    $GroupScope = $_.GroupScope
    $Name = $_.Name
    $ObjectClass = $_.ObjectClass
    $ObjectGUID = $_.ObjectGUID
    $SamAccountName = $_.SamAccountName
    $SID = $_.SID
    $nTSecurityDescriptor = $_.nTSecurityDescriptor
    
    
    $Array += New-Object psobject -Property @{
        DistinguishedName = $DistinguishedName
        GroupCategory = $GroupCategory
        GroupScope = $GroupScope
        Name = $Name
        ObjectClass = $ObjectClass
        ObjectGUID = $ObjectGUID
        SamAccountName = $SamAccountName
        SID = $SID
        Owner = $nTSecurityDescriptor.owner
        }
    
    $DistinguishedName = $null
    $DNSHostName = $null
    $Enabled = $null
    $Name = $null
    $ObjectClass = $null
    $ObjectGUID = $null
    $SamAccountName = $null
    $SID = $null
    $nTSecurityDescriptor = $null
    }

# How many Accounts were returns ?
Write-Host $Array.Count -ForegroundColor Yellow

# How many Accounts need to be reviewed ?
$NoGood = $Array.Where({(($_.Owner -ne "$Domain\Domain Admins") -and ($_.Owner -ne "$Domain\Enterprise Admins") -and ($_.Owner -ne "BUILTIN\Administrators"))})
Write-Host $NoGood.count -ForegroundColor Cyan

 

Ordinateurs

# Collect AD infos
$Domain = Get-ADDomain | select -ExpandProperty NetBIOSName
$AllComputers = Get-ADComputer -Filter * -Properties nTSecurityDescriptor

# Store Info
$AllComputers | foreach {
    $DistinguishedName = $_.DistinguishedName
    $GroupCategory = $_.GroupCategory
    $GroupScope = $_.GroupScope
    $Name = $_.Name
    $ObjectClass = $_.ObjectClass
    $ObjectGUID = $_.ObjectGUID
    $SamAccountName = $_.SamAccountName
    $SID = $_.SID
    $nTSecurityDescriptor = $_.nTSecurityDescriptor
    
    
    $Array += New-Object psobject -Property @{
        DistinguishedName = $DistinguishedName
        DNSHostName = $DNSHostName
        Enabled = $Enabled
        Name = $Name
        ObjectClass = $ObjectClass
        ObjectGUID = $ObjectGUID
        SamAccountName = $SamAccountName
        SID = $SID
        Owner = $nTSecurityDescriptor.owner
        }
    
    $DistinguishedName = $null
    $DNSHostName = $null
    $Enabled = $null
    $Name = $null
    $ObjectClass = $null
    $ObjectGUID = $null
    $SamAccountName = $null
    $SID = $null
    $nTSecurityDescriptor = $null
    }

# How many Accounts were returns ?
Write-Host $Array.Count -ForegroundColor Yellow

# How many Accounts need to be reviewed ?
$NoGood = $Array.Where({(($_.Owner -ne "$Domain\Domain Admins") -and ($_.Owner -ne "$Domain\Enterprise Admins") -and ($_.Owner -ne "BUILTIN\Administrators"))})
Write-Host $NoGood.count -ForegroundColor Cyan



MECM (SCCM) : Code d'erreur de séquences de tâches 0X80091007

Lors du déploiement du Master sur un ordinateur portable, la séquence de tâches SCCM a échoué avec le code d’erreur 0X80091007.

Cette séquence de tâches fonctionnait bien, mais cette erreur s’est produite sans aucune explication.

En regardant le fichier log "smsts.log" de la machine en question, il y a une ligne qui dit clairement que la séquence de tâche a échoué lors de l’installation de Microsoft Office 2013. Cependant, le package Office n'était pas corrompu. Ce problème avait donc une autre solution que la recréation du package.

Après une investigation plus approfondie du fichier log, il a révélé les erreurs ci-dessous :

Failed to run the action: Error in the task sequence.
Task Sequence Error Running: Install Microsoft Office 2013 Professional.
Install Microsoft Office 2013 Professional has failed with the error code (0x80091007).
The hash value is not correct. (Error: 80091007; Source: Windows)
For more information, please contact your system administrator or help-desk operator.

DownloadContentAndVerifyHash() failed. 80091007

En cherchant sur internet, le code d'erreur 0X80091007 se traduit par Hash Mismatch (The hash value is not correct).

Conclusion:

Il n’y avait pas de solution unique à cette erreur. Si vous rencontrez également le code d’erreur de séquence de tâches SCCM 0X80091007, essayez les solutions ci-dessous :

  • Supprimez le package du point de distribution et re-distribuez-le. C’est juste pour être sûr qu’un package valide est disponible avec le point de distribution
  • Vérifiez si la mémoire RAM installée est défaillante. Cette solution semble être la plus stupide. Mais, le remplacement de barrette RAM a résolu ce problème dans notre scénario.
  • Certaines personnes ont résolu l’erreur d’incompatibilité de hachage en désactivant la réplication différentielle binaire et en redistribuant le package à DP.

 

Dans notre scénario, problème détecté :

Barrette mémoire ram amovible défaillante. Elle est la source d’un problème de vérification de hash lors du téléchargement des sources de la séquence de tâches depuis MECM (DownloadContentAndVerifyHash() failed. 80091007)

Solution :

Enlever la barrette ram amovible et la remplacer par une nouvelle.

Script - SCCM - Endpoint Protection Info

Le script SQL ci-dessous propose de lister les détails de l'état et la configuration des antivirus Defender pour des machines gérés par SCCM.

 

/****** ALL WORKSTATIONS ENDPOINT PROTECTION DETAILS  ******/

	SELECT DISTINCT (S.ResourceID)
	,S.Name0 AS 'Machine Name'
	,AD_Site_Name0 AS 'AD Site'
	,S.Operating_System_Name_and0 AS 'Operating System'
	,CASE [EpProtected]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Protected'
	,CASE [EpAtRisk]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Computer at Risk'
	,CASE [EpNotYetInstalled]
		WHEN 1 THEN 'NOT INSTALLED'
		WHEN 0 THEN 'INSTALLED'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Installed'
	,CASE [EpUnsupported]
		WHEN 1 THEN 'UNSUPPORTED'
		WHEN 0 THEN 'SUPPORTED'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Support'
	,CASE[Inactive]
		WHEN 1 THEN 'INACTIVE'
		WHEN 0 THEN 'ACTIVE'
		ELSE 'UNKNOWN' 
		END AS 'SCCM Client Activity'
	,CASE[NotClient]
		WHEN 1 THEN 'NO'
		WHEN 0 THEN 'YES'
		ELSE 'UNKNOWN' 
		END AS 'SCCM Client'
	,CASE [AmRemediationFailed]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Failed Remediation'
	,CASE [AmFullscanRequired]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Full Scan Required'
	,CASE [AmRestartRequired]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Restart Required'
	,CASE [AmOfflineScanRequired]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Offline Scan Required'
	,CASE [AmManualStepsRequired]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Manual Scan Required'
	,CASE [AmRecentlyCleaned]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Recently Cleaned'
	,CASE [AmThreatActivity]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Threat Activity'
	,CASE [EpInstallFailed]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Failed Install'
	,CASE [EpEnforcementSucceeded]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Enforce Succeed'
	,CASE [EpEnforcementFailed]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Enforce Failed'
	,CASE [EpPendingReboot]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Pending Reboot'
	,CASE [Unhealthy]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Unhealthy'
	,CASE [SignatureUpTo1DayOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Signature Age 1 day old'
	,CASE [SignatureUpTo3DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Signature Age 3 day old'
	,CASE [SignatureUpTo7DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Signature Age 7 day old'
	,CASE [SignatureOlderThan7Days]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Signature Age over 7 day old'
	,CASE [NoSignature]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'No Signature'
	,CASE [AmPending]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware Pending'
	,CASE [LastScanUpTo2DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Last Scan 2 days old'
	,CASE [LastScanUpTo8DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Last Scan 8 days old'
	,CASE [LastScanUpTo31DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Last Scan 31 days old'
	,CASE [LastScanOver31DaysOld]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Last Scan Over 31 days old'
	,CASE [Healthy]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Healthy'
	,CASE [Active]
		WHEN 1 THEN 'ACTIVE'
		WHEN 0 THEN 'INACTIVE'
		ELSE 'UNKNOWN' 
		END AS 'Client Activity'
	,CASE [EpUnmanaged]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Not Managed'
	,CASE [EpToBeInstalled]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint To be installed'
	,CASE [EpManaged]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Managed'
	,CASE [EpInstalled]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Managed'
	,CASE [EpEnforced]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Enforced'
	,CASE [EpEnabled]
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Endpoint Enabled'
	
	,CASE AMSH.Enabled 
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'AntiMalware_Enabled'
	,AMSH.Version as AntiMalware_Version
	--,AMSH.ProductStatus
	,CASE AMSH.RtpEnabled
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'RealTime_Ptct_Enabled'
	,CASE AMSH.OnAccessProtectionEnabled -- Specifies whether the computer is monitoring file and program activity on your computer
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'OnAccess_Ptct_Enabled'
	,CASE AMSH.IoavProtectionEnabled -- Scan all downloaded files and attachments
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Downloaded_Ptct_Enabled'
	,CASE AMSH.BehaviorMonitorEnabled
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Behavior_Monitor_Enabled'
	,CASE AMSH.AntivirusEnabled
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Antivirus_Enabled'
	,CASE AMSH.AntispywareEnabled
		WHEN 1 THEN 'YES'
		WHEN 0 THEN 'NO'
		ELSE 'UNKNOWN' 
		END AS 'Antispyware_Enabled'
	,AMSH.EngineVersion
	,AMSH.LastQuickScanDateTimeStart as 'Last QuickScan DateTime Start'
	,AMSH.LastQuickScanDateTimeEnd as 'Last QuickScan DateTime End'
	,AMSH.LastFullScanDateTimeStart as 'Last FullScan DateTime Start'
	,AMSH.LastFullScanDateTimeEnd as 'Last FullScan DateTime End'
	,AMSH.LastFullScanAge as 'Last FullScan Age'
	,AMSH.LastQuickScanAge as 'Last Quick Scan Age'
	,AMSH.AntivirusSignatureUpdateDateTime as 'Antivirus Signature Update DateTime'
	,AMSH.AntiSpywareSignatureUpdateDateTime as 'AntiSpyware Signature Update DateTime'
	,AMSH.AntivirusSignatureAge as 'Antivirus Signature Age'
	,AMSH.AntispywareSignatureAge as 'Antispyware Signature Age'
	,AMSH.AntivirusSignatureVersion as 'Antivirus Signature Version'
	,AMSH.AntispywareSignatureVersion as 'Anti spyware Signature Version'
	
	FROM [CM_BIM].[dbo].[v_EndpointProtectionStatus] EPPS /*(v_EndpointProtectionStatus: Fournit un résumé de l'état des clients Endpoint Protection global pour chaque ordinateur)*/
	INNER JOIN v_R_System S on S.ResourceID = EPPS.ResourceID
	INNER JOIN v_GS_AntimalwareHealthStatus AMSH on AMSH.ResourceID = EPPS.ResourceID /*(v_GS_AntimalwareHealthStatus:  Most recent snapshot of the AntimalwareHealthStatus WMI class for each client where EndPoint Protection is installed)*/