Skip to content

Commit 7f52b1f

Browse files
Upgrade to PowerShell 7.4 (#900)
* Upgrade to PowerShell SDK 7.4.0-preview.1 * Upgrade to .NET SDK 7.0 * Update README.md to target net7.0 and PowerShell 7.4 * Upgrade TargetFramework to net7.0 * Update tests: Convertfrom-Json returns an ordered hashtable * Reset build counter for PowerShell 7.4 * Update package id to Microsoft.Azure.Functions.PowerShellWorker.PS7.4 * Add PowerShell 7.4 to the list of supported versions * Update E2E tests to target PowerShell 7.4 * Remove logic to create case-insensitive hashtable from the ConvertFromJson output * Update tests * Add support to update the PowerShell 7.2 and 7.4 language workers in the Core Tools * Try to create a case insensitive Hashtable for the DurableClient when deserializing JSON * Update ConvertFromJson logic for Durable client * Add test case to validate TypedDataToCaseInsensitiveHashtable deserialization * Update build.ps1 logging
1 parent a5a8132 commit 7f52b1f

16 files changed

+101
-51
lines changed

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ with any additional questions or comments.
4949

5050
### Prereqs
5151

52-
* [.NET 6.0 SDK](https://www.microsoft.com/net/download/visual-studio-sdks)
52+
* [.NET 7.0 SDK](https://www.microsoft.com/net/download/visual-studio-sdks)
5353

5454
### Build
5555

@@ -82,18 +82,18 @@ On macOS if you installed via `brew`
8282
/usr/local/Cellar/azure-functions-core-tools/<version>/workers/
8383
```
8484

85-
Under the `workers/powershell` folder, create a folder with the name `7.2` if it does not exist yet. Copy the result of the `publish` directory into the `workers/powershell/7.2` folder, and copy the `publish/worker.config.json` file into the `workers/powershell` folder:
85+
Under the `workers/powershell` folder, create a folder with the name `7.4` if it does not exist yet. Copy the result of the `publish` directory into the `workers/powershell/7.4` folder, and copy the `publish/worker.config.json` file into the `workers/powershell` folder:
8686
```powershell
87-
Copy-Item -Recurse -Force ./src/bin/Debug/net6.0/publish/ "/usr/local/Cellar/azure-functions-core-tools/$(func --version)/workers/powershell/7.2"
88-
Copy-Item -Recurse -Force ./src/bin/Debug/net6.0/publish/worker.config.json "/usr/local/Cellar/azure-functions-core-tools/$(func --version)/workers/powershell"
87+
Copy-Item -Recurse -Force ./src/bin/Debug/net7.0/publish/ "/usr/local/Cellar/azure-functions-core-tools/$(func --version)/workers/powershell/7.4"
88+
Copy-Item -Recurse -Force ./src/bin/Debug/net7.0/publish/worker.config.json "/usr/local/Cellar/azure-functions-core-tools/$(func --version)/workers/powershell"
8989
```
9090

9191
> NOTE: if the powershell folder already exists, you should delete it or debugging won't work.
9292
9393
Then `cd` into a Function App with PowerShell as the worker runtime
9494
(NOTE: There's an example PowerShell Function App in the `examples` folder).
9595

96-
Set the environment variable `FUNCTIONS_WORKER_RUNTIME_VERSION` to `7.2`, or add this as an app setting to the `local.settings.json` file.
96+
Set the environment variable `FUNCTIONS_WORKER_RUNTIME_VERSION` to `7.4`, or add this as an app setting to the `local.settings.json` file.
9797

9898
Lastly, run:
9999

@@ -119,15 +119,15 @@ set the environment variable `"AzureWebJobsScriptRoot"`
119119
to the root folder path (the folder which contains the `host.json`)
120120
of your test functions app.
121121

122-
Under the `workers/powershell` folder, create a folder with the name `7.2` if it does not exist yet. Then copy the `publish` directory to `workers/powershell/7.2`, and the `publish/worker.config.json` to `workers/powershell`:
122+
Under the `workers/powershell` folder, create a folder with the name `7.4` if it does not exist yet. Then copy the `publish` directory to `workers/powershell/7.4`, and the `publish/worker.config.json` to `workers/powershell`:
123123
```powershell
124-
Copy-Item -Recurse -Force ./src/bin/Debug/net6.0/publish/ "<Azure Functions Host Root>/src/WebJobs.Script.WebHost/bin/Debug/net6.0/workers/powershell/7.2"
125-
Copy-Item -Force ./src/bin/Debug/net6.0/publish/worker.config.json "<Azure Functions Host Root>/src/WebJobs.Script.WebHost/bin/Debug/net6.0/workers/powershell"
124+
Copy-Item -Recurse -Force ./src/bin/Debug/net7.0/publish/ "<Azure Functions Host Root>/src/WebJobs.Script.WebHost/bin/Debug/net7.0/workers/powershell/7.4"
125+
Copy-Item -Force ./src/bin/Debug/net7.0/publish/worker.config.json "<Azure Functions Host Root>/src/WebJobs.Script.WebHost/bin/Debug/net7.0/workers/powershell"
126126
```
127127

128128
Then you can start the host by running:
129129
```sh
130-
dotnet ./src/WebJobs.Script.WebHost/bin/Debug/net6.0/Microsoft.Azure.WebJobs.Script.WebHost.dll
130+
dotnet ./src/WebJobs.Script.WebHost/bin/Debug/net7.0/Microsoft.Azure.WebJobs.Script.WebHost.dll
131131
```
132132

133133
> Note: Remember to remove `"AzureWebJobsScriptRoot"`
@@ -149,6 +149,6 @@ That will place a `Microsoft.Azure.Functions.PowerShellWorker.*.nupkg` in:
149149

150150
It pulls the contents of the publish folder in:
151151

152-
`azure-functions-powershell-worker/src/bin/Debug/net6.0/publish`
152+
`azure-functions-powershell-worker/src/bin/Debug/net7.0/publish`
153153

154154
if you specify a different Configuration or TargetFramework that will be honored.

azure-pipelines.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pool:
2121

2222
variables:
2323
Configuration: Release
24-
buildNumber: $[ counter('build', 400) ] # Start higher than our AppVeyor versions. Every build (pr or branch) will increment.
24+
buildNumber: $[ counter('build', 001) ] # Start higher than our AppVeyor versions. Every build (pr or branch) will increment.
2525

2626
steps:
2727
- pwsh: |

build.ps1

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,33 @@ param(
3434
$AddSBOM,
3535

3636
[string]
37-
$SBOMUtilSASUrl
37+
$SBOMUtilSASUrl,
38+
39+
[string]
40+
[ValidateSet("7.2", "7.4")]
41+
$WorkerVersion
3842
)
3943

40-
#Requires -Version 6.0
44+
#Requires -Version 7.0
45+
46+
Import-Module "$PSScriptRoot/tools/helper.psm1" -Force
47+
48+
$PowerShellVersion = $null
49+
$TargetFramework = $null
50+
$DefaultPSWorkerVersion = '7.4'
51+
52+
if (-not $workerVersion)
53+
{
54+
Write-Log "Worker version not specified. Setting workerVersion to '$DefaultPSWorkerVersion'"
55+
$workerVersion = $DefaultPSWorkerVersion
56+
}
57+
58+
$PowerShellVersion = $WorkerVersion
59+
Write-Log "Build worker version: $PowerShellVersion"
4160

42-
$PowerShellVersion = '7.2'
43-
$TargetFramework = 'net6.0'
61+
# Set target framework for 7.2 to net6.0 and for 7.4 to net7.0
62+
$TargetFramework = ($PowerShellVersion -eq "7.2") ? 'net6.0' : 'net7.0'
63+
Write-Log "Target framework: $TargetFramework"
4464

4565
function Get-FunctionsCoreToolsDir {
4666
if ($CoreToolsDir) {
@@ -76,7 +96,7 @@ function Install-SBOMUtil
7696
}
7797

7898
$MANIFESTOOLNAME = "ManifestTool"
79-
Write-Host "Installing $MANIFESTOOLNAME..."
99+
Write-Log "Installing $MANIFESTOOLNAME..."
80100

81101
$MANIFESTOOL_DIRECTORY = Join-Path $PSScriptRoot $MANIFESTOOLNAME
82102
Remove-Item -Recurse -Force $MANIFESTOOL_DIRECTORY -ErrorAction Ignore
@@ -92,7 +112,7 @@ function Install-SBOMUtil
92112
throw "$MANIFESTOOL_DIRECTORY does not contain '$dllName'"
93113
}
94114

95-
Write-Host 'Done.'
115+
Write-Log 'Done.'
96116

97117
return $manifestToolPath
98118
}
@@ -102,6 +122,12 @@ function Deploy-PowerShellWorker {
102122

103123
$powerShellWorkerDir = "$(Get-FunctionsCoreToolsDir)/workers/powershell/$PowerShellVersion"
104124

125+
if (-not (Test-Path $powerShellWorkerDir))
126+
{
127+
Write-Log "Creating directory: '$powerShellWorkerDir'"
128+
New-Item -Path $powerShellWorkerDir -ItemType Directory -Force | Out-Null
129+
}
130+
105131
Write-Log "Deploying worker to $powerShellWorkerDir..."
106132

107133
if (-not $IsWindows) {
@@ -115,8 +141,6 @@ function Deploy-PowerShellWorker {
115141
Write-Log "Deployed worker to $powerShellWorkerDir"
116142
}
117143

118-
Import-Module "$PSScriptRoot/tools/helper.psm1" -Force
119-
120144
# Bootstrap step
121145
if ($Bootstrap.IsPresent) {
122146
Write-Log "Validate and install missing prerequisits for building ..."

package/Microsoft.Azure.Functions.PowerShellWorker.Package.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Licensed under the MIT license. See LICENSE file in the project root for full li
55
<Project Sdk="Microsoft.NET.Sdk">
66
<Import Project="..\PowerShellWorker.Common.props" />
77
<PropertyGroup>
8-
<TargetFramework>net6.0</TargetFramework>
8+
<TargetFramework>net7.0</TargetFramework>
99
<NoBuild>true</NoBuild>
1010
<IncludeBuildOutput>false</IncludeBuildOutput>
1111
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

package/Microsoft.Azure.Functions.PowerShellWorker.nuspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Licensed under the MIT license. See LICENSE file in the project root for full li
55
-->
66
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
77
<metadata>
8-
<id>Microsoft.Azure.Functions.PowerShellWorker.PS7.2</id>
8+
<id>Microsoft.Azure.Functions.PowerShellWorker.PS7.4</id>
99
<!-- Needed to specify the version here for the nuspec to be valid -->
1010
<version>$version$</version>
1111
<title>Azure Function PowerShell Language Worker (PowerShell 7.2)</title>
@@ -26,7 +26,7 @@ Licensed under the MIT license. See LICENSE file in the project root for full li
2626
</contentFiles>
2727
</metadata>
2828
<files>
29-
<file src="..\src\bin\$configuration$\$targetFramework$\publish\**\*" target="contentFiles\any\any\workers\powershell\7.2" />
29+
<file src="..\src\bin\$configuration$\$targetFramework$\publish\**\*" target="contentFiles\any\any\workers\powershell\7.4" />
3030
<file src="..\src\bin\$configuration$\$targetFramework$\publish\worker.config.json" target="contentFiles\any\any\workers\powershell" />
3131
<file src="..\images\Powershell_black_64.png" target="images\" />
3232
</files>

src/DurableWorker/DurableController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public void InitializeBindings(IList<ParameterBinding> inputData, out bool hasEx
9595
{
9696
var durableClient =
9797
inputData.First(item => item.Name == _durableFunctionInfo.DurableClientBindingName)
98-
.Data.ToObject();
98+
.Data.ToObject(isDurableClient: true);
9999

100100
_powerShellServices.SetDurableClient(durableClient);
101101
}

src/Microsoft.Azure.Functions.PowerShellWorker.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Licensed under the MIT license. See LICENSE file in the project root for full li
66
<Import Project="..\PowerShellWorker.Common.props" />
77
<PropertyGroup>
88
<OutputType>Exe</OutputType>
9-
<TargetFramework>net6.0</TargetFramework>
9+
<TargetFramework>net7.0</TargetFramework>
1010
<TieredCompilation>true</TieredCompilation>
1111
<Product>Azure Function PowerShell Language Worker</Product>
1212
<AssemblyName>Microsoft.Azure.Functions.PowerShellWorker</AssemblyName>
@@ -21,7 +21,7 @@ Licensed under the MIT license. See LICENSE file in the project root for full li
2121

2222
<ItemGroup>
2323
<PackageReference Include="Grpc.Net.Client" Version="2.49.0" />
24-
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.8" />
24+
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.4.0-preview.1" />
2525
<PackageReference Include="CommandLineParser" Version="2.9.1" />
2626
<PackageReference Include="Google.Protobuf" Version="3.21.9" />
2727
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.3" />

src/Utility/TypeExtensions.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private static HttpRequestContext ToHttpRequestContext (this RpcHttp rpcHttp)
6565
return httpRequestContext;
6666
}
6767

68-
internal static object ToObject(this TypedData data, bool convertFromJsonIfValidJson = true)
68+
internal static object ToObject(this TypedData data, bool convertFromJsonIfValidJson = true, bool isDurableClient = false)
6969
{
7070
if (data == null)
7171
{
@@ -75,7 +75,7 @@ internal static object ToObject(this TypedData data, bool convertFromJsonIfValid
7575
switch (data.DataCase)
7676
{
7777
case TypedData.DataOneofCase.Json:
78-
return ConvertFromJson(data.Json);
78+
return ConvertFromJson(data.Json, returnCaseInsensitiveHashtable: isDurableClient);
7979
case TypedData.DataOneofCase.Bytes:
8080
return data.Bytes.ToByteArray();
8181
case TypedData.DataOneofCase.Double:
@@ -89,7 +89,7 @@ internal static object ToObject(this TypedData data, bool convertFromJsonIfValid
8989
case TypedData.DataOneofCase.String:
9090
string str = data.String;
9191
return convertFromJsonIfValidJson && IsValidJson(str)
92-
? ConvertFromJson(str)
92+
? ConvertFromJson(str, returnCaseInsensitiveHashtable: isDurableClient)
9393
: str;
9494
case TypedData.DataOneofCase.None:
9595
return null;
@@ -113,7 +113,7 @@ private static object GetRawBody(TypedData rpcHttpBody)
113113
}
114114
}
115115

116-
public static object ConvertFromJson(string json)
116+
public static object ConvertFromJson(string json, bool returnCaseInsensitiveHashtable = false)
117117
{
118118
object retObj = JsonObject.ConvertFromJson(json, returnHashtable: true, error: out _);
119119

@@ -122,12 +122,17 @@ public static object ConvertFromJson(string json)
122122
retObj = psObj.BaseObject;
123123
}
124124

125-
if (retObj is Hashtable hashtable)
125+
// By default, the PowerShell language worker no longer tries to create a case-insensitive Hashtable from the output of ConvertFromJson.
126+
// This is a breaking change which is tracked by https://github.com/Azure/azure-functions-powershell-worker/issues/909.
127+
128+
if (returnCaseInsensitiveHashtable && (retObj is Hashtable hashtable))
126129
{
130+
// In order to call into the DurableClient properties without having to worry about casing,
131+
// we need to return a case-insensitive Hashtable for the DurableClient code path.
127132
try
128133
{
129-
// ConvertFromJson returns case-sensitive Hashtable by design -- JSON may contain keys that only differ in case.
130-
// We try casting the Hashtable to a case-insensitive one, but if that fails, we keep using the original one.
134+
// ConvertFromJson returns case-sensitive Ordered Hashtable by design -- JSON may contain keys that only differ in case.
135+
// We try to convert the Ordered Hashtable to a case-insensitive Hashtable, but if that fails, we keep using the original one.
131136
retObj = new Hashtable(hashtable, StringComparer.OrdinalIgnoreCase);
132137
}
133138
catch

src/worker.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"extensions":[".ps1", ".psm1"],
55
"defaultExecutablePath":"dotnet",
66
"defaultWorkerPath":"%FUNCTIONS_WORKER_RUNTIME_VERSION%/Microsoft.Azure.Functions.PowerShellWorker.dll",
7-
"supportedRuntimeVersions":["7", "7.2"],
7+
"supportedRuntimeVersions":["7", "7.2", "7.4"],
88
"defaultRuntimeVersion": "7.2",
99
"sanitizeRuntimeVersionRegex":"\\d+\\.?\\d*"
1010
}

test/E2E/Azure.Functions.PowerShellWorker.E2E/Azure.Functions.PowerShellWorker.E2E/Azure.Functions.PowerShellWorker.E2E.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net7.0</TargetFramework>
55

66
<IsPackable>false</IsPackable>
77
</PropertyGroup>

0 commit comments

Comments
 (0)