lib/Actions.ps1
# Actions Function New-TMAction { param( [Parameter(Mandatory = $false)][String]$TMSession = "Default", [Parameter(Mandatory = $true)][PSObject]$Action, [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer, [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL, [Parameter(Mandatory = $false)][PSObject]$Project, [Parameter(Mandatory = $false)][Switch]$Update, [Parameter(Mandatory = $false)][Switch]$Passthru ) ## Use the TM Session provided if ($global:TMSessions[$TMSession].TMVersion -like '4.6*') { New-TMAction46 @PSBoundParameters } else { New-TMAction474 @PSBoundParameters } } Function New-TMAction46 { param( [Parameter(Mandatory = $false)][String]$TMSession = "Default", [Parameter(Mandatory = $true)][PSObject]$Action, [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer, [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL, [Parameter(Mandatory = $false)][PSObject]$Project, [Parameter(Mandatory = $false)][Switch]$Passthru ) ## Get Session Configuration $TMSessionConfig = $global:TMSessions[$TMSession] if (-not $TMSessionConfig) { Write-Host 'TMSession: [' -NoNewline Write-Host $TMSession -ForegroundColor Cyan Write-Host '] was not Found. Please use the New-TMSession command.' Throw "TM Session Not Found. Use New-TMSession command before using features." } #Honor SSL Settings if ($TMSessionConfig.AllowInsecureSSL) { $TMCertSettings = @{SkipCertificateCheck = $true } } else { $TMCertSettings = @{SkipCertificateCheck = $false } } ## Check for existing Action $ActionCheck = Get-TMAction -Name $Action.name -TMSession $TMSession if ($ActionCheck) { if ($Passthru) { return $ActionCheck } else { return } } else { ## No Credential exists. Create it $instance = $Server.Replace('/tdstm', '') $instance = $instance.Replace('https://', '') $instance = $instance.Replace('http://', '') $uri = "https://" $uri += $instance $uri += '/tdstm/ws/apiAction' ## Lookup Cross References if (-not $Project) { $Project = $Projects | Where-Object { $_.name -eq $Action.project.name } } $ProjectID = $Project.id $ProviderID = (Get-TMProvider -TMSession $TMSession | Where-Object { $_.name -eq $Action.provider.name }).id $CredentialID = (Get-TMCredential -TMSession $TMSession | Where-Object { $_.name -eq $Action.credential.name }).id ## Fix up the object $Action.PSObject.properties.Remove('id') $Action.actionType = $Action.actionType.id $Action.project.id = $ProjectID $Action.provider.id = $ProviderID $Action.credential.id = $CredentialID $Action.version = 1 $PostBodyJSON = $Action | ConvertTo-Json -Depth 100 Set-TMHeaderAccept "JSON" -TMSession $TMSession Set-TMHeaderContentType "JSON" -TMSession $TMSession try { $response = Invoke-WebRequest -Method Post -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBodyJSON @TMCertSettings if ($response.StatusCode -eq 200) { $responseContent = $response.Content | ConvertFrom-Json if ($responseContent.status -eq "success") { if ($Passthru) { return $responseContent.data } else { return } } } } catch { Write-Host "Unable to create Action." return $_ } } } Function New-TMAction474 { param( [Parameter(Mandatory = $false)][String]$TMSession = "Default", [Parameter(Mandatory = $true)][PSObject]$Action, [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer, [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL, [Parameter(Mandatory = $false)][PSObject]$Project, [Parameter(Mandatory = $false)][Switch]$Update, [Parameter(Mandatory = $false)][Switch]$Passthru ) ## Get Session Configuration $TMSessionConfig = $global:TMSessions[$TMSession] if (-not $TMSessionConfig) { Write-Host 'TMSession: [' -NoNewline Write-Host $TMSession -ForegroundColor Cyan Write-Host '] was not Found. Please use the New-TMSession command.' Throw "TM Session Not Found. Use New-TMSession command before using features." } #Honor SSL Settings if ($TMSessionConfig.AllowInsecureSSL) { $TMCertSettings = @{SkipCertificateCheck = $true } } else { $TMCertSettings = @{SkipCertificateCheck = $false } } ## Check for existing Action $ActionCheck = Get-TMAction -Name $Action.name -TMSession $TMSession if ($ActionCheck -and -not $Update) { if ($PassThru) { return $ActionCheck } else { return } } else { ## No Credential exists. Create it $instance = $Server.Replace('/tdstm', '') $instance = $instance.Replace('https://', '') $instance = $instance.Replace('http://', '') $uri = "https://" $uri += $instance $uri += '/tdstm/ws/apiAction' ## Cleans the Action Name of characters we don't want $Action.name = $Action.name -replace "\\", '' -replace "\/", '' -replace "\:", '' -replace ">", '' -replace "<", '' -replace '\(', '' -replace '\)', '' -replace '\*', '' # $Action.name = $SafeActionName ## If The Existing action should be updated if ($ActionCheck -and $Update) { ## When the Action is an update, use important details from the current object. $Action.id = $ActionCheck.id $Action.dateCreated = $ActionCheck.dateCreated $Action.lastUpdated = $ActionCheck.lastUpdated $Action.debugEnabled = $ActionCheck.debugEnabled $Action.version = $ActionCheck.version $action.project = $ActionCheck.project ## Set the HTTP call details $uri += '/' + $Action.id $HttpMethod = 'Put' } else { ## Process as a new object. $HttpMethod = 'Post' $Action.PSObject.Properties.Remove('id') } ## Lookup Provider and Credential IDs, Field Specs if ([String]::IsNullOrWhiteSpace($Action.provider.name)) { Write-Error -Message "Provider name is blank for Action: $($Action.name)" return } $ProviderID = (Get-TMProvider -Name $Action.provider.name -TMSession $TMSession).id if (!$ProviderID) { # Create the provider if it doesn't exist $NowFormatted = (Get-Date -Format 'yyyy-MM-ddTHH:mm:ssZ' -AsUTC).ToString() $Provider = [PSCustomObject]@{ id = $null name = $Action.provider.name description = "" comment = "" dateCreated = $NowFormatted lastUpdated = $NowFormatted } $ProviderID = (New-TMProvider -Provider $Provider -PassThru -TMSession $TMSession).id } $Action.provider.id = $ProviderID ## If the Credential name is provided, look up the proper credential and add the ID if ($Action.credential) { if ($Action.credential.name) { $CredentialID = (Get-TMCredential -Name $Action.credential.name -TMSession $TMSession ).id if ($CredentialID) { $Action.credential.id = $CredentialID } $Action.remoteCredentialMethod = 'SUPPLIED' } else { $Action.credential = $null $Action.remoteCredentialMethod = 'USER_PRIV' } } $FieldSettings = Get-TMFieldSpecs -TMSession $TMSession ## Fix the Parameters to the correct custom field name if ($Action.methodParams) { $Parameters = $Action.methodParams | ConvertFrom-Json for ($j = 0; $j -lt $Parameters.Count; $j++) { if ($Parameters[$j].context -in @('DEVICE', 'APPLICATION', 'STORAGE', 'DATABASE')) { ## Check if a fieldLabel param exists in the Parameters[$j]. ## This is added by the New-TMIntegrationPlugin command so the correct ## Custom fields can be assigned when the new Action is installed. if ($Parameters[$j].PSobject.Properties.name -match 'fieldLabel') { ## Update the Project's assigned Field by associating the label to the current field list. $Parameters[$j].fieldName = ($FieldSettings.($Parameters[$j].context).fields | Where-Object { $_.label -eq $Parameters[$j].fieldLabel }).field ## Remove the 'fieldLabel property as it's invalid column definition $Parameters[$j].PSObject.Properties.Remove('fieldLabel') } } } $Action.methodParams = (ConvertTo-Array -InputObject $Parameters | ConvertTo-Json -Depth 100 -Compress ).toString() } $PostBodyJSON = $Action | ConvertTo-Json Set-TMHeaderAccept "JSON" -TMSession $TMSession Set-TMHeaderContentType "JSON" -TMSession $TMSession try { $response = Invoke-WebRequest -Method $HttpMethod -Uri $uri -WebSession $TMSessionConfig.TMWebSession -Body $PostBodyJSON @TMCertSettings if ($response.StatusCode -eq 200) { $responseContent = $response.Content | ConvertFrom-Json if ($responseContent.status -eq "success") { if ($PassThru) { return $responseContent.data } } } elseif ($response.StatusCode -eq 204) { return } } catch { Write-Host "Unable to create Action." return $_ } } } Function Get-TMAction { [CmdletBinding(DefaultParameterSetName = 'Default')] param( [Parameter(Mandatory = $false)] [String]$TMSession = "Default", [Parameter(Mandatory = $false, ParameterSetName = 'ByName')] [String[]]$Name, [Parameter(Mandatory = $false, ParameterSetName = 'ById')] [String[]]$Id, [Parameter(Mandatory = $false)] [String[]]$ProviderName, [Parameter(Mandatory = $false)] [String]$Server = $global:TMSessions[$TMSession].TMServer, [Parameter(Mandatory = $false)] [Bool]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL, [Parameter(Mandatory = $false)] [Switch]$ResetIDs, [Parameter(Mandatory = $false)] [String]$SaveCodePath, [Parameter(Mandatory = $false)] [Switch]$Passthru ) ## Get Session Configuration $TMSessionConfig = $global:TMSessions[$TMSession] if (-not $TMSessionConfig) { Write-Host 'TMSession: [' -NoNewline Write-Host $TMSession -ForegroundColor Cyan Write-Host '] was not Found. Please use the New-TMSession command.' Throw "TM Session Not Found. Use New-TMSession command before using features." } #Honor SSL Settings $TMCertSettings = $TMSessionConfig.AllowInsecureSSL ? @{SkipCertificateCheck = $true } : @{SkipCertificateCheck = $false } # Format the uri $instance = $Server.Replace('/tdstm', '').Replace('https://', '').Replace('http://', '') $uri = "https://$instance/tdstm/ws/apiAction" try { $response = Invoke-WebRequest -Method Get -Uri $uri -WebSession $TMSessionConfig.TMWebSession @TMCertSettings } catch { throw $_ } if ($response.StatusCode -in @(200, 204)) { $Result = ($response.Content | ConvertFrom-Json).data $Result = $Result | Where-Object actionType -eq 'POWER_SHELL' } else { throw "Unable to collect Actions." } ## Return the details -- Filter based on passed parameters if ($ProviderName) { $Result = $Result | Where-Object { $_.provider.name -in $ProviderName } } elseif ($Name) { $Result = $Result | Where-Object { $_.name -in $Name } } elseif ($Id) { $Result = $Result | Where-Object { $_.id -in $Id } } # Get Field / Label maps to translate the parameters $FieldToLabelMap = Get-TMFieldToLabelMap -Server $Server -TMSession $TMSession -AllowInsecureSSL $AllowInsecureSSL for ($i = 0; $i -lt $Result.Count; $i++) { ## Fix the Parameters to the correct custom field name if ($Result[$i].methodParams) { $Parameters = $Result[$i].methodParams | ConvertFrom-Json for ($j = 0; $j -lt $Parameters.Count; $j++) { if ($Parameters[$j].context -in @('DEVICE', 'APPLICATION', 'STORAGE', 'DATABASE')) { ## The custom column field identifer is lost when the IDs get reset. Add a fieldLabel node to put the custom field label. This will get replaced/updated by the Import $FieldLabel = $FieldToLabelMap."$($Parameters[$j].context)"."$($Parameters[$j].fieldName)" $Parameters[$j] | Add-Member -NotePropertyName 'fieldLabel' -NotePropertyValue $FieldLabel -Force } } $Result[$i].methodParams = ($Parameters | ConvertTo-Json -Depth 100 -Compress ).toString() } } if ($ResetIDs) { ## Clear pertinent data in each Action for ($i = 0; $i -lt $Result.Count; $i++) { $Result[$i].id = $null $Result[$i].project.id = $null if ($Result[$i].credential) { $Result[$i].credential.id = $null } $Result[$i].provider.id = $null } } ## Save the Code Files to a folder if ($SaveCodePath) { ## Save Each of the Script Source Data foreach ($Item in $Result) { ## Get a FileName safe version of the Provider Name $SafeProviderName = Get-FilenameSafeString $Item.provider.name $SafeActionName = Get-FilenameSafeString $Item.name ## Create the Provider Action Folder path $ProviderPath = Join-Path $SaveCodePath $SafeProviderName Test-FolderPath -FolderPath $ProviderPath ## Create a File ame for the Action $ProviderScriptPath = Join-Path $ProviderPath ($SafeActionName + '.TMAction.ps1') ## Collect the Script into a Script Block try { $Script = [ScriptBlock]::Create($Item.script) } catch { Write-Host 'There was an error converting the Script for action ' -NoNewline Write-Host $Item.Name -ForegroundColor Magenta throw $_.Exception.Message } ## Build a config of the important References $TMConfig = [PSCustomObject]@{ ActionName = $Item.name ProviderName = $Item.provider.name Credential = $Item.credential.name } | ConvertTo-Json | Out-String ## Collect the Parameters $Parameters = $Item.methodParams ? ($Item.methodParams | ConvertFrom-Json) : $null ## Create a Script String output ## Note - Indentations don't look correct here, but they produce good looking code. Don't adjust. $ScriptOutput = [System.Text.StringBuilder]::new() [void]$ScriptOutput.AppendLine("<####### TransitionManager Action Script ######") [void]$ScriptOutput.AppendLine() [void]$ScriptOutput.AppendLine(" ActionName = $SafeActionName ") [void]$ScriptOutput.AppendLine(" ProviderName = $SafeProviderName ") [void]$ScriptOutput.AppendLine((" CredentialName = " + $TMConfig.Credential)) [void]$ScriptOutput.AppendLine() [void]$ScriptOutput.AppendLine((" Description = " + $Item.description )) [void]$ScriptOutput.AppendLine('#>') [void]$ScriptOutput.AppendLine() if ($Parameters) { ## Open a Parameters Array [void]$ScriptOutput.AppendLine("## Parameter Configuration") [void]$ScriptOutput.AppendLine('$Params = @{') for ($i = 0; $i -lt $Parameters.Count; $i++) { ## Get the singular Param $Parameter = $Parameters[$i] $ParameterName = $Parameter.paramName -replace ' ', '' ## Add Strings to the Parameter Name if it has any offending (non-word) characters if ($ParameterName -match '\W') { $ParameterName = "`"" + $ParameterName + "`"" } ## Add the Param Object Header [void]$ScriptOutput.AppendLine((" " + $ParameterName + " = @{")) [void]$ScriptOutput.AppendLine((" Context = `"" + $Parameter.context + "`"")) ## Add Conditional Fields if ($Parameter.fieldLabel) { [void]$ScriptOutput.AppendLine((" FieldLabel = `"" + $Parameter.fieldLabel + "`"")) } if ($Parameter.context -eq 'USER_DEF') { [void]$ScriptOutput.AppendLine((" Value = @`"" )) [void]$ScriptOutput.AppendLine($Parameter.value) [void]$ScriptOutput.AppendLine("`"@") } ## Write the param details that are always present if (![String]::IsNullOrWhiteSpace($Parameter.description)) { [void]$ScriptOutput.AppendLine((" Description = @`"" )) [void]$ScriptOutput.AppendLine($Parameter.description) [void]$ScriptOutput.AppendLine("`"@") } else { [void]$ScriptOutput.AppendLine((" Description = `"`"")) } ## Close the Parameter Object [void]$ScriptOutput.AppendLine(' }') } ## Close the Parameters Object [void]$ScriptOutput.AppendLine('}') } ## Write the Configuration Footer [void]$ScriptOutput.AppendLine('## End of TM Configuration, Begin Script') [void]$ScriptOutput.AppendLine() ## Write the Script to the Configuration [void]$ScriptOutput.AppendLine($Script) [void]$ScriptOutput.AppendLine() ## Start Writing the Content of the Script (Force to overwrite any existing files) Set-Content -Path $ProviderScriptPath -Force -Value $ScriptOutput.toString() } } if ($Passthru -or !$SaveCodePath) { ## Return a single value, or an Array if ($Result.Count -eq 1) { return $Result[0] } else { return $Result } } } Function Read-TMActionScriptFile { param( [Parameter(Mandatory = $true)]$Path ) ## Name the Input File # $File = 'C:\Src\TDS\TM-Servers Git\tmddev.transitionmanager.net\Lab - TBW\Actions\TransitionManager\Devices - Get Windows System Info.ps1' $Content = Get-Content -Path $Path -Raw ## Ignore Empty Files if (-Not $Content) { return } $ContentLines = Get-Content -Path $Path ## Create Automation Token Variables Parse the Script File New-Variable astTokens -Force New-Variable astErr -Force $ast = [System.Management.Automation.Language.Parser]::ParseInput($Content, [ref]$astTokens, [ref]$astErr) ## ## Assess the Script Parts to get delineating line numbers ## ## Locate the Delimiting line $ConfigBlockEndLine = $astTokens | ` Where-Object { $_.Text -like '## End of TM Configuration, Begin Script*' } |` Select-Object -First 1 | ` Select-Object -ExpandProperty Extent | ` Select-Object -ExpandProperty StartLineNumber ## Test to see if the Script is formatted output with Metadata if (-not $ConfigBlockEndLine) { ## There is no metadata, create the basic object with just the source code $ActionConfig = [pscustomobject]@{ ActionName = (Get-Item -Path $Path).BaseName -replace '.TMAction', '' Description = "" ProviderName = (Get-Item -Path $Path).Directory.BaseName } ## Create the objects the below constructor expect $ConfigBlockEndLine = -1 $Params = $null $TMActionParams = [System.Collections.ArrayList] @() } else { ## ## Read the Script Header to gather the configurations ## ## Get all of the lines in the header comment $TMConfigHeader = 0..$ConfigBlockEndLine | ForEach-Object { if ($astTokens[$_].kind -eq 'comment') { $astTokens[$_] } } | Select-Object -First 1 | Select-Object -ExpandProperty Text ## Create a Properties object that will store the values listed in the header of the script file $ActionConfig = [PSCustomObject]@{ } ## Process each line of the Header string $TMConfigHeader -split "`n" | ForEach-Object { ## Process each line of the comment if ($_ -like '*=*') { $k, $v = $_ -split '=' $k = $k.Trim() -replace "'", '' -replace '"', '' $v = $v.Trim() -replace "'", '' -replace '"', '' $ActionConfig | Add-Member -NotePropertyName $k -NotePropertyValue $v } } ## ## Read the Script Block ## ## Create a Text StrinBuilder to collect the Script into $ActionConfigStringBuilder = New-Object System.Text.StringBuilder ## For each line in the Code Block, add it to the Action Script Code StringBuilder 0..$ConfigBlockEndLine | ForEach-Object { $ActionConfigStringBuilder.AppendLine($ContentLines[$_]) | Out-Null } $ActionConfigScriptString = $ActionConfigStringBuilder.ToString() $ActionConfigScriptBlock = [scriptblock]::Create($ActionConfigScriptString) ## Invoke the Script Block to create the $Params Object in this scope ## this line populates the $Params object from the Action Script Invoke-Command -ScriptBlock $ActionConfigScriptBlock -NoNewScope ## Collect the Parameters $TMActionParams = [System.Collections.ArrayList] @() ## Action Parameter Class Definition # { # "desc": "", # "type": "string", # "value": "", # "context": "DEVICE", # "encoded": false, # "readonly": false, # "required": false, # "fieldName": null, # "paramName": "IPAddress", # "fieldLabel": "IP Address" # } ## Process the Parameters into Action Params foreach ($ParamLabel in $Params.Keys) { ## Create a new Params Object to load to the Action $NewParamConfig = [PSCustomObject]@{ type = 'string' value = '' desc = '' context = '' fieldLabel = '' fieldName = '' required = $false encoded = $false readonly = $false } ## Read the existing Params configuration, assembling each additional Paramater option $ScriptParamConfig = $Params.$ParamLabel $ScriptParamConfig.Keys | ForEach-Object { switch ($_.toLower()) { 'value' { $NewParamConfig.value = $ScriptParamConfig[$_] break } 'type' { $NewParamConfig.type = $ScriptParamConfig[$_] break } 'description' { $NewParamConfig.desc = $ScriptParamConfig[$_] break } 'context' { $NewParamConfig.context = $ScriptParamConfig[$_] break } 'fieldlabel' { $NewParamConfig.fieldLabel = $ScriptParamConfig[$_] break } 'fieldName' { $NewParamConfig.fieldName = $ScriptParamConfig[$_] break } 'required' { $NewParamConfig.required = (ConvertTo-Boolean $ScriptParamConfig[$_]) break } } } ## Add the Parameter Name from the Configuration Object Add-Member -InputObject $NewParamConfig -NotePropertyName 'paramName' -NotePropertyValue $ParamLabel $TMActionParams.Add($NewParamConfig) | Out-Null } } ## Note where the Action Code is located $StartCodeBlockLine = $ConfigBlockEndLine + 1 $EndCodeBlockLine = $ast[-1].Extent.EndLineNumber ## Create a Text StrinBuilder to collect the Script into $ActionScriptStringBuilder = New-Object System.Text.StringBuilder ## For each line in the Code Block, add it to the Action Script Code StringBuilder $StartCodeBlockLine..$EndCodeBlockLine | ForEach-Object { $ActionScriptStringBuilder.AppendLine($ContentLines[$_]) | Out-Null } ## Convert the StringBuilder to a Multi-Line String $ActionScriptCode = $ActionScriptStringBuilder.ToString() ## If no Parameters were assembled, provide an empty array if (-not $TMActionParams) { $TMActionParams = [System.Collections.ArrayList] @() } # } ## Assemble the Action Object $TMAction = [pscustomobject]@{ id = $null name = $ActionConfig.ActionName description = $ActionConfig.Description debugEnabled = $false methodParams = ($TMActionParams | ConvertTo-Json -Compress) script = $ActionScriptCode reactionScripts = '{"PRE":"","ERROR":"// Put the task on hold and add a comment with the cause of the error\n task.error( response.stderr )","FINAL":"","FAILED":"","LAPSED":"","STATUS":"// Check the HTTP response code for a 200 OK \n if (response.status == SC.OK) { \n \t return SUCCESS \n } else { \n \t return ERROR \n}","DEFAULT":"// Put the task on hold and add a comment with the cause of the error\n task.error( response.stderr )\n","STALLED":"","SUCCESS":"// Update Asset Fields\nif(response?.data?.assetUpdates){\n\tfor (field in response.data.assetUpdates) {\n \t\tasset.\"${field.key}\" = field.value;\n\t}\n}\ntask.done()"}' provider = @{ id = $null name = $ActionConfig.ProviderName } project = @{ id = $null name = $null } remoteCredentialMethod = 'USER_PRIV' credential = $null asyncQueue = $null version = 1 dateCreated = Get-Date lastUpdated = Get-Date timeout = 0 commandLine = $null dictionaryMethodName = "Select..." callbackMethod = $null connectorMethod = $null pollingStalledAfter = 0 pollingInterval = 0 pollingLapsedAfter = 0 defaultDataScript = $null useWithTask = 0 reactionScriptsValid = 1 docUrl = '' isRemote = $true actionType = 'POWER_SHELL' useWithAsset = 0 isPolling = 0 endpointUrl = '' apiCatalog = $null } ## Handle Credential Loading Defaults to User priv, but if there is a credential Name supplied, the credential should be used if ($ActionConfig.CredentialName) { $TMAction.remoteCredentialMethod = 'SUPPLIED' $TMAction.credential = [pscustomobject]@{ name = $TMCredential.name } } ## Return the Action Object return $TMAction } function Invoke-TMActionScript { <# .SYNOPSIS Runs the Script Code in the specified TransitionManager Action .DESCRIPTION Runs the Script Code in the specified TransitionManager Action .PARAMETER TMSession Name of an open TMSession. Use Get-TMSession to get open sessions .EXAMPLE Invoke-TMActionScript -Name 'Ping Remote Machine' .OUTPUTS This command does not output any content #> [CmdletBinding()] param( [Parameter(Mandatory = $false)][String]$TMSession = "Default", [Parameter(Mandatory = $true)][String]$Name, [Parameter(Mandatory = $false)][String]$Server = $global:TMSessions[$TMSession].TMServer, [Parameter(Mandatory = $false)]$AllowInsecureSSL = $global:TMSessions[$TMSession].AllowInsecureSSL, [Parameter(Mandatory = $false)][PSObject]$Project= $global:TMSessions[$TMSession].UserContext.Project ) ## Get Session Configuration $TMSessionConfig = $global:TMSessions[$TMSession] if (-not $TMSessionConfig) { Write-Host 'TMSession: [' -NoNewline Write-Host $TMSession -ForegroundColor Cyan Write-Host '] was not Found. Please use the New-TMSession command.' Throw "TM Session Not Found. Use New-TMSession command before using features." } ## Get the TM Action $TMAction = Get-TMAction @PSBoundParameters if(-Not $TMAction){ throw 'Unable to get the Action' } ## Try converting and running the script block from the Action try { $ActionScriptBlock = [scriptblock]::Create($TMAction.Script) ## Invoke the script block, No New Scope to use the available variables, ## and with Debug enabled to allow stepping into the file via debugging mode Invoke-Command -ScriptBlock $ActionScriptBlock -NoNewScope -Debug } catch { throw $_ } } |