PI Services

Le blog des collaborateurs de PI Services

[Powershell] - Durcissement Windows Server 2016

Ce script permet de désactiver les éléments non essentiels au serveur lors de son installation.

##################################
# Step 1 : Network configuration #
##################################
Write-Host 'Network configuration' -ForegroundColor Green
Write-Host 'WINS configuration' -ForegroundColor Gray
$Arguments = New-Object System.Collections.Hashtable
$Arguments.Add('DNSEnabledForWINSResolution', $false)
$Arguments.Add('WINSEnableLMHostsLookup', $false)

$ErrorCode = (Invoke-CimMethod -ClassName Win32_NetworkAdapterConfiguration -MethodName EnableWINS -Arguments $Arguments).ReturnValue
If ($ErrorCode -gt 0) {
	Write-Host 'Error when disabling WINS' -ForegroundColor Red
    }

############################
# Step 2 : Remove Features #
############################

Write-Host 'Features configuration' -ForegroundColor Green
$Features = @(
    'FS-SMB1'
    )
$Features | ForEach-Object { 
    $CurrentFeature = $_
    Try {
        Uninstall-WindowsFeature -Name $CurrentFeature -ErrorAction Stop
        }
    Catch {
        Write-Warning $($_)
        }
    # Release
    $CurrentFeature = $null
    }

######################################
# Step 3 : Disabling Scheduled Tasks #
######################################

Write-Host 'Scheduled Tasks configuration' -ForegroundColor Green
$ScheduledTasks = @(
    '*XblGameSaveTask*'
    '*XblGameSaveTaskLogon*'
    )
$ScheduledTasks | ForEach-Object {
    $CurrentScheduledTask = $_
    Try {
        Get-ScheduledTask -TaskName $CurrentScheduledTask | Disable-ScheduledTask -ErrorAction Stop | Out-Null
        }
    Catch {
        Write-Warning $($_)
        }
    $CurrentScheduledTask = $null
    }

################################
# Step 4: Windows Applications #
################################

Write-Host 'Windows Applications configuration' -ForegroundColor Green
$Apps = Get-AppxPackage -AllUsers | Where-Object {$_.NonRemovable -eq $false}
$Packages = Get-AppxProvisionedPackage -Online:$true

# Verifying if some Apps could be remove
If ($Apps.count -gt 0) {
    $Apps | ForEach-Object {
        $AppName = $_.Name
        Try {
            $Package = Get-AppxPackage -Name $AppName -ErrorAction Stop
            If ($Package) {
                Try {
                    # Remove App
                    Write-Host "Removing $AppName" -ForegroundColor Cyan
                    #Remove-AppPackage -Package $Package -ErrorAction Stop
                    $Package = $null
                    }
                Catch {
                    Write-Warning $($_)
                    }
                }
            Else {
                If ($Packages.Count -gt 0) {
                    # Remove the app with Online Package
                    $Package = $Packages.Where({$_.DisplayName -eq $AppName})
                    If ($Package) {
                        Try {
                            Write-Host "Removing $AppName" -ForegroundColor DarkCyan
                            Remove-AppxProvisionedPackage -PackageName $Package.PackageName -Online -ErrorAction Stop
                            }
                        Catch {
                            Write-Warning $($_)
                            }
                        }
                    }
                }
            }
        Catch {
            Write-Warning $($_)
            }
        # Release
        $AppName = $null
        }
    }

###################################
# Step 5 : OneDrive configuration #
###################################

Write-Host 'OneDrive configuration' -ForegroundColor Green
If (Get-Process -Name "*onedrive*") {
    Try {
        Get-Process -Name "*onedrive*" | Stop-Process -Force -ErrorAction Stop
        If (Test-Path -Path "$env:SystemRoot\SysWOW64\OneDriveSetup.exe") {
            Try {
                Start-Process -FilePath "$($env:SystemRoot)\SysWOW64\OneDriveSetup.exe" -ArgumentList '/uninstall' -ErrorAction Stop | out-Null
                }
            Catch {
                Write-Warning $($_)
                }
            }
        Elseif (Test-Path -Path "$env:SystemRoot\System32\OneDriveSetup.exe") {
            Try {
                Start-Process -FilePath "$($env:SystemRoot)\System32\OneDriveSetup.exe" -ArgumentList '/uninstall' -ErrorAction Stop | out-Null
                }
            Catch {
                Write-Warning $($_)
                }
            }
        }
    Catch {
        Write-Warning $($_)
        }
    }
