PI Services

Le blog des collaborateurs de PI Services

Defender for Endpoint – Enrollment d’un client Windows 10 via un script local


Defender for Endpoint, nouveau nom de Defender ATP, représente les fonctionnalités de sécurité avancé permettant de gérer les Endpoint (PC Client, Smartphone..).

Defender for Endpoint est utilisable soit conjointement avec Endpoint Manager (Intune), soit de manière autonome en inscrivant les devices via l’utilisation d’une GPO, d’un déploiement de package SCCM ou encore l’utilisation d’un script local généré depuis la console dédiée a Defender for Endpoint: Defender Security Center.

L’exemple qui suit est celui de l’enrollment d’un client Windows 10 via l’utilisation du script local.


Depuis la console Endpoint Manager, aller sur «Sécurité du point de terminaison » puis « Installation / Microsoft Defender ATP »

image


image

Cliquer sur le lien Ouvrir la console d'administration du connecteur Microsoft Defender ATP pour ouvrir la console Defender Security Center.

image

Aller sur Settings / Device management / Onboarding


image

Selectionner Windows 10

Selectionner Local Script

Cliquer Download package


image

image

Copier le package sur la machine cible


image

image

image

Decompresser l’archive et executer le fichier WindowsDefenderATPLocalOnboardingScript.cmd avec des droits administrateur.


image

Y

image

Press any Key


Le service ‘Windows Defender Advanced Threat Protection Service’ (Sense) passe en mode de démarrage automatique.

image


L’information ci-dessous est logué dans l’eventlog Application

image


Dans le registre local, la valeur OnboardingState doit être à 1

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Advanced Threat Protection\Status

image


Afin de tester l’enrollment du client executer la commande ci-dessous dans une fenetre de commande éxécutée en tant qu’administrateur.

powershell.exe -NoExit -ExecutionPolicy Bypass -WindowStyle Hidden $ErrorActionPreference= 'silentlycontinue';(New-Object System.Net.WebClient).DownloadFile('http://127.0.0.1/1.exe', 'C:\\test-MDATP-test\\invoice.exe');Start-Process 'C:\\test-MDATP-test\\invoice.exe'


La fenêtre d’invite de commandes se ferme automatiquement. En cas de succès, le test de détection sera marqué comme terminé et une nouvelle alerte apparaitra quelques minutes plus tard dans la console Defender Security Center.

En paralelle le nouveau client apparait dans la zone Device Inventory de la console Defender Security Center.

image


En cas d’erreur, consultez le Lien : https://docs.microsoft.com/fr-fr/windows/security/threat-protection/microsoft-defender-atp/troubleshoot-onboarding (rubrique Résoudre les problèmes d’intégration lors du déploiement à l’aide d’un script)

Script – Attribution de droits utilisateur dans la Local Policy

Le script ci-dessous prend en paramètre un compte et un nom de Privilège pour l’attribution des ‘User Rights Assignment’ au niveau de la 'Local Policy' d’une machine.

LocPolicyAddUserRight.ps1 (5,75 kb)

 

#### SCRIPT: ADD NEW ACCOUNT IN USER RIGHT ASSIGNMENT OF LOCAL SECURITY POLICY

# SCRIPTNAME : LocPolicyAddUserRight.ps1

# PARAMETERS:
# User: Account to grant
# PrivilegeName : See $AccesList to select right name
# ConfFilesPath : Path to export/import Conf File

# EXAMPLE: LocPolicyAddUserRight.ps1 -User MyDomain\MyAccount -PrivilegeName SeTimeZonePrivilege -ConfFilesPath C:\



Param
(
$User,
$PrivilegeName,
$ConfFilesPath
)



#USER RIGHT ASSIGNMENT LIST

