powershell
2235 TopicsUnderstanding How Graph Permissions for Groups Work
Understanding the set of Graph permissions required by apps can be challenging. In this article we discuss how the Group.Read.All and GroupMember.Real.All permissions work and why you should choose one permission over the other so that you respect the principle of least permission when it comes to assigning Graph permissions to your apps and PowerShell scripts. Experience of reviewing scripts shows that too many people use Group.Read.All without needing to. Don't over-permission your scripts! https://office365itpros.com/2026/05/13/graph-permissions-groups/18Views0likes0CommentsGet-Secret fails when PowerShell script runs as a scheduled task.
I have a PowerShell backup script that connects to SMB shares, copies files from one share to the other share, and disconnects. Passwords used to connect to the shares are stored in a SecretStore. The user account that the script runs under is an unpriviledged Backup Operator that has access to the SMB shares. THe SecretStore was created under the same user context. I can run the script manually in the console, and it executes correctly. When I run the same script as a scheduled task, running under the same user account, the script stops when the Get-Secret cmdlet is called. Here is some pertinent information: PS C:\Users\incodebackup\Documents\Scripts\TUNet_Backup> $PSVersionTable Name Value ---- ----- PSVersion 5.1.14393.3471 PSEdition Desktop PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.14393.3471 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 PS C:\Users\incodebackup\Documents\Scripts\TUNet_Backup> Get-Module -ListAvailable Directory: C:\Program Files\WindowsPowerShell\Modules ModuleType Version Name ExportedCommands ---------- ------- ---- ---------------- Script 1.0.1 Microsoft.PowerShell.Operation.V... {Get-OperationValidation, Invoke-OperationValidation} Binary 1.1.2 Microsoft.PowerShell.SecretManag... {Register-SecretVault, Unregister-SecretVault, Get-SecretVault, Set-SecretVaultDefault...} Binary 1.0.6 Microsoft.PowerShell.SecretStore {Unlock-SecretStore, Set-SecretStorePassword, Get-SecretStoreConfiguration, Set-SecretStoreConfiguration...} PS C:\Users\incodebackup\Documents\Scripts\TUNet_Backup> Get-SCheduledTask | Format-List -Property * State : Ready Actions : {MSFT_TaskExecAction} Author : WIN-M95PVJLVDAB\incodebackup Date : 2026-01-27T15:28:35.7952875 Description : This task copies files out of the TUNET/datafile directory once a say to ARCHIBALD. Documentation : Principal : MSFT_TaskPrincipal2 SecurityDescriptor : Settings : MSFT_TaskSettings3 Source : TaskName : Daily TUNet Backup Copy TaskPath : \ Triggers : {MSFT_TaskDailyTrigger} URI : \Daily TUNet Backup Copy Version : PSComputerName : CimClass : Root/Microsoft/Windows/TaskScheduler:MSFT_ScheduledTask CimInstanceProperties : {Actions, Author, Date, Description...} CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties I execute Start-Transcript early in the script execution, and because of the crash(?), it is short enough to included in its entirety: ********************** Windows PowerShell transcript start Start time: 20260127190002 Username: WIN-M95PVJLVDAB\incodebackup RunAs User: WIN-M95PVJLVDAB\incodebackup Machine: WIN-M95PVJLVDAB (Microsoft Windows NT 10.0.14393.0) Host Application: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -NonInteractive -File C:\Users\Incodebackup\Documents\Scripts\TUNet_Backup\Copy-TUNetBackup.ps1 -daily -test Process ID: 2084 PSVersion: 5.1.14393.3471 PSEdition: Desktop PSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.14393.3471 BuildVersion: 10.0.14393.3471 CLRVersion: 4.0.30319.42000 WSManStackVersion: 3.0 PSRemotingProtocolVersion: 2.3 SerializationVersion: 1.1.0.1 ********************** Transcript started, output file is C:\Users\Incodebackup\Documents\Scripts\TUNet_Backup\daily_2026-01-27_190002.log 2026/01/27 19:00:02 INFO 940 TUNet backup script started. 2026/01/27 19:00:02 INFO 941 Copy-TUNetBackup.ps1 Version: 6.0F 2026/01/27 19:00:02 INFO 942 Parameter qhourly: False 2026/01/27 19:00:02 INFO 943 Parameter hourly: False 2026/01/27 19:00:02 INFO 944 Parameter daily: True 2026/01/27 19:00:02 INFO 945 Parameter purge: False 2026/01/27 19:00:02 INFO 946 Parameter archive: False 2026/01/27 19:00:02 INFO 947 Parameter test: True 2026/01/27 19:00:02 INFO 1035 Creating mutex object. 2026/01/27 19:00:02 INFO 1037 Creating semaphore object. 2026/01/27 19:00:02 INFO 1058 Mutex timeout set: 300000 2026/01/27 19:00:02 INFO 1072 Attempting to acquire mutex to enter semaphore... 2026/01/27 19:00:02 INFO 1074 ...got the mutex! 2026/01/27 19:00:02 INFO 1075 Attempting to enter the semaphore... 2026/01/27 19:00:02 INFO 1077 ... got the semaphore! 2026/01/27 19:00:02 INFO 719 Release-Mutex: Attempting to release mutex... 2026/01/27 19:00:02 INFO 721 Release-Mutex: ...done. 2026/01/27 19:00:02 INFO 1090 Using TEST values for source and destination paths. 2026/01/27 19:00:02 INFO 1109 TUnet Source: \\192.168.100.46\Netbackup\Netbackup\Tantalus\test_src\datafile 2026/01/27 19:00:02 INFO 1110 ARCHIE Dest: \\192.168.100.46\Netbackup\Netbackup\Tantalus\test_dest\datafile 2026/01/27 19:00:02 INFO 1114 Attempt to acquire mutex to mount network shares... 2026/01/27 19:00:02 INFO 1116 ...got the mutex! 2026/01/27 19:00:02 INFO 1117 Opening SecretStore vault...! 2026/01/27 19:00:02 INFO 1120 ... vault opened! 2026/01/27 19:00:02 INFO 1121 Checking connection to \\192.168.100.46\Netbackup\Netbackup\Tantalus ... 2026/01/27 19:00:02 INFO 1126 ...not connected to \\192.168.100.46\Netbackup\Netbackup\Tantalus . 2026/01/27 19:00:02 INFO 1127 Get FULTON\incodebackup password... ********************** Windows PowerShell transcript end End time: 20260127190002 ********************** Now I will show you the script around line 1127 where it goes out into the weeds: Write-Log -Level "INFO" -Message "$(__LINE__) Opening SecretStore vault...!" $pw = Import-CliXml -Path '.\TUNet-Backup-Vault.xml' -Verbose Unlock-SecretStore -Password $pw Write-Log -Level "INFO" -Message "$(__LINE__) ... vault opened!" # # Statements omitted # Write-Log -Level "INFO" -Message "$(__LINE__) Get $archie_un password..." try { $pw = Get-Secret -Name $archie_un -Verbose -Debug } catch { $err_msg = "Get-Secret exception. Name: $archie_un Exception: $($_.Exception.Message)" Write-Log -Level "FATAL" -Message "$(__LINE__) $err_msg" throw $err_msg } Write-Log -Level "INFO" -Message "$(__LINE__) ...done!" I was able to unlock the SecretStore, but Get-Secret fails. The very odd thing, besides not getting my password out the SecretStore, is that there is no exception posted by Powershell. I have no information at all about why my attempt did not work. If Get-Secret exited, then I would expect one of the two possible log messages printed in the transcript, but as you can see, the transcript ended. Note: the entire script body is encapsulated in a try{} block, which has an associated finally{} block, which contains other logging commands that execute when the finally{} block is entered, but in scheduled task instance, nothing. If anyone can tell me how to make Get-Secret work, that would be great, but I'll settle very gratefully for some way to get more information from this system to try to figure out why it is not, that would be most helpful. Additional information supplied on request.163Views0likes3CommentsMicrosoft Entra /Azure Connect Reinstallation and Source Anchor Change
Hello everyone, I would like to talk about the possibility of changing the SourceAnchor in Azure Connect. Officially, this is not supported by Microsoft, but there is still a way to do this via a few detours. the running AD Sync must be stopped first of all. to make the changeover, all users must first be soft-deleted. The most practical way to do this is to synchronize an OU in which there are no users. Now the Entra objects are stored under deleted It is important to note that before restoring the users who do not have an Exchange Online mailbox, Entra P1 or 2 must be removed so that a second mailbox is not created here. Now all users must be restored. After this has been done, the Immutable id of the users must be removed via PowerShell. This is possible with the following command: Get-MsolUser -all | Set-MsolUser -ImmutableID "$Null" (If this command is required for individual users, replace -all with -userpricipalname "example@email,de") If the Immutable Id has been removed for all users, the status in Entra must be set to Cloud Only. If this is the case, you can start with the next steps. It is important to note that the actions carried out above can lead to short-term failures and should therefore ideally be carried out before the weekend! In the next step, a clean uninstallation of Azure Connect must be carried out. Here I would recommend the article ADsync uninstallation from MSXFAQ where it is well explained. When uninstalling, only the steps that do not hinder a new installation should be carried out, but this is well explained in the article. after successfully uninstalling the AD Sync, there may be delays, which is why I would recommend waiting 24 hours before reinstalling. The waiting time can be skipped, but it still worked for me. as soon as you have installed the AD Sync with the new desired attribute, you can start the sync. The users should now be matched with the existing cloud objects via Softmatch. If this does not work, it is possible to delete the Immutable ID again or to correct the errors via the AD Connect error display of the Entra ID. Under the function other errors, several errors may be displayed, this was fixed by us by fixing all duplicate attribute errors. I hope this has helped you a little. I am always open to feedback!566Views0likes1CommentHow Do I Target the Azure VPN Client in a Conditional Access Policy?
I am using the Azure VPN Client to connect users to an Azure VPN Gateway using their Entra ID credentials to authenticate. I want to target this application with a CA policy that requires MFA every time it connects. The problem is that I don't see the applications in my Enterprise Apps and all of my searching says that it won't appear because it was "pre-certified" by Microsoft. In the Gateway setup I used the Audience GUID of c632b3df-fb67-4d84-bdcf-b95ad541b5c8. And this is working as expected. The only solution that I have found for targeting the Azure VPN Client app is to create a Service Principal using that Audience GUID. This seems like a bit of a hack, so I am posting here to see if there are any other methods that I am missing to target this app when it doesn't appear in my Enterprise Apps list.539Views1like4CommentsPowershell Entra and General Forum Layout Questions
Hello, I am returning to PowerShell, and it seems a lot has changed. I need to create some Security Groups in MS Entra and would like to know the best way to do so. I have a .csv file for the groups. Also, what is the best way to display the topic titles as a list in this forum? At this moment, I have to go scroll through pages of posts, and it's not easy. I used to like the old formats that let you see all the thread titles. Thanks75Views0likes1CommentExtracting and Auditing Azure DevOps Permissions at Scale with PowerShell
Managing access in Azure DevOps is easy at small scale — and increasingly opaque as organizations grow. This post introduces ADO Permissions Output, an open-source PowerShell toolset that queries Azure DevOps REST APIs across 30+ security namespaces, decodes bitmask permissions, resolves cryptic GUIDs and tokens into readable names, and produces structured JSON/CSV output ready for Power BI. It also surfaces "ghost" members — users who appear in ADO through nested Entra groups but hold no active entitlement — which the standard Graph API alone cannot detect. Whether you're preparing for a compliance review or just want to know who actually has access to what, this tool closes the gap between the ADO portal and a complete audit picture.The Microsoft Graph PowerShell SDK and the additionalProperties Property
The additionalProperties property is available for many Microsoft Graph PowerShell SDK cmdlets. In this article, we explain the function of the additionalProperties property and how it functions in holding output for Microsoft Graph PowerShell SDK cmdlets. It’s all because of the lack of strongly-typed properties, or so the AutoRest process would have us believe. https://office365itpros.com/2026/04/21/additionalproperties-property/37Views0likes0CommentsSharePoint List Migration to new Tenant
Hi All, I am preparing for a tenant-to-tenant migration of 60+ SharePoint lists that function as the back-end for various PowerApps. Since we are doing a staggered cutover, I need to perform an initial migration now and then run 'Delta' syncs over the next few weeks to catch new records, updates, and deletes. My primary challenge is that SharePoint's native ID column is not preserved during manual migrations (PowerShell/CSV), which will break our App logic and Lookups. How have others handled cross-tenant list synchronization at this scale? Specifically: How do you maintain record relationships and deep links when the system IDs change? What is the most efficient way to handle deltas across 60 lists without buying expensive 3rd-party migration tools? thanks, Jake122Views0likes1CommentAutomating Microsoft 365 with PowerShell Second Edition
The Office 365 for IT Pros team are thrilled to announce the availability of Automating Microsoft 365 with PowerShell (2nd edition). This completely revised 350-page book delivers the most comprehensive coverage of how to use Microsoft Graph APIs and the Microsoft Graph PowerShell SDK with Microsoft 365 workloads (Entra ID, Exchange Online, SharePoint Online, Teams, Planner, and more). Existing subscribers can download the second edition now free of charge. https://office365itpros.com/2025/06/30/automating-microsoft-365-with-powershell2/966Views2likes11CommentsBLOG: Determine and modernize Filesystem Deduplication
Version history - 1.6 Added references / links - 1.5 Added insights from Steven Ekren. Many thanks! / Added ReFS Docs link and added clarification about drawbacks. - 1.4 revised script so ReFS volumes with classic dedup will be identified, added more eligibly checks and error handling - 1.3 added point #4 in migration guidance - 1.2 revised script - 1.1 formatting This blog explains the two Windows deduplication modes classic Windows Data Deduplication (ReFS or NTFS) and ReFS Deduplication (ReFS). It covers how they differ, why you should consider upgrading to Windows Server 2025 to leverage the new ReFS dedup engine, and clear warnings about scenarios where ReFS is not recommended. Practical migration guidance and detection commands are included. Differences between classic dedup and ReFS dedup File system: Classic dedup runs on NTFS or ReFS; ReFS dedup runs on ReFS and Windows Server 2025 or later, only. Implementation: They are separate engines with different metadata formats and management cmdlets. Management: Classic dedup uses the Dedup PowerShell module (Get‑DedupVolume, Start‑DedupJob, Disable‑DedupVolume). ReFS dedup uses its own ReFS dedup cmdlets (Get‑ReFSDedupStatus, Enable‑ReFSDedup). Conversion: There is no in‑place conversion between the two; metadata and chunk formats are incompatible. Improvements: the new in-line ReFS Deduplication leverages the advantages of ReFS files system. This makes deduplication more efficient and less CPU intensive. The new ReFS Deduplication can also compress data in-line using L1Z algorithm. This makes it up to par with enterprise solutions, often found in SAN storage or Linux appliances. Compression needs to be set per volume, and optional. Edit: Steven Ekren, a former Senior Product Manager for Hyper-V shared valuable insights on how both engines operate in a comment on LinkedIn: [...] the basic conceptual difference between WS Deduplication and ReFS deduplication is that the Windows Server [dedup] version takes the duplicate file data and moves it to a repository and puts a reparse point in the file system from each point that references the data. This involves data movement and therefore not recommended for workloads that are changing it's data often, but best for more static data like documents and picture/videos. ReFS is a file system that uses links natively for all the objects so leaving the data in place and managing the links is much more efficient and doesn't involve the data copy and managing a repository. Effectively it's built into the file system. As the blog notes, there are some situations not recommended for this version of dedupe, but generally it's lower performance and storage I/O impact. Why upgrade to Windows Server 2025 Improved version of ReFS Filesystem Improved ReFS in-line deduplication + optional L1Z compression: Server 2025 includes enhancements to ReFS dedup performance, scalability, and integration with modern storage features. Support and fixes: Windows Server 2016 and 2019 are past mainstream support, increasing the likelihood of costly support cases and delayed fixes; upgrading reduces operational risk and ensures access to ongoing improvements. Future compatibility: Newer OS releases receive optimizations and bug fixes for ReFS and dedup scenarios that older releases will not. SMB compression: for reasonably faster data transfer at minimal CPU when transferring data through the networks. Feature and security related improvements refer to availabile Microsoft Windows Server 2025 Summit content on techcommunity.microsoft.com Scenarios where ReFS is not recommended ReFS on SAN in clustered CSV environments: Avoid placing ReFS dedup on top of SAN‑backed Cluster Shared Volumes (CSVFS) in production clusters; clustered SAN/CSV scenarios causing severe performance issues in practice. Please refer to the ReFS documentation. (personal opinion and experience, not endorsed by Microsoft): Many small, fast‑changing files: Workloads with frequent small writes, such as user profiles, folder redirection of AppData folders, or applications that churn small config files (for example, Lotus Notes config files) can cause locks, performance degradation, or unexpected behavior on ReFS. Exclude these disks from dedup or keep them on NTFS. Note: Restrictions on high churn rate, like lockups or high RAM consumption, deadlocks / BSOD might have been addressed in Windows Server 2025 and the ReFS Dedup, see comment of Steven Ekren. Improving reliability and performance is a top goal for ReFS, to improve the adoption and feature parity with NTFS. For information about feature parity please refer to the ReFS documentation. Migration guidance The following instructions describe a high level and supported migration path from Windows deduplication using the NTFS file system to native ReFS Deduplication. Note: Step #3, data migration is not required when already using ReFS with Data Deduplication. In this case it's enough to execute step #1 and #2. Note: Validate on non‑production data first. Plan for rehydration time and network/storage throughput. Ensure backups are current before starting. Make sure to have a full backup before upgrading Server OS or making changes. 1. Disable classic dedup on the NTFS source: Disable-DedupVolume -Volume YourDriveLetter: 2. Rehydrate (un‑deduplicate) the data: Start-DedupJob -Volume YourDriveLetter: -Type Unoptimization 3. Copy or move data to a ReFS volume (new target): For straightforward NTFS→ReFS copies, robocopy is recommended. A GUI and job based alternative to this is the File Server Migration Feature (uses robocopy) in Windows Admin Center. For complex scenarios, open files long path names very large datasets (< 5 TB) or many small files restructuring, GUI (including Windows Server Core) automation, improved logging cloud/hybrid migrations I recommend the usage of GS RichCopy Enterprise by GuruSquad for higher speed (up to 40%) and reliability, compared to robocopy. 4. Optionally remove the Windows Server feature When there is no old deduplication in use consider to remove the feature. Your advantages of doing so: removes an unneccessary service. removes the file system filter driver for dedup, which causes performance impacts, even when not in use. removes the PowerShell commandlets for the old dedup, so they cannot mistakenly used by existing scripts, unaware admins etc. When migrating files over network: SMB compression: consider both source and target run Windows Server 2025 and leverage SMB compression. SMB Compression is available in Microsoft xcopy, Microsoft robocopy and Gurusquad GScopy Enterprise. Balancing and Teaming with SMB: SMB does not require LFBO or SET Teaming. It automagically detects network links and actively balances on its own on Windows Server 2016 and later. Using teaming, depending the configuration, can negatively affect transfer speed. Quick detection and diagnostic commands Check file systems: Get-Volume | Select DriveLetter, FileSystem Check classic dedup feature: Get-WindowsFeature -Name FS-Data-Deduplication Get-DedupVolume Get-DedupStatus Check ReFS dedup: Get-Command -Module Microsoft.ReFsDedup.Commands Get-ReFSDedupStatus -Volume YourDriveLetter: Diagnostic script to detect both: <# .SYNOPSIS Detects classic NTFS Data Deduplication and ReFS Deduplication across local volumes. .DESCRIPTION - Reports NTFS volumes with classic Data Dedup enabled. - Lists ReFS volumes present on the host. - If the ReFS dedup cmdlet exists AND OS build >= 26100, checks ReFS dedup status per ReFS volume. - Color coding: * Classic dedup enabled → Yellow * Classic dedup not enabled → Cyan * ReFS dedup enabled → Green * ReFS dedup not enabled → Cyan .NOTES Version: 1.7 Author: Karl Wester-Ebbinghaus + Copilot Requirements: Elevated PowerShell session, PowerShell 5.1 or newer Supported OS: Windows Server 2025, Azure Stack HCI 24H2 or newer Unsupported OS: Windows 10, Windows 11 (script terminates) #> #region Initialization Write-Verbose "Initializing variables and environment..." $Volumes = $null $Volume = $null $DedupVolumesList = $null $DedupReFSVolumesList = $null $DedupReFSVolumesListLetters = $null $DedupReFSStatus = $null $refsCmd = $null $OSBuild = $null $runReFSDedupChecks = $null #endregion Initialization #region Volume Discovery Clear-Host Write-Verbose "Querying NTFS and ReFS volumes..." $Volumes = Get-Volume | Where-Object FileSystem -in 'NTFS','ReFS' #endregion Volume Discovery #region ReFS Dedup Cmdlet, OS Build and OS SKU Detection Write-Verbose "Checking for ReFS deduplication cmdlet..." $refsCmd = Get-Command -Name Get-ReFSDedupStatus -ErrorAction SilentlyContinue Write-Verbose "Reading OS build number..." try { $OSBuild = [int](Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name CurrentBuildNumber).CurrentBuildNumber } catch { Write-Verbose "Registry read for OS build failed. Falling back to Environment OSVersion." $OSBuild = [int][Environment]::OSVersion.Version.Build } # end try/catch for OS build detection Write-Verbose "Checking OS InstallationType and EditionID..." $CurrentVersionKey = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' $InstallationType = $CurrentVersionKey.InstallationType # "Client" or "Server" $EditionID = $CurrentVersionKey.EditionID # e.g. "AzureStackHCI", "ServerStandard", etc. Write-Verbose "Detected InstallationType: $InstallationType" Write-Verbose "Detected EditionID: $EditionID" Write-Verbose "Detected OSBuild: $OSBuild" # Block Windows 10/11 (Client OS) if ($InstallationType -eq 'Client') { Write-Error "Unsupported OS detected: Windows Client (Windows 10/11). Only Windows Server or Azure Stack HCI are supported. Script will terminate." exit } # Allow Azure Stack HCI explicitly if ($EditionID -eq 'AzureStackHCI') { Write-Verbose "Azure Stack HCI detected. Supported platform." } else { # Must be Windows Server if ($InstallationType -ne 'Server') { Write-Error "Unsupported OS detected. Only Windows Server or Azure Stack HCI are supported. Script will terminate." exit } Write-Verbose "Windows Server detected (EditionID: $EditionID). Supported platform." } Write-Verbose "Evaluating ReFS dedup eligibility based on cmdlet presence and build >= 26100..." $runReFSDedupChecks = $false if ($refsCmd -and ($OSBuild -ge 26100)) { $runReFSDedupChecks = $true Write-Verbose "ReFS dedup checks ENABLED (cmdlet present and OS build >= 26100)." } else { Write-Verbose "ReFS dedup checks DISABLED (cmdlet missing or OS build < 26100)." } #endregion ReFS Dedup Cmdlet, OS Build and OS SKU Detection #region Main Loop foreach ($Volume in $Volumes) { # begin foreach volume loop Write-Host "Volume $($Volume.DriveLetter): ($($Volume.FileSystem))" Write-Verbose "Processing volume $($Volume.DriveLetter)..." #region Classic Dedup + ReFS Volume Listing if ($Volume.FileSystem -eq 'NTFS' -or $Volume.FileSystem -eq 'ReFS') { Write-Verbose "Checking classic deduplication status for volume $($Volume.DriveLetter)..." $DedupVolumesList = Get-DedupVolume -Volume $Volume.DriveLetter -ErrorAction SilentlyContinue if ($DedupVolumesList) { Write-Host " → Classic Data Dedup ENABLED on $($Volume.DriveLetter), $($Volume.FileSystem)" -ForegroundColor Yellow } else { Write-Host " → Classic Data Dedup NOT enabled on $($Volume.DriveLetter),$($Volume.FileSystem)" -ForegroundColor Cyan } # end if classic dedup enabled Write-Verbose "Listing ReFS volumes on host..." $DedupReFSVolumesList = Get-Volume | Where-Object FileSystem -eq 'ReFS' if ($DedupReFSVolumesList) { $DedupReFSVolumesListLetters = ($DedupReFSVolumesList | ForEach-Object { $_.DriveLetter }) -join ',' Write-Host " → ReFS volumes present on host: $DedupReFSVolumesListLetters" } else { Write-Host " → No ReFS volumes detected on host" } # end if ReFS volumes present } # end NTFS/ReFS block #endregion Classic Dedup + ReFS Volume Listing #region ReFS Dedup Status if ($Volume.FileSystem -eq 'ReFS') { if ($runReFSDedupChecks) { Write-Verbose "Checking ReFS deduplication status for volume $($Volume.DriveLetter)..." $DedupReFSStatus = Get-ReFSDedupStatus -Volume $Volume.DriveLetter -ErrorAction SilentlyContinue if ($DedupReFSStatus) { Write-Host " → ReFS Dedup ENABLED on $($Volume.DriveLetter), $($Volume.FileSystem)" -ForegroundColor Green } else { Write-Host " → ReFS Dedup NOT enabled on $($Volume.DriveLetter), $($Volume.FileSystem)" -ForegroundColor Cyan } # end if ReFS dedup enabled } else { if (-not $refsCmd) { Write-Error " → Skipping ReFS dedup check: Get-ReFSDedupStatus cmdlet not present" -ForegroundColor Cyan } else { Write-Error " → Skipping ReFS dedup check: OS build $OSBuild < required 26100" -ForegroundColor Cyan } # end reason for skipping ReFS dedup check } # end if runReFSDedupChecks } # end if ReFS filesystem block #endregion ReFS Dedup Status Write-Host "" } # end foreach volume loop #endregion Main Loop #region End Write-Verbose "Script completed." #endregion End Recommendations and next steps Inventory: Identify volumes using NTFS dedup and ReFS dedup, and map workloads that create many small or rapidly changing files. Plan: Schedule rehydration and migration windows; test ReFS dedup on representative datasets. Upgrade: Prioritize upgrading servers still on 2016/2019 (End of Mainstream Support) to reduce support risk and gain the latest ReFS dedup improvements. Kindly consider reading my Windows Server Installation Guidance and Windows Server Upgrade Guidance Exclude: Keep user profiles, AppData, and other high‑churn small‑file paths off ReFS dedup or on NTFS. Consider ReFS Dedup with Compression: Enable compression optionally. Mind ReFS dedup compression is not the same as compress files integration in File Explorer or File Explorer properties (Windows 9x). It's transparent to the application Make smart decisions: Avoid using dedup when the dataset is changing fast or your dedup + compression rate is below 20%. Usually you can expect 40% or more savings, and up to 80% in specific use cases like VDI VHDX with ReFS Dedup + Compression. Plan your dedup jobs: Ensure of making use of the planning features for dedup jobs through PowerShell or Windows Admin Center (WAC) when using ReFS dedup on more than one volume per Server. Otherwise they might all run at the same time and impact your storage performance (esp. spinning rust) and consumption of RAM and CPU. Share and Educate: Inform your infrastructure team about the changes so they avoid using the traditional dedup on ReFS. Related blogposts: https://splitbrain.com/windows-data-deduplication-vs-refs-deduplication/ , Thanks Darryl van der Peijl and team. https://www.veeam.com/kb2023 Veeam best practices about Windows Deduplication and ReFS Deduplication.996Views2likes3Comments