PowerShell

On-prem

Run as other user

start powershell -Credential «  »

Identifier les dépendances d’un module

Import-Module -Verbose -Force « Az.Storage »

Installation manuelle d’un module

Il m’est récemment arrivé de ne pas pouvoir télécharger un module PowerShell à cause d’un Proxy bloquant les flux d’installation.
La première étape consiste à télécharger puis extraire le fichier.
https://www.it-connect.fr/installer-un-module-powershell-a-partir-dun-fichier-nupkg/

Rechercher PARAMS d’une commande

PowerShell Cmdlets: List all availabe parameters without using the Help – SID-500.COM

VSCODE – ps5 et 7

Pour avoir PS5 et 7 sur son vscode
Ouvrir le dossier contenant le fichier setting.json, à savoir %APPDATA%\Code\User\

Intégrer le code suivant dans les brackets { } déjà existants

    "terminal.integrated.defaultProfile.windows": "Command Prompt",
    "terminal.integrated.profiles.windows": {
        "PowerShell 5": {
            "path": [
                "${env:windir}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
            ],
            "args": [],
            "icon": "terminal-powershell"
        },
        "Command Prompt": {
            "path": [
                "${env:windir}\\Sysnative\\cmd.exe",
                "${env:windir}\\System32\\cmd.exe"
            ],
            "args": [],
            "icon": "terminal-cmd"
        },
        "PowerShell": {
            "source": "PowerShell",
            "icon": "terminal-powershell"
        },
        "Git Bash": {
            "source": "Git Bash"
        }
    },

Source : Add PowerShell 5 to Integrated Shell profiles · Issue #128728 · microsoft/vscode · GitHub

PowerShell CMD GNRL

Get-Help ou CTRL+SPACE

Pour rechercher les paramètres d’une commande, on peut utiliser le Get-Help
Ou sinon, commencer à taper le « – » du paramètre, puis faire CTRL+ESPACE

Type de variable

Pour identifier un type de variable

$x = 10 
$x.GetType()

Do while / DO until

Do While fonctionne jusqu'à ce que la condition soit vraie. Quand la condition est fausse, la boucle se termine.

Do Until fonctionne jusqu'à ce que la condition soit fausse. Quand la condition est vraie, la boucle se termine.

Ajouter plusieurs valeurs dans une variable

$array = @()
foreach ($attribute in $attributes){
$projname = $attribute.ProjectName
$size = $attribute.Size
$array += "The $projname project uses $size GB"
}
$body = $array -join "`n"

Mettre dans une liste

$ErrorFinded = @()
foreach ($blockedmail in $RetiredList.mail) {
foreach ($controledmail in $Report.Sender) {
if ($blockedmail -like $controledmail) {
$ErrorFinded += « $blockedmail »
}
}
}
OU
$ErrorFinded = [System.Collections.Generic.List[Object]]::new()
foreach ($blockedmail in $RetiredList.mail) {
foreach ($controledmail in $Report.Sender) {
if ($blockedmail -like $controledmail) {
#$ErrorFinded += « $blockedmail »
$rec = [pscustomobject]@{
blockedmail = $blockedmail
}
$ErrorFinded.add($rec)
}
}
}

Recherche d’un caractère dans un répertoire

Get-ChildItem "D:\Scripts*" -Recurse | Select-String -Pattern "extensionAttribute1"

Ajouter des 0 en début de nom

$number = 0
$file = « http://lurldontonveutlafin/6761_32/2 »
$name = $file.Split(« / »)[4]
$fullname = ‘{1:00000}{0}’ -f $data,($number++)
write-host $fullname

Création de fichiers (taille 20 Mo)

function New-File {
param( [string]$FilePath,[double]$Size )
$file = [System.IO.File]::Create($FilePath)
$file.SetLength($Size)
$file.Close()
Get-Item $file.Name
}
For ($i=0; $i -lt 3; $i++) {
$files = "C:\Users\xx\test\file"+$i+".txt"
New-File -FilePath $files -Size 20mb
}

PowerShell AD

Extraction des postes Windows10 1909

Get-ADComputer -Filter {(operatingSystemVersion -eq "10.0 (18363)") -and (Enabled -eq $true)} -Properties * | Select-Object Name,operatingSystemVersion,whenCreated,@{n="lastLogonDate";e={[datetime]::FromFileTime($_.lastLogon)}} | Export-CSV C:\Temp\20202206-1909.csv -NoTypeInformation -Encoding Unicode