[array]$AccessList = $(
"Access Credential Manager as a trusted caller = SeTrustedCredManAccessPrivilege"
"Access this computer from the network = SeNetworkLogonRight"
"Act as part of the operating system;SeTcbPrivilege"
"Add workstations to domain = SeMachineAccountPrivilege"
"Adjust memory quotas for a process = SeIncreaseQuotaPrivilege"
"Allow log on locally = SeInteractiveLogonRight"
"Allow log on through Remote Desktop Services = SeRemoteInteractiveLogonRight"
"Back up files and directories = SeBackupPrivilege"
"Bypass traverse checking = SeChangeNotifyPrivilege"
"Change the system time = SeSystemtimePrivilege"
"Change the time zone = SeTimeZonePrivilege"
"Create a pagefile = SeCreatePagefilePrivilege"
"Create a token object = SeCreateTokenPrivilege"
"Create global objects = SeCreateGlobalPrivilege"
"Create permanent shared objects = SeCreatePermanentPrivilege"
"Create symbolic links = SeCreateSymbolicLinkPrivilege"
"Debug programs = SeDebugPrivilege"
"Deny access to this computer from the network = SeDenyNetworkLogonRight"
"Deny log on as a batch job = SeDenyBatchLogonRight"
"Deny log on as a service = SeDenyServiceLogonRight"
"Deny log on locally = SeDenyInteractiveLogonRight"
"Deny log on through Remote Desktop Services = SeDenyRemoteInteractiveLogonRight"
"Enable computer and user accounts to be trusted for delegation = SeEnableDelegationPrivilege"
"Force shutdown from a remote system = SeRemoteShutdownPrivilege"
"Generate security audits = SeAuditPrivilege"
"Impersonate a client after authentication = SeImpersonatePrivilege"
"Increase a process working set = SeIncreaseWorkingSetPrivilege"
"Increase scheduling priority = SeIncreaseBasePriorityPrivilege"
"Load and unload device drivers = SeLoadDriverPrivilege"
"Lock pages in memory = SeLockMemoryPrivilege"
"Log on as a batch job = SeBatchLogonRight"
"Log on as a service = SeServiceLogonRight"
"Manage auditing and security log = SeSecurityPrivilege"
"Modify an object label = SeRelabelPrivilege"
"Modify firmware environment values = SeSystemEnvironmentPrivilege"
"Perform volume maintenance tasks = SeManageVolumePrivilege"
"Profile single process = SeProfileSingleProcessPrivilege"
"Profile system performance = SeSystemProfilePrivilege"
"Remove computer from docking station = SeUndockPrivilege"
"Replace a process level token = SeAssignPrimaryTokenPrivilege"
"Restore files and directories = SeRestorePrivilege"
"Shut down the system = SeShutdownPrivilege"
"Synchronize directory service data = SeSyncAgentPrivilege"
"Take ownership of files or other objects = SeTakeOwnershipPrivilege"

)



Function GetUserSID($UserName)
{
(New-Object System.Security.Principal.NTAccount($UserName)).Translate([System.Security.Principal.SecurityIdentifier]).value
}




Function Parse-SecPol($CfgFile){ 
    secedit /export /cfg "$CfgFile" | out-null
    $obj = New-Object psobject
    $index = 0
    $contents = Get-Content $CfgFile -raw
    [regex]::Matches($contents,"(?<=\[)(.*)(?=\])") | %{
        $title = $_
        [regex]::Matches($contents,"(?<=\]).*?((?=\[)|(\Z))", [System.Text.RegularExpressions.RegexOptions]::Singleline)[$index] | %{
            $section = new-object psobject
            $_.value -split "\r\n" | ?{$_.length -gt 0} | %{
                $value = [regex]::Match($_,"(?<=\=).*").value
                $name = [regex]::Match($_,".*(?=\=)").value
                $section | add-member -MemberType NoteProperty -Name $name.tostring().trim() -Value $value.tostring().trim() -ErrorAction SilentlyContinue | out-null
            }
            $obj | Add-Member -MemberType NoteProperty -Name $title -Value $section
        }
        $index += 1
    }
    return $obj
}




