General Discussion
General Discussion
I am working on some automation using powershell and the powershell toolkit. After creating a qtree and then its share, I am trying to set the 'ShareProperties' parameter, "browsable", which correlates to the checkbox in the UI for "allow client access to snapshot copies directory". It fails saying, "ShareProperties parameter specified, which is not supported for REST call".
I have tried it with Set-NcCifsShare and Add-NcCifsShare. I am running the powershell module for NetApp.ONTAP Version: 9.16.1.2501 in PowerShell 7.5.1.
An example of the script. If I take out the shareproperties piece, it works perfectly.
Set-NcCifsShare -Name $shareName -SymlinkProperties enable -AccessBasedEnumeration $true -ShareProperties "browsable" -VserverContext $storageVM
Is there any way to set that option via PowerShell?
Solved! See The Solution
Hey Matt,
Just FYI if a PowerShell CmdLet doesn't support setting a value you can either use the Private REST CLI to invoke an SSH command HTTPS or if the PSTK CmdLet doesn't support setting a property value but the REST API does and you don't want to use ZAPI you can write your own functions around the native ONTAP REST API's. Here's an example that enables you to set a CIFS share property value using REST and PowerShell
Param(
[Parameter(Mandatory = $True, HelpMessage = "The IP Address of the Cluster or SVM")]
[String]$Cluster,
[Parameter(Mandatory = $True, HelpMessage = "The Vserver Name")]
[String]$VserverName,
[Parameter(Mandatory = $False, HelpMessage = "The Vserver UUID")]
[String]$VserverID,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Name")]
[String]$ShareName,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Property")]
[ValidateSet("oplocks","browsable","showsnapshot","changenotify","homedirectory","attributecache")]
[String]$ShareProperty,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Property Enabled State")]
[Bool]$Enabled,
[Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to the Cluster or SVM")]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]$Credential
)
#'------------------------------------------------------------------------------
Function Get-OntapVserver{
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, HelpMessage = "The Cluster Name or IP Address")]
[String]$Cluster,
[Parameter(Mandatory = $True, HelpMessage = "The Vserver Name")]
[String]$VserverName,
[Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to the Cluster")]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]$Credential
)
#'---------------------------------------------------------------------------
#'Set the authentication header to connect to AIQUM.
#'---------------------------------------------------------------------------
$headers = Get-UMAuthorization -Credential $Credential
#'---------------------------------------------------------------------------
#'Enumerate the vservers.
#'---------------------------------------------------------------------------
[String]$uri = "https://$Cluster/api/svm/svms?name=$VserverName"
Try{
$response = Invoke-RestMethod -Uri $uri -Method GET -Headers $headers -ErrorAction Stop
Write-Host "Enumerated Vserver ""$VserverName"" on Cluster ""$Cluster"" using URI ""$uri"""
}Catch{
Write-Warning -Message $("Failed enumerating Vserver ""$VserverName"" on Cluster ""$Cluster"" using URI ""$uri"". Error " + $_.Exception.Message + ". Status Code " + $_.Exception.Response.StatusCode.value__)
}
Return $response;
}#'End Function Get-OntapVserver.
#'------------------------------------------------------------------------------
Function Set-OntapCifsShareProperty{
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, HelpMessage = "The IP Address of the Cluster or SVM")]
[String]$Cluster,
[Parameter(Mandatory = $True, HelpMessage = "The Vserver Name")]
[String]$VserverName,
[Parameter(Mandatory = $False, HelpMessage = "The Vserver UUID")]
[String]$VserverID,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Name")]
[String]$ShareName,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Property")]
[ValidateSet("oplocks","browsable","showsnapshot","changenotify","homedirectory","attributecache")]
[String]$ShareProperty,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Property Enabled State")]
[Bool]$Enabled,
[Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to the Cluster or SVM")]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]$Credential
)
#'---------------------------------------------------------------------------
#'Enumerate the Vserver UUID if not provided.
#'---------------------------------------------------------------------------
If(-Not($VserverID)){
$vserver = Get-OntapVserver -Cluster $Cluster -VserverName $VserverName -Credential $Credential
If(($Null -eq $Vserver) -Or ($vserver.num_records -ne 1)){
Write-Warning -Message "Failed enumerating UUID for Vserver ""$VserverName"" on Cluster ""$Cluster"""
Return $Null;
}Else{
[String]$VserverID = $vserver.records.uuid
}
}
#'---------------------------------------------------------------------------
#'Set the CIFS Share Property.
#'---------------------------------------------------------------------------
[String]$url = "https://$Cluster/api/protocols/cifs/shares/$VserverID/$ShareName"
$json = @{"$ShareProperty" = $Enabled.ToString()}
$body = $json | ConvertTo-Json
Try{
$response = Invoke-RestMethod -Method Patch -Body $body -Uri $url -Credential $Credential -ErrorAction Stop
Write-Host "Set CIFS Share ""$ShareName"" Property ""$ShareProperty"" on Vserver ""$VserverName"" on Cluster ""$Cluster"" using URL`: ""$url"""
}Catch{
Write-Warning -Message $("Failed setting CIFS Share Property ""$ShareProperty"" on Vserver ""$VserverName"" on Cluster ""$Cluster"" using URL`: ""$url"". Error " + $_.Exception.Message)
}
Return $response;
}#'End Function Set-OntapCifsShareProperty.
#'------------------------------------------------------------------------------
Function Get-UMAuthorization{
[Alias("Get-UMAuth")]
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to AIQUM")]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]$Credential
)
#'---------------------------------------------------------------------------
#'Set the authentication header to connect to AIQUM.
#'---------------------------------------------------------------------------
$auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Credential.UserName + ':' + $Credential.GetNetworkCredential().Password))
$headers = @{
"Authorization" = "Basic $auth"
"Accept" = "application/json"
"Content-Type" = "application/json"
}
Return $headers;
}#'End Function Get-UMAuthorization.
#'------------------------------------------------------------------------------
#'Set the certificate policy and TLS version.
#'------------------------------------------------------------------------------
Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
#[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
#'------------------------------------------------------------------------------
#'Disable SSL Check.
#'------------------------------------------------------------------------------
$sslHandler = @"
public class SSLHandler{
public static System.Net.Security.RemoteCertificateValidationCallback GetSSLHandler(){
return new System.Net.Security.RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });
}
}
"@
Add-Type -TypeDefinition $sslHandler
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = [SSLHandler]::GetSSLHandler()
#'------------------------------------------------------------------------------
$response = Set-OntapCifsShareProperty -Cluster $Cluster -VserverName $VserverName -ShareName $ShareName -ShareProperty $ShareProperty -Enabled $Enabled -Credential $Credential
$response
Example:
PS C:\Scripts\PowerShell\Projects\SetCifsShareProperty> $Credential = Get-Credential
PS C:\Scripts\PowerShell\Projects\SetCifsShareProperty> .\SetCifsShareProperty.ps1 -Cluster 192.168.100.2 -VserverName svm1 -ShareName "share1`$" -ShareProperty browsable -Enabled $true -Credential $credential
Enumerated Vserver "svm1" on Cluster "192.168.100.2" using URI "https://192.168.100.2/api/svm/svms?name=svm1"
Set CIFS Share "share1$" Property "browsable" on Vserver "svm1" on Cluster "192.168.100.2" using URL: "https://192.168.100.2/api/protocols/cifs/shares/939ee27e-e202-11ef-aef5-00a098bd4884/testshare$"
cluster1::> cifs share show -vserver svm1 -share-name share1$ -fields share-properties
vserver share-name share-properties
------------ ----------- -----------------------------------------------------
svm1 share1$ oplocks,browsable,changenotify,show-previous-versions
Hope that helps
/Matt
Hey Matt,
The browsable parameter was introduced in the REST API in ONTAP 9.13
/protocols/cifs/shares/{svm.uuid}/{name}
It's possible that the PSTK CmdLet has not yet been updated to support setting this property (although it is possible if you use the native REST API). You could either write a PowerShell Function that invokes the REST API externally to the PSTK or alternately you can use the -ZapiCall parameter on the "Connect-NcController" CmdLet which will force the connection to the cluster to use ZAPI instead of the REST API and then you should be able to set the "ShareProperties" parameter to "browsable".
/Matt
Hey Matt,
Just FYI if a PowerShell CmdLet doesn't support setting a value you can either use the Private REST CLI to invoke an SSH command HTTPS or if the PSTK CmdLet doesn't support setting a property value but the REST API does and you don't want to use ZAPI you can write your own functions around the native ONTAP REST API's. Here's an example that enables you to set a CIFS share property value using REST and PowerShell
Param(
[Parameter(Mandatory = $True, HelpMessage = "The IP Address of the Cluster or SVM")]
[String]$Cluster,
[Parameter(Mandatory = $True, HelpMessage = "The Vserver Name")]
[String]$VserverName,
[Parameter(Mandatory = $False, HelpMessage = "The Vserver UUID")]
[String]$VserverID,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Name")]
[String]$ShareName,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Property")]
[ValidateSet("oplocks","browsable","showsnapshot","changenotify","homedirectory","attributecache")]
[String]$ShareProperty,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Property Enabled State")]
[Bool]$Enabled,
[Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to the Cluster or SVM")]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]$Credential
)
#'------------------------------------------------------------------------------
Function Get-OntapVserver{
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, HelpMessage = "The Cluster Name or IP Address")]
[String]$Cluster,
[Parameter(Mandatory = $True, HelpMessage = "The Vserver Name")]
[String]$VserverName,
[Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to the Cluster")]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]$Credential
)
#'---------------------------------------------------------------------------
#'Set the authentication header to connect to AIQUM.
#'---------------------------------------------------------------------------
$headers = Get-UMAuthorization -Credential $Credential
#'---------------------------------------------------------------------------
#'Enumerate the vservers.
#'---------------------------------------------------------------------------
[String]$uri = "https://$Cluster/api/svm/svms?name=$VserverName"
Try{
$response = Invoke-RestMethod -Uri $uri -Method GET -Headers $headers -ErrorAction Stop
Write-Host "Enumerated Vserver ""$VserverName"" on Cluster ""$Cluster"" using URI ""$uri"""
}Catch{
Write-Warning -Message $("Failed enumerating Vserver ""$VserverName"" on Cluster ""$Cluster"" using URI ""$uri"". Error " + $_.Exception.Message + ". Status Code " + $_.Exception.Response.StatusCode.value__)
}
Return $response;
}#'End Function Get-OntapVserver.
#'------------------------------------------------------------------------------
Function Set-OntapCifsShareProperty{
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, HelpMessage = "The IP Address of the Cluster or SVM")]
[String]$Cluster,
[Parameter(Mandatory = $True, HelpMessage = "The Vserver Name")]
[String]$VserverName,
[Parameter(Mandatory = $False, HelpMessage = "The Vserver UUID")]
[String]$VserverID,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Name")]
[String]$ShareName,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Property")]
[ValidateSet("oplocks","browsable","showsnapshot","changenotify","homedirectory","attributecache")]
[String]$ShareProperty,
[Parameter(Mandatory = $True, HelpMessage = "The CIFS Share Property Enabled State")]
[Bool]$Enabled,
[Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to the Cluster or SVM")]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]$Credential
)
#'---------------------------------------------------------------------------
#'Enumerate the Vserver UUID if not provided.
#'---------------------------------------------------------------------------
If(-Not($VserverID)){
$vserver = Get-OntapVserver -Cluster $Cluster -VserverName $VserverName -Credential $Credential
If(($Null -eq $Vserver) -Or ($vserver.num_records -ne 1)){
Write-Warning -Message "Failed enumerating UUID for Vserver ""$VserverName"" on Cluster ""$Cluster"""
Return $Null;
}Else{
[String]$VserverID = $vserver.records.uuid
}
}
#'---------------------------------------------------------------------------
#'Set the CIFS Share Property.
#'---------------------------------------------------------------------------
[String]$url = "https://$Cluster/api/protocols/cifs/shares/$VserverID/$ShareName"
$json = @{"$ShareProperty" = $Enabled.ToString()}
$body = $json | ConvertTo-Json
Try{
$response = Invoke-RestMethod -Method Patch -Body $body -Uri $url -Credential $Credential -ErrorAction Stop
Write-Host "Set CIFS Share ""$ShareName"" Property ""$ShareProperty"" on Vserver ""$VserverName"" on Cluster ""$Cluster"" using URL`: ""$url"""
}Catch{
Write-Warning -Message $("Failed setting CIFS Share Property ""$ShareProperty"" on Vserver ""$VserverName"" on Cluster ""$Cluster"" using URL`: ""$url"". Error " + $_.Exception.Message)
}
Return $response;
}#'End Function Set-OntapCifsShareProperty.
#'------------------------------------------------------------------------------
Function Get-UMAuthorization{
[Alias("Get-UMAuth")]
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, HelpMessage = "The Credential to authenticate to AIQUM")]
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]$Credential
)
#'---------------------------------------------------------------------------
#'Set the authentication header to connect to AIQUM.
#'---------------------------------------------------------------------------
$auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Credential.UserName + ':' + $Credential.GetNetworkCredential().Password))
$headers = @{
"Authorization" = "Basic $auth"
"Accept" = "application/json"
"Content-Type" = "application/json"
}
Return $headers;
}#'End Function Get-UMAuthorization.
#'------------------------------------------------------------------------------
#'Set the certificate policy and TLS version.
#'------------------------------------------------------------------------------
Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
#[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
#'------------------------------------------------------------------------------
#'Disable SSL Check.
#'------------------------------------------------------------------------------
$sslHandler = @"
public class SSLHandler{
public static System.Net.Security.RemoteCertificateValidationCallback GetSSLHandler(){
return new System.Net.Security.RemoteCertificateValidationCallback((sender, certificate, chain, policyErrors) => { return true; });
}
}
"@
Add-Type -TypeDefinition $sslHandler
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = [SSLHandler]::GetSSLHandler()
#'------------------------------------------------------------------------------
$response = Set-OntapCifsShareProperty -Cluster $Cluster -VserverName $VserverName -ShareName $ShareName -ShareProperty $ShareProperty -Enabled $Enabled -Credential $Credential
$response
Example:
PS C:\Scripts\PowerShell\Projects\SetCifsShareProperty> $Credential = Get-Credential
PS C:\Scripts\PowerShell\Projects\SetCifsShareProperty> .\SetCifsShareProperty.ps1 -Cluster 192.168.100.2 -VserverName svm1 -ShareName "share1`$" -ShareProperty browsable -Enabled $true -Credential $credential
Enumerated Vserver "svm1" on Cluster "192.168.100.2" using URI "https://192.168.100.2/api/svm/svms?name=svm1"
Set CIFS Share "share1$" Property "browsable" on Vserver "svm1" on Cluster "192.168.100.2" using URL: "https://192.168.100.2/api/protocols/cifs/shares/939ee27e-e202-11ef-aef5-00a098bd4884/testshare$"
cluster1::> cifs share show -vserver svm1 -share-name share1$ -fields share-properties
vserver share-name share-properties
------------ ----------- -----------------------------------------------------
svm1 share1$ oplocks,browsable,changenotify,show-previous-versions
Hope that helps
/Matt
Thank you both for the replies! Do you think this is something that will eventually be added to the PSTK?
Hey Matt,
Yes I would assume this will be fixed in a future PSTK as it's possible to set the browsable CIFS Share property via the REST API. I'll ping the dev team to put it on their radar.
/Matt
Sounds good. Thanks, Matt.