Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
runs-on: windows-latest

steps:
- name: PowerShell Update to latest stable (initially because 7.2.13/lts had issues, forced latest stable 7.3.6 or higher)
- name: PowerShell Update to latest stable (initially because 7.2.13/lts had issues, forcing latest stable)
uses: bjompen/UpdatePWSHAction@v1.0.1
with:
ReleaseVersion: 'Stable'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
using System.Linq;
using System.Management.Automation;
using System.ServiceModel;
using System.Threading;
using Trisoft.ISHRemote.Exceptions;
using Trisoft.ISHRemote.ExtensionMethods;
using Trisoft.ISHRemote.HelperClasses;
using Trisoft.ISHRemote.Objects;
using Trisoft.ISHRemote.Objects.Public;
Expand All @@ -48,8 +46,8 @@ public sealed class GetIshDocumentObj : DocumentObjCmdlet
/// <summary>
/// <para type="description">The IshSession variable holds the authentication and contract information. This object can be initialized using the New-IshSession cmdlet.</para>
/// </summary>
[Parameter(Mandatory =false, ValueFromPipelineByPropertyName = false, ParameterSetName = "ParameterGroup")]
[Parameter(Mandatory =false, ValueFromPipelineByPropertyName = false, ParameterSetName = "IshObjectsGroup")]
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = false, ParameterSetName = "ParameterGroup")]
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = false, ParameterSetName = "IshObjectsGroup")]
[ValidateNotNullOrEmpty]
public IshSession IshSession { get; set; }