Function Set-SecPol($Object, $CfgFile){
   $OldSecPool.psobject.Properties.GetEnumerator() | %{
        "[$($_.Name)]"
        $_.Value | %{
            $_.psobject.Properties.GetEnumerator() | %{
                "$($_.Name)=$($_.Value)"
            }
        }
    } | out-file $CfgFile -ErrorAction Stop
    secedit /configure /db c:\windows\security\local.sdb /cfg "$CfgFile" #| out-null
}



# Export Original Conf
$OldSecPool = Parse-SecPol -CfgFile "$ConfFilesPath`Old.inf"

# Get user SID
try
    {
    $newsid = GetUserSID -UserName $User
    }
catch
    {
    $Message = "'$User' user SID has not been found"
    Write-Host -F Red $Message.ToUpper()
    exit 1 
    }


# 
if ($OldSecPool.'Privilege Rights'.$PrivilegeName -eq $null)
    {
    $Message = "'$PrivilegeName' privilege has not been found. Check Name. `n "
    Write-Host -F Red $Message.ToUpper()
    Write-Host "--- ACCESS RIGHTS NAMES ---:`n"
    $AccessList
    exit 1
    }
Else
    {
    # get original value
    $OldValue = $OldSecPool.'Privilege Rights'.$PrivilegeName
    # Add new SID to the string with required additional characters
    $NewValue = $OldValue+",*$newsid"
    # Set New Value
    $OldSecPool.'Privilege Rights'.$PrivilegeName = $NewValue
    }


$result = Set-SecPol -Object $OldValue -CfgFile "$ConfFilesPath`New.inf" 

if ($result[-2] -like "*successfully*")
    {
    $Message = "OK - '$User' has been granted '$PrivilegeName' `n $($result[-2]) `n $($result[-1])"
    write-host -F Green $Message.ToUpper()
    exit 0
    }

Else
    {
    $Message = "Error during grant of rights"
    write-host -F Red $Message.ToUpper()
    $result
    exit 1
    }

 

 

 

Active Directory : Restaurer des objets de la corbeille sous 2008

Quand on a l'habitude d'utiliser la console Active Directory Administrative Center pour restaurer des objets AD et que l'on désire restaurer des objets AD sur un Active Directory sous Windows server 2008, on peut se sentir décontenancer.

Eh oui pas de console ADAC sur Windows Server 2008, bon alors on fait quoi ? Powershell !!!

Pour lister tous les objets de la corbeille :

# List All Deleted objects
$AllDeletedObjects = Get-ADObject -ldapFilter:"(msDS-LastKnownRDN=*)" –IncludeDeletedObjects -Properties *

Ensuite libre à vous de filtrer sur les types d'objets, nom et autres propriétés.

# List All Deleted Groups
$DeletedGroups = $AllDeletedObjects | Where {$_.ObjectClass -eq "group"}

Et enfin restaurer ce qui vous intéresse dans l'OU de destination qui convient (ici le groupe "GS-Office-E3" restaurer dans l'OU "RestaurationPlace")

$ToRestore = $DeletedGroups | Where {$_.Name -like "GS-Office-E3"}
$DeletedGroups | Restore-ADObject -TargetPath "OU=RestorationPlace,DC=Demo,DC=corp"

 

SCOM - Comprendre la supervision des erreurs réseau

Un client m’a récemment demandé comment fonctionnait techniquement la supervision des erreurs sur les ports réseau, et il m’a fallu un peu d’analyse pour lui fournir une réponse complète.

Commençons par le début : cette supervision est assurée par les moniteurs High Output et High Input Error Rate.

La lecture du Knowledge associé fournit quelques informations, mais reste assez floue :

This monitor enters a warning state when the percentage of output packet errors is greater than the error threshold configured for this interface (the default is 10%). The output packet error percentage is derived by dividing the number of output packets in error by the total number of output packets. The result of this calculation is expressed as a percentage and compared to the error threshold.

