9 sept. 2015

[Howto] Mémoriser le mot de passe Exchange dans Outlook une bonne fois pour toutes !

Dans d'obscures conditions, Outlook 2007, 2010 ou 2013 peuvent demander sans cesse le mot de passe du compte Exchange. Parfois juste après l'avoir validé, il réitère la demande.

Soit les conditions et symptômes suivants :
- Le compte de messagerie est un compte Exchange
- Le problème persiste en RPC ou HTTPS
- Avec OWA il n'y a pas de problème
- Même en cochant Mémoriser le mot de passe, le problème persiste
- Pour Outlook 2013, même en supprimant l'entrée Outlook15 dans le gestionnaire d'identification de Windows 7 ne corrige pas le problème

Outlook affiche une clé en bas à gauche Mot de passe requis.


Pourtant, si on clique sur Annuler, il ne pose plus la question pour un moment (à priori jusqu'au prochain cycle d'Envoyer/recevoir défini dans Définir les groupes d'envoi/réception). Et tout fonctionne correctement : l'envoi, la réception, les tâches, les calendriers, le carnet...

Solution :

Il suffit de créer la clé (s'il elle n'existe pas déjà de registre suivante :
HKEY_CURRENT_USER\Software\Microsoft\Office\XX.0\Outlook\RPC (où XX correspond à votre version de Microsoft Office) et de créer un DWORD UseWindowsUserCredentials avec la valeur 1.

État du registre après application de la solution


Relancez Outlook.



[snippet] Comment s'approprier rapidement des profils itinérants ?

Vous voulez vous approprier tous les profils itinérants Windows XP ? Mais si vous faites ça, les utilisateurs n'auront plus accès à leur profils itinérant et obtiendrons une erreur à l'ouverture de session.
Le profil itinérant possède une ACL NTFS qui indique que l'utilisateur du profil est le propriétaire du répertoire et des fichiers. L'administrateur ne peut pas accéder à ces fichiers, car il ne figure pas dans l'ACL par défaut. Une GPO existe pour rajouter le groupe Administrateurs dans l'ACL à la création du répertoire, mais admettons que cette GPO ne s'applique pas ou a été créée après les répertoires.
Le but du jeu est d'ajouter le groupe Administrateurs dans l'ACL de chaque répertoire. Or, pour modifier une ACL, il faut pouvoir y accéder, ce qui n'est pas le cas... La seule façon est de s'approprier le répertoire (ce qui va remplacer l'ACL existante par une ACL vierge, avec pour seule entrée le nouveau propriétaire). En faisant cela, les utilisateurs n'auront donc plus le droit d'accéder à leur propre profil. Il faut rajouter l'utilisateur dans l'ACL en contrôle total, et ce, récursivement pour les fichiers existants.

Attention : pour que Windows autorise de charger un profil itinérant, même si l'utilisateur a un contrôle total sur tous ses fichiers, il faut que le propriétaire du répertoire soit : soit le compte utilisateur soit le groupe Administrateurs. S'il s'agit d'un autre compte, même le compte Administrateur, le chargement échouera.

Voici le script powershell :

# répertoire à scanner
$dir = "D:\profils"

$profils = Get-ChildItem -Path $dir -Force -ea 0

$profils | ForEach-Object {
    $rep = $_
    if($rep.Mode.startsWith('d')) { # on ignore les fichiers
        $user = $_.Fullname.Split('\')[2]
        $owner = $acl = $null
        $acl = $rep.GetAccessControl()
        $owner = $acl.Owner
        if($owner -ne 'BUILTIN\Administrateurs' -and $owner -ne 'BUILTIN\Administrators') { # le propriétaire n'est pas déjà administrateur, on ne fait rien
            echo "$user MAUVAIS OWNER!"
        }
        else {
            $found =  $false
            $acl.Access|Where-Object{$_.IdentityReference.ToString() -ieq $user}|ForEach-Object{$found=$true} # on vérifie si le répertoire possède déjà l'ACL...
            if($found) {
                Write-Host -fore gray "$user have rights ($owner)"
            }
            else {
                write-host -fore blue "Il faut ajouter DOMAINE\$user."
                $NTuser = New-Object System.Security.Principal.NTAccount("DOMAINE\$user")
                $access = [System.Security.AccessControl.FileSystemRights]::FullControl
                $heritage = [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit
                $heritagefile = [System.Security.AccessControl.InheritanceFlags]::None
                $propa = [System.Security.AccessControl.PropagationFlags]::None
                $allow = [System.Security.AccessControl.AccessControlType]::Allow
                $ace = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAINE\$user",$access,$heritage,$propa,$allow) # on cré une ACE pour répertoire
                $acefile = New-Object System.Security.AccessControl.FileSystemAccessRule("DOMAINE\$user",$access,$heritagefile,$propa,$allow) # on cré une ACE pour les fichiers
                $acl.AddAccessRule($ace)
                if(!$?) {
                    echo "Impossible de créer l'ACL"
                }
                else { # l'ACL est OK, on l'applique
                    $rep.SetAccessControl($acl)
                    if($?) { # on répète récursivement aux fichiers et répertoires déjà existants
                        echo "Appropriation récursive de $($rep.Fullname)."
                        $aclfile = $null
                        Get-ChildItem -Path $rep.FullName -Force -Recurse | ForEach-Object {
                            if($_.Mode.StartsWith('d')) { # répertoire...
                                $_.SetAccessControl($acl)
                            }
                            else { # fichier...
                                $aclfile = $_.GetAccessControl() # doit recréer l'ACL à chaque fois pour les fichiers
                                $aclfile.AddAccessRule($acefile)
                                $_.SetAccessControl($aclfile)
                            }
                        }
                        Write-Host -fore green "`r`n$user : OK"
                    }
                    else {
                        Write-Host -fore red "`r`n$user : ERR"
                    }
                }
            }
        }
    }
}

Il est utile pour l'administrateur d'avoir accès au contenu des profils pour vérifier les abus de stockage de fichiers (notamment car le contenu du profil est "streamé" à l'ouverture de la session, contrairement au contenu d'un lecteur réseau ou d'une redirection de Mes documents).

7 sept. 2015

[snippet] Méthode d'extension C# ToTuple

J'ai eu besoin d'exporter sous la forme d'un tableau d'objet certaines colonnes résultantes d'une expression LINQ.
Mon objectif était de sérialiser le résultat en JSON avec JavascriptSerializer avec un tableau non-associatif (pas de paire clé-valeur).

public static object[] ToTuple<T, U, V>(this 
IEnumerable<T> queryable, Func<T, U> t1)
        {
            List<object[]> tab = new List<object[]>();
            foreach (var e in queryable)
                tab.Add(new object[] { t1.Invoke(e) });
            return tab.ToArray();
        }  
 
//...
 
public static object[] ToTuple<T, U, V, W, X, Y, Z>(this 
IEnumerable<T> queryable, Func<T, U> t1, Func<T, V> 
t2, Func<T, W> t3, Func<T, X> t4, Func<T, Y> t5, 
Func<T, Z> t6)
        {
            List<object[]> tab = new List<object[]>();
            foreach (var e in queryable)
                tab.Add(new object[] { t1.Invoke(e), t2.Invoke(e), t3.Invoke(e), t4.Invoke(e), t5.Invoke(e), t6.Invoke(e) });
            return tab.ToArray();
        } 

Ces méthodes sont à ajouter dans des classes statiques pour être utilisables.
Note : on pourrait retourner un Tuple<U,V...>[] à la place de object[], mais la sérialisation serait associative avec les clés Item1, Item2...