Set-StoragePool -IsReadOnly $false leads to access denied error
Introduction
This blog post is about the case where a phantom storage pool on disks recuperated from a previous Storage Spaces Direct deployment could not be made writable. The storage pool showed up on a standalone member server in the lab. The pool was not functional, nor did we expect or want it to be functional. We wanted to get rid of it and use the recuperated disks from that old S2D cluster for some other storage spaces testing. As part of getting rid if this old storage pool information we ran into the issue that Set-StoragePool -IsReadOnly $false leads to access denied error.
The Issue
When prepping a number of previously used servers to deploy Storage Spaces Direct there is a nice script available from Microsoft Docs Deploy Storage Spaces Direct in section 3.1 Clean drives.
# Fill in these variables with your values
$ServerList = „Server01“, „Server02“, „Server03“, „Server04“
Invoke-Command ($ServerList) {Update-StorageProviderCacheGet-StoragePool | ? IsPrimordial -eq $false | Set-StoragePool -IsReadOnly:$false -ErrorAction SilentlyContinueGet-StoragePool | ? IsPrimordial -eq $false | Get-VirtualDisk | Remove-VirtualDisk -Confirm:$false -ErrorAction SilentlyContinueGet-StoragePool | ? IsPrimordial -eq $false | Remove-StoragePool -Confirm:$false -ErrorAction SilentlyContinueGet-PhysicalDisk | Reset-PhysicalDisk -ErrorAction SilentlyContinueGet-Disk | ? Number -ne $null | ? IsBoot -ne $true | ? IsSystem -ne $true | ? PartitionStyle -ne RAW | % {$_ | Set-Disk -isoffline:$false$_ | Set-Disk -isreadonly:$false$_ | Clear-Disk -RemoveData -RemoveOEM -Confirm:$false$_ | Set-Disk -isreadonly:$true$_ | Set-Disk -isoffline:$true}Get-Disk | Where Number -Ne $Null | Where IsBoot -Ne $True | Where IsSystem -Ne $True | Where PartitionStyle -Eq RAW | Group -NoElement -Property FriendlyName} | Sort -Property PsComputerName, Count
Be careful with this as it will clear the disks and their content. Normally this works quite well. I do prefer to tweak it a bit to exclude any USB disks or other disks I do not want to be affected by this script. But this is not the subject of this blog post. We are talking about an issue with:
Get-StoragePool | ? IsPrimordial -eq $false | Set-StoragePool -IsReadOnly:$false -ErrorAction SilentlyContinue
It throws an error:
PS C:Windowssystem32> Get-StoragePool -FriendlyName „S2D on TaroxCluster“ | Set-StoragePool -IsReadOnly $false
Set-StoragePool : Access deniedExtended information:Access is denied. Recommended Actions:- Check if you have the necessary privileges to perform the operation.Activity ID: {7480dd11-3547-4ade-aef4-3f8ae460d7c7}At line:1 char:56+ … endlyName „S2D on TaroxCluster“ | Set-StoragePool -IsReadOnly $false+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : PermissionDenied: (StorageWMI:ROOT/Microsoft/…_StorageCmdlets) [Set-StoragePool], CimException + FullyQualifiedErrorId : StorageWMI 40001,Set-StoragePool
Normally this works fine and you need to do this or otherwise you run into problems when you try to remove virtual disks later in the script. This is clear when we try it out on its own and see the following error:
Error deleting virtual disk: The storage pool could not complete the operation because its configuration is read-only.
Basically, that means the storage pool is not writable, which is why the first thing the script does is make the storage pool writable. But that failed with an “access denied” error.
This also means we could not delete the storage pool, due to it being read only. We’re pretty much stuck and we need to fix this.
Figuring out what’s causing the problem
Let’s take a closer look at our problematic storage pool via:
Get-StoragePool -FriendlyName „S2D on TaroxCluster
FriendlyName OperationalStatus HealthStatus IsPrimordial IsReadOnly Size AllocatedSize———— —————– ———— ———— ———- —- ————-S2D on TaroxCluster Read-only Unknown False True 22.77 TB 16.23 TB
We can see that the Operational Status is read-only and “IsReadOnly” Is set to true. The normal fix can is to make the storage pool writable via PowerShell with:
Get-StoragePool -FriendlyName „S2D on TaroxCluster“ | Set-StoragePool -IsReadOnly $false
That does not work. I keep getting an access denied error. A well-known reason for this error is that you are trying to run this PowerShell commands without administrative privileges. This is not the reason in this case, I made sure of that.
So I dive in a little deeper and list all the details of the Get-StoragePool command:
Get-StoragePool -FriendlyName „S2D on TaroxCluster“ | fl *
PS C:Windowssystem32> Get-StoragePool -FriendlyName „S2D on TaroxCluster“ | fl *Usage : OtherOperationalStatus : Read-onlyHealthStatus : UnknownProvisioningTypeDefault : FixedSupportedProvisioningTypes : {Thin, Fixed}MediaTypeDefault : UnspecifiedReadOnlyReason : By PolicyRepairPolicy : ParallelRetireMissingPhysicalDisks : NeverWriteCacheSizeDefault : AutoVersion : Windows Server 2019FaultDomainAwarenessDefault : StorageScaleUnitObjectId : {1}\TAROXS2D4root/Microsoft/Windows/Storage/Providers_v2SPACES_StoragePool.ObjectId=“{76bbc2fd-c8a2-11e8-8546-806e6f6e6963}:SP:{50aadde0-2fc3-4457-b701-fe8460df7b32}“PassThroughClass : PassThroughIds : PassThroughNamespace : PassThroughServer : UniqueId : {50aadde0-2fc3-4457-b701-fe8460df7b32}AllocatedSize : 17846662856704ClearOnDeallocate : FalseEnclosureAwareDefault : FalseFriendlyName : S2D on TaroxClusterIsClustered : TrueIsPowerProtected : TrueIsPrimordial : FalseIsReadOnly : TrueLogicalSectorSize : 4096Name : OtherOperationalStatusDescription : OtherUsageDescription : Reserved for S2DPhysicalSectorSize : 4096ResiliencySettingNameDefault : MirrorSize : 25033928867840SupportsDeduplication : TrueThinProvisioningAlertThresholds : {70}WriteCacheSizeMax : 18446744073709551614WriteCacheSizeMin : 0PSComputerName : CimClass : ROOT/Microsoft/Windows/Storage:MSFT_StoragePoolCimInstanceProperties : {ObjectId, PassThroughClass, PassThroughIds, PassThroughNamespace…}CimSystemProperties : Microsoft.Management.Infrastructure.CimSystemProperties
I noticed a couple of things (yellow highlights). The health status is unknown. The reason for being read only is “By Policy”. This could lead you to investigate disk policies for storage, but that would be a diversion at best. When we look at the individual disks most of them are visible in disk manager and diskpart but they are also offline due to a policy. Changing the policy in diskpart will not help and trying to get the disk to come on line fail with an access denied and write errors. This is not the path to follow.
In Server Manager, Storage Pools we see that the “Managed By” and “Available to” are blank. The storage pool is set to Read only.
The second thing that I noticed, even when I knew this before, is that the friendly name “S2D on TaroxCluster” reminded me of the fact the Storage Pool belonged to a cluster before as indicated by “IsClustered” being true.
Diagnosis
While a functional storage pool will also be off line after a reinstall of the OS, an in-place upgrade or moving them to a new server it normally can be brought on line quite quickly. But not here, it doesn’t work, there is no cluster and the storage pool is clustered. When the storage pool is a cluster resource it is normally made writable by bringing the pool on line. But as this node isn’t part of a cluster anymore so that won’t work. We don’t even have the cluster tools installed anymore on this server.
We can also normally use the Storage Pools page of Server Manager. When the storage pool is “read-only” you’ll have and option Set Read-Write Access when you right-click the storage pool. That doesn’t work, just like the PowerShell commands do not work. All options are blanked out and not available.
Basically, the metadata on the disks is showing us the phantom storage pool from a former S2D deployment, where that pool is a cluster resource. The disks in this server have come from other nodes and the metadata on there is preventing us form reusing them. The fact that they were part of an S2D cluster deployment holds the key to the fix.
The Solution
Once I realized that the fact that this storage pool thinks it is part of a cluster that isn’t around anymore prevents us changing the properties and cause the “Access denied” error I came up with a plan.
In the end, I created a 1 node on the host with the disks. I added the storage pool to the cluster pools…
The existing Storage Pool was found and I clicked OK to add it.
That made the storage pool managed by the cluster. Normally you can bring the storage pool online with a cluster to make it writable. That would not work here as the storage pool only exists on the metadata on some of the disks and not in real life.
The trick then was to remove the storage pool from the cluster as shown below.
You confirm this is what you want and that’s it…
Once I did that it was still read-only. But now the command Get-StoragePool -FriendlyName „S2D on TaroxCluster“ | Set-StoragePool -IsReadOnly $false could be run successfully.
Finally, I got to run the script to clean the drives from any remaining metadata from the disks. After that I had all of my NVMe, SSD and HDD disks available to build a new storage spaces set up.
Conclusion
Never give up. Things can and will confuse you now and then. That’s normal. It is OK you need some time to investigate and figure out what has happened to a system. Take that time and once you’ve wrapped your head around the context you will likely come up with some ideas to try and solve the issue at hand. You can figure it out. I hope this helps some of you when you run into a storage pool that cannot be made writable in any way. Thank you for reading!