#Requires -Version 7.2 <# .SYNOPSIS Shows what a v1 Entra Policy Suite install's rules and settings become in Entra Policy Suite 2.0. Writes nothing. .DESCRIPTION Reads a v1 folder - DATA\Identity_Tagging*.csv, Device_Tagging*.csv, EntraNamedLocations_AzureNetworkServiceTags.csv, Entra_Policy_Suite_custom.config, Entra_Policy_Suite_locked.config, and the attribute per tag type from Entra-Policy-Suite\Entra-ID-User-Tagging.ps1 - and shows the plan: the rule cards it makes (v1 rows with the same ConditionGroup become one card), the tag types and their values, the settings, break-glass accounts, admin units, target groups and service tags, and the HINTS on the rules (cloned rows that kept their ConditionGroup, a condition twice, a contradiction, an unknown condition type ...). This script never writes to the database (since 2.0.69 nobody needs a database right to import v1): the import is done in the web app - Overview > Import v1 (SuperAdmin): upload the same files, look at the plan, approve, and Entra Policy Suite writes it. -Apply prints those steps and the files to upload. The v1 folder is only read, never changed. Demo material (Identity_Tagging_Demo_Reset.csv, the demo scripts) is not read. .PARAMETER Path The v1 folder: its DATA folder, or the folder that holds DATA (e.g. C:\SCRIPTS). .PARAMETER UserTaggingScript v1's Entra-ID-User-Tagging.ps1, for the attribute per tag type. Default: \Entra-Policy-Suite\. .PARAMETER OutFile Also save the plan as JSON (for review, or to hand to support). .PARAMETER Apply Print how to import: the files to upload on the web app's Import v1 page. Nothing is written. .PARAMETER ConnectionString No longer used (2.0.69): the script never connects to the database. Accepted so older command lines still run. .EXAMPLE .\Import-EpsV1Data.ps1 -Path C:\SCRIPTS Shows the plan, writes nothing. .EXAMPLE .\Import-EpsV1Data.ps1 -Path C:\SCRIPTS -Apply Shows the plan and the files to upload on Overview > Import v1. .LINK https://invardia.com/docs/eps/scripts/Import-EpsV1Data #> # PUBLISHED as a self-contained launcher of Import-EpsV1Data.ps1 (EntraPolicySuite 2.0.107, Publish-EpsHandover): it runs release 2.0.107 unless -EpsVersion picks another. [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)][string]$Path, [string]$UserTaggingScript, [string]$OutFile, [switch]$Apply, [string]$ConnectionString, [switch]$Quiet, [ValidatePattern('^$|^2\.\d+\.\d+$')][string]$EpsVersion = '2.0.107' ) $ErrorActionPreference = 'Stop' # A self-contained launcher of Import-EpsV1Data.ps1 (invardia.com/support/eps/): it downloads the EntraPolicySuite release this script # was handed over for (2.0.107 - the version of your install's ring; -EpsVersion picks another, -EpsVersion '' the # latest), checks it against the release's published SHA-256 digest and runs the release's own Import-EpsV1Data.ps1 with the # parameters you gave. Nothing is installed on this machine; the download goes to a temporary folder. $what = [bool]$WhatIfPreference; $WhatIfPreference = $false $repo = 'KnudsenMorten/EntraPolicySuite'; $h = @{ 'User-Agent' = 'EntraPolicySuite-support' } $rel = Invoke-RestMethod -Uri $(if ($EpsVersion) { "https://api.github.com/repos/$repo/releases/tags/v$EpsVersion" } else { "https://api.github.com/repos/$repo/releases?per_page=30" }) -Headers $h $rel = @($rel | Where-Object { $_.tag_name -match '^v2\.' -and -not $_.draft -and -not $_.prerelease } | Sort-Object { [version]($_.tag_name.TrimStart('v') -replace '[^0-9.].*$', '') } -Descending)[0] if (-not $rel) { Write-Host 'No EntraPolicySuite v2 release found.' -ForegroundColor Red; exit 3 } $asset = @($rel.assets | Where-Object { $_.name -match '^EntraPolicySuite-v2[0-9A-Za-z.+-]*\.zip$' })[0] if (-not $asset) { Write-Host "Release $($rel.tag_name) has no EntraPolicySuite-v2*.zip." -ForegroundColor Red; exit 3 } $dir = Join-Path ([IO.Path]::GetTempPath()) "eps-$($rel.tag_name)-$([guid]::NewGuid().ToString('N').Substring(0, 6))" New-Item -ItemType Directory -Path $dir | Out-Null $zip = Join-Path $dir $asset.name Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zip -Headers $h $got = (Get-FileHash -LiteralPath $zip -Algorithm SHA256).Hash.ToLowerInvariant() $published = if ("$($asset.digest)" -match '^(?i)sha256:([0-9a-f]{64})$') { $Matches[1].ToLowerInvariant() } else { '' } if (-not $published -or $got -ne $published) { [IO.Directory]::Delete($dir, $true); Write-Host "The download does not match the release's SHA-256 - deleted, nothing run." -ForegroundColor Red; exit 3 } Write-Host "Release $($rel.tag_name), SHA-256 $got (matches the release)" Expand-Archive -LiteralPath $zip -DestinationPath $dir -Force $script = Get-ChildItem -LiteralPath $dir -Recurse -Filter 'Import-EpsV1Data.ps1' -File | Select-Object -First 1 if (-not $script) { Write-Host 'The release has no Import-EpsV1Data.ps1.' -ForegroundColor Red; exit 3 } $pass = @{} foreach ($k in @($PSBoundParameters.Keys)) { if ($k -notin 'EpsVersion', 'WhatIf', 'Confirm') { $pass[$k] = $PSBoundParameters[$k] } } if ($what) { $pass.WhatIf = $true } & $script.FullName @pass exit $LASTEXITCODE