Skip to content

Commit

Permalink
Bug fix 2020 04 (#114)
Browse files Browse the repository at this point in the history
* BugFix
WebSession now assigned to Script Scope
Fixed formatting

* Changes:
Added additional help for Connect-Qlik Parameters
Added Type Check for TrustAllCertsPolicy to prevent trying to re-add

* BugFix
...Hashtable] does not contain a method named 'ForEach'.

* Formatting:
Fixed to align with ScriptAnalyzer requirements

* BugFix
Handle Null -eq Attributes correctly

* Various:
Added pipline support
Added Architecture
Added LogOn

* Formatting

* Formatting Bug workaround:
PowerShell/PSScriptAnalyzer#1319
  • Loading branch information
Nillth authored Apr 6, 2020
1 parent 52c7f7b commit ca8b9f7
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 79 deletions.
134 changes: 82 additions & 52 deletions Qlik-Cli.psm1
Original file line number Diff line number Diff line change
@@ -1,49 +1,74 @@
Add-Type -AssemblyName System.Web

function Connect-Qlik {
<#
.SYNOPSIS
Establishes a session with a Qlik Sense server, other Qlik cmdlets will use this session to invoke commands.
.DESCRIPTION
Uses the parameter values to establish a new session with a Sense server, if a valid certificate can be found in the Windows certificate store it will be used unless this is overridden by the certificate parameter. If a valid certificate cannot be found Windows authentication will be attempted using the credentials of the user that is running the PowerShell console.
.EXAMPLE
Connect-Qlik -computername CentralNodeName -username domain\username
.LINK
https://github.com/ahaydon/Qlik-Cli
<#
.SYNOPSIS
Establishes a session with a Qlik Sense server, other Qlik cmdlets will use this session to invoke commands.
.DESCRIPTION
Uses the parameter values to establish a new session with a Sense server, if a valid certificate can be found in the Windows certificate store it will be used unless this is overridden by the certificate parameter. If a valid certificate cannot be found Windows authentication will be attempted using the credentials of the user that is running the PowerShell console.
.PARAMETER Computername
Name of the Sense server to connect to
.PARAMETER TrustAllCerts
Disable checking of certificate trust
.PARAMETER Username
UserId to use with certificate authentication in the format domain\username
.PARAMETER Certificate
Client certificate to use for authentication
.PARAMETER Context
User Context for Connection
.PARAMETER Attributes
Any additional attributes to use on the connection request
.PARAMETER UseDefaultCredentials
Use credentials of logged on user for authentication, prevents automatically locating a certificate
.PARAMETER TimeoutSec
Set a Global Timeout for all Rest Requests
.EXAMPLE
Connect-Qlik -computername CentralNodeName -username domain\username
.LINK
https://github.com/ahaydon/Qlik-Cli
#>
[CmdletBinding(DefaultParameterSetName = "Default")]
param (
# Name of the Sense server to connect to
[parameter(Position = 0)]
function Connect-Qlik {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param
(
[Parameter(Position = 0)]
[string]$Computername,
# Disable checking of certificate trust
[switch]$TrustAllCerts,
# UserId to use with certificate authentication in the format domain\username
[Parameter(ParameterSetName = "Certificate")]
[Parameter(ParameterSetName = 'Certificate')]
[string]$Username = "$($env:userdomain)\$($env:username)",
# Client certificate to use for authentication
[parameter(ParameterSetName = "Certificate", Mandatory = $true, ValueFromPipeline = $true)]
[Parameter(ParameterSetName = 'Certificate',
Mandatory = $true,
ValueFromPipeline = $true)]
[System.Security.Cryptography.X509Certificates.X509Certificate]$Certificate,
[parameter(ParameterSetName = "Certificate")]
[Parameter(ParameterSetName = 'Certificate')]
[ValidateSet('AppAccess', 'ManagementAccess')]
[string]$Context = 'ManagementAccess',
[parameter(ParameterSetName = "Certificate")]
[Parameter(ParameterSetName = 'Certificate')]
[hashtable]$Attributes,
# Use credentials of logged on user for authentication, prevents automatically locating a certificate
[parameter(ParameterSetName = "Default")]
[Parameter(ParameterSetName = 'Default')]
[switch]$UseDefaultCredentials,

[int]$TimeoutSec
)

PROCESS {
# Since we are connecting we need to clear any variables relating to previous connections
$script:api_params = $null
$script:prefix = $null
$script:webSession = $null

If ( $TrustAllCerts -and $PSVersionTable.PSVersion.Major -lt 6 ) {
Add-Type @"

If ($TrustAllCerts -and $PSVersionTable.PSVersion.Major -lt 6) {
if (-not ([System.Management.Automation.PSTypeName]'TrustAllCertsPolicy').Type) {
Add-Type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
Expand All @@ -54,34 +79,40 @@ function Connect-Qlik {
}
}
"@
}
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]'Tls,Tls11,Tls12'
If ( !$Certificate -And !$Credential -And !$UseDefaultCredentials ) {
If (!$Certificate -And !$Credential -And !$UseDefaultCredentials) {
$certs = @(FetchCertificate "My" "CurrentUser")
Write-Verbose "Found $($certs.Count) certificates in CurrentUser store"
If ( $certs.Count -eq 0 ) {
If ($certs.Count -eq 0) {
$certs = @(FetchCertificate "My" "LocalMachine")
Write-Verbose "Found $($certs.Count) certificates in LocalMachine store"
}
If ( $certs.Count -gt 0 ) {
If ($certs.Count -gt 0) {
$Certificate = $certs[0]
}
}

If ( $Certificate ) {
If ($Certificate) {
Write-Verbose "Using certificate $($Certificate.FriendlyName) and user $username"

$Script:api_params = @{
Certificate = $Certificate
Header = @{
"X-Qlik-User" = $("UserDirectory={0};UserId={1}" -f $($username -split "\\"))
"X-Qlik-Security" = "Context=$Context; " -f ($Attributes.ForEach{ "$_=$($Attributes.$_)" } -join '; ')
}
}
if ($null -eq $Attributes) {
$Script:api_params.Header."X-Qlik-Security" = "Context=$Context"
}
else {
$Script:api_params.Header."X-Qlik-Security" = "Context=$Context; " -f ($Attributes.Keys.ForEach{ "$_=$($Attributes.$_)" } -join '; ')
}

$port = ":4242"
}
ElseIf ( $Credential ) {
ElseIf ($Credential) {
Write-Verbose $("Using credentials for {0}" -f $Credential.Username)
$Script:api_params = @{
Credential = $Credential
Expand All @@ -93,14 +124,14 @@ function Connect-Qlik {
UseDefaultCredentials = $true
}
}

if ($TrustAllCerts -and $PSVersionTable.PSVersion.Major -ge 6) {
$Script:api_params.SkipCertificateCheck = $true
}

if ($TimeoutSec) { $script:api_params.TimeoutSec = $TimeoutSec }

if (! $Computername ) {
if (! $Computername) {
$HostPath = 'C:\ProgramData\Qlik\Sense\Host.cfg'
if (Test-Path $HostPath) {
$Computername = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($(Get-Content $HostPath)))
Expand All @@ -109,13 +140,13 @@ function Connect-Qlik {
$Computername = $env:computername
}
}
If ( $Computername.ToLower().StartsWith( "http" ) ) {
If ($Computername.ToLower().StartsWith("http")) {
$Script:prefix = $Computername
}
else {
$Script:prefix = "https://" + $Computername + $port
}

$result = Get-QlikAbout
return $result
}
Expand All @@ -128,7 +159,7 @@ function Import-QlikObject {
[parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)]
[PSObject[]]$object
)

PROCESS {
$object | ForEach-Object {
$path = "/qrs/{0}" -F $_.schemaPath
Expand Down Expand Up @@ -158,16 +189,16 @@ function Invoke-QlikGet {
[string]$filter
)
PROCESS {
If ( $filter ) {
If ($filter) {
$filter = [System.Web.HttpUtility]::UrlEncode($filter)
If ( $path.contains("?") ) {
If ($path.contains("?")) {
$path += "&filter=$filter"
}
else {
$path += "?filter=$filter"
}
}

return CallRestUri Get $path
}
}
Expand All @@ -186,7 +217,7 @@ function Invoke-QlikPost {
ContentType = $contentType
Body = $body
}

return CallRestUri Post $path $params
}
}
Expand All @@ -205,7 +236,7 @@ function Invoke-QlikPut {
ContentType = $contentType
Body = $body
}

return CallRestUri Put $path $params
}
}
Expand All @@ -222,7 +253,7 @@ function Invoke-QlikDownload {
$params = @{
OutFile = $filename
}

return CallRestUri Get $path $params
}
}
Expand All @@ -234,15 +265,14 @@ function Invoke-QlikUpload {
[string]$path,
[parameter(Mandatory = $true, Position = 1)]
[string]$filename,

[string]$ContentType = "application/vnd.qlik.sense.app"
)
PROCESS {
$params = @{
InFile = $filename
ContentType = $ContentType
}

return CallRestUri Post $path $params
}
}
Expand All @@ -267,7 +297,7 @@ function Update-QlikOdag {
$id = $(Invoke-QlikGet "/qrs/odagservice").id
$odag = Invoke-QlikGet "/qrs/odagservice/$id"
$odag.settings.enabled = $enabled
If ( $maxConcurrentRequests ) { $odag.settings.maxConcurrentRequests = $maxConcurrentRequests }
If ($maxConcurrentRequests) { $odag.settings.maxConcurrentRequests = $maxConcurrentRequests }
$json = $odag | ConvertTo-Json -Compress -Depth 10
return Invoke-QlikPut "/qrs/odagservice/$id" $json
}
Expand Down
41 changes: 31 additions & 10 deletions functions/core.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,84 @@
$script:isDate = "^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$"
if ($qlik_output_raw) { $rawOutput = $true }

function CallRestUri($method, $path, $extraParams) {

function CallRestUri {
param
(
$method,
$path,
$extraParams
)

Write-Verbose "Raw output: $rawOutput"
If ($null -eq $Script:prefix) { Connect-Qlik > $null }
If (! $path.StartsWith("http")) {
$path = $Script:prefix + $path
}

$xrfKey = GetXrfKey
If ($path.contains("?")) {
$path += "&xrfkey=$xrfKey"
}
else {
$path += "?xrfkey=$xrfKey"
}

$params = DeepCopy $api_params

If ($extraParams) { $params += $extraParams }
If (!$params.Header) { $params.Header = @{ } }
If (!$params.Header) {
$params.Header = @{ }
}
If (!$params.Header.ContainsKey("x-Qlik-Xrfkey")) {
Write-Verbose "Adding header x-Qlik-Xrfkey: $xrfKey"
$params.Header.Add("x-Qlik-Xrfkey", $xrfKey)
}
If ($params.Body) { Write-Verbose $params.Body }

Write-Verbose "Calling $method for $path"

try {
$paramInvokeRestMethod = @{
Method = $method
Uri = $path
WebSession = $script:webSession
}

If ($null -eq $script:webSession) {
$paramInvokeRestMethod.SessionVariable = 'webSession'
}
else {
$paramInvokeRestMethod.WebSession = $script:webSession
}

if ($params.OutFile -or $params.InFile) {
$ProgressPreference = 'SilentlyContinue'
if ($null -eq $params.TimeoutSec) {
$paramInvokeRestMethod.TimeoutSec = 300
}
}

$result = Invoke-RestMethod @paramInvokeRestMethod @params
$script:webSession = $webSession
}
catch {
throw $_
return
}

if (!$rawOutput) {
Write-Verbose "Formatting response"
$result = FormatOutput($result)
}
return $result
}

function DeepCopy($data) {
function DeepCopy {
param
(
$data
)

$copy = @{ }
$data.Keys | ForEach-Object {
$copy.Add($_, $(
Expand Down
Binary file modified resources/dataconnection.ps1
Binary file not shown.
Loading

0 comments on commit ca8b9f7

Please sign in to comment.