Expand Down Expand Up @@ -81,7 +79,7 @@ public sealed class GetIshDocumentObj : DocumentObjCmdlet
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = false, ParameterSetName = "ParameterGroup")]
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = false, ParameterSetName = "IshObjectsGroup")]
[ValidateNotNullOrEmpty]
public Enumerations.StatusFilter StatusFilter
public Enumerations.StatusFilter StatusFilter
{
get { return _statusFilter; }
set { _statusFilter = value; }
Expand Down Expand Up @@ -112,12 +110,6 @@ public SwitchParameter IncludeData
[AllowEmptyCollection]
public IshObject[] IshObject { get; set; }

/// <summary>
/// <para type="description">Switch parameter to use REST API (OpenAPI) instead of SOAP API for retrieval. This is experimental in Phase 1.</para>
/// </summary>
[Parameter(Mandatory = false, ParameterSetName = "ParameterGroup")]
public SwitchParameter UseREST { get; set; }




Expand Down Expand Up @@ -156,7 +148,7 @@ protected override void ProcessRecord()
{
// 1. Validating the input
WriteDebug("Validating");

List<IshObject> returnIshObjects = new List<IshObject>();

if (IshObject != null && IshObject.Length == 0)
Expand Down Expand Up @@ -224,85 +216,24 @@ protected override void ProcessRecord()
var statusFilter = EnumConverter.ToStatusFilter<DocumentObj25ServiceReference.StatusFilter>(StatusFilter);
if (!_includeData)
{
if (!UseREST)
{
//RetrieveMetadata via SOAP (default implementation)
WriteDebug($"[SOAP] Retrieving LogicalId.length[{LogicalId.Length}] StatusFilter[{statusFilter}] MetadataFilter.length[{metadataFilter.ToXml().Length}] RequestedMetadata.length[{requestedMetadata.ToXml().Length}] 0/{LogicalId.Length}");
// Divides the list of language card ids in different lists that all have maximally MetadataBatchSize elements
List<List<string>> dividedLogicalIdsList = DivideListInBatches<string>(LogicalId.ToList(), IshSession.MetadataBatchSize);
int currentLogicalIdCount = 0;
foreach (List<string> logicalIdBatch in dividedLogicalIdsList)
{
// Process language card ids in batches
string xmlIshObjects = IshSession.DocumentObj25.RetrieveMetadata(
logicalIdBatch.ToArray(),
statusFilter,
metadataFilter.ToXml(),
requestedMetadata.ToXml());
IshObjects retrievedObjects = new IshObjects(ISHType, xmlIshObjects);
returnIshObjects.AddRange(retrievedObjects.Objects);
currentLogicalIdCount += logicalIdBatch.Count;
WriteDebug($"[SOAP] Retrieving LogicalId.length[{logicalIdBatch.Count}] StatusFilter[{statusFilter}] MetadataFilter.length[{metadataFilter.ToXml().Length}] RequestedMetadata.length[{requestedMetadata.ToXml().Length}] {currentLogicalIdCount}/{LogicalId.Length}");
}
}
else
//RetrieveMetadata
WriteDebug($"Retrieving LogicalId.length[{LogicalId.Length}] StatusFilter[{statusFilter}] MetadataFilter.length[{metadataFilter.ToXml().Length}] RequestedMetadata.length[{requestedMetadata.ToXml().Length}] 0/{LogicalId.Length}");
// Divides the list of language card ids in different lists that all have maximally MetadataBatchSize elements
List<List<string>> dividedLogicalIdsList = DivideListInBatches<string>(LogicalId.ToList(), IshSession.MetadataBatchSize);
int currentLogicalIdCount = 0;
foreach (List<string> logicalIdBatch in dividedLogicalIdsList)
{
//RetrieveMetadata via REST/OpenAPI (experimental Phase 1 implementation)
WriteDebug($"[REST] Retrieving LogicalId.length[{LogicalId.Length}] StatusFilter[{StatusFilter}] MetadataFilter fields[{metadataFilter.Fields().Length}] RequestedMetadata fields[{requestedMetadata.Fields().Length}]");

// Convert ISHRemote types to OpenAPI types
var openApiStatusFilter = StatusFilter.ToOpenApiISH30StatusFilter();
var filterFields = metadataFilter.ToOpenApiISH30FilterFieldValues();
var requestedFields = requestedMetadata.ToOpenApiISH30RequestedFields();

// Divide logical IDs into batches (same batch size as SOAP for consistency)
List<List<string>> dividedLogicalIdsList = DivideListInBatches<string>(LogicalId.ToList(), IshSession.MetadataBatchSize);
int currentLogicalIdCount = 0;

foreach (List<string> logicalIdBatch in dividedLogicalIdsList)
{
// Build the request object for this batch
var getDocumentObjectRequest = new OpenApiISH30.GetDocumentObjectListByLogicalId
{
LogicalIds = logicalIdBatch,
StatusFilter = openApiStatusFilter,
FilterFields = filterFields,
Fields = requestedFields,
SelectedProperties = OpenApiISH30.SelectedProperties.Id,
FieldGroup = requestedMetadata.Fields().Length > 0 ? OpenApiISH30.FieldGroup.None : OpenApiISH30.FieldGroup.Basic,
IncludeLinks = false,
IncludePartialItems = false
};

WriteDebug($"[REST] Calling GetDocumentObjectListByLogicalIdAsync for batch {currentLogicalIdCount}/{LogicalId.Length}");

// Make the async call synchronously (using GetAwaiter().GetResult() for PowerShell compatibility)
var documentObjects = IshSession.OpenApiISH30Client.GetDocumentObjectListByLogicalIdAsync(
getDocumentObjectRequest,
CancellationToken.None)
.GetAwaiter()
.GetResult();

WriteDebug($"[REST] Retrieved {documentObjects.Count} document objects from OpenAPI");

// TODO [Phase 2]: Convert OpenApiISH30.DocumentObject collection to IshObjects
// For Phase 1, we log that REST API was called successfully but cannot yet process results
WriteWarning($"[REST Phase 1] Successfully retrieved {documentObjects.Count} objects via REST API, but conversion to IshObjects not yet implemented. Falling back to SOAP for this batch.");

// Fallback to SOAP for actual data retrieval in Phase 1
string xmlIshObjects = IshSession.DocumentObj25.RetrieveMetadata(
logicalIdBatch.ToArray(),
statusFilter,
metadataFilter.ToXml(),
requestedMetadata.ToXml());
IshObjects retrievedObjects = new IshObjects(ISHType, xmlIshObjects);
returnIshObjects.AddRange(retrievedObjects.Objects);

currentLogicalIdCount += logicalIdBatch.Count;
WriteDebug($"[REST] Processed batch {currentLogicalIdCount}/{LogicalId.Length}");
}
// Process language card ids in batches
string xmlIshObjects = IshSession.DocumentObj25.RetrieveMetadata(
logicalIdBatch.ToArray(),
statusFilter,
metadataFilter.ToXml(),
requestedMetadata.ToXml());
IshObjects retrievedObjects = new IshObjects(ISHType, xmlIshObjects);
returnIshObjects.AddRange(retrievedObjects.Objects);
currentLogicalIdCount += logicalIdBatch.Count;
WriteDebug($"Retrieving LogicalId.length[{logicalIdBatch.Count}] StatusFilter[{statusFilter}] MetadataFilter.length[{metadataFilter.ToXml().Length}] RequestedMetadata.length[{requestedMetadata.ToXml().Length}] {currentLogicalIdCount}/{LogicalId.Length}");
}

}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,45 @@
}

Describe "Test-Prerequisite" -Tags "Read" {
Context "Package ISHRemote verification" {
It "Folder ISHRemote exists" {
Test-Path -Path $moduleFolder | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "ISHRemote.psm1") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "ISHRemote.psd1") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "ISHRemote.Format.ps1xml") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "Trisoft.ISHRemote.dll-Help.xml") | Should -Be $true
}
It "Folder ISHRemote/Scripts exists" {
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "Scripts") | Should -Be $true
}
It "Folder ISHRemote/Scripts/Public exists" {
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "Scripts/Public") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "Scripts/Public/Expand-ISHParameter.ps1") | Should -Be $true
}
It "Folder ISHRemote/Scripts/Private exists" {
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "Scripts/Private") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "Scripts/Private/Register-IshAuxParameterCompleter.ps1") | Should -Be $true
}
It "Folder ISHRemote/net48 exists" {
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net48") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net48/Trisoft.ISHRemote.dll") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net48/Trisoft.ISHRemote.xml") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net48/Trisoft.ISHRemote.dll-Help.xml") | Should -Be $true
}
It "Folder ISHRemote/net6.0 exists" {
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net6.0") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net6.0/Trisoft.ISHRemote.dll") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net6.0/Trisoft.ISHRemote.xml") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net6.0/Trisoft.ISHRemote.dll-Help.xml") | Should -Be $true
}
It "Folder ISHRemote/net10.0 exists" {
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net10.0") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net10.0/Trisoft.ISHRemote.dll") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net10.0/Trisoft.ISHRemote.xml") | Should -Be $true
Test-Path -Path (Join-Path -Path $moduleFolder -ChildPath "net10.0/Trisoft.ISHRemote.dll-Help.xml") | Should -Be $true
}
}

