<# .SYNOPSIS Comprehensive Snyk organization and project inventory across all accessible Snyk organizations. .DESCRIPTION This script connects to the Snyk API to retrieve a complete inventory of all organizations and their associated projects. It provides essential information for security governance, project oversight, and vulnerability management across your Snyk ecosystem. Features: • Multi-organization project enumeration across Snyk groups • Project metadata collection including repository, type, and runtime information • Comprehensive CSV reporting with timestamped output files • Automatic project name parsing for repository identification • Support for all Snyk project types (npm, Maven, Docker, etc.) • Secure API key management via Azure Key Vault .PARAMETER None This script does not accept parameters. Configuration is managed through Azure Key Vault integration. .EXAMPLE .\SnykOverview.ps1 Executes a complete inventory of all Snyk organizations and projects with CSV export. .EXAMPLE Connect-AzAccount Set-AzContext -SubscriptionId "your-subscription-id" .\SnykOverview.ps1 Ensures proper Azure authentication before accessing Key Vault for Snyk API credentials. .INPUTS None. This script does not accept pipeline input. .OUTPUTS System.IO.FileInfo Generates a timestamped CSV file containing Snyk project inventory with the following columns: - OrganisationId: Snyk organization unique identifier - OrganisationName: Human-readable organization name - GroupId: Snyk group identifier for organization grouping - OrganisationSlug: URL-friendly organization identifier - ProjectId: Unique project identifier within Snyk - ProjectRepo: Repository name extracted from project name - ProjectName: Specific project/component name within repository - ProjectType: Project technology type (npm, maven, docker, etc.) - ProjectCreateDate: Project creation timestamp in Snyk - ProjectTargetFile: Target manifest file (package.json, pom.xml, etc.) - ProjectTargetRuntime: Runtime environment or version information .NOTES Requires PowerShell 5.1 or later Requires Az.KeyVault PowerShell module for secure API key retrieval Prerequisites: - Must be connected to Azure (Connect-AzAccount) - Requires access to the 'consoleapp' Key Vault containing 'SnykKey' secret - Snyk API token must have appropriate organization and project read permissions - Network connectivity to api.snyk.io (HTTPS outbound on port 443) API Information: - Uses Snyk REST API v2023-08-29~beta - Rate limiting: Respects Snyk API rate limits (varies by plan) - Pagination: Handles up to 100 projects per organization (adjust limit if needed) Security Considerations: - API tokens are securely retrieved from Azure Key Vault - No credentials are stored in script or output files - Uses encrypted HTTPS connections to Snyk API - Audit trail is maintained in timestamped CSV files .LINK https://docs.snyk.io/snyk-api-info/snyk-rest-api https://docs.snyk.io/snyk-api-info/authentication-for-api .COMPONENT Az.KeyVault PowerShell Module, Snyk REST API .ROLE Security Administration, DevSecOps, Vulnerability Management .FUNCTIONALITY Snyk project inventory, security governance, vulnerability management reporting #> $access_token = Get-AzKeyVaultSecret -VaultName "consoleapp" -Name "SnykKey" -AsPlainText $head = @{ Authorization ="$access_token" } $version = "2023-08-29%7Ebeta" $ofs = ', ' # Generate timestamped output filename [string] $date = Get-Date -Format "yyyy-MM-dd HHmm" $fileName = ".\$date snyk projects.csv" Write-Host "========================================================================================================================================================================" Write-Host "🔍 Snyk Organization and Project Inventory" -ForegroundColor Green Write-Host "========================================================================================================================================================================" Write-Host "🔐 Retrieving Snyk API credentials from Azure Key Vault..." -ForegroundColor Cyan Write-Host "📊 Output file: $fileName" -ForegroundColor Gray Write-Host "" # Data structure class for Snyk project information class SnykOverview { [string] $OrganisationId = "" [string] $OrganisationName = "" [string] $GroupId = "" [string] $OrganisationSlug = "" [string] $ProjectId = "" [string] $ProjectRepo = "" [string] $ProjectName = "" [string] $ProjectType = "" [string] $ProjectCreateDate = "" [string] $ProjectTargetFile = "" [string] $ProjectTargetRunTime = "" } # Initialize results collection [SnykOverview[]]$Result = @() $totalOrganizations = 0 $totalProjects = 0 Write-Host "📋 Retrieving Snyk organizations..." -ForegroundColor Cyan # Retrieve all accessible Snyk organizations $organisationUrl = "https://api.snyk.io/rest/orgs?version=$version" $organisationResponse = Invoke-RestMethod -Uri $organisationUrl -Method GET -Headers $head Write-Host "✅ Found $($organisationResponse.data.Count) Snyk organization(s)" -ForegroundColor Green Write-Host "" # Process each organization to retrieve its projects foreach ($organisation in $organisationResponse.data) { $totalOrganizations++ $organisationId = $organisation.id Write-Host "----------------------------------------------------------------------------------------------------------------------------------------------------------------------" Write-Host "🏢 Processing Organization [$($organisation.attributes.name)] (ID: $organisationId)" -ForegroundColor Yellow # Retrieve all projects for the current organization $projectUrl = "https://api.snyk.io/rest/orgs/$organisationId/projects?version=$version&limit=100" $projectResponse = Invoke-RestMethod -Uri $projectUrl -Method GET -Headers $head $orgProjectCount = $projectResponse.data.Count Write-Host " 📦 Found $orgProjectCount project(s) in this organization" -ForegroundColor White # Process each project within the organization foreach ($project in $projectResponse.data) { $totalProjects++ $projectName = $project.attributes.name # Create new project record with comprehensive metadata [SnykOverview] $SnykOverview = [SnykOverview]::new() # Populate organization-level information $SnykOverview.OrganisationId = $organisationId $SnykOverview.OrganisationName = $organisation.attributes.name $SnykOverview.GroupId = $organisation.attributes.group_id $SnykOverview.OrganisationSlug = $organisation.attributes.slug # Populate project-level information $SnykOverview.ProjectId = $project.id # Parse project name to extract repository and component names (format: "repo:component") $SnykOverview.ProjectRepo = $projectName.Split(":")[0] $SnykOverview.ProjectName = $projectName.Split(":")[1] $SnykOverview.ProjectType = $project.attributes.type $SnykOverview.ProjectCreateDate = $project.attributes.created $SnykOverview.ProjectTargetFile = $project.attributes.target_file $SnykOverview.ProjectTargetRunTime = $project.attributes.target_runtime $Result += $SnykOverview } } Write-Host "" Write-Host "========================================================================================================================================================================" Write-Host "📊 Snyk Inventory Summary" -ForegroundColor Green Write-Host "========================================================================================================================================================================" Write-Host "" Write-Host "Inventory Results:" -ForegroundColor Cyan Write-Host "==================" Write-Host "• Organizations Processed: $totalOrganizations" -ForegroundColor White Write-Host "• Total Projects Found: $totalProjects" -ForegroundColor White Write-Host "" # Export results to CSV file Write-Host "💾 Exporting results to CSV..." -ForegroundColor Cyan $Result | Export-Csv -Path $fileName -NoTypeInformation -Force if (Test-Path $fileName) { $fileSize = [math]::Round((Get-Item $fileName).Length / 1KB, 2) Write-Host "✅ Export completed successfully!" -ForegroundColor Green Write-Host " 📁 File: $fileName" -ForegroundColor Gray Write-Host " 📏 Size: $fileSize KB" -ForegroundColor Gray } else { Write-Host "❌ Export failed - file not created" -ForegroundColor Red } Write-Host "" Write-Host "🔍 Project Type Breakdown:" -ForegroundColor Cyan $projectTypes = $Result | Group-Object ProjectType | Sort-Object Count -Descending foreach ($type in $projectTypes) { Write-Host " $($type.Name): $($type.Count) projects" -ForegroundColor White } Write-Host "" Write-Host "🏢 Organization Summary:" -ForegroundColor Cyan $orgSummary = $Result | Group-Object OrganisationName | Sort-Object Count -Descending foreach ($org in $orgSummary) { Write-Host " $($org.Name): $($org.Count) projects" -ForegroundColor White } Write-Host "" Write-Host "📋 Displaying first 10 results..." -ForegroundColor Cyan $Result | Select-Object -First 10 | Format-Table -AutoSize Write-Host "" Write-Host "========================================================================================================================================================================" Write-Host "✅ Snyk inventory completed successfully!" -ForegroundColor Green Write-Host "========================================================================================================================================================================"