Public/Extensions.ps1
function Get-TMExtension { <# .SYNOPSIS Gets/Downloads a Reference Design from the TDS BitBucket tm-reference-designs repo .DESCRIPTION This function .PARAMETER Name The name of the Reference Design to download .PARAMETER Credential The credentials used to log into BitBucket .PARAMETER SkipDependencies Switch indicating that the Reference Designs on which the named Reference Design depends on should not be downloaded .PARAMETER ManifestUri The uri of the raw rd-manifest.json. Defaults to the file in the __Releases directory .PARAMETER Dev Switch indicating that all reference designs should be searched/retrieved rather than just the published ones .PARAMETER ProviderName One or more specific Providers to get. All other Providers will be removed from the downloaded Reference Design .EXAMPLE $Credential = Get-StoredCredential -Name 'ME' Get-TMExtension -Name 'vmware-vcenter' -Credential $Credential -Dev .OUTPUTS None #> [alias('Get-TMReferenceDesign')] [CmdletBinding(DefaultParameterSetName = 'Console')] param ( [Parameter(Mandatory = $false, Position = 0, ParameterSetName = 'Console')] [String[]]$Name, [Parameter(Mandatory = $false, Position = 1)] [PSCredential]$Credential, [Parameter(Mandatory = $false)] [Switch]$SkipDependencies, [Parameter(Mandatory = $false)] [String]$ManifestUri, [Parameter(Mandatory = $false)] [Switch]$Dev, [Parameter(Mandatory = $false)] [String[]]$ProviderName # [Parameter(Mandatory = $false, ParameterSetName = "UI")] # [Switch]$ShowMenu # TODO: Consider if we could add a $Path/$Location type # parameter to allow the user to specify a filesystem ) # Some of the TMD functions will be needed in this function if (!( Get-Module 'TMD.Common')) { Import-Module 'TMD.Common' } ## Create a $PackageNames variable with all of the Reference Design names (Lower, no spaces) $PackageNames = $Name.ToLower() -replace ' - ', '-' -replace ' ', '-' ## Save the Progress Preference now so that it can be changed and set back later $ProgressPreferenceBackup = $Global:ProgressPreference $Global:ProgressPreference = 'SilentlyContinue' $ExtensionFolder = Join-Path $Global:userFilesRoot 'Reference Designs' $LocalExtensions = [System.Collections.ArrayList]::new() $ExtensionsToDownload = [System.Collections.ArrayList]::new() # $ShouldInstall = $false ## TODO: I don't like this credential handling. If a user supplies a credential, it should not be written to disk, but only used. ## To mitigate this, you could do a few things -StoreCredentialAs (Name), or ## -CredentialName {Which would hand off to Get-StoredCredential} # Check if the credential is already cached $CredentialPath = Join-Path -Path $Global:UserPaths.credentials -ChildPath 'Bitbucket.credential' if (!$Credential) { $Credential = (Test-Path -Path $CredentialPath) ? (Get-StoredCredential -Name 'Bitbucket') : (Get-Credential) } # Save the credential for future use Add-StoredCredential -Name 'Bitbucket' -Credential $Credential Write-Verbose 'Credential was stored as Bitbucket.credential' # Get the reference design manifest from bitbucket Write-Host 'Getting available Reference Designs from Bitbucket...' try { if ([String]::IsNullOrWhiteSpace($ManifestUri)) { $ManifestUri = "https://git.tdsops.com/projects/TM/repos/tm-reference-designs/raw/__Releases/$(if ($Dev) {'dev-'})rd-manifest.json?at=refs%2Fheads%2Fmain" } $AvailableExtensions = Invoke-RestMethod -Method Get -Uri $ManifestUri -Authentication Basic -Credential $Credential } catch { throw "Couldn't get the manifest file. Check credentials and try again" } Write-Host "`tFound " -NoNewline Write-Host "$($AvailableExtensions.Count)" -NoNewline -ForegroundColor DarkBlue Write-Host ' available Reference Design(s)' # Fix the version so that it can be compared later in the script for ($i = 0; $i -lt $AvailableExtensions.Count; $i++) { $AvailableExtensions[$i].Version = ConvertTo-SemanticVersion -VersionString $AvailableExtensions[$i].Version for ($j = 0; $j -lt $AvailableExtensions[$i].extension.dependencies.extensions.Count; $j++) { $AvailableExtensions[$i].extension.dependencies.extensions[$j].version = ConvertTo-SemanticVersion -VersionString $AvailableExtensions[$i].extension.dependencies.extensions[$j].version } } # Either show the UI to get the user's selections or switch ($PSCmdlet.ParameterSetName) { 'Console' { Write-Verbose 'Console mode was selected' # If no name was supplied, just output the Extension objects if (!$PackageNames) { $AvailableExtensions | ForEach-Object { $_ } return } else { $PackageNames | ForEach-Object { $Extension = $AvailableExtensions | Where-Object name -EQ $_ | Sort-Object -Property version | Select-Object -Last 1 if ($Extension) { [void]$ExtensionsToDownload.Add($Extension) } } } } <# "UI" { Write-Verbose "UI mode was selected" # $ExePath = "..\exe\RD Installer.exe" $ExePath = "C:\DEV\git\tm-reference-designs\_ReferenceDesignManager\ReferenceDesignManager\bin\Debug\net5.0-windows\ReferenceDesignManager.exe" $StartInfo = [System.Diagnostics.ProcessStartInfo]::new() $StartInfo.RedirectStandardError = $true $StartInfo.RedirectStandardOutput = $true $StartInfo.FileName = $ExePath # $StartInfo.ArgumentList = @( # "--repocredential `"$CredentialPath`"" # "--powershell" # ) $StartInfo.Arguments = "--repocredential `"$CredentialPath`" --powershell" $ExtensionInstallerProc = [System.Diagnostics.Process]::new() $ExtensionInstallerProc.StartInfo = $StartInfo # Start the UI and wait for it to exit so that the stdout can be parsed Write-Host "Showing UI..." $ExtensionInstallerProc.Start() $ExtensionInstallerProc.WaitForExit() $StdOut = $ExtensionInstallerProc.StandardOutput.ReadToEnd() if ([String]::IsNullOrWhiteSpace($StdOut)) { throw "Output was not received from $(Split-Path $ExePath -Leaf)" } $UserChoices = $StdOut | ConvertFrom-Json $UserChoices.ExtensionsToDownload | ForEach-Object { [void]$ExtensionsToDownload.Add( @{ Name = $_ Version = $null } ) } $ShouldInstall = $UserChoices.ShouldInstall } #> } # Make sure one or more available Reference Designs were found if ($ExtensionsToDownload.Count -eq 0) { throw "No available Reference Designs were found with the specified name(s): $($PackageNames.ToString())" } ## Create the Destination Downloaded Folder $DownloadedFolder = Join-Path $ExtensionFolder 'Downloaded' Test-FolderPath $DownloadedFolder # Get all of the Reference Designs that are already downloaded Write-Host 'Checking for downloaded Reference Designs...' Write-Verbose "Looking in '$DownloadFolder'" try { Get-ChildItem -Path $DownloadedFolder -Filter 'package.json' -Recurse -ErrorAction SilentlyContinue | Get-Content -Raw | ConvertFrom-Json | ForEach-Object { [void]$LocalExtensions.Add($_) } } catch { Write-Verbose $_ } Write-Host "`tFound " -NoNewline Write-Host "$($LocalExtensions.Count)" -NoNewline -ForegroundColor DarkBlue Write-Host ' local Reference Design(s)' # Check if the selected Reference Designs have any dependencies on other Reference Designs if (!$SkipDependencies) { Write-Host 'Checking for Reference Design dependencies...' $Count = $ExtensionsToDownload.Count for ($i = 0; $i -lt $Count; $i++) { $Design = $ExtensionsToDownload[$i] foreach ($Dependency in $Design.extension.dependencies.extensions) { $AvailableExtension = $AvailableExtensions | Where-Object Name -EQ $Dependency.name | Sort-Object -Property version | Select-Object -Last 1 if ($AvailableExtension) { $LocalExtension = $LocalExtensions | Where-Object Name -EQ $Dependency.name | Sort-Object -Property version | Select-Object -Last 1 if ($LocalExtension) { if ($LocalExtension.version -lt $Dependency.version) { Write-Host "`tFound Reference Design to update: " -NoNewline Write-Host "$($AvailableExtension.Name) - v$($AvailableExtension.Version.ToString())" [void]$ExtensionsToDownload.Add($AvailableExtension) } } else { Write-Host "`tFound additional Reference Design to download: " -NoNewline Write-Host "$($AvailableExtension.Name) - v$($AvailableExtension.Version.ToString())" [void]$ExtensionsToDownload.Add($AvailableExtension) } } } } } # Start downloading the named reference designs Write-Host 'Downloading Reference Designs...' # $EncounteredError = $false foreach ($ExtensionSpec in $ExtensionsToDownload) { Write-Host "`tProcessing: " -NoNewline Write-Host $ExtensionSpec.ProductName -ForegroundColor DarkBlue ## Resolve the file name and the destination path $ZipFileName = $ExtensionSpec.Name + '-' + $ExtensionSpec.Version + '.zip' $Url = 'https://git.tdsops.com/projects/TM/repos/tm-reference-designs/raw/__Releases/{0}?at=refs%2Fheads%2Fmain' -f $ZipFileName $DestinationFilePath = Join-Path -Path $ExtensionFolder -ChildPath 'Downloaded' -AdditionalChildPath $ZipFileName try { ## Call to Bitbucket to download the file Write-Host "`t`tDownloading $ZipFileName ($([Math]::Round(($ExtensionSpec.Size / 1MB), 2)) MB)..." -NoNewline Invoke-WebRequest -Uri $Url -Credential $Credential -Authentication Basic -Method Get -OutFile $DestinationFilePath Write-Host 'Done' -ForegroundColor Green } catch { Write-Error $_ continue } try { # Unzip the downloaded file Write-Host "`t`tExpanding archive..." -NoNewline $DestinationDirectory = Join-Path -Path $ExtensionFolder -ChildPath 'Downloaded' -AdditionalChildPath $ExtensionSpec.ProductName Expand-Archive -Path $DestinationFilePath -DestinationPath $DestinationDirectory -Force Write-Host 'Done' -ForegroundColor DarkGreen } catch { Write-Error $_ continue } # Remove the .zip file now that its contents been extracted Remove-Item -Path $DestinationFilePath -Force if ($PSBoundParameters.ContainsKey('ProviderName')) { # Remove the actions and Datascripts that don't belong to the specified providers $ScriptPaths = @( (Join-Path -Path $DestinationDirectory -ChildPath '_REFERENCE DESIGN' 'Actions') (Join-Path -Path $DestinationDirectory -ChildPath '_REFERENCE DESIGN' 'ETL') ) Get-ChildItem -Path $ScriptPaths -Directory -Exclude $ProviderName -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force # Remove the providers from providers.json that weren't specified in ProviderName $FilteredProviders = [System.Collections.ArrayList]::new() $ProviderFile = Join-Path -Path $DestinationDirectory -ChildPath '_REFERENCE DESIGN' -AdditionalChildPath 'Providers.json' $Providers = , @(Get-Content -Path $ProviderFile | ConvertFrom-Json -Depth 10) foreach ($Provider in $Providers) { if ($Provider.name -in $ProviderName) { [void]($FilteredProviders.Add($Provider)) } } ConvertTo-Json -Depth 10 -InputObject $FilteredProviders | Set-Content -Path $ProviderFile -Force } } ## Set the progress preference back $Global:ProgressPreference = $ProgressPreferenceBackup # if ($ShouldInstall -and !$EncounteredError) { # Install-TMExtension -Name $UserChoices.ExtensionsToDownload # } } function Get-TMLocalExtension { <# .SYNOPSIS Gets one or more Reference Designs that have been downloaded loacally .DESCRIPTION This function scans the C:\Users\<user>\TMD_Files\Reference Designs directory for the package.json file(s) associated with Reference Designs that have been downloaded locally .PARAMETER Name The name(s) of the downloaded Reference Design(s) to retrieve .PARAMETER List Switch indicating that only a list of downloaded Reference Design names should be returned .EXAMPLE Get-TMLocalExtension -Name 'vmware-vcenter', 'vmware-hcx' .EXAMPLE Get-TMLocalExtension -List .OUTPUTS An array of strings representing the downloaded Reference Design names if the -List switch is used otherwise a PSCustomObject for each name that was passed #> [alias('Get-TMLocalReferenceDesign')] [CmdletBinding(DefaultParameterSetName = 'Named')] [OutputType([PSCustomObject[]], ParameterSetName = 'Named')] [OutputType([String[]], ParameterSetName = 'List')] param ( [Parameter( Mandatory = $false, ParameterSetName = 'Named', ValueFromPipeline = $true)] [String[]]$Name, [Parameter(Mandatory = $false, ParameterSetName = 'List')] [Switch]$List ) begin { if (!(Get-Module 'TMD.Common')) { Import-Module 'TMD.Common' } $ExtensionDirectory = Join-Path $Global:userFilesRoot 'Reference Designs' $LocalExtensions = Get-ChildItem -Path $ExtensionDirectory -Filter 'package.json' -Recurse -Force -ErrorAction SilentlyContinue | ForEach-Object { $Package = Get-Content -Path $_.FullName -Raw | ConvertFrom-Json -Depth 100 Add-Member -InputObject $Package -Name 'path' -Value (Split-Path $_.FullName) -MemberType NoteProperty -PassThru -Force } } process { if ($List) { $LocalExtensions | ForEach-Object { $_.Name } } else { if ($Name) { $Name | ForEach-Object { $LocalExtensions | Where-Object Name -EQ $_ } } else { $LocalExtensions } } } } function Import-TMExtension { <# .SYNOPSIS Imports a downloaded Reference Design to the specified project on the specified server .DESCRIPTION This function will apply the different configuration components of a Reference Design into a TransitonManager project. .PARAMETER Name The name of the locally downloaded Reference Design to apply/install .PARAMETER TMSession The name of the TM Session to use when creating a Team .PARAMETER Project The project in which the Reference Design will be applied .PARAMETER Include An array of components to include when performing the export. Options are: * ServerSettings ProjectSettings Code DependencyTypes FieldSpecs Bundles Providers Actions DataScripts Recipes AssetViews Events AppTypes DeviceTypes Teams TaskCategories NOTE: ServerSettings, ProjectSettings and Code are not components, but sets of components that are expanded to the following during runtime: ServerSettings: App Types, Dependency Types, Device Types, Teams, and Task Categories ProjectSettings: Asset Views, Bundles, Events, FieldSpecs, Providers, and Tags Code: Actions, DataScripts, Recipes, and (On Import Only) SetupScripts. .PARAMETER Exclude An array of components to skip when performing the import. Options are: ServerSettings ProjectSettings Code DependencyTypes FieldSpecs Bundles Providers Actions Datascripts Recipes Tags AssetViews Events AppTypes DeviceTypes Teams TaskCategories SetupScripts NOTE: ServerSettings, ProjectSettings and Code are not components, but sets of components that are expanded to the following during runtime: ServerSettings: App Types, Dependency Types, Device Types, Teams, and Task Categories ProjectSettings: Asset Views, Bundles, Events, FieldSpecs, Providers, and Tags Code: Actions, DataScripts, Recipes, and (On Import Only) SetupScripts. .PARAMETER SkipDependencies Switch indicating that the Reference Designs on which the named Reference Design depends on should not be imported .PARAMETER ProviderName One or more specific Providers to import. All other Providers will not be imported into the project .EXAMPLE $Credential = Get-StoredCredential -Name 'ME' $ImportSplat = @{ Name = 'vmware-vcenter' Project = 'New Project - VMware vCenter' TMSession = 'TMAD60' } Import-TMExtension @ImportSplat .OUTPUTS None #> [alias('Import-TMReferenceDesign')] [CmdletBinding(DefaultParameterSetName = 'ByInclusion')] param ( [Parameter( Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [ArgumentCompleter( { Get-TMLocalExtension -List } )] [String[]]$Name, [Parameter(Mandatory = $false, Position = 1)] [PSObject]$TMSession = 'Default', [Parameter(Mandatory = $false, Position = 2)] [String]$Project, [Parameter(Mandatory = $false, Position = 3, ParameterSetName = 'ByExclusion')] [ValidateSet( 'ServerSettings', 'ProjectSettings', 'Code', 'DependencyTypes', 'FieldSpecs', 'Bundles', 'Providers', 'Actions', 'DataScripts', 'Recipes', 'Tags', 'AssetData', 'AssetViews', 'Events', 'AppTypes', 'DeviceTypes', 'Teams', 'TaskCategories', 'SetupScripts' )] [String[]]$Exclude, [Parameter(Mandatory = $false, Position = 3, ParameterSetName = 'ByInclusion')] [ValidateSet( '*', 'ServerSettings', 'ProjectSettings', 'Code', 'DependencyTypes', 'FieldSpecs', 'Bundles', 'Providers', 'Actions', 'DataScripts', 'Recipes', 'Tags', 'AssetData', 'AssetViews', 'Events', 'AppTypes', 'DeviceTypes', 'Teams', 'TaskCategories', 'SetupScripts' )] [String[]]$Include = '*', [Parameter(Mandatory = $false)] [Switch]$SkipDependencies, [Parameter(Mandatory = $false)] [String[]]$ProviderName, [Parameter(Mandatory = $false)] [scriptblock] $Where = { $true } # This default value will act as a no-filter ) begin { # As per TM-22256, ServerSettings, ProjectSettings, and Code will be used to contain a set of components to exclude/include. $ServerSettings = 'AppTypes', 'DependencyTypes', 'DeviceTypes', 'Teams', 'TaskCategories' $ProjectSettings = 'AssetViews', 'Bundles', 'Events', 'FieldSpecs', 'Providers', 'Tags' $Code = 'Actions', 'DataScripts', 'Recipes', # (On Import Only) 'SetupScripts' if ($Include -contains 'ServerSettings') { $Include += $ServerSettings } if ($Include -contains 'ProjectSettings') { $Include += $ProjectSettings } if ($Include -contains 'Code') { $Include += $Code } if ($Exclude -contains 'ServerSettings') { $Exclude += $ServerSettings } if ($Exclude -contains 'ProjectSettings') { $Exclude += $ProjectSettings } if ($Exclude -contains 'Code') { $Exclude += $Code } # Get the session configuration Write-Verbose 'Checking for cached TMSession' $TMSession = Get-TMSession $TMSession Write-Debug 'TMSession:' Write-Debug ($TMSession | ConvertTo-Json -Depth 5) if (!(Get-Module 'TMD.Common')) { Import-Module 'TMD.Common' } $FilterByProvider = $PSBoundParameters.ContainsKey('ProviderName') ## Tag Color Map ## PowerShell Colors: ## Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White ## TM Tag Colors: ## 'Grey', 'Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Cyan', 'Purple', 'Pink', 'White' $TagColorToForeground = @{ 'Grey' = 'DarkGray' 'Red' = 'Red' 'Orange' = 'DarkYellow' 'Yellow' = 'Yellow' 'Green' = 'Green' 'Blue' = 'Blue' 'Cyan' = 'Cyan' 'Purple' = 'DarkMagenta' 'Pink' = 'Magenta' 'White' = 'White' } # Set up a configuration object to determine which components to install later in the process block $Components = @{ DependencyTypes = $true FieldSpecs = $true Bundles = $true Providers = $true Actions = $true Datascripts = $true Recipes = $true Tags = $true AssetViews = $true Events = $true AppTypes = $true DeviceTypes = $true Teams = $true TaskCategories = $true SetupScripts = $true } switch ($PSCmdlet.ParameterSetName) { 'ByInclusion' { if ($Include -notcontains '*') { foreach ($Key in $Components.GetEnumerator().Name) { if ($Include -notcontains $Key) { $Components.$Key = $false } } } } 'ByExclusion' { # Process the Exclude parameter and turn components off $ComponentSets = 'ServerSettings', 'ProjectSettings', 'Code' $Exclude | ForEach-Object { #Component sets are not actual components, so we don't want to process them. if ($_ -notin $ComponentSets) { $Components.$_ = $false } } } } # Get a list of all of the Reference Designs that have been saved locally $ExtensionDirectory = Join-Path $Global:userFilesRoot 'Reference Designs' $LocalExtensions = Get-TMLocalExtension if (!$LocalExtensions) { throw "No locally saved reference designs were found in $ExtensionDirectory. Use Get-TMExtension to download before installing." } # Determine the project to export if (-not [String]::IsNullOrWhiteSpace($Project) -and ($TMSession.userContext.project.name -ne $Project)) { Enter-TMProject -ProjectName $Project -TMSession $TMSession } else { $Project = $TMSession.userContext.project.name } } process { # Get the Extension spec from the passed Names and verify they are already downloaded $ExtensionToInstall = [System.Collections.Stack]::new() $DependencyCheckQueue = [System.Collections.Queue]@() foreach ($ExtensionName in $Name) { $ExtensionName = $ExtensionName.ToLower().Replace(' - ', '-').Replace(' ', '-') $Extension = $LocalExtensions | Where-Object Name -EQ $ExtensionName if (!$Extension) { throw "The reference design $ExtensionName has not been downloaded locally. Use Get-TMExtension and try again." } ## Check for Dependencies to add to the list before the Extension being installed if (!$SkipDependencies) { ## Add This Extension to the DependencyCheckList $DependencyCheckQueue.Enqueue($Extension) } ## Add the Extension being installed to the list, after dependencies are added $ExtensionToInstall.Push($Extension) } ## Check every Reference Design for Dependencies if (-Not $SkipDependencies) { Write-Host 'Checking Dependency Requirements' while ($DependencyCheckQueue.Count -ne 0) { # ## Check Each of the Extensions that are queued for installation for Dependencies # foreach ($ExtensionCheck in $ExtensionsToCheckDependenciesFor) { $ExtensionCheck = $DependencyCheckQueue.Dequeue() ## Remove Placeholder tokens provided by the template file creation $DependentExtensions = @() $ExtensionCheck.referenceDesign.dependencies.referenceDesigns | Where-Object { $_.name -ne '<PLACEHOLDER>' } | ForEach-Object { if ($_) { $DependentExtensions += $_ } } $ExtensionCheck.extension.dependencies.extensions | Where-Object { $_.name -ne '<PLACEHOLDER>' } | ForEach-Object { if ($_) { $DependentExtensions += $_ } } foreach ($DependencyItem in $DependentExtensions) { ## Get the Highest version number that matches the requirement $Dependency = $LocalExtensions | Where-Object { $_.Name -eq $DependencyItem.Name -and $_.Version -ge $DependencyItem.Version } | Sort-Object -Property 'version' -Descending | Select-Object -First 1 ## Ensure a dependency was found if (!$Dependency) { throw "The dependency Reference Design $($DependencyItem.Name) (Minimum v$($DependencyItem.Version)) was not found on the local hard drive. Use Get-TMExtension and try again." } if ($ExtensionToInstall -notcontains $Dependency) { Write-Host 'Required Prerequisite Extension also will be installed: ' -NoNewline Write-Host $Dependency.name -ForegroundColor Cyan -NoNewline Write-Host " v$($Dependency.version)" -ForegroundColor DarkGray # $ExtensionToInstall += $Dependency $ExtensionToInstall.Push($Dependency) [void]($DependencyCheckQueue.Enqueue($Dependency)) } } } } ## Create an array of Setup Scripts to run $SetupScriptsToRun = [System.Collections.ArrayList]@() ## Iterate over each Reference Design to Install while ($ExtensionToInstall.Count) { ## Get the next item from the Stack $Extension = $ExtensionToInstall.Pop() Write-Host 'Importing: ' -NoNewline Write-Host $Extension.productName -NoNewline -ForegroundColor Cyan Write-Host ', Version: ' -NoNewline Write-Host $Extension.Version -ForegroundColor DarkGray $ExtensionPath = Join-Path $Extension.Path '_REFERENCE DESIGN' # Create the dependency types if ($Components.DependencyTypes) { Write-Host 'Loading Dependency Types...' $DependencyTypes = [system.collections.arraylist]@() $DependencyTypesFolderPath = Join-Path $ExtensionPath 'DependencyTypes' if (Test-Path $DependencyTypesFolderPath -ErrorAction SilentlyContinue) { $DependencyTypeFiles = Get-ChildItem -Path $DependencyTypesFolderPath -ErrorAction SilentlyContinue $DependencyTypeFiles | ForEach-Object { [void]($DependencyTypes.Add((Get-Content -Path $_.FullName | ConvertFrom-Json))) } } else { $DependencyTypesFilePath = Join-Path $ExtensionPath 'DependencyTypes.json' if (Test-Path $DependencyTypesFilePath -ErrorAction SilentlyContinue) { $DependencyTypes = Get-ChildItem -Path $DependencyTypesFilePath -ErrorAction SilentlyContinue | Get-Content | ConvertFrom-Json } } ## Check if there were any entries $DependencyTypes = $DependencyTypes | Where-Object -FilterScript $Where if ($DependencyTypes.Count -eq 0) { Write-Host "`tNo Dependency Types to add" } else { ## Get the Server's existing Dependency Types $ServerDependencyTypes = Get-TMDependencyType -TMSession $TMSession foreach ($DependencyType in $DependencyTypes) { ## If the server doesn't have the dependency type if ($ServerDependencyTypes.label -notcontains $DependencyType.label) { ## Add it to the server Write-Host "`tLoading Dependency Type: " -NoNewline Write-Host "$($DependencyType.label)" -ForegroundColor DarkBlue $DependencyType = [TMDependencyType]::new($DependencyType.label) New-TMDependencyType -TMSession $TMSession -DependencyType $DependencyType } else { Write-Host "`tSkipping Dependency Type (was installed): " -NoNewline Write-Host "$($DependencyType.label)" -ForegroundColor DarkGreen } } } } # Create the App types if ($Components.AppTypes) { Write-Host 'Loading App Types...' $AppTypes = [system.collections.arraylist]@() $AppTypesFolderPath = Join-Path $ExtensionPath 'AppTypes' if (Test-Path $AppTypesFolderPath -ErrorAction SilentlyContinue) { $AppTypeFiles = Get-ChildItem -Path $AppTypesFolderPath -ErrorAction SilentlyContinue $AppTypeFiles | ForEach-Object { [void]($AppTypes.Add((Get-Content -Path $_.FullName | ConvertFrom-Json))) } } else { $AppTypesFilePath = Join-Path $ExtensionPath 'AppTypes.json' if (Test-Path $AppTypesFilePath -ErrorAction SilentlyContinue) { $AppTypes = Get-Content -Path $AppTypesFilePath | ConvertFrom-Json } } ## Check if there were any entries $AppTypes = $AppTypes | Where-Object -FilterScript $Where if ($AppTypes.Count -eq 0) { Write-Host "`tNo App Types to add" } else { ## Get the Server's existing App Types $ServerAppTypes = Get-TMAssetOption -Type 'App Type' -TMSession $TMSession foreach ($AppType in $AppTypes) { ## If the server doesn't have the App type if ($ServerAppTypes.label -notcontains $AppType.label) { Write-Host "`tLoading App Type: " -NoNewline Write-Host "$($AppType.label)" -ForegroundColor DarkBlue ## Add it to the server $AppType = [TMAppType]::new($AppType.label) New-TMAssetOption -Type 'App Type' -Name $AppType.label -TMSession $TMSession } else { Write-Host "`tSkipping App Type (was installed): " -NoNewline Write-Host "$($AppType.label)" -ForegroundColor DarkGreen } } } } # Create the Device types if ($Components.DeviceTypes) { Write-Host 'Loading Device Types...' $DeviceTypes = [system.collections.arraylist]@() $DeviceTypesFolderPath = Join-Path $ExtensionPath 'DeviceTypes' if (Test-Path $DeviceTypesFolderPath -ErrorAction SilentlyContinue) { $DeviceTypeFiles = Get-ChildItem -Path $DeviceTypesFolderPath -ErrorAction SilentlyContinue $DeviceTypeFiles | ForEach-Object { [void]($DeviceTypes.Add((Get-Content -Path $_.FullName | ConvertFrom-Json))) } } else { $DeviceTypesFilePath = Join-Path $ExtensionPath 'DeviceTypes.json' if (Test-Path $AppTypesFilePath -ErrorAction SilentlyContinue) { $DeviceTypes = Get-Content -Path $DeviceTypesFilePath | ConvertFrom-Json } } $DeviceTypes = $DeviceTypes | Where-Object -FilterScript $Where if ($DeviceTypes.Count -eq 0) { Write-Host "`tNo Device Types to add" } else { ## Get the Server's existing Device Types $ServerDeviceTypes = Get-TMAssetOption -Type 'Asset Type' -TMSession $TMSession foreach ($DeviceType in $DeviceTypes) { ## If the server doesn't have the Device type if ($ServerDeviceTypes.label -notcontains $DeviceType.label) { ## Add it to the server Write-Host "`tLoading Device Type: " -NoNewline Write-Host "$($DeviceType.label)" -ForegroundColor DarkBlue $DeviceType = [TMAssetType]::new($DeviceType.label) New-TMAssetOption -Type 'Asset Type' -Name $DeviceType.label -TMSession $TMSession } else { Write-Host "`tSkipping Device Type (was installed): " -NoNewline Write-Host "$($ServerDeviceTypes.label)" -ForegroundColor DarkGreen } } } } # Create the Task Categories if ($Components.TaskCategories) { Write-Host 'Loading Task Categories...' $TaskCategories = [system.collections.arraylist]@() $TaskCategoriesFolderPath = Join-Path $ExtensionPath 'TaskCategories' if (Test-Path $TaskCategoriesFolderPath -ErrorAction SilentlyContinue) { $TaskCategoryFiles = Get-ChildItem -Path $TaskCategoriesFolderPath -ErrorAction SilentlyContinue $TaskCategoryFiles | ForEach-Object { [void]($TaskCategories.Add((Get-Content -Path $_.FullName | ConvertFrom-Json))) } } else { $TaskCategoriesFilePath = Join-Path $ExtensionPath 'TaskCategories.json' if (Test-Path $TaskCategoriesFilePath -ErrorAction SilentlyContinue) { $TaskCategories = Get-Content -Path $TaskCategoriesFilePath | ConvertFrom-Json } } $TaskCategories = $TaskCategories | Where-Object -FilterScript $Where if ($TaskCategories.Count -eq 0) { Write-Host "`tNo Task Categories to add" } else { ## Get the Server's existing Task Categories $ServerTaskCategories = Get-TMAssetOption -Type 'Task Category' -TMSession $TMSession foreach ($TaskCategory in $TaskCategories) { ## If the server doesn't have the Device type if ($ServerTaskCategories.label -notcontains $TaskCategory.label) { ## Add it to the server Write-Host "`tLoading Task Category: " -NoNewline Write-Host "$($TaskCategory.label)" -ForegroundColor DarkBlue $TaskCategory = [TMTaskCategory]::new($TaskCategory.label) New-TMAssetOption -Type 'Task Category' -Name $TaskCategory.label -TMSession $TMSession } else { Write-Host "`tSkipping Task Category (was installed): " -NoNewline Write-Host "$($TaskCategory.label)" -ForegroundColor DarkGreen } } } } # Load the Teams if ($Components.Teams) { Write-Host 'Loading Teams...' $Teams = [system.collections.arraylist]@() $TeamsFolderPath = Join-Path $ExtensionPath 'Teams' if (Test-Path $TeamsFolderPath -ErrorAction SilentlyContinue) { $TeamFiles = Get-ChildItem -Path $TeamsFolderPath -ErrorAction SilentlyContinue $TeamFiles | ForEach-Object { [void]($Teams.Add((Get-Content -Path $_.FullName | ConvertFrom-Json))) } } else { $TeamsFilePath = Join-Path $ExtensionPath 'Teams.json' if (Test-Path $TeamsFilePath -ErrorAction SilentlyContinue) { $Teams = Get-Content -Path $TeamsFilePath | ConvertFrom-Json } } $Teams = $Teams | Where-Object -FilterScript $Where if ($Teams.Count -eq 0) { Write-Host "`tNo Teams to add" } else { foreach ($Team in $Teams) { Write-Host "`tLoading Team: " -NoNewline Write-Host "$($Team.Code)" -ForegroundColor DarkBlue New-TMTeam -Code $Team.Code -Description $Team.Description -Level $Team.Level -Help $Team.Help -TMSession $TMSession } } } # Load the Tags if ($Components.Tags) { Write-Host 'Loading Tags...' $Tags = [system.collections.arraylist]@() $TagsFolderPath = Join-Path $ExtensionPath 'Tags' if (Test-Path $TagsFolderPath -ErrorAction SilentlyContinue) { $TagFiles = Get-ChildItem -Path $TagsFolderPath -ErrorAction SilentlyContinue $TagFiles | ForEach-Object { [void]($Tags.Add((Get-Content -Path $_.FullName | ConvertFrom-Json))) } } else { $TagsFilePath = Join-Path $ExtensionPath 'Tags.json' if (Test-Path $TagsFilePath -ErrorAction SilentlyContinue) { $Tags = Get-Content -Path $TagsFilePath | ConvertFrom-Json } } $Tags = $Tags | Where-Object -FilterScript $Where if ($Tags.Count -eq 0) { Write-Host "`tNo Tags to add" } else { foreach ($Tag in $Tags) { Write-Host "`tLoading Tag: " -NoNewline Write-Host "$($Tag.Name)" -ForegroundColor $TagColorToForeground.($Tag.Color) New-TMTag -Name $Tag.Name -Description $Tag.description -Color $Tag.color -TMSession $TMSession } } } # Load the Field Specs if ($Components.FieldSpecs) { Write-Host 'Loading Field Specs...' $FieldSpecs = $null ## Check Extension Package v3 (Folder of Files) $FieldSpecsFolderPath = Join-Path $ExtensionPath 'FieldSpecs' if (Test-Path $FieldSpecsFolderPath -ErrorAction SilentlyContinue) { ## Create the FieldSpecs Object to add all of the fields to $FieldSpecs = [pscustomobject]@{ APPLICATION = [PSCustomObject]@{ lastUpdated = '' dateCreated = '' domain = 'APPLICATION' fields = @() version = 1 } DATABASE = [PSCustomObject]@{ lastUpdated = '' dateCreated = '' domain = 'DATABASE' fields = @() version = 1 } DEVICE = [PSCustomObject]@{ lastUpdated = '' dateCreated = '' domain = 'DEVICE' fields = @() version = 1 } STORAGE = [PSCustomObject]@{ lastUpdated = '' dateCreated = '' domain = 'STORAGE' fields = @() version = 1 } } ## Handle Single JSON field files from folders $SharedFieldFiles = Get-ChildItem -Path (Join-Path $FieldSpecsFolderPath 'Shared') -Filter '*.json' -Force -ErrorAction 'SilentlyContinue' foreach ($FieldFile in $SharedFieldFiles) { $FieldSpecs.APPLICATION.fields += (Get-Content -Path $FieldFile.FullName | ConvertFrom-Json) $FieldSpecs.DATABASE.fields += (Get-Content -Path $FieldFile.FullName | ConvertFrom-Json) $FieldSpecs.DEVICE.fields += (Get-Content -Path $FieldFile.FullName | ConvertFrom-Json) $FieldSpecs.STORAGE.fields += (Get-Content -Path $FieldFile.FullName | ConvertFrom-Json) } $ApplicationFieldFiles = Get-ChildItem -Path (Join-Path $FieldSpecsFolderPath 'Application') -Filter '*.json' -Force -ErrorAction 'SilentlyContinue' foreach ($FieldFile in $ApplicationFieldFiles) { $FieldSpecs.APPLICATION.fields += (Get-Content -Path $FieldFile.FullName | ConvertFrom-Json -ErrorAction 'SilentlyContinue') } $DatabaseFieldFiles = Get-ChildItem -Path (Join-Path $FieldSpecsFolderPath 'Database') -Filter '*.json' -Force -ErrorAction 'SilentlyContinue' foreach ($FieldFile in $DatabaseFieldFiles) { $FieldSpecs.DATABASE.fields += (Get-Content -Path $FieldFile.FullName | ConvertFrom-Json -ErrorAction 'SilentlyContinue') } $DeviceFieldFiles = Get-ChildItem -Path (Join-Path $FieldSpecsFolderPath 'Device') -Filter '*.json' -Force -ErrorAction 'SilentlyContinue' foreach ($FieldFile in $DeviceFieldFiles) { $FieldSpecs.DEVICE.fields += (Get-Content -Path $FieldFile.FullName | ConvertFrom-Json -ErrorAction 'SilentlyContinue') } $StorageFieldFiles = Get-ChildItem -Path (Join-Path $FieldSpecsFolderPath 'Storage') -Filter '*.json' -Force -ErrorAction 'SilentlyContinue' foreach ($FieldFile in $StorageFieldFiles) { $FieldSpecs.STORAGE.fields += (Get-Content -Path $FieldFile.FullName | ConvertFrom-Json) } } else { ## Check Extension Package <v3 (Single FieldSpecs.json file) $FieldSpecsFilePath = Join-Path $ExtensionPath 'FieldSpecs.json' if (Test-Path $FieldSpecsFilePath -ErrorAction SilentlyContinue) { ## Version 6.0.2.1+ (and TODO version 6.1?, 5x?) ## Requires the class names to be lower case ## Convert each Asset Class name to lowercase $FieldSpecsData = ((Get-Content -Path $FieldSpecsFilePath) -replace 'constraints', 'constraint') $FieldSpecs = ($FieldSpecsData | ConvertFrom-Json -ErrorAction SilentlyContinue) } } ## Determine if any fields are needed if (-Not $FieldSpecs) { Write-Host "`tNo Asset Field Specs to add" } else { 'APPLICATION', 'DEVICE', 'DATABASE', 'STORAGE' | ForEach-Object { $DomainColor = switch ($_) { 'APPLICATION' { 'DarkMagenta' } 'DEVICE' { 'DarkCyan' } 'DATABASE' { 'DarkYellow' } 'STORAGE' { 'DarkGreen' } } foreach ($Field in $FieldSpecs.$_.fields) { Write-Host "`tLoading Field Spec: [" -NoNewline Write-Host "$_" -ForegroundColor $DomainColor -NoNewline Write-Host '] ' -NoNewline Write-Host "$($Field.label)" -ForegroundColor DarkBlue ## Convert JSON defaultValue fields to a JSON string if they're not if ($Field.control -eq 'JSON' -and $Field.defaultValue.GetType().Name -ne 'String') { $Field.defaultValue = $Field.defaultValue | ConvertTo-Json -Depth 100 -Compress } } } Update-TMFieldSpecs -FieldSpecs $FieldSpecs -TMSession $TMSession } } # Load the Bundles if ($Components.Bundles) { Write-Host 'Loading Bundles...' $Bundles = [system.collections.arraylist]@() $BundlesFolderPath = Join-Path $ExtensionPath 'Bundles' if (Test-Path $BundlesFolderPath -ErrorAction SilentlyContinue) { $BundleFiles = Get-ChildItem -Path $BundlesFolderPath -ErrorAction SilentlyContinue $BundleFiles | ForEach-Object { [void]($Bundles.Add((Get-Content -Path $_.FullName | ConvertFrom-Json))) } } else { $BundlesFilePath = Join-Path $ExtensionPath 'Bundles.json' if (Test-Path $BundlesFilePath -ErrorAction SilentlyContinue) { $Bundles = Get-Content -Path $BundlesFilePath | ConvertFrom-Json } } $Bundles = $Bundles | Where-Object -FilterScript $Where if ($Bundles.Count -eq 0) { Write-Host "`tNo Bundles to add" } else { foreach ($Bundle in $Bundles) { Write-Host "`tLoading Bundle: " -NoNewline Write-Host "$($Bundle.Name)" -ForegroundColor DarkBlue New-TMBundle -Bundle $Bundle -TMSession $TMSession } } } # Load the Events if ($Components.Events) { Write-Host 'Loading Events...' $Events = [system.collections.arraylist]@() $EventsFolderPath = Join-Path $ExtensionPath 'Events' if (Test-Path $EventsFolderPath -ErrorAction SilentlyContinue) { $EventFiles = Get-ChildItem -Path $EventsFolderPath -ErrorAction SilentlyContinue $EventFiles | ForEach-Object { [void]($Events.Add((Get-Content -Path $_.FullName | ConvertFrom-Json))) } } else { $EventsFilePath = Join-Path $ExtensionPath 'Events.json' if (Test-Path $EventsFilePath -ErrorAction SilentlyContinue) { $Events = Get-Content -Path $EventsFilePath | ConvertFrom-Json } } $Events = $Events | Where-Object -FilterScript $Where if ($Events.Count -eq 0) { Write-Host "`tNo Events to add" } else { foreach ($TMEvent in $Events) { Write-Host "`tLoading Event: " -NoNewline Write-Host "$($TMEvent.Name)" -ForegroundColor DarkBlue New-TMEvent -InputObject $TMEvent -TMSession $TMSession } } } # Load the Providers if ($Components.Providers) { Write-Host 'Loading Providers...' $Providers = [system.collections.arraylist]@() $ProvidersFolderPath = Join-Path $ExtensionPath 'Providers' if (Test-Path $ProvidersFolderPath -ErrorAction SilentlyContinue) { $ProviderFiles = Get-ChildItem -Path $ProvidersFolderPath -ErrorAction SilentlyContinue $ProviderFiles | ForEach-Object { [void]($Providers.Add((Get-Content -Path $_.FullName | ConvertFrom-Json))) } } else { $ProvidersFilePath = Join-Path $ExtensionPath 'Providers.json' if (Test-Path $ProvidersFilePath -ErrorAction SilentlyContinue) { $Providers = Get-Content -Path $ProvidersFilePath | ConvertFrom-Json } } $Providers = $Providers | Where-Object -FilterScript $Where if ($Providers.Count -eq 0) { Write-Host "`tNo Providers to add" } else { foreach ($Provider in $Providers) { if ($FilterByProvider -and ($Provider.Name -notin $ProviderName)) { continue } Write-Host "`tLoading Provider: " -NoNewline Write-Host "$($Provider.Name)" -ForegroundColor DarkBlue New-TMProvider -Provider $Provider -TMSession $TMSession } } } # Load Actions if ($Components.Actions) { Write-Host 'Loading Actions...' $Actions = @() $ActionsPath = Join-Path $ExtensionPath 'Actions' if (Test-Path -Path $ActionsPath -ErrorAction SilentlyContinue) { $Actions = Get-ChildItem -Path $ActionsPath -Recurse -Include '*.ps1' -ErrorAction SilentlyContinue | ForEach-Object { Read-TMActionScriptFile -Path $_.FullName -TMSession $TMSession } } if ($FilterByProvider) { $Actions = $Actions | Where-Object { $_.Provider.Name -in $ProviderName } } $Actions = $Actions | Where-Object -FilterScript $Where if ($Actions.count -eq 0) { Write-Host "`tNo Actions to add" } else { foreach ($Action in $Actions) { Write-Host "`tLoading Action: " -NoNewline Write-Host "$($Action.Name)" -ForegroundColor DarkBlue New-TMAction -Action $Action -Update -TMSession $TMSession } } } # DataScripts if ($Components.Datascripts) { Write-Host 'Loading DataScripts...' $DataScripts = @() $DataScriptsPath = Join-Path $ExtensionPath 'DataScripts' if (Test-Path -Path $DataScriptsPath -ErrorAction SilentlyContinue) { $DataScripts = Get-ChildItem -Path $DataScriptsPath -Recurse -Include '*.groovy' -ErrorAction SilentlyContinue | ForEach-Object { Read-TMDatascriptFile -Path $_.FullName } } if ($FilterByProvider) { $DataScripts = $DataScripts | Where-Object { $_.Provider.Name -in $ProviderName } } $DataScripts = $DataScripts | Where-Object -FilterScript $Where if ($DataScripts.count -eq 0) { Write-Host "`tNo DataScripts to add" } else { foreach ($DataScript in $DataScripts) { Write-Host "`tLoading DataScript: " -NoNewline Write-Host "$($DataScript.Name) " -ForegroundColor DarkBlue -NoNewline $SemVer = "" if ($DataScript.semVer) { $SemVer = "v$($DataScript.semVer)" } Write-Host $SemVer -ForegroundColor DarkYellow New-TMDatascript -Datascript $DataScript -Update -TMSession $TMSession } } } # Recipes if ($Components.Recipes) { Write-Host 'Loading Recipes...' $Recipes = @() $RecipesPath = Join-Path $ExtensionPath 'Recipes' if (Test-Path -Path $RecipesPath -ErrorAction SilentlyContinue) { $Recipes = Get-ChildItem -Path $RecipesPath -Recurse -Include '*.json' -ErrorAction SilentlyContinue | ForEach-Object { Read-TMRecipeScriptFile -Path $_.FullName -UpdateFieldNames } } $Recipes = $Recipes | Where-Object -FilterScript $Where if ($Recipes.count -eq 0) { Write-Host "`tNo Recipes to add" } else { foreach ($Recipe in $Recipes) { Write-Host "`tLoading Recipe: " -NoNewline Write-Host "$($Recipe.Name)" -ForegroundColor DarkBlue New-TMRecipe -Recipe $Recipe -Update -TMSession $TMSession } } } # Load the AssetViews if ($Components.AssetViews) { Write-Host 'Loading AssetViews...' $AssetViewsFolderPath = Join-Path $ExtensionPath 'AssetViews' if (Test-Path $AssetViewsFolderPath -ErrorAction SilentlyContinue) { $AssetViews = [System.Collections.ArrayList]@() $AssetViewConfigurationFiles = Get-ChildItem -Path $AssetViewsFolderPath -File -ErrorAction SilentlyContinue | Where-Object { $_.Extension -in @('.json') } foreach ($AssetViewConfigurationFile in $AssetViewConfigurationFiles) { $AssetView = Get-Content -Path $AssetViewConfigurationFile.FullName | ConvertFrom-Json -ErrorAction 'SilentlyContinue' if ($AssetView) { [void]($AssetViews.Add($AssetView)) } } } else { $AssetViewsFilePath = Join-Path $ExtensionPath 'AssetViews.json' if (-Not (Test-Path $AssetViewsFilePath -ErrorAction SilentlyContinue)) { Write-Host "`tNo AssetViews to add" } else { $AssetViews = Get-Content -Path $AssetViewsFilePath | ConvertFrom-Json -ErrorAction 'SilentlyContinue' if ($AssetViews.Count -eq 0) { Write-Host "`tNo Asset Views to add" } } } $AssetViews = $AssetViews | Where-Object -FilterScript $Where foreach ($AssetView in $AssetViews) { Write-Host "`tLoading AssetView: " -NoNewline Write-Host "$($AssetView.Name)" -ForegroundColor DarkBlue New-TMAssetViewConfiguration $AssetView -TMSession $TMSession -Update } } # SetupScripts if ($Components.SetupScripts) { Write-Host 'Collecting Setup Scripts...' $SetupScriptsFolderPath = Join-Path $ExtensionPath '_SETUP' if (-Not (Test-Path $SetupScriptsFolderPath -ErrorAction SilentlyContinue)) { Write-Host "`tNo Setup Scripts to run" } else { $SetupScriptFiles = Get-ChildItem -Path $SetupScriptsFolderPath -File -ErrorAction SilentlyContinue | Where-Object { $_.Extension -eq '.ps1' } foreach ($SetupScriptFile in $SetupScriptFiles) { Write-Host "`Queuing Setup Script: " -NoNewline Write-Host "$($SetupScriptFile.Name)" -ForegroundColor DarkBlue [void]$SetupScriptsToRun.Add($SetupScriptFile) } } } } ## Sort the Setup Scripts to run by name $SortedSetupScripts = $SetupScriptsToRun | Sort-Object -Property 'Name' ## Iterate over each setup script and run them each foreach ($SetupScript in $SortedSetupScripts) { Write-Host "`tRunning Setup Script: " -NoNewline Write-Host "$($SetupScript.Name)" -ForegroundColor DarkBlue ## Try the script try { & "$($SetupScript.FullName)" } catch { Write-Host 'Setup Script Failed!' Write-Error $_ } } } } function Export-TMExtension { <# .SYNOPSIS Exports a TransitionManager project into a portable configuration package that can be applied in a different project and/or on a different server .DESCRIPTION This function will retreieve the different configuration components from a TransitonManager project and save them locally in a standardized format that can then be used to import those configurations on another TM project or TM instance. .PARAMETER Name What the Reference Design will be named .PARAMETER TMSession The name of, or a Variable containing, the TM Session to use .PARAMETER Project The project that will be exported .PARAMETER Include An array of components to include when performing the export. Options are: * ServerSettings ProjectSettings Code DependencyTypes FieldSpecs Bundles Providers Actions DataScripts Recipes AssetViews Events AppTypes DeviceTypes Teams TaskCategories NOTE: ServerSettings, ProjectSettings and Code are not components, but sets of components that are expanded to the following during runtime: ServerSettings: App Types, Dependency Types, Device Types, Teams, and Task Categories ProjectSettings: Asset Views, Bundles, Events, FieldSpecs, Providers, and Tags Code: Actions, DataScripts, Recipes, and (On Import Only) SetupScripts. .PARAMETER Exclude An array of components to skip when performing the export. Options are: ServerSettings ProjectSettings Code DependencyTypes FieldSpecs Bundles Providers Actions DataScripts Recipes AssetViews Events AppTypes DeviceTypes Teams TaskCategories NOTE: ServerSettings, ProjectSettings and Code are not components, but sets of components that are expanded to the following during runtime: ServerSettings: App Types, Dependency Types, Device Types, Teams, and Task Categories ProjectSettings: Asset Views, Bundles, Events, FieldSpecs, Providers, and Tags Code: Actions, DataScripts, Recipes, and (On Import Only) SetupScripts. .PARAMETER OutPath The directory where the Reference Design will be saved .PARAMETER PackageFile Produce an updated package.json file for the Extension .EXAMPLE $Credential = Get-StoredCredential -Name 'ME' $ExportSplat = @{ Name = 'VMWare - vCenter' Server = 'tmddev.transitionmanager.net' Project = 'Extension - VMware vCenter' Credential = $Credential PackageFile = $true } Export-TMExtension @ExportSplat .NOTES -Force is always applied to the New-TMExtensionPackageFile command if -PackageFile is used. This evaluates the output path of the extension exported at the directory path targted. .OUTPUTS None #> [alias('Export-TMExtension')] [CmdletBinding(DefaultParameterSetName = 'ByInclusion')] param ( [Parameter(Mandatory = $false, Position = 0)] [String]$Name, [Parameter(Mandatory = $false, Position = 1)] [PSObject]$TMSession = 'Default', [Parameter(Mandatory = $false, Position = 2)] [String]$Project, [Parameter(Mandatory = $false, Position = 3, ParameterSetName = 'ByInclusion')] [ValidateSet( '*', 'ServerSettings', 'ProjectSettings', 'Code', 'DependencyTypes', 'FieldSpecs', 'Bundles', 'Providers', 'Actions', 'DataScripts', 'Recipes', 'Tags', 'AssetData', 'AssetViews', 'Events', 'AppTypes', 'DeviceTypes', 'Teams', 'TaskCategories' )] [String[]]$Include = '*', [Parameter(Mandatory = $false, Position = 3, ParameterSetName = 'ByExclusion')] [ValidateSet( 'ServerSettings', 'ProjectSettings', 'Code', 'DependencyTypes', 'FieldSpecs', 'Bundles', 'Providers', 'Actions', 'DataScripts', 'Recipes', 'Tags', 'AssetData', 'AssetViews', 'Events', 'AppTypes', 'DeviceTypes', 'Teams', 'TaskCategories' )] [String[]]$Exclude, [Parameter(Mandatory = $false, Position = 4)] [String[]]$ProviderName, [Parameter(Mandatory = $false, Position = 5)] [AllowNull()] [String]$OutPath = '', [Parameter(Mandatory = $false, Position = 6)] [Switch]$ClearExistingFiles, [Parameter(Mandatory = $false, Position = 7)] [Switch]$PackageFile ) begin { # As per TM-22256, ServerSettings, ProjectSettings, and Code will be used to contain a set of components to exclude/include. $ServerSettings = 'AppTypes', 'DependencyTypes', 'DeviceTypes', 'Teams', 'TaskCategories' $ProjectSettings = 'AssetViews', 'Bundles', 'Events', 'FieldSpecs', 'Providers', 'Tags' $Code = 'Actions', 'DataScripts', 'Recipes' # (On Import Only) # 'SetupScripts' if ($Include -contains 'ServerSettings') { $Include += $ServerSettings } if ($Include -contains 'ProjectSettings') { $Include += $ProjectSettings } if ($Include -contains 'Code') { $Include += $Code } if ($Exclude -contains 'ServerSettings') { $Exclude += $ServerSettings } if ($Exclude -contains 'ProjectSettings') { $Exclude += $ProjectSettings } if ($Exclude -contains 'Code') { $Exclude += $Code } # Get the session configuration Write-Verbose 'Checking for cached TMSession' $TMSession = Get-TMSession $TMSession Write-Debug 'TMSession:' Write-Debug ($TMSession | ConvertTo-Json -Depth 5) if (!(Get-Module 'TMD.Common')) { Import-Module 'TMD.Common' } # Default to the reference design directory if an out path wasn't specified if ([String]::IsNullOrWhiteSpace($OutPath)) { Write-Verbose 'No OutPath as provided and will use the default export location' $OutPath = Join-Path -Path $Global:userPaths.referencedesigns -ChildPath 'Exported' -AdditionalChildPath $TMSession.TMServer $OutPath = Join-Path -Path $Global:userPaths.referencedesigns -ChildPath 'Exported' -AdditionalChildPath $TMSession.TMServer ## Create the Extension's root path Test-FolderPath -Path $OutPath } # Set up a configuration object to determine which components to install later in the process block $Components = @{ DependencyTypes = $true FieldSpecs = $true Bundles = $true Providers = $true Actions = $true DataScripts = $true Recipes = $true Tags = $true AssetData = $true AssetViews = $true Events = $true AppTypes = $true DeviceTypes = $true Teams = $true TaskCategories = $true } switch ($PSCmdlet.ParameterSetName) { 'ByInclusion' { if ($Include -notcontains '*') { foreach ($Key in $Components.GetEnumerator().Name) { if ($Include -notcontains $Key) { $Components.$Key = $false } } } } 'ByExclusion' { # Process the Exclude parameter and turn components off $ComponentSets = 'ServerSettings', 'ProjectSettings', 'Code' $Exclude | ForEach-Object { #Component sets are not actual components, so we don't want to process them. if ($_ -notin $ComponentSets) { $Components.$_ = $false } } } } # Write about what is going to be exported Write-Host 'Exporting Component Types from Project:' foreach ($Component in $Components.Keys) { ## For each Enabled Component if ($Components.$Component) { Write-Host "`t$Component" -ForegroundColor Cyan } } # Determine the project to export if (-not [String]::IsNullOrWhiteSpace($Project) -and ($TMSession.userContext.project.name -ne $Project)) { Enter-TMProject -ProjectName $Project -TMSession $TMSession } else { $Project = $TMSession.userContext.project.name } ## Set the name to the project name if it wasn't provided $Name = [String]::IsNullOrWhiteSpace($Name) ? $Project : $Name ## Write a Banner Write-Host 'Exporting TM Extension From:' Write-Host "`tServer: " -NoNewline Write-Host $TMSession.TMServer -ForegroundColor Cyan Write-Host "`tProject: " -NoNewline Write-Host $Project -ForegroundColor Cyan Write-Host "`tAt: " -NoNewline Write-Host (Get-Date).ToString() -ForegroundColor Cyan Write-Host "`tTo: " -NoNewline Write-Host $OutPath -ForegroundColor Cyan $FilterByProvider = $false Write-Host "`tProviders:`t" -NoNewline if ($ProviderName) { Write-Host $ProviderName -ForegroundColor Cyan $FilterByProvider = $true } else { Write-Host 'All Providers' -ForegroundColor Cyan } ## Clear existing files from the output folder if ($ClearExistingFiles) { Write-Host 'Export is Clearing Existing files before writing!!' -ForegroundColor Magenta ## Delete Files $ExistingFiles = Get-ChildItem -Path (Join-Path -Path $OutPath $Name -ChildPath '_REFERENCE DESIGN') -Recurse -File -Force -ErrorAction SilentlyContinue foreach ($ExistingFile in $ExistingFiles) { Write-Verbose "Removing Old File: $($ExistingFile.Name)" Remove-Item $ExistingFile -Force -Recurse } ## Delete Folders $ExistingFolders = Get-ChildItem -Path (Join-Path -Path $OutPath $Name -ChildPath '_REFERENCE DESIGN') -Recurse -Directory -Force -ErrorAction SilentlyContinue foreach ($ExistingFolder in $ExistingFolders) { Write-Verbose "Removing Old File: $($ExistingFolder.Name)" Remove-Item $ExistingFolder -Force -Recurse -ErrorAction 'SilentlyContinue' } } } process { # Set up the directory structure for all of the output files $OutputDirectory = Join-Path $OutPath $Name $ExtensionDirectory = Join-Path $OutputDirectory '_REFERENCE DESIGN' $ExtensionDataDirectory = Join-Path $OutputDirectory '_REFERENCE DATA' Test-FolderPath $ExtensionDirectory Test-FolderPath (Join-Path $OutputDirectory 'Documentation') Test-FolderPath (Join-Path $OutputDirectory '_REFERENCE DATA') ## ## Export all of the components ## # Export the Dependency Types if ($Components.DependencyTypes) { Write-Host 'Exporting Dependency Types...' -NoNewline $DependencyTypesFolderPath = Join-Path $ExtensionDirectory 'DependencyTypes' Test-FolderPath -FolderPath $DependencyTypesFolderPath $DependencyTypes = Get-TMDependencyType -ResetIDs -TMSession $TMSession if (!$DependencyTypes) { Write-Host "`tNo Dependency Types to export" } else { foreach ($DependencyType in $DependencyTypes) { if ($DependencyType.label) { $Filename = Get-FilenameSafeString -String $DependencyType.label $DependencyType | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $DependencyTypesFolderPath "$Filename.json") -Force } } Write-Host "`t$($DependencyTypes.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Dependency Type(s) exported' } } # Export the App Types if ($Components.AppTypes) { Write-Host "Exporting App Types...`t" -NoNewline $AppTypesFolderPath = Join-Path $ExtensionDirectory 'AppTypes' Test-FolderPath -FolderPath $AppTypesFolderPath $AppTypes = Get-TMAssetOption -Type 'App Type' -ResetIDs -TMSession $TMSession if (!$AppTypes) { Write-Host "`tNo App Types to export" } else { foreach ($AppType in $AppTypes) { if ($AppType.label) { $Filename = Get-FilenameSafeString -String $AppType.label $AppType | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $AppTypesFolderPath "$Filename.json") -Force } } Write-Host "`t$($AppTypes.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'App Type(s) exported' } } # Export the Device Types if ($Components.DeviceTypes) { Write-Host 'Exporting Device Types...' -NoNewline $DeviceTypesFolderPath = Join-Path $ExtensionDirectory 'DeviceTypes' Test-FolderPath -FolderPath $DeviceTypesFolderPath $DeviceTypes = Get-TMAssetOption -Type 'Asset Type' -ResetIDs -TMSession $TMSession if (!$DeviceTypes) { Write-Host "`tNo Device Types to export" } else { foreach ($DeviceType in $DeviceTypes) { if ($DeviceType.label) { $Filename = Get-FilenameSafeString -String $DeviceType.label $DeviceType | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $DeviceTypesFolderPath "$Filename.json") -Force } } Write-Host "`t$($DeviceTypes.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Device Type(s) exported' } } # Export the Task Categories if ($Components.TaskCategories) { Write-Host 'Exporting Task Categories...' -NoNewline $TaskCategoriesFolderPath = Join-Path $ExtensionDirectory 'TaskCategories' Test-FolderPath -FolderPath $TaskCategoriesFolderPath $TaskCategories = Get-TMAssetOption -Type 'Task Category' -ResetIDs -TMSession $TMSession if (!$TaskCategories) { Write-Host "`tNo Task Categories to export" } else { foreach ($TaskCategory in $TaskCategories) { if ($TaskCategory.label) { $Filename = Get-FilenameSafeString -String $TaskCategory.label $TaskCategory | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $TaskCategoriesFolderPath "$Filename.json") -Force } } Write-Host "`t$($TaskCategories.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Task Categories exported' } } # Export the Field Specs if ($Components.FieldSpecs) { Write-Host 'Exporting Field Specs...' -NoNewline $FieldSpecs = Get-TMFieldSpecs -ResetIDs -CustomOnly -TMSession $TMSession if (!$FieldSpecs) { Write-Host "`tNo Asset Field Specs to export" } else { $FieldSpecsFolderPath = Join-Path $ExtensionDirectory 'FieldSpecs' Test-FolderPath -FolderPath (Join-Path $FieldSpecsFolderPath 'Shared') Test-FolderPath -FolderPath (Join-Path $FieldSpecsFolderPath 'Application') Test-FolderPath -FolderPath (Join-Path $FieldSpecsFolderPath 'Database') Test-FolderPath -FolderPath (Join-Path $FieldSpecsFolderPath 'Device') Test-FolderPath -FolderPath (Join-Path $FieldSpecsFolderPath 'Storage') ## Iterate through each Domain Class ##### This is done in this order expressly described because shared fields will be UPDATED because it exists in each domain. ##### This order ensures that if there is variation in the color/order, etc. Application will win. ##### This is because the Shared fields are inserted with ONE configuration across each domain. $DomainClasses = @('STORAGE', 'DATABASE', 'DEVICE', 'APPLICATION') foreach ($DomainClass in $DomainClasses) { ## Iterate over each Domain Field $DomainFields = $FieldSpecs.$DomainClass.fields foreach ($DomainField in $DomainFields) { ## Get the Shared-or-Domain class $FieldClass = ($DomainField.shared -eq 1 ? 'Shared' : $DomainClass) ## Cast the file name to a safe character set [string]$FieldFileName = (Get-FilenameSafeString $DomainField.label) + '.json' $FieldPath = Join-Path -Path $FieldSpecsFolderPath -ChildPath $FieldClass -AdditionalChildPath $FieldFileName if ($DomainField.PSObject.Properties.Name.contains('constraints')) { [void](Add-Member -InputObject $DomainField -NotePropertyName 'constraint' -NotePropertyValue $DomainField.constraints -Force) $DomainField.PSObject.Properties.Remove('constraints') } if ($DomainField.PSObject.Properties.Name.contains('default')) { [void](Add-Member -InputObject $DomainField -NotePropertyName 'defaultValue' -NotePropertyValue $DomainField.default -Force) $DomainField.PSObject.Properties.Remove('defaultValue') } ## Convert JSON Field default Values to an Object if ($DomainField.control -eq 'JSON') { $DomainField.defaultValue = ConvertFrom-Json $DomainField.defaultValue } Set-Content -Path $FieldPath -Value ($DomainField | ConvertTo-Json -Depth 5) -Force } } Write-Host "`tAsset Field Specs exported" } } # Export the Bundles if ($Components.Bundles) { Write-Host "Exporting Bundles...`t" -NoNewline $BundlesFolderPath = Join-Path $ExtensionDirectory 'Bundles' Test-FolderPath -FolderPath $BundlesFolderPath $Bundles = Get-TMBundle -ResetIDs -TMSession $TMSession if (!$Bundles) { Write-Host "`tNo Bundles to export" } else { $Bundles | ForEach-Object { $Filename = Get-FilenameSafeString -String $_.Name $_ | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $BundlesFolderPath "$Filename.json") -Force } Write-Host "`t$($Bundles.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Bundle(s) exported' } } # Export the Events if ($Components.Events) { Write-Host "Exporting Events...`t" -NoNewline $EventsFolderPath = Join-Path $ExtensionDirectory 'Events' Test-FolderPath -FolderPath $EventsFolderPath $Events = Get-TMEvent -ResetIDs -TMSession $TMSession if (!$Events) { Write-Host "`tNo Events to export" } else { $Events | ForEach-Object { $Filename = Get-FilenameSafeString -String $_.Name $_ | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $EventsFolderPath "$Filename.json") -Force } Write-Host "`t$($Events.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Event(s) exported' } } # Export the Teams if ($Components.Teams) { Write-Host "Exporting Teams...`t" -NoNewline $TeamsFolderPath = Join-Path $ExtensionDirectory 'Teams' Test-FolderPath -FolderPath $TeamsFolderPath $Teams = Get-TMTeam -TMSession $TMSession if (!$Teams) { Write-Host "`tNo Teams to export" } else { $Teams | ForEach-Object { $Filename = Get-FilenameSafeString -String $_.Code $_ | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $TeamsFolderPath "$Filename.json") -Force } Write-Host "`t$($Teams.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Team(s) exported' } } # Export the Providers $Providers = Get-TMProvider -ResetIDs -TMSession $TMSession if (-not $FilterByProvider) { $ProviderName = $Providers.Name } if ($Components.Providers) { Write-Host "Exporting Providers...`t" -NoNewline $ProvidersFolderPath = Join-Path $ExtensionDirectory 'Providers' Test-FolderPath -FolderPath $ProvidersFolderPath if (!$Providers) { Write-Host "`tNo Providers to export" } else { if ($FilterByProvider) { $Providers = $Providers | Where-Object Name -In $ProviderName } $Providers | ForEach-Object { $Filename = Get-FilenameSafeString -String $_.Name $_ | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $ProvidersFolderPath "$Filename.json") -Force } Write-Host "`t$($Providers.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Provider(s) exported' } } # Export the Actions if ($Components.Actions) { Write-Host "Exporting Actions...`t" -NoNewline $ActionsFolderPath = Join-Path $ExtensionDirectory 'Actions' Test-FolderPath $ActionsFolderPath $Actions = Get-TMAction -SaveCodePath $ActionsFolderPath -ProviderName $ProviderName -ResetIDs -Passthru -TMSession $TMSession if (!$Actions) { Write-Host "`tNo Actions to export" } else { Write-Host "`t$($Actions.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Action(s) exported' } } # Export the DataScript Scripts if ($Components.DataScripts) { Write-Host 'Exporting DataScripts...' -NoNewline $DataScriptsFolderPath = Join-Path $ExtensionDirectory 'DataScripts' Test-FolderPath $DataScriptsFolderPath $DataScripts = Get-TMDatascript -ResetIDs -SaveCodePath $DataScriptsFolderPath -ProviderName $ProviderName -Passthru -TMSession $TMSession if (!$DataScripts) { Write-Host "`tNo Datascripts to export" } else { # TODO: Is the 'Private' folder supposed to be excluded? Write-Host "`t$($DataScripts.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Datascript(s) exported' } } # Export the Recipes if ($Components.Recipes) { Write-Host "Exporting Recipes...`t" -NoNewline $RecipesFolderPath = Join-Path $ExtensionDirectory 'Recipes' Test-FolderPath $RecipesFolderPath $Recipes = Get-TMRecipe -ResetIDs -SaveCodePath $RecipesFolderPath -Passthru -TMSession $TMSession if (!$Recipes) { Write-Host "`tNo Recipes to export" } else { Write-Host "`t$($Recipes.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Recipe(s) exported' } } # Export the Tags if ($Components.Tags) { Write-Host "Exporting Tags...`t" -NoNewline $TagsFolderPath = Join-Path $ExtensionDirectory 'Tags' Test-FolderPath -FolderPath $TagsFolderPath $Tags = Get-TMTag -ResetIDs -TMSession $TMSession if (!$Tags) { Write-Host "`tNo Tags to export" } else { $Tags | ForEach-Object { $Filename = Get-FilenameSafeString -String $_.Name $_ | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $TagsFolderPath "$Filename.json") -Force } Write-Host "`t$($Tags.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'Tags(s) exported' } } # Export the AssetViews if ($Components.AssetViews) { Write-Host "Exporting AssetViews...`t" -NoNewline $AssetViewsFolderPath = Join-Path $ExtensionDirectory 'AssetViews' Test-FolderPath -FolderPath $AssetViewsFolderPath $AssetViews = Get-TMAssetViewConfiguration -ResetIDs -TMSession $TMSession -ExcludeSystem if (!$AssetViews) { Write-Host "`tNo AssetViews to export" return } foreach ($AssetView in $AssetViews) { Test-FolderPath -FolderPath $AssetViewsFolderPath $AssetViewFileName = Get-FilenameSafeString $AssetView.Name $AssetView | ConvertTo-Json -Depth 100 | Set-Content -Path (Join-Path $AssetViewsFolderPath "$AssetViewFileName.json") -Force } Write-Host "`t$($AssetViews.Count) " -NoNewline -ForegroundColor DarkBlue Write-Host 'AssetView(s) exported' } # Export Asset Data if ($Components.AssetData) { Write-Host 'Exporting Asset Data...' -NoNewline Export-TMExcel -Path $ExtensionDataDirectory -TMSession $TMSession Write-Host "`t`tAsset Data exported" } # Write-Host 'Creating package.json file...' # New-TMExtensionPackageFile -Name $Name -Path $OutputDirectory } } function New-TMExtensionPackageFile { <# .SYNOPSIS Creates a new package.json file for a locally downloaded/exported Reference Design .DESCRIPTION This function will look at the .PARAMETER Name Parameter description .PARAMETER Path Parameter description .PARAMETER Description Parameter description .PARAMETER Author Parameter description .PARAMETER Email Parameter description .PARAMETER Passthru A switch indicating that the created package object should be sent back to the caller .EXAMPLE New-TMExtensionPackageFile -Name 'TM - Rules Engine' -Path 'C:\DEV\Downloaded Reference Design' .EXAMPLE $PackageSplat = @{ Name = VMware - vCenter' Path = 'C:\Users\user\TMD_Files\Reference Designs\Downloaded\VMware - vCenter' Description = 'This is a detailed description of the Reference Design' Author = 'Me' Email = 'me@tdsi.com' } New-TMExtensionPackageFile @PackageSplat .EXAMPLE $ExtensionPackage = New-TMExtensionPackageFile -Name 'New Extension' -Path 'C:\DEV\Extension' -Passthru Write-Host "There are $($ExtensionPackage.Inventory.actions.Count) action(s) included in this Reference Design" .OUTPUTS A [PSCustomObject] if -Passthru is specified, otherwise nothing #> [alias('New-TMReferenceDesignPackageFile')] param( [Parameter(Mandatory = $true, Position = 0)] [String]$Name, [Parameter(Mandatory = $true, Position = 1)] [ValidateScript( { (Get-Item $_) -is [System.IO.DirectoryInfo] })] [String]$Path, [Parameter(Mandatory = $false, Position = 2)] [String]$Description, [Parameter(Mandatory = $false, Position = 3)] [String]$Author, [Parameter(Mandatory = $false, Position = 4)] [String]$Email, [Parameter(Mandatory = $false)] [Switch]$Passthru ) $Inventory = @{ Artifacts = [System.Collections.ArrayList]::new() ArtifactLinks = [System.Collections.ArrayList]::new() Actions = [System.Collections.ArrayList]::new() DataScripts = [System.Collections.ArrayList]::new() Recipes = [System.Collections.ArrayList]::new() Bundles = [System.Collections.ArrayList]::new() Providers = [System.Collections.ArrayList]::new() DependencyTypes = [System.Collections.ArrayList]::new() FieldSpecs = @{} } $ExtensionPath = Join-Path $Path '_REFERENCE DESIGN' ## Read the Actions Folder to get the name of Scripts $ActionFiles = Get-ChildItem -Path (Join-Path $ExtensionPath 'Actions') -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.Name -like '*.ps1' } foreach ($ActionFile in $ActionFiles) { ## Convert the Script into a proper ActionObject $Action = Read-TMActionScriptFile -Path $ActionFile.FullName -TMSession $TMSession ## Some files are not setup or created with all of the metadata. Fill in details based on the filename. if (-Not $Action.Name) { ## Add this Action to the Actions array for writing to JSON [void]$Inventory.Actions.Add( [PSCustomObject]@{ name = $ActionFile.BaseName description = '' } ) } else { ## Add this Action to the Actions array for writing to JSON [void]$Inventory.Actions.Add( [PSCustomObject]@{ name = $Action.Name description = $Action.Description } ) } } ## Read the DataScript Scripts Folder to get the name Scripts if (Test-Path($ExtensionPath + '\DataScripts')) { $DataScriptFiles = Get-ChildItem -Path (Join-Path $ExtensionPath 'DataScripts') -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.Name -like '*.groovy' } } elseif (Test-Path($ExtensionPath + '\ETL')) { $DataScriptFiles = Get-ChildItem -Path (Join-Path $ExtensionPath 'ETL') -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.Name -like '*.groovy' } } foreach ($DataScriptFile in $DataScriptFiles) { ## Convert the Script into a proper TMDatascript Object $DataScript_File = Read-TMDatascriptFile -Path $DataScriptFiles.FullName -ErrorAction 'SilentlyContinue' ## Some files are not setup or created with all of the metadata. Fill in details based on the filename. if (-Not $DataScript_File) { [void]$Inventory.DataScripts.Add( [PSCustomObject]@{ name = $DataScript_File.name description = '' } ) } else { ## Add this DataScript Script to the array for writing to JSON [void]$Inventory.DataScripts.Add( [PSCustomObject]@{ name = $DataScript_File.name description = $DataScript_File.description } ) } } ## Read the Recipes Folder to get the name Scripts $RecipeFiles = Get-ChildItem -Path (Join-Path $ExtensionPath 'Recipes') -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.Name -like '*.json' } foreach ($RecipeFile in $RecipeFiles) { ## Convert the Script into a proper TMRecipeScript Object $Recipe = Read-TMRecipeScriptFile -Path $RecipeFile.FullName ## Some files are not setup or created with all of the metadata. Fill in details based on the filename. if (-Not $Recipe) { ## Add this Recipe Script to the array for writing to JSON [void]$Inventory.Recipes.Add( [PSCustomObject]@{ name = $RecipeFile.name description = $RecipeFile.description } ) } else { ## Add this Recipe Script to the array for writing to JSON [void]$Inventory.Recipes.Add( [PSCustomObject]@{ name = $Recipe.name description = $Recipe.description } ) } } } |