Public/New-HDTWorkspaceShare.ps1
|
function New-HDTWorkspaceShare { <# .SYNOPSIS Publishes a deployment share's folder over SMB, and answers with the deploy root that reaches it. .DESCRIPTION THE HALF MDT'S WIZARD DOES AND HDT'S DID NOT. New Deployment Share asks for a folder and a share name, creates the share, and derives DeployRoot from it. Until this existed the console asked for the UNC instead - a box somebody typed a path into, naming a share nothing had created, which is a boot image that fails at the Welcome screen. IT CHANGES THE MACHINE, WHICH IS WHY IT IS NOT New-HDTWorkspace. Writing a folder of YAML and publishing an SMB share are different kinds of act - the first needs nothing, the second needs elevation and alters what the network can reach - and a command that did both could not be run twice, nor run at all by somebody without rights. ELEVATION IS SAID, NOT THROWN. Creating a share without it fails inside the SmbShare module with an access error naming a CIM class; this checks first and says which console to reopen - and says it before the folder's name is even judged, because "reopen elevated" is the whole answer and a share name complaint on top of it is noise. THE ACL MATTERS MORE HERE THAN IN MDT. Control\share-credential.json is obfuscated rather than encrypted, so read access to this share is the deployment account. -Account grants read to one account and nothing else; without it the share is created with no grant at all and the administrator sets it, which is the safe default because it reaches nobody until somebody decides who. IT IS NOT A REPAIR. A name already published on this machine is refused, naming it, rather than reconfigured - somebody else's share is not this command's to change. .PARAMETER Path The folder to publish. It is not created here: New-HDTWorkspace writes it, and this publishes what is there. .PARAMETER ShareName The name to publish under. Omitted, the folder's leaf with a dollar. .PARAMETER ServerName The machine the deploy root should name. Defaults to this one. .PARAMETER Account An account to grant read access to - the deployment account. Omitted, no access is granted and the share reaches nobody until somebody decides who. .PARAMETER Description What the share is called in the share list. .PARAMETER SmbService An ISmbService. Defaults to the real adapter. .PARAMETER Elevated Whether this process can publish a share. Defaults to what Test-HDTElevation answers; passed explicitly, the refusal can be proved without a second process. .INPUTS None. This command does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject with ShareName, Path and DeployRoot. .EXAMPLE New-HDTWorkspaceShare -Path 'C:\HDTLab\Share' -Account 'LAP-AMMSO01\svc-hdt-deploy' .LINK New-HDTWorkspace .LINK Get-HDTWorkspaceShareName #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] [OutputType([pscustomobject])] param( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Position = 1)] [AllowEmptyString()] [string] $ShareName = '', [Parameter()] [AllowEmptyString()] [string] $ServerName = [System.Environment]::MachineName, [Parameter()] [AllowEmptyString()] [string] $Account = '', [Parameter()] [AllowEmptyString()] [string] $Description = 'HDT deployment share', [Parameter()] [AllowNull()] [object] $SmbService, # WHETHER THIS PROCESS CAN PUBLISH ONE AT ALL. Taken as a parameter # rather than asked here, so the refusal is provable without a second # process and a UAC prompt - Test-HDTElevation is the adapter that asks. [Parameter()] [bool] $Elevated = (Test-HDTElevation) ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' if ($null -eq $SmbService) { $SmbService = New-HDTSmbService } # ELEVATION FIRST, BEFORE ANYTHING IS SAID ABOUT NAMES. Without it # New-SmbShare fails inside the SmbShare module with an access error naming # a CIM class, which tells a technician nothing about what to do - and it # fails AFTER the folder has been written, so the share is the only half # missing and nothing says which half. if (-not $Elevated) { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord -TargetObject $Path -Category PermissionDenied ` -Message 'publishing a folder over SMB needs administrator rights, and this console does not have them. Close it and reopen it as an administrator - right-click, Run as administrator - or create the share yourself and set the deploy root on the share''s properties. The folder itself is already written either way.')) } $decided = Get-HDTWorkspaceShareName -Path $Path -ShareName $ShareName -ServerName $ServerName if (-not $decided.IsValid) { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord -TargetObject $ShareName -Category InvalidArgument ` -Message ([string] $decided.Message))) } # ALREADY PUBLISHED IS NOT THIS COMMAND'S TO CHANGE. if ($SmbService.GetShare([string] $decided.ShareName)) { $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord -TargetObject $decided.ShareName -Category ResourceExists ` -Message ("'{0}' is already a share on {1}. Choose another name, or point the deploy root at the share that is already there - the folder itself is untouched either way." -f $decided.ShareName, $ServerName))) } if (-not $PSCmdlet.ShouldProcess( ('{0} as \\{1}\{2}' -f $Path, $ServerName, $decided.ShareName), 'Publish this folder over SMB')) { return [pscustomobject] @{ ShareName = [string] $decided.ShareName Path = $Path DeployRoot = [string] $decided.DeployRoot } } $SmbService.NewShare($Path, [string] $decided.ShareName, $Description) if (-not [string]::IsNullOrWhiteSpace($Account)) { $SmbService.GrantShareAccess([string] $decided.ShareName, $Account, 'Read') } return [pscustomobject] @{ ShareName = [string] $decided.ShareName Path = $Path DeployRoot = [string] $decided.DeployRoot } } |