On y apprend donc que le moniteur réagit à un pourcentage d’erreur supérieur à 10%, et que ce taux est calculé en divisant le nombre de paquets en erreur par le nombre de paquets total.

Très bien, mais d’où proviennent ces informations ? Pour le savoir, il va falloir comme souvent aller regarder ce qui se passe dans le code.

On y constate en premier lieu que ces moniteurs ne s’appuient non pas sur deux OIDs (« nombre total de paquets » et « paquets en erreur »), mais sur 6 OIDs pour le moniteur Input et 4 OIDs pour le moniteur Output :

<OIDifHCInUcastPkts>.1.3.6.1.2.1.31.1.1.1.7.$Target/Property[Type="NetworkLibrary!System.NetworkManagement.NetworkAdapter"]/Index$</OIDifHCInUcastPkts>

<OIDifHCInMulticastPkts>.1.3.6.1.2.1.31.1.1.1.8.$Target/Property[Type="NetworkLibrary!System.NetworkManagement.NetworkAdapter"]/Index$</OIDifHCInMulticastPkts>

<OIDifHCInBroadcastPkts>.1.3.6.1.2.1.31.1.1.1.9.$Target/Property[Type="NetworkLibrary!System.NetworkManagement.NetworkAdapter"]/Index$</OIDifHCInBroadcastPkts>

<OIDifInDiscards>.1.3.6.1.2.1.2.2.1.13.$Target/Property[Type="NetworkLibrary!System.NetworkManagement.NetworkAdapter"]/Index$</OIDifInDiscards>

<OIDifInErrors>.1.3.6.1.2.1.2.2.1.14.$Target/Property[Type="NetworkLibrary!System.NetworkManagement.NetworkAdapter"]/Index$</OIDifInErrors>

<OIDifInUnknownProtos>.1.3.6.1.2.1.2.2.1.15.$Target/Property[Type="NetworkLibrary!System.NetworkManagement.NetworkAdapter"]/Index$</OIDifInUnknownProtos>



Une rapide recherché dans une base de MIB nous indique que ces OIDs remontent les valeurs suivantes :

  • Nombre de paquets Unicast
  • Nombre de paquets Multicast
  • Nombre de paquets Broadcast
  • Nombre de paquets Discarded (input seulement)
  • Nombre de paquets en Erreur
  • Nombre de paquets d’un protocole inconnu (input seulement).

Et également qu’il s’agit du nombre total de paquets transmis depuis le démarrage de l’équipement réseau.

Comment SCOM fait-il donc pour agglomérer ces données et en ressortir un pourcentage ?

Voyons maintenant un peu plus loin dans le code, du côté du module ConditionDetection System.NetworkManagement.NetworkAdapter.InputErrorRate.ifMIB.

Il repose principalement sur une ConditionDetection de type Network.Computation, qui permet des expressions assez copieuses :

clip_image002

Nous nous intéresserons ici à trois éléments en particulier, les champs DeltaValue et les expressions BranchValueExpression et Summation/Division/Product

Delta Value

Ces éléments permettent de travailler non pas sur la valeur absolue renvoyée depuis l’OID, mais plutôt sur la valeur de son augmentation depuis la mesure précédente.
Autrement dit, si le moniteur vérifie toutes les 10 minutes la valeur de l’OID et que cette dernière est d’abord « 1000 » puis, 10 minutes plus tard, « 1500 », alors la valeur de l’expression DeltaValue sera la différence entre 1500 et 1000, soit 500.

Cela permet au moniteur de superviser une variation du taux d’erreur lors du dernier intervalle de mesure uniquement, et pas en se basant sur des valeurs « diluées » depuis le démarrage du device.

 BranchValueExpression
clip_image003

Probablement le champ qui m’a donné le plus de fil à retordre, il est composé de trois sous-blocs :

