QlikResources.psm1
enum Ensure { Absent Present } enum ReloadOn { None Create Update } [DscResource()] class QlikApp{ [DscProperty()] [string]$Id [DscProperty(Key)] [string]$Name [DscProperty()] [string]$Source [DscProperty()] [hashtable]$CustomProperties [DscProperty()] [string[]]$Tags [DscProperty(Key)] [string]$Stream [DscProperty()] [ReloadOn]$ReloadOn [DscProperty()] [bool]$Force [DscProperty(Mandatory)] [Ensure]$Ensure [void] Set() { $item = Get-QlikApp -raw -full -filter "name eq '$($this.name)' and (stream.name eq '$($this.Stream)' or stream eq null)" if(@($item).count -gt 1) { $item = $item | ? stream -eq $this.Stream } $present = $item -ne $null if($this.ensure -eq [Ensure]::Present) { if (-Not $present) { Write-Verbose "App not found but should be present" Write-Verbose -Message "Importing app from $($this.Source)" $item = Import-QlikApp -file $this.Source -name $this.Name -upload if ($this.ReloadOn -eq [ReloadOn]::Create) { Write-Verbose "Reloading app since ReloadOn is set to $($this.ReloadOn)" Invoke-QlikPost /qrs/app/$($item.id)/reload } } else #if ($this.Force) { Write-Verbose "Updating app with ID $($item.id)" Write-Verbose -Message "Importing app from $($this.Source)" $replace = Import-QlikApp -file $this.Source -name $this.Name -upload if ($this.ReloadOn -eq [ReloadOn]::Update) { Write-Verbose "Reloading app since ReloadOn is set to $($this.ReloadOn)" # if (($this.Stream -ne ".") -And ($this.Stream -ne $item.stream.name)) # { # Publish-QlikApp -id $replace.id -stream $item.stream.id # } $this.configure($replace) Invoke-QlikPost /qrs/app/$($replace.id)/reload $task = Get-QlikReloadTask -filter "app.id eq $($replace.id)" Start-QlikTask -wait $task.id Wait-QlikExecution -taskId $task.id } Switch-QlikApp -id $replace.id -appId $item.id Remove-QlikApp -id $replace.id } # $props = @() # foreach ($prop in $this.CustomProperties.Keys) # { # $cp = Get-QlikCustomProperty -filter "name eq '$prop'" -raw # if (-Not ($cp.choiceValues -contains $this.CustomProperties.$prop)) # { # $cp.choiceValues += $this.CustomProperties.$prop # Write-Verbose -Message "Updating property $prop with new value of $($this.CustomProperties.$prop)" # Update-QlikCustomProperty -id $cp.id -choiceValues $cp.choiceValues # } # $props += "$($prop)=$($this.CustomProperties.$prop)" # } # $appTags = @() # foreach ($tag in $this.Tags) # { # $tagId = (Get-QlikTag -filter "name eq '$tag'").id # if (-Not $tagId) # { # $tagId = (New-QlikTag -name $tag).id # Write-Verbose "Created tag for $tag with id $tagId" # } # $appTags += $tag # } # Update-QlikApp -id $item.id -tags $appTags -customProperties $props $this.configure($item) if (($this.Stream -ne ".") -And ($this.Stream -ne $item.stream.name)) { $streamId = (Get-QlikStream -filter "name eq '$($this.Stream)'" -raw).id Publish-QlikApp -id $item.id -stream $streamId } } else { if($present) { Write-Verbose -Message "Deleting app $($item.name)" Remove-QlikApp -id $item.id } } } [bool] Test() { $item = Get-QlikApp -raw -full -filter "name eq '$($this.name)' and (stream.name eq '$($this.Stream)' or stream eq null)" if(@($item).count -gt 1) { $item = $item | ? stream -eq $this.Stream } $present = $item -ne $null if($this.Ensure -eq [Ensure]::Present) { if($present) { if($this.hasProperties($item)) { return $true } else { return $false } } else { return $false } } else { if($present) { Write-Verbose "App exists but should be absent" return $false } else { Write-Verbose "App should be absent and was not found" return $true } } } [QlikApp] Get() { $item = Get-QlikApp -raw -full -filter "name eq '$($this.name)' and (stream.name eq '$($this.Stream)' or stream eq null)" if(@($item).count -gt 1) { $item = $item | ? stream -eq $this.Stream } $present = $item -ne $null if ($present) { $this.Ensure = [Ensure]::Present } else { $this.Ensure = [Ensure]::Absent } return $this } [void] configure($item) { $props = @() foreach ($prop in $this.CustomProperties.Keys) { $cp = Get-QlikCustomProperty -filter "name eq '$prop'" -raw if (-Not ($cp.choiceValues -contains $this.CustomProperties.$prop)) { $cp.choiceValues += $this.CustomProperties.$prop Write-Verbose -Message "Updating property $prop with new value of $($this.CustomProperties.$prop)" Update-QlikCustomProperty -id $cp.id -choiceValues $cp.choiceValues } $props += "$($prop)=$($this.CustomProperties.$prop)" } $appTags = @() foreach ($tag in $this.Tags) { $tagId = (Get-QlikTag -filter "name eq '$tag'").id if (-Not $tagId) { $tagId = (New-QlikTag -name $tag).id Write-Verbose "Created tag for $tag with id $tagId" } $appTags += $tag } Update-QlikApp -id $item.id -tags $appTags -customProperties $props } [bool] hasProperties($item) { if( !(CompareProperties $this $item @( 'Name' ) ) ) { return $false } if ($this.Tags) { foreach ($tag in $this.Tags) { if (-Not ($item.tags.name -contains $tag)) { Write-Verbose "Not tagged with $tag" return $false } } } if ($this.CustomProperties) { foreach ($prop in $this.CustomProperties.Keys) { $cp = $item.customProperties | where {$_.definition.name -eq $prop} if (-Not (($cp) -And ($cp.value -eq $this.CustomProperties.$prop))) { Write-Verbose "Property $prop should have value $($this.CustomProperties.$prop) but instead has value $($cp.value)" return $false } } } if (($this.Stream -ne $item.stream.name) -And ($this.Stream -ne ".")) { return $false } return $true } } [DscResource()] class QlikConnect{ [DscProperty(Key)] [string]$Username [DscProperty()] [string]$Computername [DscProperty()] [string]$Certificate #[System.Security.Cryptography.X509Certificates.X509Certificate]$Certificate [DscProperty()] [bool]$TrustAllCerts [DscProperty()] [int]$MaxRetries = 10 [DscProperty()] [int]$RetryDelay = 10 [void] Set() { $cert = gci $this.Certificate $params = @{ Username=$this.Username } if( $this.Computername ) { $params.Add( "Computername", $this.Computername ) } if( $this.Certificate ) { $params.Add( "Certificate", $cert ) } if( $this.TrustAllCerts ) { $params.Add( "TrustAllCerts", $true ) } #Connect-Qlik @params -TrustAllCerts $err = $null for ($i = 1; $i -lt $this.MaxRetries; $i++) { Write-Progress "Connecting to Qlik, attempt $i" try { if (Connect-Qlik -ErrorAction Ignore -ErrorVariable err @params) { break } } catch { Start-Sleep $this.RetryDelay } } if ($err) { throw $err } } [bool] Test() { return $false } [QlikConnect] Get() { $this.Username = $env:Username $this.Computername = $env:Computername return $this } } [DscResource()] class QlikCustomProperty{ [DscProperty(Key)] [string]$Name [DscProperty(Mandatory)] [Ensure]$Ensure [DscProperty()] [string]$ValueType [DscProperty()] [string[]]$ChoiceValues [DscProperty()] [string[]]$ObjectTypes [void] Set() { $item = Get-QlikCustomProperty -raw -full -filter "name eq '$($this.name)'" $present = $item -ne $null if($this.ensure -eq [Ensure]::Present) { $params = @{ "Name" = $this.Name } if($this.ValueType) { $params.Add("ValueType", $this.ValueType) } if($this.ChoiceValues) { $params.Add("ChoiceValues", $this.ChoiceValues) } if($this.ObjectTypes) { $params.Add("ObjectTypes", $this.ObjectTypes) } if($present) { if(-not $this.hasProperties($item)) { Update-QlikCustomProperty -id $item.id @params } } else { New-QlikCustomProperty @params } } else { if($present) { Write-Verbose -Message "Deleting the property $($this.name)" #Remove-QlikCustomProperty -Name $this.Name } } } [bool] Test() { $item = Get-QlikCustomProperty -raw -full -filter "name eq '$($this.name)'" $present = $item -ne $null if($this.Ensure -eq [Ensure]::Present) { if($present) { if($this.hasProperties($item)) { return $true } else { return $false } } else { return $false } } else { return -not $present } } [QlikCustomProperty] Get() { $item = Get-QlikCustomProperty -raw -full -filter "name eq '$($this.name)'" $present = $item -ne $null if ($present) { $this.ValueType = $item.ValueType $this.ChoiceValues = $item.ChoiceValues $this.ObjectTypes = $item.ObjectTypes $this.Ensure = [Ensure]::Present } else { $this.Ensure = [Ensure]::Absent } return $this } [bool] hasProperties($item) { if( !(CompareProperties $this $item @( 'ValueType' ) ) ) { return $false } if($this.ChoiceValues) { if(@($this.ChoiceValues).Count -ne @($item.choiceValues).Count) { Write-Verbose "Test-HasProperties: ChoiceValues property count - $(@($item.choiceValues).Count) does not match desired state - $(@($this.ChoiceValues).Count)" return $false } else { foreach($value in $item.ChoiceValues) { if($this.choiceValues -notcontains $value) { Write-Verbose "Test-HasProperties: ChoiceValues property value - $($value) not found in desired state" return $false } } } } if($this.ObjectTypes) { if(@($this.ObjectTypes).Count -ne @($item.ObjectTypes).Count) { Write-Verbose "Test-HasProperties: ObjectTypes property count - $(@($item.ObjectTypes).Count) does not match desired state - $(@($this.ObjectTypes).Count)" return $false } else { foreach($value in $item.ObjectTypes) { if($this.ObjectTypes -notcontains $value) { Write-Verbose "Test-HasProperties: ObjectTypes property value - $($value) not found in desired state" return $false } } } } return $true } } [DscResource()] class QlikDataConnection{ [DscProperty(Key)] [string]$Name [DscProperty(Mandatory)] [Ensure]$Ensure [DscProperty(Mandatory)] [string]$ConnectionString [DscProperty()] [string]$Tags [DscProperty(Mandatory)] [string]$Type [void] Set() { $item = Get-QlikDataConnection -raw -filter "name eq '$($this.name)'" $present = $item -ne $null if($this.ensure -eq [Ensure]::Present) { if(!$present) { $item = New-QlikDataConnection -Name $this.Name -ConnectionString $this.ConnectionString -Type $this.Type } $prop = ConfigurePropertiesAndTags($this) Update-QlikDataConnection -id $item.id -ConnectionString $this.ConnectionString -Tags $prop.tags } else { if($present) { Write-Verbose -Message "Deleting the file $($this.name)" #Remove-QlikDataConnection -Name $this.Name } } } [bool] Test() { $item = Get-QlikDataConnection -raw -filter "name eq '$($this.name)'" $present = $item -ne $null if($this.Ensure -eq [Ensure]::Present) { if($present) { if($this.hasProperties($item)) { return $true } else { return $false } } else { return $false } } else { return -not $present } } [QlikDataConnection] Get() { $present = $(Get-QlikDataConnection -raw -filter "name eq '$($this.name)'") -ne $null if ($present) { $qdc = Get-QlikDataConnection -raw -filter "name eq '$this.name'" $this.ConnectionString = $qdc.ConnectionString $this.Type = $qdc.Type $this.Ensure = [Ensure]::Present } else { $this.CreationTime = $null $this.Ensure = [Ensure]::Absent } return $this } [bool] hasProperties($item) { if( !(CompareProperties $this $item @( 'ConnectionString', 'Type' ) ) ) { return $false } if ($this.Tags) { foreach ($tag in $this.Tags) { if (-Not ($item.tags.name -contains $tag)) { Write-Verbose "Not tagged with $tag" return $false } } } return $true } } [DscResource()] class QlikLicense{ [DscProperty(Key)] [string]$Serial [DscProperty(Mandatory)] [string]$Control [DscProperty(Mandatory)] [string]$Name [DscProperty(Mandatory)] [string]$Organization [DscProperty(Mandatory)] [string]$Lef [DscProperty(Mandatory)] [Ensure]$Ensure [void] Set() { $license = $(Get-QlikLicense) if ($license) { $present = ($license.serial -eq $this.Serial) } else { $present = $false } Write-Debug $present if($this.ensure -eq [Ensure]::Present) { if(-not $present) { if ($license) { Invoke-QlikDelete "/qrs/license/$($license.id)" } Set-QlikLicense -Serial $this.Serial -Control $this.Control -Name $this.Name -Organization $this.Organization -Lef $this.Lef } } else { if($present) { Write-Verbose -Message "Deleting license $($this.Serial)" Invoke-QlikDelete "/qrs/license/$($license.id)" } } } [bool] Test() { $license = $(Get-QlikLicense) if ($license) { $present = ($license.serial -eq $this.Serial) } else { $present = $false } Write-Debug $present if($this.Ensure -eq [Ensure]::Present) { return $present } else { return -not $present } } [QlikLicense] Get() { $present = $(Get-QlikLicense) -ne $null if ($present) { $license = Get-QlikLicense $this.Serial = $license.Serial $this.Name = $license.Name $this.Organization = $license.Organization $this.Lef = $license.Lef $this.Ensure = [Ensure]::Present } else { $this.Ensure = [Ensure]::Absent } return $this } } [DscResource()] class QlikNode{ [DscProperty(Key)] [string]$HostName [DscProperty()] [string]$Name [DscProperty()] [string]$NodePurpose [DscProperty()] [string[]]$CustomProperties [DscProperty()] [string[]]$Tags [DscProperty()] [bool]$Engine [DscProperty()] [bool]$Proxy [DscProperty()] [bool]$Scheduler [DscProperty()] [bool]$Printing [DscProperty(Mandatory)] [Ensure]$Ensure [void] Set() { $item = Get-QlikNode -raw -full -filter "hostName eq '$($this.HostName)'" $present = $item -ne $null if($this.ensure -eq [Ensure]::Present) { Write-Verbose "Proxy should be $($this.Proxy)" $params = @{} if($this.Name) { $params.Add("Name", $this.Name) } if($this.NodePurpose) { $params.Add("NodePurpose", $this.NodePurpose) } if($this.CustomProperties) { $params.Add("CustomProperties", $this.CustomProperties) } if($this.Tags) { $params.Add("Tags", $this.Tags) } if($this.Engine) { $params.Add("engineEnabled", $this.Engine) } if($this.Proxy) { $params.Add("proxyEnabled", $this.Proxy) } if($this.Scheduler) { $params.Add("schedulerEnabled", $this.Scheduler) } if($this.Printing) { $params.Add("printingEnabled", $this.Printing) } if($present) { if(-not $this.hasProperties($item)) { Update-QlikNode -id $item.id @params } } else { Register-QlikNode -hostName $this.HostName @params } } else { #Remove-QlikNode $this.id } } [bool] Test() { $item = Get-QlikNode -raw -full -filter "hostName eq '$($this.HostName)'" $present = $item -ne $null if($present) { if($this.hasProperties($item)) { return $true } else { return $false } } else { return $false } } [QlikNode] Get() { $item = Get-QlikNode -raw -full -filter "hostName eq '$($this.HostName)'" $present = $item -ne $null if ($present) { $this.NodePurpose = $item.NodePurpose $this.CustomProperties = $item.CustomProperties $this.Tags = $item.Tags $this.Engine = $item.EngineEnabled $this.Proxy = $item.ProxyEnabled $this.Scheduler = $item.SchedulerEnabled $this.Printing = $item.PrintingEnabled } else { } return $this } [bool] hasProperties($item) { if( !(CompareProperties $this $item @( 'NodePurpose', 'Tags' ) ) ) { return $false } If($this.CustomProperties) { foreach( $defined in $this.CustomProperties) { $val = $defined.Split("=") $found = $false foreach( $exists in $item.customProperties ) { if($exists.definition.name -eq $val[0]) { if($val[1] -eq "null" -Or $val[1] -ne $exists.value) { Write-Verbose "Test-HasProperties: Custom property value - $($val[0])=$($exists.value) does not match desired state - $($val[1])" return $false } else { $found = $true } } } if(-not $found) { return $false } } } If($item.EngineEnabled -ne $this.Engine) { Write-Verbose "Test-HasProperties: Engine property value - $($item.EngineEnabled) does not match desired state - $($this.Engine)" return $false } If($item.ProxyEnabled -ne $this.Proxy) { Write-Verbose "Test-HasProperties: Proxy property value - $($item.ProxyEnabled) does not match desired state - $($this.Proxy)" return $false } If($item.SchedulerEnabled -ne $this.Scheduler) { Write-Verbose "Test-HasProperties: Scheduler property value - $($item.SchedulerEnabled) does not match desired state - $($this.Scheduler)" return $false } If($item.PrintingEnabled -ne $this.Printing) { Write-Verbose "Test-HasProperties: Printing property value - $($item.PrintingEnabled) does not match desired state - $($this.Printing)" return $false } return $true } } [DscResource()] class QlikRule{ [DscProperty(Key)] [string]$Name [DscProperty(Mandatory)] [Ensure]$Ensure [DscProperty()] [string]$Category [DscProperty()] [string]$Rule [DscProperty()] [string]$ResourceFilter [DscProperty()] [ValidateSet("hub","qmc","both")] [string]$RuleContext [DscProperty()] [int]$Actions [DscProperty()] [string]$Comment [DscProperty()] [bool]$Disabled [void] Set() { $item = Get-QlikRule -raw -full -filter "name eq '$($this.Name)'" $present = $item -ne $null if($this.ensure -eq [Ensure]::Present) { $params = @{ "Name" = $this.Name } if($this.Category) { $params.Add("Category", $this.Category) } if($this.Rule) { $params.Add("Rule", $this.Rule) } if($this.ResourceFilter) { $params.Add("ResourceFilter", $this.ResourceFilter) } if($this.RuleContext) { $params.Add("RuleContext", $this.RuleContext) } if($this.Actions) { $params.Add("Actions", $this.Actions) } if($this.Comment) { $params.Add("Comment", $this.Comment) } if($this.Disabled) { $params.Add("Disabled", $this.Disabled) } if($present) { if(-not $this.hasProperties($item)) { Update-QlikRule -id $item.id @params } } else { Write-Verbose "Rule $($this.Name) should be present but was not found" if($this.Category -eq "license" -And (-not $this.ResourceFilter)) { $group = New-QlikUserAccessGroup "License rule to grant user access" $params.Add("ResourceFilter", "License.UserAccessGroup_$($group.id)") } New-QlikRule @params } } else { if($present) { Write-Verbose -Message "Deleting the rule $($this.Name)" #Remove-QlikRule -Name $this.Name } } } [bool] Test() { $item = Get-QlikRule -raw -full -filter "name eq '$($this.name)'" $present = $item -ne $null if($this.Ensure -eq [Ensure]::Present) { if($present) { if($this.hasProperties($item)) { return $true } else { return $false } } else { return $false } } else { return -not $present } } [QlikRule] Get() { $item = Get-QlikRule -raw -full -filter "name eq '$($this.name)'" $present = $item -ne $null if ($present) { $this.Category = $item.Category $this.Rule = $item.Rule $this.ResourceFilter = $item.ResourceFilter $this.RuleContext = $item.RuleContext $this.Actions = $item.Actions $this.Comment = $item.Comment $this.Disabled = $item.Disabled $this.Ensure = [Ensure]::Present } else { $this.Ensure = [Ensure]::Absent } return $this } [bool] hasProperties($item) { if( !(CompareProperties $this $item @( 'Category', 'Rule', 'ResourceFilter', 'Actions', 'Comment', 'Disabled' ) ) ) { return $false } if($this.RuleContext) { $context = -1 switch ($this.RuleContext) { both { $context = 0 } hub { $context = 1 } qmc { $context = 2 } } If($item.RuleContext -ne $context) { Write-Verbose "Test-HasProperties: RuleContext property value - $($item.RuleContext) does not match desired state - $context" return $false } } return $true } } [DscResource()] class QlikScheduler{ [DscProperty(Key)] [string]$Node [DscProperty()] [string]$SchedulerServiceType [DscProperty()] [Int]$MaxConcurrentEngines [DscProperty()] [Int]$EngineTimeout [void] Set() { $item = Get-QlikScheduler -raw -full -filter "serverNodeConfiguration.name eq '$($this.Node)'" $params = @{ "id" = $item.id } if($this.SchedulerServiceType) { $params.Add("SchedulerServiceType", $this.SchedulerServiceType) } if($this.MaxConcurrentEngines) { $params.Add("maxConcurrentEngines", $this.MaxConcurrentEngines) } if($this.EngineTimeout) { $params.Add("engineTimeout", $this.EngineTimeout) } Update-QlikScheduler @params } [bool] Test() { $item = Get-QlikScheduler -raw -full -filter "serverNodeConfiguration.name eq '$($this.Node)'" if($this.hasProperties($item)) { return $true } else { return $false } } [QlikScheduler] Get() { $item = Get-QlikScheduler -raw -full -filter "serverNodeConfiguration.name eq '$($this.Node)'" $present = $item -ne $null if ($present) { $this.SchedulerServiceType = $item.settings.SchedulerServiceType } return $this } [bool] hasProperties($item) { If($this.SchedulerServiceType) { $sched_type = -1 switch ($this.schedulerServiceType) { master { $sched_type = 0 } slave { $sched_type = 1 } both { $sched_type = 2 } } if($item.settings.SchedulerServiceType -ne $sched_type) { Write-Verbose "Test-HasProperties: SchedulerServiceType property value - $($item.settings.SchedulerServiceType) does not match desired state - $($sched_type)" return $false } if($item.settings.maxConcurrentEngines -ne $sched_type) { Write-Verbose "Test-HasProperties: MaxConcurrentEngines property value - $($item.settings.maxConcurrentEngines) does not match desired state - $($this.MaxConcurrentEngines)" return $false } if($item.settings.EngineTimeout -ne $sched_type) { Write-Verbose "Test-HasProperties: EngineTimeout property value - $($item.settings.EngineTimeout) does not match desired state - $($this.EngineTimeout)" return $false } } return $true } } [DscResource()] class QlikTask{ [DscProperty(Key)] [string]$Name [DscProperty(Mandatory)] [string]$App [DscProperty()] [string]$Stream [DscProperty()] [hashtable]$Schedule [DscProperty()] [string]$OnSuccess [DscProperty()] [ReloadOn]$StartOn [DscProperty()] [bool]$WaitUntilFinished [DscProperty()] [string]$Tags [DscProperty(Mandatory)] [Ensure]$Ensure [void] Set() { $item = Get-QlikTask -raw -filter "name eq '$($this.name)'" -full $present = $item -ne $null if($this.ensure -eq [Ensure]::Present) { if (-Not $present) { Write-Verbose "Task not found but should be present" $appfilter = "name eq '$($this.App)'" if($this.Stream -ne $null){ $appfilter += " and stream.name eq '$($this.Stream)'"} $item = New-QlikTask -name $this.Name -appId (Get-QlikApp -filter $appfilter).id Write-Verbose -Message "Created task with id $($item.id)" if ($this.StartOn -eq [ReloadOn]::Create) { Write-Verbose "Starting task since StartOn is set to $($this.StartOn)" if ($this.WaitUntilFinished) { Start-QlikTask -id $item.id -wait | Wait-QlikExecution } else { Start-QlikTask -id $item.id } } } else { #$appTags = @() #foreach ($tag in $this.Tags) #{ # $tagId = (Get-QlikTag -filter "name eq '$tag'").id # if (-Not $tagId) # { # $tagId = (New-QlikTag -name $tag).id # Write-Verbose "Created tag for $tag with id $tagId" # } # $appTags += $tag #} $prop = ConfigurePropertiesAndTags($this) Update-QlikReloadTask -id $item.id -tags $prop.Tags if ($this.StartOn -eq [ReloadOn]::Update) { Write-Verbose "Starting task since StartOn is set to $($this.StartOn)" if ($this.WaitUntilFinished) { Start-QlikTask -id $item.id -wait | Wait-QlikExecution } else { Start-QlikTask -id $item.id } } } if ($this.Schedule) { Add-QlikTrigger -taskId $item.id -date $this.Schedule.Date } elseif ($this.OnSuccess -And (-Not (Invoke-QlikGet "/qrs/compositeevent?filter=compositeRules.reloadTask.id eq $($this.OnSuccess) and reloadTask.id eq $($item.id)"))) { Add-QlikTrigger -taskId $item.id -OnSuccess $this.OnSuccess } } else { if($present) { Write-Verbose -Message "Deleting app $($this.name)" Remove-QlikApp -id $this.id } } } [bool] Test() { $item = Get-QlikTask -raw -filter "name eq '$($this.name)'" -full $present = $item -ne $null if($this.Ensure -eq [Ensure]::Present) { if($present) { if($this.hasProperties($item)) { return $true } else { return $false } } else { return $false } } else { if($present) { return $false } else { return $true } } } [QlikTask] Get() { $item = Get-QlikApp -raw -filter "name eq '$($this.name)'" $present = $item -ne $null if ($present) { $this.Ensure = [Ensure]::Present } else { $this.Ensure = [Ensure]::Absent } return $this } [bool] hasProperties($item) { $result = $true if( !(CompareProperties $this $item @( 'Name' ) ) ) { $result = $false } if (-Not ($item.app.name -eq $this.App)) { Write-Verbose "Task $($item.id) uses app $($item.app.name) and should use $($this.App)" $result = $false } if ($this.OnSuccess -And (-Not (Invoke-QlikGet "/qrs/compositeevent?filter=compositeRules.reloadTask.id eq $($this.OnSuccess) and reloadTask.id eq $($item.id)"))) { Write-Verbose "Trigger for OnSuccess event of task $($this.OnSuccess) does not exist" $result = $false } if ($this.Tags) { foreach ($tag in $this.Tags) { if (-Not ($item.tags.name -contains $tag)) { Write-Verbose "Not tagged with $tag" return $false } } } return $result } } [DscResource()] class QlikVirtualProxy{ [DscProperty(Key)] [string]$Prefix [DscProperty(Mandatory)] [string]$Description [DscProperty(Mandatory)] [string]$SessionCookieHeaderName [DscProperty(Mandatory=$false)] [string]$authenticationModuleRedirectUri [DscProperty(Mandatory=$false)] [string]$loadBalancingServerNodes [DscProperty(Mandatory=$false)] [string[]]$websocketCrossOriginWhiteList [DscProperty(Mandatory=$false)] [string[]]$proxy [DscProperty(Mandatory)] [Ensure]$Ensure [void] Set() { $item = $(Get-QlikVirtualProxy -raw -filter "Prefix eq '$($this.Prefix)'") $present = $item -ne $null if($this.ensure -eq [Ensure]::Present) { $engines = Get-QlikNode -raw -filter $this.loadBalancingServerNodes | foreach { $_.id } | ? { $_ } $params = @{ Prefix = $this.Prefix Description = $this.Description SessionCookieHeaderName = $this.SessionCookieHeaderName } If( $engines ) { $params.Add("loadBalancingServerNodes", $engines) } If( $this.websocketCrossOriginWhiteList ) { $params.Add("websocketCrossOriginWhiteList", $this.websocketCrossOriginWhiteList) } If( $this.authenticationModuleRedirectUri ) { $params.Add("authenticationModuleRedirectUri", $this.authenticationModuleRedirectUri) } if($present) { if(-not $this.hasProperties($item)) { Update-QlikVirtualProxy -id $item.id @params } } else { $item = New-QlikVirtualProxy @params } if( $this.proxy ) { $this.proxy | foreach { $qp = Get-QlikProxy -raw -filter "serverNodeConfiguration.hostName eq '$_'" Add-QlikProxy $qp.id $item.id } } } else { if($present) { Write-Verbose -Message "Deleting virtual proxy $($this.Prefix)" #Get-QlikVirtualProxy -filter "Prefix eq $($this.Prefix) | Remove-QlikVirtualProxy } } } [bool] Test() { $item = $(Get-QlikVirtualProxy -raw -filter "Prefix eq '$($this.Prefix)'") $present = $item -ne $null if($this.Ensure -eq [Ensure]::Present) { if($present) { if($this.hasProperties($item)) { return $true } else { return $false } } else { return $false } } else { return -not $present } } [QlikVirtualProxy] Get() { $present = $(Get-QlikVirtualProxy -raw -filter "Prefix eq '$($this.Prefix)'") -ne $null if ($present) { $qvp = Get-QlikVirtualProxy -raw -filter "Prefix eq '$($this.Prefix)'" $this.Description = $qvp.Description $this.SessionCookieHeaderName = $qvp.SessionCookieHeaderName $this.authenticationModuleRedirectUri = $qvp.authenticationModuleRedirectUri $this.loadBalancingServerNodes = $qvp.loadBalancingServerNodes $this.websocketCrossOriginWhiteList = $qvp.websocketCrossOriginWhiteList $this.Ensure = [Ensure]::Present } else { $this.Ensure = [Ensure]::Absent } return $this } [bool] hasProperties($item) { if( !(CompareProperties $this $item @( 'Description', 'SessionCookieHeaderName', 'authenticationModuleRedirectUri' ) ) ) { return $false } if($this.loadBalancingServerNodes) { $nodes = Get-QlikNode -filter $this.loadBalancingServerNodes | foreach { $_.id } | ? { $_ } if(@($nodes).Count -ne @($item.loadBalancingServerNodes).Count) { Write-Verbose "Test-HasProperties: loadBalancingServerNodes property count - $(@($item.loadBalancingServerNodes).Count) does not match desired state - $(@($this.loadBalancingServerNodes).Count)" return $false } else { foreach($value in $item.loadBalancingServerNodes) { if($nodes -notcontains $value.id) { Write-Verbose "Test-HasProperties: loadBalancingServerNodes property value - $($value) not found in desired state" return $false } } } } if($this.websocketCrossOriginWhiteList) { if(@($this.websocketCrossOriginWhiteList).Count -ne @($item.websocketCrossOriginWhiteList).Count) { Write-Verbose "Test-HasProperties: websocketCrossOriginWhiteList property count - $(@($item.websocketCrossOriginWhiteList).Count) does not match desired state - $(@($this.websocketCrossOriginWhiteList).Count)" return $false } else { foreach($value in $item.websocketCrossOriginWhiteList) { if($this.websocketCrossOriginWhiteList -notcontains $value) { Write-Verbose "Test-HasProperties: websocketCrossOriginWhiteList property value - $($value) not found in desired state" return $false } } } } if( $this.proxy ) { $proxies = Get-QlikProxy -raw -full -filter "settings.virtualProxies.id eq $($item.id)" | select -ExpandProperty serverNodeConfiguration | select hostName foreach( $proxy in $this.proxy ) { if( -Not ($proxies.hostName -Contains $proxy) ) { Write-Verbose "Test-HasProperties: $proxy not linked" return $false } } } return $true } } [DscResource()] class QlikEngine { [DscProperty(Key)] [string]$Node [DscProperty()] [string]$DocumentDirectory [DscProperty()] [Int]$DocumentTimeout [DscProperty()] [ValidateRange(0,100)] [Int]$MinMemUsage [DscProperty()] [ValidateRange(0,100)] [Int]$MaxMemUsage [DscProperty()] [ValidateSet("IgnoreMaxLimit", "SoftMaxLimit", "HardMaxLimit")] [String]$MemUsageMode [DscProperty()] [ValidateRange(0,100)] [Int]$CpuThrottle [DscProperty()] [Bool]$AllowDataLineage [DscProperty()] [Bool]$StandardReload [Void] Set () { Write-Verbose "Get Qlik Engine: $($this.Node)" $item = Get-QlikEngine -Full -Filter "serverNodeConfiguration.hostName eq '$($this.Node)'" if($item.id) { $engparams = @{ "id" = $item.id } if($this.DocumentDirectory) { $engparams.Add("documentDirectory", $this.DocumentDirectory) } if($this.DocumentTimeout) { $engparams.Add("documentTimeout", $this.DocumentTimeout) } if($this.MinMemUsage) { $engparams.Add("workingSetSizeLoPct", $this.MinMemUsage) } if($this.MaxMemUsage) { $engparams.Add("workingSetSizeHiPct", $this.MaxMemUsage) } if($this.MemUsageMode) { $engparams.Add("workingSetSizeMode", $this.MemUsageMode) } if($this.CpuThrottle) { $engparams.Add("cpuThrottlePercentage", $this.CpuThrottle) } if($this.AllowDataLineage) { $engparams.Add("allowDataLineage", $this.AllowDataLineage) } if($this.StandardReload) { $engparams.Add("standardReload", $this.StandardReload) } Write-Verbose "Update Qlik Engine: $($this.Node)" Update-QlikEngine @engparams } else { Write-Verbose "Qlik Engine '$($this.Node)' not found!" } } [Bool] Test () { Write-Verbose "Get Qlik Engine: $($this.Node)" $item = Get-QlikEngine -Full -Filter "serverNodeConfiguration.hostName eq '$($this.Node)'" if($item -ne $null) { if($this.hasProperties($item)) { Write-Verbose "Qlik Engine '$($this.Node)' is in desired state" return $true } else { Write-Verbose "Qlik Engine '$($this.Node)' is not in desired state" return $false } } else { Write-Verbose "Qlik Engine '$($this.Node)' not found!" return $false } } [QlikEngine] Get () { Write-Verbose "Get Qlik Engine: $($this.Node)" $item = Get-QlikEngine -Full -Filter "serverNodeConfiguration.hostName eq '$($this.Node)'" if($item -ne $null) { $this.DocumentDirectory = $item.settings.documentDirectory $this.DocumentTimeout = $item.settings.documentTimeout $this.AllowDataLineage = $item.settings.allowDataLineage $this.CpuThrottle = $item.settings.cpuThrottlePercentage $this.MaxMemUsage = $item.settings.workingSetSizeHiPct switch($item.settings.workingSetSizeMode) { 0 { $this.MemUsageMode = "IgnoreMaxLimit" } 1 { $this.MemUsageMode = "SoftMaxLimit" } 2 { $this.MemUsageMode = "HardMaxLimit" } } $this.MinMemUsage = $this.settings.workingSetSizeLoPct $this.StandardReload = $this.settings.standardReload $this.Ensure = [Ensure]::Present } else { $this.Ensure = [Ensure]::Absent } return $this } [bool] hasProperties($item) { $desiredState = $true if($this.MemUsageMode) { $sizeMode = -1 switch ($this.MemUsageMode) { IgnoreMaxLimit { $sizeMode = 0 } SoftMaxLimit { $sizeMode = 1 } HardMaxLimit { $sizeMode = 2 } } if($item.settings.workingSetSizeMode -ne $sizeMode) { Write-Verbose "Test-HasProperties: Memory usage mode property value - $($item.settings.workingSetSizeMode) does not match desired state - $sizeMode" $desiredState = $false } } if($this.documentDirectory) { if($item.settings.documentDirectory -ne $this.documentDirectory) { Write-Verbose "Test-HasProperties: documentDirectory property value - $($item.settings.documentDirectory) does not match desired state - $($this.documentDirectory)" $desiredState = $false } } if($this.DocumentTimeout) { if($item.settings.documentTimeout -ne $this.DocumentTimeout) { Write-Verbose "Test-HasProperties: documentTimeout property value - $($item.settings.documentTimeout) does not match desired state - $($this.DocumentTimeout)" $desiredState = $false } } if($this.MinMemUsage) { if($item.settings.workingSetSizeLoPct -ne $this.MinMemUsage) { Write-Verbose "Test-HasProperties: Min memory use property value - $($item.settings.workingSetSizeLoPct) does not match desired state - $($this.MinMemUsage)" $desiredState = $false } } if($this.MaxMemUsage) { if($item.settings.workingSetSizeHiPct -ne $this.MaxMemUsage) { Write-Verbose "Test-HasProperties: Max memory usage property value - $($item.settings.workingSetSizeHiPct) does not match desired state - $($this.MaxMemUsage)" $desiredState = $false } } if($this.CpuThrottle) { if($item.settings.cpuThrottlePercentage -ne $this.CpuThrottle) { Write-Verbose "Test-HasProperties: CPU throttle property value - $($item.settings.cpuThrottlePercentage) does not match desired state - $($this.CpuThrottle)" $desiredState = $false } } if($item.settings.allowDataLineage -ne $this.AllowDataLineage) { Write-Verbose "Test-HasProperties: Allow data lineage property value - $($item.settings.allowDataLineage) does not match desired state - $($this.AllowDataLineage)" $desiredState = $false } if($item.settings.standardReload -ne $this.StandardReload) { Write-Verbose "Test-HasProperties: Standard reload property value - $($item.settings.standardReload) does not match desired state - $($this.StandardReload)" $desiredState = $false } return $desiredState } } [DscResource()] class QlikServiceCluster{ [DscProperty(Key)] [string] $Name [DscProperty(Mandatory)] [Ensure] $Ensure [DscProperty()] [int] $PersistenceType [DscProperty()] [int] $PersistenceMode [DscProperty()] [string] $RootFolder [DscProperty()] [string] $AppFolder [DscProperty()] [string] $StaticContentRootFolder [DscProperty()] [string] $Connector32RootFolder [DscProperty()] [string] $Connector64RootFolder [DscProperty()] [string] $ArchivedLogsRootFolder [void] Set() { $item = Get-QlikServiceCluster -filter "name eq '$($this.Name)'" -raw $present = $item -ne $null if ($this.ensure -eq [Ensure]::Present) { if (-Not $present) { $item = New-QlikServiceCluster -Name $this.Name Write-Verbose "Created cluster with ID $($item.ID)" } elseif (-Not $this.hasProperties($item)) { $params = @{ "id" = $item.id } if ($this.PersistenceType) { $params.Add("persistenceType", $this.PersistenceType) } if ($this.PersistenceMode) { $params.Add("persistenceMode", $this.PersistenceMode) } if ($this.RootFolder) { $params.Add("rootFolder", $this.RootFolder) } if ($this.AppFolder) { $params.Add("appFolder", $this.AppFolder) } if ($this.StaticContentRootFolder) { $params.Add("staticContentRootFolder", $this.StaticContentRootFolder) } if ($this.Connector32RootFolder) { $params.Add("connector32RootFolder", $this.Connector32RootFolder) } if ($this.Connector64RootFolder) { $params.Add("connector64RootFolder", $this.Connector64RootFolder) } if ($this.ArchivedLogsRootFolder) { $params.Add("archivedLogsRootFolder", $this.ArchivedLogsRootFolder) } Update-QlikServiceCluster @params } } else { if ($present) { #Write-Verbose "Deleting Service Cluster $($item.ID)" #Remove-QlikServiceCluster $item.ID } } } [bool] Test() { $item = Get-QlikServiceCluster -filter "name eq '$($this.Name)'" -raw $present = $item -ne $null if ($this.Ensure -eq [Ensure]::Present) { if ($present) { return $this.hasProperties($item) } else { Write-Verbose "Service Cluster $($this.Name) should be present but was not found" return $false } } else { if ($present) { Write-Verbose "Service Cluster $($this.Name) should not be present but was found" return $false } else { return $true } } } [QlikServiceCluster] Get() { $item = Get-QlikServiceCluster -filter "name eq '$($this.Name)'" -raw if ($item -ne $null) { $this.Ensure = [Ensure]::Present } else { $this.Ensure = [Ensure]::Absent } return $this } [bool] hasProperties($item) { if (-Not (CompareProperties $this $item.settings @('PersistenceType', 'PersistenceMode'))) { return $false } if (-Not (CompareProperties $this $item.settings.sharedPersistenceProperties @('rootFolder', 'appFolder', 'staticContentRootFolder', 'connector32RootFolder', 'connector64RootFolder', 'archivedLogsRootFolder'))) { return $false } return $true } } [DscResource()] class QlikStream{ [DscProperty(Key)] [string]$Name [DscProperty()] [hashtable]$CustomProperties [DscProperty()] [string[]]$Tags [DscProperty(Mandatory)] [Ensure] $Ensure [void] Set() { $item = Get-QlikStream -filter "name eq '$($this.Name)'" $present = $item -ne $null if ($this.ensure -eq [Ensure]::Present) { if (-Not $present) { $item = New-QlikStream -Name $this.Name Write-Verbose "Created stream with ID $($item.ID)" } $prop = ConfigurePropertiesAndTags($this) Update-QlikStream -id $item.id -customProperties $prop.Properties -tags $prop.Tags } else { if ($present) { Write-Verbose "Deleting stream $($item.ID)" Remove-QlikStream $item.ID } } } [bool] Test() { $item = Get-QlikStream -filter "name eq '$($this.Name)'" $present = $item -ne $null if ($this.Ensure -eq [Ensure]::Present) { if ($present) { if ($this.hasProperties($item)) { return $true } else { Write-Verbose "Stream $($this.Name) does not match desired state" return $false } } else { Write-Verbose "Stream $($this.Name) should be present but was not found" return $false } } else { if ($present) { Write-Verbose "Stream $($this.Name) should not be present but was found" return $false } else { return $true } } } [QlikStream] Get() { $item = Get-QlikStream -filter "name eq '$($this.Name)'" if ($item -ne $null) { $this.Ensure = [Ensure]::Present } else { $this.Ensure = [Ensure]::Absent } return $this } [bool] hasProperties($item) { #if( !(CompareProperties $this $item @( 'Description', 'SessionCookieHeaderName', 'authenticationModuleRedirectUri' ) ) ) #{ # return $false #} if ($this.Tags) { foreach ($tag in $this.Tags) { if (-Not ($item.tags.name -contains $tag)) { Write-Verbose "Not tagged with $tag" return $false } } } if ($this.CustomProperties) { foreach ($prop in $this.CustomProperties.Keys) { $cp = $item.customProperties | where {$_.definition.name -eq $prop} if (-Not (($cp) -And ($cp.value -eq $this.CustomProperties.$prop))) { Write-Verbose "Property $prop should have value $($this.CustomProperties.$prop) but instead has value $($cp.value)" return $false } } } return $true } } function CompareProperties( $expected, $actual, $prop ) { $result = $true $prop.foreach({ If($expected.$_ -And ($actual.$_ -ne $expected.$_)) { Write-Verbose "CompareProperties: $_ property value - $($actual.$_) does not match desired state - $($expected.$_)" $result = $false } }) return $result } function ConfigurePropertiesAndTags( $item ) { $props = @() foreach ($prop in $item.CustomProperties.Keys) { $cp = Get-QlikCustomProperty -filter "name eq '$prop'" -raw if (-Not ($cp.choiceValues -contains $item.CustomProperties.$prop)) { $cp.choiceValues += $item.CustomProperties.$prop Write-Verbose -Message "Updating property $prop with new value of $($item.CustomProperties.$prop)" Update-QlikCustomProperty -id $cp.id -choiceValues $cp.choiceValues } $props += "$($prop)=$($item.CustomProperties.$prop)" } $tags = @() foreach ($tag in $item.Tags) { $tagId = (Get-QlikTag -filter "name eq '$tag'").id if (-Not $tagId) { $tagId = (New-QlikTag -name $tag).id Write-Verbose "Created tag for $tag with id $tagId" } $tags += $tag } return @{Properties = $props; Tags = $tags} } # ---------------- Move to new module when nested modules fixed in WMF ------------------- [DscResource()] class EncryptConfig{ [DscProperty(Key)] [string] $exePath [DscProperty(Mandatory)] [string[]] $configSection [DscProperty()] [string] $connectionString [DscProperty()] [string] $provName = "DataProtectionConfigurationProvider" [DscProperty(Mandatory)] [Ensure] $Ensure [void] Set() { $config = [System.Configuration.ConfigurationManager]::OpenExeConfiguration($this.exePath) foreach ($sectionName in $this.configSection) { $section = $config.GetSection($sectionName) if ($section.SectionInformation.IsProtected) { $conn = $section.connectionStrings | where name -eq 'QSR' if ($conn.connectionString -ne $this.connectionString) { $conn.connectionString = $this.connectionString } } else { Write-Verbose "Encrypting $sectionName" $section.SectionInformation.ProtectSection($this.provName) $section.SectionInformation.ForceSave = $true } } $config.Save([System.Configuration.ConfigurationSaveMode]::Modified) } [bool] Test() { $config = [System.Configuration.ConfigurationManager]::OpenExeConfiguration($this.exePath) foreach ($sectionName in $this.configSection) { $section = $config.GetSection($sectionName) if ($section.SectionInformation.IsProtected) { $conn = $section.connectionStrings | where name -eq 'QSR' if ($conn.connectionString -ne $this.connectionString) { Write-Verbose "Connection string does not match desired state" return $false } } else { Write-Verbose "$sectionName in $($config.FilePath) is not encrypted" return $false } } return $true } [EncryptConfig] Get() { $this.Ensure = [Ensure]::Present return $this } } [DscResource()] class ConfigFile{ [DscProperty(Key)] [string] $configPath [DscProperty(Mandatory)] [hashtable] $appSettings [DscProperty(Mandatory)] [Ensure] $Ensure [void] Set() { $xml = [xml](Get-Content $this.configPath) $this.appSettings.Keys | foreach { $setting = $xml.configuration.appSettings.add | where key -eq $_ if ($setting) { $setting.value = $this.appSettings.$_ } } $xml.save($this.configPath) } [bool] Test() { $xml = [xml](Get-Content $this.configPath) $result = $true $this.appSettings.Keys | foreach { $setting = $xml.configuration.appSettings.add | where key -eq $_ if ($setting.value -ne $this.appSettings.$_) { Write-Verbose "Config setting for $_ has value $($setting.value) and should be $($this.appSettings.$_)" $result = $false } } return $result } [ConfigFile] Get() { $xml = [xml](Get-Content $this.configPath) $this.appSettings = $xml.configuration.appSettings.add $this.Ensure = [Ensure]::Present return $this } } [DscResource()] class LineInFile { [DscProperty(Key)] [string] $Path [DscProperty(Key)] [string] $Line [DscProperty()] [string] $InsertBefore [DscProperty()] [Ensure] $Ensure [void] Set() { $file = Get-Content $this.Path $out = "" $found = $false if ($this.InsertBefore) { ForEach ($fl in $file) { if ($fl | Select-String -Pattern $this.InsertBefore) { $out += $this.Line + "`r`n" $found = $true } $out += $fl + "`r`n" } } else { $out = $file } if (-Not $found) { $out += $this.Line + "`r`n" } Set-Content -Path $this.Path -Value $out } [bool] Test() { $file = Get-Content $this.Path ForEach ($fl in $file) { if ($fl -eq $this.Line) { Write-Verbose "Line exists in file" return $true } } return $false } [LineInFile] Get() { $this.Ensure = [Ensure]::Absent $file = Get-Content $this.Path ForEach ($fl in $file) { if ($fl | Select-String -Pattern $this.Line) { $this.Ensure = [Ensure]::Present break } } return $this } } |