Else {
    Write-Host "No Process OneDrive here" -ForegroundColor Cyan
    }

###################################
# Step 6 : Services configuration #
###################################

$services = @(
    'AppVClient';
    'AudioEndpointBuilder';
    'Audiosrv';
    'AxInstSV';
    'Browser';
    'bthserv';
    'CDPUserSvc';
    'CscService';
    'dmwappushservice';
    'FrameServer';
    'icssvc';
    'lfsvc';
    'lltdsvc';
    'MapsBroker';
    'NcbService';
    'NetTcpPortSharing';
    'OneSyncSvc';
    'PcaSvc';
    'PhoneSvc';
    'PrintNotify';
    'QWAVE';
    'RemoteAccess';
    'RmSvc';
    'SCardSvr';
    'ScDeviceEnum';
    'SensorDataService';
    'SensorService';
    'SensrSvc';
    'SharedAccess';
    'ShellHWDetection';
    'Spooler';
    'SSDPSRV';
    'stisvc';
    'TabletInputService';
    'tzautoupdate';
    'UevAgentService';
    'upnphost';
    'WalletService';
    'WiaRpc';
    'wisvc';
    'wlidsvc';
    'WpnService';
    'WSearch';
    'XblAuthManager';
    'XblGameSave'
    )

$services | Get-Service | Stop-Service -Force

$services | Get-Service | Set-Service -StartupType Disabled -Status Stopped

Try {
    Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NgcCtnrSvc" -Name "Start" -Value 0x4 -Force -ErrorAction Stop
    }
Catch {
    Write-Warning $($_)
    }
Try {
    Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NgcSvc" -Name "Start" -Value 0x4 -Force -ErrorAction Stop
    }
Catch {
    Write-Warning $($_)
    }
Try {
    Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\PimIndexMaintenanceSvc" -Name "Start" -Value 0x4 -Force -ErrorAction Stop
    }
Catch {
    Write-Warning $($_)
    }
Try {
    Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\UnistoreSvc" -Name "Start" -Value 0x4 -Force -ErrorAction Stop
    }
Catch {
    Write-Warning $($_)
    }
Try {
    Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\UserDataSvc" -Name "Start" -Value 0x4 -Force -ErrorAction Stop
    }
Catch {
    Write-Warning $($_)
    }
Try {
    Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\WpnUserService" -Name "Start" -Value 0x4 -Force -ErrorAction Stop
    }
Catch {
    Write-Warning $($_)
    }

$services2 = @(
    'NgcCtnrSvc';
    'NgcSvc';
    'PimIndexMaintenanceSvc';
    'UnistoreSvc';
    'UserDataSvc';
    'WpnUserService';
    )

$services2 | Get-Service | ft Name,StartType,Status

If (Test-Path -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NgcCtnrSvc_*") {
    Try {
        Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\NgcCtnrSvc_*' -Name 'Start' -Value 0x4 -Force -ErrorAction Stop
        }
    Catch {
        Write-Warning $($_)
        }
    }


If (Test-Path -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NgcSvc_*") {
    Try {
        Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\NgcSvc_*' -Name 'Start' -Value 0x4 -Force -ErrorAction Stop
        }
    Catch {
        Write-Warning $($_)
        }
    }


If (Test-Path -Path "HKLM:\SYSTEM\CurrentControlSet\Services\PimIndexMaintenanceSvc_*") {
    Try {
        Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\PimIndexMaintenanceSvc_*' -Name 'Start' -Value 0x4 -Force -ErrorAction Stop
        }
    Catch {
        Write-Warning $($_)
        }
    }


