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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 77 additions & 1 deletion .github/workflows/majorrelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ jobs:
permissions:
id-token: write
contents: write


outputs:
version: ${{ steps.variables.outputs.BUILDVERSION }}
steps:
- name: Setup .NET
uses: actions/setup-dotnet@v5
Expand All @@ -26,6 +28,20 @@ jobs:
with:
ref: dev
token: ${{ secrets.PAT }}
# The provenance names the commit the workflow run is for, so stop before publishing anything when that is not the commit checked out
- name: Check the commit to build
shell: pwsh
run: |
$head = git rev-parse HEAD
if ($head -ne $env:GITHUB_SHA) {
throw "dev is at $head, but this workflow run is for $env:GITHUB_SHA. Start the workflow from dev again."
}
- name: Install SBOM tool
shell: pwsh
run: |
$sbomToolPath = Join-Path $env:RUNNER_TEMP "sbom-tool"
dotnet tool install Microsoft.Sbom.DotNetTool --tool-path $sbomToolPath --version 4.1.13
"SBOM_TOOL_PATH=$sbomToolPath" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
- name: Install Sign CLI tool
shell: pwsh
run: |
Expand All @@ -50,13 +66,73 @@ jobs:
run: |
./build/Build-Release.ps1
- name: Set variables
id: variables
shell: pwsh
run: |
$version = Get-Content version.txt -raw
"BUILDVERSION=$version" | Out-File $env:GITHUB_ENV -Encoding utf8 -Append
"BUILDVERSION=$version" | Out-File $env:GITHUB_OUTPUT -Encoding utf8 -Append
- name: Add & Commit
uses: EndBug/add-and-commit@v10
with:
message: 'Major release to PowerShell Gallery'
tag: '${{env.BUILDVERSION}} --force'
push: true
# The SBOM is generated here, as its packages are read from the restore this build used
- name: Package module and generate SBOM
Comment thread
gautamdsheth marked this conversation as resolved.
shell: pwsh
run: |
$moduleFolder = Join-Path ([environment]::GetFolderPath("MyDocuments")) "PowerShell/Modules/PnP.PowerShell"
$releaseFolder = Join-Path $env:RUNNER_TEMP "release"
New-Item -Path $releaseFolder -ItemType Directory -Force | Out-Null
Compress-Archive -Path "$moduleFolder/*" -DestinationPath (Join-Path $releaseFolder "PnP.PowerShell-$env:BUILDVERSION.zip") -CompressionLevel Optimal
& (Join-Path $env:SBOM_TOOL_PATH "sbom-tool.exe") generate -b $moduleFolder -bc ./src/Commands -pn PnP.PowerShell -pv $env:BUILDVERSION -ps "Microsoft 365 Patterns and Practices" -nsb https://github.com/pnp/powershell -m $env:SBOM_TOOL_PATH
if ($LASTEXITCODE -ne 0) {
throw "Generating the SBOM failed"
}
Copy-Item -LiteralPath (Join-Path $env:SBOM_TOOL_PATH "_manifest/spdx_2.2/manifest.spdx.json") -Destination (Join-Path $releaseFolder "PnP.PowerShell-$env:BUILDVERSION.spdx.json")
- name: Upload release files
uses: actions/upload-artifact@v7
with:
name: release
path: ${{ runner.temp }}/release

# Attests and drafts the release apart from the signing environment, so that it can be rerun on its own when it fails
attest:
if: github.repository_owner == 'pnp'
needs: build
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
attestations: write

