From 0cbacb02685b40eda22030c6fc29281f03582cdd Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Tue, 3 Sep 2024 16:40:16 +0200 Subject: [PATCH 1/5] Added cmdlets to work with external items --- CHANGELOG.md | 3 + .../Get-PnPSearchExternalConnection.md | 90 +++++++++++ documentation/Get-PnPSearchExternalSchema.md | 83 ++++++++++ .../New-PnPSearchExternalConnection.md | 128 +++++++++++++++ .../Remove-PnPSearchExternalConnection.md | 83 ++++++++++ .../Set-PnPSearchExternalConnection.md | 135 ++++++++++++++++ documentation/Set-PnPSearchExternalItem.md | 8 +- documentation/Set-PnPSearchExternalSchema.md | 150 ++++++++++++++++++ .../SearchExternalConnectionPipeBind.cs | 39 +++++ .../Enums/SearchExternalConnectionState.cs | 29 ++++ .../SearchExternalSchemaPropertyLabel.cs | 59 +++++++ .../Enums/SearchExternalSchemaPropertyType.cs | 54 +++++++ .../MicrosoftSearch/ExternalConnection.cs | 42 +++++ .../ExternalConnectionConfiguration.cs | 16 ++ .../Graph/MicrosoftSearch/ExternalSchema.cs | 23 +++ .../MicrosoftSearch/ExternalSchemaProperty.cs | 58 +++++++ .../Search/GetSearchExternalConnection.cs | 39 +++++ .../Search/GetSearchExternalSchema.cs | 24 +++ .../Search/NewSearchExternalConnection.cs | 53 +++++++ .../Search/RemoveSearchExternalConnection.cs | 21 +++ .../Search/SetSearchExternalConnection.cs | 49 ++++++ src/Commands/Search/SetSearchExternalItem.cs | 24 +-- .../Search/SetSearchExternalSchema.cs | 61 +++++++ src/Commands/Utilities/REST/GraphHelper.cs | 12 +- 24 files changed, 1257 insertions(+), 26 deletions(-) create mode 100644 documentation/Get-PnPSearchExternalConnection.md create mode 100644 documentation/Get-PnPSearchExternalSchema.md create mode 100644 documentation/New-PnPSearchExternalConnection.md create mode 100644 documentation/Remove-PnPSearchExternalConnection.md create mode 100644 documentation/Set-PnPSearchExternalConnection.md create mode 100644 documentation/Set-PnPSearchExternalSchema.md create mode 100644 src/Commands/Base/PipeBinds/SearchExternalConnectionPipeBind.cs create mode 100644 src/Commands/Enums/SearchExternalConnectionState.cs create mode 100644 src/Commands/Enums/SearchExternalSchemaPropertyLabel.cs create mode 100644 src/Commands/Enums/SearchExternalSchemaPropertyType.cs create mode 100644 src/Commands/Model/Graph/MicrosoftSearch/ExternalConnection.cs create mode 100644 src/Commands/Model/Graph/MicrosoftSearch/ExternalConnectionConfiguration.cs create mode 100644 src/Commands/Model/Graph/MicrosoftSearch/ExternalSchema.cs create mode 100644 src/Commands/Model/Graph/MicrosoftSearch/ExternalSchemaProperty.cs create mode 100644 src/Commands/Search/GetSearchExternalConnection.cs create mode 100644 src/Commands/Search/GetSearchExternalSchema.cs create mode 100644 src/Commands/Search/NewSearchExternalConnection.cs create mode 100644 src/Commands/Search/RemoveSearchExternalConnection.cs create mode 100644 src/Commands/Search/SetSearchExternalConnection.cs create mode 100644 src/Commands/Search/SetSearchExternalSchema.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c616da5c..a6a7b9ff9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added support for `WAM` login for Windows OS to support Windows Hello, FIDO keys, Conditional Access policies and other secure authentication modes. - Added `-SkipCertCreation` parameter in `Register-PnPAzureADApp` cmdlet to prevent creation and uploading of certificates in the Entra ID app. - Added support to `-ValidateConnection` in managed identity authentication. +- Added `New-PnPSearchExternalConnection`, `Get-PnPSearchExternalConnection`, `Set-PnPSearchExternalConnection` and `Remove-PnPSearchExternalConnection` cmdlets to manage external connections for Microsoft Search +- Added `Get-PnPSearchExternalSchema` and `Set-PnPSearchExternalSchema` cmdlets to manage the schema for external connections for Microsoft Search ### Changed @@ -35,6 +37,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Giacomo Pozzoni [jackpoz] - Nishkalank Bezawada [NishkalankBezawada] - Reshmee Auckloo [reshmee011] +- Koen Zomers [koenzomers] ## [2.10.0] diff --git a/documentation/Get-PnPSearchExternalConnection.md b/documentation/Get-PnPSearchExternalConnection.md new file mode 100644 index 000000000..6a8111df6 --- /dev/null +++ b/documentation/Get-PnPSearchExternalConnection.md @@ -0,0 +1,90 @@ +--- +Module Name: PnP.PowerShell +schema: 2.0.0 +applicable: SharePoint Online +online version: https://pnp.github.io/powershell/cmdlets/Get-PnPSearchExternalConnection.html +external help file: PnP.PowerShell.dll-Help.xml +title: Get-PnPSearchExternalConnection +--- + +# Get-PnPSearchExternalConnection + +## SYNOPSIS + +**Required Permissions** + + * Microsoft Graph API : One of ExternalConnection.ReadWrite.OwnedBy, ExternalConnection.Read.All, ExternalConnection.ReadWrite.All + +Retrieves all connections to external datasources belonging to Microsoft Search + +## SYNTAX + +```powershell +Get-PnPSearchExternalConnection [-Identity ] [-Verbose] [-Connection ] +``` + +## DESCRIPTION + +This cmdlet can be used to retrieve all connections to external datasources that are being indexed into Microsoft Search through a custom connector. Use [Set-PnPSearchExternalItem](Set-PnPSearchExternalItem.md) to add items to the index for a connector. + +## EXAMPLES + +### EXAMPLE 1 +```powershell +Get-PnPSearchExternalConnection +``` + +This will return all connections to external datasources that are being indexed into Microsoft Search that exist within the tenant. + +### EXAMPLE 2 +```powershell +Get-PnPSearchExternalConnection -Identity "pnppowershell" +``` + +This will return the connection to the external datasource with the specified identity that is being indexed into Microsoft Search. + +## PARAMETERS + +### -Connection +Optional connection to be used by the cmdlet. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing [Get-PnPConnection](Get-PnPConnection.md). + +```yaml +Type: PnPConnection +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Identity +Unique identifier of the external connection in Microsoft Search. If not provided, all connections will be returned. + +```yaml +Type: String +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Verbose +When provided, additional debug statements will be shown while executing the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) \ No newline at end of file diff --git a/documentation/Get-PnPSearchExternalSchema.md b/documentation/Get-PnPSearchExternalSchema.md new file mode 100644 index 000000000..ac8701b37 --- /dev/null +++ b/documentation/Get-PnPSearchExternalSchema.md @@ -0,0 +1,83 @@ +--- +Module Name: PnP.PowerShell +schema: 2.0.0 +applicable: SharePoint Online +online version: https://pnp.github.io/powershell/cmdlets/Get-PnPSearchExternalSchema.html +external help file: PnP.PowerShell.dll-Help.xml +title: Get-PnPSearchExternalSchema +--- + +# Get-PnPSearchExternalSchema + +## SYNOPSIS + +**Required Permissions** + + * Microsoft Graph API : One of ExternalConnection.ReadWrite.OwnedBy, ExternalConnection.Read.All, ExternalConnection.ReadWrite.All + +Retrieves the schema set on a connection to an external datasource belonging to Microsoft Search + +## SYNTAX + +```powershell +Get-PnPSearchExternalSchema -ConnectionId [-Verbose] [-Connection ] +``` + +## DESCRIPTION + +This cmdlet can be used to retrieve the current schema set on a connection to an external datasource that is being indexed into Microsoft Search through a custom connector. + +## EXAMPLES + +### EXAMPLE 1 +```powershell +Get-PnPSearchExternalSchema -ConnectionId "pnppowershell" +``` + +This will return the current schema being used on the external Microsoft Search connection with the specified identity. + +## PARAMETERS + +### -Connection +Optional connection to be used by the cmdlet. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing [Get-PnPConnection](Get-PnPConnection.md). + +```yaml +Type: PnPConnection +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ConnectionId +Unique identifier or instance of the external connection in Microsoft Search to retrieve the schema for + +```yaml +Type: String +Parameter Sets: (All) +Required: True +Position: Named +Default value: None +Accept pipeline input: True +Accept wildcard characters: False +``` + +### -Verbose +When provided, additional debug statements will be shown while executing the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) \ No newline at end of file diff --git a/documentation/New-PnPSearchExternalConnection.md b/documentation/New-PnPSearchExternalConnection.md new file mode 100644 index 000000000..c1169a288 --- /dev/null +++ b/documentation/New-PnPSearchExternalConnection.md @@ -0,0 +1,128 @@ +--- +Module Name: PnP.PowerShell +schema: 2.0.0 +applicable: SharePoint Online +online version: https://pnp.github.io/powershell/cmdlets/New-PnPSearchExternalConnection.html +external help file: PnP.PowerShell.dll-Help.xml +title: New-PnPSearchExternalConnection +--- + +# New-PnPSearchExternalConnection + +## SYNOPSIS + +**Required Permissions** + + * Microsoft Graph API : One of ExternalConnection.ReadWrite.OwnedBy, ExternalConnection.ReadWrite.All + +Creates a new connection to an external datasource for Microsoft Search + +## SYNTAX + +```powershell +New-PnPSearchExternalConnection -Identity -Name -Description [-AuthorizedAppIds ] [-Verbose] [-Connection ] +``` + +## DESCRIPTION + +This cmdlet can be used to create a new connection to an external datasource that needs to be indexed into Microsoft Search through a custom connector. Use [Set-PnPSearchExternalItem](Set-PnPSearchExternalItem.md) to add items to the index for this connector. + +## EXAMPLES + +### EXAMPLE 1 +```powershell +New-PnPSearchExternalConnection -Identity "pnppowershell" -Name "PnP PowerShell" -Description "External content ingested using PnP PowerShell" +``` + +This will create a new external connection with the provided name and description. Any application registration with the proper permissions can add items to the index for this connection. + +### EXAMPLE 2 +```powershell +New-PnPSearchExternalConnection -Identity "pnppowershell" -Name "PnP PowerShell" -Description "External content ingested using PnP PowerShell" -AuthorizedAppIds "00000000-0000-0000-0000-000000000000","11111111-1111-1111-1111-111111111111" +``` + +This will create a new external connection with the provided name and description. Only the application registrations of which the client Ids have been provided can add items to the index for this connection. + +## PARAMETERS + +### -Connection +Optional connection to be used by the cmdlet. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing [Get-PnPConnection](Get-PnPConnection.md). + +```yaml +Type: PnPConnection +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Identity +Unique identifier of the external connection in Microsoft Search. Must be unique within the tenant. Must be between 3 and 32 characters in length. Must only contain alphanumeric characters. Cannot begin with Microsoft or be one of the following values: None, Directory, Exchange, ExchangeArchive, LinkedIn, Mailbox, OneDriveBusiness, SharePoint, Teams, Yammer, Connectors, TaskFabric, PowerBI, Assistant, TopicEngine, MSFT_All_Connectors. + +```yaml +Type: String +Parameter Sets: (All) +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Name +The display name of the connection to be displayed in the Microsoft 365 admin center. Maximum length of 128 characters. + +```yaml +Type: String +Parameter Sets: (All) +Required: True +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Description +Description of the connection displayed in the Microsoft 365 admin center + +```yaml +Type: String +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -AuthorizedAppIds +The client Ids of the application registrations that are allowed to add items to the index for this connection. If not provided, any application registration with the proper permissions can add items to the index for this connection. + +```yaml +Type: String[] +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Verbose +When provided, additional debug statements will be shown while executing the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) \ No newline at end of file diff --git a/documentation/Remove-PnPSearchExternalConnection.md b/documentation/Remove-PnPSearchExternalConnection.md new file mode 100644 index 000000000..a111ddb55 --- /dev/null +++ b/documentation/Remove-PnPSearchExternalConnection.md @@ -0,0 +1,83 @@ +--- +Module Name: PnP.PowerShell +schema: 2.0.0 +applicable: SharePoint Online +online version: https://pnp.github.io/powershell/cmdlets/Remove-PnPSearchExternalConnection.html +external help file: PnP.PowerShell.dll-Help.xml +title: Remove-PnPSearchExternalConnection +--- + +# Remove-PnPSearchExternalConnection + +## SYNOPSIS + +**Required Permissions** + + * Microsoft Graph API : One of ExternalConnection.ReadWrite.OwnedBy, ExternalConnection.ReadWrite.All + +Removes a specific connection to external datasources belonging to Microsoft Search + +## SYNTAX + +```powershell +Remove-PnPSearchExternalConnection -Identity [-Verbose] [-Connection ] +``` + +## DESCRIPTION + +This cmdlet can be used to remove a connection to an external datasource that is being indexed into Microsoft Search through a custom connector. + +## EXAMPLES + +### EXAMPLE 1 +```powershell +Remove-PnPSearchExternalConnection -Identity "pnppowershell" +``` + +This will remove the connection to the external datasource with the specified identity from Microsoft Search. + +## PARAMETERS + +### -Connection +Optional connection to be used by the cmdlet. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing [Get-PnPConnection](Get-PnPConnection.md). + +```yaml +Type: PnPConnection +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Identity +Unique identifier or an instance of the external connection in Microsoft Search that needs to be removed. + +```yaml +Type: SearchExternalConnectionPipeBind +Parameter Sets: (All) +Required: True +Position: Named +Default value: None +Accept pipeline input: True +Accept wildcard characters: False +``` + +### -Verbose +When provided, additional debug statements will be shown while executing the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) \ No newline at end of file diff --git a/documentation/Set-PnPSearchExternalConnection.md b/documentation/Set-PnPSearchExternalConnection.md new file mode 100644 index 000000000..3a6ed1421 --- /dev/null +++ b/documentation/Set-PnPSearchExternalConnection.md @@ -0,0 +1,135 @@ +--- +Module Name: PnP.PowerShell +schema: 2.0.0 +applicable: SharePoint Online +online version: https://pnp.github.io/powershell/cmdlets/Set-PnPSearchExternalConnection.html +external help file: PnP.PowerShell.dll-Help.xml +title: Set-PnPSearchExternalConnection +--- + +# Set-PnPSearchExternalConnection + +## SYNOPSIS + +**Required Permissions** + + * Microsoft Graph API : One of ExternalConnection.ReadWrite.OwnedBy, ExternalConnection.ReadWrite.All + +Updates a connection to an external datasource for Microsoft Search + +## SYNTAX + +```powershell +Set-PnPSearchExternalConnection -Identity [-Name ] [-Description ] [-AuthorizedAppIds ] [-Verbose] [-Connection ] +``` + +## DESCRIPTION + +This cmdlet can be used to update an external datasource connection that is being indexed into Microsoft Search through a custom connector. Use [New-PnPSearchExternalConnection](New-PnPSearchExternalConnection.md) to create a new connector. + +## EXAMPLES + +### EXAMPLE 1 +```powershell +Set-PnPSearchExternalConnection -Identity "pnppowershell" -Name "PnP PowerShell Rocks" +``` + +This will update just the name of the external connection with the provided identity to the value provided. The description will remain unchanged. + +### EXAMPLE 2 +```powershell +Set-PnPSearchExternalConnection -Identity "pnppowershell" -Name "PnP PowerShell Rocks" -Description "External content ingested using PnP PowerShell which rocks" +``` + +This will update the name and description of the external connection with the provided identity to the values provided. + +### EXAMPLE 3 +```powershell +Set-PnPSearchExternalConnection -Identity "pnppowershell" -AuthorizedAppIds "00000000-0000-0000-0000-000000000000","11111111-1111-1111-1111-111111111111" +``` + +This will replace the application registration identifiers of which the client Ids have been provided that can add items to the index for this connection. + +## PARAMETERS + +### -Connection +Optional connection to be used by the cmdlet. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing [Get-PnPConnection](Get-PnPConnection.md). + +```yaml +Type: PnPConnection +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Identity +Unique identifier or an instance of the external connection in Microsoft Search that needs to be updated. + +```yaml +Type: SearchExternalConnectionPipeBind +Parameter Sets: (All) +Required: True +Position: Named +Default value: None +Accept pipeline input: True +Accept wildcard characters: False +``` + +### -Name +The display name of the connection to be displayed in the Microsoft 365 admin center. Maximum length of 128 characters. Only provide when it needs to change. + +```yaml +Type: String +Parameter Sets: (All) +Required: False +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Description +Description of the connection displayed in the Microsoft 365 admin center. Only provide when it needs to change. + +```yaml +Type: String +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -AuthorizedAppIds +The client Ids of the application registrations that are allowed to add items to the index for this connection. Only provide when it needs to change. + +```yaml +Type: String[] +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Verbose +When provided, additional debug statements will be shown while executing the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) \ No newline at end of file diff --git a/documentation/Set-PnPSearchExternalItem.md b/documentation/Set-PnPSearchExternalItem.md index 67cb4f542..9c7e165f0 100644 --- a/documentation/Set-PnPSearchExternalItem.md +++ b/documentation/Set-PnPSearchExternalItem.md @@ -20,7 +20,7 @@ Adds or updates an external item in Microsoft Search ## SYNTAX ```powershell -Set-PnPSearchExternalItem -ItemId -ConnectionId -Properties [-ContentValue ] [-ContentType ] [-GrantUsers ] [-GrantGroups ] [-DenyUsers ] [-DenyGroups ] [-GrantExternalGroups ] [-DenyExternalGroups ] [-GrantEveryone ] [-Verbose] [-Connection ] +Set-PnPSearchExternalItem -ItemId -ConnectionId -Properties [-ContentValue ] [-ContentType ] [-GrantUsers ] [-GrantGroups ] [-DenyUsers ] [-DenyGroups ] [-GrantExternalGroups ] [-DenyExternalGroups ] [-GrantEveryone ] [-Verbose] [-Connection ] ``` ## DESCRIPTION @@ -72,14 +72,14 @@ Accept wildcard characters: False ``` ### -ConnectionId -The Connection ID of the custom connector to use. This is the ID that was entered when registering the custom connector and will indicate for which custom connector this external item is being added to the Microsoft Search index. +The Connection ID or connection instance of the custom connector to use. This is the ID that was entered when registering the custom connector and will indicate for which custom connector this external item is being added to the Microsoft Search index. ```yaml -Type: String +Type: SearchExternalConnectionPipeBind Parameter Sets: (All) Required: True Default value: None -Accept pipeline input: False +Accept pipeline input: True Accept wildcard characters: False ``` diff --git a/documentation/Set-PnPSearchExternalSchema.md b/documentation/Set-PnPSearchExternalSchema.md new file mode 100644 index 000000000..78e5f0420 --- /dev/null +++ b/documentation/Set-PnPSearchExternalSchema.md @@ -0,0 +1,150 @@ +--- +Module Name: PnP.PowerShell +schema: 2.0.0 +applicable: SharePoint Online +online version: https://pnp.github.io/powershell/cmdlets/Set-PnPSearchExternalSchema.html +external help file: PnP.PowerShell.dll-Help.xml +title: Set-PnPSearchExternalSchema +--- + +# Set-PnPSearchExternalSchema + +## SYNOPSIS + +**Required Permissions** + + * Microsoft Graph API : One of ExternalConnection.ReadWrite.OwnedBy, ExternalConnection.ReadWrite.All + +Updates the schema set on a connection to an external datasource belonging to Microsoft Search + +## SYNTAX + +### By textual schema + +```powershell +Set-PnPSearchExternalSchema -ConnectionId -SchemaAsText [-Verbose] [-Connection ] +``` + +### By schema instance + +```powershell +Set-PnPSearchExternalSchema -ConnectionId -Schema [-Verbose] [-Connection ] +``` + +## DESCRIPTION + +This cmdlet can be used to initially set or update the current schema set on a connection to an external datasource that is being indexed into Microsoft Search through a custom connector. + +## EXAMPLES + +### EXAMPLE 1 +```powershell +Set-PnPSearchExternalSchema -ConnectionId "pnppowershell" -SchemaAsText '{ + "baseType": "microsoft.graph.externalItem", + "properties": [ + { + "name": "ticketTitle", + "type": "String", + "isSearchable": "true", + "isRetrievable": "true", + "labels": [ + "title" + ] + }, + { + "name": "priority", + "type": "String", + "isQueryable": "true", + "isRetrievable": "true", + "isSearchable": "false" + }, + { + "name": "assignee", + "type": "String", + "isRetrievable": "true" + } + ] + }' +``` + +This will set the provided JSON schema to be used for the external search connection with the provided name + +### EXAMPLE 2 +```powershell +$schema = Get-PnPSearchExternalSchema -ConnectionId "pnppowershell1" +Set-PnPSearchExternalSchema -ConnectionId "pnppowershell2" -Schema $schema +``` + +This will take the current schema set on the external search connection named 'pnppowershell1' and sets the same schema on the external search connection named 'pnppowershell2' + +## PARAMETERS + +### -Connection +Optional connection to be used by the cmdlet. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing [Get-PnPConnection](Get-PnPConnection.md). + +```yaml +Type: PnPConnection +Parameter Sets: (All) +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -ConnectionId +Unique identifier or instance of the external connection in Microsoft Search to set the schema for + +```yaml +Type: String +Parameter Sets: (All) +Required: True +Position: Named +Default value: None +Accept pipeline input: True +Accept wildcard characters: False +``` + +### -SchemaAsText +The textual representation of the schema to set on the external connection + +```yaml +Type: String +Parameter Sets: By textual schema +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Schema +An instance of a schema to set on the external connection + +```yaml +Type: String +Parameter Sets: By schema instance +Required: True +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Verbose +When provided, additional debug statements will be shown while executing the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) \ No newline at end of file diff --git a/src/Commands/Base/PipeBinds/SearchExternalConnectionPipeBind.cs b/src/Commands/Base/PipeBinds/SearchExternalConnectionPipeBind.cs new file mode 100644 index 000000000..5360c7645 --- /dev/null +++ b/src/Commands/Base/PipeBinds/SearchExternalConnectionPipeBind.cs @@ -0,0 +1,39 @@ +using System.Management.Automation; + +namespace PnP.PowerShell.Commands.Base.PipeBinds +{ + public class SearchExternalConnectionPipeBind + { + private readonly Model.Graph.MicrosoftSearch.ExternalConnection _searchExternalConnection; + private readonly string _identity; + + public SearchExternalConnectionPipeBind() + { + _searchExternalConnection = null; + _identity = null; + } + + public SearchExternalConnectionPipeBind(Model.Graph.MicrosoftSearch.ExternalConnection searchExternalConnection) + { + _searchExternalConnection = searchExternalConnection; + } + + public SearchExternalConnectionPipeBind(string identity) + { + _identity = identity; + } + + public Model.Graph.MicrosoftSearch.ExternalConnection GetExternalConnection(PSCmdlet cmdlet, PnPConnection connection, string accessToken) + { + if(_searchExternalConnection != null) + { + return _searchExternalConnection; + } + else + { + var externalConnectionResult = Utilities.REST.GraphHelper.Get(cmdlet, connection, $"v1.0/external/connections/{_identity}", accessToken); + return externalConnectionResult; + } + } + } +} diff --git a/src/Commands/Enums/SearchExternalConnectionState.cs b/src/Commands/Enums/SearchExternalConnectionState.cs new file mode 100644 index 000000000..0077d6469 --- /dev/null +++ b/src/Commands/Enums/SearchExternalConnectionState.cs @@ -0,0 +1,29 @@ +namespace PnP.PowerShell.Commands.Enums +{ + /// + /// Contains the possible states of an external connection + /// + /// + public enum SearchExternalConnectionState : short + { + /// + /// Connection is in draft state + /// + Draft = 0, + + /// + /// Connection is ready to be used + /// + Ready = 1, + + /// + /// Connection can no longer be used + /// + Obsolete = 2, + + /// + /// Too many connections have been created on the tenant + /// + LimitExceeded = 3 + } +} diff --git a/src/Commands/Enums/SearchExternalSchemaPropertyLabel.cs b/src/Commands/Enums/SearchExternalSchemaPropertyLabel.cs new file mode 100644 index 000000000..058597d8a --- /dev/null +++ b/src/Commands/Enums/SearchExternalSchemaPropertyLabel.cs @@ -0,0 +1,59 @@ +namespace PnP.PowerShell.Commands.Enums +{ + /// + /// Contains the possible well-known tags that can be assigned to properties in the schema definition of an external search connection to make Microsoft Search understand its content better + /// + /// + public enum SearchExternalSchemaPropertyLabel : short + { + /// + /// Property represents the title of the item + /// + Title, + + /// + /// Property represents a link to the item + /// + Url, + + /// + /// Property represents the author of the item + /// + CreatedBy, + + /// + /// Property represents the last person who modified the item + /// + LastModifiedBy, + + /// + /// Property represents the authors of the item + /// + Authors, + + /// + /// Property represents the date and time the item was created + /// + CreatedDateTime, + + /// + /// Property represents the date and time the item was last modified + /// + LastModifiedDateTime, + + /// + /// Property represents the name of the file + /// + FileName, + + /// + /// Property represents the extension of the file + /// + FileExtension, + + /// + /// Property represents the icon to be shown with the item + /// + IconUrl + } +} diff --git a/src/Commands/Enums/SearchExternalSchemaPropertyType.cs b/src/Commands/Enums/SearchExternalSchemaPropertyType.cs new file mode 100644 index 000000000..cf6ac73c3 --- /dev/null +++ b/src/Commands/Enums/SearchExternalSchemaPropertyType.cs @@ -0,0 +1,54 @@ +namespace PnP.PowerShell.Commands.Enums +{ + /// + /// Contains the possible types of properties in the schema definition of an external search connection + /// + /// + public enum SearchExternalSchemaPropertyType : short + { + /// + /// Property contains a text value + /// + String, + + /// + /// Property contains a numeric value + /// + Int64, + + /// + /// Property contains a floating point value + /// + Double, + + /// + /// Property contains a date and time value + /// + DateTime, + + /// + /// Property contains a boolean value + /// + Boolean, + + /// + /// Property contains a collection of text values + /// + StringCollection, + + /// + /// Property contains a collection of numeric values + /// + Int64Collection, + + /// + /// Property contains a collection of floating point values + /// + DoubleCollection, + + /// + /// Property contains a collection of date and time values + /// + DateTimeCollection + } +} diff --git a/src/Commands/Model/Graph/MicrosoftSearch/ExternalConnection.cs b/src/Commands/Model/Graph/MicrosoftSearch/ExternalConnection.cs new file mode 100644 index 000000000..3dd69321c --- /dev/null +++ b/src/Commands/Model/Graph/MicrosoftSearch/ExternalConnection.cs @@ -0,0 +1,42 @@ +using System.Text.Json.Serialization; + +namespace PnP.PowerShell.Commands.Model.Graph.MicrosoftSearch; + +/// +/// Defines a connection to an external datasource used by Microsoft Search +/// +/// +public class ExternalConnection +{ + /// + /// Unique identifier of the external connection + /// + [JsonPropertyName("id")] + public string Id { get; set; } + + /// + /// Name of the external connection + /// + [JsonPropertyName("name")] + public string Name { get; set; } + + /// + /// Description of the external connection + /// + [JsonPropertyName("description")] + public string Description { get; set; } + + /// + /// The configuration on the external connection + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("configuration")] + public ExternalConnectionConfiguration Configuration { get; set; } + + /// + /// The state of the external connection + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonPropertyName("state")] + public Enums.SearchExternalConnectionState? State { get; set; } +} \ No newline at end of file diff --git a/src/Commands/Model/Graph/MicrosoftSearch/ExternalConnectionConfiguration.cs b/src/Commands/Model/Graph/MicrosoftSearch/ExternalConnectionConfiguration.cs new file mode 100644 index 000000000..55cc7fcb4 --- /dev/null +++ b/src/Commands/Model/Graph/MicrosoftSearch/ExternalConnectionConfiguration.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; + +namespace PnP.PowerShell.Commands.Model.Graph.MicrosoftSearch; + +/// +/// Defines the configuration of an external connection used by Microsoft Search +/// +/// +public class ExternalConnectionConfiguration +{ + /// + /// A collection of application IDs for registered Microsoft Entra apps that are allowed to manage the externalConnection and to index content in the externalConnection + /// + [JsonPropertyName("authorizedAppIds")] + public string[] AuthorizedAppIds { get; set; } +} \ No newline at end of file diff --git a/src/Commands/Model/Graph/MicrosoftSearch/ExternalSchema.cs b/src/Commands/Model/Graph/MicrosoftSearch/ExternalSchema.cs new file mode 100644 index 000000000..f15dd6e0e --- /dev/null +++ b/src/Commands/Model/Graph/MicrosoftSearch/ExternalSchema.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace PnP.PowerShell.Commands.Model.Graph.MicrosoftSearch; + +/// +/// Defines a schema for a connection to an external datasource used by Microsoft Search +/// +/// +public class ExternalSchema +{ + /// + /// Schema base type. Do not modify. + /// + [JsonPropertyName("baseType")] + public string BaseType { get; } = "microsoft.graph.externalItem"; + + /// + /// Properties in the schema of the external connection defining which information is available on the external items + /// + [JsonPropertyName("properties")] + public List Properties { get; set; } +} \ No newline at end of file diff --git a/src/Commands/Model/Graph/MicrosoftSearch/ExternalSchemaProperty.cs b/src/Commands/Model/Graph/MicrosoftSearch/ExternalSchemaProperty.cs new file mode 100644 index 000000000..651df7239 --- /dev/null +++ b/src/Commands/Model/Graph/MicrosoftSearch/ExternalSchemaProperty.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace PnP.PowerShell.Commands.Model.Graph.MicrosoftSearch; + +/// +/// Defines a schema property for a connection to an external datasource used by Microsoft Search +/// +/// +public class ExternalSchemaProperty +{ + /// + /// Name of the schema property + /// + [JsonPropertyName("name")] + public string Name { get; set; } + + /// + /// A set of aliases or a friendly name for the property. Maximum 32 characters. Only alphanumeric characters allowed. For example, each string may not contain control characters, whitespace, or any of the following: :, ;, ,, (, ), [, ], {, }, %, $, +, !, *, =, &, ?, @, #, \, ~, ', ", <, >, `, ^. Optional. + /// + [JsonPropertyName("aliases")] + public string[] Aliases { get; set; } + + /// + /// Specifies if the property is queryable. Queryable properties can be used in Keyword Query Language (KQL) queries. Optional. + /// + [JsonPropertyName("isQueryable")] + public bool IsQueryable { get; set; } + + /// + /// Specifies if the property is refinable. Refinable properties can be used to filter search results in the Search API and add a refiner control in the Microsoft Search user experience. Optional. + /// + [JsonPropertyName("isRefinable")] + public bool IsRefinable { get; set; } + + /// + /// Specifies if the property is retrievable. Retrievable properties are returned in the result set when items are returned by the search API. Retrievable properties are also available to add to the display template used to render search results. Optional. + /// + [JsonPropertyName("isRetrievable")] + public bool IsRetrievable { get; set; } + + /// + /// Specifies if the property is searchable. Only properties of type String or StringCollection can be searchable. Nonsearchable properties aren't added to the search index. Optional. + /// + [JsonPropertyName("isSearchable")] + public bool IsSearchable { get; set; } + + /// + /// Specifies the type of information stored in the property. Required. + /// + [JsonPropertyName("type")] + public Enums.SearchExternalSchemaPropertyType? Type { get; set; } + + /// + /// Specifies the labels to tag the property with to make Microsoft Search better understand the data. Optional. + /// + public List Labels { get; set; } +} \ No newline at end of file diff --git a/src/Commands/Search/GetSearchExternalConnection.cs b/src/Commands/Search/GetSearchExternalConnection.cs new file mode 100644 index 000000000..bb57058e6 --- /dev/null +++ b/src/Commands/Search/GetSearchExternalConnection.cs @@ -0,0 +1,39 @@ +using System.Management.Automation; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Attributes; +using System.Collections.Generic; + +namespace PnP.PowerShell.Commands.Search +{ + [Cmdlet(VerbsCommon.Get, "PnPSearchExternalConnection")] + [RequiredMinimalApiPermissions("ExternalConnection.ReadWrite.OwnedBy")] + [OutputType(typeof(IEnumerable))] + [OutputType(typeof(Model.Graph.MicrosoftSearch.ExternalConnection))] + public class GetSearchExternalConnection : PnPGraphCmdlet + { + [Parameter(Mandatory = false)] + public string Identity; + + protected override void ExecuteCmdlet() + { + var graphApiUrl = $"v1.0/external/connections"; + + if(ParameterSpecified(nameof(Identity))) + { + graphApiUrl += $"/{Identity}"; + + WriteVerbose($"Retrieving external connection with Identity '{Identity}'"); + + var externalConnectionResult = Utilities.REST.GraphHelper.Get(this, Connection, graphApiUrl, AccessToken); + WriteObject(externalConnectionResult, false); + } + else + { + WriteVerbose("Retrieving all external connections"); + + var externalConnectionResults = Utilities.REST.GraphHelper.GetResultCollection(this, Connection, graphApiUrl, AccessToken); + WriteObject(externalConnectionResults, true); + } + } + } +} \ No newline at end of file diff --git a/src/Commands/Search/GetSearchExternalSchema.cs b/src/Commands/Search/GetSearchExternalSchema.cs new file mode 100644 index 000000000..49af6ade5 --- /dev/null +++ b/src/Commands/Search/GetSearchExternalSchema.cs @@ -0,0 +1,24 @@ +using System.Management.Automation; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Base.PipeBinds; +using PnP.PowerShell.Commands.Attributes; + +namespace PnP.PowerShell.Commands.Search +{ + [Cmdlet(VerbsCommon.Get, "PnPSearchExternalSchema")] + [RequiredMinimalApiPermissions("ExternalConnection.ReadWrite.OwnedBy")] + [OutputType(typeof(Model.Graph.MicrosoftSearch.ExternalSchema))] + public class GetSearchExternalSchema : PnPGraphCmdlet + { + [Parameter(Mandatory = true, ValueFromPipeline = true, Position = 0)] + public SearchExternalConnectionPipeBind ConnectionId; + + protected override void ExecuteCmdlet() + { + var searchExternalConnection = ConnectionId.GetExternalConnection(this, Connection, AccessToken); + var graphApiUrl = $"v1.0/external/connections/{searchExternalConnection.Id}/schema"; + var result = Utilities.REST.GraphHelper.Get(this, Connection, graphApiUrl, AccessToken); + WriteObject(result, false); + } + } +} \ No newline at end of file diff --git a/src/Commands/Search/NewSearchExternalConnection.cs b/src/Commands/Search/NewSearchExternalConnection.cs new file mode 100644 index 000000000..ebb3765f4 --- /dev/null +++ b/src/Commands/Search/NewSearchExternalConnection.cs @@ -0,0 +1,53 @@ +using System.Management.Automation; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Attributes; +using System.Net.Http.Json; + +namespace PnP.PowerShell.Commands.Search +{ + [Cmdlet(VerbsCommon.New, "PnPSearchExternalConnection")] + [RequiredMinimalApiPermissions("ExternalConnection.ReadWrite.OwnedBy")] + [OutputType(typeof(Model.Graph.MicrosoftSearch.ExternalConnection))] + public class NewSearchExternalConnection : PnPGraphCmdlet + { + [Parameter(Mandatory = true)] + [ValidateLength(3, 32)] + public string Identity; + + [Parameter(Mandatory = true)] + [ValidateLength(1, 128)] + public string Name; + + [Parameter(Mandatory = false)] + public string Description; + + [Parameter(Mandatory = false)] + public string[] AuthorizedAppIds; + protected override void ExecuteCmdlet() + { + var bodyContent = new Model.Graph.MicrosoftSearch.ExternalConnection + { + Id = Identity, + Name = Name, + Description = Description + }; + + if(ParameterSpecified(nameof(AuthorizedAppIds))) + { + bodyContent.Configuration = new() { + AuthorizedAppIds = AuthorizedAppIds + }; + } + + var jsonContent = JsonContent.Create(bodyContent); + WriteVerbose($"Constructed payload: {jsonContent.ReadAsStringAsync().GetAwaiter().GetResult()}"); + + var graphApiUrl = $"v1.0/external/connections"; + var results = Utilities.REST.GraphHelper.Post(this, Connection, graphApiUrl, AccessToken, jsonContent); + var resultsContent = results.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + var externalConnectionResult = System.Text.Json.JsonSerializer.Deserialize(resultsContent); + + WriteObject(externalConnectionResult, false); + } + } +} \ No newline at end of file diff --git a/src/Commands/Search/RemoveSearchExternalConnection.cs b/src/Commands/Search/RemoveSearchExternalConnection.cs new file mode 100644 index 000000000..d7ce3b03d --- /dev/null +++ b/src/Commands/Search/RemoveSearchExternalConnection.cs @@ -0,0 +1,21 @@ +using System.Management.Automation; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Attributes; +using PnP.PowerShell.Commands.Base.PipeBinds; + +namespace PnP.PowerShell.Commands.Search +{ + [Cmdlet(VerbsCommon.Remove, "PnPSearchExternalConnection")] + [RequiredMinimalApiPermissions("ExternalConnection.ReadWrite.OwnedBy")] + public class RemoveSearchExternalConnection : PnPGraphCmdlet + { + [Parameter(Mandatory = true, ValueFromPipeline = true, Position = 0)] + public SearchExternalConnectionPipeBind Identity; + + protected override void ExecuteCmdlet() + { + var externalConnection = Identity.GetExternalConnection(this, Connection, AccessToken); + Utilities.REST.GraphHelper.Delete(this, Connection, $"v1.0/external/connections/{externalConnection.Id}", AccessToken); + } + } +} \ No newline at end of file diff --git a/src/Commands/Search/SetSearchExternalConnection.cs b/src/Commands/Search/SetSearchExternalConnection.cs new file mode 100644 index 000000000..abf5d1378 --- /dev/null +++ b/src/Commands/Search/SetSearchExternalConnection.cs @@ -0,0 +1,49 @@ +using System.Management.Automation; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Attributes; +using System.Net.Http.Json; +using System.Text.Json; +using PnP.PowerShell.Commands.Base.PipeBinds; + +namespace PnP.PowerShell.Commands.Search +{ + [Cmdlet(VerbsCommon.Set, "PnPSearchExternalConnection")] + [RequiredMinimalApiPermissions("ExternalConnection.ReadWrite.OwnedBy")] + public class SetSearchExternalConnection : PnPGraphCmdlet + { + [Parameter(Mandatory = true, ValueFromPipeline = true, Position = 0)] + public SearchExternalConnectionPipeBind Identity; + + [Parameter(Mandatory = true)] + [ValidateLength(1, 128)] + public string Name; + + [Parameter(Mandatory = false)] + public string Description; + + [Parameter(Mandatory = false)] + public string[] AuthorizedAppIds; + protected override void ExecuteCmdlet() + { + var bodyContent = new Model.Graph.MicrosoftSearch.ExternalConnection + { + Name = Name, + Description = Description + }; + + if(ParameterSpecified(nameof(AuthorizedAppIds))) + { + bodyContent.Configuration = new() { + AuthorizedAppIds = AuthorizedAppIds + }; + } + + var jsonContent = JsonContent.Create(bodyContent, null, new JsonSerializerOptions { DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull }); + WriteVerbose($"Constructed payload: {jsonContent.ReadAsStringAsync().GetAwaiter().GetResult()}"); + + var externalConnection = Identity.GetExternalConnection(this, Connection, AccessToken); + var graphApiUrl = $"v1.0/external/connections/{externalConnection.Id}"; + Utilities.REST.GraphHelper.Patch(this, Connection, AccessToken, jsonContent, graphApiUrl); + } + } +} \ No newline at end of file diff --git a/src/Commands/Search/SetSearchExternalItem.cs b/src/Commands/Search/SetSearchExternalItem.cs index 1d1f497a1..5f3f3b5df 100644 --- a/src/Commands/Search/SetSearchExternalItem.cs +++ b/src/Commands/Search/SetSearchExternalItem.cs @@ -13,10 +13,10 @@ namespace PnP.PowerShell.Commands.Search [Cmdlet(VerbsCommon.Set, "PnPSearchExternalItem")] [RequiredMinimalApiPermissions("ExternalItem.ReadWrite.All")] [OutputType(typeof(Model.Graph.MicrosoftSearch.ExternalItem))] - public class AddSearchExternalItem : PnPGraphCmdlet + public class SetSearchExternalItem : PnPGraphCmdlet { - [Parameter(Mandatory = true)] - public string ConnectionId; + [Parameter(Mandatory = true, ValueFromPipeline = true, Position = 0)] + public SearchExternalConnectionPipeBind ConnectionId; [Parameter(Mandatory = true)] [ValidateLength(1,128)] @@ -105,20 +105,10 @@ protected override void ExecuteCmdlet() var jsonContent = JsonContent.Create(bodyContent); WriteVerbose($"Constructed payload: {jsonContent.ReadAsStringAsync().GetAwaiter().GetResult()}"); - var graphApiUrl = $"v1.0/external/connections/{ConnectionId}/items/{ItemId}"; - WriteVerbose($"Calling Graph API at {graphApiUrl}"); - - var results = Utilities.REST.GraphHelper.Put(this, Connection, graphApiUrl, AccessToken, jsonContent); - - WriteVerbose($"Graph API responded with HTTP {results.StatusCode} {results.ReasonPhrase}"); - - var resultsContent = results.Content.ReadAsStringAsync().GetAwaiter().GetResult(); - - WriteVerbose($"Graph API responded with payload: {resultsContent}"); - - var externalItemResult = System.Text.Json.JsonSerializer.Deserialize(resultsContent); - - WriteObject(externalItemResult, false); + var searchExternalConnection = ConnectionId.GetExternalConnection(this, Connection, AccessToken); + var graphApiUrl = $"v1.0/external/connections/{searchExternalConnection.Id}/items/{ItemId}"; + var results = Utilities.REST.GraphHelper.Put(this, Connection, graphApiUrl, AccessToken, jsonContent); + WriteObject(results, false); } private List GetUserAcls(AzureADUserPipeBind[] users, Enums.SearchExternalItemAclAccessType accessType) diff --git a/src/Commands/Search/SetSearchExternalSchema.cs b/src/Commands/Search/SetSearchExternalSchema.cs new file mode 100644 index 000000000..272919ca9 --- /dev/null +++ b/src/Commands/Search/SetSearchExternalSchema.cs @@ -0,0 +1,61 @@ +using System.Management.Automation; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Base.PipeBinds; +using PnP.PowerShell.Commands.Attributes; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Json; + +namespace PnP.PowerShell.Commands.Search +{ + [Cmdlet(VerbsCommon.Set, "PnPSearchExternalSchema")] + [RequiredMinimalApiPermissions("ExternalConnection.ReadWrite.OwnedBy")] + [OutputType(typeof(string))] + public class SetSearchExternalSchema : PnPGraphCmdlet + { + const string ParamSet_TextualSchema = "By textual schema"; + const string ParamSet_SchemaInstance = "By schema instance"; + + [Parameter(Mandatory = true, ValueFromPipeline = true, Position = 0, ParameterSetName = ParamSet_TextualSchema)] + [Parameter(Mandatory = true, ValueFromPipeline = true, Position = 0, ParameterSetName = ParamSet_SchemaInstance)] + public SearchExternalConnectionPipeBind ConnectionId; + + [Parameter(Mandatory = true, ParameterSetName = ParamSet_TextualSchema)] + public string SchemaAsText; + + [Parameter(Mandatory = true, ParameterSetName = ParamSet_SchemaInstance)] + public Model.Graph.MicrosoftSearch.ExternalSchema Schema; + + protected override void ExecuteCmdlet() + { + var searchExternalConnection = ConnectionId.GetExternalConnection(this, Connection, AccessToken); + + switch(ParameterSetName) + { + case ParamSet_TextualSchema: + WriteVerbose("Parsing schema from textual representation"); + break; + case ParamSet_SchemaInstance: + WriteVerbose("Using provided schema instance"); + SchemaAsText = System.Text.Json.JsonSerializer.Serialize(Schema); + break; + } + + var jsonContent = new StringContent(SchemaAsText); + WriteVerbose($"Constructed payload: {jsonContent.ReadAsStringAsync().GetAwaiter().GetResult()}"); + + var graphApiUrl = $"v1.0/external/connections/{searchExternalConnection.Id}/schema"; + var results = Utilities.REST.GraphHelper.Patch(this, Connection, AccessToken, jsonContent, graphApiUrl); + + WriteVerbose("Trying to retrieve location header from response which can be used to poll for the status of the schema operation"); + if(results.Headers.TryGetValues("Location", out var location) && location.Any()) + { + WriteObject(location.FirstOrDefault(), false); + } + else + { + WriteVerbose("No valid Location header found in response"); + } + } + } +} \ No newline at end of file diff --git a/src/Commands/Utilities/REST/GraphHelper.cs b/src/Commands/Utilities/REST/GraphHelper.cs index 5b1784498..dc1e5db30 100644 --- a/src/Commands/Utilities/REST/GraphHelper.cs +++ b/src/Commands/Utilities/REST/GraphHelper.cs @@ -10,7 +10,6 @@ using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; -using System.Threading.Tasks; namespace PnP.PowerShell.Commands.Utilities.REST { @@ -51,9 +50,11 @@ private static HttpRequestMessage GetMessage(string url, HttpMethod method, PnPC url = url.Substring(1); } - var message = new HttpRequestMessage(); - message.Version = new Version(2, 0); - message.Method = method; + var message = new HttpRequestMessage + { + Version = new Version(2, 0), + Method = method + }; message.Headers.TryAddWithoutValidation("Accept", "application/json"); message.RequestUri = !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) ? new Uri($"https://{connection.GraphEndPoint}/{url}") : new Uri(url); message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); @@ -150,8 +151,9 @@ public static T Get(Cmdlet cmdlet, PnPConnection connection, string url, stri var entity = JsonSerializer.Deserialize(stringContent, options); return entity; } - catch (Exception) + catch (Exception e) { + cmdlet.WriteWarning($"Failed to parse response from server. Error message: '{e.Message}'. Received content: '{stringContent}'. Model type to parse it to: '{typeof(T)}'."); return default(T); } } From 0d13ab9908cc2b594ed1dff082e0f9cd45285021 Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Tue, 3 Sep 2024 16:58:09 +0200 Subject: [PATCH 2/5] Adding comment on URL returned from a schema update --- documentation/Set-PnPSearchExternalSchema.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/Set-PnPSearchExternalSchema.md b/documentation/Set-PnPSearchExternalSchema.md index 78e5f0420..8888a4211 100644 --- a/documentation/Set-PnPSearchExternalSchema.md +++ b/documentation/Set-PnPSearchExternalSchema.md @@ -33,7 +33,7 @@ Set-PnPSearchExternalSchema -ConnectionId -Sc ## DESCRIPTION -This cmdlet can be used to initially set or update the current schema set on a connection to an external datasource that is being indexed into Microsoft Search through a custom connector. +This cmdlet can be used to initially set or update the current schema set on a connection to an external datasource that is being indexed into Microsoft Search through a custom connector. The URL returned can be queried in Microsoft Graph to check on the status of the schema update. ## EXAMPLES From d39435e4555cd9ae87d2363f9edba456ca71885b Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Tue, 3 Sep 2024 17:15:40 +0200 Subject: [PATCH 3/5] Adding PR reference --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6a7b9ff9..adcd45127 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added support for `WAM` login for Windows OS to support Windows Hello, FIDO keys, Conditional Access policies and other secure authentication modes. - Added `-SkipCertCreation` parameter in `Register-PnPAzureADApp` cmdlet to prevent creation and uploading of certificates in the Entra ID app. - Added support to `-ValidateConnection` in managed identity authentication. -- Added `New-PnPSearchExternalConnection`, `Get-PnPSearchExternalConnection`, `Set-PnPSearchExternalConnection` and `Remove-PnPSearchExternalConnection` cmdlets to manage external connections for Microsoft Search -- Added `Get-PnPSearchExternalSchema` and `Set-PnPSearchExternalSchema` cmdlets to manage the schema for external connections for Microsoft Search +- Added `New-PnPSearchExternalConnection`, `Get-PnPSearchExternalConnection`, `Set-PnPSearchExternalConnection` and `Remove-PnPSearchExternalConnection` cmdlets to manage external connections for Microsoft Search [#4231](https://github.com/pnp/powershell/pull/4231) +- Added `Get-PnPSearchExternalSchema` and `Set-PnPSearchExternalSchema` cmdlets to manage the schema for external connections for Microsoft Search [#4231](https://github.com/pnp/powershell/pull/4231) ### Changed From 2a6ea0f91a1aafa4958319340dec56f1d4f36f67 Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Tue, 3 Sep 2024 17:17:39 +0200 Subject: [PATCH 4/5] Adding option to wait for schema update to be done --- src/Commands/Model/Graph/OperationStatus.cs | 29 ++++++++++++ .../Search/SetSearchExternalSchema.cs | 44 ++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 src/Commands/Model/Graph/OperationStatus.cs diff --git a/src/Commands/Model/Graph/OperationStatus.cs b/src/Commands/Model/Graph/OperationStatus.cs new file mode 100644 index 000000000..da5026914 --- /dev/null +++ b/src/Commands/Model/Graph/OperationStatus.cs @@ -0,0 +1,29 @@ +using System; +using Newtonsoft.Json; + +namespace PnP.PowerShell.Commands.Model.Graph +{ + /// + /// Model for an operation status in Microsoft Graph + /// + public class OperationStatus + { + /// + /// Unique identifier of the operation + /// + [JsonProperty("id")] + public Guid? Id { get; set; } + + /// + /// The status of the operation + /// + [JsonProperty("status")] + public string Status { get; set; } + + /// + /// The error message, if anything went wrong + /// + [JsonProperty("error")] + public string Error { get; set; } + } +} diff --git a/src/Commands/Search/SetSearchExternalSchema.cs b/src/Commands/Search/SetSearchExternalSchema.cs index 272919ca9..9f8200152 100644 --- a/src/Commands/Search/SetSearchExternalSchema.cs +++ b/src/Commands/Search/SetSearchExternalSchema.cs @@ -4,7 +4,8 @@ using PnP.PowerShell.Commands.Attributes; using System.Linq; using System.Net.Http; -using System.Net.Http.Json; +using System.Threading; +using System; namespace PnP.PowerShell.Commands.Search { @@ -26,6 +27,14 @@ public class SetSearchExternalSchema : PnPGraphCmdlet [Parameter(Mandatory = true, ParameterSetName = ParamSet_SchemaInstance)] public Model.Graph.MicrosoftSearch.ExternalSchema Schema; + [Parameter(Mandatory = false, ParameterSetName = ParamSet_TextualSchema)] + [Parameter(Mandatory = false, ParameterSetName = ParamSet_SchemaInstance)] + public SwitchParameter Wait; + + [Parameter(Mandatory = false, ParameterSetName = ParamSet_TextualSchema)] + [Parameter(Mandatory = false, ParameterSetName = ParamSet_SchemaInstance)] + public short? OperationStatusPollingInterval = 30; + protected override void ExecuteCmdlet() { var searchExternalConnection = ConnectionId.GetExternalConnection(this, Connection, AccessToken); @@ -50,7 +59,38 @@ protected override void ExecuteCmdlet() WriteVerbose("Trying to retrieve location header from response which can be used to poll for the status of the schema operation"); if(results.Headers.TryGetValues("Location", out var location) && location.Any()) { - WriteObject(location.FirstOrDefault(), false); + var schemaOperationStatusUrl = location.FirstOrDefault(); + WriteVerbose("Schema update has been scheduled"); + + if(Wait.ToBool()) + { + WriteVerbose($"Waiting for schema operation to complete by polling {schemaOperationStatusUrl}"); + + do + { + WriteVerbose("Polling schema operation status"); + var schemaOperationResult = Utilities.REST.GraphHelper.Get(this, Connection, schemaOperationStatusUrl, AccessToken); + + if(!string.IsNullOrEmpty(schemaOperationResult.Status)) + { + if (schemaOperationResult.Status.ToLowerInvariant() == "completed") + { + WriteVerbose("Schema operation has completed"); + break; + } + else + { + WriteVerbose($"Schema operation still in progress with status {schemaOperationResult.Status}"); + } + } + + WriteVerbose($"Waiting for {OperationStatusPollingInterval.GetValueOrDefault(30)} seconds before polling again"); + Thread.Sleep(TimeSpan.FromSeconds(OperationStatusPollingInterval.GetValueOrDefault(30))); + } + while (true); + } + + WriteObject(schemaOperationStatusUrl, false); } else { From 90518d75624350ca6cb3cbfb0b4f50750d5391f5 Mon Sep 17 00:00:00 2001 From: Koen Zomers Date: Wed, 4 Sep 2024 11:27:45 +0200 Subject: [PATCH 5/5] Changing mandatory property --- src/Commands/Search/SetSearchExternalConnection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Commands/Search/SetSearchExternalConnection.cs b/src/Commands/Search/SetSearchExternalConnection.cs index abf5d1378..3794f098d 100644 --- a/src/Commands/Search/SetSearchExternalConnection.cs +++ b/src/Commands/Search/SetSearchExternalConnection.cs @@ -14,7 +14,7 @@ public class SetSearchExternalConnection : PnPGraphCmdlet [Parameter(Mandatory = true, ValueFromPipeline = true, Position = 0)] public SearchExternalConnectionPipeBind Identity; - [Parameter(Mandatory = true)] + [Parameter(Mandatory = false)] [ValidateLength(1, 128)] public string Name;