If (Test-Path -Path "HKLM:\SYSTEM\CurrentControlSet\Services\UnistoreSvc_*") {
    Try {
        Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\UnistoreSvc_*' -Name 'Start' -Value 0x4 -Force -ErrorAction Stop
        }
    Catch {
        Write-Warning $($_)
        }
    }


If (Test-Path -Path "HKLM:\SYSTEM\CurrentControlSet\Services\UserDataSvc_*") {
    Try {
        Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\UserDataSvc_*' -Name 'Start' -Value 0x4 -Force -ErrorAction Stop
        }
    Catch {
        Write-Warning $($_)
        }
    }


If (Test-Path -Path "HKLM:\SYSTEM\CurrentControlSet\Services\WpnUserService_*") {
    Try {
        Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\WpnUserService_*' -Name 'Start' -Value 0x4 -Force -ErrorAction Stop
        }
    Catch {
        Write-Warning $($_)
        }
    }

If (Test-Path -Path "HKLM:\SYSTEM\CurrentControlSet\Services\xbgm") {
    Try {
        Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\xbgm' -Name 'Start' -Value 0x4 -Force -ErrorAction Stop
        }
    Catch {
        Write-Warning $($_)
        }
    }

 

MECM : Paramètres de langue dans SUP pour Windows 11 Servicing (déploiement Feature Updates)

Contrairement aux versions précédentes de Windows, les Feature Updates de Windows 11 dans MECM Servicing nécessitent de définir toutes les langues nécessaires dans le point de mise à jour logicielle. Sinon, ils seront synchronisés mais pas téléchargés.

Configuration classique pour Windows 10

Prenant un exemple où on souhaite télécharger les Feature updates Windows 10 en Anglais, Français, Italien, Allemand et Espagnol :

--> Uniquement deux langues cochées dans la configuration SUP, mais les Feature Updates Windows 10 peuvent être synchronisés et téléchargés en plusieurs langues.

Configuration pour Windows 11

Le Windows Servicing dans MECM ne télécharge les maj d'upgrade Windows 11 que si les langues sont configurées dans SUP.

Prenant le même exemple ci-dessus (Anglais, Français, Italien, Allemand et Espagnol) :

Si on ne coche que Français et Anglais, les Feature Updates Windows 11 seront synchronisés en plusieurs langues mais ne peuvent être téléchargés que en langue française et anglaise.

Active Directory - Comment afficher les attributs LDAP non-visibles dans l'utilitaire de délégation Active Directory ?

Cela fait 1 h que vous cherchez dans l'utilitaire de délégation de permission d'Active Directory votre attribut, mais impossible de le trouver ?

Dans un premier temps, il faut savoir que les noms affichés dans cet utilitaire sont sous le format "friendly name" qui n'est pas le nom technique dit "LDAP name". Vous pouvez vous référer à l'article suivant qui fait la correspondance entre les 2 représentations pour les attributs les plus utilisés : tableau de correspondance attribut LDAP et friendly name

Si votre attribut n'est toujours pas visible, c'est parce que par défaut certains attributs sont volontairement cachés.

 

Afficher un attribut caché dans l'utilitaire de délégation Active Directory

 

Pour afficher un attribut caché dans l'utilitaire de délégation Active Directory, il faut se connecter à un contrôleur de domaine (DC) et ouvrir le fichier dssec.dat.

Par défaut, celui-ci se trouve sous C:\Windows\System32

Le fichier est divisé par type d'objet LDAP : utilisateur, ordinateur, etc.

Lorsqu'un attribut est égale à 7 l'attribut n'est pas visible dans l'utilitaire de délégation, il faut modifier la valeur à 0 pour le rendre visible.

 

Exemple sur l'attribut "st" dont le friendly name est "State/Province"

Avant :

 

Après :

 

Remarque : les modifications dans le fichier dssec.dat ne sont pas répliqués sur les autres DC, il faut donc réutiliser le même DC pour de futures modifications ou refaire les mêmes manipulations sur le nouveau DC. À noter que cela ne concerne que l'affichage dans l'utilitaire de délégation, toute modification de permission via l'utilitaire est répliquée sur l'ensemble des DC.

