mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 10:45:02 +01:00
219 lines
9.7 KiB
PowerShell
219 lines
9.7 KiB
PowerShell
<#
|
|
.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 "========================================================================================================================================================================" |