diff --git a/AptecoPSFramework/AptecoPSFramework.psd1 b/AptecoPSFramework/AptecoPSFramework.psd1 index 70928b9..82c9c9b 100644 --- a/AptecoPSFramework/AptecoPSFramework.psd1 +++ b/AptecoPSFramework/AptecoPSFramework.psd1 @@ -148,6 +148,14 @@ PrivateData = @{ # 'ReleaseNotes' des Moduls ReleaseNotes = ' +0.2.1 Feature: New internal function for plugins to allow multipart uploads via `Prepare-MultipartUpload` + Feature: Addition for Hubspot to load single or multiple properties by name in `Get-Property` + Feature: New function for Hubspot to allow the loading of a pipeline + Feature: New function for Hubspot to load "owners" + Fix: Invoking hubspot has not used the correct headers which is now fixed + Fix: Better error handling dependent from PS version in `Import-ErrorForResponseBody`^ + Fix: Improved input file handling for Salesforce plugin + Fix: The get messages boilerplate was outdated and has now been updated 0.2.0 Added yaml as a new functionality to save and load settings - please make sure to install your dependencies again CleverReach - Fixed output for validations (showed 1 as valid when there is 0 valid entries) CleverReach - Putting failed entries also in log and returns it to Orbit Monitoring diff --git a/AptecoPSFramework/boilerplate/getmessages.ps1 b/AptecoPSFramework/boilerplate/getmessages.ps1 index 6ba6a52..c12c57d 100644 --- a/AptecoPSFramework/boilerplate/getmessages.ps1 +++ b/AptecoPSFramework/boilerplate/getmessages.ps1 @@ -22,42 +22,12 @@ $debug = $false #----------------------------------------------- If ( $debug -eq $true ) { - [System.Environment]::GetEnvironmentVariables([System.EnvironmentVariableTarget]::Process).GetEnumerator() | ForEach { + [System.Environment]::GetEnvironmentVariables([System.EnvironmentVariableTarget]::Process).GetEnumerator() | ForEach-Object { Write-Log "$( $_.Name ) = $( $_.Value )" } } -#----------------------------------------------- -# ADD MODULE PATH, IF NOT PRESENT -#----------------------------------------------- - -$modulePath = @( [System.Environment]::GetEnvironmentVariable("PSModulePath") -split ";" ) + @( - "C:\Program Files\WindowsPowerShell\Modules" - #C:\Program Files\powershell\7\Modules - "$( [System.Environment]::GetEnvironmentVariable("ProgramFiles") )\WindowsPowerShell\Modules" - "$( [System.Environment]::GetEnvironmentVariable("ProgramFiles(x86)") )\WindowsPowerShell\Modules" - "$( [System.Environment]::GetEnvironmentVariable("USERPROFILE") )\Documents\WindowsPowerShell\Modules" - "$( [System.Environment]::GetEnvironmentVariable("windir") )\system32\WindowsPowerShell\v1.0\Modules" -) -$Env:PSModulePath = ( $modulePath | Sort-Object -unique ) -join ";" -# Using $env:PSModulePath for only temporary override - - -#----------------------------------------------- -# ADD SCRIPT PATH, IF NOT PRESENT -#----------------------------------------------- - -#$envVariables = [System.Environment]::GetEnvironmentVariables() -$scriptPath = @( [System.Environment]::GetEnvironmentVariable("Path") -split ";" ) + @( - "$( [System.Environment]::GetEnvironmentVariable("ProgramFiles") )\WindowsPowerShell\Scripts" - "$( [System.Environment]::GetEnvironmentVariable("ProgramFiles(x86)") )\WindowsPowerShell\Scripts" - "$( [System.Environment]::GetEnvironmentVariable("USERPROFILE") )\Documents\WindowsPowerShell\Scripts" -) -$Env:Path = ( $scriptPath | Sort-Object -unique ) -join ";" -# Using $env:Path for only temporary override - - #----------------------------------------------- # INPUT PARAMETERS, IF DEBUG IS TRUE #----------------------------------------------- @@ -88,29 +58,6 @@ bla bla #> -################################################ -# -# SCRIPT ROOT -# -################################################ -<# -if ( $debug -eq $true ) { - - if ($MyInvocation.MyCommand.CommandType -eq "ExternalScript") { - $scriptPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition - } else { - $scriptPath = Split-Path -Parent -Path ([Environment]::GetCommandLineArgs()[0]) - } - - $params.scriptPath = $scriptPath - -} - -# Some local settings -$dir = $params.scriptPath -Set-Location $dir -#> - ################################################ # # SETTINGS @@ -121,15 +68,27 @@ Set-Location $dir # IMPORT MODULE #----------------------------------------------- -Import-Module "AptecoPSFramework" -Verbose -#Set-ExecutionDirectory -Path $dir +try { + Import-Module "AptecoPSFramework" -Verbose -#----------------------------------------------- -# ADD MORE PLUGINS -#----------------------------------------------- +} catch { -#Add-PluginFolder "D:\Scripts\CleverReach\Plugins" + # ADD MODULE PATH, IF NOT PRESENT + $modulePath = @( [System.Environment]::GetEnvironmentVariable("PSModulePath") -split ";" ) + @( + "C:\Program Files\WindowsPowerShell\Modules" + #C:\Program Files\powershell\7\Modules + "$( [System.Environment]::GetEnvironmentVariable("ProgramFiles") )\WindowsPowerShell\Modules" + "$( [System.Environment]::GetEnvironmentVariable("ProgramFiles(x86)") )\WindowsPowerShell\Modules" + "$( [System.Environment]::GetEnvironmentVariable("USERPROFILE") )\Documents\WindowsPowerShell\Modules" + "$( [System.Environment]::GetEnvironmentVariable("windir") )\system32\WindowsPowerShell\v1.0\Modules" + ) + $Env:PSModulePath = ( $modulePath | Sort-Object -unique ) -join ";" + + # Try again + Import-Module "AptecoPSFramework" -Verbose + +} #----------------------------------------------- @@ -144,11 +103,6 @@ Set-DebugMode -DebugMode $debug #----------------------------------------------- # Set the settings -<# -$settings = Get-settings -$settings.logfile = ".\file.log" -Set-Settings -PSCustom $settings -#> Import-Settings -Path $params.settingsFile @@ -158,21 +112,10 @@ Import-Settings -Path $params.settingsFile # ################################################ -# TODO [x] check if we need to make a try catch here -> not needed, if we use a combination like - -<# - $msg = "Temporary count of $( $mssqlResult ) is less than $( $rowsCount ) in the original export. Please check!" - Write-Log -Message $msg -Severity ERROR - throw [System.IO.InvalidDataException] $msg - -#> - - #----------------------------------------------- # GET MESSAGES #----------------------------------------------- - # Added try/catch again because of extras.xml wrapper try { diff --git a/AptecoPSFramework/plugins/Hubspot/Private/invoke/Invoke-Hubspot.ps1 b/AptecoPSFramework/plugins/Hubspot/Private/invoke/Invoke-Hubspot.ps1 index 611d099..87f73b2 100644 --- a/AptecoPSFramework/plugins/Hubspot/Private/invoke/Invoke-Hubspot.ps1 +++ b/AptecoPSFramework/plugins/Hubspot/Private/invoke/Invoke-Hubspot.ps1 @@ -3,7 +3,7 @@ function Invoke-Hubspot { [CmdletBinding()] param ( - [Parameter(Mandatory=$true)][String]$Object # The cleverreach object like groups or mailings (first part after the main url) + [Parameter(Mandatory=$true)][String]$Object # The hubspot object like groups or mailings (first part after the main url) ,[Parameter(Mandatory=$false)][String]$Path = "" # The path in the url after the object ,[Parameter(Mandatory=$false)][PSCustomObject]$Query = [PSCustomObject]@{} # Query parameters for the url ,[Parameter(Mandatory=$false)][Switch]$Paging = $false # Automatic paging through the result, only needed for a few calls @@ -101,13 +101,13 @@ function Invoke-Hubspot { $rawToken = "" # Add auth header or just set it - If ( $updatedParameters.ContainsKey("Header") -eq $true ) { + If ( $updatedParameters.ContainsKey("Headers") -eq $true ) { $header.Keys | ForEach-Object { $key = $_ $updatedParameters.Header.Add( $key, $header.$key ) } } else { - $updatedParameters.add("Header",$header) + $updatedParameters.add("Headers",$header) } @@ -117,7 +117,7 @@ function Invoke-Hubspot { # Add additional headers from the settings, e.g. for api gateways or proxies $Script:settings.additionalHeaders.PSObject.Properties | ForEach-Object { - $updatedParameters.add($_.Name, $_.Value) + $updatedParameters.Headers.add($_.Name, $_.Value) } @@ -279,7 +279,7 @@ function Invoke-Hubspot { try { $newToken = Save-NewToken Write-Log -Severity WARNING -Message "Successful token refresh" - $wrInput.Params.Header.Authorization = "Bearer $( $newToken )" + $wrInput.Params.Headers.Authorization = "Bearer $( $newToken )" $continueAfterTokenRefresh = $true } catch { Write-Log -Severity ERROR -Message "Token refresh not successful" diff --git a/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Owner.ps1 b/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Owner.ps1 new file mode 100644 index 0000000..f185e71 --- /dev/null +++ b/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Owner.ps1 @@ -0,0 +1,27 @@ + +function Get-Owner { + + [CmdletBinding()] + param ( + # [Parameter(Mandatory=$true)][String]$Object + #,[Parameter(Mandatory=$false)][String[]]$PropertyName = "" + #,[Parameter(Mandatory=$false)][Switch]$Archived = $false + #,[Parameter(Mandatory=$false)][Switch]$IncludeObjectName = $false # Include the object name like "contacts" + + ) + + begin { + + } + process { + + $owners = @( Invoke-Hubspot -Object "crm" -Path "owners" -Method GET ) + $owners.results + + } + + end { + + } + +} diff --git a/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Pipeline.ps1 b/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Pipeline.ps1 new file mode 100644 index 0000000..f28f5f2 --- /dev/null +++ b/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Pipeline.ps1 @@ -0,0 +1,26 @@ + +function Get-Pipeline { + + [CmdletBinding()] + param ( + [Parameter(Mandatory=$true)][String]$Object + #,[Parameter(Mandatory=$false)][String[]]$PropertyName = "" + #,[Parameter(Mandatory=$false)][Switch]$Archived = $false + #,[Parameter(Mandatory=$false)][Switch]$IncludeObjectName = $false # Include the object name like "contacts" + + ) + + begin { + + } + process { + + $pipelines = @( Invoke-Hubspot -Object "crm" -Path "pipelines/$( $Object )" -Method GET ) + $pipelines.results + } + + end { + + } + +} diff --git a/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Property.ps1 b/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Property.ps1 index 7820711..4549ebf 100644 --- a/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Property.ps1 +++ b/AptecoPSFramework/plugins/Hubspot/Public/Hubspot/Get-Property.ps1 @@ -3,14 +3,21 @@ function Get-Property { [CmdletBinding()] param ( - #[Parameter(Mandatory=$false)][Hashtable] $InputHashtable [Parameter(Mandatory=$true)][String]$Object + ,[Parameter(Mandatory=$false)][String[]]$PropertyName = "" ,[Parameter(Mandatory=$false)][Switch]$Archived = $false ,[Parameter(Mandatory=$false)][Switch]$IncludeObjectName = $false # Include the object name like "contacts" ) begin { + + $isSingleCall = $false + If ( $PropertyName -ne "" ) { + $isSingleCall = $true + } + + $properties = [System.Collections.ArrayList]@() } process { @@ -20,12 +27,28 @@ function Get-Property { $loadArchived = $true } - $properties = @( Invoke-Hubspot -Object "crm" -Path "properties/$( $Object )" -Query ([PSCustomObject]@{"archived"=$loadArchived}) -Method GET ) + # Single properties + If ( $isSingleCall -eq $true ) { + $PropertyName | ForEach-Object { + $propName = $_ + $propData = Invoke-Hubspot -Object "crm" -Path "properties/$( $Object )/$( $propName )" -Method GET + #Write-Host $propData + [void]$properties.add( $propData ) + } + $return = $properties + + # All properties + } else { + [void]$properties.Add( ( Invoke-Hubspot -Object "crm" -Path "properties/$( $Object )" -Query ([PSCustomObject]@{"archived"=$loadArchived}) -Method GET )) + $return = $properties.results + } If ( $IncludeObjectName -eq $true ) { - $properties.results | Add-Member -MemberType NoteProperty -Name "object" -Value $Object + $return | Add-Member -MemberType NoteProperty -Name "object" -Value $Object } - $properties.results + + $return + } diff --git a/AptecoPSFramework/plugins/SalesforceSC/Public/peoplestage/invoke-upload.ps1 b/AptecoPSFramework/plugins/SalesforceSC/Public/peoplestage/invoke-upload.ps1 index d1cc1dd..6ce5b33 100644 --- a/AptecoPSFramework/plugins/SalesforceSC/Public/peoplestage/invoke-upload.ps1 +++ b/AptecoPSFramework/plugins/SalesforceSC/Public/peoplestage/invoke-upload.ps1 @@ -348,7 +348,7 @@ function Invoke-Upload{ Write-Log "Converted $( $newCsv.count ) lines" - $nf = "$( $Env:TEMP )\$( [guid]::NewGuid().toString() ).csv" #New-TemporaryFile + $nf = Join-Path -Path $Env:tmp -ChildPath "$( [guid]::newguid().toString() ).csv" #New-TemporaryFile Write-Log "Using temporary file $( $nf )" # TODO [ ] Not the best way when you have quotes in values $newCsvContent = $newCsv | convertto-csv -NoTypeInformation -Delimiter "`t" | % {$_ -replace '"',''} diff --git a/AptecoPSFramework/private/http/Import-ErrorForResponseBody.ps1 b/AptecoPSFramework/private/http/Import-ErrorForResponseBody.ps1 index 194b7fa..21b47c0 100644 --- a/AptecoPSFramework/private/http/Import-ErrorForResponseBody.ps1 +++ b/AptecoPSFramework/private/http/Import-ErrorForResponseBody.ps1 @@ -18,21 +18,28 @@ function Import-ErrorForResponseBody() { $Err ) - # Only needed in PS5.1, not in Pwsh - if ($PSVersionTable.PSVersion.Major -lt 6) { - if ($err.Exception.Response) { - $Reader = New-Object System.IO.StreamReader($Err.Exception.Response.GetResponseStream()) - $Reader.BaseStream.Position = 0 - $Reader.DiscardBufferedData() - $ResponseBody = $Reader.ReadToEnd() - if ($ResponseBody.StartsWith('{')) { - $ResponseBody = $ResponseBody | ConvertFrom-Json + try { + + # Only needed in PS5.1, not in Pwsh + if ($PSVersionTable.PSVersion.Major -lt 6) { + if ($err.Exception.Response) { + $Reader = New-Object System.IO.StreamReader($Err.Exception.Response.GetResponseStream()) + $Reader.BaseStream.Position = 0 + $Reader.DiscardBufferedData() + $ResponseBody = $Reader.ReadToEnd() + if ($ResponseBody.StartsWith('{')) { + $ResponseBody = $ResponseBody | ConvertFrom-Json + } + return $ResponseBody } - return $ResponseBody + } else { + return $Err.ErrorDetails.Message } - } - else { + + } catch { + return $Err.ErrorDetails.Message + } } \ No newline at end of file diff --git a/AptecoPSFramework/private/http/Prepare-MultipartUpload.ps1 b/AptecoPSFramework/private/http/Prepare-MultipartUpload.ps1 new file mode 100644 index 0000000..49e4a23 --- /dev/null +++ b/AptecoPSFramework/private/http/Prepare-MultipartUpload.ps1 @@ -0,0 +1,43 @@ + + +Function Prepare-MultipartUpload { + param( + [Parameter(Mandatory=$true)][String]$path, + [Parameter(Mandatory=$false)]$part = $false + ) + + # default settings + $uploadEncoding = "ISO-8859-1" + $crlf = "`r`n"; + + # if multipart, remove the part prefix + $fileItem = Get-Item -Path $path + if ($part) { + $fileName = $fileItem.Name.Substring(0, $fileItem.Name.lastIndexOf('.')) + } else { + $fileName = $fileItem.Name + } + + # get file, load and encode it + $fileBytes = [System.IO.File]::ReadAllBytes($fileItem.FullName); + $fileEncoded = [System.Text.Encoding]::GetEncoding($uploadEncoding).GetString($fileBytes); + + # create guid for multipart upload + $boundary = [System.Guid]::NewGuid().ToString(); + + # create body + $body = ( + "--$( $boundary )", + "Content-Disposition: form-data; name=`"file`"; filename=`"$( $fileName )`"", + "Content-Type: application/octet-stream$( $crlf )", + $fileEncoded, + "--$( $boundary )--$( $crlf )" + ) -join $crlf + + # put it together + @{ + "body"=$body + "contentType"="multipart/form-data; boundary=""$( $boundary )""" + } + +} \ No newline at end of file