<SimpleExpression>

<TrueValueExpression>

<FalseValueExpression>



Son fonctionnement est en réalité assez simple : l’expression comprise dans SimpleExpression est évaluée en premier et, en fonction de si elle est Vraie ou Fausse, le workflow continue par l’évaluation de l’expression True ou False.

Ce mécanisme est utilisé ici pour déterminer une propriété du moniteur (IsMib2SNMP) et moduler le fonctionnement en conséquence puis plus loin pour éviter les « divisions par 0 ».

Sumation/Division/Product

Ces expressions sont celles qui vont réellement produire le résultat qui nous intéresse, le taux d’erreur sur le port réseau.

Dans un premier temps, les valeurs obtenues pour toutes les OIDs (Unicast/Multicast/Broadcast/Discard/Error/Unknown) vont être additionnées (Summation) pour obtenir le total de paquets transmis :
clip_image005

Puis le nombre de paquets en erreur va être divisé (Division) par le total obtenu juste avant, et enfin cette dernière valeur sera multipliée (Product) par 100 :

clip_image007

De cette facon, on a bien comme résultat final le pourcentage de paquets en erreur lors du dernier intervalle de mesure.

Script - Modification du fichier host et test de la resolution a distance

Le script ci-dessous propose de remplacer a distance le contenu du fichier de resolution c:\windows\system32\etc\hosts et d'effectuer un test de resolution des nouveaux noms.

Remote_ModifyHostFiles_And_Test.ps1 (3,61 kb)

# SCRIPT TO MODIFY HOSTS FILE ON TARGET SERVER AND REMOTELY TEST RESOLUTION

Param(
$SrvList = ("Srv1","Srv2"),
$HostFilePath = "C:\Windows\System32\drivers\etc\hosts",
$cred = $(Get-Credential -Credential MyDomain\Me),
$Host1 = "Host1",
$IP1 = "0.0.0.1",
$Host2 = "Host2",
$IP2 = "0.0.0.2"
)


$cred = $(Get-Credential -Credential MyDomain\Me)




# host file
$hostcontent = 
"# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#	127.0.0.1       localhost
#	::1             localhost


# MY SERVERS
$Host1     $IP1
$Host2     $IP2
"


# FUNCTIONS
function Spec-Ping
{
Param($HostToPing)
Try {
            Test-Connection -ComputerName $HostToPing -Count 1 -ErrorAction Stop
            } 
            Catch [System.Net.NetworkInformation.PingException]
            {
            $pingresult = "PING ERROR TO $HostToPing - CHECK NAME RESOLVING"
            }

}


# OPENING WINRM SESSIONS ON MGS SERVERS
$SrvList | foreach {


            try
            {
            New-PSSession -Name $($_.Substring(0,13)) -ComputerName $_ -Credential $cred
            }
            catch
            {
            write-host -F red "Erreur lors de la creation de la session Winrm vers $_"
            }

}





$sessions = Get-PSSession

Foreach ($sess in $sessions)
    {
        
        Invoke-Command -Session $sess -ScriptBlock {Param($hostcontent,$HostFilePath) Set-Content -Path $HostFilePath -value $hostcontent} -ArgumentList $hostcontent,$HostFilePath
    
}



Write-Host "`n--- PING RESULT:"