[Office 365] - Forcer la création de OneDrive

Par défaut lorsque vous créez un utilisateur sur Azure AD et que vous lui attribuez une licence Office (F3, E3, E5) le OneDrive n'est pas créé directement; en effet ce dernier n'est provisionné que lorsque l'utilisateur cliquera sur Onedrive lors de sa connexion.

Lorsque vous souhaitez réaliser une migration O365 ce sujet peut être une problématique, car si les Onedrive ne sont pas créés vous pourrez difficilement lancer une migration en amont.

Il est possible de contourner ce sujet en utilisant les commandes Powershell suivantes (avec les droits minimum de "SharePoint Online administrator") :

# Conect To Sharepoint Online
Connect-SPOService -Credential $Credential -Url https://XXXXX-admin.sharepoint.com

Prenez soin de remplacer l'url de connexion par la votre.

Ensuite vous pouvez soit fournir une liste d'utilisateur, soit récupérer l'ensemble des utilisateurs possédant une licence (ici nous importons une liste) et, lancer les requêtes de création.

# Import Users
$users = Import-Csv C:\Temp\Users.csv 

# Start Request
foreach ($u in $users) {
    $upn = $u.userprincipalname
    $list += $upn

    if ($i -eq 199) {
        #We reached the limit
        Request-SPOPersonalSite -UserEmails $list -NoWait
        Start-Sleep -Milliseconds 655
        $list = @()
        $i = 0
    }
}

 

[Powershell] - Etat des lieux des licences O365

Besoin d'avoir un état des lieux de vos licences O365 (voir de l'automatiser) ?

Voici quelques lignes Powershell qui vous remontrons les informations.

Prérequis:

Vous aurez besoin de:

  • Powershell 5.1
  • Le module Azure AD

Code :

Connect-AzureAD
$Array = @()
$AllSKU = Get-AzureADSubscribedSku

$AllSKU | sort SkuPartNumber | foreach {
    $SkuPartNumber = $_.SkuPartNumber
    $Bought = $_.PrepaidUnits.enabled
    $Suspended = $_.PrepaidUnits.Suspended
    $Warning = $_.PrepaidUnits.Warning
    $Assigned = $_.ConsumedUnits
    $Rest = $Bought - $Assigned

    $Array += New-Object psobject -Property @{
        License = $SkuPartNumber
        Bought = $Bought
        Assigned = $Assigned
        Will_Expired = $Warning
        Suspended = $Suspended
        Rest = $Rest
        }
    $SkuPartNumber = $null
    $Bought = $null
    $Assigned = $null
    $Warning = $null
    $Suspended = $null
    $Rest = $null
        
    }

$Array | FT License,Bought,Assigned,Will_Expired,Suspended,Rest
$Array | Export-Csv C:\temp\Licenses.csv -Delimiter ";" -Encoding UTF8 -NoTypeInformation

 

Bien entendu, pour l'automatiser il faudra modifier l'authentification et passer par de la moderne authentification (via un SPN).

Autoriser les utilisateurs non administrateurs locaux à gérer les services à distance

Une erreur de sécurité courante consiste à configurer les services pour utiliser un descripteur de sécurité trop permissif, et ainsi accorder par inattention l'accès et la gestion des services à plus d'appelants distants que prévu.

Depuis les versions Windows 10 version 1709 et Windows Server 2016 version 1709, Microsoft avait appliqué une nouvelle politique de sécurité. En vertu de cette nouvelle politique, seuls les administrateurs locaux peuvent gérer les services à distance. En effet, un nouveau paramètre de sécurité du système a été introduit qui exige que les appelants distants soient également des administrateurs locaux sur l'ordinateur pour pouvoir demander la liste des autorisation de service suivante :

  • SERVICE_CHANGE_CONFIG
  • SERVICE_START
  • SERVICE_STOP
  • SERVICE_PAUSE_CONTINUE
  • SUPPRIMER
  • WRITE_DAC
  • WRITE_OWNER

