DSCClassResources/JeaRoleCapabilities/JeaRoleCapabilities.psm1
using namespace System.Management.Automation.Language enum Ensure { Present Absent } [DscResource()] class JeaRoleCapabilities { [DscProperty()] [Ensure]$Ensure = [Ensure]::Present # Where to store the file. [DscProperty(Key)] [String]$Path # Specifies the modules that are automatically imported into sessions that use the role capability file. # By default, all of the commands in listed modules are visible. When used with VisibleCmdlets or VisibleFunctions, # the commands visible from the specified modules can be restricted. Hashtable with keys ModuleName, ModuleVersion and GUID. [DscProperty()] [string[]]$ModulesToImport # Limits the aliases in the session to those aliases specified in the value of this parameter, # plus any aliases that you define in the AliasDefinition parameter. Wildcard characters are supported. # By default, all aliases that are defined by the Windows PowerShell engine and all aliases that modules export are # visible in the session. [DscProperty()] [String[]]$VisibleAliases # Limits the cmdlets in the session to those specified in the value of this parameter. # Wildcard characters and Module Qualified Names are supported. [DscProperty()] [String[]]$VisibleCmdlets # Limits the functions in the session to those specified in the value of this parameter, # plus any functions that you define in the FunctionDefinitions parameter. Wildcard characters are supported. [DscProperty()] [String[]]$VisibleFunctions # Limits the external binaries, scripts and commands that can be executed in the session to those specified in # the value of this parameter. Wildcard characters are supported. [DscProperty()] [String[]]$VisibleExternalCommands # Limits the Windows PowerShell providers in the session to those specified in the value of this parameter. # Wildcard characters are supported. [DscProperty()] [String[]]$VisibleProviders # Specifies scripts to add to sessions that use the role capability file. [DscProperty()] [string[]]$ScriptsToProcess # Adds the specified aliases to sessions that use the role capability file. # Hashtable with keys Name, Value, Description and Options. [DscProperty()] [string[]]$AliasDefinitions # Adds the specified functions to sessions that expose the role capability. # Hashtable with keys Name, Scriptblock and Options. [DscProperty()] [string[]]$FunctionDefinitions # Specifies variables to add to sessions that use the role capability file. # Hashtable with keys Name, Value, Options. [DscProperty()] [string[]]$VariableDefinitions # Specifies the environment variables for sessions that expose this role capability file. # Hashtable of environment variables. [DscProperty()] [string[]]$EnvironmentVariables # Specifies type files (.ps1xml) to add to sessions that use the role capability file. # The value of this parameter must be a full or absolute path of the type file names. [DscProperty()] [string[]]$TypesToProcess # Specifies the formatting files (.ps1xml) that run in sessions that use the role capability file. # The value of this parameter must be a full or absolute path of the formatting files. [DscProperty()] [String[]]$FormatsToProcess # Specifies the assemblies to load into the sessions that use the role capability file. [DscProperty()] [String[]]$AssembliesToLoad Hidden [Boolean] ValidatePath() { $FileObject = [System.IO.FileInfo]::new($this.Path) Write-Verbose -Message "Validating Path: $($FileObject.Fullname)" Write-Verbose -Message "Checking file extension is psrc for: $($FileObject.Fullname)" if ($FileObject.Extension -ne '.psrc') { Write-Verbose -Message "Doesn't have psrc extension for: $($FileObject.Fullname)" return $false } Write-Verbose -Message "Checking parent forlder is RoleCapabilities for: $($FileObject.Fullname)" if ($FileObject.Directory.Name -ne 'RoleCapabilities') { Write-Verbose -Message "Parent folder isn't RoleCapabilities for: $($FileObject.Fullname)" return $false } Write-Verbose -Message "Checking Folder is in PSModulePath is psrc for: $($FileObject.Fullname)" $PSModulePathRegexPattern = (([Regex]::Escape($env:PSModulePath)).TrimStart(';').TrimEnd(';') -replace ';', '|') if ($FileObject.FullName -notmatch $PSModulePathRegexPattern) { Write-Verbose -Message "Path isn't part of PSModulePath, valid values are:" foreach ($path in $env:PSModulePath -split ';') { Write-Verbose -Message "$Path" } return $false } Write-Verbose -Message "Path is a valid psrc path. Returning true." return $true } [JeaRoleCapabilities] Get() { $CurrentState = [JeaRoleCapabilities]::new() $CurrentState.Path = $this.Path if (Test-Path -Path $this.Path) { $CurrentStateFile = Import-PowerShellDataFile -Path $this.Path 'Copyright', 'GUID', 'Author', 'CompanyName' | Foreach-Object { $CurrentStateFile.Remove($_) } foreach ($Property in $CurrentStateFile.Keys) { $CurrentState.$Property = $CurrentStateFile[$Property] } $CurrentState.Ensure = [Ensure]::Present } else { $CurrentState.Ensure = [Ensure]::Absent } return $CurrentState } [void] Set() { if ($this.Ensure -eq [Ensure]::Present) { $Parameters = Convert-ObjectToHashtable($this) $Parameters.Remove('Ensure') Foreach ($Parameter in $Parameters.Keys.Where( {$Parameters[$_] -match '@{'})) { $Parameters[$Parameter] = Convert-StringToObject -InputString $Parameters[$Parameter] } $InvalidConfiguration = $false if ($Parameters.ContainsKey('FunctionDefinitions')) { foreach ($FunctionDefName in $Parameters['FunctionDefinitions'].Name) { if ($FunctionDefName -notin $Parameters['VisibleFunctions']) { Write-Error -Message "Function defined but not visible to Role Configuration: $FunctionDefName" $InvalidConfiguration = $true } } } if (-not $InvalidConfiguration) { $null = New-Item -Path $this.Path -ItemType File -Force New-PSRoleCapabilityFile @Parameters } } elseif ($this.Ensure -eq [Ensure]::Absent -and (Test-Path -Path $this.Path)) { Remove-Item -Path $this.Path -Confirm:$False } } [bool] Test() { if (-not ($this.ValidatePath())) { Write-Error -Message "Invalid path specified. It must point to a Module folder, be a psrc file and the parent folder must be called RoleCapabilities" return $false } if ($this.Ensure -eq [Ensure]::Present -and -not (Test-Path -Path $this.Path)) { return $false } elseif ($this.Ensure -eq [Ensure]::Present -and (Test-Path -Path $this.Path)) { $CurrentState = Convert-ObjectToHashtable -Object $this.Get() $Parameters = Convert-ObjectToHashtable -Object $this $Compare = Compare-JeaConfiguration -ReferenceObject $CurrentState -DifferenceObject $Parameters if ($null -eq $Compare) { return $true } else { return $false } } elseif ($this.Ensure -eq [Ensure]::Absent -and (Test-Path -Path $this.Path)) { return $false } elseif ($this.Ensure -eq [Ensure]::Absent -and -not (Test-Path -Path $this.Path)) { return $true } return $false } } function Convert-StringToObject { [cmdletbinding()] param ( [string[]]$InputString ) $ParseErrors = @() $FakeCommand = "Totally-NotACmdlet -FakeParameter $InputString" $AST = [Parser]::ParseInput($FakeCommand, [ref]$null, [ref]$ParseErrors) if (-not $ParseErrors) { # Use Ast.Find() to locate the CommandAst parsed from our fake command $CmdAst = $AST.Find( {param($ChildAst) $ChildAst -is [CommandAst]}, $false) # Grab the user-supplied arguments (index 0 is the command name, 1 is our fake parameter) $AllArgumentAst = $CmdAst.CommandElements.Where( {$_ -isnot [CommandParameterAst] -and $_.Value -ne 'Totally-NotACmdlet'}) foreach ($ArgumentAst in $AllArgumentAst) { if ($ArgumentAst -is [ArrayLiteralAst]) { # Argument was a list foreach ($Element in $ArgumentAst.Elements) { if ($Element.StaticType.Name -eq 'String') { $Element.value } if ($Element.StaticType.Name -eq 'Hashtable') { [Hashtable]$Element.SafeGetValue() } } } else { if ($ArgumentAst -is [HashtableAst]) { $ht = [Hashtable]$ArgumentAst.SafeGetValue() for ($i = 1; $i -lt $ht.Keys.Count; $i++) { $value = $ht[([array]$ht.Keys)[$i]] if ($value -is [scriptblock]) { $scriptBlockText = $value.Ast.Extent.Text if ($scriptBlockText[$value.Ast.Extent.StartOffset] -eq '{' -and $scriptBlockText[$endOffset - 1] -eq '}') { $scriptBlockText = $scriptBlockText.Substring(0, $scriptBlockText.Length - 1) $scriptBlockText = $scriptBlockText.Substring(1, $scriptBlockText.Length - 1) } $ht[([array]$ht.Keys)[$i]] = [scriptblock]::Create($scriptBlockText) } } $ht } elseif ($ArgumentAst -is [StringConstantExpressionAst]) { $ArgumentAst.Value } else { Write-Error -Message "Input was not a valid hashtable, string or collection of both. Please check the contents and try again." } } } } } |