Foreach ($sess in $sessions) 
    {
        
        # First Host Test
        $pingresult = Invoke-Command -Session $sess -ScriptBlock ${Function:Spec-Ping} -ArgumentList $Host1
            
            
            
             switch -Wildcard ($pingresult.value)
             {
             "PING ERROR*" {write-host -ForegroundColor red $pingresult.value}
             }
             

             Switch ($pingresult.IPV4Address.IPAddressToString)
                {
                $IP1 {Write-Host "OK -- $Host1 is resolved by "$sess.ComputerName" to $IP1"}
                default {Write-Host "KO - Unable to get resolution of $Host1 on"$sess.ComputerName""}
                }
    



        
         # Second Host Test
         $pingresult = Invoke-Command -Session $sess -ScriptBlock ${Function:Spec-Ping} -ArgumentList $Host2
         switch -Wildcard ($pingresult.value)
             {
             "PING ERROR*" {write-host -ForegroundColor red $pingresult.value}
             }
             

             Switch ($pingresult.IPV4Address.IPAddressToString)
                {
                $IP2 {Write-Host "OK -- $Host2 is resolved by "$sess.ComputerName" to $IP2"}
                default {Write-Host "KO - Unable to get resolution of $Host2 on"$sess.ComputerName""}
                }

    }     




#Remove Pssessions
Remove-PSSession *

 

 

Popup mot de passe répétitif lors de la création d'un profil Outlook 2016/365 pour se connecter à Exchange Onpremise 2016

Description

Dans les dernières mises à jour des versions Microsoft Office 2016,  lorsqu’un utilisateur ajoute un nouveau compte Exchange 2016 , il est invité à plusieurs reprises à saisir son nom d’utilisateur et son mot de passe pour aboutir finalement à un échec.

Ce problème est lié à la configuration de découverte automatique qu'Outlook utilise. Microsoft semble avoir défini Outlook pour utiliser leurs serveurs Office 365 comme point de configuration initial indépendamment de la façon dont la découverte automatique est configurée.

Résolution

La résolution consiste à définir une entrée du Registre sur l’ordinateur qui rencontre le problème ayant la valeur dessous:

[HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\AutoDiscover]
"ExcludeExplicitO365Endpoint"=dword:00000001

 

Attention: Cette modification ne doit se faire que si un compte Exchange On-Premise est utilisé.

 

 

Echec de la connexion Outlook après migration des boîtes aux lettres Exchange 2010 vers Exchange 2013/2016

Symptômes

Lorsque les boîtes aux lettres sont déplacées depuis Exchange 2010 vers Exchange Server 2013/2016, les utilisateurs ne peuvent plus accéder à leur boîtes aux lettres.

Ce problème se produit dans le scénario suivant:

  • Un utilisateur utilise généralement Outlook Anywhere pour se connecter à sa boîte aux lettres Exchange Server 2010.
  • La boîte aux lettres de l'utilisateur est déplacée vers Exchange Server 2013 ou Exchange Server 2016.
  • Une fois la boîte aux lettres déplacée et l'utilisateur tente de se connecter, le message «L'administrateur Microsoft Exchange a effectué une modification qui requiert que Microsoft Outlook soit fermé puis redémarrer » apparaît.
  • Après le redémarrage d'Outlook, le client reste déconnecté.

Cause

ce problème n’arrive pas trop souvent mais il peut être gênant: Une fois le déplacement de la boîte aux lettres terminé, Exchange Server 2013 ou 2016 continue à transmettre par proxy la demande Autodiscover à Exchange Server 2010 qui rebondit ensuite sur Exchange 2016. Il s’agit de ping-pong des demandes de reconfiguration de profil Outlook jusqu’à ce que le cache d’application de découverte automatique expire et que les informations soient actualisées.

Résolution

Le recyclage du pool d’applications actualise le cache et Outlook se connecte avec succès. Ainsi, pour résoudre ce problème, redémarrer le pool d’applications de découverte automatique sur les serveurs Exchange Server 2013 ou Exchange Server 2016 en exécutant la commande:

Restart-WebAppPool MSExchangeAutodiscoverAppPool

A noter qu'Exchange 2016 est un serveur combinant tous les rôles, mais il s’affiche comme serveur de boîtes aux lettres, ainsi, il faut redémarrer le pool Autodiscover sur chaque serveur Exchange 2016.

Dans un environnement hybride, la boite aux lettres est marquée Remote Mailbox mais elle est introuvable sur Exchange Online

