diff --git a/examples/V2App/.funcignore b/examples/V2App/.funcignore
new file mode 100644
index 00000000..d42c5253
--- /dev/null
+++ b/examples/V2App/.funcignore
@@ -0,0 +1,5 @@
+.git*
+.vscode
+local.settings.json
+test
+*.tests.ps1
diff --git a/examples/V2App/HttpFunctions.psm1 b/examples/V2App/HttpFunctions.psm1
new file mode 100644
index 00000000..8f16e2a3
--- /dev/null
+++ b/examples/V2App/HttpFunctions.psm1
@@ -0,0 +1,61 @@
+# HTTP Trigger functions using the V2 attribute-based programming model.
+# No function.json files are needed — the worker indexes these automatically.
+
+function HttpExample {
+ [AzFunction()]
+ param(
+ [HttpTrigger(AuthLevel = 'Anonymous', Methods = 'GET', 'POST', Route = 'hello')]
+ $Request
+ )
+
+ $name = $Request.Query['name']
+ if (-not $name) {
+ $name = $Request.Body.name
+ }
+
+ if ($name) {
+ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
+ StatusCode = [System.Net.HttpStatusCode]::OK
+ Body = "Hello, $name!"
+ })
+ }
+ else {
+ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
+ StatusCode = [System.Net.HttpStatusCode]::BadRequest
+ Body = 'Please pass a name on the query string or in the request body.'
+ })
+ }
+}
+
+function GetAzureVm {
+ [AzFunction(Name = 'GetAzureVm')]
+ param(
+ [HttpTrigger(AuthLevel = 'Function', Methods = 'GET')]
+ $Request
+ )
+
+ $vmName = $Request.Query['vmName']
+ $resourceGroup = $Request.Query['resourceGroup']
+
+ if ($vmName -and $resourceGroup) {
+ $vm = Get-AzVM -ResourceGroupName $resourceGroup -Name $vmName -ErrorAction SilentlyContinue
+ if ($vm) {
+ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
+ StatusCode = [System.Net.HttpStatusCode]::OK
+ Body = ($vm | ConvertTo-Json -Depth 5)
+ })
+ }
+ else {
+ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
+ StatusCode = [System.Net.HttpStatusCode]::NotFound
+ Body = "VM '$vmName' not found in resource group '$resourceGroup'."
+ })
+ }
+ }
+ else {
+ Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
+ StatusCode = [System.Net.HttpStatusCode]::BadRequest
+ Body = 'Please provide vmName and resourceGroup query parameters.'
+ })
+ }
+}
diff --git a/examples/V2App/QueueFunctions.psm1 b/examples/V2App/QueueFunctions.psm1
new file mode 100644
index 00000000..f8e7edf4
--- /dev/null
+++ b/examples/V2App/QueueFunctions.psm1
@@ -0,0 +1,23 @@
+# Queue Trigger with Queue Output using the V2 attribute-based programming model.
+
+function ProcessQueueMessage {
+ [AzFunction()]
+ param(
+ [QueueTrigger(QueueName = 'input-queue', Connection = 'AzureWebJobsStorage')]
+ $QueueItem,
+
+ [QueueOutput(QueueName = 'output-queue', Connection = 'AzureWebJobsStorage')]
+ $OutputQueue
+ )
+
+ Write-Information "Processing queue message: $QueueItem"
+
+ # Transform the message and send to output queue
+ $result = @{
+ OriginalMessage = $QueueItem
+ ProcessedAt = (Get-Date).ToString('o')
+ Status = 'Processed'
+ } | ConvertTo-Json
+
+ Push-OutputBinding -Name OutputQueue -Value $result
+}
diff --git a/examples/V2App/README.md b/examples/V2App/README.md
new file mode 100644
index 00000000..563389f1
--- /dev/null
+++ b/examples/V2App/README.md
@@ -0,0 +1,40 @@
+# V2 Programming Model Example App
+
+This example demonstrates the **V2 attribute-based programming model** for Azure Functions with PowerShell. Functions are defined using PowerShell attributes — no `function.json` files are needed.
+
+## Key Differences from V1
+
+| Feature | V1 (Classic) | V2 (Attribute-based) |
+|---|---|---|
+| Function definition | `function.json` + `run.ps1` per function | `[AzFunction()]` attribute in `.psm1` files |
+| File layout | One folder per function | Functions organized by domain in `.psm1` files |
+| Binding configuration | JSON in `function.json` | Attributes on parameters |
+| Indexing | Host reads `function.json` | Worker indexes via AST parsing |
+
+## Functions Included
+
+### HttpFunctions.psm1
+- **HttpExample** — Anonymous HTTP trigger (GET/POST) with custom route `/hello`
+- **GetAzureVm** — Function-level auth HTTP trigger that fetches an Azure VM
+
+### TimerFunctions.psm1
+- **CleanupJob** — Timer trigger that runs every 6 hours
+
+### QueueFunctions.psm1
+- **ProcessQueueMessage** — Queue trigger with queue output binding
+
+## Running Locally
+
+```powershell
+cd examples/V2App
+func start
+```
+
+## .funcignore
+
+The `.funcignore` file excludes files from deployment (similar to `.gitignore`):
+- `.git*` — Git metadata
+- `.vscode` — Editor settings
+- `local.settings.json` — Local-only settings
+- `test` — Test directories
+- `*.tests.ps1` — Test files
diff --git a/examples/V2App/TimerFunctions.psm1 b/examples/V2App/TimerFunctions.psm1
new file mode 100644
index 00000000..01cbcb87
--- /dev/null
+++ b/examples/V2App/TimerFunctions.psm1
@@ -0,0 +1,19 @@
+# Timer Trigger function using the V2 attribute-based programming model.
+
+function CleanupJob {
+ [AzFunction(Name = 'CleanupJob')]
+ param(
+ [TimerTrigger(Schedule = '0 0 */6 * * *')]
+ $Timer
+ )
+
+ Write-Information "Cleanup job triggered at: $(Get-Date)"
+
+ if ($Timer.IsPastDue) {
+ Write-Warning 'Timer is running late!'
+ }
+
+ # Add your cleanup logic here, for example:
+ # Remove-Item -Path "$env:TEMP\my-app-cache\*" -Recurse -Force -ErrorAction SilentlyContinue
+ Write-Information 'Cleanup job completed.'
+}
diff --git a/examples/V2App/host.json b/examples/V2App/host.json
new file mode 100644
index 00000000..7d551012
--- /dev/null
+++ b/examples/V2App/host.json
@@ -0,0 +1,12 @@
+{
+ "version": "2.0",
+ "logging": {
+ "logLevel": {
+ "default": "Information"
+ }
+ },
+ "extensionBundle": {
+ "id": "Microsoft.Azure.Functions.ExtensionBundle",
+ "version": "[4.*, 5.0.0)"
+ }
+}
diff --git a/examples/V2App/local.settings.json b/examples/V2App/local.settings.json
new file mode 100644
index 00000000..5cf9eedc
--- /dev/null
+++ b/examples/V2App/local.settings.json
@@ -0,0 +1,7 @@
+{
+ "IsEncrypted": false,
+ "Values": {
+ "FUNCTIONS_WORKER_RUNTIME": "powershell",
+ "AzureWebJobsStorage": "UseDevelopmentStorage=true"
+ }
+}
diff --git a/examples/V2App/profile.ps1 b/examples/V2App/profile.ps1
new file mode 100644
index 00000000..302fa781
--- /dev/null
+++ b/examples/V2App/profile.ps1
@@ -0,0 +1,7 @@
+# Azure Functions profile.ps1
+#
+# This profile.ps1 will get executed every cold start of the Function App.
+# Use it to define helper functions, set environment variables, or run initialization logic.
+
+# Uncomment the next line to enable Az module connectivity via managed identity:
+# Connect-AzAccount -Identity
diff --git a/examples/V2App/requirements.psd1 b/examples/V2App/requirements.psd1
new file mode 100644
index 00000000..9b54e3e5
--- /dev/null
+++ b/examples/V2App/requirements.psd1
@@ -0,0 +1,4 @@
+@{
+ # Uncomment to use the Az module for Azure resource management:
+ # 'Az' = '12.*'
+}
diff --git a/src/Attributes/AzFunctionAttribute.cs b/src/Attributes/AzFunctionAttribute.cs
new file mode 100644
index 00000000..e97862f1
--- /dev/null
+++ b/src/Attributes/AzFunctionAttribute.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Marks a PowerShell function for indexing as an Azure Function (V2 programming model).
+ /// Apply this attribute to the function's [CmdletBinding()] or param block.
+ ///
+ ///
+ /// function HttpExample {
+ /// [AzFunction()]
+ /// param(
+ /// [HttpTrigger(AuthLevel = "Anonymous", Route = "hello")]
+ /// $Request
+ /// )
+ /// ...
+ /// }
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+ public sealed class AzFunctionAttribute : Attribute
+ {
+ ///
+ /// Optional function name override. If not specified, the PowerShell function name is used.
+ ///
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Attributes/CosmosDB/CosmosDBInputAttribute.cs b/src/Attributes/CosmosDB/CosmosDBInputAttribute.cs
new file mode 100644
index 00000000..05b8a085
--- /dev/null
+++ b/src/Attributes/CosmosDB/CosmosDBInputAttribute.cs
@@ -0,0 +1,29 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a Cosmos DB input binding.
+ ///
+ public sealed class CosmosDBInputAttribute : InputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "cosmosDB";
+
+ /// The DatabaseName property.
+ public string DatabaseName { get; set; }
+ /// The ContainerName property.
+ public string ContainerName { get; set; }
+ /// The Id property.
+ public string Id { get; set; }
+ /// The PartitionKey property.
+ public string PartitionKey { get; set; }
+ /// The SqlQuery property.
+ public string SqlQuery { get; set; }
+ /// The PreferredLocations property.
+ public string PreferredLocations { get; set; }
+ }
+}
diff --git a/src/Attributes/CosmosDB/CosmosDBOutputAttribute.cs b/src/Attributes/CosmosDB/CosmosDBOutputAttribute.cs
new file mode 100644
index 00000000..efa7594a
--- /dev/null
+++ b/src/Attributes/CosmosDB/CosmosDBOutputAttribute.cs
@@ -0,0 +1,27 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a Cosmos DB output binding.
+ ///
+ public sealed class CosmosDBOutputAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "cosmosDB";
+
+ /// The DatabaseName property.
+ public string DatabaseName { get; set; }
+ /// The ContainerName property.
+ public string ContainerName { get; set; }
+ /// The CreateIfNotExists property.
+ public bool CreateIfNotExists { get; set; }
+ /// The PartitionKey property.
+ public string PartitionKey { get; set; }
+ /// The PreferredLocations property.
+ public string PreferredLocations { get; set; }
+ }
+}
diff --git a/src/Attributes/CosmosDB/CosmosDBTriggerAttribute.cs b/src/Attributes/CosmosDB/CosmosDBTriggerAttribute.cs
new file mode 100644
index 00000000..05dc9a95
--- /dev/null
+++ b/src/Attributes/CosmosDB/CosmosDBTriggerAttribute.cs
@@ -0,0 +1,38 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a Cosmos DB trigger binding.
+ ///
+ public sealed class CosmosDBTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "cosmosDBTrigger";
+
+ ///
+ public override string RequiredProperties => "DatabaseName,ContainerName";
+
+ /// The DatabaseName property.
+ public string DatabaseName { get; set; }
+ /// The ContainerName property.
+ public string ContainerName { get; set; }
+ /// The LeaseContainerName property.
+ public string LeaseContainerName { get; set; }
+ /// The CreateLeaseContainerIfNotExists property.
+ public bool CreateLeaseContainerIfNotExists { get; set; }
+ /// The LeaseContainerPrefix property.
+ public string LeaseContainerPrefix { get; set; }
+ /// The FeedPollDelay property.
+ public int FeedPollDelay { get; set; } = -1;
+ /// The StartFromBeginning property.
+ public bool StartFromBeginning { get; set; }
+ /// The MaxItemsPerInvocation property.
+ public int MaxItemsPerInvocation { get; set; } = -1;
+ /// The PreferredLocations property.
+ public string PreferredLocations { get; set; }
+ }
+}
diff --git a/src/Attributes/Durable/ActivityTriggerAttribute.cs b/src/Attributes/Durable/ActivityTriggerAttribute.cs
new file mode 100644
index 00000000..66a07bbe
--- /dev/null
+++ b/src/Attributes/Durable/ActivityTriggerAttribute.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a Durable Functions activity trigger binding.
+ ///
+ public sealed class ActivityTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "activityTrigger";
+ }
+}
diff --git a/src/Attributes/Durable/DurableClientAttribute.cs b/src/Attributes/Durable/DurableClientAttribute.cs
new file mode 100644
index 00000000..c2300821
--- /dev/null
+++ b/src/Attributes/Durable/DurableClientAttribute.cs
@@ -0,0 +1,26 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a Durable Functions client input binding (starter).
+ ///
+ public sealed class DurableClientAttribute : InputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "durableClient";
+
+ ///
+ /// The task hub name. Overrides the default task hub name from host.json.
+ ///
+ public string TaskHub { get; set; }
+
+ ///
+ /// The connection name for the durable storage backend.
+ ///
+ public string ConnectionName { get; set; }
+ }
+}
diff --git a/src/Attributes/Durable/EntityTriggerAttribute.cs b/src/Attributes/Durable/EntityTriggerAttribute.cs
new file mode 100644
index 00000000..8304d22a
--- /dev/null
+++ b/src/Attributes/Durable/EntityTriggerAttribute.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a Durable Functions entity trigger binding.
+ ///
+ public sealed class EntityTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "entityTrigger";
+ }
+}
diff --git a/src/Attributes/Durable/OrchestrationTriggerAttribute.cs b/src/Attributes/Durable/OrchestrationTriggerAttribute.cs
new file mode 100644
index 00000000..7b691244
--- /dev/null
+++ b/src/Attributes/Durable/OrchestrationTriggerAttribute.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a Durable Functions orchestration trigger binding.
+ ///
+ public sealed class OrchestrationTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "orchestrationTrigger";
+ }
+}
diff --git a/src/Attributes/EventGrid/EventGridOutputAttribute.cs b/src/Attributes/EventGrid/EventGridOutputAttribute.cs
new file mode 100644
index 00000000..6613ab74
--- /dev/null
+++ b/src/Attributes/EventGrid/EventGridOutputAttribute.cs
@@ -0,0 +1,21 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines an Event Grid output binding.
+ ///
+ public sealed class EventGridOutputAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "eventGrid";
+
+ /// The TopicEndpointUri property.
+ public string TopicEndpointUri { get; set; }
+ /// The TopicKeySetting property.
+ public string TopicKeySetting { get; set; }
+ }
+}
diff --git a/src/Attributes/EventGrid/EventGridTriggerAttribute.cs b/src/Attributes/EventGrid/EventGridTriggerAttribute.cs
new file mode 100644
index 00000000..97d705ba
--- /dev/null
+++ b/src/Attributes/EventGrid/EventGridTriggerAttribute.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines an Event Grid trigger binding.
+ ///
+ public sealed class EventGridTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "eventGridTrigger";
+ }
+}
diff --git a/src/Attributes/EventHub/EventHubOutputAttribute.cs b/src/Attributes/EventHub/EventHubOutputAttribute.cs
new file mode 100644
index 00000000..98cad8de
--- /dev/null
+++ b/src/Attributes/EventHub/EventHubOutputAttribute.cs
@@ -0,0 +1,19 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines an Event Hub output binding.
+ ///
+ public sealed class EventHubOutputAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "eventHub";
+
+ /// The EventHubName property.
+ public string EventHubName { get; set; }
+ }
+}
diff --git a/src/Attributes/EventHub/EventHubTriggerAttribute.cs b/src/Attributes/EventHub/EventHubTriggerAttribute.cs
new file mode 100644
index 00000000..a386939f
--- /dev/null
+++ b/src/Attributes/EventHub/EventHubTriggerAttribute.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines an Event Hub trigger binding.
+ ///
+ public sealed class EventHubTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "eventHubTrigger";
+
+ ///
+ public override string RequiredProperties => "EventHubName";
+
+ /// The EventHubName property.
+ public string EventHubName { get; set; }
+ /// The ConsumerGroup property.
+ public string ConsumerGroup { get; set; }
+ ///
+ /// "one" or "many". Defaults to "many".
+ ///
+ public string Cardinality { get; set; }
+ }
+}
diff --git a/src/Attributes/GenericInputBindingAttribute.cs b/src/Attributes/GenericInputBindingAttribute.cs
new file mode 100644
index 00000000..ce218d31
--- /dev/null
+++ b/src/Attributes/GenericInputBindingAttribute.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// A generic input binding attribute for third-party or unsupported input binding types.
+ /// Use this when no built-in input binding attribute exists for your binding extension.
+ ///
+ ///
+ /// param(
+ /// [GenericInputBinding(Type = "daprState", Connection = "DaprConn",
+ /// Properties = @("stateStore=myStore", "key=myKey"))]
+ /// $State
+ /// )
+ ///
+ public sealed class GenericInputBindingAttribute : InputBindingBaseAttribute
+ {
+ ///
+ /// The binding type string (e.g., "daprState", "graphWebhookSubscription").
+ ///
+ public string Type { get; set; }
+
+ ///
+ public override string BindingType => Type;
+
+ ///
+ /// Additional binding properties as "key=value" strings.
+ ///
+ public string Properties { get; set; }
+ }
+}
diff --git a/src/Attributes/GenericOutputBindingAttribute.cs b/src/Attributes/GenericOutputBindingAttribute.cs
new file mode 100644
index 00000000..f18c2b6b
--- /dev/null
+++ b/src/Attributes/GenericOutputBindingAttribute.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// A generic output binding attribute for third-party or unsupported output binding types.
+ /// Use this when no built-in output binding attribute exists for your binding extension.
+ ///
+ ///
+ /// param(
+ /// [GenericOutputBinding(Type = "daprPublish", Connection = "DaprConn",
+ /// Properties = @("pubSubName=myPubSub", "topic=myTopic"))]
+ /// $Output
+ /// )
+ ///
+ public sealed class GenericOutputBindingAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ /// The binding type string (e.g., "daprPublish", "twilioSms").
+ ///
+ public string Type { get; set; }
+
+ ///
+ public override string BindingType => Type;
+
+ ///
+ /// Additional binding properties as "key=value" strings.
+ ///
+ public string Properties { get; set; }
+ }
+}
diff --git a/src/Attributes/GenericTriggerAttribute.cs b/src/Attributes/GenericTriggerAttribute.cs
new file mode 100644
index 00000000..5b84695c
--- /dev/null
+++ b/src/Attributes/GenericTriggerAttribute.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// A generic trigger binding attribute for third-party or unsupported trigger types.
+ /// Use this when no built-in trigger attribute exists for your binding extension.
+ ///
+ ///
+ /// param(
+ /// [GenericTrigger(Type = "kafkaTrigger", Connection = "KafkaConn",
+ /// Properties = @("brokerList=myBroker", "topic=myTopic", "consumerGroup=myGroup"))]
+ /// $Message
+ /// )
+ ///
+ public sealed class GenericTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ /// The binding type string (e.g., "kafkaTrigger", "daprBindingTrigger").
+ ///
+ public string Type { get; set; }
+
+ ///
+ public override string BindingType => Type;
+
+ ///
+ /// Additional binding properties as "key=value" strings.
+ ///
+ public string Properties { get; set; }
+ }
+}
diff --git a/src/Attributes/Http/HttpOutputAttribute.cs b/src/Attributes/Http/HttpOutputAttribute.cs
new file mode 100644
index 00000000..efb54596
--- /dev/null
+++ b/src/Attributes/Http/HttpOutputAttribute.cs
@@ -0,0 +1,17 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines an explicit HTTP response output binding.
+ /// For most HTTP functions this is implicit and not needed.
+ ///
+ public sealed class HttpOutputAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "http";
+ }
+}
diff --git a/src/Attributes/Http/HttpTriggerAttribute.cs b/src/Attributes/Http/HttpTriggerAttribute.cs
new file mode 100644
index 00000000..bff61265
--- /dev/null
+++ b/src/Attributes/Http/HttpTriggerAttribute.cs
@@ -0,0 +1,44 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines an HTTP trigger binding for a V2 PowerShell function.
+ ///
+ ///
+ /// param(
+ /// [HttpTrigger(AuthLevel = "Anonymous", Methods = @("GET", "POST"), Route = "hello")]
+ /// $Request
+ /// )
+ ///
+ public sealed class HttpTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "httpTrigger";
+ ///
+ public override string ImplicitOutputBindingType => "http";
+ ///
+ public override string ArrayProperties => "Methods";
+
+ ///
+ /// The authorization level for the HTTP trigger.
+ /// Valid values: "Anonymous", "Function", "Admin". Defaults to "Function".
+ ///
+ public string AuthLevel { get; set; } = "Function";
+
+ ///
+ /// The HTTP methods that the function responds to.
+ /// If not specified, the function responds to all methods.
+ ///
+ public string Methods { get; set; }
+
+ ///
+ /// The route template for the HTTP trigger.
+ /// If not specified, the function name is used as the route.
+ ///
+ public string Route { get; set; }
+ }
+}
diff --git a/src/Attributes/InputBindingBaseAttribute.cs b/src/Attributes/InputBindingBaseAttribute.cs
new file mode 100644
index 00000000..5f9c358d
--- /dev/null
+++ b/src/Attributes/InputBindingBaseAttribute.cs
@@ -0,0 +1,38 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Base class for all input binding attributes in the V2 programming model.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
+ public abstract class InputBindingBaseAttribute : Attribute
+ {
+ ///
+ /// The binding type string for function.json (e.g., "cosmosDB", "blob").
+ /// Each derived class must return its binding type.
+ ///
+ public abstract string BindingType { get; }
+
+ ///
+ /// The connection string setting name for this binding.
+ ///
+ public string Connection { get; set; }
+
+ ///
+ /// Comma-delimited list of property names that should always be serialized as JSON arrays.
+ ///
+ public virtual string ArrayProperties => null;
+
+ ///
+ /// Comma-delimited list of property names that are required for this binding.
+ /// Override in derived classes to enable indexing-time validation.
+ ///
+ public virtual string RequiredProperties => null;
+ }
+}
diff --git a/src/Attributes/OutputBindingBaseAttribute.cs b/src/Attributes/OutputBindingBaseAttribute.cs
new file mode 100644
index 00000000..4c2b59f1
--- /dev/null
+++ b/src/Attributes/OutputBindingBaseAttribute.cs
@@ -0,0 +1,38 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Base class for all output binding attributes in the V2 programming model.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
+ public abstract class OutputBindingBaseAttribute : Attribute
+ {
+ ///
+ /// The binding type string for function.json (e.g., "queue", "cosmosDB").
+ /// Each derived class must return its binding type.
+ ///
+ public abstract string BindingType { get; }
+
+ ///
+ /// The connection string setting name for this binding.
+ ///
+ public string Connection { get; set; }
+
+ ///
+ /// Comma-delimited list of property names that should always be serialized as JSON arrays.
+ ///
+ public virtual string ArrayProperties => null;
+
+ ///
+ /// Comma-delimited list of property names that are required for this binding.
+ /// Override in derived classes to enable indexing-time validation.
+ ///
+ public virtual string RequiredProperties => null;
+ }
+}
diff --git a/src/Attributes/ServiceBus/ServiceBusOutputAttribute.cs b/src/Attributes/ServiceBus/ServiceBusOutputAttribute.cs
new file mode 100644
index 00000000..eb31eeb6
--- /dev/null
+++ b/src/Attributes/ServiceBus/ServiceBusOutputAttribute.cs
@@ -0,0 +1,21 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a Service Bus output binding.
+ ///
+ public sealed class ServiceBusOutputAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "serviceBus";
+
+ /// The QueueName property.
+ public string QueueName { get; set; }
+ /// The TopicName property.
+ public string TopicName { get; set; }
+ }
+}
diff --git a/src/Attributes/ServiceBus/ServiceBusTriggerAttribute.cs b/src/Attributes/ServiceBus/ServiceBusTriggerAttribute.cs
new file mode 100644
index 00000000..6df1ef32
--- /dev/null
+++ b/src/Attributes/ServiceBus/ServiceBusTriggerAttribute.cs
@@ -0,0 +1,29 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a Service Bus trigger binding.
+ ///
+ public sealed class ServiceBusTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "serviceBusTrigger";
+
+ /// The QueueName property.
+ public string QueueName { get; set; }
+ /// The TopicName property.
+ public string TopicName { get; set; }
+ /// The SubscriptionName property.
+ public string SubscriptionName { get; set; }
+ /// The IsSessionsEnabled property.
+ public bool IsSessionsEnabled { get; set; }
+ ///
+ /// "one" or "many". Defaults to "one".
+ ///
+ public string Cardinality { get; set; }
+ }
+}
diff --git a/src/Attributes/SignalR/SignalRInputAttribute.cs b/src/Attributes/SignalR/SignalRInputAttribute.cs
new file mode 100644
index 00000000..a2b3218f
--- /dev/null
+++ b/src/Attributes/SignalR/SignalRInputAttribute.cs
@@ -0,0 +1,25 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a SignalR connection info input binding.
+ ///
+ public sealed class SignalRInputAttribute : InputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "signalRConnectionInfo";
+
+ /// The HubName property.
+ public string HubName { get; set; }
+ /// The UserId property.
+ public string UserId { get; set; }
+ /// The IdToken property.
+ public string IdToken { get; set; }
+ /// The ClaimTypeList property.
+ public string ClaimTypeList { get; set; }
+ }
+}
diff --git a/src/Attributes/SignalR/SignalROutputAttribute.cs b/src/Attributes/SignalR/SignalROutputAttribute.cs
new file mode 100644
index 00000000..34874db2
--- /dev/null
+++ b/src/Attributes/SignalR/SignalROutputAttribute.cs
@@ -0,0 +1,19 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a SignalR message output binding.
+ ///
+ public sealed class SignalROutputAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "signalR";
+
+ /// The HubName property.
+ public string HubName { get; set; }
+ }
+}
diff --git a/src/Attributes/SignalR/SignalRTriggerAttribute.cs b/src/Attributes/SignalR/SignalRTriggerAttribute.cs
new file mode 100644
index 00000000..2ef0a8ee
--- /dev/null
+++ b/src/Attributes/SignalR/SignalRTriggerAttribute.cs
@@ -0,0 +1,23 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a SignalR trigger binding (for serverless SignalR upstream).
+ ///
+ public sealed class SignalRTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "signalRTrigger";
+
+ /// The HubName property.
+ public string HubName { get; set; }
+ /// The Category property.
+ public string Category { get; set; }
+ /// The Event property.
+ public string Event { get; set; }
+ }
+}
diff --git a/src/Attributes/Storage/BlobInputAttribute.cs b/src/Attributes/Storage/BlobInputAttribute.cs
new file mode 100644
index 00000000..050ac7c7
--- /dev/null
+++ b/src/Attributes/Storage/BlobInputAttribute.cs
@@ -0,0 +1,21 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a blob input binding.
+ ///
+ public sealed class BlobInputAttribute : InputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "blob";
+
+ ///
+ /// The blob path to read from (e.g., "container/{name}").
+ ///
+ public string Path { get; set; }
+ }
+}
diff --git a/src/Attributes/Storage/BlobOutputAttribute.cs b/src/Attributes/Storage/BlobOutputAttribute.cs
new file mode 100644
index 00000000..1ed167a2
--- /dev/null
+++ b/src/Attributes/Storage/BlobOutputAttribute.cs
@@ -0,0 +1,21 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a blob output binding.
+ ///
+ public sealed class BlobOutputAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "blob";
+
+ ///
+ /// The blob path to write to (e.g., "container/{name}").
+ ///
+ public string Path { get; set; }
+ }
+}
diff --git a/src/Attributes/Storage/BlobTriggerAttribute.cs b/src/Attributes/Storage/BlobTriggerAttribute.cs
new file mode 100644
index 00000000..a6607a84
--- /dev/null
+++ b/src/Attributes/Storage/BlobTriggerAttribute.cs
@@ -0,0 +1,29 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a blob trigger binding.
+ ///
+ public sealed class BlobTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "blobTrigger";
+
+ ///
+ public override string RequiredProperties => "Path";
+
+ ///
+ /// The blob path to monitor (e.g., "container/{name}").
+ ///
+ public string Path { get; set; }
+
+ ///
+ /// The source of the blob trigger event ("EventGrid" or "LogsAndContainerScan").
+ ///
+ public string Source { get; set; }
+ }
+}
diff --git a/src/Attributes/Storage/QueueOutputAttribute.cs b/src/Attributes/Storage/QueueOutputAttribute.cs
new file mode 100644
index 00000000..82f105b6
--- /dev/null
+++ b/src/Attributes/Storage/QueueOutputAttribute.cs
@@ -0,0 +1,21 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a queue output binding.
+ ///
+ public sealed class QueueOutputAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "queue";
+
+ ///
+ /// The name of the queue to write to.
+ ///
+ public string QueueName { get; set; }
+ }
+}
diff --git a/src/Attributes/Storage/QueueTriggerAttribute.cs b/src/Attributes/Storage/QueueTriggerAttribute.cs
new file mode 100644
index 00000000..15600505
--- /dev/null
+++ b/src/Attributes/Storage/QueueTriggerAttribute.cs
@@ -0,0 +1,24 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a queue trigger binding.
+ ///
+ public sealed class QueueTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "queueTrigger";
+
+ ///
+ public override string RequiredProperties => "QueueName";
+
+ ///
+ /// The name of the queue to monitor.
+ ///
+ public string QueueName { get; set; }
+ }
+}
diff --git a/src/Attributes/Storage/TableInputAttribute.cs b/src/Attributes/Storage/TableInputAttribute.cs
new file mode 100644
index 00000000..049c9aa2
--- /dev/null
+++ b/src/Attributes/Storage/TableInputAttribute.cs
@@ -0,0 +1,41 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a table input binding.
+ ///
+ public sealed class TableInputAttribute : InputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "table";
+
+ ///
+ /// The name of the storage table.
+ ///
+ public string TableName { get; set; }
+
+ ///
+ /// The row key to read. If not specified, reads all rows matching the filter.
+ ///
+ public string RowKey { get; set; }
+
+ ///
+ /// The partition key to filter by.
+ ///
+ public string PartitionKey { get; set; }
+
+ ///
+ /// An OData filter expression for rows.
+ ///
+ public string Filter { get; set; }
+
+ ///
+ /// The maximum number of rows to return.
+ ///
+ public int Take { get; set; } = -1;
+ }
+}
diff --git a/src/Attributes/Storage/TableOutputAttribute.cs b/src/Attributes/Storage/TableOutputAttribute.cs
new file mode 100644
index 00000000..0ecbcc25
--- /dev/null
+++ b/src/Attributes/Storage/TableOutputAttribute.cs
@@ -0,0 +1,31 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a table output binding.
+ ///
+ public sealed class TableOutputAttribute : OutputBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "table";
+
+ ///
+ /// The name of the storage table.
+ ///
+ public string TableName { get; set; }
+
+ ///
+ /// The row key for the entity to write.
+ ///
+ public string RowKey { get; set; }
+
+ ///
+ /// The partition key for the entity to write.
+ ///
+ public string PartitionKey { get; set; }
+ }
+}
diff --git a/src/Attributes/Timer/TimerTriggerAttribute.cs b/src/Attributes/Timer/TimerTriggerAttribute.cs
new file mode 100644
index 00000000..9d39a64d
--- /dev/null
+++ b/src/Attributes/Timer/TimerTriggerAttribute.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Defines a timer trigger binding.
+ ///
+ public sealed class TimerTriggerAttribute : TriggerBindingBaseAttribute
+ {
+ ///
+ public override string BindingType => "timerTrigger";
+
+ ///
+ public override string RequiredProperties => "Schedule";
+
+ ///
+ /// A CRON expression or TimeSpan string representing the timer schedule.
+ ///
+ public string Schedule { get; set; }
+
+ ///
+ /// Whether the function should be invoked immediately on startup.
+ ///
+ public bool RunOnStartup { get; set; }
+
+ ///
+ /// Whether to use the schedule monitor to ensure schedules are maintained.
+ ///
+ public bool UseMonitor { get; set; } = true;
+ }
+}
diff --git a/src/Attributes/TriggerBindingBaseAttribute.cs b/src/Attributes/TriggerBindingBaseAttribute.cs
new file mode 100644
index 00000000..892ccba1
--- /dev/null
+++ b/src/Attributes/TriggerBindingBaseAttribute.cs
@@ -0,0 +1,46 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+
+namespace Microsoft.Azure.Functions.PowerShellWorker.Attributes
+{
+ ///
+ /// Base class for all trigger binding attributes in the V2 programming model.
+ ///
+ [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
+ public abstract class TriggerBindingBaseAttribute : Attribute
+ {
+ ///
+ /// The binding type string for function.json (e.g., "httpTrigger", "queueTrigger").
+ /// Each derived class must return its binding type.
+ ///
+ public abstract string BindingType { get; }
+
+ ///
+ /// If this trigger implies an automatic output binding, return its type (e.g., "http").
+ /// Return null if no implicit output. Override in derived classes as needed.
+ ///
+ public virtual string ImplicitOutputBindingType => null;
+
+ ///
+ /// Comma-delimited list of property names that should always be serialized as JSON arrays
+ /// in the raw binding, even when they contain a single value (e.g., "Methods").
+ /// Override in derived classes as needed.
+ ///
+ public virtual string ArrayProperties => null;
+
+ ///
+ /// Comma-delimited list of property names that are required for this binding.
+ /// Override in derived classes to enable indexing-time validation.
+ ///
+ public virtual string RequiredProperties => null;
+
+ ///
+ /// The connection string setting name for this binding.
+ ///
+ public string Connection { get; set; }
+ }
+}
diff --git a/src/DependencyManagement/DependencyManager.cs b/src/DependencyManagement/DependencyManager.cs
index a2bbe57f..6bed1b15 100644
--- a/src/DependencyManagement/DependencyManager.cs
+++ b/src/DependencyManagement/DependencyManager.cs
@@ -280,6 +280,14 @@ private static string GetFunctionAppRootPath(string requestMetadataDirectory)
throw new ArgumentException("Empty request metadata directory path", nameof(requestMetadataDirectory));
}
+ // V2 (worker-indexed): directory IS the app root.
+ // V1: directory is FunctionAppRoot/FunctionName/, go up one level.
+ if (File.Exists(Path.Join(requestMetadataDirectory, "requirements.psd1"))
+ || File.Exists(Path.Join(requestMetadataDirectory, "host.json")))
+ {
+ return requestMetadataDirectory;
+ }
+
return Path.GetFullPath(Path.Join(requestMetadataDirectory, ".."));
}
diff --git a/src/FunctionInfo.cs b/src/FunctionInfo.cs
index 091eecde..b276f3a9 100644
--- a/src/FunctionInfo.cs
+++ b/src/FunctionInfo.cs
@@ -57,7 +57,9 @@ internal AzFunctionInfo(RpcFunctionMetadata metadata)
// Support 'entryPoint' only if 'scriptFile' is a .psm1 file;
// Support .psm1 'scriptFile' only if 'entryPoint' is specified.
+ // Exception: V2 programming model (worker-indexed) uses entryPoint with .ps1 files.
bool isScriptFilePsm1 = ScriptPath.EndsWith(".psm1", StringComparison.OrdinalIgnoreCase);
+ bool isWorkerIndexed = metadata.Properties.ContainsKey("WorkerIndexed");
bool entryPointNotDefined = string.IsNullOrEmpty(EntryPoint);
if (entryPointNotDefined)
{
@@ -66,7 +68,7 @@ internal AzFunctionInfo(RpcFunctionMetadata metadata)
throw new ArgumentException(PowerShellWorkerStrings.RequireEntryPointForScriptModule);
}
}
- else if (!isScriptFilePsm1)
+ else if (!isScriptFilePsm1 && !isWorkerIndexed)
{
throw new ArgumentException(PowerShellWorkerStrings.InvalidEntryPointForScriptFile);
}
@@ -109,6 +111,10 @@ internal AzFunctionInfo(RpcFunctionMetadata metadata)
else if (bindingInfo.Direction == BindingInfo.Types.Direction.Out)
{
outputBindings.Add(bindingName, bindingInfo);
+
+ // V2 programming model: output bindings may also be declared as parameters.
+ // Remove them from the parameter copy so they aren't flagged as unknown.
+ parametersCopy.Remove(bindingName);
}
else
{
diff --git a/src/FunctionLoader.cs b/src/FunctionLoader.cs
index ae33dbf1..5959688e 100644
--- a/src/FunctionLoader.cs
+++ b/src/FunctionLoader.cs
@@ -74,9 +74,37 @@ internal static void ClearLoadedFunctions()
///
internal static void SetupWellKnownPaths(FunctionLoadRequest request, string managedDependenciesPath)
{
- // Resolve the FunctionApp root path
- FunctionAppRootPath = Path.GetFullPath(Path.Join(request.Metadata.Directory, ".."));
+ // For V2 (worker-indexed), FunctionAppRootPath is already set by SetFunctionAppRootPath
+ // during ProcessFunctionMetadataRequest. For V1, resolve it from the function directory.
+ if (FunctionAppRootPath == null)
+ {
+ // V1: Metadata.Directory is FunctionAppRoot/FunctionName/, so go up one level
+ FunctionAppRootPath = Path.GetFullPath(Path.Join(request.Metadata.Directory, ".."));
+ }
+
+ SetupModuleAndProfilePaths(managedDependenciesPath);
+ }
+ ///
+ /// Sets the FunctionAppRootPath directly from a directory path.
+ /// Used by the V2 programming model (worker indexing) where the function app directory
+ /// is provided by FunctionsMetadataRequest before any FunctionLoadRequest arrives.
+ ///
+ internal static void SetFunctionAppRootPath(string functionAppDirectory)
+ {
+ if (FunctionAppRootPath == null)
+ {
+ FunctionAppRootPath = functionAppDirectory;
+
+ // Discover profile.ps1 early for V2 apps
+ var options = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive };
+ var profiles = Directory.EnumerateFiles(FunctionAppRootPath, "profile.ps1", options);
+ FunctionAppProfilePath = profiles.FirstOrDefault();
+ }
+ }
+
+ private static void SetupModuleAndProfilePaths(string managedDependenciesPath)
+ {
// Resolve module paths
var appLevelModulesPath = Path.Join(FunctionAppRootPath, "Modules");
var workerLevelModulesPath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Modules");
diff --git a/src/PowerShell/PowerShellManager.cs b/src/PowerShell/PowerShellManager.cs
index a8c506ac..2f140760 100644
--- a/src/PowerShell/PowerShellManager.cs
+++ b/src/PowerShell/PowerShellManager.cs
@@ -10,6 +10,7 @@
using System.Reflection;
using Microsoft.Azure.Functions.PowerShellWorker.Durable;
using Microsoft.Azure.Functions.PowerShellWorker.Utility;
+using Microsoft.Azure.Functions.PowerShellWorker.Attributes;
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
using LogLevel = Microsoft.Azure.WebJobs.Script.Grpc.Messages.RpcLog.Types.Level;
@@ -51,7 +52,7 @@ internal class PowerShellManager
static PowerShellManager()
{
- // Set the type accelerators for 'HttpResponseContext' and 'HttpResponseContext'.
+ // Set the type accelerators for 'HttpResponseContext' and 'HttpRequestContext'.
// We probably will expose more public types from the worker in future for the interop between worker and the 'PowerShellWorker' module.
// But it's most likely only 'HttpResponseContext' and 'HttpResponseContext' are supposed to be used directly by users, so we only add
// type accelerators for these two explicitly.
@@ -59,6 +60,64 @@ static PowerShellManager()
var addMethod = accelerator.GetMethod("Add", new Type[] { typeof(string), typeof(Type) });
addMethod.Invoke(null, new object[] { "HttpResponseContext", typeof(HttpResponseContext) });
addMethod.Invoke(null, new object[] { "HttpRequestContext", typeof(HttpRequestContext) });
+
+ // V2 programming model: auto-register type accelerators for all binding attribute types
+ // so users can write [HttpTrigger()] etc. without 'using namespace'.
+ // Discovers all concrete classes deriving from our base attribute classes via reflection.
+ RegisterBindingAttributeAccelerators(addMethod);
+ }
+
+ ///
+ /// Discovers all public concrete attribute classes that derive from TriggerBindingBaseAttribute,
+ /// InputBindingBaseAttribute, OutputBindingBaseAttribute, or AzFunctionAttribute and registers
+ /// them as PowerShell type accelerators using their short name (without "Attribute" suffix).
+ ///
+ private static void RegisterBindingAttributeAccelerators(MethodInfo addMethod)
+ {
+ var baseTypes = new[]
+ {
+ typeof(TriggerBindingBaseAttribute),
+ typeof(InputBindingBaseAttribute),
+ typeof(OutputBindingBaseAttribute),
+ typeof(AzFunctionAttribute),
+ };
+
+ var assembly = typeof(AzFunctionAttribute).Assembly;
+
+ foreach (var type in assembly.GetExportedTypes())
+ {
+ if (type.IsAbstract || type.IsInterface)
+ continue;
+
+ bool isBindingAttr = false;
+ foreach (var baseType in baseTypes)
+ {
+ if (baseType.IsAssignableFrom(type))
+ {
+ isBindingAttr = true;
+ break;
+ }
+ }
+
+ if (!isBindingAttr)
+ continue;
+
+ // Strip "Attribute" suffix for the short name
+ var shortName = type.Name;
+ if (shortName.EndsWith("Attribute", StringComparison.OrdinalIgnoreCase))
+ {
+ shortName = shortName.Substring(0, shortName.Length - "Attribute".Length);
+ }
+
+ try
+ {
+ addMethod.Invoke(null, new object[] { shortName, type });
+ }
+ catch
+ {
+ // If a name is already registered, skip it
+ }
+ }
}
///
@@ -247,7 +306,7 @@ public Hashtable InvokeFunction(
{
_pwsh.AddCommand(Utils.TracePipelineObjectCmdlet);
}
- return ExecuteUserCode(isActivityFunction || FunctionInfoUtilities.hasAssistantSkillTrigger(functionInfo), outputBindings);
+ return ExecuteUserCode(isActivityFunction || FunctionInfoUtilities.hasAssistantSkillTrigger(functionInfo), outputBindings, functionInfo);
}
}
catch (RuntimeException e)
@@ -315,10 +374,20 @@ private void SetInputBindingParameterValues(
///
/// Execution a function fired by a trigger or an activity function scheduled by an orchestration.
///
- private Hashtable ExecuteUserCode(bool addPipelineOutput, IDictionary outputBindings)
+ private Hashtable ExecuteUserCode(bool addPipelineOutput, IDictionary outputBindings, AzFunctionInfo functionInfo = null)
{
var pipelineItems = _pwsh.InvokeAndClearCommands