Test d’un mot de passe

function Test-ADCrential{
[CmdletBinding()]
param(
[pscredential]$Credential
)
try {
Add-Type -AssemblyName System.DirectoryServices.AccountManagement
if(!$Credential) {
$Credential = Get-Credential -EA Stop
}
if($Credential.username.split("\").count -ne 2) {
throw "You haven't entered credentials in DOMAIN\USERNAME format. Given value : $($Credential.Username)"
}
$DomainName = $Credential.username.Split("\")[0]
$UserName = $Credential.username.Split("\")[1]
$Password = $Credential.GetNetworkCredential().Password
$PC = New-Object System.DirectoryServices.AccountManagement.PrincipalContext([System.DirectoryServices.AccountManagement.ContextType]::Domain, $DomainName)
if($PC.ValidateCredentials($UserName,$Password)) {
Write-Verbose "Credential validation successful for $($Credential.Username)"
return $True
} else {
throw "Credential validation failed for $($Credential.Username)"
}
} catch {
Write-Verbose "Error occurred while performing credential validation. $_"
return $False
}
}
Test-ADCrential

PowerShell M365/AAD

Volumétrie

Volumétrie des OneDrive

#Variable for SharePoint Online Admin Center URL
$AdminSiteURL="https://xxx-admin.sharepoint.com"
$CSVFile = "C:\Temp\OneDrives.csv"
#Connect to SharePoint Online Admin Center
Connect-SPOService -Url $AdminSiteURL -credential (Get-Credential)
#Get All OneDrive Sites usage details and export to CSV
Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Url -like '-my.sharepoint.com/personal/'" | Select URL, Owner, StorageQuota, StorageUsageCurrent, LastContentModifiedDate

Possible aussi via l’interface graphique : https://learn.microsoft.com/en-us/microsoft-365/admin/activity-reports/onedrive-for-business-usage-ww?view=o365-worldwide

Volumétrie des BAL

Get-Mailbox -ResultSize Unlimited | where {((($_.PrimarySmtpAddress -match "domain.com") -and ($_.RecipientTypeDetails -eq "UserMailbox"))} | Get-MailboxStatistics |Select DisplayName,@{name="TotalItemSize (MB)"; expression={[math]::Round(($_.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",","")/1MB),2)}},ItemCount | Sort "TotalItemSize (MB)" -Descending | export-csv C:\temp\sizeallmailbox.csv -encoding unicode -notypeinformation -delimiter ";"

Volumétrie des BAL partagées

Get-Mailbox -ResultSize Unlimited | where {($_.RecipientTypeDetails -eq "SharedMailbox")} | Get-MailboxStatistics |Select DisplayName,@{name="TotalItemSize (MB)"; expression={[math]::Round(($_.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",","")/1MB),2)}},ItemCount | Sort "TotalItemSize (MB)" -Descending | export-csv C:\temp\2022-10-18-sizesharedmailbox.csv -encoding unicode -notypeinformation -delimiter ";"

Autres

Ajouter un ensemble d’utilisateurs sur un SharePoint

$SiteURL = "https://xxx.sharepoint.com/sites/EXTxxx"
$GroupName="xxx"
$UserLoginID = $mail
Add-PnPGroupMember -LoginName $UserLoginID -Identity $GroupName

Retirer un utilisateur en cache sur un SharePoint

Install-Module -Name PnP.PowerShell
Connect-PnPOnline -url "https://xxx" -Credentials $psCred
Get-pnpuser | where {$_.Title -match "sonprenom"}
Remove-PnpUser -Identity {lenumerod'ID}

Litigation Hold (multiples mailbox)

#Placer en Litigation Hold un ensemble de boites mails :
Import-CSV C:\temp\xxx.csv -delimiter ";" | foreach-object {
$Email = $_.EMail
Set-Mailbox $Email -LitigationHoldEnabled $True
}

Lister les API sur le tenant

$applist = Get-MsolServicePrincipal -all |Where-Object -FilterScript { ($_.DisplayName -notlike "Microsoft") -and ($_.DisplayName -notlike "autohost") -and ($_.ServicePrincipalNames -notlike "localhost*") }

foreach ($appentry in $applist) {
   $principalId = $appentry.AppPrincipalId
   $principalName = $appentry.DisplayName
   Get-MsolServicePrincipalCredential -AppPrincipalId $principalId -ReturnKeyValues $false | ? { $_.Type -eq "Password" } | % { "$principalName;$principalId;" + $_.KeyId.ToString() +";" + $_.StartDate.ToString() + ";" + $_.EndDate.ToString() } | out-file -FilePath c:\temp\appsec-2022xxx.txt -append
}

Trace des messages

Get-MessageTrace -RecipientAddress "xxx@domain.com" -StartDate "07/10/2022" -EndDate "07/19/2022" | where {$_.'Sender Address' -notlike "domain.com"}

Ajout d’un ensemble de domaine dans une règle anti-spam

$emails = "C:\temp\domain-spoofing.txt"
$count = 1
foreach ($content in ($total = get-content $emails)){
$totalcount = $total.count
Set-HostedContentFilterPolicy -Identity "Anti-spam inbound policy (REQ00XXXX)" –BlockedSenderDomains @{add=$content}
write-host "Added $count entries of $totalcount : $content"
$count += 1
}

Boites mails avec des redirections

Get-Mailbox -ResultSize Unlimited | where {$_.ForwardingAddress -ne $null -or $_.ForwardingSMTPAddress -ne $null} | Select UserPrincipalName,ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward | export-csv C:\temp\ForwardingSmtpAddress.csv -NoTypeInformation -Encoding Unicode

Restauration d’une boite mail sans le calendrier

#Voir les folders
Get-MailboxFolderStatistics -Identity "xxx@domain.com" | Select FolderPath
#Retrait des évènements du calendrier
Remove-CalendarEvents -Identity xxx@domain.com -CancelOrganizedMeetings -QueryWindowInDays 360
#Migration des mails sans le Calendrier
New-MailboxRestoreRequest -Name "Restore_$NouveauSSO-1" -SourceMailbox $Ancien_Exchange_GUID -TargetMailbox $Nouveau_Exchange_GUID -AllowLegacyDNMismatch -TargetRootFolder "Mailbox_xxx" -ExcludeFolders "#Calendar#"

#Migration des mails en incluant uniquement certains dossiers
New-MailboxRestoreRequest -Name "Restore_$NouveauSSO" -SourceMailbox $Ancien_Exchange_GUID -TargetMailbox $Nouveau_Exchange_GUID -AllowLegacyDNMismatch -TargetRootFolder "Mailbox_XXX" -TargetIsArchive -includefolders “#Inbox,SentITems,DeletedItems#”

Vider le contenu d’une boite mail

Search-Mailbox -Identity "<MailboxOrMailUserIdParameter>" -EstimateResultOnly
​​Search-Mailbox -Identity "<MailboxOrMailUserIdParameter>" -DeleteContent -force

Membres d’une liste de distribution dynamique

Get-Recipient –RecipientPreviewFilter (Get-DynamicDistributionGroup –Identity "Office 365 for IT Pros Writers").RecipientFilter

Trace message

(Get-MessageTrace -RecipientAddress "xxx@domain.com" -StartDate "07/10/2022" -EndDate "07/19/2022" | Where-Object -Property SenderAddress -NotLike "@domain").count

Extractions

Extraction des comptes Cloud (sans les invités)

Get-MsolUser -All | Where-Object {($_.lastdirsynctime -eq $null) -and ($_.UserPrincipalName -notmatch "#EXT#")} | Select DisplayName,UserPrincipalName,isLicensed,@{n="Licenses Type";e={$_.Licenses.AccountSKUid}},@{N="LastLogonDate";E={(Get-MailboxStatistics $_.UserPrincipalName).LastLogonTime}} | Export-CSV C:\Temp\clouduser.csv -Encoding Unicode -NoTypeInformation -Delimiter ";"

Extraction de tous les groupes d’un utilisateur

foreach ($Group in (Get-MsolGroup -all)) {if (Get-MsolGroupMember -all -GroupObjectId $Group.ObjectId | where {$_.Emailaddress -eq "xxx@domain.com"}) {$Group.Displayname}}

Extraction des utilisateurs avec licence E3

Get-MsolUser -all | Where-Object {(($_.licenses).AccountSkuId -contains "domainname:ENTERPRISEPACK")} | Select-Object UserPrincipalName,BlockCredential,LastDirSyncTime

Extraction de l’activité des utilisateurs

#########################
###### 1ère partie ######
#########################
#Connexion via une API
$ApplicationID = "xx"
$TenantDomainName = "xx"

$AccessSecret = "xx"
$Body = @{    
Grant_Type    = "client_credentials"
Scope         = "https://graph.microsoft.com/.default"
client_Id     = $ApplicationID
Client_Secret = $AccessSecret
} 
$ConnectGraph = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantDomainName/oauth2/v2.0/token" -Method POST -Body $Body
$token = $ConnectGraph.access_token
#Export
$date = get-date -Format 'dd-MM-yyyy'
$file = "C:\temp\Office365ActiveUserDetail-$date.csv"
if (Test-Path $file -PathType leaf)
{
    Remove-Item $file
}
$GraphUserOneDriveUrl = "https://graph.microsoft.com/v1.0/reports/getOffice365ActiveUserDetail(period='D7')"
(Invoke-RestMethod -Headers @{Authorization = "Bearer $($token)"} -Uri $GraphUserOneDriveUrl -Method Get -OutFile $file) 
#Note : le fichier a toujours 3j d'écart
#########################
###### 2ème partie ######
#########################
Import-Module ActiveDirectory
Import-Module ImportExcel
$date = get-date -Format 'dd-MM-yyyy'
$inputfile = "C:\temp\Office365ActiveUserDetail-$date.csv"
$exportfiletxt = "C:\temp\Office365ActiveUserDetail-AD-$date.txt"
$exportfilecsv = "C:\temp\Office365ActiveUserDetail-AD-$date.csv"
$exportfilexlsx = "C:\temp\Office365ActiveUserDetail-AD-$date.xlsx"
#On supprime les fichiers historiques
if (Test-Path $exportfiletxt -PathType leaf)
{
    Remove-Item $exportfiletxt
    Remove-Item $exportfilecsv
    Remove-Item $exportfilexlsx
}
Out-File -FilePath $exportfiletxt -InputObject "Date;UserPrincipalName;DisplayName;ExchangeLastActivity;OneDriveLastActivity;SharePointLastActivity;TeamsLastActivity;AssignedProducts;samaccountname;company;manager;AccountExpirationDate;Enabled" -Append
Import-Csv $file | ForEach-Object {
    $date = $_.'Report Refresh Date'
    $upn = $_.'User Principal Name'
    $DisplayName = $_.'Display Name'
    $ExchangeLastActivity = $_.'Exchange Last Activity Date'
    $OneDriveLastActivity = $_.'OneDrive Last Activity Date'
    $SharePointLastActivity = $_.'SharePoint Last Activity Date'
    $TeamsLastActivity = $_.'Teams Last Activity Date'
    $AssignedProducts = $_.'Assigned Products'
    write-host $upn
    $samaccountname = get-aduser -filter {userPrincipalName -eq $upn} -Properties * | Select-Object samaccountname
    $company = get-aduser -filter {userPrincipalName -eq $upn} -Properties * | Select-Object company
    $Managerdn = get-aduser -filter {userPrincipalName -eq $upn} -Properties * | Select-Object manager
    Try {
        Get-ADUser -identity $managerdn.manager -Properties * -ErrorAction Stop | Out-Null
        #Manager trouvé, on complète $Manager
        $Manager = Get-ADUser -identity $managerdn.manager -Properties * | Select-Object DisplayName
    }
    Catch { 
        #Manager non trouvé (ex : pour les bal partagées)
        $Manager = "N/A"
    }
    $AccountExpirationDate = get-aduser -filter {userPrincipalName -eq $upn} -Properties * | Select-Object @{Name="accountExpires";Expression={([datetime]::FromFileTime($_.accountExpires))}}
    $Enabled = get-aduser -filter {userPrincipalName -eq $upn} -Properties * | Select-Object Enabled
    Out-File -FilePath $exportfiletxt -InputObject "$($date);$($upn);$($DisplayName);$($ExchangeLastActivity);$($OneDriveLastActivity);$($SharePointLastActivity);$($TeamsLastActivity);$($AssignedProducts);$($samaccountname.samaccountname);$($company.company);$($Manager.DisplayName);$($AccountExpirationDate.accountExpires);$($Enabled.enabled)" -Append
}
#Conversion en CSV
Import-Csv $exportfiletxt -Delimiter "`t" | Export-Csv $exportfilecsv -NoTypeInformation -Encoding Unicode
#Conversion en XLSX
Import-CSV $exportfilecsv -Delimiter ";" | Export-Excel $exportfilexlsx -WorkSheetName O365ActiveUserDetail

Extraction des membres d’un SharePoint

$file = "C:\temp\exportuser.csv"
rm $file
$Sites = Get-SPOSite -Limit all | where {$_.Template -match "GROUP"}

Out-File -FilePath $file -InputObject "SiteName;SiteMembers;SiteAdmins;SiteGuests" -Append
Foreach($Site in $Sites)
{
    Write-host "Getting Users from Site collection:"$Site.Url -f Yellow
    Get-SPOUser -Limit ALL -Site $Site.Url | Select DisplayName, LoginName,IsSiteAdmin,IsGroup,UserType | where {($_.IsGroup -match "False") -and ($_.DisplayName -notmatch "System Account") -and ($_.DisplayName -notmatch "SharePoint App") -and ($_.DisplayName -notmatch "NT Service") -and ($_.DisplayName -notmatch "DProdMGD104") -and ($_.LoginName -notmatch "domainname.com") -and ($_.LoginName -notmatch "\\_")}
    $SiteName = $Site.Url
    $SiteMembers = (Get-SPOUser -Limit ALL -Site $Site.Url | Select DisplayName, LoginName,IsSiteAdmin,IsGroup,UserType | where {($_.IsGroup -match "False") -and ($_.DisplayName -notmatch "System Account") -and ($_.DisplayName -notmatch "SharePoint App") -and ($_.DisplayName -notmatch "NT Service") -and ($_.DisplayName -notmatch "DProdMGD104") -and ($_.LoginName -notmatch "system") -and ($_.LoginName -notmatch "\\_") -and ($_.IsSiteAdmin -match "false") -and ($_.UserType -match "Member")} | select -expand LoginName) -join ', '
    $SiteAdmins = (Get-SPOUser -Limit ALL -Site $Site.Url | Select DisplayName, LoginName,IsSiteAdmin,IsGroup,UserType | where {($_.IsGroup -match "False") -and ($_.DisplayName -notmatch "System Account") -and ($_.DisplayName -notmatch "SharePoint App") -and ($_.DisplayName -notmatch "NT Service") -and ($_.DisplayName -notmatch "DProdMGD104") -and ($_.LoginName -notmatch "system") -and ($_.LoginName -notmatch "\\_") -and ($_.IsSiteAdmin -match "true")} | select -expand LoginName) -join ', '
    $SiteGuests = (Get-SPOUser -Limit ALL -Site $Site.Url | Select DisplayName, LoginName,IsSiteAdmin,IsGroup,UserType | where {($_.UserType -match "Guest")} | select -expand LoginName) -join ', '
    Out-File -FilePath $file -InputObject "$($SiteName);$($SiteMembers);$($SiteAdmins);$($SiteGuests)" -Append
}

Récupérer liste Sharepoint en CSV

#Config Parameter  
$SiteURL = "https://xxx.sharepoint.com/sites/xxx-Rapportsxx/"  
$ListName = "xxx"  
#InternalName of the selected fields  
$SelectedFields = @("Owners","Site","Date de creation","Url")   
$CSVPath = "C:\Temp\ListData.csv"  
$ListDataCollection= @()  
   
#Connect to PnP Online  
$Counter = 0  
  
#PageSize:The number of items to retrieve per page request  
$ListItems = Get-PnPListItem -List $ListName -Fields $SelectedFields -PageSize 2000  
   
#Get all items from list  
$ListItems | ForEach-Object {  
        $ListItem  = Get-PnPProperty -ClientObject $_ -Property FieldValuesAsText  
        $ListRow = New-Object PSObject  
        $Counter++  
        ForEach($Field in $SelectedFields)   
        {  
            $ListRow | Add-Member -MemberType NoteProperty $Field $ListItem[$Field]  
        }  
        Write-Progress -PercentComplete ($Counter / $($ListItems.Count)  * 100) -Activity "Exporting List Items..." -Status  "Exporting Item $Counter of $($ListItems.Count)"  
        $ListDataCollection += $ListRow  
}  
#Export the result Array to CSV file  
$ListDataCollection | Export-CSV $CSVPath -NoTypeInformation -Encoding Unicode