Dans un environnement hybride, un utilisateur avait une boîte aux lettres Exchange Online. La BAL est marquée en tant que boîte aux lettres distante (visible sur Exchange Onpremise) mais la boîte aux lettres Office 365 n'était pas disponible. Dans ce cas, le GUID Exchange Onpremise doit être mis à jour.

Pour ce faire, les étapes ci-dessous ont été réalisées :

  • Accéder à Exchange Management Shell (Onpremise) et sauvegarder les paramètres de la BAL via la commande suivante:

Get-Mailbox "affectedUser" | fl > mailboxinfo.txt

  • Mettre à jour le GUID Exchange à Null sur la boîte aux lettres affectée via l'exécution de la commande:

Set-remotemailbox "affectedUser"  -ExchangeGuid 00000000-0000-0000-0000-0000-0000000000000000000

  • S’assurer que Exchange Guid se reflète correctement :

Get-RemoteMailbox "affectedUser"  | Fl ExchangeGuid 

Get-MailUser "affectedUser"   | fl ExchangeGuid

  • L’étape suivante consiste à supprimer la licence exchange Online, synchroniser, puis à ré ajouter la licence et vérifier l’état :

Get-Mailbox "affectedUser" | fl exchangeGuid,RecipientTypeDetails

  • Récupérer la valeur d'ExchangeGuid
  • Dans Exchange Management Shell (Onpremise), rétablir l’attribut Exchange Online GUID sur la boîte aux lettres distante Set-RemoteMailbox "affectedUser" -ExchangeGuid " ExchangeGuidRecupéré"  Puis vérifier le paramètre via la commande: Get-RemoteMailbox "affectedUser"  | Fl ExchangeGuid 

  • Dans la console Exchange Online, vérifier aussi que l'objet s'affiche en tant que boîte aux lettres utilisateur.

SCOM – Faire correctement échouer une tâche


Sous ce titre qui peut prêter à sourire se cache une fonctionnalité peu connue et finalement pas vraiment indispensable, mais qui donnera une touche un peu plus finie et professionnelles à vos management packs.

Lorsque vous exécutez une tâche basée sur un script Powershell, il peut arriver que ce dernier échoue à remplir son but pour diverses raisons. Dans ce cas, par défaut, la tâche présentera malgré tout un résultat en succès ou, au mieux, un résultat ressemblant au suivant :

clip_image002

Vous avez cependant déjà vu des tâches qui échouent « proprement », avec un symbole d’échec et le message d’erreur associé dans la sortie de la tâche.

Pour obtenir le même résultat dans vos propres développements, c’est très simple, il y a deux conditions à remplir :

- Lever une exception dans le script, via une commande Throw

- Ajouter le paramètre <StrictErrorHandling>true</StrictErrorHandling> à la WriteAction ou à la Probe utilisée dans votre tâche :
clip_image004

Et vous obtiendrez alors une sortie indiquant bien un Status Failed, avec l’icone « rouge » et le texte envoyé dans le Throw dans la sortie lorsque la tâche échoue :

clip_image006

Teams : Exporter les utilisateurs et leurs numéros

Vous souhaitez exporter la liste de vos numéros Teams et les utilisateurs associés, vous devrez utiliser les commandes SkypeOnline (et oui pas Teams...) suivantes :

# Define variable
$Domain = Read-Host -Prompt "Quel est votre domain ?"
$Csv = "C:\temp\TeamsPhoneNumbers.csv"

# Skype Online Connection
Import-Module SkypeOnlineConnector
$sessionCS = New-CsOnlineSession -OverrideAdminDomain $Domain
Import-PSSession $sessionCS

# Collect All Voice User
$AllVoiceUsers = Get-CsOnlineVoiceUser

# Export to Csv
$AllVoiceUsers | Export-Csv $Csv -Delimiter ";" -Encoding UTF8 -NoTypeInformation