Le nouveau paramètre de sécurité requiert également que les appelants distants soient des administrateurs locaux sur l'ordinateur pour demander l'autorisation de gestionnaire de contrôle de service suivante :

  • SC_MANAGER_CREATE_SERVICE

Ce paramètre a été introduit à partir de Windows 10 version 1709 et de Windows Server 2016 version 1709. Par défaut, le paramètre est activé.

Cette nouvelle vérification peut causer des problèmes à certains clients dont les services reposent sur la possibilité pour les non-administrateurs de les démarrer ou de les arrêter à distance. Si nécessaire, vous pouvez exclure certains services de cette stratégie en ajoutant le nom du service à la valeur de registre RemoteAccessCheckExemptionList REG_MULTI_SZ à l'emplacement de registre suivant :

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurePipeServers\SCM

Pour le faire, veuillez choisir une des deux méthodes suivantes :

Méthode 1 : Par interface graphique 

  1. Dans le menu démarrer , accédez à la console regedit.exe .
  2. Recherchez et sélectionnez la sous-clé suivante dans le Registre :

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurePipeServers\SCM

    Remarque 
     Si la sous-clé n'existe pas, vous devez la créer : Dans le menu Edition , sélectionnez  Nouveau , puis sélectionnez  Clé . Tapez le nom de la nouvelle sous-clé, puis appuyez sur Entrée.
  3. Dans le menu Edition , pointez sur Nouveau , puis sélectionnez  Valeur REG_MULTI_SZ .
  4. Tapez RemoteAccessCheckExemptionList  pour le nom de la valeur REG_MULTI_SZ, puis appuyez sur ENTRÉE.
  5. Double-cliquez sur la valeur RemoteAccessCheckExemptionList , saisissez le nom du service à exempter de la nouvelle stratégie, puis cliquez sur OK .
  6. Quittez l'Éditeur du Registre, puis redémarrez l'ordinateur.

Méthode 2 : Par commandes PowerShell

#récuperer le contenu de la clé de registre
$services = (Get-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\SecurePipeServers\SCM).RemoteAccessCheckExemptionList

#définir la liste des services à exclure de la politique de sécurité
$newservices= 'spooler','LPDSVC' 

#ajouter la nouvelle liste de services
foreach ($newsvc in $newservices)
{
$services += $newsvc +" "
}

#reconfigurer la clé de registre
Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\SecurePipeServers\SCM -Name RemoteAccessCheckExemptionList -Value $services -Type Multistring 


 

Script - API Vmware VCenter v7 - Get VM infos

Une mise a jour du script proposé récemment, utilisant la nouvelle version de l'API de Vcenter.

 

### QUERY VCENTER REST API (v7) TO GET VM LIST ###


$user = ‘myaccount’
$pswd = Read-Host -Prompt "Enter Password"
$vCenterName = ‘MyVcenter’
$encoded = [System.Text.Encoding]::UTF8.GetBytes(($user, $pswd -Join ‘:’))
$encodedPassword = [System.Convert]::ToBase64String($Encoded)
$authHeader = @{
Authorization = "Basic $($EncodedPassword)"
}
$sRest = @{
Method = ‘Post’
Uri = "https://$($vCenterName)/api/session"
Headers = $authHeader
}
$result = Invoke-RestMethod @sRest


# Get TokenID
$authHeader = @{
‘vmware-api-session-id’ = $result.value
}


# Get All Hosts
$gethosts = "https://$($vCenterName)/api/vcenter/host"
$resultgethost = Invoke-RestMethod -Uri $gethosts -Headers $authHeader
$hostidlist = $resultgethost.value.host


# For each host, get all VMs

foreach ($hostid in $hostidlist)
{
$get_vm = "https://$($vCenterName)/rest/vcenter/vm?filter.hosts=$hostid"
$resultvm = Invoke-RestMethod -Uri $get_vm -Headers $authHeader
[array]$FinalTableau += $resultvm
}

