Functions/Invoke-POSHOriginNEW.ps1
function Invoke-POSHOriginNEW { [cmdletbinding()] param( [parameter(Mandatory,ValueFromPipeline)] [psobject[]]$Resource, [switch]$NoTranslate, [switch]$WhatIf, [switch]$PassThru ) begin { # Start stopwatch $sw = [diagnostics.stopwatch]::StartNew() $results = @() # Used to track DSC resources that have been executed. # We'll use this so any dependent resources will only execute # if all of their dependencies have. # NOTE # This doesn't validate that the dependent service is in the desired state. Only that the "Set" function was executed $executedResources = @() if ($PSBoundParameters.ContainsKey('NoTranslate')) { Write-Verbose -Message "NoTranslate specified. No property translation will be attempted" } function Write-ResourceStatus { param ( [string]$Resource, [string]$Name, [ValidateSet('Test', 'Get', 'Set')] [string]$State ) $cmd = { switch ($State) { 'Test' { Write-Host -Object "Testing resource " -ForegroundColor Cyan -NoNewLine } 'Get' { Write-Host -Object "Getting resource " -ForegroundColor Cyan -NoNewLine } 'Set' { Write-Host -Object "Setting resource " -ForegroundColor Cyan -NoNewLine } } Write-Host -Object "[$Resource" -ForegroundColor Magenta -NoNewLine Write-Host -Object "[$Name]" -ForegroundColor Green -NoNewLine Write-Host -Object "]" -ForegroundColor Magenta } Invoke-Command -ScriptBlock $cmd } } process { foreach ($item in $Resource) { #Write-Host -Object "`n" $result = "" | Select Resource, InDesiredState # Derive the resource type and module from the resource properties # and try to find the DSC resource $module = $item.Resource.Split(':')[0] $resource = $item.Resource.Split(':')[1] $dscResource = Get-DscResource -Name $resource -Module $module -ErrorAction SilentlyContinue -WarningAction SilentlyContinue if (-Not $dscResource) { $dscResource = Get-DscResource -Name $resource -Module "POSHOrigin_$module" -ErrorAction SilentlyContinue -WarningAction SilentlyContinue } if (-Not $dscResource) { $dscResource = Get-DscResource -Name $resource -Module 'POSHOrigin' -ErrorAction SilentlyContinue -WarningAction SilentlyContinue } if ($dscResource) { # Construct resource parameters if ($null -eq $item.Options.Ensure) { $item.Options | Add-Member -Type NoteProperty -Name 'Ensure' -Value 'Present' } # Our params and hash to be splatted to Invoke-DscResource $params = @{} $hash = @{} # Test for 'Invoke.ps1' script in DSC resource module and optionally use it to translate our options into what the # DSC resource expects. # If there is no 'Invoke.ps1' script or we specified '-NoTranslate' then pass the resource object directly to the DSC resource # without any translation. This requires that the correct property names are specificed in the configurations file # as they will be passed directly to Invoke-DscResource. $invokePath = Join-Path -Path $dscResource.ParentPath -ChildPath 'Invoke.ps1' if (Test-Path -Path $invokePath) { if (-Not $PSBoundParameters.ContainsKey('NoTranslate')) { # Use the 'Invoke.ps1' script to translate our options into what the DSC resource expects. Write-Verbose -Message "Calling $invokePath to translate properties" $hash = & $invokePath -Options $item -Direct:$true } else { # We are intentially not using the 'Invoke.ps1' script and instead directly passing the object on $propNames = $item.options | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name | Where-Object {$_ -ne 'DependsOn'} $propNames | ForEach-Object { $hash.Add($_, $item.Options.$_) } # We have to stip out any properties from the POSHOrigin resource object that the DSC resource does not expect $dscResourceProperties = $dscResource.Properties | Select-Object -ExpandProperty Name $hashProperties = $hash.GetEnumerator() | Select-Object -ExpandProperty Name foreach ($hashProperty in $hashProperties) { if ($hashProperty -inotin $dscResourceProperties) { $hash.remove($hashProperty) } } } } else { #throw "$invokePath not found in DSC module so no property translation could be made. Try using the -NoTranslate switch instead." # There is no 'Invoke.ps1' script we we'll just pass on the properties directly to the DSC resource # without any translation $propNames = $item.options | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name $propNames | ForEach-Object { $hash.Add($_, $item.Options.$_) } # We have to stip out any properties from the POSHOrigin resource object that the DSC resource does not expect $dscResourceProperties = $dscResource.Properties | Select-Object -ExpandProperty Name $hashProperties = $hash.GetEnumerator() | Select-Object -ExpandProperty Name foreach ($hashProperty in $hashProperties) { if ($hashProperty -inotin $dscResourceProperties) { $hash.remove($hashProperty) } } } $params = @{ Name = $dscResource.Name ModuleName = $dscResource.ModuleName Property = $hash } #Write-Host ($params.Property | format-list * | Out-String) #Write-Host $hash.GuestCredentials.Username if ($PSBoundParameters.ContainsKey('WhatIf')) { # Just test the resource Write-ResourceStatus -Resource $dscResource.Name -Name $item.Name -State Test $testResult = $null $testResult = Invoke-DscResource -Method Test @params -Verbose:$VerbosePreference if ($PSBoundParameters.ContainsKey('PassThru')) { $result = "" | Select Resource, InDesiredState Write-ResourceStatus -Resource $dscResource.Name -Name $item.Name -State Get $getResult = $null $getResult = Invoke-DscResource -Method Get @params -Verbose:$VerbosePreference $result.Resource = $getResult $result.InDesiredState = $testResult.InDesiredState $results += $result } } else { # Test if this resource has any dependencies and only execute if those have been met. $continue = $true $dependenciesExist = @(($item.DependsOn).Count -gt 0) if ($dependenciesExist) { if ($dependency -inotin $executedResources.Keys) { $continue = $false } } else { $continue = $true } # All dependencies met? if ($continue) { # Test and invoke the resource $testResult = $null Write-ResourceStatus -Resource $dscResource.Name -Name $item.Name -State Test $testResult = Invoke-DscResource -Method Test @params -Verbose:$VerbosePreference -InformationAction $InformationPreference if (-Not $testResult.InDesiredState) { Write-ResourceStatus -Resource $dscResource.Name -Name $item.Name -State Set try { $setResult = Invoke-DscResource -Method Set @params -Verbose:$VerbosePreference -InformationAction $InformationPreference } catch { Write-Error -Message 'There was a problem setting the resource' Write-Error -Message "$($_.InvocationInfo.ScriptName)($($_.InvocationInfo.ScriptLineNumber)): $($_.InvocationInfo.Line)" write-Error $_ } } # Track the resource as 'executed' for dependent resources $executedResources += $item.FullName } else { Write-Error -Message "Dependencies have not been met for resource $($item.FullName). This resource will not be invoked." } if ($PSBoundParameters.ContainsKey('PassThru')) { Write-ResourceStatus -Resource $dscResource.Name -Name $item.Name -State Test $testResult = $null $testResult = Invoke-DscResource -Method Test @params -Verbose:$VerbosePreference -InformationAction $InformationPreference Write-ResourceStatus -Resource $dscResource.Name -Name $item.Name -State Get $getResult = $null $getResult = Invoke-DscResource -Method Get @params -Verbose:$VerbosePreference -InformationAction $InformationPreference $result.Resource = $getResult $result.InDesiredState = $testResult.InDesiredState $results += $result } } } else { Write-Error -Message "Unable to find DSC resource: $($item.Resource)" } } } end { if ($PSBoundParameters.ContainsKey('PassThru')) { $results } # Stop stopwatch Write-Verbose -Message "`nCommand finished in $($sw.elapsed.seconds) seconds" $sw.stop() } } |