Context "ISHRemote.PesterSetup.Debug.ps1 minimal overwrites" {
It "baseUrl" {
$baseUrl | Should -Not -Be 'https://ish.example.com'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ BeforeAll {

}

Describe "Invoke-IshRemoteMcpHandleRequest" {
Describe "Invoke-IshRemoteMcpHandleRequest" -Skip:($PSVersionTable.PSVersion.Major -lt 7){
Context "Method Initialize" {
BeforeAll {
Mock -ModuleName ISHRemote Write-IshRemoteLog { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ BeforeAll {
. (Join-Path (Split-Path -Parent $PSCommandPath) "\..\..\ISHRemote.PesterSetup.ps1")
}

Describe "Register-IshRemoteMcpInstructions" {
Describe "Register-IshRemoteMcpInstructions" -Skip:($PSVersionTable.PSVersion.Major -lt 7) {

Context "Function Output" {
It "Should return valid JSON" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ BeforeAll {

}

Describe "Register-IshRemoteMcpTool" -Tags "Read" {
Describe "Register-IshRemoteMcpTool" -Tags "Read" -Skip:($PSVersionTable.PSVersion.Major -lt 7) {
Context "Register-IshRemoteMcpTool (beware Get-Help is empty if Get-InstalledPSResource still shows ISHRemote installed)" {
BeforeEach{
Mock -ModuleName ISHRemote Write-IshRemoteLog { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ BeforeAll {
}
}

Describe "Start-IshRemoteMcpServer" -Tags "Read" {
Describe "Start-IshRemoteMcpServer" -Tags "Read" -Skip:($PSVersionTable.PSVersion.Major -lt 7) {
Context "Start-IshRemoteMcpServer with ActivateWhileLoop=false" {
BeforeEach {
Mock -ModuleName ISHRemote Write-IshRemoteLog { }
Expand Down
21 changes: 11 additions & 10 deletions Source/ISHRemote/Trisoft.ISHRemote/Trisoft.ISHRemote.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,22 @@
<XmlDoc2CmdletDocToolPath>net48\XmlDoc2CmdletDoc.dll</XmlDoc2CmdletDocToolPath>
<XmlDocToolsPath>net48\XmlDoc2CmdletDoc.dll</XmlDocToolsPath>
</PropertyGroup>
<!-- Trisoft.ISHRemote.dll-Help.xml is generated next to \bin\Debug\ISHRemote\net48\Trisoft.ISHRemote.dll
then duplicated next to \bin\Debug\ISHRemote\net6.0\Trisoft.ISHRemote.dll so that debug get-help have proper parameter descriptions
then copied to ISHRemote packaging folder where it is delivered in the root and per TargetFramework subfolder
<!-- Trisoft.ISHRemote.dll-Help.xml is generated next to \bin\Debug\net48\Trisoft.ISHRemote.dll during net48 build
then copied to ISHRemote packaging folder root
then copied per non-net48 framework
-->
<Target Name="CopyCmdletDoc" AfterTargets="AfterBuild" Condition="'$(TargetFramework)' == 'net48'">
<PropertyGroup>
<ISHRemoteDir>$(ProjectDir)bin/$(Configuration)/ISHRemote</ISHRemoteDir>
<ISHRemoteNet6Dir>$(ProjectDir)bin/$(Configuration)/ISHRemote/net6.0</ISHRemoteNet6Dir>
<ISHRemoteNet10Dir>$(ProjectDir)bin/$(Configuration)/ISHRemote/net10.0</ISHRemoteNet10Dir>
</PropertyGroup>
<MakeDir Directories="$(ISHRemoteDir)" Condition="Exists('$(ISHRemoteDir)')" />
<MakeDir Directories="$(ProjectDir)bin/$(Configuration)/net6.0" Condition="Exists('$(ProjectDir)bin/$(Configuration)/net6.0')" />
<MakeDir Directories="$(ProjectDir)bin/$(Configuration)/net10.0" Condition="Exists('$(ProjectDir)bin/$(Configuration)/net10.0')" />
<MakeDir Directories="$(ISHRemoteDir)" Condition="!Exists('$(ISHRemoteDir)')" />
<MakeDir Directories="$(ISHRemoteNet6Dir)" Condition="!Exists('$(ISHRemoteNet6Dir)')" />
<MakeDir Directories="$(ISHRemoteNet10Dir)" Condition="!Exists('$(ISHRemoteNet10Dir)')" />
<Copy SourceFiles="$(TargetPath)-Help.xml" DestinationFolder="$(ISHRemoteDir)" />
<Copy SourceFiles="$(TargetPath)-Help.xml" DestinationFolder="$(ProjectDir)bin/$(Configuration)/net6.0" />
<Copy SourceFiles="$(TargetPath)-Help.xml" DestinationFolder="$(ProjectDir)bin/$(Configuration)/net10.0" />
<Copy SourceFiles="$(TargetPath)-Help.xml" DestinationFolder="$(ISHRemoteNet6Dir)" />
<Copy SourceFiles="$(TargetPath)-Help.xml" DestinationFolder="$(ISHRemoteNet10Dir)" />
</Target>

<!-- Generating Module Manifest only once -->
Expand All @@ -147,7 +149,6 @@
<PowerShellExe Condition=" '$(PowerShellExe)'=='' ">&quot;%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe&quot;</PowerShellExe>
<ISHRemoteDir>$(ProjectDir)bin/$(Configuration)/ISHRemote</ISHRemoteDir>
<ISHRemote48DllFilePath>$(ProjectDir)bin/$(Configuration)/net48/Trisoft.ISHRemote.dll</ISHRemote48DllFilePath>
<ISHRemote60DllFilePath>$(ProjectDir)bin/$(Configuration)/net6.0/Trisoft.ISHRemote.dll</ISHRemote60DllFilePath>
<ManifestFilePath>$(ISHRemoteDir)/$(ModuleName).psd1</ManifestFilePath>
<RootModuleFileName>$(ModuleName).psm1</RootModuleFileName>
<FormatsToProcessFileName>$(ModuleName).Format.ps1xml</FormatsToProcessFileName>
Expand All @@ -158,7 +159,7 @@
</Target>

<!-- Copy all the required files to folder named ISHRemote which is needed for packaging -->
<Target Name="CopyRequiredFilesToPowerShellModuleFolder" AfterTargets="ModuleManifest" Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<Target Name="CopyRequiredFilesToPowerShellModuleFolder" AfterTargets="ModuleManifest">
<PropertyGroup>
<LocalPSRepoDir>$(ProjectDir)bin/$(Configuration)</LocalPSRepoDir>
<ISHRemoteFrameworkDir>$(ProjectDir)bin/$(Configuration)/ISHRemote/$(TargetFramework)</ISHRemoteFrameworkDir>
Expand Down
Loading