# Display Result
$FinalTableau.value | select name,power_state


# Output to CSV
$CsvTab = $FinalTableau.value | select name,power_state | ConvertTo-Csv -Delimiter ';' -NoTypeInformation
$CsvTab | Out-File .\VMList.csv

 

 

Exchange hybride : Impossible de partager le calendrier "tous les détails" et "détails limités" à partir d'Outlook

Problème

Lorsqu'un utilisateur On premises tente de partager son calendrier avec un utilisateur Office 365, il reçoit le message d’erreur suivant :

Cause

Ce problème se produit si la stratégie de partage n’autorise pas l’utilisateur à partager le niveau de détails que l’utilisateur a défini dans l’invitation de partage.

Solution

Pour résoudre ce problème, suivez les étapes suivantes :

  1. Ouvrez le Centre d’administration Exchange, cliquez sur Organization --> Sharing
  2. Double-cliquez sur "Default Sharing Policy (DEFAULT)"
  3. Cette règle indique que vous ne pouvez partager que l'autorisation « Disponibilité uniquement » avec les autres organisations.

    Vous pouvez soit modifier la règle de partage  « Toutes les informations de calendrier, notamment l'heure, l'objet, l'emplacement et le titre » pour tous les domaines

  4. Ou vous créez une nouvelle règle de partage pour votre domaine smtp qui est partagé dans Office 365 et attribuez "Toutes les informations de calendrier, notamment l'heure, l'objet, l'emplacement et le titre". 
  5. Cliquez ensuite sur "Enregistrer"

Erreur MSExchange Autodiscover_Event ID 1

Dans Exchange 2016, vous remarquerez des messages d'erreurs  "MSExchange Autodiscover" avec l'Event ID 1 dans le journal des événements d'application du serveur :

 

Ce problème a été résolu dans Exchange 2016 CU15 et Exchange 2019 CU4, mais apparaît parfois dans des versions plus récentes.

Il s'agit d'un problème connu chez Microsoft et la solution de contournement est simple:

  • Définissez la propriété ExternalURL du répertoire virtuel Autodiscover, comme ceci:

Get-AutodiscoverVirtualDirectory -Server | Set-AutodiscoverVirtualDirectory -ExternalUrl https://autodiscover.contoso.com/Autodiscover/Autodiscover.xml

Exchange Hybride_Configuration TLS pour les connecteurs de réception

Si vous souhaitez utiliser TLS ou utilisez l'authentification TLS dans un environnement Office 365 hybride ou encore vous avez modifié ou renouvelé manuellement le certificat SSL, vous pouvez toujours obtenir des erreurs indiquant que vous ne pouvez pas lancer la session TLS (STARTTLS), même si le certificat SSL a été correctement renouvelé.

Il ne suffit pas de définir le certificat SSL à utiliser avec SMTP pour que TLS fonctionne correctement. Vous devez également (re)configurer le nom du certificat TLS sur vos connecteurs de réception.

Pour formater correctement le contenu du TlsCertificateName, vous pouvez l'extraire du certificat via des commandes ci-dessous.

  • Dans un environnement Exchange Management Shell, récupérez les certificats actuels :

Get-ExchangeCertificate

  • Vous obtiendrez une liste de tous les certificats, mais vous n'aurez besoin que de celui à utiliser pour TLS, que vous pouvez extraire en spécifiant son empreinte :

$cert = Get-ExchangeCertificate -Thumbprint DE67EC3C8D679DC35D171341FEC5148D012B1BAE2

  • À partir de la variable précédemment créée, vous pouvez maintenant compiler la valeur pour le nom du certificat TLS :

$tlscertificatename = "<i>$($cert.Issuer)<s>$($cert.Subject)"

  • Avec la nouvelle variable, vous pouvez maintenant changer chaque connecteur de réception en activant le TLS et modifiant le nom du certificat TLS :
    Set-ReceiveConnector "Inbound from Office 365" -RequireTLS $True -TlsCertificateName $tlscertificatename