steps:
- name: Download release files
uses: actions/download-artifact@v7
with:
name: release
path: release
- name: Attest build provenance
id: provenance
uses: actions/attest@v4
with:
subject-path: release/PnP.PowerShell-${{ needs.build.outputs.version }}.zip
- name: Attest SBOM
uses: actions/attest@v4
with:
subject-path: release/PnP.PowerShell-${{ needs.build.outputs.version }}.zip
sbom-path: release/PnP.PowerShell-${{ needs.build.outputs.version }}.spdx.json
- name: Create draft GitHub release
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ needs.build.outputs.version }}
run: |
# Scorecard reads provenance from the release assets, not from the attestation store
cp "${{ steps.provenance.outputs.bundle-path }}" "release/PnP.PowerShell-$VERSION.intoto.jsonl"
gh release create "v$VERSION" release/* \
--repo "$GITHUB_REPOSITORY" \
--target "$GITHUB_SHA" \
--title "Release $VERSION" \
--notes "The zip holds the module as published to the PowerShell Gallery. Verify where it was built with \`gh attestation verify PnP.PowerShell-$VERSION.zip --repo pnp/powershell\`." \
--draft
6 changes: 3 additions & 3 deletions .github/workflows/nightlydockerimages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ jobs:
platforms: linux/arm/v7
push: true
tags: ${{ env.IMAGE_NAME }}:${{ needs.compute-version.outputs.VERSION_NIGHTLY }}-linux-arm32v7
# Optional: pass your own build args
# build-args: |
# PNP_VERSION=${{ needs.compute-version.outputs.VERSION }}
# The image installs this version each time a container starts; without it, it falls back to the dockerfile's default
build-args: |
PNP_VERSION=${{ needs.compute-version.outputs.VERSION_NIGHTLY }}

publish-docker-manifest:
if: github.repository_owner == 'pnp'
Expand Down
82 changes: 54 additions & 28 deletions .github/workflows/stabledockerimages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,103 +6,129 @@ on:
permissions: read-all

jobs:
compute-version:
if: github.repository_owner == 'pnp'
runs-on: ubuntu-latest
outputs:
VERSION: ${{ steps.v.outputs.VERSION }}
steps:
# The images install the module from the PowerShell Gallery, so its latest stable release is the version to publish
- id: v
shell: pwsh
run: |
$version = (Find-Module -Name PnP.PowerShell -Repository PSGallery).Version
"VERSION=$version" | Out-File $env:GITHUB_OUTPUT -Encoding utf8 -Append

publish-docker-windows-amd64:
if: github.repository_owner == 'pnp'
runs-on: windows-2025
needs: compute-version
steps:
- name: Checkout main branch
uses: actions/checkout@v6
with:
ref: main
- name: Build an image
run: |
$VERSION="$(cat ./version.txt)"
$VERSION="${{ needs.compute-version.outputs.VERSION }}"
docker build --build-arg PNP_VERSION=$VERSION --platform windows/amd64 ./docker -f ./docker/windows-amd64.dockerfile --tag ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-stable-windows-amd64
- name: Push the image
run: |
$VERSION="$(cat ./version.txt)"
$VERSION="${{ needs.compute-version.outputs.VERSION }}"
docker login -u ${{ secrets.DOCKER_USERNAME }} -p '${{ secrets.DOCKER_PASSWORD }}'
docker push "${{ secrets.DOCKER_ORG }}/powershell:$VERSION-stable-windows-amd64"

publish-docker-linux-arm32:
runs-on: ubuntu-22.04
if: false
publish-docker-linux-arm32v7:
if: github.repository_owner == 'pnp'
runs-on: ubuntu-latest
needs: compute-version
steps:
- uses: actions/checkout@v6
- name: Build an image
run: |
VERSION="$(cat ./version.txt)"
docker build --build-arg PNP_VERSION=$VERSION ./docker -f ./docker/pnppowershell.dockerFile --tag ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-stable-ubuntu-22.04-arm32;
- name: Push the image
run: |
VERSION="$(cat ./version.txt)"
docker login -u ${{ secrets.DOCKER_USERNAME }} -p '${{ secrets.DOCKER_PASSWORD }}'
docker push "${{ secrets.DOCKER_ORG }}/powershell:$VERSION-stable-ubuntu-22.04-arm32"
- name: Checkout main branch
uses: actions/checkout@v6
with:
ref: main
# Buildx emulates arm32 on the x64 runner; the image installs the module each time a container starts
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build & push the image
uses: docker/build-push-action@v7
with:
context: ./docker
file: ./docker/linux-arm32.dockerfile
platforms: linux/arm/v7
push: true
tags: ${{ secrets.DOCKER_ORG }}/powershell:${{ needs.compute-version.outputs.VERSION }}-stable-linux-arm32v7
build-args: |
PNP_VERSION=${{ needs.compute-version.outputs.VERSION }}
# Without attestations the tag is a single image manifest, which docker manifest create can amend
provenance: false
sbom: false

publish-docker-linux-arm64:
if: github.repository_owner == 'pnp'
runs-on: ubuntu-24.04-arm
needs: compute-version
steps:
- name: Checkout main branch
uses: actions/checkout@v6
with:
ref: main
- name: Build an image
run: |
VERSION="$(cat ./version.txt)"
VERSION="${{ needs.compute-version.outputs.VERSION }}"
docker build --build-arg PNP_VERSION=$VERSION --platform linux/arm64/v8 ./docker -f ./docker/linux-arm64.dockerfile --tag ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-stable-linux-arm64
- name: Push the image
run: |
VERSION="$(cat ./version.txt)"
VERSION="${{ needs.compute-version.outputs.VERSION }}"
docker login -u ${{ secrets.DOCKER_USERNAME }} -p '${{ secrets.DOCKER_PASSWORD }}'
docker push "${{ secrets.DOCKER_ORG }}/powershell:$VERSION-stable-linux-arm64"

publish-docker-linux-amd64:
if: github.repository_owner == 'pnp'
runs-on: ubuntu-latest
needs: compute-version
steps:
- name: Checkout main branch
uses: actions/checkout@v6
with:
ref: main
- name: Build an image
run: |
VERSION="$(cat ./version.txt)"
VERSION="${{ needs.compute-version.outputs.VERSION }}"
docker build --build-arg PNP_VERSION=$VERSION --platform linux/amd64 ./docker -f ./docker/linux-amd64.dockerfile --tag ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-stable-linux-amd64
- name: Push the image
run: |
VERSION="$(cat ./version.txt)"
VERSION="${{ needs.compute-version.outputs.VERSION }}"
docker login -u ${{ secrets.DOCKER_USERNAME }} -p '${{ secrets.DOCKER_PASSWORD }}'
docker push "${{ secrets.DOCKER_ORG }}/powershell:$VERSION-stable-linux-amd64"

publish-docker-manifest:
if: github.repository_owner == 'pnp'
runs-on: ubuntu-latest
needs: [ publish-docker-linux-arm64, publish-docker-linux-amd64, publish-docker-windows-amd64 ]
needs: [ compute-version, publish-docker-linux-arm32v7, publish-docker-linux-arm64, publish-docker-linux-amd64, publish-docker-windows-amd64 ]
steps:
- name: Checkout main branch
uses: actions/checkout@v6
with:
ref: main
- name: Publish manifest
run: |
VERSION="$(cat ./version.txt)-stable"
VERSION="${{ needs.compute-version.outputs.VERSION }}-stable"
docker login -u ${{ secrets.DOCKER_USERNAME }} -p '${{ secrets.DOCKER_PASSWORD }}'
docker manifest create ${{ secrets.DOCKER_ORG }}/powershell:$VERSION \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-amd64 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-arm32 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-arm32v7 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-arm64 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-windows-amd64
docker manifest push ${{ secrets.DOCKER_ORG }}/powershell:$VERSION
docker manifest create ${{ secrets.DOCKER_ORG }}/powershell:stable \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-amd64 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-arm32 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-arm32v7 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-arm64 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-windows-amd64
docker manifest push ${{ secrets.DOCKER_ORG }}/powershell:stable
docker manifest create ${{ secrets.DOCKER_ORG }}/powershell:latest \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-amd64 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-arm32 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-arm32v7 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-linux-arm64 \
--amend ${{ secrets.DOCKER_ORG }}/powershell:$VERSION-windows-amd64
docker manifest push ${{ secrets.DOCKER_ORG }}/powershell:latest
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,22 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Added `Get-PnPPersistedLogin` which lists the tenant url, client id and authentication type of every login registered to use the local token cache, so the cache can be inspected without reading it. [#5463](https://github.com/pnp/powershell/pull/5463)
- Added `-PersistLogin` to the certificate based app only parameter sets of `Connect-PnPOnline`, so a connection made with `-CertificatePath`, `-CertificateBase64Encoded`, `-Thumbprint` or the environment variables can reuse its access token from the local cache. The certificate, tenant and client id are still required on each connection, as neither the certificate nor its password is stored. [#5463](https://github.com/pnp/powershell/pull/5463)
- Added `-CopilotSearchOptOut` to `Set-PnPSearchSettings` and exposed the value through `Get-PnPSearchSettings`; added `-CopilotSearchOptIn` to `Set-PnPTenant` and exposed the value through `Get-PnPTenant`. [#5478](https://github.com/pnp/powershell/pull/5478)
- Added a zip of the module, its SPDX software bill of materials and its build provenance to each stable release on GitHub, so the zip can be verified with `gh attestation verify`. [#5483](https://github.com/pnp/powershell/pull/5483)
- Added `-AzureEnvironment` and `-MicrosoftGraphEndPoint` to `Connect-PnPOnline -AzureADWorkloadIdentity`, so a connection through a workload identity calls Microsoft Graph and the other APIs of a national cloud instead of the worldwide ones. [#5483](https://github.com/pnp/powershell/pull/5483)

### Changed
- Changed `Connect-PnPOnline` to write verbose message on which stored credential it resolved for the url, as it previously picked one up from the credential manager without saying so. [#5463](https://github.com/pnp/powershell/pull/5463)
- Changed `Disconnect-PnPOnline -ClearPersistedLogin` to write a warning when no persisted login exists for the current connection, instead of silently doing nothing. [#5463](https://github.com/pnp/powershell/pull/5463)
- Telemetry in PnP PowerShell has been removed due to the costs of collecting the data didn't outweigh the benefits to the PnP PowerShell team to have insights into its usage. The involved cmdlets `Get-PnPPowerShellTelemetryEnabled`, `Enable-PnPPowerShellTelemetry` and `Disable-PnPPowerShellTelemetry` have been marked as deprecated and no longer function, but will stay in v3 for backwards compatibility with existing scripts. These cmdlets will be removed in the next v4 release. All versions of PnP PowerShell will no longer be able to submit telemetry. You might see background requests for this failing. This will not interfear with the normal execution of your PowerShell script. [#5460](https://github.com/pnp/powershell/pull/5460)
- Changed `Disable-PnPFeature` to mark `-Force` as obsolete, as it never had an effect. Using it now writes a warning. [#5483](https://github.com/pnp/powershell/pull/5483)
- Changed `Get-PnPUnifiedAuditLog` to call the Office 365 Management API of the cloud given with `Connect-PnPOnline -AzureEnvironment` for `USGovernment`, `USGovernmentHigh` and `USGovernmentDoD`, instead of always calling `manage.office.com`. [#5483](https://github.com/pnp/powershell/pull/5483)
- Changed `Connect-PnPOnline -ManagedIdentity` and `Connect-PnPOnline -AccessToken` to keep the cloud given with `-AzureEnvironment`, so the cmdlets that look it up, such as `Get-PnPEntraIDUser`, `Get-PnPUnifiedAuditLog` and those calling Power Platform or Azure Resource Manager APIs, call that cloud instead of the worldwide one. Microsoft Graph requests on such a connection now go to that cloud as well, also without `-Url`. [#5483](https://github.com/pnp/powershell/pull/5483)

### Fixed
- Using UPNs with an apostrophe in it not working with `Remove-PnPUserProfile`, `Export-PnPUserProfile`, `Export-PnPUserInfo`, and `Remove-PnPUserInfo`. The apostrophe is now escaped in the API request. [#5459](https://github.com/pnp/powershell/pull/5459)
- Fix PnP ALC initializer with loaded assemblies stackoverflow issue. [#5481](https://github.com/pnp/powershell/pull/5481)
- Fixed the stable Docker images stopping at 3.1.0: `m365pnp/powershell:latest` and `m365pnp/powershell:stable` are published again, for the latest stable release on the PowerShell Gallery, now also for 32 bit ARM (`linux/arm/v7`). [#5483](https://github.com/pnp/powershell/pull/5483)
- Fixed `Get-Help Move-PnPItemProxy` returning only the syntax of the cmdlet, as it had no documentation page. [#5483](https://github.com/pnp/powershell/pull/5483)

### Contributors

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ This module is a successor of the [PnP-PowerShell](https://github.com/pnp/pnp-po

For more information about installing or upgrading to this module, please refer to [the documentation](https://pnp.github.io/powershell/articles/index.html).

To use PnP PowerShell from an AI assistant such as GitHub Copilot or Claude, see the [PnP PowerShell MCP server](https://pnp.github.io/powershell/articles/mcpserver.html).

## IMPORTANT - New PnP PowerShell 3.x

We released a new major version of PnP PowerShell, version 3 and upwards. This version of PnP PowerShell requires as of today PowerShell 7.4.0 or newer, and is based upon .NET 8.0.
Expand Down
Loading
Loading