PSTANSS.psm1
$script:ModuleRoot = $PSScriptRoot $script:ModuleVersion = (Import-PowerShellDataFile -Path "$($script:ModuleRoot)\PSTANSS.psd1").ModuleVersion # Detect whether at some level dotsourcing was enforced $script:doDotSource = Get-PSFConfigValue -FullName PSTANSS.Import.DoDotSource -Fallback $false if ($PSTANSS_dotsourcemodule) { $script:doDotSource = $true } <# Note on Resolve-Path: All paths are sent through Resolve-Path/Resolve-PSFPath in order to convert them to the correct path separator. This allows ignoring path separators throughout the import sequence, which could otherwise cause trouble depending on OS. Resolve-Path can only be used for paths that already exist, Resolve-PSFPath can accept that the last leaf my not exist. This is important when testing for paths. #> # Detect whether at some level loading individual module files, rather than the compiled module was enforced $importIndividualFiles = Get-PSFConfigValue -FullName PSTANSS.Import.IndividualFiles -Fallback $false if ($PSTANSS_importIndividualFiles) { $importIndividualFiles = $true } if (Test-Path (Resolve-PSFPath -Path "$($script:ModuleRoot)\..\.git" -SingleItem -NewChild)) { $importIndividualFiles = $true } if ("<was compiled>" -eq '<was not compiled>') { $importIndividualFiles = $true } function Import-ModuleFile { <# .SYNOPSIS Loads files into the module on module import. .DESCRIPTION This helper function is used during module initialization. It should always be dotsourced itself, in order to proper function. This provides a central location to react to files being imported, if later desired .PARAMETER Path The path to the file to load .EXAMPLE PS C:\> . Import-ModuleFile -File $function.FullName Imports the file stored in $function according to import policy #> [CmdletBinding()] Param ( [string] $Path ) $resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path).ProviderPath if ($doDotSource) { . $resolvedPath } else { $ExecutionContext.InvokeCommand.InvokeScript($false, ([scriptblock]::Create([io.file]::ReadAllText($resolvedPath))), $null, $null) } } #region Load individual files if ($importIndividualFiles) { # Execute Preimport actions foreach ($path in (& "$ModuleRoot\internal\scripts\preimport.ps1")) { . Import-ModuleFile -Path $path } # Import all internal functions foreach ($function in (Get-ChildItem "$ModuleRoot\internal\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Import all public functions foreach ($function in (Get-ChildItem "$ModuleRoot\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Execute Postimport actions foreach ($path in (& "$ModuleRoot\internal\scripts\postimport.ps1")) { . Import-ModuleFile -Path $path } # End it here, do not load compiled code below return } #endregion Load individual files #region Load compiled code <# This file loads the strings documents from the respective language folders. This allows localizing messages and errors. Load psd1 language files for each language you wish to support. Partial translations are acceptable - when missing a current language message, it will fallback to English or another available language. #> Import-PSFLocalizedString -Path "$($script:ModuleRoot)\en-us\*.psd1" -Module 'PSTANSS' -Language 'en-US' function Assert-CacheRunspaceRunning { <# .Synopsis Assert-CacheRunspaceRunning .DESCRIPTION Check cache validation runspace on status .EXAMPLE PS C:\> Assert-CacheRunspaceRunning Check cache validation runspace on status .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( ) Write-PSFMessage -Level Debug -Message "Check cache validationRunspace" if ([TANSS.Cache]::StopValidationRunspace -eq $true) { Write-PSFMessage -Level Debug -Message "ValidationRunspace is stopped. Going to start the runspace again" # force to stop the runspace [TANSS.Cache]::StopValidationRunspace = $true Get-PSFRunspace -Name "TANSS.LookupValidation" | Stop-PSFRunspace # Restart the runspace try { [TANSS.Cache]::StopValidationRunspace = $false Start-PSFRunspace -Name "TANSS.LookupValidation" -ErrorAction Stop -ErrorVariable invokeError } catch { Stop-PSFFunction -Message "Error Starting ValidationRunspace. Unknown module behaviour. Please restart your powershell console!" -EnableException $true -Exception $invokeError -Tag "RunSpace" throw $invokeError } } } function ConvertFrom-Base64StringWithNoPadding( [string]$Data ) { <# .SYNOPSIS Helper function build valid Base64 strings from JWT access tokens .DESCRIPTION Helper function build valid Base64 strings from JWT access tokens .PARAMETER Data The Token to convert .EXAMPLE PS C:\> ConvertFrom-Base64StringWithNoPadding -Data $data build valid base64 string the content from variable $data #> $Data = $Data.Replace('-', '+').Replace('_', '/') switch ($Data.Length % 4) { 0 { break } 2 { $Data += '==' } 3 { $Data += '=' } default { throw New-Object ArgumentException('data') } } [System.Convert]::FromBase64String($Data) } function ConvertFrom-JWTtoken { <# .SYNOPSIS Converts access tokens to readable objects .DESCRIPTION Converts access tokens to readable objects .PARAMETER TokenText The Token to convert .EXAMPLE PS C:\> ConvertFrom-JWTtoken -Token $TokenText Converts the content from variable $TokenText to an object #> [cmdletbinding()] param( [Parameter(Mandatory = $true)] [string] $TokenText ) # Validate as per https://tools.ietf.org/html/rfc7519 - Access and ID tokens are fine, Refresh tokens will not work if ((-not $TokenText.Contains(".")) -or (-not $TokenText.StartsWith("eyJ"))) { $msg = "Invalid data or not an access/refresh token. $($TokenText)" Stop-PSFFunction -Message $msg -Tag "JWT" -EnableException $true -Exception ([System.Management.Automation.RuntimeException]::new($msg)) } # Split the token in its parts $tokenParts = $TokenText.Split(".") # Work on header $tokenHeader = [System.Text.Encoding]::UTF8.GetString( (ConvertFrom-Base64StringWithNoPadding $tokenParts[0]) ) $tokenHeaderJSON = $tokenHeader | ConvertFrom-Json # Work on payload $tokenPayload = [System.Text.Encoding]::UTF8.GetString( (ConvertFrom-Base64StringWithNoPadding $tokenParts[1]) ) $tokenPayloadJSON = $tokenPayload | ConvertFrom-Json # Work on signature $tokenSignature = ConvertFrom-Base64StringWithNoPadding $tokenParts[2] # Output $resultObject = [PSCustomObject]@{ "alg" = $tokenHeaderJSON.alg "typ" = $tokenHeaderJSON.typ "kid" = $tokenHeaderJSON.kid "sub" = $tokenPayloadJSON.sub "exp" = [datetime]::new(1970, 1, 1, 0, 0, 0, 0, [DateTimeKind]::Utc).AddSeconds($tokenPayloadJSON.exp).ToLocalTime() "type" = $tokenPayloadJSON.type "signature" = $tokenSignature } $resultObject } function ConvertFrom-NameCache { <# .Synopsis ConvertFrom-NameCache .DESCRIPTION Convert Name to ID from cached TANSS.Lookup values .PARAMETER Name Name to convert into ID .PARAMETER Id Id to convert into Name .PARAMETER Type Lookup type where the name should convert from .EXAMPLE PS C:\> ConvertFrom-NameCache -Name "User X" -Type "Employee" Example .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "FromName", SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( [Parameter( ParameterSetName = "FromName", Mandatory = $true )] [string] $Name, [Parameter( ParameterSetName = "FromId", Mandatory = $true )] [int] $Id, [Parameter(Mandatory = $true)] [ValidateSet("Companies", "Contracts", "CostCenters", "Departments", "Employees", "OrderBys", "Phases", "Tags", "Tickets", "TicketStates", "TicketTypes", "VacationAbsenceSubTypes", "VacationTypesPredefinedApi")] [string] $Type ) $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" switch ($parameterSetName) { "FromName" { Write-PSFMessage -Level Verbose -Message "Start converting '$($Name)' of type '$($Type)' to ID" if ( ([TANSS.Lookup]::$Type).ContainsValue($Name) ) { foreach ($key in [TANSS.Lookup]::$Type.Keys) { if ([TANSS.Lookup]::$Type[$key] -like $Name) { Write-PSFMessage -Level Verbose -Message "Found ID '$key' for name '$($Name)' of type '$($Type)'" return $key } } } else { Write-PSFMessage -Level Error -Message "Unable to convert '$($Name)' of type '$($Type)' in ID. Name is not in present in cache." } } "FromId" { Write-PSFMessage -Level Verbose -Message "Start converting ID '$($Id)' of type '$($Type)' to name" if ( ([TANSS.Lookup]::$Type).ContainsKey("$($Id)") ) { $output = [TANSS.Lookup]::$Type["$($Id)"] Write-PSFMessage -Level Verbose -Message "Found '$output' with ID '$($Id)' of type '$($Type)'" return $output } else { Write-PSFMessage -Level Error -Message "Unable to convert '$($Id)' of type '$($Type)' into Name. Id is not in present in cache." } } Default { Stop-PSFFunction -Message "Unhandeled ParameterSetName. Developers mistake." -EnableException $true throw } } } Function ConvertFrom-UnixEpochTime { <# .SYNOPSIS Converts UNIX Epoch Time to DateTime object .DESCRIPTION Converts UNIX Epoch Time to DateTime object .PARAMETER EpochTime The time value to convert .PARAMETER UTC convert the given Epoch without following the lcoal timezone .EXAMPLE PS C:\> ConvertFrom-UnixEpochTime -EpochTime "1641769200" Converts the content from variable $TokenText to an object #> param( # Parameter help description [Parameter( ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true )] [int[]] $EpochTime, [switch] $UTC ) Process { foreach ($item in $EpochTime) { if ($UTC) { ([datetime]'1/1/1970').AddSeconds($item) } else { [timezone]::CurrentTimeZone.ToLocalTime(([datetime]'1/1/1970').AddSeconds($item)) } } } } function Format-ApiPath { <# .Synopsis Format-ApiPath .DESCRIPTION Ensure the right format and the existense of api prefix in the given path .PARAMETER Path Path to format .PARAMETER QueryParameter A hashtable for all the parameters to the api route .EXAMPLE PS C:\> Format-ApiPath -Path $ApiPath Api path data from variable $ApiPath will be tested and formatted. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( [Parameter(Mandatory = $true)] [string] $Path, [hashtable] $QueryParameter ) # Start Function Write-PSFMessage -Level System -Message "Formatting API path '$($Path)'" # receive module cental configuration for prefix on api path (default is 'backend/') $apiPrefix = Get-PSFConfigValue -FullName 'PSTANSS.API.RestPathPrefix' -Fallback "" # remove no more need slashes $apiPath = $Path.Trim('/') # check on API path prefix if (-not $ApiPath.StartsWith($apiPrefix)) { $ApiPath = $apiPrefix + $ApiPath Write-PSFMessage -Level Debug -Message "Add API prefix, formatting path to '$($ApiPath)'" } else { Write-PSFMessage -Level Debug -Message "Prefix API path already present" } # If specified, process hashtable QueryParameters to valid parameters into uri if ($MyInvocation.BoundParameters['QueryParameter'] -and $QueryParameter) { Write-PSFMessage -Level Debug -Message "Add query parameters '$([string]::Join("' ,'", $QueryParameter.Keys))'" $apiPath = "$($apiPath)?" $i = 0 foreach ($key in $QueryParameter.Keys) { if ($i -gt 0) { $apiPath = "$($apiPath)&" } if ("System.Array" -in ($QueryParameter[$Key]).psobject.TypeNames) { $parts = $QueryParameter[$Key] | ForEach-Object { "$($key)=$($_)" } $apiPath = "$($apiPath)$([string]::Join("&", $parts))" } else { $apiPath = "$($apiPath)$($key)=$($QueryParameter[$Key])" } $i++ } } # Output Result $ApiPath = $ApiPath.TrimEnd("?") $ApiPath } function Invoke-CacheRefresh { <# .Synopsis Invoke-CacheRefresh .DESCRIPTION Invokes api calls to fill mostly used lookup values .PARAMETER Token AccessToken object to register as default connection for TANSS .EXAMPLE PS C:\> Invoke-CacheRefresh -Token $token Example .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( [Parameter(Mandatory = $true)] [TANSS.Connection] $Token ) Write-PSFMessage -Level Verbose -Message "Start updating lookup cache from current tickets in TANSS" -Tag "Cache" $tickets = @() $tickets += Get-TANSSTicket -MyTickets -Token $token $tickets += Get-TANSSTicket -NotAssigned -Token $token $tickets += Get-TANSSTicket -AllTechnician -Token $token Write-PSFMessage -Level Verbose -Message "Built cache from $($tickets.count) tickets" -Tag "Cache" $null = Get-TANSSVacationAbsenceSubType -Token $token $null = Get-TANSSDepartment -Token $token $null = Get-TANSSTicketStatus -Token $token $null = Get-TANSSTicketType -Token $token } function Invoke-TANSSTokenCheck { <# .Synopsis Test a TANSS connection- oder service-token .DESCRIPTION Tests validity for a TANSS.Connection object .PARAMETER Token TANSS.Connection Token object to check on .PARAMETER NoRefresh Indicates that the function will not try to update the specified token .PARAMETER DoNotRegisterConnection Do not register the connection as default connection .PARAMETER PassThru Outputs the token to the console, even when the register switch is set .EXAMPLE PS C:\> Invoke-TANSSTokenCheck -Token $Token Test the TANSS.Connection object from variable $Token for validity If the token has a lifetime under 5 percent, the function will try to update the token. If the token matches the registered token within the module, the updated token will also be registered. .EXAMPLE PS C:\> Invoke-TANSSTokenCheck -Token $Token -NoRefresh Test the TANSS.Connection object from variable $Token for validity, but will NOT try to update the token. Considered for testing ServiceTokes, that can't be updated .EXAMPLE PS C:\> Invoke-TANSSTokenCheck -Token $Token -DoNotRegisterConnection -PassThru Test the TANSS.Connection object from variable $Token for validity. If the token has a lifetime under 5 percent, the function will try to update the token, but not registered as the standard token for the module. Instead, the token will be outputted to the console. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "Default", SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] [OutputType([TANSS.Connection])] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [TANSS.Connection] $Token, [Parameter(ParameterSetName = "NoRefresh")] [switch] $NoRefresh, [Parameter(ParameterSetName = "Default")] [switch] $DoNotRegisterConnection, [switch] $PassThru ) begin { $registeredToken = Get-TANSSRegisteredAccessToken } process { # General validity check if (-not $Token.IsValid) { Stop-PSFFunction -Message "$($Token.EmployeeType) token for '$($Token.UserName)' on $($Token.Server) is not valid" -Tag "AccessToken", "InvalidToken" -EnableException $true -PSCmdlet $pscmdlet } # Lifetime check if ($Token.PercentRemaining -lt 5) { Write-PSFMessage -Level Warning -Message "$($Token.EmployeeType) token for '$($Token.UserName)' on $($Token.Server) is about to expire in $($Token.TimeRemaining.Minutes) min" -Tag "AccessToken", "InvalidToken" if ((-not $NoRefresh) -and $Token.RefreshToken) { Write-PSFMessage -Level Verbose -Message "Going to try a token refresh" -Tag "AccessToken" # Compile parameters for Token refresh $paramUpdateTANSSAccessToken = @{ "Token" = $Token "NoCacheRefresh" = $true "PassThru" = $true } if ((([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($registeredToken.AccessToken))) -notlike [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token.AccessToken))) -or $DoNotRegisterConnection) { $paramUpdateTANSSAccessToken.add("DoNotRegisterConnection", $false) } else { $paramUpdateTANSSAccessToken.add("DoNotRegisterConnection", $true) } $newToken = Update-TANSSAccessToken @paramUpdateTANSSAccessToken # Output result if ($PassThru) { $newToken } } else { Write-PSFMessage -Level Important -Message "Please aquire a new token as soon as possible" -Tag "AccessToken", "NoAccessTokenRefresh" } } # Output if if((-not $newToken) -and $PassThru) { $Token } } end {} } function Push-DataToCacheRunspace { <# .Synopsis Push-DataToCacheRunspace .DESCRIPTION Push meta information to runspace cache .PARAMETER MetaData The metadata PSCusomobject to push to Cache .EXAMPLE PS C:\> Push-DataToCacheRunspace -MetaData $response.meta Push meta information to runspace cache .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding( SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [Alias("Meta", "Data")] $MetaData ) Write-PSFMessage -Level Debug -Message "Pushing data to cache validationRunspace" [TANSS.Cache]::Data.Add((New-Guid), $MetaData) } function Update-CacheLookup { <# .Synopsis Update-CacheLookup .DESCRIPTION Update a cache lookup hashtable with an object .PARAMETER LookupName Name of LokkupClass where to update .PARAMETER Id The Id to of the record to cache .PARAMETER Name The name of the record to cache .EXAMPLE PS C:\> Update-CacheLookup -LookupName "Departments" -Id $department.Id -Name $department.Name Update or insert the key from variable $department.Id of the cache-lookup-hashtable [TANSS.Lookup]::Departments with the name $department.Name .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding( SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [string] $LookupName, [int] $Id, [string] $Name ) if ([TANSS.Lookup]::$LookupName["$($Id)"] -notlike $Name) { if ([TANSS.Lookup]::$LookupName["$($Id)"]) { Write-PSFMessage -Level Debug -Message "Update existing id '$($Id)' in [TANSS.Lookup]::$($LookupName) with value '$($Name)'" -Tag "Cache", $LookupName [TANSS.Lookup]::$LookupName["$($Id)"] = $Name } else { Write-PSFMessage -Level Debug -Message "Insert in [TANSS.Lookup]::$($LookupName): $($Id) - '$($($Name))'" -Tag "Cache", $LookupName ([TANSS.Lookup]::$LookupName).Add("$($Id)", $Name) } } } function ConvertFrom-TANSSTimeStampParameter { <# .Synopsis ConvertFrom-TANSSTimeStampParameter .DESCRIPTION Convert display names for Type & State parameter into api texts .PARAMETER Text If not specified, the registered default token from within the module is going to be used .PARAMETER TextType Specifies if the text is a timestampe "state" or "type" .EXAMPLE PS C:\> ConvertFrom-TANSSTimeStampParameter -Text "Coming" -TextType "State" Outputs "On" as a "comming state for TANSS api .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [Parameter( Mandatory=$true, ValueFromPipeline=$true )] [ValidateSet("Coming", "Leaving", "StartPause", "EndPause", "Work", "Inhouse", "Errand", "Vacation", "Illness", "PaidAbsence", "UnpaidAbsence", "Overtime", "Support")] [string] $Text, [Parameter( Mandatory=$true )] [ValidateSet("State", "Type")] [String] $TextType ) begin {} process { Write-PSFMessage -Level Debug -Message "Start converting '$($Text)' as '$($TextType)' to ApiText value" $apiText = "" switch ($TextType) { "State" { switch ($Text) { "Coming" { $apiText = "ON" } "Leaving" { $apiText = "OFF" } "StartPause" { $apiText = "PAUSE_START" } "EndPause" { $apiText = "PAUSE_END" } Default { Stop-PSFFunction -Message "Unhandeled pattern for parameter Text. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } } "Type" { switch ($Text) { "Work" { $apiText = "WORK" } "Inhouse" { $apiText = "INHOUSE" } "Errand" { $apiText = "ERRAND" } "Vacation" { $apiText = "VACATION" } "Illness" { $apiText = "ILLNESS" } "PaidAbsence" { $apiText = "ABSENCE_PAID" } "UnpaidAbsence" { $apiText = "ABSENCE_UNPAID" } "Overtime" { $apiText = "OVERTIME" } "Support" { $apiText = "DOCUMENTED_SUPPORT" } Default { Stop-PSFFunction -Message "Unhandeled pattern for parameter Text. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } } Default { Stop-PSFFunction -Message "Unhandeled pattern for parameter TextType. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } # Output Write-PSFMessage -Level Debug -Message "'$($Text)' as '$($TextType)' converted into ApiText value: $($apiText) done" $apiText } end {} } function Connect-TANSS { <# .Synopsis Connect-TANSS .DESCRIPTION Connect to TANSS Service .PARAMETER Server Name of the service to connect to .PARAMETER Credential The credentials to login .PARAMETER LoginToken If the user needs an -application specific- login token for MFA, this field must be set as well .PARAMETER Protocol Specifies if the connection is done with http or https .PARAMETER DoNotRegisterConnection Do not register the connection as default connection .PARAMETER NoCacheInit Do not query current existing tickets and various types to fill cache data for lookup types .PARAMETER PassThru Outputs the token to the console, even when the register switch is set .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Connect-TANSS -Server "tanss.company.com" -Credential (Get-Credential "username") Connects to "tanss.company.com" via HTTPS protocol and the specified credentials. Connection will be set as default connection for any further action. .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [CmdletBinding( DefaultParameterSetName = 'Credential', SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Connection])] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias("ComputerName", "Hostname", "Host", "ServerName")] [String] $Server, [Parameter( Mandatory = $true, ParameterSetName = 'Credential' )] [System.Management.Automation.PSCredential] $Credential, [Parameter(ParameterSetName = 'Credential')] [string] $LoginToken, [ValidateSet("HTTP", "HTTPS")] [ValidateNotNullOrEmpty()] [String] $Protocol = "HTTPS", [Alias('NoRegistration')] [Switch] $DoNotRegisterConnection, [switch] $NoCacheInit, [switch] $PassThru ) begin { $ApiPath = Format-ApiPath -Path "api/v1/user/login" } process { if ($protocol -eq 'HTTP') { Write-PSFMessage -Level Important -Message "Unsecure $($protocol) connection with possible security risk detected. Please consider switch to HTTPS!" -Tag "Connection" $prefix = 'http://' } else { Write-PSFMessage -Level System -Message "Using secure $($protocol) connection." -Tag "Connection" $prefix = 'https://' } if ($Server -match '//') { if ($Server -match '\/\/(?<Server>(\w+|\.)+)') { $Server = $Matches["Server"] } Remove-Variable -Name Matches -Force -Verbose:$false -Debug:$false -Confirm:$false } if ($PsCmdlet.ParameterSetName -eq 'Credential') { if (($credential.UserName.Split('\')).count -gt 1) { $userName = $credential.UserName.Split('\')[1] } else { $userName = $credential.UserName } Write-PSFMessage -Level Verbose -Message "Authenticate user '$($userName)' to service '$($Prefix)$($server)'" -Tag "Connection", "Authentication" $param = @{ "Uri" = "$($prefix)$($server)/$($ApiPath)" "Headers" = @{ "user" = $userName "password" = $credential.GetNetworkCredential().Password "logintoken" = "$($LoginToken)" } "Verbose" = $false "Debug" = $false "ErrorAction" = "Stop" "ErrorVariable" = "invokeError" } try { $response = Invoke-RestMethod @param } catch { Stop-PSFFunction -Message "Error invoking rest call on service '$($Prefix)$($server)'. $($invokeError)" -Tag "Connection", "Authentication" -EnableException $true -Cmdlet $pscmdlet } if ($response.meta.text -like "Unsuccesful login attempt") { $msgText = "$($response.meta.text) to service '$($Prefix)$($server)'. Maybe wrong password" if (-not $LoginToken) { $msgText = "$($msgText) or LoginToken (OTP) is needed" } else { $msgText = "$($msgText) or LoginToken (OTP) wrong/expired" } Stop-PSFFunction -Message $msgText -Tag "Connection", "Authentication" -EnableException $true -Cmdlet $pscmdlet } if (-not $response.content.apiKey) { Stop-PSFFunction -Message "Something went wrong on authenticating user $($userName). No apiKey found in response. Unable login to service '$($Prefix)$($server)'" -Tag "Connection", "Authentication" -EnableException $true -Cmdlet $pscmdlet } } Write-PSFMessage -Level System -Message "Creating TANSS.Connection" -Tag "Connection" $token = [TANSS.Connection]@{ Server = "$($Prefix)$($Server)" UserName = $userName EmployeeId = $response.content.employeeId EmployeeType = $response.content.employeeType AccessToken = ($response.content.apiKey | ConvertTo-SecureString -AsPlainText -Force) RefreshToken = ($response.content.refresh | ConvertTo-SecureString -AsPlainText -Force) Message = $response.meta.text TimeStampCreated = Get-Date TimeStampExpires = [datetime]::new(1970, 1, 1, 0, 0, 0, 0, [DateTimeKind]::Utc).AddSeconds($response.content.expire).ToLocalTime() TimeStampModified = Get-Date } if (-not $NoCacheInit) { Invoke-CacheRefresh -Token $token } if (-not $DoNotRegisterConnection) { # Make the connection the default connection for further commands Register-TANSSAccessToken -Token $token Write-PSFMessage -Level Significant -Message "Connected to service '($($token.Server))' as '$($token.UserName)' as default connection" -Tag "Connection" if ($PassThru) { Write-PSFMessage -Level System -Message "Outputting TANSS.Connection object" -Tag "Connection" $token } } else { Write-PSFMessage -Level Significant -Message "Connected to service '($($token.Server))' as '$($token.UserName)', outputting TANSS.Connection" -Tag "Connection" $token } } end { } } function Find-TANSSObject { <# .Synopsis Find-TANSSObject .DESCRIPTION Find a object via global search in TANSS The search has to be initiated on one of three areas. (Company, Employees, Tickets) .PARAMETER Company Initiate a search in the company area of TANSS .PARAMETER Employee Initiate a search within the employee/person database of TANSS .PARAMETER TicketPreview Initiate a search in the tickets of TANSS .PARAMETER Text The Text (id or name) to seach for .PARAMETER ShowInactive Search company records that are marked as inactive By default, only companies that are marked as "active" This is bound to company search only .PARAMETER ShowLocked Search company records that are marked as locked By default, only companies that are marked as "Unlocked" This is bound to company search only .PARAMETER CompanyId Return tickets or employees of the specified company id This is bound to ticket- and employee-search only .PARAMETER CompanyName Return tickets or employees of the specified company name This is bound to ticket- and employee-search only .PARAMETER Status Return "All", only "Active" or only "Inactive" employees. .PARAMETER GetCategories If true, categories will be fetches as well. The names are given in the "linked entities"-"employeeCategories" Default is $false .PARAMETER GetCallbacks If true, expected callbacks will be fetched as well Default is $false .PARAMETER PreviewContentMaxChars If defined, it overrides the to preview the content Default values within the api is 60 .PARAMETER ResultSize The amount of objects the query will return To avoid long waitings while query a large number of items, the api by default only query an amount of 100 items within one call .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Find-TANSSObject -Company -Text "Customer X" Search for "Customer X" within all company data .EXAMPLE PS C:\> Find-TANSSObject -TicketPreview -Text "Issue Y" Search for "Issue Y" within all tickets .EXAMPLE PS C:\> "Mister T" | Find-TANSSObject -Employee Search "Mister T" in the employee records of all companies .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "Company", PositionalBinding = $true, SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] [OutputType([TANSS.TicketPreview], [TANSS.Company], [TANSS.EmployeeSearched])] Param( [Parameter(ParameterSetName = "Company")] [switch] $Company, [Parameter(ParameterSetName = "Employee-UserFriendly")] [Parameter(ParameterSetName = "Employee-ApiNative")] [switch] $Employee, [Parameter(ParameterSetName = "Ticket-UserFriendly")] [Parameter(ParameterSetName = "Ticket-ApiNative")] [Alias("Ticket")] [switch] $TicketPreview, [Parameter(ParameterSetName = "Company", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = "Employee-UserFriendly", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = "Employee-ApiNative", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = "Ticket-UserFriendly", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Parameter(ParameterSetName = "Ticket-ApiNative", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateLength(2, [int]::MaxValue)] [string[]] $Text, [Parameter(ParameterSetName = "Company")] [switch] $ShowInactive, [Parameter(ParameterSetName = "Company")] [switch] $ShowLocked, [Parameter(ParameterSetName = "Employee-ApiNative")] [Parameter(ParameterSetName = "Ticket-ApiNative")] [int] $CompanyId, [Parameter(ParameterSetName = "Employee-UserFriendly", Mandatory = $true)] [Parameter(ParameterSetName = "Ticket-UserFriendly", Mandatory = $true)] [string] $CompanyName, [Parameter(ParameterSetName = "Employee-UserFriendly")] [Parameter(ParameterSetName = "Employee-ApiNative")] [ValidateSet("All", "Active", "Inactive")] [string] $Status = "All", [Parameter(ParameterSetName = "Employee-UserFriendly")] [Parameter(ParameterSetName = "Employee-ApiNative")] [bool] $GetCategories = $false, [Parameter(ParameterSetName = "Employee-UserFriendly")] [Parameter(ParameterSetName = "Employee-ApiNative")] [bool] $GetCallbacks = $false, [Parameter(ParameterSetName = "Ticket-UserFriendly")] [Parameter(ParameterSetName = "Ticket-ApiNative")] [int] $PreviewContentMaxChars, [Parameter(ParameterSetName = "Company")] [Parameter(ParameterSetName = "Employee-UserFriendly")] [Parameter(ParameterSetName = "Employee-ApiNative")] [Parameter(ParameterSetName = "Ticket-UserFriendly")] [Parameter(ParameterSetName = "Ticket-ApiNative")] [int] $ResultSize, [Parameter(ParameterSetName = "Company")] [Parameter(ParameterSetName = "Employee-UserFriendly")] [Parameter(ParameterSetName = "Employee-ApiNative")] [Parameter(ParameterSetName = "Ticket-UserFriendly")] [Parameter(ParameterSetName = "Ticket-ApiNative")] [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning $apiPath = Format-ApiPath -Path "api/v1/search" if ((-not $ResultSize) -or ($ResultSize -eq 0)) { $ResultSize = 100 } if ($Status) { switch ($Status) { "All" { $inactive = $true } "Active" { $inactive = $false } "Inactive" { $inactive = $true } Default { Stop-PSFFunction -Message "Unhandeled Status. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } } if($MyInvocation.BoundParameters['CompanyName'] -and $CompanyName) { $CompanyId = ConvertFrom-NameCache -Name CompanyName -Type "Companies" if(-not $CompanyId) { Write-PSFMessage -Level Warning -Message "No Id for company '$($Company)' found. Ticket will be created with blank value on CompanyId" } } } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" switch ($parameterSetName) { "Company" { foreach ($textItem in $Text) { $body = @{ areas = @("COMPANY") query = $textItem.replace("*", "") configs = @{ company = @{ maxResults = $ResultSize } } } $response = Invoke-TANSSRequest -Type PUT -ApiPath $apiPath -Body $body -Token $Token if ($response.content.companies) { $countCompanyAll = ([array]($response.content.companies)).count Write-PSFMessage -Level Verbose -Message "API response: $($response.meta.text) - $($countCompanyAll) records returned" if (-not $ShowInactive) { $countCompanyFiltered = ([array]($response.content.companies | Where-Object { $_.inactive -like "False" })).Count Write-PSFMessage -Level Verbose -Message "Filtering companies marked as inactive - keeping $($countCompanyFiltered) of $($countCompanyAll) records" } else { $countCompanyFiltered = $countCompanyAll } if (-not $ShowLocked) { $countCompanyFiltered = $countCompanyFiltered - ([array]($response.content.companies | Where-Object { $_.lockout -like "True" })).Count Write-PSFMessage -Level Verbose -Message "Filtering companies marked as locked - keeping $($countCompanyFiltered) of $($countCompanyAll) records" } foreach ($companyItem in $response.content.companies) { # Filtering if(-not $ShowInactive) { if($companyItem.inactive -like "True") { continue } } if(-not $ShowLocked) { if($companyItem.lockout -like "True") { continue } } # Output data [TANSS.Company]@{ BaseObject = $companyItem Id = $companyItem.id } } } else { Write-PSFMessage -Level Verbose -Message "API response: $($response.meta.text) - no records returned from global search" } } } {$_ -like "Employee-ApiNative" -or $_ -like "Employee-UserFriendly"} { foreach ($textItem in $Text) { $body = @{ areas = @("EMPLOYEE") query = $textItem configs = @{ employee = @{ maxResults = $ResultSize } } } if($CompanyId) { $body.configs.employee.Add("companyId", $CompanyId) } if($Status) { $body.configs.employee.Add("inactive", $inactive) } if("GetCategories" -in $PSCmdlet.MyInvocation.BoundParameters.Keys) { $body.configs.employee.Add("categories", $GetCategories) } if("GetCallbacks" -in $PSCmdlet.MyInvocation.BoundParameters.Keys) { $body.configs.employee.Add("callbacks", $GetCallbacks) } $response = Invoke-TANSSRequest -Type PUT -ApiPath $apiPath -Body $body -Token $Token if ($response.content.employees) { $countEmployeeAll = ([array]($response.content.employees)).count Write-PSFMessage -Level Verbose -Message "API response: $($response.meta.text) - $($countEmployeeAll) records returned" Push-DataToCacheRunspace -MetaData $response.meta foreach ($employeeItem in $response.content.employees) { # Output data [TANSS.EmployeeSearched]@{ BaseObject = $employeeItem Id = $employeeItem.id } } } else { Write-PSFMessage -Level Verbose -Message "API response: $($response.meta.text) - no records returned from global search" } } } {$_ -like "Ticket-ApiNative" -or $_ -like "Ticket-UserFriendly"} { foreach ($textItem in $Text) { $body = @{ areas = @("TICKET") query = $textItem configs = @{ employee = @{ maxResults = $ResultSize } } } if($CompanyId) { $body.configs.employee.Add("companyId", $CompanyId) } if($PreviewContentMaxChars) { $body.configs.employee.Add("previewContentMaxChars", $PreviewContentMaxChars) } $response = Invoke-TANSSRequest -Type PUT -ApiPath $apiPath -Body $body -Token $Token if ($response.content.Tickets) { $countTicketsAll = ([array]($response.content.Tickets)).count Write-PSFMessage -Level Verbose -Message "API response: $($response.meta.text) - $($countTicketsAll) records returned" Push-DataToCacheRunspace -MetaData $response.meta foreach ($ticketItem in $response.content.Tickets) { # Output data [TANSS.TicketPreview]@{ BaseObject = $ticketItem Id = $ticketItem.id } } } else { Write-PSFMessage -Level Verbose -Message "API response: $($response.meta.text) - no records returned from global search" } } } Default { Stop-PSFFunction -Message "Unhandeled ParameterSetName. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } } end {} } function Get-TANSSDepartment { <# .Synopsis Get-TANSSDepartment .DESCRIPTION Get department from TANSS .PARAMETER Id Id of the department to get .PARAMETER Name Name of the department to get .PARAMETER IncludeEmployeeId Include assigned employees .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSDepartment Get departments from TANSS .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "All", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] [OutputType([TANSS.Department])] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "ById" )] [int[]] $Id, [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "ByName" )] [string[]] $Name, [switch] $IncludeEmployeeId, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning if ($IncludeEmployeeId) { Write-PSFMessage -Level Verbose -Message "IncludeEmployeeId switch is specified, going to ask for linked IDs" -Tag "Department", "IncludeEmployeeId" $deparmentsWithEmployeeId = Invoke-TANSSRequest -Type GET -ApiPath "api/v1/companies/departments?withEmployees=true" -Token $Token | Select-Object -ExpandProperty content $departments = foreach ($department in $departments) { [array]$_employeeIds = $deparmentsWithEmployeeId | Where-Object id -like $department.id | Select-Object -ExpandProperty employeeIds $department | Add-Member -MemberType NoteProperty -Name employeeIds -Value $_employeeIds $department } Remove-Variable -Name deparmentsWithEmployeeId, _employeeIds, deparment -Force -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false -ErrorAction:Ignore -WarningAction:Ignore -InformationAction:Ignore } else { $departments = Invoke-TANSSRequest -Type GET -ApiPath "api/v1/employees/departments" -Token $Token | Select-Object -ExpandProperty content } [array]$filteredDepartments = @() } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" switch ($parameterSetName) { "ById" { foreach ($item in $Id) { $filteredDepartments += $departments | Where-Object id -eq $item } } "ByName" { foreach ($item in $Name) { $filteredDepartments += $departments | Where-Object name -like $item } } "All" { $filteredDepartments = $departments } Default { Stop-PSFFunction -Message "Unhandled ParameterSet '$($parameterSetName)', developers mistake" -EnableException $true -Cmdlet $pscmdlet -Tag "Department", "SwitchException", "ParameterSet" } } } end { $filteredDepartments = $filteredDepartments | Sort-Object name, id -Unique Write-PSFMessage -Level Verbose -Message "Going to return $($filteredDepartments.count) departments" -Tag "Department", "Output" foreach ($department in $filteredDepartments) { Write-PSFMessage -Level System -Message "Working on department '$($department.name)' with id '$($department.id)'" -Tag "Department" # put id and name to cache lookups Update-CacheLookup -LookupName "Departments" -Id $department.Id -Name $department.Name # output result [TANSS.Department]@{ Baseobject = $department Id = $department.id } } } } function Get-TANSSRegisteredAccessToken { <# .Synopsis Get-TANSSRegisteredAccessToken .DESCRIPTION Retrieve the registered LoginToken for default TANSS connection .EXAMPLE PS C:\> Get-TANSSRegisteredAccessToken Retrieve the registered LoginToken for TANSS .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] Param( ) begin {} process { Write-PSFMessage -Level Verbose -Message "Retrieving the registered LoginToken for '$($script:TANSSToken.UserName)' on '$($script:TANSSToken.Server)'" -Tag "AccessToken" $script:TANSSToken } end {} } function Invoke-TANSSRequest { <# .Synopsis Invoke-TANSSRequest .DESCRIPTION Invoke a API request to TANSS Server .PARAMETER Type Type of web request .PARAMETER ApiPath Uri path for the REST call in the API .PARAMETER QueryParameter A hashtable for all the parameters to the api route .PARAMETER AdditionalHeader Hashtable with additional values to put in the header of the request .PARAMETER Body The body as a hashtable for the request .PARAMETER Pdf if a PDF should be queried, this switch must be specified .PARAMETER BodyForceArray Tells the function always to invoke the data in the body as a JSON array formatted string .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Invoke-TANSSRequest -Type GET -ApiPath "api/v1/something" Invoke a GET request to API with path api/v1/something by using the default registered token within the module .EXAMPLE PS C:\> Invoke-TANSSRequest -Type GET -ApiPath "api/v1/something" -Token $Token Invoke a GET request to API with path api/v1/something by using the explicit token from the variale $Token .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = 'Default', SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] param ( [Parameter(Mandatory = $true)] [ValidateSet("GET", "POST", "PUT", "DELETE")] [string] $Type, [Parameter(Mandatory = $true)] [string] $ApiPath, [hashtable] $QueryParameter, [hashtable[]] $Body, [hashtable] $AdditionalHeader, [switch] $Pdf, [switch] $BodyForceArray, [TANSS.Connection] $Token ) begin { } process { } end { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Invoke-TANSSTokenCheck -Token $Token $ApiPath = Format-ApiPath -Path $ApiPath -QueryParameter $QueryParameter # Body if ($Body) { $bodyData = $Body | ConvertTo-Json -Compress } else { $bodyData = $null } if ($BodyForceArray -and (-not ([string]$bodyData).StartsWith("["))) { $bodyData = "[$($bodyData)]" } # Header $header = @{ "apiToken" = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token.AccessToken)) } if ($Pdf) { $header.Add("Accept", "pdf") } if ($MyInvocation.BoundParameters['AdditionalHeader'] -and $AdditionalHeader) { foreach ($key in $AdditionalHeader.Keys) { $header.Add($key, $AdditionalHeader[$key]) } } # Invoke request $param = [ordered]@{ "Uri" = "$($Token.Server)/$($ApiPath)" "Headers" = $header "Body" = $bodyData "Method" = $Type "ContentType" = 'application/json; charset=UTF-8' "Verbose" = $false "Debug" = $false "ErrorAction" = "Stop" "ErrorVariable" = "invokeError" } if ($pscmdlet.ShouldProcess("$($Type) web REST call against URL '$($param.Uri)'", "Invoke")) { Write-PSFMessage -Level Verbose -Message "Invoke $($Type) web REST call against URL '$($param.Uri)'" -Tag "TANSSApiRequest" -Data @{ "body" = $bodyData; "Method" = $Type } try { $response = Invoke-RestMethod @param Write-PSFMessage -Level System -Message "API Response: $($response.meta.text)" -Tag "TANSSApiRequest", "SuccessfulRequest" -Data @{ "response" = $response } } catch { if ($invokeError[0].Message.StartsWith("{")) { $response = $invokeError[0].Message | ConvertFrom-Json -ErrorAction SilentlyContinue } if ($response) { Write-PSFMessage -Level Error -Message "$($response.Error.text) - $($response.Error.localizedText)" -Exception $response.Error.type -Tag "TANSSApiRequest", "FailedRequest", "REST call $($Type)" -Data @{ "Message" = $invokeError[0].Message } -PSCmdlet $pscmdlet -ErrorRecord $invokeError[0].ErrorRecord } else { Write-PSFMessage -Level Error -Message "$($invokeError[0].Source) ($($invokeError[0].HResult)): $($invokeError[0].Message)" -Exception $invokeError[0].InnerException -Tag "TANSSApiRequest", "FailedRequest", "REST call $($Type)" -ErrorRecord $invokeError[0].ErrorRecord -PSCmdlet $pscmdlet -Data @{ "Message" = $invokeError[0].Message } } return } # Output $response } } } function New-TANSSServiceToken { <# .Synopsis Create a new (user unspecific) api service access token object .DESCRIPTION Create a new api service access token object. Apart from the regular user login, there are aspects and api routes, that are only available via explicit service token. This function allows you to create a service token to give to other functions, that require such a token. .PARAMETER Server Name of the service the token is generated from .PARAMETER ServiceToken A API token generated within Tanss to access specific TANSS modules explicit via API service as a non-employee-account. For security reaons, the parameter only accept secure strings. Please avoid plain-text for sensitive informations! To generate secure strings use: $ServiceTokenSecureString = Read-Host -AsSecureString .PARAMETER Protocol Specifies if the service connection is done with http or https .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> $tanssServiceToken = New-TANSSServiceToken -Server "tanss.corp.company.com" -ServiceToken $ServiceTokenSecureString Outputs a ServiceToken as a TANSS.Connection object for "tanss.corp.company.com" with the api key from the variable $ServiceTokenSecureString API variable $ServiceTokenSecureString hast to be a securestring. ($ServiceTokenSecureString = Read-Host -AsSecureString) .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "Default", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Connection])] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias("ComputerName", "Hostname", "Host", "ServerName")] [ValidateNotNull()] [String] $Server, [Parameter( Mandatory = $true, ValueFromPipeline = $true )] [Alias("ApiKey", "Password", "AccessToken", "Token")] [securestring] $ServiceToken, [ValidateSet("HTTP", "HTTPS")] [ValidateNotNullOrEmpty()] [String] $Protocol = "HTTPS" ) begin { } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" # Ensure Prefix if ($protocol -eq 'HTTP') { Write-PSFMessage -Level Important -Message "Unsecure $($protocol) connection with possible security risk detected. Please consider switch to HTTPS!" -Tag "ServiceToken" $prefix = 'http://' } else { Write-PSFMessage -Level System -Message "Using secure $($protocol) connection." -Tag "ServiceToken" $prefix = 'https://' } # Validate Server Parameter to avoid accidentally input bearer token information in $Server try { $null = ConvertFrom-JWTtoken -TokenText $Server $serverIsTokenObject = $true } catch { $serverIsTokenObject = $false } if (($Server.StartsWith("Bearer")) -or ($Server.Length -gt 256) -or ($serverIsTokenObject)) { if ($Server.Length -gt 10) { $textlength = $Server.Length / 2 } elseif ($Server.Length -gt 5) { $textlength = 4 } else { $textlength = 2 } Stop-PSFFunction -Message "The specified Server '$($Server.Substring(0, $textlength))****' looks like a service token. ServiceToken has to be piped in as a SecureString or has to be specified via parameter '-ServiceToken'. For security reason, please don't use plaintext for sensitive information." -EnableException $true -Cmdlet $pscmdlet -Tag "ServiceToken" } # Read JWT from service token $TokenText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($ServiceToken)) if ($TokenText.StartsWith("Bearer")) { Write-PSFMessage -Level System -Message "Found Bearer token information. Going to extract JWT" -Tag "ServiceToken" $TokenText = $TokenText.split(" ")[-1] } Write-PSFMessage -Level Verbose -Message "Reading JWT information from serviceToken" -Tag "ServiceToken" $tokenInfo = ConvertFrom-JWTtoken -TokenText $TokenText # Create ServiceToken if (($tokenInfo.typ -like "JWT") -and $Server -and $prefix) { if ($pscmdlet.ShouldProcess("Service token for '$($UserName)'", "New")) { Write-PSFMessage -Level System -Message "Creating TANSS.Connection with service token" -Tag "ServiceToken" $serviceTokenObject = [TANSS.Connection]@{ Server = "$($Prefix)$($Server)" UserName = $tokenInfo.sub EmployeeId = 0 EmployeeType = "ServiceAccessToken" AccessToken = $ServiceToken RefreshToken = $null Message = "Explizit specified API token. May not work with all functions!" TimeStampCreated = (Get-Date) TimeStampExpires = $tokenInfo.exp TimeStampModified = (Get-Date) } Invoke-TANSSTokenCheck -Token $serviceTokenObject -NoRefresh # output result $serviceTokenObject } } else { Write-PSFMessage -Level Important -Message "Unable to create TANSS ServiceToken object with specified ServiceToken '$($TokenText.Substring(0,10))*****'" -Tag "ServiceToken" } } end {} } function Register-TANSSAccessToken { <# .Synopsis Register-TANSSAccessToken .DESCRIPTION Register the AccessToken as default connection setting for TANSS .PARAMETER Token AccessToken object to register as default connection for TANSS .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Register-TANSSAccessToken -Token $Token Register the LoginToken from variable $Token as a default connection for TANSS .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Medium' )] Param( [Parameter(Mandatory = $true)] [TANSS.Connection] $Token ) begin {} process { if ($pscmdlet.ShouldProcess("AccessToken for $($Token.UserName) on '$($Token.Server)'", "Register")) { Write-PSFMessage -Level Verbose -Message "Registering AccessToken for $($Token.UserName) on '$($Token.Server)' valid until '$($Token.TimeStampExpires)'" -Tag "AccessToken" $script:TANSSToken = $Token } } end {} } function Update-TANSSAccessToken { <# .Synopsis Update-TANSSAccessToken .DESCRIPTION Updates the AccessToken from a refreshToken for TANSS connection By defaault, the new Access is registered to as default connection .PARAMETER NoCacheRefresh Do not requery tickets and various types to fill cache data for lookup types .PARAMETER DoNotRegisterConnection Do not register the connection as default connection .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the new token to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Update-TANSSAccessToken Updates the AccessToken from the default connection and register it as new AccessToken on default Connection .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [CmdletBinding( SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] Param( [TANSS.Connection] $Token, [Alias('NoRegistration')] [Switch] $DoNotRegisterConnection, [switch] $NoCacheRefresh, [switch] $PassThru ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { if ($Token.RefreshToken) { $refreshTokenInfo = ConvertFrom-JWTtoken -TokenText ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token.RefreshToken))).split(" ")[1] } else { Stop-PSFFunction -Message "Invalid Token specified. No refreshToken found" -Tag "Connection", "Authentication" -EnableException $true -Cmdlet $pscmdlet } Write-PSFMessage -Level Verbose -Message "Checking RefreshToken from TANSS.Connection of $($Token.UserName) on '$($Token.Server)'" -Tag "AccessToken", "Connection", "Authentication" if ( (Get-Date) -ge $refreshTokenInfo.exp ) { Stop-PSFFunction -Message "RefreshToken expired. Unable to refresh with current token. Please use Connect-TANSS to login again" -Tag "Connection", "Authentication" return } if ($pscmdlet.ShouldProcess("AccessToken from TANSS.Connection of $($Token.UserName) on '$($Token.Server)' with RefreshToken valid until '$($refreshTokenInfo.exp)'", "Update")) { $apiPath = Format-ApiPath -Path "api/v1/tickets/own" Write-PSFMessage -Level Verbose -Message "Updating AccessToken from TANSS.Connection of $($Token.UserName) on '$($Token.Server)' with RefreshToken valid until '$($refreshTokenInfo.exp)'" -Tag "AccessToken" $param = @{ "Uri" = "$($Token.Server)/$($ApiPath)" "Headers" = @{ "refreshToken" = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token.RefreshToken)) } "Verbose" = $false "Debug" = $false "ErrorAction" = "Stop" "ErrorVariable" = "invokeError" } try { $response = Invoke-RestMethod @param } catch { Stop-PSFFunction -Message "Error invoking rest call on service '$($Token.Server)'. $($invokeError)" -Tag "Connection", "Authentication" -EnableException $true -Cmdlet $pscmdlet } if ($response.meta.text -notlike "Welcome, your ApiToken is 4 hours valid.") { Stop-PSFFunction -Message "$($response.meta.text) to service '$($Token.Server)'. Apperantly, refreshToken is not valid" -Tag "Connection", "Authentication" -EnableException $true -Cmdlet $pscmdlet } if (-not $response.content.apiKey) { Stop-PSFFunction -Message "Something went wrong on authenticating user $($Token.UserName). No apiKey found in response. Unable to refresh token from connection '$($Token.Server)'" -Tag "Connection", "Authentication" -EnableException $true -Cmdlet $pscmdlet } Write-PSFMessage -Level System -Message "Creating TANSS.Connection from refreshed AccessToken" -Tag "Connection" $token = [TANSS.Connection]@{ Server = $Token.Server UserName = $Token.UserName EmployeeId = $response.content.employeeId EmployeeType = $response.content.employeeType AccessToken = ($response.content.apiKey | ConvertTo-SecureString -AsPlainText -Force) RefreshToken = ($response.content.refresh | ConvertTo-SecureString -AsPlainText -Force) Message = $response.meta.text TimeStampCreated = $Token.TimeStampCreated TimeStampExpires = [datetime]::new(1970, 1, 1, 0, 0, 0, 0, [DateTimeKind]::Utc).AddSeconds($response.content.expire).ToLocalTime() TimeStampModified = Get-Date } if (-not $NoCacheRefresh) { Invoke-CacheRefresh -Token $token } if (-not $DoNotRegisterConnection) { # Make the connection the default connection for further commands Write-PSFMessage -Level Significant -Message "Updating AccessToken for service '($($token.Server))' as '$($token.UserName)' and register it as default connection" -Tag "Connection" Register-TANSSAccessToken -Token $token if ($PassThru) { Write-PSFMessage -Level System -Message "Outputting TANSS.Connection object" -Tag "Connection" $token } } else { Write-PSFMessage -Level Significant -Message "Updating AccessToken for service '($($token.Server))' as '$($token.UserName)'" -Tag "Connection" $token } } } end {} } function Get-TANSSEmployee { <# .Synopsis Get-TANSSEmployee .DESCRIPTION Get employees out of TANSS service. You can pipe in IDs o employee objects to get refreshed data out of the service You can also pipe in company objects to receive employees of that company .PARAMETER EmployeeId The ID of the employee to get from TANSS service .PARAMETER Employee A TANSS.Employee object to query again from the service .PARAMETER CompanyId The ID of the company to get employees from .PARAMETER Company A passed in TANSS.Company object to query employees from .PARAMETER CompanyName The name of the company to query employees from .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSEmployee -EmployeeId 2 Get the employee with ID 2 (usually the first employee created in TANSS) .EXAMPLE PS C:\> $employee | Get-TANSSEmployee Query the employee from variable $employee again .EXAMPLE PS C:\> Get-TANSSEmployee -CompanyId 100000 Get all employees from company ID 100000 (your own company) .EXAMPLE PS C:\> $company | Get-TANSSEmployee Get all employees from company $company .EXAMPLE PS C:\> Get-TANSSEmployee -CompanyName "Company X" Get all employees from "Company X" .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "Employee_ApiNative", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] [OutputType([TANSS.Employee])] Param( [Parameter( ParameterSetName = "Employee_ApiNative", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [Alias("Id")] [int[]] $EmployeeId, [Parameter( ParameterSetName = "Employee_UserFriendly", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [tanss.employee] $Employee, [Parameter( ParameterSetName = "Company_ApiNative", ValueFromPipelineByPropertyName = $true, Mandatory = $true )] [int[]] $CompanyId, [Parameter( ParameterSetName = "Company_UserFriendly", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [tanss.company] $Company, [Parameter( ParameterSetName = "Company_UserFriendlyByName", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [string[]] $CompanyName, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" # If objects are piped in -> collect IDs switch ($parameterSetName) { "Employee_UserFriendly" { $EmployeeId = $Employee.Id } "Company_UserFriendly" { $CompanyId = $Company.Id } "Company_UserFriendlyByName" { $CompanyId = foreach ($_name in $CompanyName) { Find-TANSSObject -Company -Text $_name -Token $Token -ShowLocked | Where-Object name -like $_name | Select-Object -ExpandProperty Id } } } switch ($parameterSetName) { { $_ -like "Employee_*" } { Write-PSFMessage -Level System -Message "Query personal employee record. $(([array]$EmployeeId).count) record(s)" foreach ($id in $EmployeeId) { Write-PSFMessage -Level Verbose -Message "Working on employee id $($id)" $response = Invoke-TANSSRequest -Type GET -ApiPath "api/v1/employees/$($id)" -Token $Token if ($response.meta.text -like "Object found") { # Cache refresh Push-DataToCacheRunspace -MetaData $response.meta Write-PSFMessage -Level Verbose -Message "Output employee $($response.content.name)" $output = [TANSS.Employee]@{ BaseObject = $response.content Id = $response.content.id } # ToDo: Filtering - add parameters (Isactive, FilterName, ) # Output result $output } else { Write-PSFMessage -Level Error -Message "API returned no data" } } } { $_ -like "Company_*" } { Write-PSFMessage -Level System -Message "Query corporate employee record. $(([array]$CompanyId).count) record(s)" foreach ($id in $CompanyId) { Write-PSFMessage -Level Verbose -Message "Query employee(s) for company id $($id)" $response = Invoke-TANSSRequest -Type GET -ApiPath "api/v1/companies/$($id)/employees" -Token $Token if ($response.meta.text -like "Object found") { # Cache refresh Push-DataToCacheRunspace -MetaData $response.meta foreach ($responseItem in $response.content) { Write-PSFMessage -Level Verbose -Message "Output corporate employee $($responseItem.name)" $output = [TANSS.Employee]@{ BaseObject = $responseItem Id = $responseItem.id } # ToDo: Filtering - add parameters (Isactive, FilterName, ) # Output result $output } } else { Write-PSFMessage -Level Error -Message "API returned no data" } } } Default { Stop-PSFFunction -Message "Unhandeled ParameterSetName. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } } end {} } function Get-TANSSTechnician { <# .Synopsis Get-TANSSTechnician .DESCRIPTION Gets all technicians of this system from default TANSS connection .PARAMETER Id ID of the technician to get (client side filtering) .PARAMETER Name Name of the technician to get (client side filtering) .PARAMETER FreelancerCompanyId If this parameter is given, also fetches the freelancers of this company. By default all users with a license are treated as "TANSS technicians". .PARAMETER ExcludeRestrictedLicenseUser Do not show account/ users / technicians with limited licenses .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTechnician Gets all technicians of this system .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] [OutputType([TANSS.Employee])] Param( [String[]] $Name, [int[]] $Id, [int[]] $FreelancerCompanyId, [switch] $ExcludeRestrictedLicenseUser, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } $apiPath = Format-ApiPath -Path "api/v1/employees/technicians" Assert-CacheRunspaceRunning if (-not $FreelancerCompanyId) { $FreelancerCompanyId = 0 } } process { $response = @() $response += foreach ($companyId in $FreelancerCompanyId) { $queryParameter = @{} if($MyInvocation.BoundParameters['ExcludeRestrictedLicenseUser'] -and $ExcludeRestrictedLicenseUser) { $queryParameter.Add("restrictedLicenses", $false) } else { $queryParameter.Add("restrictedLicenses", $true) } if ($companyId -ne 0) { Write-PSFMessage -Level System -Message "FreelancerCompanyId specified, compiling body to query freelancers of company '$($companyId)'" -Tag "Technician", "Freelancer" $queryParameter.Add("FreelancerCompanyId", $companyId) } $invokeParam = @{ "Type" = "GET" "ApiPath" = (Format-ApiPath -Path $apiPath -QueryParameter $queryParameter) "Token" = $Token } Invoke-TANSSRequest @invokeParam Remove-Variable -Name queryParameter, invokeParam -Force -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false -ErrorAction Ignore -WarningAction Ignore -InformationAction Ignore } if ($response) { Write-PSFMessage -Level Verbose -Message "Found $(($response.content).count) technicians" -Tag "Technician" foreach ($responseItem in $response) { # Output result foreach ($technician in $responseItem.content) { # Do filtering on name if ($MyInvocation.BoundParameters['Name'] -and $Name) { $filterSuccess = $false foreach ($filterName in $Name) { if ($technician.Name -like $filterName) { $filterSuccess = $true } } # if filter does not hit, continue with next technician if ($filterSuccess -eq $false) { continue } } # Do filtering on id if ($MyInvocation.BoundParameters['Id'] -and $Id) { $filterSuccess = $false foreach ($filterId in $Id) { if ([int]($technician.id) -eq $filterId) { $filterSuccess = $true } } # if filter does not hit, continue with next technician if ($filterSuccess -eq $false) { continue } } # Query details Write-PSFMessage -Level Verbose -Message "Getting details of '$($technician.name)' (Id $($technician.id))" -Tag "Technician" $invokeParam = @{ "Type" = "GET" "ApiPath" = (Format-ApiPath -Path "api/v1/employees/$($technician.id)") "Token" = $Token } $employeeResponse = Invoke-TANSSRequest @invokeParam if ($employeeResponse) { Push-DataToCacheRunspace -MetaData $employeeResponse.meta foreach ($employeeItem in $employeeResponse.content) { Write-PSFMessage -Level Debug -Message "Found '$($employeeItem.Name)' with id $($employeeItem.id)" # Output data [TANSS.Employee]@{ BaseObject = $employeeItem Id = $employeeItem.id } } } else { Stop-PSFFunction -Message "Unexpected error searching '$($employeeResponse.content.name)' with ID '$($technician.id)'. TANSS is unable to find details of employee" -EnableException $true -Cmdlet $pscmdlet } } } } else { Write-PSFMessage -Level Warning -Message "No technicians found." -Tag "Technician" } } end { } } function New-TANSSEmployee { <# .Synopsis New-TANSSEmployee .DESCRIPTION Create a new employee in TANSS .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE New-TANSSEmployee -Name "User, Test" Create a new employee (as technician) in your own company .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "Userfriendly", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Employee])] param ( # Fullname of the employee [Parameter( ParameterSetName = "ApiNative", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Parameter( ParameterSetName = "Userfriendly", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias("Fullname", "Displayname")] [string] $Name, # first name of the employee [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("Givenname")] [string] $FirstName, # Last name of the employee [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("Surname")] [string] $LastName, # Id of the salutation for this employee [Parameter(ParameterSetName = "ApiNative")] [Alias("IdSalutation")] [Int] $SalutationId = 0, # Id of the department which tis employee is assigned to [Parameter(ParameterSetName = "ApiNative")] [Alias("IdDepartment")] [Int] $DepartmentId, # Name of the department which tis employee is assigned to [Parameter(ParameterSetName = "Userfriendly")] [string] $Department, # location / room of the employee [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("Location")] [string] $Room, # Main telephone number [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("TelephoneNumber")] [string] $Phone, # e-Mail address [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("EmailAddress")] [string] $Email, # if this employee is assigned to a specific car, the id goes here [Parameter(ParameterSetName = "ApiNative")] [Alias("IdCar")] $CarId = 0, # mobile telephone number [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("MobilePhone")] [string] $Mobile, # initials for this employee [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [string] $Initials, # Working hour model for this employee [Parameter(ParameterSetName = "ApiNative")] [Alias("IdWorkingHourModel")] [int] $WorkingHourModelId = 0, # Id of the accounting type for this employee [Parameter(ParameterSetName = "ApiNative")] [Alias("IdAccountingType")] [int] $accountingTypeId = 0, # Private telephone number [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("PrivatePhoneNumber")] [string] $PrivateNumber, # True if the employee is active [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("Active")] [bool] $IsActive = $true, # Identification number in foreign ERP system [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [string] $ERPNumber, # Fax number [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("PersonalFaxNumber")] [string] $Fax, # Role for this employee [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [string] $Role, # if the employee uses a title, the id goes here [Parameter(ParameterSetName = "ApiNative")] [Alias("IdTitle")] [int] $TitleId = 0, # Language which this employee uses [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [string] $Language, # Second telephone number [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("TelephoneNumberTwo")] [string] $Phone2, # second mobile telephone number [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("MobileNumberTwo")] [string] $Mobile2, # Employee birthday date [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [Alias("BirthdayDate", "DateBirthday", "DateOfBirth")] [datetime] $Birthday, # Company id of the ticket. Name is stored in the "linked entities" - "companies". Can only be set if the user has access to the company [Parameter(ParameterSetName = "ApiNative")] [Alias("CompanyAssignments", "IdCompany")] [int[]] $CompanyId, # Company name where the ticket should create for. Can only be set if the user has access to the company [Parameter(ParameterSetName = "Userfriendly")] [Alias("Company")] [String[]] $CompanyName, [Parameter(ParameterSetName = "ApiNative")] [Parameter(ParameterSetName = "Userfriendly")] [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning $apiPath = Format-ApiPath -Path "api/v1/employees" if ($Department) { $DepartmentId = ConvertFrom-NameCache -Name $Department -Type "Departments" if (-not $DepartmentId) { Write-PSFMessage -Level Warning -Message "No Id for department '$($Department)' found. Employee will be created with blank value on departmentId" #todo implement API call for departments $DepartmentId = 0 } } if ($CompanyName) { $CompanyId = foreach ($companyItem in $CompanyName) { $_id = ConvertFrom-NameCache -Name $companyItem -Type Companies if (-not $_id) { Write-PSFMessage -Level Warning -Message "No Id for company '$($companyItem)' found. Employee will be created without assignment to this company" } else { $_id } } Remove-Variable -Name _id -Force -Confirm:$false -WhatIf:$false -Verbose:$false -Debug:$false -ErrorAction Ignore -WarningAction Ignore } if (-not $CompanyId) { $_name = ConvertFrom-NameCache -Id 100000 -Type "Companies" Write-PSFMessage -Level Important -Message "No company specified. Employee will be created within your own company $(if($_name) { "($($_name)) "})as a technician" $CompanyId = 100000 Remove-Variable -Name _name -Force -Confirm:$false -WhatIf:$false -Verbose:$false -Debug:$false -ErrorAction Ignore -WarningAction Ignore } } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "Userfriendly" -and (-not $Name)) { Write-PSFMessage -Level Error -Message "No name specified" continue } #region rest call prepare if ($Birthday) { $_birthday = Get-Date -Date $Birthday -Format "yyyy-MM-dd" } else { $_birthday = "0000-00-00" } [array]$_companies = foreach ($CompanyIdItem in $CompanyId) { @{ "companyId" = $CompanyIdItem } } if (-not $LastName) { $nameParts = $Name.split(",").Trim() if ($nameParts.Count -eq 2) { # Assuming schema "<Lastname>, <Firstname>" $LastName = $nameParts[0] } elseif ($nameParts.Count -eq 1) { $nameParts = $Name.split(" ").Trim() if ($nameParts.Count -eq 2) { # Assuming schema "<Firstname> <Lastname>" $LastName = $nameParts[1] } else { $LastName = $Name } } else { $LastName = $Name } } Remove-Variable -Name nameParts -Force -Confirm:$false -WhatIf:$false -Verbose:$false -Debug:$false -ErrorAction Ignore -WarningAction Ignore if (-not $FirstName) { $nameParts = $Name.split(",").Trim() if ($nameParts.Count -eq 2) { # Assuming schema "<Lastname>, <Firstname>" $FirstName = $nameParts[1] } elseif ($nameParts.Count -eq 1) { $nameParts = $Name.split(" ").Trim() if ($nameParts.Count -eq 2) { # Assuming schema "<Firstname> <Lastname>" $FirstName = $nameParts[0] } else { $FirstName = "" } } else { $FirstName = "" } } Remove-Variable -Name nameParts -Force -Confirm:$false -WhatIf:$false -Verbose:$false -Debug:$false -ErrorAction Ignore -WarningAction Ignore if (-not $Initials -and $FirstName -and $LastName) { $_initials = "$(([string]$FirstName)[0])$(([string]$LastName)[0])" } else { $_initials = $Initials } $body = [ordered]@{ "id" = 0 "name" = "$Name" "firstName" = "$FirstName" "lastName" = "$LastName" "salutationId" = $SalutationId "departmentId" = $DepartmentId "room" = "$Room" "telephoneNumber" = "$Phone" "emailAddress" = "$Email" "carId" = $CarId "mobilePhone" = "$Mobile" "initials" = "$_initials" "workingHourModelId" = $WorkingHourModelId "accountingTypeId" = $accountingTypeId "privatePhoneNumber" = "$PrivateNumber" "active" = $IsActive "erpNumber" = "$ERPNumber" "personalFaxNumber" = "$Fax" "role" = "$Role" "titleId" = $TitleId "language" = "$Language" "telephoneNumberTwo" = "$Phone2" "mobileNumberTwo" = "$Mobile2" "birthday" = "$_birthday" "companyAssignments" = $_companies } #endregion rest call prepare if ($pscmdlet.ShouldProcess("Employee '$($Name)' on companyID '$([string]::Join(", ", $CompanyId))'", "New")) { Write-PSFMessage -Level Verbose -Message "Creating new employee '$($Name)' on companyID '$([string]::Join(", ", $CompanyId))'" -Tag "Employee" -Data $body $response = Invoke-TANSSRequest -Type POST -ApiPath $apiPath -Body $body -Token $Token if ($response) { Write-PSFMessage -Level Verbose -Message "API Response: $($response.meta.text)" Push-DataToCacheRunspace -MetaData $response.meta [TANSS.Employee]@{ BaseObject = $response.content Id = $response.content.id } } else { Write-PSFMessage -Level Error -Message "Error creating employee, no response from API" } } } end { } } function Get-TANSSProject { <# .Synopsis Get-TANSSProject .DESCRIPTION Get all projects from TANSS .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSProject Get all projects from TANSS .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidMultipleTypeAttributes", "")] [CmdletBinding( SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] [OutputType([TANSS.Ticket])] param ( [TANSS.Connection] $Token ) begin { try { $outBuffer = $null if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) { $PSBoundParameters['OutBuffer'] = 1 } $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Get-TANSSTicket', [System.Management.Automation.CommandTypes]::Function) $scriptCmd = {& $wrappedCmd -Project @PSBoundParameters } $steppablePipeline = $scriptCmd.GetSteppablePipeline() $steppablePipeline.Begin($PSCmdlet) } catch { throw } } process { try { $steppablePipeline.Process($_) } catch { throw } } end { try { $steppablePipeline.End() } catch { throw } } } function Get-TANSSProjectPhase { <# .Synopsis Get-TANSSProjectPhase .DESCRIPTION Get phases of a project in TANSS .PARAMETER ProjectID The ID of the poject to receive phases from .PARAMETER Project TANSS.Project object to receive phases from .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSProjectPhase -ProjectId 10 Get phases out of project 10 .EXAMPLE PS C:\> $projects | Get-TANSSTicketActivity Get all phases of projects in variable $tickets .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByProject", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] [OutputType([TANSS.ProjectPhase])] Param( [Parameter( ParameterSetName = "ByProjectId", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [Alias("Id")] [int[]] $ProjectID, [Parameter( ParameterSetName = "ByProject", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Project[]] $Project, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByProject") { $inputobjectProjectCount = ([array]$Project).Count Write-PSFMessage -Level System -Message "Getting IDs of $($inputobjectProjectCount) project$(if($inputobjectProjectCount -gt 1){'s'})" -Tag "ProjectPhase", "CollectInputObjects" [array]$ProjectID = $Project.id } foreach ($projectIdItem in $ProjectID) { Write-PSFMessage -Level Verbose -Message "Working on project ID $($projectIdItem)" -Tag "ProjectPhase", "Query" # build api path $apiPath = Format-ApiPath -Path "api/v1/projects/$projectIdItem/phases" # query content $response = Invoke-TANSSRequest -Type GET -ApiPath $apiPath -Token $Token Push-DataToCacheRunspace -MetaData $response.meta Write-PSFMessage -Level Verbose -Message "$($response.meta.text): Received $($response.meta.properties.extras.count) VacationEntitlement records in year $($Year)" -Tag "ProjectPhase", "Query" # create output foreach ($phase in $response.content) { # output object [TANSS.ProjectPhase]@{ BaseObject = $phase Id = $phase.id } # cache Lookup refresh [TANSS.Lookup]::Phases[$phase.id] = $phase.name } } } end {} } function New-TANSSProject { <# .Synopsis New-TANSSProject .DESCRIPTION Creates a project in TANSS, that can contain multiple tickets .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> New-TANSSProject -Title "A new project" Create a project with title "A new project" .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidMultipleTypeAttributes", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "")] [CmdletBinding( DefaultParameterSetName = "Userfriendly", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Ticket])] param ( # Company id of the ticket. Name is stored in the "linked entities" - "companies". Can only be set if the user has access to the company [Parameter(ParameterSetName="ApiNative")] [int] $CompanyId, # Company name where the ticket should create for. Can only be set if the user has access to the company [Parameter(ParameterSetName="Userfriendly")] [String] $Company, # If the ticket has a remitter, the id goes here. Name is stored in the "linked entities" - "employees" [Parameter(ParameterSetName="ApiNative")] [Alias('ClientId')] [int] $RemitterId, # If the ticket has a remitter/client, the name of the client [Parameter(ParameterSetName="Userfriendly")] [String] $Client, # gives infos about how the remitter gave the order. Infos are stored in the "linked entities" - "orderBys" [Parameter(ParameterSetName="ApiNative")] [int] $OrderById, # gives infos about how the Client gave the order. [Parameter(ParameterSetName="Userfriendly")] [string] $OrderBy, # The title / subject of the ticket [Parameter( ParameterSetName="Userfriendly", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Parameter( ParameterSetName="ApiNative", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string] $Title, # The content / description of the ticket [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('content')] [string] $Description, # External ticket id (optional) [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('extTicketId')] [string] $ExternalTicketId, # id of employee which ticket is assigned to. Name is stored in "linked entities" - "employees" [Parameter(ParameterSetName="ApiNative")] [Alias('assignedToEmployeeId')] [int] $EmployeeIdAssigned, # Name of the employee the ticket is assigned to [Parameter(ParameterSetName="Userfriendly")] [String] $EmployeeAssigned, # id of department the ticket is assigned to. Name is stored in "linked entities" - "departments" [Parameter(ParameterSetName="ApiNative")] [Alias('assignedToDepartmentId')] [int] $DepartmentIdAssigned, # Name of the department the ticket is assigned to [Parameter(ParameterSetName="Userfriendly")] [String] $Department, # id of the ticket state. Name is give in "linked entities" - "ticketStates" [Parameter(ParameterSetName="ApiNative")] [int] $StatusId, # The name of the ticket status [Parameter(ParameterSetName="Userfriendly")] [String] $Status, # id of the ticket type. Name is give in "linked entities" - "ticketTypes" [Parameter(ParameterSetName="ApiNative")] [int] $TypeId, # The name of the ticket type [Parameter(ParameterSetName="Userfriendly")] [String] $Type, # if ticket is assigned to device / employee, linktype is given here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('LinkTypeId')] [int] $AssignmentId, # If ticket has a deadline, the date is given here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('deadlineDate')] [datetime] $Deadline, # if true, this ticket is a "repair ticket" [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('repair')] [bool] $IsRepair = $false, # if ticket has a due date, the timestamp is given here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [datetime] $DueDate, # Determines the "attention" flag state of a ticket [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [ValidateSet("NO", "YES", "RESUBMISSION", "MAIL")] [string] $Attention = "NO", # If the ticket has an installation fee, this value is true [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [ValidateSet("NO", "YES", "NO_PROJECT_INSTALLATION_FEE")] [string] $InstallationFee = "NO", # Sets the installation fee drive mode. If it is set to NONE then the system config parameter "leistung.ip.fahrzeit_berechnen" will be used. If the company from the ticket has an installation fee drive mode set then that will be used instead of the system config parameter. [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [ValidateSet("NONE", "DRIVE_INCLUDED", "DRIVE_EXCLUDED")] [string] $InstallationFeeDriveMode = "NONE", #Amount for the installation fee [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $InstallationFeeAmount, # If true, the ticket shall be billed separately [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [bool] $SeparateBilling = $false, # if the ticket has a service cap, here the amount is given [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $ServiceCapAmount, # linkId of the relationship (if ticket has a relation) [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $RelationshipLinkId, # linkTypeId of the relationship (if ticket has a relation) [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $RelationshipLinkTypeId, # if the ticket as a resubmission date set, this is given here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [datetime] $ResubmissionDate, # If a resubmission text is set, this text is returned here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [string] $ResubmissionText, # Number of estimated minutes which is planned for the ticket [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $EstimatedMinutes, # Determines wether the ticket is assigned to a local ticket admin or not # NONE: "normal" ticket # LOCAL_ADMIN: ticket is assigned to a local ticket admin # TECHNICIAN: local ticket admin has forwarded the ticket to a technician [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [ValidateSet("NONE", "LOCAL_ADMIN", "TECHNICIAN")] [string] $LocalTicketAdminFlag = "NONE", # if the ticket is assigned to a local ticket admin, this represents the employee (local ticket admin) who is assigned for this ticket [Parameter(ParameterSetName="ApiNative")] [int] $LocalTicketAdminEmployeeId, # if the ticket is assigned to a local ticket admin, this represents the name of the employee (local ticket admin) who is assigned for this ticket [Parameter(ParameterSetName="Userfriendly")] [ValidateNotNullOrEmpty] [string] $EmployeeTicketAdmin, # Sets the order number [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [string] $OrderNumber, # If the ticket has a reminder set, the timestamp is returned here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [datetime] $Reminder, # When persisting a ticket, you can also send a list of tag assignments which will be assigned to the ticket [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [string[]] $Tags, [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [TANSS.Connection] $Token ) begin { try { $outBuffer = $null if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) { $PSBoundParameters['OutBuffer'] = 1 } $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('New-TANSSTicket', [System.Management.Automation.CommandTypes]::Function) $scriptCmd = {& $wrappedCmd -IsProject $true @PSBoundParameters } $steppablePipeline = $scriptCmd.GetSteppablePipeline() $steppablePipeline.Begin($PSCmdlet) } catch { throw } } process { try { $steppablePipeline.Process($_) } catch { throw } } end { try { $steppablePipeline.End() } catch { throw } } } function New-TANSSProjectPhase { <# .Synopsis Add a project phase into a project .DESCRIPTION Add a project phase into a project .PARAMETER ProjectID The ID of the poject where to create the specified phase .PARAMETER Project TANSS.Project object where to create the specified phase .PARAMETER Name The name of the phase .PARAMETER Rank The rank of the phase, when there are other phases in the project .PARAMETER StartDate The (planned) starting date of the phase .PARAMETER EndDate The (planned) ending date of the phase .PARAMETER RequiredPrePhasesComplete Indicates that all tickets in the previous phase has to be finished to open this phase Default: $false .PARAMETER BillingType Set the behavour how to bill tickets. Values are available via TabCompletion. Possible are: "InstantBillSupportActivities" = Support activities of sub-tickets are immediately billable "BillClosedTicketOnly" = Only Support activities of completed sub-tickets are billable "BillOnlyWhenAllTicketsClosed" = Phase may only be billed when all sub-tickets have been completed Default: "InstantBillSupportActivities" .PARAMETER ClearanceMode Set the behavour how support activities in tickets for the phase are treated. Values are available via TabCompletion. Possible are: "Default" = Setting from TANSS application base preferences is used "ReleaseSupportOfUnresolvedTickets" = support activities in open tickets can be released "LockSupportsOfUnresolvedTickets" = support activities in open tickets can not be released Default: "Default" .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> New-TANSSProjectPhase -Project $project -Name "Phase X" Creates "Phase X" within the project in the variable $project .EXAMPLE PS C:\> $project | New-TANSSProjectPhase -Name "Phase X" Creates "Phase X" within the project in the variable $project .EXAMPLE PS C:\> New-TANSSProjectPhase -ProjectId $project.id -Name "Phase X", "Phase Y", "Phase Z" Creates 3 phases ("Phase X", "Phase Y", "Phase Z") within the project in the variable $project .EXAMPLE PS C:\> "Phase X", "Phase Y", "Phase Z" | New-TANSSProjectPhase -ProjectId $project.id Creates 3 phases ("Phase X", "Phase Y", "Phase Z") within the project in the variable $project .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByProject", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.ProjectPhase])] Param( [Parameter( ParameterSetName = "ByPhaseName", Mandatory = $true )] [Alias("Id")] [int] $ProjectID, [Parameter( ParameterSetName = "ByProject", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Project] $Project, [Parameter( ValueFromPipeline = $true, Mandatory = $true )] [string[]] $Name, [int] $Rank, [datetime] $StartDate, [datetime] $EndDate, [bool] $RequiredPrePhasesComplete = $false, [ValidateSet("InstantBillSupportActivities", "BillClosedTicketOnly", "BillOnlyWhenAllTicketsClosed")] [string] $BillingType = "InstantBillSupportActivities", [ValidateSet("Default", "ReleaseSupportOfUnresolvedTickets", "LockSupportsOfUnresolvedTickets")] [String] $ClearanceMode = "Default", [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning $apiPath = Format-ApiPath -Path "api/v1/projects/phases" # Translate BillingType into api value if ($BillingType) { switch ($BillingType) { "InstantBillSupportActivities" { $_billingType = "DEFAULT" } "BillClosedTicketOnly" { $_billingType = "TICKET_MUST_BE_CLOSED" } "BillOnlyWhenAllTicketsClosed" { $_billingType = "ALL_TICKETS_MUST_BE_CLOSED" } Default { Stop-PSFFunction -Message "Unhandeled Value in BillingType. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } } # Translate BillingType into api value if ($ClearanceMode) { switch ($ClearanceMode) { "Default" { $_clearanceMode = "DEFAULT" } "ReleaseSupportOfUnresolvedTickets" { $_clearanceMode = "DONT_CLEAR_SUPPORTS" } "LockSupportsOfUnresolvedTickets" { $_clearanceMode = "MAY_CLEAR_SUPPORTS" } Default { Stop-PSFFunction -Message "Unhandeled Value in ClearanceMode. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } } } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByProject") { $ProjectID = $Project.id Write-PSFMessage -Level System -Message "Identified ID '$($ProjectID) for project $($Project.Title)" -Tag "ProjectPhase", "CollectInputObjects" } # Create body object for api call foreach ($nameItem in $Name) { Write-PSFMessage -Level Verbose -Message "Working new phase '$($nameItem)' for project ID $($ProjectID)" -Tag "ProjectPhase", "New" $phaseToCreate = [ordered]@{ projectId = $ProjectID name = $nameItem closedPrePhasesRequired = $RequiredPrePhasesComplete billingType = $_billingType clearanceMode = $_clearanceMode } if ($Rank) { $phaseToCreate.add("rank", $Rank) } if ($StartDate) { $_startDate = [int32][double]::Parse((Get-Date -Date $StartDate.ToUniversalTime() -UFormat %s)) $phaseToCreate.add("startDate", $_startDate) } if ($EndDate) { $_endDate = [int32][double]::Parse((Get-Date -Date $EndDate.ToUniversalTime() -UFormat %s)) $phaseToCreate.add("endDate", $_endDate) } # Create phase if ($pscmdlet.ShouldProcess("phase '$($nameItem)' in project id $($ProjectID)", "New")) { Write-PSFMessage -Level Verbose -Message "New phase '$($nameItem)' in project id $($ProjectID)" -Tag "ProjectPhase", "New" # invoke api call $response = Invoke-TANSSRequest -Type POST -ApiPath $apiPath -Body $phaseToCreate -Token $Token Write-PSFMessage -Level Verbose -Message "$($response.meta.text): $($response.content.name) (Rank: $($response.content.rank), Id: $($response.content.id))" -Tag "ProjectPhase", "New", "CreatedSuccessfully" # create output [TANSS.ProjectPhase]@{ BaseObject = $response.content Id = $response.content.id } # cache Lookup refresh [TANSS.Lookup]::Phases[$response.content.id] = $response.content.name } } } end {} } function Remove-TANSSProject { <# .Synopsis Remove-TANSSProject .DESCRIPTION Delete a project in TANSS .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Remove-TANSSProject -ID 100 Remove project with ticketID 100 from TANSS .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidMultipleTypeAttributes", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "")] [CmdletBinding( DefaultParameterSetName = 'ById', SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'High' )] [OutputType([TANSS.Ticket])] param ( # TANSS Ticket object to remove [Parameter( ParameterSetName = "ByInputObject", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [TANSS.Ticket[]] $InputObject, # Id of the ticket to remove [Parameter( ParameterSetName = "ById", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias("ProjectId", "Project","TicketId", "Ticket")] [int[]] $Id, [TANSS.Connection] $Token ) begin { try { $outBuffer = $null if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) { $PSBoundParameters['OutBuffer'] = 1 } $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Remove-TANSSTicket', [System.Management.Automation.CommandTypes]::Function) $scriptCmd = {& $wrappedCmd @PSBoundParameters } $steppablePipeline = $scriptCmd.GetSteppablePipeline() $steppablePipeline.Begin($PSCmdlet) } catch { throw } } process { try { $steppablePipeline.Process($_) } catch { throw } } end { try { $steppablePipeline.End() } catch { throw } } } function Remove-TANSSProjectPhase { <# .Synopsis Remove-TANSSProjectPhase .DESCRIPTION Removes a project phase from TANSS .PARAMETER InputObject TANSS.ProjectPhase object to remove .PARAMETER Force Process the removal quietly. .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> $phase | Remove-TANSSProjectPhase Remove project phase in variable $phase from TANSS .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'High' )] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias("Phase", "ProjectPhase")] [TANSS.ProjectPhase[]] $InputObject, [switch] $Force, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $processRemoval = $false foreach ($projectPhase in $InputObject) { # Check on Force parameter, otherwise process shouldprocess if ($Force) { $processRemoval = $true } else { if ($pscmdlet.ShouldProcess("ProjectPhase Id $($projectPhase.Id) '$($projectPhase.Name)' from project '$($projectPhase.Project)' (Id $($projectPhase.ProjectId))", "Remove")) { $processRemoval = $true } } if ($processRemoval) { Write-PSFMessage -Level Verbose -Message "Remove ProjectPhase Id $($projectPhase.Id) '$($projectPhase.Name)' from project '$($projectPhase.Project)' (Id $($projectPhase.ProjectId))" -Tag "ProjectPhase", "Remove" # Remove projectPhase $apiPath = Format-ApiPath -Path "api/v1/projects/phases/$($projectPhase.Id)" Invoke-TANSSRequest -Type DELETE -ApiPath $apiPath -Token $Token -Confirm:$false -ErrorVariable "invokeError" # cache Lookup refresh [TANSS.Lookup]::Phases.Remove($($projectPhase.Id)) } } } end {} } function Set-TANSSProjectPhase { <# .Synopsis Modify a phase inside project .DESCRIPTION Modify a phase inside project .PARAMETER Phase TANSS.ProjectPhase object to set .PARAMETER PhaseID The ID of the poject phase to set .PARAMETER Project TANSS.Project where to modify a phase .PARAMETER PhaseName The name of the phase to modify .PARAMETER Name The (new) name for the phase to set .PARAMETER Rank The order of the phase in relation to other project phases .PARAMETER StartDate The (planned) starting date of the phase .PARAMETER EndDate The (planned) ending date of the phase .PARAMETER RequiredPrePhasesComplete Indicates that all tickets in the previous phase has to be finished to open this phase Default: $false .PARAMETER BillingType Set the behavour how to bill tickets. Values are available via TabCompletion. Possible are: "InstantBillSupportActivities" = Support activities of sub-tickets are immediately billable "BillClosedTicketOnly" = Only Support activities of completed sub-tickets are billable "BillOnlyWhenAllTicketsClosed" = Phase may only be billed when all sub-tickets have been completed Default: "InstantBillSupportActivities" .PARAMETER ClearanceMode Set the behavour how support activities in tickets for the phase are treated. Values are available via TabCompletion. Possible are: "Default" = Setting from TANSS application base preferences is used "ReleaseSupportOfUnresolvedTickets" = support activities in open tickets can be released "LockSupportsOfUnresolvedTickets" = support activities in open tickets can not be released Default: "Default" .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Set-TANSSProjectPhase -PhaseID $phase.Id -Name "NewPhaseName X" Rename the phase from variable $phase to "NewPhaseName X" $Phase has to be filled with a .EXAMPLE PS C:\> $phase | Set-TANSSProjectPhase -Name "NewPhaseName X" Rename the phase from variable $phase to "NewPhaseName X" $Phase has to be filled with a .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByPhase", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.ProjectPhase])] Param( [Parameter( ParameterSetName = "ByPhaseId", ValueFromPipeline = $true, Mandatory = $true )] [Alias("Id")] [int] $PhaseID, [Parameter( ParameterSetName = "ByPhase", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.ProjectPhase] $Phase, [Parameter( ParameterSetName = "ByProject", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Ticket] $Project, [Parameter( ParameterSetName = "ByProject", Mandatory = $true )] [string] $PhaseName, [ValidateNotNullOrEmpty()] [Alias("NewName")] [string] $Name, [ValidateNotNullOrEmpty()] [int] $Rank, [ValidateNotNullOrEmpty()] [datetime] $StartDate, [ValidateNotNullOrEmpty()] [datetime] $EndDate, [bool] $RequiredPrePhasesComplete, [ValidateSet("InstantBillSupportActivities", "BillClosedTicketOnly", "BillOnlyWhenAllTicketsClosed")] [string] $BillingType, [ValidateSet("Default", "ReleaseSupportOfUnresolvedTickets", "LockSupportsOfUnresolvedTickets")] [String] $ClearanceMode, [switch] $PassThru, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning # Translate BillingType into api value if ($BillingType) { switch ($BillingType) { "InstantBillSupportActivities" { $_billingType = "DEFAULT" } "BillClosedTicketOnly" { $_billingType = "TICKET_MUST_BE_CLOSED" } "BillOnlyWhenAllTicketsClosed" { $_billingType = "ALL_TICKETS_MUST_BE_CLOSED" } Default { Stop-PSFFunction -Message "Unhandeled Value in BillingType. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } } # Translate BillingType into api value if ($ClearanceMode) { switch ($ClearanceMode) { "Default" { $_clearanceMode = "DEFAULT" } "ReleaseSupportOfUnresolvedTickets" { $_clearanceMode = "DONT_CLEAR_SUPPORTS" } "LockSupportsOfUnresolvedTickets" { $_clearanceMode = "MAY_CLEAR_SUPPORTS" } Default { Stop-PSFFunction -Message "Unhandeled Value in ClearanceMode. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } } } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" # ParameterSet handling if ($parameterSetName -like "ByPhase") { $PhaseID = $Phase.id $projectID = $Phase.ProjectId Write-PSFMessage -Level System -Message "Identified ID '$($PhaseID) for project phase $($Phase.Name) within project '$($Phase.Project)' (Id: $($projectID))" -Tag "ProjectPhase", "CollectInputObjects" } if ($parameterSetName -like "ByProject") { $projectID = $Project.Id $Phase = Get-TANSSProjectPhase -ProjectID $Project.Id -Token $Token | Where-Object Name -Like $PhaseName if (-not $Phase) { Write-PSFMessage -Level Error -Message "Phase '$($PhaseName)' not found in project '$($Project.Title)' (Id: $($Project.Id))" -Tag "ProjectPhase", "CollectInputObjects" -Data @{"Project" = $Project } continue } $PhaseID = $Phase.Id Write-PSFMessage -Level System -Message "Identified ID '$($PhaseID) for project phase $($Phase.Name) within project $($Phase.Project)" -Tag "ProjectPhase", "CollectInputObjects" } # Create body object for api call Write-PSFMessage -Level Verbose -Message "Going to set phase ID $($PhaseID)" -Tag "ProjectPhase", "Set" $paramFormatApiPath = @{ "Path" = "api/v1/projects/phases/$($PhaseID)" } $paramFormatApiPathQueryParameter = @{} $phaseToSet = [ordered]@{ Id = $PhaseID #projectId = $ProjectID } if ($ProjectID) { $phaseToSet.add("projectId", $ProjectID) } if ($Name) { $phaseToSet.add("name", $Name) } if ($RequiredPrePhasesComplete) { $phaseToSet.add("closedPrePhasesRequired", $RequiredPrePhasesComplete) } if ($BillingType) { $phaseToSet.add("billingType", $_billingType) } if ($ClearanceMode) { $phaseToSet.add("clearanceMode", $_clearanceMode) } if ($Rank) { $phaseToSet.add("rank", $Rank) } if ($StartDate) { $_startDate = [int32][double]::Parse((Get-Date -Date $StartDate.ToUniversalTime() -UFormat %s)) $phaseToSet.add("startDate", $_startDate) $paramFormatApiPathQueryParameter["adjustStart"] = $true $paramFormatApiPathQueryParameter["adjustEnd"] = $true } if ($EndDate) { $_endDate = [int32][double]::Parse((Get-Date -Date $EndDate.ToUniversalTime() -UFormat %s)) $phaseToSet.add("endDate", $_endDate) $paramFormatApiPathQueryParameter["adjustStart"] = $true $paramFormatApiPathQueryParameter["adjustEnd"] = $true } if ($paramFormatApiPathQueryParameter["adjustStart"] -or $paramFormatApiPathQueryParameter["adjustEnd"]) { $paramFormatApiPath.Add("QueryParameter", $paramFormatApiPathQueryParameter) } $apiPath = Format-ApiPath @paramFormatApiPath # Create phase $response = Invoke-TANSSRequest -Type PUT -ApiPath $apiPath -Body $phaseToSet -Token $Token Write-PSFMessage -Level Verbose -Message "$($response.meta.text): $($response.content.adjustedPhases.name) (Rank: $($response.content.adjustedPhases.rank), Id: $($response.content.adjustedPhases.id))" -Tag "ProjectPhase", "Set", "Modify" # create output i($PassThru) { foreach($_phase in $response.content.adjustedPhases) { # object [TANSS.ProjectPhase]@{ BaseObject = $_phase Id = $_phase.id } # cache Lookup refresh [TANSS.Lookup]::Phases[$_phase.id] = $_phase.name } } } end { $null = Get-TANSSProject -Token $Token } } function Get-TANSSTicket { <# .Synopsis Get-TANSSTicket .DESCRIPTION Gat a ticket from TANSS service .PARAMETER Id The ticket Id (one or more) to query .PARAMETER CompanyId Get all tickets of company Id .PARAMETER MyTickets Get all tickets assigned to the authenticated account .PARAMETER NotAssigned Get all tickets not assigned to somebody .PARAMETER AllTechnician Get all tickets assigned to somebody .PARAMETER RepairTickets Get tickets marked as repair tickets .PARAMETER NotIdentified Get all unidentified tickets .PARAMETER Project Get tickets marked as a project .PARAMETER LocalTicketAdmin Get all tickets specified for a ticket admin .PARAMETER TicketWithTechnicianRole Get all tickets with a technician role .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTicket Get all tickets assinged to the authenticated user .EXAMPLE PS C:\> Get-TANSSTicket -Id 100 Get ticket with Id 100 .EXAMPLE PS C:\> Get-TANSSTicket -CompanyId 12345 Get all tickets of company Id 12345 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")] [CmdletBinding( DefaultParameterSetName = 'MyTickets', SupportsShouldProcess = $false, ConfirmImpact = 'Low' )] [OutputType([TANSS.Ticket], [TANSS.Project])] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "TicketId" )] [int[]] $Id, [Parameter( Mandatory = $true, ValueFromPipeline = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = "CompanyId" )] [int[]] $CompanyId, [Parameter( Mandatory = $false, ParameterSetName = "MyTickets" )] [Alias("Own", "OwnTickets", "MyOwn", "NyOwnTickets")] [switch] $MyTickets, [Parameter( Mandatory = $true, ParameterSetName = "NotAssigned" )] [Alias("General", "GeneralTickets")] [switch] $NotAssigned, [Parameter( Mandatory = $true, ParameterSetName = "AllTechnician" )] [Alias("TicketsAllTechnicians", "Assigned", "AssignedTickets")] [switch] $AllTechnician, [Parameter( Mandatory = $true, ParameterSetName = "RepairTickets" )] [switch] $RepairTickets, [Parameter( Mandatory = $true, ParameterSetName = "NotIdentified" )] [switch] $NotIdentified, [Parameter( Mandatory = $true, ParameterSetName = "Projects" )] [switch] [Alias("AllProjects")] $Project, [Parameter( Mandatory = $true, ParameterSetName = "LocalTicketAdmin" )] [Alias("AssignedToTicketAdmin")] [switch] $LocalTicketAdmin, [Parameter( Mandatory = $true, ParameterSetName = "TicketWithTechnicianRole" )] [switch] $TicketWithTechnicianRole, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" $response = @() # Construct query switch ($parameterSetName) { "TicketId" { # in case of "Query by Id" -> Do the query now $response += foreach ($ticketId in $Id) { Invoke-TANSSRequest -Type GET -ApiPath "api/v1/tickets/$($ticketId)" -Token $Token } } "CompanyId" { # in case of "Query by CompanyId" -> Do the query now $response += foreach ($_companyId in $CompanyId) { Invoke-TANSSRequest -Type GET -ApiPath "api/v1/tickets/company/$($_companyId)" -Token $Token } } "MyTickets" { $apiPath = Format-ApiPath -Path "api/v1/tickets/own" } "NotAssigned" { $apiPath = Format-ApiPath -Path "api/v1/tickets/general" } "AllTechnician" { $apiPath = Format-ApiPath -Path "api/v1/tickets/technician" } "RepairTickets" { $apiPath = Format-ApiPath -Path "api/v1/tickets/repair" } "NotIdentified" { $apiPath = Format-ApiPath -Path "api/v1/tickets/notIdentified" } "Projects" { $apiPath = Format-ApiPath -Path "api/v1/tickets/projects" } "LocalTicketAdmin" { $apiPath = Format-ApiPath -Path "api/v1/tickets/localAdminOverview" } "TicketWithTechnicianRole" { $apiPath = Format-ApiPath -Path "api/v1/tickets/withRole" } Default { Stop-PSFFunction -Message "Unhandeled ParameterSetName. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } # Do the constructed query, as long, as variable apiPath has a value if ($apiPath) { $response += Invoke-TANSSRequest -Type GET -ApiPath $apiPath -Token $Token } if ($response) { Write-PSFMessage -Level Verbose -Message "Found $(($response.content).count) tickets" # Push meta to cache runspace foreach ($responseItem in $response) { Push-DataToCacheRunspace -MetaData $responseItem.meta # Output result foreach($ticket in $responseItem.content) { if($parameterSetName -like "Projects") { [TANSS.Project]@{ BaseObject = $ticket Id = $ticket.id } } else { [TANSS.Ticket]@{ BaseObject = $ticket Id = $ticket.id } } } } } else { Write-PSFMessage -Level Warning -Message "No tickets found." -Tag "Ticket" } } end { } } function Get-TANSSTicketActivity { <# .Synopsis Get-TANSSTicketActivity .DESCRIPTION Retreive support activities within a ticket .PARAMETER TicketID The ID of the ticket to receive activities of .PARAMETER Ticket TANSS.Ticket object to receive activities of .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTicketActivity -TicketID 555 Get all support activities from ticket 555 .EXAMPLE PS C:\> $tickets | Get-TANSSTicketActivity Get all support activities from all tickets from variable $tickets .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByTicketId", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [Parameter( ParameterSetName = "ByTicketId", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [int[]] $TicketID, [Parameter( ParameterSetName = "ByTicket", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Ticket[]] $Ticket, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByTicket") { $inputobjectTicketCount = ([array]$Ticket).Count Write-PSFMessage -Level System -Message "Getting IDs of $($inputobjectTicketCount) ticket$(if($inputobjectTicketCount -gt 1){'s'})" -Tag "TicketComment", "CollectInputObjects" [array]$TicketID = $Ticket.id } foreach ($ticketIdItem in $TicketID) { Write-PSFMessage -Level Verbose -Message "Working on ticket ID $($ticketIdItem)" -Tag "TicketComment", "Query" Get-TANSSTicketContent -TicketID $ticketIdItem -Type "Activity" -Token $Token | Select-Object -ExpandProperty Object } } end { } } function Get-TANSSTicketComment { <# .Synopsis Get-TANSSTicketComment .DESCRIPTION Retreive the ticket comments .PARAMETER TicketID The ID of the ticket to receive comments of .PARAMETER Ticket TANSS.Ticket object to receive comments of .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTicketComment -TicketID 555 Get all comments from ticket 555 .EXAMPLE PS C:\> $tickets | Get-TANSSTicketComment Get all comments from all tickets from variable $tickets .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByTicketId", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [Parameter( ParameterSetName = "ByTicketId", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [int[]] $TicketID, [Parameter( ParameterSetName = "ByTicket", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Ticket[]] $Ticket, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByTicket") { $inputobjectTicketCount = ([array]$Ticket).Count Write-PSFMessage -Level System -Message "Getting IDs of $($inputobjectTicketCount) ticket$(if($inputobjectTicketCount -gt 1){'s'})" -Tag "TicketComment", "CollectInputObjects" [array]$TicketID = $Ticket.id } foreach ($ticketIdItem in $TicketID) { Write-PSFMessage -Level Verbose -Message "Working on ticket ID $($ticketIdItem)" -Tag "TicketComment", "Query" Get-TANSSTicketContent -TicketID $ticketIdItem -Type "Comment" -Token $Token | Select-Object -ExpandProperty Object } } end { } } function Get-TANSSTicketContent { <# .Synopsis Get-TANSSTicketContent .DESCRIPTION Retreive the various entries from a ticket. Entries can be a comment, activity, mail, document, image .PARAMETER TicketID The ID of the ticket to receive comments of .PARAMETER Ticket TANSS.Ticket object to receive comments of .PARAMETER Type Specifies the type of content you want to get Available types: "All" = everthing within the ticket "Comment" = only comments within the ticket "Activity" = only activites within the ticket "Mail" = = only mails within the ticket "Document" = uploaded documents within the ticket "Image" = uploaded images within the ticket .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTicketContent -TicketID 555 Get everthing out of ticket 555 .EXAMPLE PS C:\> $tickets | Get-TANSSTicketContent -Type "Mail" Get only malis out of all tickets from variable $tickets .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByTicketId", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [Parameter( ParameterSetName = "ByTicketId", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [int[]] $TicketID, [Parameter( ParameterSetName = "ByTicket", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Ticket[]] $Ticket, [ValidateNotNullOrEmpty()] [ValidateSet("All", "Comment", "Activity", "Mail", "Document", "Image")] [string[]] $Type = "All", [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByTicket") { $inputobjectTicketCount = ([array]$Ticket).Count Write-PSFMessage -Level System -Message "Getting IDs of $($inputobjectTicketCount) ticket$(if($inputobjectTicketCount -gt 1){'s'})" -Tag "TicketContent", "CollectInputObjects" [array]$TicketID = $Ticket.id } foreach ($ticketIdItem in $TicketID) { Write-PSFMessage -Level Verbose -Message "Working on ticket ID $($ticketIdItem)" -Tag "TicketContent", "Query" $content = @() # Get documents, if included in Type filter if ( ($Type | Where-Object { $_ -in @("All", "Document") }) ) { Write-PSFMessage -Level Verbose -Message "Getting documents from ticket $($ticketIdItem)" -Tag "TicketContent", "Query", "QueryDocuments" $apiPath = Format-ApiPath -Path "api/v1/tickets/$ticketIdItem/documents" $response = Invoke-TANSSRequest -Type GET -ApiPath $apiPath -Token $Token Push-DataToCacheRunspace -MetaData $response.meta if ($response.content) { Write-PSFMessage -Level Verbose -Message "Found $($response.content.count) documents" -Tag "TicketContent", "Query", "QueryDocuments" $content += foreach ($document in $response.content) { # create output objects, but first query download uri # build api path $apiPath = Format-ApiPath -Path "api/v1/tickets/$ticketIdItem/documents/$($document.id)" # query download uri $responseDocumentUri = Invoke-TANSSRequest -Type GET -ApiPath $apiPath -Token $Token # create output $object = [TANSS.TicketDocument]@{ BaseObject = $document Id = $document.id } if ($responseDocumentUri.content) { $object.Key = $responseDocumentUri.content.key $object.DownloadUri = Format-ApiPath -Path $responseDocumentUri.content.url } [TANSS.TicketContent]@{ TicketId = $object.TicketId Type = "Document" Id = $object.Id Date = $object.Date Text = $object.Description Object = $object } } } else { Write-PSFMessage -Level Verbose -Message "No documents found" -Tag "TicketContent", "Query", "QueryDocuments" } } # Get images, if included in Type filter if ( ($Type | Where-Object { $_ -in @("All", "Image") }) ) { Write-PSFMessage -Level Verbose -Message "Getting images from ticket $($ticketIdItem)" -Tag "TicketContent", "Query", "QueryImages" $apiPath = Format-ApiPath -Path "api/v1/tickets/$ticketIdItem/screenshots" $response = Invoke-TANSSRequest -Type GET -ApiPath $apiPath -Token $Token Push-DataToCacheRunspace -MetaData $response.meta if ($response.content) { Write-PSFMessage -Level Verbose -Message "Found $($response.content.count) images" -Tag "TicketContent", "Query", "QueryImages" $content += foreach ($image in $response.content) { $object = [TANSS.TicketImage]@{ BaseObject = $image Id = $image.id } [TANSS.TicketContent]@{ TicketId = $object.TicketId Type = "Image" Id = $object.Id Date = $object.Date Text = $object.Description Object = $object } } } else { Write-PSFMessage -Level Verbose -Message "No images found" -Tag "TicketContent", "Query", "QueryImages" } } # Get Comments, Activities, Mails if ( ($Type | Where-Object { $_ -in @("All", "Comment", "Activity", "Mail") }) ) { Write-PSFMessage -Level Verbose -Message "Getting comments, mails and activities from ticket $($ticketIdItem)" -Tag "TicketContent", "Query", "QueryHistory" $apiPath = Format-ApiPath -Path "api/v1/tickets/history/$ticketIdItem" $response = Invoke-TANSSRequest -Type GET -ApiPath "backend/api/v1/tickets/history/$ticketID" -Token $Token Push-DataToCacheRunspace -MetaData $response.meta if ($response.content) { Write-PSFMessage -Level Verbose -Message "Found content in ticket $($ticketIdItem), going to parse content" -Tag "TicketContent", "Query", "QueryHistory" # Get comments if ( ($Type | Where-Object { $_ -in @("All", "Comment") }) ) { Write-PSFMessage -Level Verbose -Message "Working through $($response.content.comments.count) comment$(if($response.content.comments.count -gt 1) {'s'})" -Tag "TicketContent", "Query", "QueryHistory", "Comment" $content += foreach ($comment in $response.content.comments) { $object = [TANSS.TicketComment]@{ BaseObject = $comment ID = $comment.id TicketId = $ticketIdItem } [TANSS.TicketContent]@{ TicketId = $object.TicketId Type = "Comment" Id = $object.Id Date = $object.Date Text = $object.Description Object = $object } } } # Get activities if ( ($Type | Where-Object { $_ -in @("All", "Activity") }) ) { Write-PSFMessage -Level Verbose -Message "Working through $($response.content.supports.count) $(if($response.content.supports.count -gt 1) {'Activities'} else {'Activity'})" -Tag "TicketContent", "Query", "QueryHistory", "Activity" $content += foreach ($activity in $response.content.supports) { $object = [TANSS.TicketActivity]@{ BaseObject = $activity ID = $activity.id } [TANSS.TicketContent]@{ TicketId = $object.TicketId Type = "Activity" Id = $object.Id Date = $object.Date Text = $object.Description Object = $object } } } # Get mails if ( ($Type | Where-Object { $_ -in @("All", "Mail") }) ) { Write-PSFMessage -Level Verbose -Message "Working through $($response.content.mails.count) mail$(if($response.content.mails.count -gt 1) {'s'})" -Tag "TicketContent", "Query", "QueryHistory", "Mail" $content += foreach ($mail in $response.content.mails) { $object = [TANSS.TicketMail]@{ BaseObject = $mail ID = $mail.id TicketId = $ticketIdItem } [TANSS.TicketContent]@{ TicketId = $object.TicketId Type = "Mail" Id = $object.Id Date = $object.Date Text = $object.Subject Object = $object } #> } } } else { $_type = $Type | Where-Object { $_ -notlike "All" } if ($_type) { $_type = [string]::Join(', ', [array]$_type) } else { $_type = [string]::Join(', ', @("Comment", "Activity", "Mail")) } Write-PSFMessage -Level Verbose -Message "No $_type data found" -Tag "TicketContent", "Query", "QueryHistory" } } # Output result if($content) { Write-PSFMessage -Level Verbose -Message "Output $(([array]$content).count) content record$(if(([array]$content).count -gt 1){'s'}) from ticket $($ticketIdItem)" -Tag "TicketContent", "Query", "OutputResult" $content | Sort-Object Date } else { Write-PSFMessage -Level Significant -Message "No $(if($Type -notlike "All") {'matching'}) content found in ticket $($ticketIdItem)" -Tag "TicketContent", "Query", "OutputResult", "NoData" } } } end {} } function Get-TANSSTicketDocument { <# .Synopsis Get-TANSSTicketDocument .DESCRIPTION Retreive documents within a ticket .PARAMETER TicketID The ID of the ticket to receive documents of .PARAMETER Ticket TANSS.Ticket object to receive documents of .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTicketDocument -TicketID 555 Get all documents from ticket 555 .EXAMPLE PS C:\> $tickets | Get-TANSSTicketDocument Get all documents from all tickets from variable $tickets .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByTicketId", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [Parameter( ParameterSetName = "ByTicketId", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [int[]] $TicketID, [Parameter( ParameterSetName = "ByTicket", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Ticket[]] $Ticket, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByTicket") { $inputobjectTicketCount = ([array]$Ticket).Count Write-PSFMessage -Level System -Message "Getting IDs of $($inputobjectTicketCount) ticket$(if($inputobjectTicketCount -gt 1){'s'})" -Tag "TicketComment", "CollectInputObjects" [array]$TicketID = $Ticket.id } foreach ($ticketIdItem in $TicketID) { Write-PSFMessage -Level Verbose -Message "Working on ticket ID $($ticketIdItem)" -Tag "TicketComment", "Query" Get-TANSSTicketContent -TicketID $ticketIdItem -Type "Document" -Token $Token | Select-Object -ExpandProperty Object } } end { } } function Get-TANSSTicketImage { <# .Synopsis Get-TANSSTicketImage .DESCRIPTION Retreive images within a ticket .PARAMETER TicketID The ID of the ticket to receive images of .PARAMETER Ticket TANSS.Ticket object to receive images of .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTicketImage -TicketID 555 Get all images from ticket 555 .EXAMPLE PS C:\> $tickets | Get-TANSSTicketImage Get all images from all tickets from variable $tickets .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByTicketId", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [Parameter( ParameterSetName = "ByTicketId", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [int[]] $TicketID, [Parameter( ParameterSetName = "ByTicket", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Ticket[]] $Ticket, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByTicket") { $inputobjectTicketCount = ([array]$Ticket).Count Write-PSFMessage -Level System -Message "Getting IDs of $($inputobjectTicketCount) ticket$(if($inputobjectTicketCount -gt 1){'s'})" -Tag "TicketComment", "CollectInputObjects" [array]$TicketID = $Ticket.id } foreach ($ticketIdItem in $TicketID) { Write-PSFMessage -Level Verbose -Message "Working on ticket ID $($ticketIdItem)" -Tag "TicketComment", "Query" Get-TANSSTicketContent -TicketID $ticketIdItem -Type "Image" -Token $Token | Select-Object -ExpandProperty Object } } end { } } function Get-TANSSTicketMail { <# .Synopsis Get-TANSSTicketMail .DESCRIPTION Retreive mail objects within a ticket .PARAMETER TicketID The ID of the ticket to receive mails of .PARAMETER Ticket TANSS.Ticket object to receive mails of .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTicketMail -TicketID 555 Get all mails from ticket 555 .EXAMPLE PS C:\> $tickets | Get-TANSSTicketMail Get all mails from all tickets from variable $tickets .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByTicketId", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [Parameter( ParameterSetName = "ByTicketId", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [int[]] $TicketID, [Parameter( ParameterSetName = "ByTicket", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Ticket[]] $Ticket, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByTicket") { $inputobjectTicketCount = ([array]$Ticket).Count Write-PSFMessage -Level System -Message "Getting IDs of $($inputobjectTicketCount) ticket$(if($inputobjectTicketCount -gt 1){'s'})" -Tag "TicketComment", "CollectInputObjects" [array]$TicketID = $Ticket.id } foreach ($ticketIdItem in $TicketID) { Write-PSFMessage -Level Verbose -Message "Working on ticket ID $($ticketIdItem)" -Tag "TicketComment", "Query" Get-TANSSTicketContent -TicketID $ticketIdItem -Type "Mail" -Token $Token | Select-Object -ExpandProperty Object } } end { } } function Get-TANSSTicketStatus { <# .Synopsis Get-TANSSTicketStatus .DESCRIPTION Get the various status types of a ticket from tanss .PARAMETER Id The Id of the status type to get .PARAMETER Name The name of the status type to get .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTicketStatus Get the available status types of a ticket .EXAMPLE PS C:\> Get-TANSSTicketStatus -Id 2 Get the status types with Id 2 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "All", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] [OutputType([TANSS.TicketStatus])] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "ById" )] [int[]] $Id, [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "ByName" )] [string[]] $Name, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning $apiPath = Format-ApiPath -Path "api/v1/tickets/status" $ticketStates = Invoke-TANSSRequest -Type GET -ApiPath $apiPath -Token $Token | Select-Object -ExpandProperty content [array]$filteredTicketStates = @() } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" switch ($parameterSetName) { "ById" { foreach ($item in $Id) { $filteredTicketStates += $ticketStates | Where-Object id -eq $item } } "ByName" { foreach ($item in $Name) { $filteredTicketStates += $ticketStates | Where-Object name -like $item } } "All" { $filteredTicketStates = $ticketStates } Default { Stop-PSFFunction -Message "Unhandled ParameterSet '$($parameterSetName)', developers mistake" -EnableException $true -Cmdlet $pscmdlet -Tag "TicketStatus", "SwitchException", "ParameterSet" } } } end { $filteredTicketStates = $filteredTicketStates | Sort-Object rank, id -Unique Write-PSFMessage -Level Verbose -Message "Going to return $($filteredTicketStates.count) ticket status" -Tag "TicketStatus", "Output" foreach ($ticketStatus in $filteredTicketStates) { Write-PSFMessage -Level System -Message "Working on ticketstatus '$($ticketStatus.name)' with id '$($ticketStatus.id)'" -Tag "TicketStatus" # put id and name to cache lookups Update-CacheLookup -LookupName "TicketStates" -Id $ticketStatus.Id -Name $ticketStatus.Name # output result [TANSS.TicketStatus]@{ Baseobject = $ticketStatus Id = $ticketStatus.id } } } } function Get-TANSSTicketType { <# .Synopsis Get-TANSSTicketType .DESCRIPTION Get the various types of a ticket from tanss .PARAMETER Id The Id of the ticket type to get .PARAMETER Name The name of the ticket type to get .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSTicketType Get the available ticket types .EXAMPLE PS C:\> Get-TANSSTicketType -Id 2 Get the tiket types with Id 2 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "All", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] [OutputType([TANSS.TicketType])] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "ById" )] [int[]] $Id, [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = "ByName" )] [string[]] $Name, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning $apiPath = Format-ApiPath -Path "api/v1/tickets/types" $ticketTypes = Invoke-TANSSRequest -Type GET -ApiPath $apiPath -Token $Token | Select-Object -ExpandProperty content [array]$filteredTicketTypes = @() } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" switch ($parameterSetName) { "ById" { foreach ($item in $Id) { $filteredTicketTypes += $ticketTypes | Where-Object id -eq $item } } "ByName" { foreach ($item in $Name) { $filteredTicketTypes += $ticketTypes | Where-Object name -like $item } } "All" { $filteredTicketTypes = $ticketTypes } Default { Stop-PSFFunction -Message "Unhandled ParameterSet '$($parameterSetName)', developers mistake" -EnableException $true -Cmdlet $pscmdlet -Tag "TicketType", "SwitchException", "ParameterSet" } } } end { $filteredTicketTypes = $filteredTicketTypes | Sort-Object Name, id -Unique Write-PSFMessage -Level Verbose -Message "Going to return $($filteredTicketTypes.count) ticket status" -Tag "TicketType", "Output" foreach ($ticketType in $filteredTicketTypes) { Write-PSFMessage -Level System -Message "Working on TicketType '$($ticketType.name)' with id '$($ticketType.id)'" -Tag "TicketType" # put id and name to cache lookups Update-CacheLookup -LookupName "TicketTypes" -Id $ticketType.Id -Name $ticketType.Name # output result [TANSS.TicketType]@{ Baseobject = $ticketType Id = $ticketType.id } } } } function New-TANSSTicket { <# .Synopsis New-TANSSTicket .DESCRIPTION Creates a ticket in the database .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> New-TANSSTicket -Title "A new Ticket" Create a ticket .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidMultipleTypeAttributes", "")] [CmdletBinding( DefaultParameterSetName = "Userfriendly", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Ticket])] param ( # Company id of the ticket. Name is stored in the "linked entities" - "companies". Can only be set if the user has access to the company [Parameter(ParameterSetName="ApiNative")] [int] $CompanyId, # Company name where the ticket should create for. Can only be set if the user has access to the company [Parameter(ParameterSetName="Userfriendly")] [String] $Company, # If the ticket has a remitter, the id goes here. Name is stored in the "linked entities" - "employees" [Parameter(ParameterSetName="ApiNative")] [Alias('ClientId')] [int] $RemitterId, # If the ticket has a remitter/client, the name of the client [Parameter(ParameterSetName="Userfriendly")] [String] $Client, # gives infos about how the remitter gave the order. Infos are stored in the "linked entities" - "orderBys" [Parameter(ParameterSetName="ApiNative")] [int] $OrderById, # gives infos about how the Client gave the order. [Parameter(ParameterSetName="Userfriendly")] [string] $OrderBy, # The title / subject of the ticket [Parameter( ParameterSetName="Userfriendly", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Parameter( ParameterSetName="ApiNative", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string] $Title, # The content / description of the ticket [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('content')] [string] $Description, # External ticket id (optional) [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('extTicketId')] [string] $ExternalTicketId, # id of employee which ticket is assigned to. Name is stored in "linked entities" - "employees" [Parameter(ParameterSetName="ApiNative")] [Alias('assignedToEmployeeId')] [int] $EmployeeIdAssigned, # Name of the employee the ticket is assigned to [Parameter(ParameterSetName="Userfriendly")] [String] $EmployeeAssigned, # id of department the ticket is assigned to. Name is stored in "linked entities" - "departments" [Parameter(ParameterSetName="ApiNative")] [Alias('assignedToDepartmentId')] [int] $DepartmentIdAssigned, # Name of the department the ticket is assigned to [Parameter(ParameterSetName="Userfriendly")] [String] $Department, # id of the ticket state. Name is give in "linked entities" - "ticketStates" [Parameter(ParameterSetName="ApiNative")] [int] $StatusId, # The name of the ticket status [Parameter(ParameterSetName="Userfriendly")] [String] $Status, # id of the ticket type. Name is give in "linked entities" - "ticketTypes" [Parameter(ParameterSetName="ApiNative")] [int] $TypeId, # The name of the ticket type [Parameter(ParameterSetName="Userfriendly")] [String] $Type, # if ticket is assigned to device / employee, linktype is given here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('LinkTypeId')] [int] $AssignmentId, # If ticket has a deadline, the date is given here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('deadlineDate')] [datetime] $Deadline, # if ticket is actually a project, this value is true [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('project')] [bool] $IsProject = $false, # if ticket is a sub-ticket of a project, the id of the project goes here. Name of the project is in the "linked entities" - "tickets" [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $ProjectId, # if the ticket is assignet to a project phase. The name of the phase is stored in the "linked entities" - "phases" [Parameter(ParameterSetName="ApiNative")] [Int] $PhaseId, # if the ticket is assignet to a project phase, the name of the phase [Parameter(ParameterSetName="Userfriendly")] [String] $Phase, # if true, this ticket is a "repair ticket" [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [Alias('repair')] [bool] $IsRepair = $false, # if ticket has a due date, the timestamp is given here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [datetime] $DueDate, # Determines the "attention" flag state of a ticket [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [ValidateSet("NO", "YES", "RESUBMISSION", "MAIL")] [string] $Attention = "NO", # If the ticket has an installation fee, this value is true [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [ValidateSet("NO", "YES", "NO_PROJECT_INSTALLATION_FEE")] [string] $InstallationFee = "NO", # Sets the installation fee drive mode. If it is set to NONE then the system config parameter "leistung.ip.fahrzeit_berechnen" will be used. If the company from the ticket has an installation fee drive mode set then that will be used instead of the system config parameter. [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [ValidateSet("NONE", "DRIVE_INCLUDED", "DRIVE_EXCLUDED")] [string] $InstallationFeeDriveMode = "NONE", #Amount for the installation fee [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $InstallationFeeAmount, # If true, the ticket shall be billed separately [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [bool] $SeparateBilling = $false, # if the ticket has a service cap, here the amount is given [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $ServiceCapAmount, # linkId of the relationship (if ticket has a relation) [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $RelationshipLinkId, # linkTypeId of the relationship (if ticket has a relation) [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $RelationshipLinkTypeId, # if the ticket as a resubmission date set, this is given here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [datetime] $ResubmissionDate, # If a resubmission text is set, this text is returned here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [string] $ResubmissionText, # Number of estimated minutes which is planned for the ticket [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [int] $EstimatedMinutes, # Determines wether the ticket is assigned to a local ticket admin or not # NONE: "normal" ticket # LOCAL_ADMIN: ticket is assigned to a local ticket admin # TECHNICIAN: local ticket admin has forwarded the ticket to a technician [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [ValidateSet("NONE", "LOCAL_ADMIN", "TECHNICIAN")] [string] $LocalTicketAdminFlag = "NONE", # if the ticket is assigned to a local ticket admin, this represents the employee (local ticket admin) who is assigned for this ticket [Parameter(ParameterSetName="ApiNative")] [int] $LocalTicketAdminEmployeeId, # if the ticket is assigned to a local ticket admin, this represents the name of the employee (local ticket admin) who is assigned for this ticket [Parameter(ParameterSetName="Userfriendly")] [ValidateNotNullOrEmpty] [string] $EmployeeTicketAdmin, # Sets the order number [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [string] $OrderNumber, # If the ticket has a reminder set, the timestamp is returned here [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [datetime] $Reminder, # When persisting a ticket, you can also send a list of tag assignments which will be assigned to the ticket [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [string[]] $Tags, [Parameter(ParameterSetName="ApiNative")] [Parameter(ParameterSetName="Userfriendly")] [TANSS.Connection] $Token ) begin { if(-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning $apiPath = Format-ApiPath -Path "api/v1/tickets" if($EmployeeTicketAdmin) { $LocalTicketAdminEmployeeId = ConvertFrom-NameCache -Name $EmployeeTicketAdmin -Type "Employees" if(-not $LocalTicketAdminEmployeeId) { Write-PSFMessage -Level Warning -Message "No Id for employee '$($EmployeeTicketAdmin)' found. Ticket will be created with blank value on TicketAdminEmployee" #todo implement API call for employee } } if($EmployeeAssigned) { $EmployeeIdAssigned = ConvertFrom-NameCache -Name $EmployeeAssigned -Type "Employees" if(-not $EmployeeIdAssigned) { Write-PSFMessage -Level Warning -Message "No Id for employee '$($EmployeeAssigned)' found. Ticket will be created with blank value on EmployeeIdAssigned" #todo implement API call for employee } } if($Client) { $RemitterId = ConvertFrom-NameCache -Name $Client -Type "Employees" if(-not $RemitterId) { Write-PSFMessage -Level Warning -Message "No Id for client '$($Client)' found. Ticket will be created with blank value on RemitterId" #todo implement API call for employee } } if($Phase) { $PhaseId = ConvertFrom-NameCache -Name $Phase -Type "Phases" if(-not $PhaseId) { Write-PSFMessage -Level Warning -Message "No Id for phase '$($Phase)' found. Ticket will be created with blank value on Phase" } } if($Type) { $TypeId = ConvertFrom-NameCache -Name $Type -Type "TicketTypes" if(-not $TypeId) { Write-PSFMessage -Level Warning -Message "No Id for ticket type '$($Type)' found. Ticket will be created with blank value on TicketType" } } if ($OrderBy) { $OrderById = ConvertFrom-NameCache -Name $OrderBy -Type "OrderBys" if (-not $OrderById) { Write-PSFMessage -Level Warning -Message "No Id for OrderBy type '$($OrderBy)' found. Ticket will be created with blank value on OrderById" } } if($Status) { $StatusId = ConvertFrom-NameCache -Name $Status -Type "TicketStates" if(-not $StatusId) { Write-PSFMessage -Level Warning -Message "No Id for ticket state '$($Status)' found. Ticket will be created with blank value on TicketStatus" } } if($Department) { $DepartmentIdAssigned = ConvertFrom-NameCache -Name $Department -Type "Departments" if(-not $DepartmentIdAssigned) { Write-PSFMessage -Level Warning -Message "No Id for department '$($Department)' found. Ticket will be created with blank value on departmentIdAssigned" } } if($Company) { $CompanyId = ConvertFrom-NameCache -Name $Company -Type "Companies" if(-not $CompanyId) { Write-PSFMessage -Level Warning -Message "No Id for company '$($Company)' found. Ticket will be created with blank value on CompanyId" } } } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "Userfriendly" -and (-not $Title)) { Write-PSFMessage -Level Error -Message "No title specified" continue } #region rest call prepare if ($Deadline) { $_deadlineDate = [int][double]::Parse((Get-Date -Date $Deadline.ToUniversalTime() -UFormat %s)) } else { $_deadlineDate = 0 } if ($ResubmissionDate) { $_resubmissionDate = [int][double]::Parse((Get-Date -Date $ResubmissionDate.ToUniversalTime() -UFormat %s)) } else { $_resubmissionDate = 0 } if ($Reminder) { $_reminder = [int][double]::Parse((Get-Date -Date $Reminder.ToUniversalTime() -UFormat %s)) } else { $_reminder = 0 } if ($DueDate) { $_dueDate = [int][double]::Parse((Get-Date -Date $DueDate.ToUniversalTime() -UFormat %s)) } else { $_dueDate = 0 } $body = [ordered]@{ companyId = $CompanyId remitterId = $RemitterId orderById = $OrderById title = "$($Title)" content = "$($Description)" extTicketId = "$($ExternalTicketId)" assignedToEmployeeId = $EmployeeIdAssigned assignedToDepartmentId = $DepartmentIdAssigned statusId = $StatusId typeId = $TypeId linkTypeId = $AssignmentId deadlineDate = $_deadlineDate project = $IsProject projectId = $ProjectId phaseId = $PhaseId repair = $IsRepair dueDate = $_dueDate attention = $Attention installationFee = $InstallationFee installationFeeDriveMode = $InstallationFeeDriveMode installationFeeAmount = $InstallationFeeAmount separateBilling = $SeparateBilling serviceCapAmount = $ServiceCapAmount relationshipLinkTypeId = $RelationshipLinkTypeId relationshipLinkId = $RelationshipLinkId resubmissionDate = $_resubmissionDate resubmissionText = "$($ResubmissionText)" estimatedMinutes = $EstimatedMinutes localTicketAdminFlag = $LocalTicketAdminFlag localTicketAdminEmployeeId = $LocalTicketAdminEmployeeId orderNumber = "$($OrderNumber)" reminder = $_reminder #subTickets = @{} tags = $Tags } #endregion rest call prepare if ($pscmdlet.ShouldProcess("Ticket with title '$($Title)' on companyID '$($CompanyId)'", "New")) { Write-PSFMessage -Level Verbose -Message "Creating Ticket with title '$($Title)' on companyID '$($CompanyId)'" -Tag "Ticket" -Data $body $response = Invoke-TANSSRequest -Type POST -ApiPath $apiPath -Body $body -Token $Token if($response) { Write-PSFMessage -Level Verbose -Message "API Response: $($response.meta.text)" Push-DataToCacheRunspace -MetaData $response.meta [TANSS.Ticket]@{ BaseObject = $response.content Id = $response.content.id } } else { Write-PSFMessage -Level Error -Message "Error creating ticket, no ticket response from API" } } } end { } } function New-TANSSTicketComment { <# .Synopsis New-TANSSTicketComment .DESCRIPTION Add a comment to a ticket .PARAMETER TicketID ID of the ticket where to put comment in .PARAMETER Ticket TANSS.Ticket object where to put comment in .PARAMETER Title Optional. A comment can have a title text. .PARAMETER Text The text to put within the comment .PARAMETER IsInternal Boolean, that specifies if the comment will be internal or public visible to customers .PARAMETER Pinned Switch parameter. If specified, the comment will be pinned at the top of the ticket .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> New-TANSSTicketComment -TicketID 555 -Title "very important info" -Text "Please note this important information" -IsInternal $true Put a comment with text "Please note this important information" within ticket 555 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByTicketId", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.TicketComment])] Param( [Parameter( ParameterSetName = "ByTicketId", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [int] $TicketID, [Parameter( ParameterSetName = "ByTicket", ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, Mandatory = $true )] [TANSS.Ticket] $Ticket, [string] $Title, [Alias("Description")] [string] $Text, [Alias("Internal")] [bool] $IsInternal = $true, [switch] $Pinned, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByTicket") { $TicketID = $Ticket.id } Write-PSFMessage -Level Verbose -Message "Working on ticket ID $($TicketID)" -Tag "TicketComment", "Add" # Prepare variables for rest call if ($Pinned) { $queryParameter = "?pinned=true" } else { $queryParameter = "?pinned=false" } $apiPath = Format-ApiPath -Path "api/v1/tickets/$ticketID/comments$($queryParameter)" $body = @{ "title" = $Title "content" = $Text "internal" = $IsInternal } if ($pscmdlet.ShouldProcess("$(if($IsInternal -eq $true) {"Internal"}else{"Public"}) comment $(if($Title){"with title '$($Title)' "})on Ticket $($TicketID)", "New")) { Write-PSFMessage -Level Verbose -Message "New $(if($IsInternal -eq $true) {"Internal"}else{"Public"}) comment $(if($Title){"with title '$($Title)' "})on Ticket $($TicketID)" -Tag "TicketComment", "Add" $response = Invoke-TANSSRequest -Type POST -ApiPath $apiPath -Body $body -Token $Token if ($response.content) { Write-PSFMessage -Level Verbose -Message "$($response.meta.text)" -Tag "TicketComment", "Added" # prepare comment object for output $object = [PSCustomObject]@{ id = $response.content.id date = $response.content.date employeeId = $response.content.employeeId categoryId = $response.content.categoryId title = $response.content.title content = $response.content.content internal = $response.content.internal } # output result [TANSS.TicketComment]@{ BaseObject = $object ID = $object.id TicketId = $response.content.commentOfId } } } } end {} } function Remove-TANSSTicket { <# .Synopsis Remove-TANSSTicket .DESCRIPTION Delete a ticket in TANSS .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Remove-TANSSTicket -ID 10 Remove ticket with ticketID 10 from TANSS .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = 'ById', SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'High' )] param ( # TANSS Ticket object to remove [Parameter( ParameterSetName = "ByInputObject", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [TANSS.Ticket[]] $InputObject, # Id of the ticket to remove [Parameter( ParameterSetName = "ById", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias("TicketId", "Ticket")] [int[]] $Id, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ById") { $InputObject = foreach ($idItem in $Id) { Get-TANSSTicket -Id $idItem -ErrorAction Continue } } foreach ($ticket in $InputObject) { Write-PSFMessage -Level Verbose -Message "Working on TicketID $($ticket.Id) '$($ticket.Title)'" $apiPath = Format-ApiPath -Path "api/v1/tickets/$($ticket.Id)" if ($pscmdlet.ShouldProcess("TicketID $($ticket.Id) '$($ticket.Title)' from TANSS", "Remove")) { Write-PSFMessage -Level Verbose -Message "Removing TicketID $($ticket.Id) '$($ticket.Title)' from TANSS" -Tag "Ticket" Invoke-TANSSRequest -Type DELETE -ApiPath $apiPath -Token $Token -ErrorAction Stop -ErrorVariable invokeError if(-not $invokeError) { [TANSS.Lookup]::Tickets.Remove("$($ticket.Id)") } } } } end { } } function Remove-TANSSTicketComment { <# .Synopsis Remove-TANSSTicketComment .DESCRIPTION Remove a comment from a ticket .PARAMETER TicketID The ID of the ticket where to remove a comment from .PARAMETER Id The id of the comment to remove .PARAMETER Comment TANSS.TicketComment object to remove .PARAMETER Force Process the removal quietly. .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Remove-TANSSTicketComment Description .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByTicketId", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'High' )] Param( [Parameter( ParameterSetName = "ById", Mandatory = $true )] [int] $TicketID, [Parameter( ParameterSetName = "ById", Mandatory = $true )] [Alias("CommentID")] [int] $Id, [Parameter( ParameterSetName = "ByInputObject", ValueFromPipeline = $true, Mandatory = $true )] [TANSS.TicketComment] $Comment, [switch] $Force, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "ByInputObject") { $TicketID = $Comment.TicketId $Id = $Comment.Id } # Check on Force parameter, otherwise process shouldprocess if ($Force) { $processRemoval = $true } else { if ($pscmdlet.ShouldProcess("comment ID $($Id) from ticket ID $($TicketID)", "Remove")) { $processRemoval = $true } } if ($processRemoval) { Write-PSFMessage -Level Verbose -Message "Remove comment ID $($Id) from ticket ID $($TicketID)" -Tag "TicketComment", "Remove" # Remove comment from ticket $apiPath = Format-ApiPath -Path "api/v1/tickets/$($TicketID)/comments/$($Id)" Invoke-TANSSRequest -Type DELETE -ApiPath $apiPath -Token $Token -Confirm:$false } } end {} } function Set-TANSSTicket { <# .Synopsis Set-TANSSTicket .DESCRIPTION Modify a ticket in TANSS .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the token to the console, even when the register switch is set .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Set-TANSSTicket -ID 10 -NewTitle "New ticket title" Update title to "New ticket title" of ticket with ticketID 10 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidMultipleTypeAttributes", "")] [CmdletBinding( DefaultParameterSetName = 'UserFriendly-ByInputObject', SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Ticket])] param ( # TANSS Ticket object to modify [Parameter( ParameterSetName = "ApiNative-ByInputObject", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Parameter( ParameterSetName = "UserFriendly-ByInputObject", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [TANSS.Ticket[]] $InputObject, # Id of the ticket to modify [Parameter( ParameterSetName = "ApiNative-ById", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Parameter( ParameterSetName = "UserFriendly-ById", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias("TicketId", "Ticket")] [int[]] $Id, # Company id of the ticket. Name is stored in the "linked entities" - "companies". Can only be set if the user has access to the company [Parameter(ParameterSetName = "ApiNative-ByInputObject")] [Parameter(ParameterSetName = "ApiNative-ById")] [int] $CompanyId, # Company name where the ticket should create for. Can only be set if the user has access to the company [Parameter(ParameterSetName = "UserFriendly-ByInputObject")] [Parameter(ParameterSetName = "UserFriendly-ById")] [String] $Company, # If the ticket has a remitter, the id goes here. Name is stored in the "linked entities" - "employees" [Parameter(ParameterSetName = "ApiNative-ByInputObject")] [Parameter(ParameterSetName = "ApiNative-ById")] [Alias('ClientId')] [int] $RemitterId, # If the ticket has a remitter/client, the name of the client [Parameter(ParameterSetName = "UserFriendly-ByInputObject")] [Parameter(ParameterSetName = "UserFriendly-ById")] [String] $Client, # gives infos about how the remitter gave the order. Infos are stored in the "linked entities" - "orderBys" [Parameter(ParameterSetName = "ApiNative-ByInputObject")] [Parameter(ParameterSetName = "ApiNative-ById")] [int] $OrderById, # gives infos about how the Client gave the order. [Parameter(ParameterSetName = "UserFriendly-ByInputObject")] [Parameter(ParameterSetName = "UserFriendly-ById")] [string] $OrderBy, # The title / subject of the ticket [Alias('Title', "NewName")] [string] $NewTitle, # The content / description of the ticket [Alias('content')] [string] $Description, # External ticket id (optional) [Alias('extTicketId')] [string] $ExternalTicketId, # id of employee which ticket is assigned to. Name is stored in "linked entities" - "employees" [Parameter(ParameterSetName = "ApiNative-ByInputObject")] [Parameter(ParameterSetName = "ApiNative-ById")] [Alias('assignedToEmployeeId')] [int] $EmployeeIdAssigned, # Name of the employee the ticket is assigned to [Parameter(ParameterSetName = "UserFriendly-ByInputObject")] [Parameter(ParameterSetName = "UserFriendly-ById")] [String] $EmployeeAssigned, # id of department the ticket is assigned to. Name is stored in "linked entities" - "departments" [Parameter(ParameterSetName = "ApiNative-ByInputObject")] [Parameter(ParameterSetName = "ApiNative-ById")] [Alias('assignedToDepartmentId')] [int] $DepartmentIdAssigned, # Name of the department the ticket is assigned to [Parameter(ParameterSetName = "UserFriendly-ByInputObject")] [Parameter(ParameterSetName = "UserFriendly-ById")] [String] $Department, # id of the ticket state. Name is give in "linked entities" - "ticketStates" [Parameter(ParameterSetName = "ApiNative-ByInputObject")] [Parameter(ParameterSetName = "ApiNative-ById")] [int] $StatusId, # The name of the ticket status [Parameter(ParameterSetName = "UserFriendly-ByInputObject")] [Parameter(ParameterSetName = "UserFriendly-ById")] [String] $Status, # id of the ticket type. Name is give in "linked entities" - "ticketTypes" [Parameter(ParameterSetName = "ApiNative-ByInputObject")] [Parameter(ParameterSetName = "ApiNative-ById")] [int] $TypeId, # The name of the ticket type [Parameter(ParameterSetName = "UserFriendly-ByInputObject")] [Parameter(ParameterSetName = "UserFriendly-ById")] [String] $Type, # if ticket is assigned to device / employee, linktype is given here [Alias('LinkTypeId')] [int] $AssignmentId, # If ticket has a deadline, the date is given here [Alias('deadlineDate')] [datetime] $Deadline, # if ticket is a sub-ticket of a project, the id of the project goes here. Name of the project is in the "linked entities" - "tickets" [int] $ProjectId, # if the ticket is assignet to a project phase. The name of the phase is stored in the "linked entities" - "phases" [Parameter(ParameterSetName = "ApiNative-ByInputObject")] [Parameter(ParameterSetName = "ApiNative-ById")] [Int] $PhaseId, # if the ticket is assignet to a project phase, the name of the phase [Parameter(ParameterSetName = "UserFriendly-ByInputObject")] [Parameter(ParameterSetName = "UserFriendly-ById")] [String] $Phase, # if true, this ticket is a "repair ticket" [Alias('repair')] [bool] $IsRepair = $false, # if ticket has a due date, the timestamp is given here [datetime] $DueDate, # Determines the "attention" flag state of a ticket [ValidateSet("NO", "YES", "RESUBMISSION", "MAIL")] [string] $Attention = "NO", # If the ticket has an installation fee, this value is true [ValidateSet("NO", "YES", "NO_PROJECT_INSTALLATION_FEE")] [string] $InstallationFee = "NO", # Sets the installation fee drive mode. If it is set to NONE then the system config parameter "leistung.ip.fahrzeit_berechnen" will be used. If the company from the ticket has an installation fee drive mode set then that will be used instead of the system config parameter. [ValidateSet("NONE", "DRIVE_INCLUDED", "DRIVE_EXCLUDED")] [string] $InstallationFeeDriveMode = "NONE", #Amount for the installation fee [int] $InstallationFeeAmount, # If true, the ticket shall be billed separately [bool] $SeparateBilling = $false, # if the ticket has a service cap, here the amount is given [int] $ServiceCapAmount, # linkId of the relationship (if ticket has a relation) [int] $RelationshipLinkId, # linkTypeId of the relationship (if ticket has a relation) [int] $RelationshipLinkTypeId, # if the ticket as a resubmission date set, this is given here [datetime] $ResubmissionDate, # If a resubmission text is set, this text is returned here [string] $ResubmissionText, # Number of estimated minutes which is planned for the ticket [int] $EstimatedMinutes, # Determines wether the ticket is assigned to a local ticket admin or not # NONE: "normal" ticket # LOCAL_ADMIN: ticket is assigned to a local ticket admin # TECHNICIAN: local ticket admin has forwarded the ticket to a technician [ValidateSet("NONE", "LOCAL_ADMIN", "TECHNICIAN")] [string] $LocalTicketAdminFlag = "NONE", # if the ticket is assigned to a local ticket admin, this represents the employee (local ticket admin) who is assigned for this ticket [Parameter(ParameterSetName = "ApiNative-ByInputObject")] [Parameter(ParameterSetName = "ApiNative-ById")] [ValidateNotNullOrEmpty] [int] $LocalTicketAdminEmployeeId, # if the ticket is assigned to a local ticket admin, this represents the name of the employee (local ticket admin) who is assigned for this ticket [Parameter(ParameterSetName = "UserFriendly-ByInputObject")] [Parameter(ParameterSetName = "UserFriendly-ById")] [ValidateNotNullOrEmpty] [String] $EmployeeTicketAdmin, # Sets the order number [string] $OrderNumber, # If the ticket has a reminder set, the timestamp is returned here [datetime] $Reminder, [switch] $PassThru, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning if ($EmployeeTicketAdmin) { $LocalTicketAdminEmployeeId = ConvertFrom-NameCache -Name $EmployeeTicketAdmin -Type "Employees" if (-not $LocalTicketAdminEmployeeId) { Write-PSFMessage -Level Warning -Message "No Id for employee '$($EmployeeTicketAdmin)' found, ticket will not be modified on TicketAdminEmployee value" #todo implement API call for employee } } if ($EmployeeAssigned) { $EmployeeIdAssigned = ConvertFrom-NameCache -Name $EmployeeAssigned -Type "Employees" if (-not $EmployeeIdAssigned) { Write-PSFMessage -Level Warning -Message "No Id for employee '$($EmployeeAssigned)' found, ticket will not be modified on EmployeeIdAssigned value" #todo implement API call for employee } } if ($Client) { $RemitterId = ConvertFrom-NameCache -Name $Client -Type "Employees" if (-not $RemitterId) { Write-PSFMessage -Level Warning -Message "No Id for client '$($Client)' found, ticket will not be modified on RemitterId value" #todo implement API call for employee } } if ($Phase) { $PhaseId = ConvertFrom-NameCache -Name $Phase -Type "Phases" if (-not $PhaseId) { Write-PSFMessage -Level Warning -Message "No Id for phase '$($Phase)' found, ticket will not be modified on Phase value" } } if ($Type) { $TypeId = ConvertFrom-NameCache -Name $Type -Type "TicketTypes" if (-not $TypeId) { Write-PSFMessage -Level Warning -Message "No Id for ticket type '$($Type)' found, ticket will not be modified on TicketType value" } } if ($OrderBy) { $OrderById = ConvertFrom-NameCache -Name $OrderBy -Type "OrderBys" if (-not $OrderById) { Write-PSFMessage -Level Warning -Message "No Id for OrderBy type '$($OrderBy)' found, ticket will not be modified on OrderBy value" } } if ($Status) { $StatusId = ConvertFrom-NameCache -Name $Status -Type "TicketStates" if (-not $StatusId) { Write-PSFMessage -Level Warning -Message "No Id for ticket state '$($Status)' found, ticket will not be modified on TicketStatus value" } } if ($Department) { $DepartmentIdAssigned = ConvertFrom-NameCache -Name $Department -Type "Departments" if (-not $DepartmentIdAssigned) { Write-PSFMessage -Level Warning -Message "No Id for department '$($Department)' found, ticket will not be modified on departmentIdAssigned value" } } if ($Company) { $CompanyId = ConvertFrom-NameCache -Name $Company -Type "Companies" if (-not $CompanyId) { Write-PSFMessage -Level Warning -Message "No Id for company '$($Company)' found, ticket will not be modified on CompanyId" } } if ($Deadline) { $_deadlineDate = [int][double]::Parse((Get-Date -Date $Deadline.ToUniversalTime() -UFormat %s)) } else { $_deadlineDate = 0 } if ($DueDate) { $_dueDate = [int][double]::Parse((Get-Date -Date $DueDate.ToUniversalTime() -UFormat %s)) } else { $_dueDate = 0 } if ($ResubmissionDate) { $_resubmissionDate = [int][double]::Parse((Get-Date -Date $ResubmissionDate.ToUniversalTime() -UFormat %s)) } else { $_resubmissionDate = 0 } if ($Reminder) { $_reminder = [int][double]::Parse((Get-Date -Date $Reminder.ToUniversalTime() -UFormat %s)) } else { $_reminder = 0 } } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" if ($parameterSetName -like "*ById*") { $InputObject = foreach ($idItem in $Id) { Get-TANSSTicket -Id $idItem -ErrorAction Continue } } foreach ($ticket in $InputObject) { Write-PSFMessage -Level Verbose -Message "Working on TicketID $($ticket.Id) '$($ticket.Title)'" $apiPath = Format-ApiPath -Path "api/v1/tickets/$($ticket.Id)" $body = [ordered]@{ "companyId" = (.{if ($CompanyId) { $CompanyId } else { $ticket.BaseObject.companyId }}) "remitterId" = (.{if ($RemitterId) { $RemitterId } else { $ticket.BaseObject.remitterId }}) "title" = (.{if ($NewTitle) { "$($NewTitle)" } else { $ticket.BaseObject.title }}) "content" = (.{if ($Description) { "$($Description)" } else { $ticket.BaseObject.content }}) "extTicketId" = (.{if ($ExternalTicketId) { "$($ExternalTicketId)" } else { $ticket.BaseObject.extTicketId }}) "assignedToEmployeeId" = (.{if ($EmployeeIdAssigned) { $EmployeeIdAssigned } else { $ticket.BaseObject.assignedToEmployeeId }}) "assignedToDepartmentId" = (.{if ($DepartmentIdAssigned) { $DepartmentIdAssigned } else { $ticket.BaseObject.assignedToDepartmentId }}) "statusId" = (.{if ($StatusId) { $StatusId } else { $ticket.BaseObject.statusId }}) "typeId" = (.{if ($TypeId) { $TypeId } else { $ticket.BaseObject.typeId }}) "linkTypeId" = (.{if ($AssignmentId) { $AssignmentId } else { $ticket.BaseObject.linkTypeId }}) "linkId" = $ticket.BaseObject.linkId "deadlineDate" = (.{if ($_deadlineDate) { $_deadlineDate } else { $ticket.BaseObject.deadlineDate }}) "project" = $ticket.BaseObject.project.ToString() "projectId" = (.{if ($ProjectId) { $ProjectId } else { $ticket.BaseObject.projectId }}) "repair" = (.{if ($IsRepair) { $IsRepair } else { $ticket.BaseObject.repair }}) "dueDate" = (.{if ($_dueDate) { $_dueDate } else { $ticket.BaseObject.dueDate }}) "attention" = (.{if ($Attention) { $Attention } else { $ticket.BaseObject.attention }}) "orderById" = (.{if ($OrderById) { $OrderById } else { $ticket.BaseObject.orderById }}) "installationFee" = (.{if ($InstallationFee) { $InstallationFee } else { $ticket.BaseObject.installationFee }}) "installationFeeDriveMode" = (.{if ($InstallationFeeDriveMode) { $InstallationFeeDriveMode } else { "None" }}) "installationFeeAmount" = (.{if ($InstallationFeeAmount) { $InstallationFeeAmount } else { $ticket.BaseObject.installationFeeAmount }}) "separateBilling" = (.{if ($SeparateBilling) { $SeparateBilling.ToString() } else { $ticket.BaseObject.separateBilling }}) "serviceCapAmount" = (.{if ($ServiceCapAmount) { $ServiceCapAmount } else { $ticket.BaseObject.serviceCapAmount }}) "relationshipLinkTypeId" = (.{if ($RelationshipLinkTypeId) { $RelationshipLinkTypeId } else { $ticket.BaseObject.orderById }}) "relationshipLinkId" = (.{if ($RelationshipLinkId) { $RelationshipLinkId } else { $ticket.BaseObject.relationshipLinkId }}) "resubmissionDate" = (.{if ($_resubmissionDate) { $_resubmissionDate } else { $ticket.BaseObject.resubmissionDate }}) "estimatedMinutes" = (.{if ($EstimatedMinutes) { $EstimatedMinutes } else { $ticket.BaseObject.estimatedMinutes }}) "localTicketAdminFlag" = (.{if ($LocalTicketAdminFlag) { $LocalTicketAdminFlag } else { $ticket.BaseObject.localTicketAdminFlag }}) "localTicketAdminEmployeeId" = (.{if ($LocalTicketAdminEmployeeId) { $LocalTicketAdminEmployeeId } else { $ticket.BaseObject.localTicketAdminEmployeeId }}) "phaseId" = (.{if ($PhaseId) { $PhaseId } else { $ticket.BaseObject.phaseId }}) "resubmissionText" = (.{if ($ResubmissionText) { "$($ResubmissionText)" } else { $ticket.BaseObject.resubmissionText }}) "orderNumber" = (.{if ($OrderNumber) { "$($OrderNumber)" } else { $ticket.BaseObject.orderNumber }}) "reminder" = (.{if ($_reminder) { $_reminder } else { $ticket.BaseObject.reminder }}) } if ($pscmdlet.ShouldProcess("TicketID $($ticket.Id) with $(if($NewTitle){"new "})title '$(if($NewTitle){$NewTitle}else{$ticket.Title})'", "Update")) { Write-PSFMessage -Level Verbose -Message "Updating TicketID $($ticket.Id) with $(if($NewTitle){"new "})title '$(if($NewTitle){$NewTitle}else{$ticket.Title})'" -Tag "Ticket" -Data $body $response = Invoke-TANSSRequest -Type PUT -ApiPath $apiPath -Body $body -Token $Token if ($response) { Write-PSFMessage -Level Verbose -Message "API Response: $($response.meta.text)" Push-DataToCacheRunspace -MetaData $response if($PassThru) { foreach ($content in $response.content) { [TANSS.Ticket]@{ BaseObject = $content Id = $content.id } } } } else { Write-PSFMessage -Level Error -Message "Error updating ticketID '$($ticket.Id)', no ticket response from API" } } } } end { } } function Get-TANSSTimeStamp { <# .Synopsis Get-TANSSTimeStamp .DESCRIPTION Get docmented timestamps from TANSS .PARAMETER Start Starting date of the pariod to retreive timestamps for If not specified,the current day will be received. .PARAMETER End Enddate of the pariod to retreive timestamps for If not specified,the current day will be received. .PARAMETER EmployeeId The Id of the employee to retreive timestamps for As a default, the Id of employee logged in will be used. .PARAMETER EmployeeName The name of the employee to retreive timestamps for Tab completion available for known names .PARAMETER State The status of the timestamps to retreive Available via tab completion: "On", "Off", "StartPause", "EndPause" As a default, all states are retreived. .PARAMETER Type The type for the period to stamp Available via tab completion: "Work", "Inhouse", "Errand", "Vacation", "Illness", "PaidAbsence", "UnpaidAbsence", "Overtime", "Support" .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Get-TANSSTimeStamp Get the timestamps of the current day .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "Default", PositionalBinding = $true, ConfirmImpact = 'Low' )] Param( [datetime] $Start, [datetime] $End, [Parameter( ParameterSetName = "ById", ValueFromPipeline = $true )] [int[]] $EmployeeId, [Parameter( ParameterSetName = "ByName", ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [string[]] $EmployeeName, [ValidateSet("Coming", "Leaving", "StartPause", "EndPause")] [string[]] $State, [ValidateSet("Work", "Inhouse", "Errand", "Vacation", "Illness", "PaidAbsence", "UnpaidAbsence", "Overtime", "Support")] [ValidateNotNullOrEmpty()] [String] $Type, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" -Tag "TimeStamp" # check parameter set switch ($parameterSetName) { "Default" { $EmployeeId = $Token.EmployeeId } "ByName" { Write-PSFMessage -Level System -Message "Convert EmployeeId from EmployeeName" -Tag "TimeStamp", "EmployeeName" $EmployeeId = @() foreach ($name in $EmployeeName) { Write-PSFMessage -Level System -Message "Working on employee name '$($name)'" -Tag "TimeStamp", "EmployeeName" [int]$id = $null try { $id = [int]$name $nameIsNumber = $true } catch { $nameIsNumber = $false } if (-not $nameIsNumber) { $id = ConvertFrom-NameCache -Name $name -Type "Employees" } if (-not $id) { Write-PSFMessage -Level Warning -Message "No Id for employee '$($name)' found" -Tag "TimeStamp", "EmployeeName", "Warning" } else { Write-PSFMessage -Level System -Message "Found id '$($id)' for employee '$($name)'" -Tag "TimeStamp", "EmployeeName" $EmployeeId += $id } } } "ById" { # Nothing to do, Id is already in place } Default { Stop-PSFFunction -Message "Unhandeled ParameterSetName. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } # Ensure there are employeeIds in the array, if not, api will always output timestamps for currently logged in user. This might produce redundant and faulty results if ($EmployeeId) { # Build api path parameters $apiParameters = @{ "employeeIds" = $([string]::Join(",", $EmployeeId)) } if ($Start) { $from = [int32][double]::Parse((Get-Date -Date $Start.ToUniversalTime() -UFormat %s)) $apiParameters.Add("from", $from) } else { $from = [int32][double]::Parse((Get-Date -Date (Get-Date).Date.ToUniversalTime() -UFormat %s)) $apiParameters.Add("from", $from) } if ($End) { $till = [int32][double]::Parse((Get-Date -Date $End.ToUniversalTime() -UFormat %s)) $apiParameters.Add("till", $till) } else { $till = [int32][double]::Parse((Get-Date -Date (Get-Date).Date.AddDays(1).ToUniversalTime() -UFormat %s)) $apiParameters.Add("till", $till) } # Compile api path $apiPath = Format-ApiPath -Path "api/v1/timestamps/info" -QueryParameter $apiParameters # Get data from service $response = Invoke-TANSSRequest -Type GET -ApiPath $apiPath Write-PSFMessage -Level Verbose -Message "$($response.meta.text) - $($response.content.timestamps.count) timestamp$(if($response.content.timestamps.count -ne 1){"s"}) received" -Tag "TimeStamp", "TimeStampRequestResult" # Output response foreach ($item in $response.content.timestamps) { Write-PSFMessage -Level System -Message "Create TANSS.TimeStamp object id '$($item.id)' ($( Get-Date -Date ( [datetime]::new(1970, 1, 1, 0, 0, 0, 0, [DateTimeKind]::Utc).AddSeconds($item.date).ToLocalTime()) -Format 'yyyy-MM-dd' ), $($item.type), $($item.state) )" -Tag "TimeStamp", "TimeStampRequestResult" # Create object $output = [TANSS.TimeStamp]@{ BaseObject = $item Id = $item.id } # filter output Write-PSFMessage -Level System -Message "Client side filtering for TANSS.TimeStamp object id '$($item.id)'" -Tag "TimeStamp", "TimeStampRequestResult" if ($State) { $output = $output | Where-Object State -in $State } if ($Type) { $output = $output | Where-Object State -in $Type } if($output) { # Output the result Write-PSFMessage -Level System -Message "Ouput TANSS.TimeStamp object id '$($item.id)'" -Tag "TimeStamp", "TimeStampRequestResult" $output } else { Write-PSFMessage -Level System -Message "TANSS.TimeStamp object id '$($item.id)' is not going to output, because of client side filtering" -Tag "TimeStamp", "TimeStampRequestResult" } } } } end {} } function New-TANSSTimeStamp { <# .Synopsis New-TANSSTimeStamp .DESCRIPTION Add a new timestamp into the service .PARAMETER State The state to stamp. Has to be one of the value: "Coming", "Leaving", "StartPause", "EndPause" (Tabcompletaion available) .PARAMETER Type The type of record for you stamp a state. Available types: "Work", "Inhouse", "Errand", "Vacation", "Illness", "PaidAbsence", "UnpaidAbsence", "Overtime", "Support" Default type is: "Work" .PARAMETER Date The date of the timestamp .PARAMETER EmployeeId ID of the employee to timestamp for. If nothing is specified the currently logged in employee will be used .PARAMETER EmployeeName The name of the employee to timestamp for. Tabcompletion available for all known employees If nothing is specified the currently logged in employee will be used .PARAMETER AutoPause Tells the api to set autoPause to true .PARAMETER ServiceToken A timestamp api service token generated within TANSS. ServiceToken hast to be specified as a TANSS.Connection. A ServiceToken is required, if timestamps for other employees than the logged in one, are used to be written into the service. .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> New-TANSSTimeStamp Description .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "Default", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.TimeStamp])] Param( [Parameter(Mandatory = $true, Position = 0)] [ValidateSet("Coming", "Leaving", "StartPause", "EndPause")] [string] $State, [Parameter(Position = 1)] [ValidateSet("Work", "Inhouse", "Errand", "Vacation", "Illness", "PaidAbsence", "UnpaidAbsence", "Overtime", "Support")] [ValidateNotNullOrEmpty()] [String] $Type = "Work", [Parameter(Position = 2)] [datetime] $Date, [bool] $AutoPause, [Parameter( ParameterSetName = "ById", ValueFromPipeline = $true )] [int[]] $EmployeeId, [Parameter( ParameterSetName = "ByName", ValueFromPipeline = $true )] [string[]] $EmployeeName, [Parameter( ParameterSetName = "ById", Mandatory = $true )] [Parameter( ParameterSetName = "ByName", Mandatory = $true )] [TANSS.Connection] $ServiceToken, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" switch ($parameterSetName) { "Default" { Write-PSFMessage -Level System -Message "Using EmployeeId '$($Token.EmployeeId)' of '$($Token.UserName)' from given Token" -Tag "TimeStamp", "ParameterSetting" $EmployeeId = $Token.EmployeeId } "ByName" { Write-PSFMessage -Level System -Message "Convert EmployeeId from EmployeeName" -Tag "TimeStamp", "ParameterSetting" $EmployeeId = @() foreach ($name in $EmployeeName) { Write-PSFMessage -Level System -Message "Working on employee name '$($name)'" -Tag "TimeStamp", "ParameterSetting" $id = ConvertFrom-NameCache -Name $name -Type "Employees" if (-not $id) { Write-PSFMessage -Level Warning -Message "No Id for employee '$($name)' found" -Tag "TimeStamp", "ParameterSetting", "Warning" } else { Write-PSFMessage -Level System -Message "Found id '$($id)' for employee '$($name)'" -Tag "TimeStamp", "ParameterSetting" $EmployeeId += $id } } } "ById" { Write-PSFMessage -Level System -Message "EmployeeId '$($Token.EmployeeId)' already given to function" -Tag "TimeStamp", "ParameterSetting" # Nothing to do } Default { Stop-PSFFunction -Message "Unhandeled ParameterSetName. Developers mistake." -EnableException $true -Cmdlet $pscmdlet } } $apiStateText = ConvertFrom-TANSSTimeStampParameter -Text $State -TextType State $apiTypeText = ConvertFrom-TANSSTimeStampParameter -Text $Type -TextType Type # Compile api path $paramFormatApiPath = @{} if ($AutoPause) { $paramFormatApiPath.Add("autoPause", 'true') } if ($parameterSetName -like "Default") { # Use the "personal" api path $apiPath = Format-ApiPath -Path "/api/v1/timestamps" -QueryParameter $paramFormatApiPath } else { # Use the api path for api keys -> this one can write timestamps for other employees then the logged in one $apiPath = Format-ApiPath -Path "/api/timestamps/v1" -QueryParameter $paramFormatApiPath } # Work through employees foreach ($id in $EmployeeId) { $name = ConvertFrom-NameCache -Id $id -Type "Employees" Write-PSFMessage -Level Verbose -Message "Working on employee '$($name)' (Id $($id))" -Tag "TimeStamp", "Stamping" # Compile body object $body = @{ "employeeId" = $id "state" = $apiStateText "type" = $apiTypeText } if ($Date) { $body.date = [int32][double]::Parse((Get-Date -Date $Date.ToUniversalTime() -UFormat %s)) } # Check WhatIf or process request if ($pscmdlet.ShouldProcess("Timestamp for employee '$($name)' (ID: $($id)) with state '$($State)'", "New")) { Write-PSFMessage -Level Verbose -Message "New timestamp for employee '$($name)' (ID: $($id)) with state '$($State)'" -Tag "TimeStamp", "Stamping" # Push data into service $paramInvokeTANSSRequest = @{ "Type" = "POST" "ApiPath" = $apiPath "Body" = $body } # Choose token for "personal writing" or "delegated writing for other employees" if ($parameterSetName -like "Default") { # Use standard user specific token to write timestamps for logged in user only Write-PSFMessage -Level System -Message "Using Employee token from connection for API call" -Tag "TimeStamp", "ParameterSetting" $paramInvokeTANSSRequest.Add("Token", $Token) } else { # Use serviceToken to allow writing for other employees then the logged in one Write-PSFMessage -Level System -Message "Using token from serviceToken parameter for API call" -Tag "TimeStamp", "ParameterSetting" $paramInvokeTANSSRequest.Add("Token", $ServiceToken) } $response = Invoke-TANSSRequest @paramInvokeTANSSRequest Write-PSFMessage -Level Verbose -Message "$($response.meta.text) - Timestamp Id '$($response.content.id)' with status '$($response.content.state)'" -Tag "TimeStamp", "Stamping", "TimeStampRequestResult" if ($response) { [TANSS.TimeStamp]@{ BaseObject = $response.content Id = $response.content.id } } } } } end {} } function Remove-TANSSTimeStamp { <# .Synopsis Remove-TANSSTimeStamp .DESCRIPTION Remove a timestamp from TANSS .PARAMETER InputObject TANSS TimeStamp object to remove .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Get-TANSSTimeStamp | Remove-TANSSTimeStamp Remove timestamp for currently logged in employee for today .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'High' )] Param( [Parameter( Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [Alias("Timestamp")] [TANSS.TimeStamp[]] $InputObject, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning $timeStamps = [System.Collections.ArrayList]@() } process { foreach ($timeStamp in $InputObject) { Write-PSFMessage -Level Verbose -Message "Collecting TimeStamp '$(Get-Date -Date ($timeStamp.Date) -Format 'yyyy-MM-dd HH:mm')' from employee '$($timeStamp.EmployeeName)' (Id $($timeStamp.Id))" $null = $timeStamps.Add($timeStamp) } } end { [array]$timeStampsOfEmployees = $timeStamps | Group-Object EmployeeId Write-PSFMessage -Level System -Message "Collected $(([array]$timeStamps).count) timestamp(s) for $(([array]$timeStampsOfEmployees).count) employee" -Tag "TimeStamp" foreach ($timeStampsOfEmployeeGroup in $timeStampsOfEmployees) { Write-PSFMessage -Level Verbose -Message "Working on timestamps for employee '$($timeStampsOfEmployeeGroup.group[0].EmployeeName)' (Id: $($timeStampsOfEmployeeGroup.Name))" -Tag "TimeStamp" if ($timeStampsOfEmployeeGroup.Name -ne $Token.EmployeeId) { Write-PSFMessage -Level Warning -Message "Unable to remove timestamps for employee '$($timeStampsOfEmployeeGroup.Name)'. TANSS API does not support removing timestamps of other employees than the logged in employee (Id: $($Token.EmployeeId), Name: $($Token.UserName))" -Tag "TimeStamp", "ApiLimitation" -PSCmdlet $pscmdlet continue } [array]$timeStampsOfDays = $timeStampsOfEmployeeGroup.Group | Group-Object { ($_.Date).Date } Write-PSFMessage -Level System -Message "Got $(([array]($timeStampsOfEmployeeGroup.Group)).count) timestamp(s) for $(([array]$timeStampsOfDays).count) day(s)" -Tag "TimeStamp" foreach ($timeStampsOfDayGroup in $timeStampsOfDays) { [array]$timeStampsToDelete = $timeStampsOfDayGroup.Group $employeeId = $timeStampsToDelete[0].EmployeeId $employeeName = $timeStampsToDelete[0].EmployeeName $dateString = Get-Date -Date $timeStampsToDelete[0].Date -Format "yyyy-MM-dd" Write-PSFMessage -Level Verbose -Message "Working on $(([array]$timeStampsToDelete).count) timestamp(s) from $($dateString) for employee '$($employeeName)'" -Tag "TimeStamp" Write-PSFMessage -Level System -Message "Going to query statistics of day '$($dateString)' for employee '$($employeeName)' (Id: $($employeeId))" -Tag "TimeStamp" $QueryParameter = @{ "employeeIds" = $employeeId "from" = ( [int32][double]::Parse((Get-Date -Date $timeStampsToDelete[0].Date.Date.ToUniversalTime() -UFormat %s)) ) "till" = ( [int32][double]::Parse((Get-Date -Date $timeStampsToDelete[0].Date.Date.AddDays(1).ToUniversalTime() -UFormat %s)) ) } $apiPath = Format-ApiPath -Path "api/v1/timestamps/statistics" -QueryParameter $QueryParameter $paramInvokeTANSSRequest = @{ "Type" = "GET" "ApiPath" = $apiPath "Token" = $Token "WhatIf" = $false "Verbose" = $false } $response = Invoke-TANSSRequest @paramInvokeTANSSRequest Push-DataToCacheRunspace -MetaData $response.meta -Verbose:$false [array]$timeStampsOfDay = $response.content.timestamps Write-PSFMessage -Level System -Message "Found $($timeStampsOfDay.count) in '$($dateString)' for employee '$($employeeName)' (Id: $($employeeId))" -Tag "TimeStamp" [array]$timeStampsRemaining = $timeStampsOfDay | Where-Object id -NotIn $timeStampsToDelete.id Write-PSFMessage -Level System -Message "There will remain $($timeStampsRemaining.count) timestamps for employee '$($employeeName)' (Id: $($employeeId)) on '$($dateString)' after processing the current removal" -Tag "TimeStamp" $apiPath = Format-ApiPath -Path "api/v1/timestamps/$($employeeId)/day/$($dateString)" -QueryParameter @{ "autoPause" = $false } $body = $timeStampsRemaining | ConvertTo-PSFHashtable $paramInvokeTANSSRequest = @{ "Type" = "PUT" "ApiPath" = $apiPath "Token" = $Token "BodyForceArray" = $true } if ($body) { $paramInvokeTANSSRequest.Add("body", $body) } if ($pscmdlet.ShouldProcess("$($timeStampsToDelete.count) timestamps for '$($employeeName)' of date '$($dateString)' (EmployeeId: $($employeeId))", "Remove")) { Write-PSFMessage -Level Verbose -Message "Removing $($timeStampsToDelete.count) timestamps for '$($employeeName)' of date '$($dateString)' (EmployeeId: $($employeeId))" -Tag "TimeStamp" $response = Invoke-TANSSRequest @paramInvokeTANSSRequest } } } } } function Approve-TANSSVacationRequest { <# .Synopsis Approve-TANSSVacationRequest .DESCRIPTION Approve a vacation request within TANSS .PARAMETER InputObject TANSS.Vacation.Request object to approve .PARAMETER Id Id of the vacation request to approve .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Get-TANSSVacationRequest -Id 10 | Approve-TANSSVacationRequest Approve the VacationRequest Id 10 .EXAMPLE PS C:\> Approve-TANSSVacationRequest -Id 10 Approve the VacationRequest Id 10 .EXAMPLE PS C:\> $vacationRequests | Approve-TANSSVacationRequest -PassThru Approve all requests in variable '$vacationrequests' and output the (approved) VacationRequests on the console Assuming, the variable is build on something like: PS C:\>$vacationrequests = Get-TANSSVacationRequest -Year 2022 -Month 8 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "")] [CmdletBinding( DefaultParameterSetName = "ById", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] Param( [Parameter( ParameterSetName = "ByInputObject", Mandatory = $true, ValueFromPipeline = $true )] [TANSS.Vacation.Request[]] $InputObject, [Parameter( ParameterSetName = "ById", Mandatory = $true, ValueFromPipeline = $true )] [Alias("RequestId", "VacationRequestId")] [int[]] $Id, [switch] $PassThru, [TANSS.Connection] $Token ) begin { try { $outBuffer = $null if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) { $PSBoundParameters['OutBuffer'] = 1 } $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Set-TANSSVacationRequestStatus', [System.Management.Automation.CommandTypes]::Function) $scriptCmd = {& $wrappedCmd -Status "Approve" @PSBoundParameters } $steppablePipeline = $scriptCmd.GetSteppablePipeline() $steppablePipeline.Begin($PSCmdlet) } catch { throw } } process { try { $steppablePipeline.Process($_) } catch { throw } } end { try { $steppablePipeline.End() } catch { throw } } } function Deny-TANSSVacationRequest { <# .Synopsis Deny-TANSSVacationRequest .DESCRIPTION Decline a vacation request within TANSS .PARAMETER InputObject TANSS.Vacation.Request object to approve .PARAMETER Id Id of the vacation request to approve .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Get-TANSSVacationRequest -Id 10 | Deny-TANSSVacationRequest Decline the VacationRequest Id 10 .EXAMPLE PS C:\> Deny-TANSSVacationRequest -Id 10 Decline the VacationRequest Id 10 .EXAMPLE PS C:\> $vacationRequests | Deny-TANSSVacationRequest -PassThru Decline all requests in variable '$vacationrequests' and output the new (declined) VacationRequests on the console Assuming, the variable is build on something like: PS C:\>$vacationrequests = Get-TANSSVacationRequest -Year 2022 -Month 8 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "")] [CmdletBinding( DefaultParameterSetName = "ById", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] Param( [Parameter( ParameterSetName = "ByInputObject", Mandatory = $true, ValueFromPipeline = $true )] [TANSS.Vacation.Request[]] $InputObject, [Parameter( ParameterSetName = "ById", Mandatory = $true, ValueFromPipeline = $true )] [Alias("RequestId", "VacationRequestId")] [int[]] $Id, [switch] $PassThru, [TANSS.Connection] $Token ) begin { try { $outBuffer = $null if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) { $PSBoundParameters['OutBuffer'] = 1 } $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Set-TANSSVacationRequestStatus', [System.Management.Automation.CommandTypes]::Function) $scriptCmd = {& $wrappedCmd -Status "Decline" @PSBoundParameters } $steppablePipeline = $scriptCmd.GetSteppablePipeline() $steppablePipeline.Begin($PSCmdlet) } catch { throw } } process { try { $steppablePipeline.Process($_) } catch { throw } } end { try { $steppablePipeline.End() } catch { throw } } } function Get-TANSSVacationAbsenceSubType { <# .Synopsis Get-TANSSVacationAbsenceSubType .DESCRIPTION Retrieve the additional absence types for the vacation type "absence". If a absence on a employee is created, one of this types can be specified as more specific information. .PARAMETER Id ID of the type to get (client side filtering) .PARAMETER Name Name of the type to get (client side filtering) .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSVacationAbsenceSubType Description .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseOutputTypeCorrectly", "")] [CmdletBinding( SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] [OutputType([TANSS.Vacation.AbsenceSubType])] Param( [string[]] $Name, [int[]] $Id, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/planningAdditionalTypes" [array]$output = @() } process { $response = Invoke-TANSSRequest -Type "GET" -ApiPath $apiPath -Token $Token if ($response) { Write-PSFMessage -Level Verbose -Message "Found $(($response.content).count) vacation types" -Tag "Vacation", "VacationType" foreach ($type in $response.content) { # Do filtering on name if ($Name) { $filterSuccess = $false foreach ($filterName in $Name) { if ($type.Name -like $filterName) { $filterSuccess = $true } } # if filter does not hit, continue with next technician if ($filterSuccess -eq $false) { continue } } # Do filtering on id if ($Id) { $filterSuccess = $false foreach ($filterId in $Id) { if ([int]($type.id) -eq $filterId) { $filterSuccess = $true } } # if filter does not hit, continue with next technician if ($filterSuccess -eq $false) { continue } } # Compiling additional TANSS.Vacation.AbsenceSubType $output += [TANSS.Vacation.AbsenceSubType]@{ BaseObject = $type Id = $type.id } # Check VacationType lookup cache if ([TANSS.Lookup]::VacationAbsenceSubTypes[$type.id] -notlike $type.name) { if ([TANSS.Lookup]::VacationAbsenceSubTypes[$type.id]) { Write-PSFMessage -Level Debug -Message "Update existing id '$($id)' in [TANSS.Lookup]::VacationAbsenceSubTypes with value '$($type.name)'" -Tag "Cache" [TANSS.Lookup]::VacationAbsenceSubTypes[$type.id] = $type.name } else { Write-PSFMessage -Level Debug -Message "Insert in [TANSS.Lookup]::VacationAbsenceSubTypes: $($type.id) - '$($($type.name))'" -Tag "Cache" ([TANSS.Lookup]::VacationAbsenceSubTypes).Add($type.id, $type.name) } } } } else { Write-PSFMessage -Level Warning -Message "No technicians found." -Tag "Technician" } } end { # Outputting TANSS.VacationType $output } } function Get-TANSSVacationEntitlement { <# .Synopsis Get-VacationEntitlement .DESCRIPTION Get the available days of vacation within a year By default the current year is queried .PARAMETER Year The year to query. .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-VacationEntitlement -Year 2022 Query entitlement from all employees in year 2022 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "Default", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] [OutputType([TANSS.Vacation.Entitlement])] Param( [ValidateNotNullOrEmpty()] [int] $Year = (Get-Date).Year, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { # Query entitlement for year $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/vacationDays/year/$($Year)" $response = Invoke-TANSSRequest -Type "GET" -ApiPath $apiPath -Token $Token # Output result Write-PSFMessage -Level Verbose -Message "$($response.meta.text): Received $($response.meta.properties.extras.count) VacationEntitlement records in year $($Year)" -Tag "VacationEntitlement", "Query" foreach ($entitlement in $response.content) { $_transferred = if ($entitlement.transferred) { $entitlement.transferred } else { 0 } [TANSS.Vacation.Entitlement]@{ BaseObject = $entitlement EmployeeId = $entitlement.employeeId Year = $entitlement.year NumberOfDays = $entitlement.numberOfDays TransferedDays = $_transferred } } } end {} } function Get-TANSSVacationRequest { <# .Synopsis Get-TANSSVacationRequest .DESCRIPTION Query vacation requests of any state from TANSS By default the current year is queried .PARAMETER Id The explicit ID of the vacation request to get from TANSS .PARAMETER Year The year to list vacation requests for .PARAMETER Month The month of the year to list vacation requests .PARAMETER EmployeeId The Id of the employee to list vacation requests from .PARAMETER EmployeeName The name of the employee to list vacation requests from .PARAMETER DepartmentId Department Id filter .PARAMETER DepartmentName Department name filter .PARAMETER Type Name of the request type Values can be tabcompleted, so you don't have to type Available: "Urlaub", "Krankheit", "Abwesenheit", "Bereitschaft", "Überstunden abfeiern", "VACATION", "ILLNESS", "ABSENCE", "STAND_BY", "OVERTIME" .PARAMETER AbsenceSubTypeId For type "Abwesenheit", "ABSENCE" there are subtypes available. This one specifies the Id of the subtype to use .PARAMETER AbsenceSubTypeName For type "Abwesenheit", "ABSENCE" there are subtypes available. This one specifies the name of the subtype to use Values can be tabcompleted, so you don't have to type .PARAMETER ExcludeVacationRequestId Exclude filter on specific IDs .PARAMETER State The status for requests to list. Available values: "NEW", "REQUESTED", "APPROVED", "DECLINED" .PARAMETER CheckPermission Boolean value from the api wether to check permission or not .PARAMETER AddFrontendValue Boolean value to add request object on .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Get-TANSSVacationRequest Get all requests from the current year .EXAMPLE PS C:\> Get-TANSSVacationRequest -Year ((Get-Date).Year - 1) Get all requests from last year .EXAMPLE PS C:\> Get-TANSSVacationRequest -Type ILLNESS Get all illness records from the current year .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ListUserFriendly", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] [OutputType([TANSS.Vacation.Request])] Param( [Parameter( ParameterSetName = "Id", Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [int[]] $Id, [Parameter( ParameterSetName = "ListApiNativ" )] [Parameter( ParameterSetName = "ListUserFriendly" )] [int] $Year = (Get-Date).Year, [Parameter( ParameterSetName = "ListApiNativ" )] [Parameter( ParameterSetName = "ListUserFriendly" )] [int] $Month, [Parameter( ParameterSetName = "ListApiNativ" )] [int[]] $EmployeeId, [Parameter( ParameterSetName = "ListUserFriendly" )] [int[]] $EmployeeName, [Parameter( ParameterSetName = "ListApiNativ" )] [int[]] $DepartmentId, [Parameter( ParameterSetName = "ListUserFriendly" )] [int[]] $DepartmentName, [Parameter( ParameterSetName = "ListApiNativ" )] [Parameter( ParameterSetName = "ListUserFriendly" )] [string[]] $Type, [Parameter( ParameterSetName = "ListApiNativ" )] [int[]] $AbsenceSubTypeId, [Parameter( ParameterSetName = "ListUserFriendly" )] [string[]] $AbsenceSubTypeName, [Parameter( ParameterSetName = "ListApiNativ" )] [Parameter( ParameterSetName = "ListUserFriendly" )] [int[]] $ExcludeVacationRequestId, [Parameter( ParameterSetName = "ListApiNativ" )] [Parameter( ParameterSetName = "ListUserFriendly" )] [ValidateSet("NEW", "REQUESTED", "APPROVED", "DECLINED")] [string[]] $State, [Parameter( ParameterSetName = "ListApiNativ" )] [Parameter( ParameterSetName = "ListUserFriendly" )] [bool] $CheckPermission = $true, [Parameter( ParameterSetName = "ListApiNativ" )] [Parameter( ParameterSetName = "ListUserFriendly" )] [bool] $AddFrontendValue = $false, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" switch ($parameterSetName) { { $_ -like "Id" } { foreach ($requesterId in $Id) { Write-PSFMessage -Level Verbose -Message "Query VacationRequestId $($requesterId)" -Tag "VacationRequest" # Query VacationRequest by ID $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/$($requesterId)" $response = Invoke-TANSSRequest -Type "GET" -ApiPath $apiPath -Token $Token # Output result Write-PSFMessage -Level Verbose -Message "$($response.meta.text): VacationRequestId $($requesterId)" -Tag "VacationRequest" [TANSS.Vacation.Request]@{ BaseObject = $response.content Id = $response.content.id } } } { $_ -like "List*" } { $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/list" #region parameter validation # Parameter EmployeeName if ($EmployeeName) { Write-PSFMessage -Level Verbose -Message "Processing lookup on filtering for Employee '$( [string]::Join("'; '", [array]$EmployeeName) )'" $EmployeeId = foreach ($item in $EmployeeName) { $result = ConvertFrom-NameCache -Name $item -Type Employees -Verbose:$false if (-not $result) { Stop-PSFFunction -Message "Employee '$($item)' not found. Unable to query VacationRequests." -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "VacationAbsenceSubTypes", "CacheException" } else { $result } } Write-PSFMessage -Level System -Message "Filtering on EmployeeId '$( [string]::Join("', '", [array]$EmployeeId) )'" } # Parameter DepartmentName if ($DepartmentName) { Write-PSFMessage -Level Verbose -Message "Processing lookup on filtering for Department '$( [string]::Join("'; '", [array]$DepartmentName) )'" $DepartmentId = foreach ($item in $DepartmentName) { $result = ConvertFrom-NameCache -Name $item -Type Departments -Verbose:$false if (-not $result) { Stop-PSFFunction -Message "Department '$($item)' not found. Unable to query VacationRequests." -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "VacationAbsenceSubTypes", "CacheException" } else { $result } } Write-PSFMessage -Level System -Message "Filtering on DepartmentId '$( [string]::Join("', '", [array]$DepartmentId) )'" } # Parameter Type if ($Type) { Write-PSFMessage -Level System -Message "Processing filtering on Type '$( [string]::Join("', '", [array]$Type) )'" $planningType = @() foreach ($absenceType in $Type) { switch ($absenceType) { { $_ -like "Urlaub" } { $planningType += "VACATION" } { $_ -like "Krankheit" } { $planningType += "ILLNESS" } { $_ -like "Abwesenheit*" } { $planningType += "ABSENCE" } { $_ -like "Bereitschaft" } { $planningType += "STAND_BY" } { $_ -like "Überstunden abfeiern" } { $planningType += "OVERTIME" } { $_ -in ("VACATION", "ILLNESS", "ABSENCE", "STAND_BY", "OVERTIME") } { $planningType += $_ } default { Stop-PSFFunction -Message "Unhandled Type '$($absenceType)', developers mistake" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "VacationType", "SwitchException" } } } $planningType = $planningType | Sort-Object -Unique Write-PSFMessage -Level Verbose -Message "Filtering on VacationRequestType '$( [string]::Join("', '", [array]$planningType) )'" } # Parameter AbsenceSubType if ($AbsenceSubTypeName) { Write-PSFMessage -Level Verbose -Message "Processing lookup on filtering for AbsenceSubType '$( [string]::Join("', '", [array]$AbsenceSubTypeName) )'" $AbsenceSubTypeId = foreach ($item in $AbsenceSubTypeName) { $result = ConvertFrom-NameCache -Name $item -Type VacationAbsenceSubTypes -Verbose:$false if (-not $result) { Stop-PSFFunction -Message "AbsenceSubType '$($item)' not found. Unable to query VacationRequests." -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "VacationAbsenceSubTypes", "CacheException" } else { $result } } Write-PSFMessage -Level System -Message "Filtering on AbsenceSubTypeId '$( [string]::Join("', '", [array]$AbsenceSubTypeId) )'" } #endregion parameter validation # Prepare body $body = @{} if ($Year) { $body.Add("year", $Year) } if ($Month) { $body.Add("month", $Month) } if ($EmployeeId) { $body.Add("employeeIds", [array]($EmployeeId)) } if ($DepartmentId) { $body.Add("departmentIds", [array]($DepartmentId)) } if ($planningType) { $body.Add("planningTypes", [array]($planningType)) } if ($AbsenceSubTypeId) { $body.Add("planningAdditionalIds", [array]($AbsenceSubTypeId)) } if ($ExcludeVacationRequestId) { $body.Add("excludeVacationRequestIds", [array]($ExcludeVacationRequestId)) } if ($State) { $body.Add("statesOnly", [array]($State)) } if ($CheckPermission) { $body.Add("checkPermissions", $CheckPermission) } if ($AddFrontendValue) { $body.Add("addFrontendValues", $AddFrontendValue) } Write-PSFMessage -Level Debug -Message "Prepared body for API request with parameters: '$( [string]::Join("', '", [array]($body.Keys)) )'" -Data $body -Tag "VacationRequest", "Query" $response = Invoke-TANSSRequest -Type "PUT" -ApiPath $apiPath -Body $body -Token $Token Write-PSFMessage -Level Verbose -Message "Found $( ([array]($response.content.vacationRequests)).count ) request" -Tag "VacationRequest", "Output" Push-DataToCacheRunspace -MetaData $response.meta foreach ($vacationRequest in $response.content.vacationRequests) { Write-PSFMessage -Level Debug -Message "Generating '$($vacationRequest.planningType)' request Id:$($vacationRequest.Id) with status '$($vacationRequest.status)" -Tag "VacationRequest", "Output" [TANSS.Vacation.Request]@{ BaseObject = $vacationRequest Id = $vacationRequest.id } } } Default { Stop-PSFFunction -Message "Unhandled ParameterSet '$($parameterSetName)', developers mistake" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "SwitchException", "ParameterSet" } } } end {} } function New-TANSSVacationRequest { <# .Synopsis New-TANSSVacationRequest .DESCRIPTION Create a new vacation/absence request within TANSS for a specified employee on a date period There are various types of "absence": - Vacation - Illness - Absence - Standby - Overtime The command is called with a paramiter called like the absence type to request The type "Absence" can have a subset of additional types. They can be specified by name (Tabcompletion is available), or by a TANSS.Vacation.AbsenceSubType object. The additional absence types can be queried by the command "Get-TANSSVacationAbsenceSubType" .PARAMETER Vacation Switch parameter to command the creation of a vacation request .PARAMETER Illness Switch parameter to command the creation of a Illness record .PARAMETER Absence Switch parameter to command the creation of a absence record .PARAMETER AbsenceSubType TANSS.Vacation.AbsenceSubType object to specify what kind of absence subtype to create .PARAMETER AbsenceSubTypeName The name of the absence subtype to create .PARAMETER Standby Switch parameter to command the creation of a Standby record .PARAMETER Overtime Switch parameter to command the creation of a Overtime record .PARAMETER EmployeeId The ID of the employee to create to request/record for .PARAMETER StartDate The start date .PARAMETER EndDate The end date .PARAMETER HalfDayStart Boolean to specify if the first day is created as a half day (forenoon not in the absence) .PARAMETER HalfDayEnd Boolean to specify if the last day is created as a half day (afternoon not in the absence) .PARAMETER Description Optional description for the request/record .PARAMETER Date The creation of the request/record By default this is the current date. .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> New-TANSSVacationRequest -Illness -EmployeeId 10 -Start "01/02/2023" -End "01/03/2023" Creates an illness record for employee with ID 10 for second of january 2023 to third of january 2023 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")] [CmdletBinding( SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Vacation.Request])] Param( [Parameter(ParameterSetName = "Vacation", Mandatory = $true)] [switch] $Vacation, [Parameter(ParameterSetName = "Illness", Mandatory = $true)] [switch] $Illness, [Parameter(ParameterSetName = "Absence", Mandatory = $true)] [Parameter(ParameterSetName = "AbsenceWithAbsenceObject", Mandatory = $true)] [Parameter(ParameterSetName = "AbsenceWithAbsenceName", Mandatory = $true)] [switch] $Absence, [Parameter(ParameterSetName = "AbsenceWithAbsenceObject", Mandatory = $true)] [TANSS.Vacation.AbsenceSubType] $AbsenceSubType, [Parameter(ParameterSetName = "AbsenceWithAbsenceName", Mandatory = $true)] [string] $AbsenceSubTypeName, [Parameter(ParameterSetName = "Standby", Mandatory = $true)] [switch] $Standby, [Parameter(ParameterSetName = "Overtime", Mandatory = $true)] [switch] $Overtime, [int[]] $EmployeeId, [Parameter(Mandatory = $true)] [datetime] $StartDate, [Parameter(Mandatory = $true)] [datetime] $EndDate, [Alias("StartHalfDay")] [bool] $HalfDayStart = $false, [Alias("EndHalfDay")] [bool] $HalfDayEnd = $false, [Alias("Reason", "RequestReason")] [string] $Description, [Alias("RequestDate")] [datetime] $Date = (Get-Date), [TANSS.Connection] $Token ) begin { # Validation - Basic checks if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" -Tag "VacationRequest" #region Validation # Check dates if ($StartDate -gt $EndDate) { Stop-PSFFunction -Message "Specified dates are not valid! Please check dates, StartDate '$($StartDate)' is greater then EndDate '$($EndDate))'" -EnableException $true -Cmdlet $pscmdlet } # Fallback to employeeId from token if no requestorId is set if (-not $EmployeeId) { Write-PSFMessage -Level Verbose -Message "No Employee specified, using current logged in employee '$($Token.UserName)' (Id:$($Token.EmployeeId))" -Tag "VacationRequest", "EmployeeId" $EmployeeId = $Token.EmployeeId } # Find additional AbsenceSubType from specified name if ($parameterSetName -like "AbsenceWithAbsenceName") { Write-PSFMessage -Level System -Message "Gathering TANSS absence type '$($AbsenceSubTypeName)'" -Tag "VacationRequest", "AbsenceSubType", "Lookup" $tmpWhatIfPreference = $WhatIfPreference $WhatIfPreference = $fals $AbsenceSubType = Get-TANSSVacationAbsenceSubType -Name $AbsenceSubTypeName -Token $Token -ErrorAction Ignore $WhatIfPreference = $tmpWhatIfPreference Remove-Variable tmpWhatIfPreference -Force -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false if ($AbsenceSubType) { Write-PSFMessage -Level Verbose -Message "Found AbsenceSubTypeId '$($AbsenceSubType.Id)' for '$($AbsenceSubTypeName)'" } else { Stop-PSFFunction -Message "Unable to find AbsenceSubType '$($AbsenceSubTypeName)'" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "AbsenceSubType" } } # set planningType switch ($parameterSetName) { { $_ -like "Vacation" } { $planningType = "VACATION" } { $_ -like "Illness" } { $planningType = "ILLNESS" } { $_ -like "Absence*" } { $planningType = "ABSENCE" } { $_ -like "Standby" } { $planningType = "STAND_BY" } { $_ -like "Overtime" } { $planningType = "OVERTIME" } Default { Stop-PSFFunction -Message "Unhandled ParameterSetName. Unable to set planningType for VacationRequest. Developers mistake!" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "PlanningType" } } #endregion Validation - checking parameters foreach ($requesterId in $EmployeeId) { $_requestDate = [int][double]::Parse((Get-Date -Date $Date.ToUniversalTime() -UFormat %s)) # gathering absence object $plannedVactionRequest = Request-TANSSVacationRequestObject -EmployeeId $requesterId -Type $planningType -StartDate $StartDate -EndDate $EndDate -Token $Token if(-not $plannedVactionRequest) { continue } Write-PSFMessage -Level Verbose -Message "Adding RequestDate and optional description to VacationRequest object" -Tag "VacationRequest", "VactionRequestObject" $plannedVactionRequest.BaseObject.requestReason = "$($Description)" $plannedVactionRequest.BaseObject.requestDate = $_requestDate if ($AbsenceSubType) { Write-PSFMessage -Level Verbose -Message "Insert additionalAbsenceSubType '$($AbsenceSubType.Name)' to VacationRequest object" -Tag "VacationRequest", "VactionRequestObject", "AbsenceSubType" $plannedVactionRequest.BaseObject.planningAdditionalId = $AbsenceSubType.Id } $days = $plannedVactionRequest.Days if($HalfDayStart) { $days[0].Afternoon = $false } if($HalfDayEnd) { $days[-1].Forenoon = $false } $plannedVactionRequest.Days = $days Remove-Variable -Name days -Force -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false -ErrorAction Ignore -WarningAction Ignore -InformationAction Ignore $body = $plannedVactionRequest.BaseObject | ConvertTo-PSFHashtable # enforce types, due to some strange conversation behaviour sometimes $body.days = [array]$body.days $body.startDate = [int]$body.startDate $body.endDate = [int]$body.endDate $apiPath = Format-ApiPath -Path "api/v1/vacationRequests" $daycount = 0 + ($plannedVactionRequest.days | Measure-Object | Select-Object -ExpandProperty Count) if ($pscmdlet.ShouldProcess("VacationRequest for employeeId '$($RequesterId)' with $($daycount) days on planningType '$($planningType)' on dates '$(Get-Date -Date $StartDate -Format 'yyyy-MM-dd')'-'$(Get-Date -Date $EndDate -Format 'yyyy-MM-dd')'", "Add")) { Write-PSFMessage -Level Verbose -Message "Add VacationRequest for employeeId '$($RequesterId)' with $($daycount) days on planningType '$($planningType)' on dates '$(Get-Date -Date $StartDate -Format 'yyyy-MM-dd')'-'$(Get-Date -Date $EndDate -Format 'yyyy-MM-dd')'" -Tag "VacationRequest", "VactionRequestObject" # Create the object within TANSS $result = Invoke-TANSSRequest -Type POST -ApiPath $apiPath -Body $body -Token $Token Write-PSFMessage -Level Verbose -Message "$($result.meta.text) - RequestId '$($result.content.id)' with status '$($result.content.status)'" -Tag "VacationRequest", "VactionRequestObject", "VacationRequestResult" # output the result [TANSS.Vacation.Request]@{ BaseObject = $result.content Id = $result.content.id } } } } end { } } function Out-TANSSVacationRequestPdf { <# .Synopsis Out-TANSSVacationRequestPdf .DESCRIPTION Write a PDF for a vacation request from Tanss. This is only available for VacataRequest of Type "vacation" .PARAMETER InputObject TANSS.Vacation.Request object to output pdf file for .PARAMETER Id The Id of the vacation request .PARAMETER Path The path to output the pdf to .PARAMETER PassThru Switch parameter. If specified, the file object will be thrown out to the console .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Out-TANSSVacationRequestPdf Description .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ByID", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] Param( [Parameter( ParameterSetName = "ByInputObject", Mandatory = $true, ValueFromPipeline = $true )] [TANSS.Vacation.Request[]] $InputObject, [Parameter( ParameterSetName = "ById", Mandatory = $true, ValueFromPipeline = $true )] [Alias("RequestId", "VacationRequestId")] [int[]] $Id, [string] $Path, [switch] $PassThru, [TANSS.Connection] $Token ) begin { # Validation - Basic checks if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning # Check path if ($Path) { if($Path.Contains("\")) { # Check if pdf filename is specified if($Path.split("\")[-1] -like "*.pdf") { # assume explicit specified PDF $fileName = $Path.split("\")[-1] $resolved = Resolve-Path -Path $Path.TrimEnd( $fileName ) -ErrorAction Ignore } else { # assume path $resolved = Resolve-Path -Path $Path -ErrorAction Ignore } if($resolved) { $_path = $resolved | Select-Object -ExpandProperty Path if($fileName) { $_path = "$($_path)\$($fileName)" } } else { Stop-PSFFunction -Message "Path '$($Path)' is not valid" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "OutPdf", "PathException" } } else { if($Path -notlike "*.pdf") { Write-PSFMessage -Level Warning -Message "Unusual behaviour, filename for outputfile does not contain '.pdf'" -Tag "VacationRequest", "OutPdf", "FileName" } $fileName = $Path $_path = "$(Resolve-Path -Path ".\" -ErrorAction Ignore | Select-Object -ExpandProperty Path)\$fileName" if(-not $_path) { Stop-PSFFunction -Message "Path '$($Path)' is not valid" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "OutPdf", "PathException" } } } else { $_path = "$(Resolve-Path -Path ".\" | Select-Object -ExpandProperty Path)\" } Write-PSFMessage -Level System -Message "Specified path: $($_path)" -Tag "VacationRequest", "OutPdf" } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" -Tag "VacationRequest", "OutPdf" # If Id is piped in, query vacationRequests from TANSS if ($parameterSetName -like "ById*") { $InputObject = foreach ($requestId in $Id) { Get-TANSSVacationRequest -Id $requestId -Token $Token } } foreach ($vacationRequest in $InputObject) { Write-PSFMessage -Level Verbose -Message "Working on '$($vacationRequest.TypeName)' VacationRequest '$($vacationRequest.Id)' ($($vacationRequest.EmployeeName)) for range '$($vacationRequest.StartDate) - $($vacationRequest.EndDate)'" -Tag "VacationRequest", "OutPdf" if ($vacationRequest.Type -ne "Vacation") { Write-PSFMessage -Level Warning -Message "VacationRequest '$(($vacationRequest.Id))' is not of type 'Vacation'. PDF output only supported for VacationRequest of type 'vacation'" -Tag "VacationRequest", "OutPdf", "Warning" continue } if (-not $fileName) { $name = "urlaubsantrag_ID$($vacationRequest.Id)_$(Get-Date -Date $vacationRequest.StartDate -Format "yyyy-MM-dd")_$(Get-Date -Date $vacationRequest.EndDate -Format "yyyy-MM-dd").pdf" Write-PSFMessage -Level Verbose -Message "No name specified output file. Using filename: $($name)" -Tag "VacationRequest", "OutPdf", "FileName" $_path = Join-Path -Path $_path -ChildPath $name Write-PSFMessage -Level System -Message "Output path is: $($_path)" -Tag "VacationRequest", "OutPdf", "Path" } $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/$($vacationRequest.Id)/pdf" #$apiPath = "backend/api/v1/vacationRequests/$($vacationRequest.Id)/pdf" $downloadLink = Invoke-TANSSRequest -Type Get -ApiPath $apiPath -Pdf if ($pscmdlet.ShouldProcess("PDF for vacation request '$vacationRequest.Id' from '$($vacationRequest.EmployeeName)' to '$_path'", "Out")) { Write-PSFMessage -Level Verbose -Message "Ouput PDF for vacation request '$vacationRequest.Id' from '$($vacationRequest.EmployeeName)' to '$_path'" -Tag "VacationRequest", "OutPdf" $apiPath = Format-ApiPath -Path $downloadLink.content.url #$apiPath = "backend/$($downloadLink.content.url)" $param = @{ "Uri" = "$($Token.Server)/$($apiPath)" "Headers" = @{ "apiToken" = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token.AccessToken)) } "Method" = "GET" "ContentType" = 'application/json; charset=UTF-8' "Verbose" = $false "Debug" = $false "ErrorAction" = "Stop" "ErrorVariable" = "invokeError" "OutFile" = $_path } try { Invoke-RestMethod @param } catch { Write-PSFMessage -Level Error -Message "Error on rest call: $($invokeError.ErrorRecord.Exception.Message)" -Tag "VacationRequest", "OutPdf", "RestException" -ErrorRecord $invokeError.ErrorRecord -PSCmdlet $pscmdlet continue } if($PassThru) { Get-Item -Path $_path } } } } end { } } function Remove-TANSSVacationRequest { <# .Synopsis Remove-TANSSVacationRequest .DESCRIPTION Remove a vacation request .PARAMETER InputObject TANSS.Vacation.Request to remove .PARAMETER Id The Id of the VacationRequest record to remove .PARAMETER Force Process the removal quietly. .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Get-TANSSVacationRequest -Id 10 | Remove-TANSSVacationRequest Remove the VacationRequest Id 10 .EXAMPLE PS C:\> Remove-TANSSVacationRequest -Id 10 -Force Remove the VacationRequest Id 10 without asking for confirmation .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ById", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'High' )] Param( [Parameter( ParameterSetName = "ByInputObject", Mandatory = $true, ValueFromPipeline = $true )] [TANSS.Vacation.Request[]] $InputObject, [Parameter( ParameterSetName = "ById", Mandatory = $true, ValueFromPipeline = $true )] [Alias("RequestId", "VacationRequestId")] [int[]] $Id, [switch] $Force, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" # If Id is piped in, query vacationRequests from TANSS if ($parameterSetName -like "ById") { $InputObject = foreach ($requesterId in $Id) { Write-PSFMessage -Level Verbose -Message "Query VacationRequestId $($requesterId)" -Tag "VacationRequest", "Query" # Query VacationRequest by ID $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/$($requesterId)" $response = Invoke-TANSSRequest -Type "GET" -ApiPath $apiPath -Token $Token -Confirm:$false # Output result Write-PSFMessage -Level Verbose -Message "$($response.meta.text): VacationRequestId $($requesterId)" -Tag "VacationRequest", "Query" [TANSS.Vacation.Request]@{ BaseObject = $response.content Id = $response.content.id } } } if (-not $InputObject) { Write-PSFMessage -Level Error -Message "No VacationRequests to remove" -Tag "VacationRequest", "Set", "NoData" -PSCmdlet $pscmdlet } else { $processRemoval = $false foreach ($vacationRequest in $InputObject) { # Check on Force parameter, otherwise process shouldprocess if ($Force) { $processRemoval = $true } else { if ($pscmdlet.ShouldProcess("VacationRequestId '$($vacationRequest.Id)' from '$($vacationRequest.EmployeeName)' on '$($vacationRequest.StartDate)-$($vacationRequest.EndDate)'", "Remove")) { $processRemoval = $true } } if ($processRemoval) { Write-PSFMessage -Level Verbose -Message "Remove VacationRequestId '$($vacationRequest.Id)' from '$($vacationRequest.EmployeeName)' on '$($vacationRequest.StartDate)-$($vacationRequest.EndDate)'" -Tag "VacationRequest", "Set", "Remove" # Remove VacationRequest $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/$($vacationRequest.Id)" $response = Invoke-TANSSRequest -Type DELETE -ApiPath $apiPath -Token $Token -Confirm:$false } } } } end { } } function Request-TANSSVacationRequestObject { <# .Synopsis Request-TANSSVacationRequestObject .DESCRIPTION Retrieve a vacation request object from TANSS. This object can be used to create a new VacationRequest .PARAMETER EmployeeId The ID of the employee to request for .PARAMETER EmployeeName The name of the employee to request for .PARAMETER StartDate The start date .PARAMETER EndDate The end date .PARAMETER Type Name of the request type Values can be tabcompleted, so you don't have to type Available: "Urlaub", "Krankheit", "Abwesenheit", "Bereitschaft", "Überstunden abfeiern", "VACATION", "ILLNESS", "ABSENCE", "STAND_BY", "OVERTIME" .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .EXAMPLE PS C:\> Request-TANSSVacationRequestObject -EmployeeId 10 -Type "Urlaub" -Start "01/02/2023" -End "01/03/2023" Request a object to create a new vacation request in the database for employee with ID 10. The output will be of type and from 2.1.2023 to 03.01.2023 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ApiNative", SupportsShouldProcess = $false, PositionalBinding = $true, ConfirmImpact = 'Low' )] [OutputType([TANSS.Vacation.Request])] Param( [Parameter( ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, ParameterSetName = "ApiNative" )] [int[]] $EmployeeId, [Parameter( ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true, ParameterSetName = "UserFriendly", Mandatory = $true )] [string[]] $EmployeeName, [Parameter(Mandatory = $true)] [string] $Type, [Parameter(Mandatory = $true)] [datetime] $StartDate, [Parameter(Mandatory = $true)] [datetime] $EndDate, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning # Parameter Type if ($Type) { Write-PSFMessage -Level System -Message "Processing Type '$($Type)'" -Tag "VacationRequest", "Request", "VacationType" switch ($Type) { { $_ -like "Urlaub" } { $planningType = "VACATION" } { $_ -like "Krankheit" } { $planningType = "ILLNESS" } { $_ -like "Abwesenheit*" } { $planningType = "ABSENCE" } { $_ -like "Bereitschaft" } { $planningType = "STAND_BY" } { $_ -like "Überstunden abfeiern" } { $planningType = "OVERTIME" } { $_ -in ("VACATION", "ILLNESS", "ABSENCE", "STAND_BY", "OVERTIME") } { $planningType = $_ } default { Stop-PSFFunction -Message "Unhandled Type '$($Type)', developers mistake" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "Request", "VacationType", "SwitchException" } } Write-PSFMessage -Level System -Message "Using VacationRequestType '$($planningType)'" -Tag "VacationRequest", "Request", "VacationType" } } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" -Tag "VacationRequest", "Request" if ($EmployeeName) { Write-PSFMessage -Level System -Message "Convert EmployeeId from EmployeeName" -Tag "VacationRequest", "Request", "EmployeeName" $EmployeeId = @() foreach ($name in $EmployeeName) { Write-PSFMessage -Level System -Message "Working on employee name '$($name)'" -Tag "VacationRequest", "Request", "EmployeeName" $id = ConvertFrom-NameCache -Name $name -Type "Employees" if (-not $id) { Write-PSFMessage -Level Warning -Message "No Id for employee '$($name)' found" -Tag "VacationRequest", "Request", "EmployeeName", "Warning" } else { Write-PSFMessage -Level System -Message "Found id '$($id)' for employee '$($name)'" -Tag "VacationRequest", "Request", "EmployeeName" } $EmployeeId += $id } } # Fallback to employeeId from token if no requestorId is set if (-not $EmployeeId) { Write-PSFMessage -Level Verbose -Message "No Employee specified, using current logged in employee '$($Token.UserName)' (Id:$($Token.EmployeeId))" -Tag "VacationRequest", "Request", "EmployeeId" $EmployeeId = $Token.EmployeeId } foreach ($requesterId in $EmployeeId) { Write-PSFMessage -Level System -Message "Request $planningType vacation object for id '$($id)' on dates '$(Get-Date -Date $StartDate -Format 'yyyy-MM-dd')'-'$(Get-Date -Date $EndDate -Format 'yyyy-MM-dd')'" -Tag "VacationRequest", "Request" # gathering absence object $_startDate = [int][double]::Parse((Get-Date -Date $StartDate.Date.ToUniversalTime() -UFormat %s)) $_endDate = [int][double]::Parse((Get-Date -Date $EndDate.Date.ToUniversalTime() -UFormat %s)) $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/properties" $body = @{ "requesterId" = $requesterId "planningType" = $planningType "startDate" = $_startDate "endDate" = $_endDate } $plannedVactionRequest = Invoke-TANSSRequest -Type POST -ApiPath $apiPath -Body $body -Token $Token | Select-Object -ExpandProperty content if ($plannedVactionRequest) { Write-PSFMessage -Level Verbose -Message "Received VacationRequest object with $($plannedVactionRequest.days | Measure-Object | Select-Object -ExpandProperty Count) days on planningType '$($planningType)'" -Tag "VacationRequest", "VactionRequestObject" # output object [TANSS.Vacation.Request]@{ BaseObject = $plannedVactionRequest Id = $plannedVactionRequest.id } } else { Stop-PSFFunction -Message "Unable gathering '$($planningType)' VacationRequest object for employeeId '$($requesterId)' on dates '$(Get-Date -Date $StartDate -Format 'yyyy-MM-dd')'-'$(Get-Date -Date $EndDate -Format 'yyyy-MM-dd')' from '$($Token.Server)'" -Cmdlet $pscmdlet } } } end {} } function Set-TANSSVacationEntitlement { <# .Synopsis Set-TANSSVacationEntitlement .DESCRIPTION Modifies yearly entitlements for employees .PARAMETER InputObject TANSS.Vacation.Entitlement object to modify .PARAMETER EmployeeId The id of the employee to modfiy .PARAMETER EmployeeName The name of the employee to modfiy .PARAMETER Year The year to modify .PARAMETER Days Amount of days to set .PARAMETER TransferedDays Amount of days transfered from the last year .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Set-VacationEntitlement -Year 2022 -EmployeeId 2 -Days 30 Set entitlement for employee ID 2 to 30 days in year 2022 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "Default", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Vacation.Entitlement])] Param( [Parameter( ParameterSetName = "ByInputObject", Mandatory = $true, ValueFromPipeline = $true )] [TANSS.Vacation.Entitlement[]] $InputObject, [Parameter( ParameterSetName = "ById", Mandatory = $true, ValueFromPipeline = $true )] [int[]] $EmployeeId, [Parameter( ParameterSetName = "ByName", Mandatory = $true, ValueFromPipeline = $true )] [string[]] $EmployeeName, [ValidateNotNullOrEmpty()] [int] $Year = (Get-Date).Year, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [Alias("NumberOfDays")] [int] $Days, [ValidateNotNullOrEmpty()] [Alias("DaysTransfered")] [int] $TransferedDays, [switch] $PassThru, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" -Tag "VacationEntitlement", "Set" if ($parameterSetName -notlike "ByInputObject") { $tempWhatIf = $WhatIfPreference $WhatIfPreference = $false $InputObject = Get-TANSSVacationEntitlement -Year $Year -Token $Token $WhatIfPreference = $tempWhatIf } # Filter on EmployeeName if ($parameterSetName -like "ByName") { $InputObject = foreach ($_employeeName in $EmployeeName) { $InputObject | Where-Object EmployeeName -like $_employeeName } Write-PSFMessage -Level Verbose -Message "Select $(([array]$InputObject).Count) records, by employee name '$([string]::Join("', '", ([array]$EmployeeName)))'" -Tag "VacationEntitlement", "Set", "Filtering" } # Filter on EmployeeId if ($parameterSetName -like "ById") { $InputObject = foreach ($_employeeId in $EmployeeId) { $InputObject | Where-Object EmployeeId -like $_employeeId } Write-PSFMessage -Level Verbose -Message "Select $(([array]$InputObject).Count) records, by employee id '$([string]::Join("', '", ([array]$EmployeeId)))'" -Tag "VacationEntitlement", "Set", "Filtering" } # Process VacationEntitlement modification foreach ($entitlement in $InputObject) { if ($pscmdlet.ShouldProcess("Vacation entitlement for '$($entitlement.EmployeeName)' to $($Days) days in $($Year)", "Set")) { Write-PSFMessage -Level Verbose -Message "Set vacation entitlement for '$($entitlement.EmployeeName)' to $($Days) days in $($Year)" -Tag "VacationEntitlement", "Set" # Prepare request $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/vacationDays" if ($TransferedDays) { $_transferred = $TransferedDays } else { $_transferred = 0 } $body = @{ "employeeId" = $entitlement.employeeId "year" = $entitlement.year "numberOfDays" = $Days "transferred" = $_transferred } # Set entitlement $response = Invoke-TANSSRequest -Type PUT -ApiPath $apiPath -Body $body -Token $Token # Output result if ($PassThru) { Write-PSFMessage -Level Verbose -Message "$($response.meta.text): Going to output $(([array]($response.content)).count) VacationEntitlement records in year $($Year)" -Tag "VacationEntitlement", "Query" foreach ($newEntitlement in $response.content) { $_baseObject = $entitlement.BaseObject $_baseObject.numberOfDays = $newEntitlement.numberOfDays if ($newEntitlement.transferred) { $_transferred = $newEntitlement.transferred if($_baseObject.TransferedDays) { $_baseObject.TransferedDays = $_transferred } } else { $_transferred = 0 } [TANSS.Vacation.Entitlement]@{ BaseObject = $_baseObject EmployeeId = $newEntitlement.employeeId Year = $newEntitlement.year NumberOfDays = $newEntitlement.numberOfDays TransferedDays = $_transferred } } } } } } end {} } function Set-TANSSVacationRequest { <# .Synopsis Set-TANSSVacationRequest .DESCRIPTION Modfiy a vacation/absence record within TANSS .PARAMETER InputObject TANSS.Vacation.Request object passed in to modify .PARAMETER Id The Id of the VacationRequest within TANSS service .PARAMETER Type Name of the request type Values can be tabcompleted, so you don't have to type Available: "Urlaub", "Krankheit", "Abwesenheit", "Bereitschaft", "Überstunden abfeiern", "VACATION", "ILLNESS", "ABSENCE", "STAND_BY", "OVERTIME" .PARAMETER AbsenceSubType TANSS.Vacation.AbsenceSubType object to set on the absense record .PARAMETER AbsenceSubTypeName For type "Abwesenheit", "ABSENCE" there are subtypes available This one specifies the name of the subtype to set on the absense record Values can be tabcompleted, so you don't have to type .PARAMETER StartDate Starting date for the record to modify .PARAMETER EndDate End date for the record to modify .PARAMETER Description Description to set on the record .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Set-TANSSVacationRequest -Id 123 -Description "new description" Change the description of the VacationRequest 123 to "new description" .EXAMPLE PS C:\> $vacationRequest | Set-TANSSVacationRequest -EndDate "01/31/2023" Set enddate to "01/31/2023" the request in variable $vacationRequest .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Vacation.Request])] Param( [Parameter( ParameterSetName = "ByInputObjectWithSubType", Mandatory = $true, ValueFromPipeline = $true )] [Parameter( ParameterSetName = "ByInputObjectWithSubTypeName", Mandatory = $true, ValueFromPipeline = $true )] [TANSS.Vacation.Request[]] $InputObject, [Parameter( ParameterSetName = "ByIdWithSubType", Mandatory = $true, ValueFromPipeline = $true )] [Parameter( ParameterSetName = "ByIdWithSubTypeName", Mandatory = $true, ValueFromPipeline = $true )] [Alias("RequestId", "VacationRequestId")] [int[]] $Id, [ValidateNotNullOrEmpty()] [string] $Type, [Parameter(ParameterSetName = "ByInputObjectWithSubType")] [Parameter(ParameterSetName = "ByIdWithSubType")] [ValidateNotNullOrEmpty()] [TANSS.Vacation.AbsenceSubType] $AbsenceSubType, [Parameter( ParameterSetName = "ByInputObjectWithSubTypeName", Mandatory = $true )] [Parameter( ParameterSetName = "ByIdWithSubTypeName", Mandatory = $true )] [ValidateNotNullOrEmpty()] [string] $AbsenceSubTypeName, [ValidateNotNullOrEmpty()] [datetime] $StartDate, [ValidateNotNullOrEmpty()] [datetime] $EndDate, [Alias("Reason", "RequestReason")] [string] $Description, [switch] $PassThru, [TANSS.Connection] $Token ) begin { # Validation - Basic checks if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning # Parameter Type if ($Type) { Write-PSFMessage -Level System -Message "Processing Type '$($Type)'" switch ($Type) { { $_ -like "Urlaub" } { $planningType = "VACATION" } { $_ -like "Krankheit" } { $planningType = "ILLNESS" } { $_ -like "Abwesenheit*" } { $planningType = "ABSENCE" } { $_ -like "Bereitschaft" } { $planningType = "STAND_BY" } { $_ -like "Überstunden abfeiern" } { $planningType = "OVERTIME" } { $_ -in ("VACATION", "ILLNESS", "ABSENCE", "STAND_BY", "OVERTIME") } { $planningType = $_ } default { Stop-PSFFunction -Message "Unhandled Type '$($Type)', developers mistake" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "VacationType", "SwitchException" } } Write-PSFMessage -Level System -Message "Using VacationRequestType '$($planningType)'" } } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" -Tag "VacationRequest" #region Validation # Check dates if (($StartDate -and $EndDate) -and ($StartDate -gt $EndDate)) { Stop-PSFFunction -Message "Specified dates are not valid! Please check dates, StartDate '$($StartDate)' is greater then EndDate '$($EndDate))'" -EnableException $true -Cmdlet $pscmdlet } # Find additional AbsenceSubType from specified name if ($parameterSetName -like "*WithSubTypeName") { Write-PSFMessage -Level System -Message "Gathering TANSS absence type '$($AbsenceSubTypeName)'" -Tag "VacationRequest", "AbsenceSubType", "Lookup" $tmpWhatIfPreference = $WhatIfPreference $WhatIfPreference = $fals $AbsenceSubType = Get-TANSSVacationAbsenceSubType -Name $AbsenceSubTypeName -Token $Token -ErrorAction Ignore $WhatIfPreference = $tmpWhatIfPreference Remove-Variable tmpWhatIfPreference -Force -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false if ($AbsenceSubType) { Write-PSFMessage -Level Verbose -Message "Found AbsenceSubTypeId '$($AbsenceSubType.Id)' for '$($AbsenceSubTypeName)'" } else { Stop-PSFFunction -Message "Unable to find AbsenceSubType '$($AbsenceSubTypeName)'" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "AbsenceSubType" } } #endregion Validation - checking parameters # If Id is piped in, query vacationRequests from TANSS if ($parameterSetName -like "ById*") { $InputObject = foreach ($requesterId in $Id) { Write-PSFMessage -Level Verbose -Message "Query VacationRequestId $($requesterId)" -Tag "VacationRequest", "Query" # Query VacationRequest by ID $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/$($requesterId)" $response = Invoke-TANSSRequest -Type "GET" -ApiPath $apiPath -Token $Token -Confirm:$false # Output result Write-PSFMessage -Level Verbose -Message "$($response.meta.text): VacationRequestId $($requesterId)" -Tag "VacationRequest", "Query" [TANSS.Vacation.Request]@{ BaseObject = $response.content Id = $response.content.id } } } foreach ($vacationRequest in $InputObject) { Write-PSFMessage -Level Verbose -Message "Working on '$($vacationRequest.TypeName)' VacationRequest '$($vacationRequest.Id)' ($($vacationRequest.EmployeeName)) for range '$($vacationRequest.StartDate) - $($vacationRequest.EndDate)'" -Tag "VacationRequest", "Set" # earlier Startdate should be set --> VacationDay objects have to be added to days property if ($StartDate -and ($StartDate -lt $vacationRequest.StartDate)) { Write-PSFMessage -Level System -Message "StartDate found, need to add $(($vacationRequest.EndDate - $StartDate).Days) days to VacationRequest" -Tag "VacationRequest", "Set", "AddDays" $plannedVactionRequest = Request-TANSSVacationRequestObject -EmployeeId $vacationRequest.BaseObject.requesterId -Type $vacationRequest.BaseObject.planningType -StartDate $StartDate -EndDate $vacationRequest.EndDate -Token $Token if(-not $plannedVactionRequest) { continue } # add days new days to vacation request $vacationRequest.Days = $plannedVactionRequest.Days Write-PSFMessage -Level System -Message "VacationRequest '$($vacationRequest.Id)' is modified with ne Startdate, new range '$($vacationRequest.StartDate) - $($vacationRequest.EndDate)'" -Tag "VacationRequest", "Set", "AddDays" Remove-Variable -Name apiPath, _startDate, body, plannedVactionRequest -Force -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false -ErrorAction:Ignore -WarningAction:Ignore -InformationAction:Ignore } # Later Enddate should be set --> VacationDay objects have to be added to days property if ($EndDate -and ($EndDate -gt $vacationRequest.EndDate)) { Write-PSFMessage -Level System -Message "EndDate found, need to add $(($EndDate - $vacationRequest.EndDate).Days) days to VacationRequest" -Tag "VacationRequest", "Set", "AddDays" # Query addiontial days $plannedVactionRequest = Request-TANSSVacationRequestObject -EmployeeId $vacationRequest.BaseObject.requesterId -Type $vacationRequest.BaseObject.planningType -StartDate $vacationRequest.StartDate -EndDate $EndDate -Token $Token if(-not $plannedVactionRequest) { continue } # add days new days to vacation request $vacationRequest.Days = $plannedVactionRequest.Days Write-PSFMessage -Level System -Message "VacationRequest '$($vacationRequest.Id)' is modified with ne Startdate, new range '$($vacationRequest.StartDate) - $($vacationRequest.EndDate)'" -Tag "VacationRequest", "Set", "AddDays" Remove-Variable -Name apiPath, _endDate, body, plannedVactionRequest -Force -WhatIf:$false -Confirm:$false -Verbose:$false -Debug:$false -ErrorAction:Ignore -WarningAction:Ignore -InformationAction:Ignore } # Later StartDate should be set --> have to be remove days from VacationRequest objects if ($StartDate -and ($StartDate -ne $vacationRequest.StartDate)) { Write-PSFMessage -Level System -Message "StartDate found, need to remove $(($StartDate - $vacationRequest.StartDate).Days) day(s) from VacationRequest '$($vacationRequest.Id)'" -Tag "VacationRequest", "Set", "RemoveDays" $_startDate = [int][double]::Parse((Get-Date -Date $StartDate.Date.ToUniversalTime() -UFormat %s)) $vacationRequest.BaseObject.startDate = $_startDate $vacationRequest.Days = $vacationRequest.Days | Where-Object date -ge $StartDate } # Earlier EndDate should be set --> have to be remove days from VacationRequest objects if ($EndDate -and ($EndDate -ne $vacationRequest.EndDate)) { Write-PSFMessage -Level System -Message "EndDate found, need to remove $(($EndDate - $vacationRequest.EndDate).Days * -1) day(s) from VacationRequest '$($vacationRequest.Id)'" -Tag "VacationRequest", "Set", "RemoveDays" $_endDate = [int][double]::Parse((Get-Date -Date $EndDate.Date.ToUniversalTime() -UFormat %s)) $vacationRequest.BaseObject.endDate = $_endDate $vacationRequest.Days = $vacationRequest.Days | Where-Object date -le $EndDate } # Set Description if ($Description) { Write-PSFMessage -Level System -Message "Description found, going to change description from '$($vacationRequest.Description)' to '$($Description)'" -Tag "VacationRequest", "Set", "RequestDate" $vacationRequest.BaseObject.requestReason = "$($Description)" } # Set type if ($planningType) { Write-PSFMessage -Level System -Message "Type found, going to change Type from '$($vacationRequest.Type)' to '$($planningType)'" -Tag "VacationRequest", "Set", "Type" $vacationRequest.BaseObject.planningType = $planningType # remove additional planning type when change from absence so something else if (($vacationRequest.BaseObject.planningType -notlike "ABSENCE") -and ($vacationRequest.BaseObject.planningAdditionalId -gt 0)) { $vacationRequest.BaseObject.planningAdditionalId = 0 } } # Set AbsenceSubType if ($AbsenceSubType -or $AbsenceSubTypeName) { if (($planningType -like "ABSENCE") -and $AbsenceSubTypeName) { $AbsenceSubType = Get-TANSSVacationAbsenceSubType -Name $AbsenceSubTypeName Write-PSFMessage -Level Verbose -Message "Set additionalAbsenceSubType '$($AbsenceSubType.Name)' to VacationRequest object" -Tag "VacationRequest", "Set", "AbsenceSubType" $vacationRequest.BaseObject.planningAdditionalId = $AbsenceSubType.Id } elseif (($planningType -notlike "ABSENCE") -and ($AbsenceSubType -or $AbsenceSubTypeName)) { Write-PSFMessage -Level Important -Message "AbsenceSubType specified, but not valid '$(if($planningType){"for '$($planningType)'"} else { "without Type"})'! AbsenceSubTypes are only possible with Type 'Abwesenheit'/'ABSENCE'. Setting will be ignored" -Tag "VacationRequest", "AbsenceSubType" } } # Make the change effective within TANSS $body = $vacationRequest.BaseObject | ConvertTo-PSFHashtable $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/$($vacationRequest.Id)" if ($pscmdlet.ShouldProcess("VacationRequest for employeeId '$($vacationRequest.EmployeeId)' with $($vacationRequest.days | Measure-Object | Select-Object -ExpandProperty Count) days on planningType '$($vacationRequest.Type)' on dates '$(Get-Date -Date $vacationRequest.StartDate -Format 'yyyy-MM-dd')'-'$(Get-Date -Date $vacationRequest.EndDate -Format 'yyyy-MM-dd')'", "Set")) { Write-PSFMessage -Level Verbose -Message "Set VacationRequest for employeeId '$($vacationRequest.EmployeeId)' with $($vacationRequest.days | Measure-Object | Select-Object -ExpandProperty Count) days on planningType '$($vacationRequest.Type)' on dates '$(Get-Date -Date $vacationRequest.StartDate -Format 'yyyy-MM-dd')'-'$(Get-Date -Date $vacationRequest.EndDate -Format 'yyyy-MM-dd')'" -Tag "VacationRequest", "Set" # Create the object within TANSS $result = Invoke-TANSSRequest -Type PUT -ApiPath $apiPath -Body $body -Token $Token Write-PSFMessage -Level Verbose -Message "$($result.meta.text) - RequestId '$($result.content.id)' with status '$($result.content.status)'" -Tag "VacationRequest", "VactionRequestObject", "VacationRequestResult" # output the result if ($result -and $PassThru) { [TANSS.Vacation.Request]@{ BaseObject = $result.content Id = $result.content.id } } } } } end { } } function Set-TANSSVacationRequestStatus { <# .Synopsis Set-TANSSVacationRequestStatus .DESCRIPTION Approve or decline a vacation request within TANSS .PARAMETER InputObject TANSS.Vacation.Request object to modify .PARAMETER Id The id of the vacation request to modify .PARAMETER Status Status to set for the request Available values are: "Approve", "Decline" Values can be tabcompleted, so you don't have to type .PARAMETER Token The TANSS.Connection token to access api If not specified, the registered default token from within the module is going to be used .PARAMETER PassThru Outputs the result to the console .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .EXAMPLE PS C:\> Get-TANSSVacationRequest -Id 10 | Set-TANSSVacationRequestStatus -Status "Approve" Approve the VacationRequest Id 10 .EXAMPLE PS C:\> Set-TANSSVacationRequestStatus -Id 10 -Status "Decline" Decline the VacationRequest Id 10 .EXAMPLE PS C:\> $vacationRequests | Set-TANSSVacationRequestStatus -Status "Approve" -PassThru Approve all requests in variable '$vacationrequests' and output the (approved) VacationRequests on the console Assuming, the variable is build on something like: PS C:\>$vacationrequests = Get-TANSSVacationRequest -Year 2022 -Month 8 .NOTES Author: Andreas Bellstedt .LINK https://github.com/AndiBellstedt/PSTANSS #> [CmdletBinding( DefaultParameterSetName = "ById", SupportsShouldProcess = $true, PositionalBinding = $true, ConfirmImpact = 'Medium' )] [OutputType([TANSS.Vacation.Request])] Param( [Parameter( ParameterSetName = "ByInputObject", Mandatory = $true, ValueFromPipeline = $true )] [TANSS.Vacation.Request[]] $InputObject, [Parameter( ParameterSetName = "ById", Mandatory = $true, ValueFromPipeline = $true )] [Alias("RequestId", "VacationRequestId")] [int[]] $Id, [Parameter(Mandatory = $true)] [ValidateSet("Approve", "Decline")] [string] $Status, [switch] $PassThru, [TANSS.Connection] $Token ) begin { if (-not $Token) { $Token = Get-TANSSRegisteredAccessToken } Assert-CacheRunspaceRunning } process { $parameterSetName = $pscmdlet.ParameterSetName Write-PSFMessage -Level Debug -Message "ParameterNameSet: $($parameterSetName)" # If Id is piped in, query vacationRequests from TANSS if ($parameterSetName -like "ById") { $InputObject = foreach ($requesterId in $Id) { Write-PSFMessage -Level Verbose -Message "Query VacationRequestId $($requesterId)" -Tag "VacationRequest", "Query" # Query VacationRequest by ID $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/$($requesterId)" $response = Invoke-TANSSRequest -Type "GET" -ApiPath $apiPath -Token $Token # Output result Write-PSFMessage -Level Verbose -Message "$($response.meta.text): VacationRequestId $($requesterId)" -Tag "VacationRequest", "Query" [TANSS.Vacation.Request]@{ BaseObject = $response.content Id = $response.content.id } } } if (-not $InputObject) { Write-PSFMessage -Level Significant -Message "No VacationRequests found to set status on" -Tag "VacationRequest", "Set", "NoData" } else { switch ($Status) { "Approve" { $Status = "Approve" # Just to be sure with the spelling $body = @{ "status" = "APPROVED" } } "Decline" { $Status = "Decline" # Just to be sure with the spelling $body = @{ "status" = "DECLINED" } } Default { Stop-PSFFunction -Message "Unhandled status '$($Status)', developers mistake" -EnableException $true -Cmdlet $pscmdlet -Tag "VacationRequest", "SwitchException", "ParameterSet" } } foreach ($vacationRequest in $InputObject) { if ($pscmdlet.ShouldProcess("VacationRequestId '$($vacationRequest.Id)' from '$($vacationRequest.EmployeeName)' on '$($vacationRequest.StartDate)-$($vacationRequest.EndDate)'", $Status)) { Write-PSFMessage -Level Verbose -Message "$($Status) VacationRequestId '$($vacationRequest.Id)' from '$($vacationRequest.EmployeeName)' on '$($vacationRequest.StartDate)-$($vacationRequest.EndDate)'" -Tag "VacationRequest", "Set", $Status # Set status on VacationRequest $apiPath = Format-ApiPath -Path "api/v1/vacationRequests/$($vacationRequest.Id)" $response = Invoke-TANSSRequest -Type "PUT" -ApiPath $apiPath -Body $body -Token $Token Write-PSFMessage -Level Verbose -Message "VacationRequestId '$($vacationRequest.Id)' - $($response.meta.text)" -Tag "VacationRequest", "Set" # Output if Passthrough is set if($PassThru) { [TANSS.Vacation.Request]@{ BaseObject = $response.content Id = $response.content.id } } } } } } end { } } <# This is an example configuration file By default, it is enough to have a single one of them, however if you have enough configuration settings to justify having multiple copies of it, feel totally free to split them into multiple files. # Example Configuration Set-PSFConfig -Module 'PSTANSS' -Name 'Example.Setting' -Value 10 -Initialize -Validation 'integer' -Handler { } -Description "Example configuration setting. Your module can then use the setting using 'Get-PSFConfigValue'" #> #region Module configurations Set-PSFConfig -Module 'PSTANSS' -Name 'Import.DoDotSource' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be dotsourced on import. By default, the files of this module are read as string value and invoked, which is faster but worse on debugging." Set-PSFConfig -Module 'PSTANSS' -Name 'Import.IndividualFiles' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be imported individually. During the module build, all module code is compiled into few files, which are imported instead by default. Loading the compiled versions is faster, using the individual files is easier for debugging and testing out adjustments." Set-PSFConfig -Module 'PSTANSS' -Name 'API.RestPathPrefix' -Value "backend/" -Initialize -Validation 'string' -Description "Individual URI path for API webservices on TANSS server. HuckIT specifies the rest calls on 'https://api-doc.tanss.de/', but on prod-installations for TANSS, there maybe a prefix in the path of the api rest calls." #endregion Module configurations #region Module variables New-Variable -Name TANSSToken -Scope Script -Visibility Public -Description "Variable for registered token. This is for convinience use with the commands in the module" -Force #endregion Module variables #region Manual Lookup definitions [TANSS.Lookup]::LinkTypes = @{ "0" = "Keine Zuweisung" "1" = "PC" "2" = "Kunde (generell)" "3" = "Mitarbeiter" "4" = "Peripherie" "5" = "Komponente" "6" = "Lizenz" "24" = "Domain" } [TANSS.Lookup]::VacationTypesPredefinedApi = [ordered]@{ "VACATION" = "Urlaub" "ILLNESS" = "Krankheit" "ABSENCE" = "Abwesenheit" "STAND_BY" = "Bereitschaft" "OVERTIME" = "Überstunden abfeiern" } [TANSS.Lookup]::VacationAbsenceSubTypes = @{} #endregion Manual Lookup definitions <# Stored scriptblocks are available in [PsfValidateScript()] attributes. This makes it easier to centrally provide the same scriptblock multiple times, without having to maintain it in separate locations. It also prevents lengthy validation scriptblocks from making your parameter block hard to read. Set-PSFScriptblock -Name 'PSTANSS.ScriptBlockName' -Scriptblock { } #> Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.Companies" -ScriptBlock { [TANSS.Lookup]::Companies.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.Client" -ScriptBlock { [TANSS.Lookup]::Employees.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.Contracts" -ScriptBlock { [TANSS.Lookup]::Contracts.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.CostCenters" -ScriptBlock { [TANSS.Lookup]::CostCenters.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.Departments" -ScriptBlock { [TANSS.Lookup]::Departments.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.Employees" -ScriptBlock { [TANSS.Lookup]::Employees.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.OrderBys" -ScriptBlock { [TANSS.Lookup]::OrderBys.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.Phases" -ScriptBlock { [TANSS.Lookup]::Phases.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.Tags" -ScriptBlock { [TANSS.Lookup]::Tags.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.Tickets" -ScriptBlock { [TANSS.Lookup]::Tickets.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.TicketStates" -ScriptBlock { [TANSS.Lookup]::TicketStates.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.TicketTypes" -ScriptBlock { [TANSS.Lookup]::TicketTypes.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.VacationAbsenceSubTypes" -ScriptBlock { [TANSS.Lookup]::VacationAbsenceSubTypes.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.CarNumberPlate" -ScriptBlock { [TANSS.Lookup]::CarNumberplate.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.SupportTypes" -ScriptBlock { [TANSS.Lookup]::SupportTypes.Values } Register-PSFTeppScriptblock -Name "PSTANSS.CacheLookup.NotChargedReasons" -ScriptBlock { [TANSS.Lookup]::NotChargedReasons.Values } <# # Example: Register-PSFTeppScriptblock -Name "PSTANSS.alcohol" -ScriptBlock { 'Beer','Mead','Whiskey','Wine','Vodka','Rum (3y)', 'Rum (5y)', 'Rum (7y)' } #> # VacationRequestTypes Register-PSFTeppScriptblock -Name "PSTANSS.Parameter.GetVacationRequest.Type" -ScriptBlock { @([TANSS.Lookup]::VacationTypesPredefinedApi.Values, [TANSS.Lookup]::VacationTypesPredefinedApi.Keys) } <# # Example: Register-PSFTeppArgumentCompleter -Command Get-Alcohol -Parameter Type -Name PSTANSS.alcohol #> #region Ticket Register-PSFTeppArgumentCompleter -Command New-TANSSTicket -Parameter Company -Name "PSTANSS.CacheLookup.Companies" Register-PSFTeppArgumentCompleter -Command New-TANSSTicket -Parameter Client -Name "PSTANSS.CacheLookup.Client" Register-PSFTeppArgumentCompleter -Command New-TANSSTicket -Parameter Department -Name "PSTANSS.CacheLookup.Departments" Register-PSFTeppArgumentCompleter -Command New-TANSSTicket -Parameter EmployeeAssigned -Name "PSTANSS.CacheLookup.Employees" Register-PSFTeppArgumentCompleter -Command New-TANSSTicket -Parameter EmployeeTicketAdmin -Name "PSTANSS.CacheLookup.Employees" Register-PSFTeppArgumentCompleter -Command New-TANSSTicket -Parameter Phase -Name "PSTANSS.CacheLookup.Phases" Register-PSFTeppArgumentCompleter -Command New-TANSSTicket -Parameter Status -Name "PSTANSS.CacheLookup.TicketStates" Register-PSFTeppArgumentCompleter -Command New-TANSSTicket -Parameter Type -Name "PSTANSS.CacheLookup.TicketTypes" Register-PSFTeppArgumentCompleter -Command New-TANSSTicket -Parameter OrderBy -Name "PSTANSS.CacheLookup.OrderBys" Register-PSFTeppArgumentCompleter -Command Set-TANSSTicket -Parameter Company -Name "PSTANSS.CacheLookup.Companies" Register-PSFTeppArgumentCompleter -Command Set-TANSSTicket -Parameter Client -Name "PSTANSS.CacheLookup.Client" Register-PSFTeppArgumentCompleter -Command Set-TANSSTicket -Parameter Department -Name "PSTANSS.CacheLookup.Departments" Register-PSFTeppArgumentCompleter -Command Set-TANSSTicket -Parameter EmployeeAssigned -Name "PSTANSS.CacheLookup.Employees" Register-PSFTeppArgumentCompleter -Command Set-TANSSTicket -Parameter EmployeeTicketAdmin -Name "PSTANSS.CacheLookup.Employees" Register-PSFTeppArgumentCompleter -Command Set-TANSSTicket -Parameter Phase -Name "PSTANSS.CacheLookup.Phases" Register-PSFTeppArgumentCompleter -Command Set-TANSSTicket -Parameter Status -Name "PSTANSS.CacheLookup.TicketStates" Register-PSFTeppArgumentCompleter -Command Set-TANSSTicket -Parameter Type -Name "PSTANSS.CacheLookup.TicketTypes" Register-PSFTeppArgumentCompleter -Command Set-TANSSTicket -Parameter OrderBy -Name "PSTANSS.CacheLookup.OrderBys" #endregion Ticket #region Core Register-PSFTeppArgumentCompleter -Command Find-TANSSObject -Parameter CompanyName -Name "PSTANSS.CacheLookup.Companies" #endregion Core #region Employee Register-PSFTeppArgumentCompleter -Command New-TANSSEmployee -Parameter Department -Name "PSTANSS.CacheLookup.Departments" Register-PSFTeppArgumentCompleter -Command New-TANSSEmployee -Parameter CompanyName -Name "PSTANSS.CacheLookup.Companies" #endregion Employee #region Vacation Register-PSFTeppArgumentCompleter -Command Get-TANSSVacationType -Parameter Name -Name "PSTANSS.CacheLookup.VacationAbsenceSubTypes" Register-PSFTeppArgumentCompleter -Command New-TANSSVacationRequest -Parameter AbsenceSubTypeName -Name "PSTANSS.CacheLookup.VacationAbsenceSubTypes" Register-PSFTeppArgumentCompleter -Command Get-TANSSVacationRequest -Parameter EmployeeName -Name "PSTANSS.CacheLookup.Employees" Register-PSFTeppArgumentCompleter -Command Get-TANSSVacationRequest -Parameter DepartmentName -Name "PSTANSS.CacheLookup.Departments" Register-PSFTeppArgumentCompleter -Command Get-TANSSVacationRequest -Parameter Type -Name "PSTANSS.Parameter.GetVacationRequest.Type" Register-PSFTeppArgumentCompleter -Command Get-TANSSVacationRequest -Parameter AbsenceSubTypeName -Name "PSTANSS.CacheLookup.VacationAbsenceSubTypes" Register-PSFTeppArgumentCompleter -Command Set-TANSSVacationRequest -Parameter Type -Name "PSTANSS.Parameter.GetVacationRequest.Type" Register-PSFTeppArgumentCompleter -Command Set-TANSSVacationRequest -Parameter AbsenceSubTypeName -Name "PSTANSS.CacheLookup.VacationAbsenceSubTypes" Register-PSFTeppArgumentCompleter -Command Request-TANSSVacationRequestObject -Parameter Type -Name "PSTANSS.Parameter.GetVacationRequest.Type" Register-PSFTeppArgumentCompleter -Command Request-TANSSVacationRequestObject -Parameter EmployeeName -Name "PSTANSS.CacheLookup.Employees" Register-PSFTeppArgumentCompleter -Command Set-TANSSVacationEntitlement -Parameter EmployeeName -Name "PSTANSS.CacheLookup.Employees" #endregion Vacation #region TimeStamp Register-PSFTeppArgumentCompleter -Command Get-TANSSTimeStamp -Parameter EmployeeName -Name "PSTANSS.CacheLookup.Employees" Register-PSFTeppArgumentCompleter -Command New-TANSSTimeStamp -Parameter EmployeeName -Name "PSTANSS.CacheLookup.Employees" #endregion TimeStamp #region ProjektPhase Register-PSFTeppArgumentCompleter -Command Set-TANSSProjectPhase -Parameter PhaseName -Name "PSTANSS.CacheLookup.Phases" #endregion ProjektPhase New-PSFLicense -Product 'PSTANSS' -Manufacturer 'Andreas Bellstedt' -ProductVersion $script:ModuleVersion -ProductType Module -Name MIT -Version "1.0.0.0" -Date (Get-Date "2022-07-29") -Text @" Copyright (c) 2022 Andreas Bellstedt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. "@ $runspaceName = "TANSS.LookupValidation" $ScriptBlock = [System.Management.Automation.ScriptBlock]::Create( (Get-Content "$($script:ModuleRoot)\internal\scripts\Expand-TANSSCacheData.ps1" -Raw) ) if (Get-PSFRunspace -Name $runspaceName) { [TANSS.Cache]::StopValidationRunspace = $true Get-PSFRunspace -Name $runspaceName | Stop-PSFRunspace } Register-PSFRunspace -Name $runspaceName -ScriptBlock $ScriptBlock [TANSS.Cache]::StopValidationRunspace = $false Start-PSFRunspace -Name $runspaceName #endregion Load compiled code |