PSSonarCloud.psm1
<#
_____ _____ _____ _____ _ _ | __ \ / ____/ ____| / ____| | | | | |__) | (___| (___ ___ _ __ __ _ _ __| | | | ___ _ _ __| | | ___/ \___ \\___ \ / _ \| '_ \ / _` | '__| | | |/ _ \| | | |/ _` | | | ____) |___) | (_) | | | | (_| | | | |____| | (_) | |_| | (_| | |_| |_____/_____/ \___/|_| |_|\__,_|_| \_____|_|\___/ \__,_|\__,_| #> # --- Clean up psSonarCloudConnection variable on module remove $ExecutionContext.SessionState.Module.OnRemove = { Remove-Variable -Name SonarCloudConnection -Force -ErrorAction SilentlyContinue } <# - Function: xCheckScriptSonarCloudConnection #> function xCheckScriptSonarCloudConnection { <# .SYNOPSIS Checks for the presence of $Script:SonarCloudConnection .DESCRIPTION Checks for the presence of $Script:SonarCloudConnection .INPUTS None .OUTPUTS None .EXAMPLE xCheckScriptSonarCloudConnection #> [CmdletBinding()] Param ( ) # --- Test for SonarCloud Connection if (-not $Script:SonarCloudConnection){ throw "SonarCloud Connection variable does not exist. Please run Connect-SonarCloud first to create it" } } <# - Function: xNewHttpQueryString #> function xNewHttpQueryString { <# .SYNOPSIS Generates HTTP Query String from URI and parameters .DESCRIPTION Generates HTTP Query String from URI and parameters Based on https://powershellmagazine.com/2019/06/14/pstip-a-better-way-to-generate-http-query-strings-in-powershell/ .INPUTS String Hashtable .OUTPUTS String .EXAMPLE $parameters = @{ organization = 'test-321' ps = 100 } $url = 'https://sonarcloud.io/api/projects/search' xNewHttpQueryString -Uri $url -QueryParameter $parameters #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$Uri, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [Hashtable]$QueryParameter ) # Add System.Web Add-Type -AssemblyName System.Web # Create a http name value collection from an empty string $nvCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) foreach ($key in $QueryParameter.Keys) { $nvCollection.Add($key, $QueryParameter.$key) } # Build the uri $uriRequest = [System.UriBuilder]$uri $uriRequest.Query = $nvCollection.ToString() return $uriRequest.Uri.OriginalString } <# - Function: Connect-SonarCloud #> function Connect-SonarCloud { <# .SYNOPSIS Make a connection to the SonarCloud API .DESCRIPTION Make a connection to the SonarCloud API. Set the SonarCloud API Key .PARAMETER APIKey SonarCloud API Key .INPUTS System.String .OUTPUTS System.Management.Automation.PSObject .EXAMPLE Connect-SonarCloud -APIKey 'xxxxxxxxxxxxxxxxx' #> [CmdletBinding()][OutputType('System.Management.Automation.PSObject')] Param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$apiKey ) try { # --- Create Output Object $Script:sonarCloudConnection = [pscustomobject]@{ apiKey = $apiKey url = 'https://sonarcloud.io/api' } } catch [Exception]{ throw } finally { Write-Output $sonarCloudConnection } } <# - Function: Disconnect-SonarCloud #> function Disconnect-SonarCloud { <# .SYNOPSIS Disconnect from the SonarCloud API .DESCRIPTION Disconnect from the SonarCloud API by removing the script SonarCloudConnection variable from PowerShell .EXAMPLE Disconnect-SonarCloud .EXAMPLE Disconnect-SonarCloud -Confirm:$false #> [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High")] Param () # --- Check for the presence of $Script:SonarCloudConnection xCheckScriptSonarCloudConnection if ($PSCmdlet.ShouldProcess($Script:SonarCloudConnection.url)){ try { Write-Verbose -Message "Removing SonarCloudConnection Script Variable" Remove-Variable -Name SonarCloudConnection -Scope Script -Force -ErrorAction SilentlyContinue } catch [Exception]{ throw } } } <# - Function: Invoke-SonarCloudRestMethod #> function Invoke-SonarCloudRestMethod { <# .SYNOPSIS Wrapper for Invoke-RestMethod/Invoke-WebRequest with SonarCloud specifics .DESCRIPTION Wrapper for Invoke-RestMethod/Invoke-WebRequest with SonarCloud specifics .PARAMETER Method REST Method: Supported Methods: GET, POST, PUT,DELETE .PARAMETER URI API URI, e.g. /projects/search .PARAMETER QueryParameters HTTP Query String Parameters .PARAMETER Headers Optionally supply custom headers .PARAMETER Body REST Body in JSON format .PARAMETER OutFile Save the results to a file .PARAMETER WebRequest Use Invoke-WebRequest rather than the default Invoke-RestMethod .INPUTS System.String Hashtable Switch .OUTPUTS System.Management.Automation.PSObject .EXAMPLE $parameters = @{ organization = 'test-321' ps = 100 } Invoke-SonarCloudRestMethod -Method GET -URI '/projects/search' -queryParameters $parameters #> [CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')] Param ( [Parameter(Mandatory=$true, ParameterSetName="Standard")] [Parameter(Mandatory=$true, ParameterSetName="Body")] [Parameter(Mandatory=$true, ParameterSetName="OutFile")] [ValidateSet("GET","POST","PUT","DELETE")] [String]$method, [Parameter(Mandatory=$true, ParameterSetName="Standard")] [Parameter(Mandatory=$true, ParameterSetName="Body")] [Parameter(Mandatory=$true, ParameterSetName="OutFile")] [ValidateNotNullOrEmpty()] [String]$uri, [Parameter(Mandatory=$true, ParameterSetName="Standard")] [Parameter(Mandatory=$true, ParameterSetName="Body")] [Parameter(Mandatory=$true, ParameterSetName="OutFile")] [ValidateNotNullOrEmpty()] [Hashtable]$queryParameters, [Parameter(Mandatory=$false, ParameterSetName="Standard")] [Parameter(Mandatory=$false, ParameterSetName="Body")] [Parameter(Mandatory=$false, ParameterSetName="OutFile")] [ValidateNotNullOrEmpty()] [System.Collections.IDictionary]$headers, [Parameter(Mandatory=$false, ParameterSetName="Body")] [ValidateNotNullOrEmpty()] [Hashtable]$body, [Parameter(Mandatory=$false, ParameterSetName="OutFile")] [ValidateNotNullOrEmpty()] [String]$outFile, [Parameter(Mandatory=$false, ParameterSetName="Standard")] [Parameter(Mandatory=$false, ParameterSetName="Body")] [Parameter(Mandatory=$false, ParameterSetName="OutFile")] [Switch]$webRequest ) # --- Test for existing connection to vRA if (-not $Script:SonarCloudConnection){ throw "SonarCloud Connection variable does not exist. Please run Connect-SonarCloud first to create it" } # --- Create Invoke-RestMethod Parameters $fullURI = "$($Script:SonarCloudConnection.url)$($uri)" # --- Update full URI if queryParameters have been supplied if ($PSBoundParameters.ContainsKey("queryParameters")){ $fullURI = xNewHttpQueryString -Uri $fullURI -QueryParameter $queryParameters } Write-Verbose "Full URI is: $($fullURI)" # --- Prepare API Key for authentication $auth = $Script:SonarCloudConnection.apiKey + ':' $encoded = [System.Text.Encoding]::UTF8.GetBytes($auth) $base64 = [System.Convert]::ToBase64String($encoded) $basicAuthValue = "Basic $base64" # --- Add default headers if not passed if (!$PSBoundParameters.ContainsKey("Headers")){ $headers = @{ "Authorization" = $basicAuthValue; } } Write-Verbose "Headers are: $($headers | ConvertTo-Json)" # --- Set up default parmaeters $params = @{ method = $method headers = $headers uri = $fullURI } if ($PSBoundParameters.ContainsKey("body")){ $params.Add("body", $body) # --- Log the payload being sent to the server Write-Debug -Message ($body | ConvertTo-Json -Depth 5) } if ($PSBoundParameters.ContainsKey("outfile")){ $params.Add("outFile", $outFile) } try { # --- Use either Invoke-WebRequest or Invoke-RestMethod if ($WebRequest.IsPresent) { Invoke-WebRequest @params } else { Invoke-RestMethod @params } } catch { throw $_ } } <# - Function: Get-SonarCloudPermissionTemplate #> function Get-SonarCloudPermissionTemplate { <# .SYNOPSIS Get SonarCloud PermissionTemplates .DESCRIPTION Get SonarCloud PermissionTemplates .PARAMETER organization SonarCloud Organization .PARAMETER permissionTemplateName SonarCloud permissionTemplateName .INPUTS System.String. .OUTPUTS System.Management.Automation.PSObject .EXAMPLE Get-SonarCloudPermissionTemplate -organization 'organization1' .EXAMPLE Get-SonarCloudPermissionTemplate -organization 'organization1' -permissionTemplateName 'PermissionTemplate A' #> [CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')] Param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$organization, [parameter(Mandatory=$false,ParameterSetName="ByName")] [ValidateNotNullOrEmpty()] [String[]]$permissionTemplateName ) begin { # --- Check for the presence of $Script:SonarCloudConnection xCheckScriptSonarCloudConnection $apiUrl = '/permissions/search_templates' function CalculateOutput([PSCustomObject]$permissionTemplate){ [PSCustomObject] @{ Name = $permissionTemplate.name Id = $permissionTemplate.id Description = $permissionTemplate.description ProjectKeyPattern = $permissionTemplate.projectKeyPattern CreatedAt = $permissionTemplate.createdAt UpdatedAt = $permissionTemplate.updatedAt Permissions = $permissionTemplate.permissions } } } process { try { switch ($PsCmdlet.ParameterSetName) { # --- Get PermissionTemplate by name 'ByName' { foreach ($name in $permissionTemplateName){ $queryParameters = @{ organization = $organization q = $name } $response = Invoke-SonarCloudRestMethod -Method GET -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference foreach ($permissionTemplate in $response.permissionTemplates){ CalculateOutput $permissionTemplate } } break } # --- No parameters passed so return all PermissionTemplates 'Standard' { $queryParameters = @{ organization = $organization } $Response = Invoke-SonarCloudRestMethod -Method GET -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference foreach ($permissionTemplate in $response.permissionTemplates){ CalculateOutput $permissionTemplate } } } } catch [Exception] { throw } } } <# - Function: Initialize-SonarCloudPermissionTemplate #> function Initialize-SonarCloudPermissionTemplate { <# .SYNOPSIS Apply a SonarCloud Permission Template .DESCRIPTION Apply a SonarCloud Permission Template .PARAMETER organization SonarCloud Organization .PARAMETER projectKey Project Key, e.g. GitLab repo id .PARAMETER permissionTemplateName Name of Permission Template to apply .INPUTS System.String. .OUTPUTS None .EXAMPLE Initialize-SonarCloudPermissionTemplate -organization 'organization1' -projectKey '32959331' -permissionTemplateName 'PermissionTemplate A' #> [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High")] Param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$organization, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$projectKey, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$permissionTemplateName ) begin { # --- Check for the presence of $Script:SonarCloudConnection xCheckScriptSonarCloudConnection $apiUrl = '/permissions/apply_template' } process { try { $queryParameters = @{ organization = $organization projectKey = $projectKey templateName = $permissionTemplateName } if ($PSCmdlet.ShouldProcess($projectKey)){ Invoke-SonarCloudRestMethod -Method POST -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference } } catch [Exception] { throw } } } <# - Function: Get-SonarCloudProject #> function Get-SonarCloudProject { <# .SYNOPSIS Get SonarCloud Projects .DESCRIPTION Get SonarCloud Projects .PARAMETER organization SonarCloud Organization .PARAMETER projectName SonarCloud Project Name .PARAMETER pageSize Specify how many records to return .INPUTS System.String. System.Int .OUTPUTS System.Management.Automation.PSObject .EXAMPLE Get-SonarCloudProject -organization 'organization1' .EXAMPLE Get-SonarCloudProject -organization 'organization1' -projectName 'Project A' #> [CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')] Param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$organization, [parameter(Mandatory=$false,ParameterSetName="ByName")] [ValidateNotNullOrEmpty()] [String[]]$projectName, [parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [Int]$pageSize = 100 ) begin { # --- Check for the presence of $Script:SonarCloudConnection xCheckScriptSonarCloudConnection $apiUrl = '/projects/search' function CalculateOutput([PSCustomObject]$project){ [PSCustomObject] @{ Name = $project.name Key = $project.Key Organization = $project.organization Qualifier = $project.qualifier Visibility = $project.visibility } } } process { try { switch ($PsCmdlet.ParameterSetName) { # --- Get Project by name 'ByName' { foreach ($name in $projectName){ $queryParameters = @{ organization = $organization q = $name ps = $pageSize } $response = Invoke-SonarCloudRestMethod -Method GET -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference foreach ($project in $response.components){ CalculateOutput $project } } break } # --- No parameters passed so return all Projects 'Standard' { $queryParameters = @{ organization = $organization ps = $pageSize } $Response = Invoke-SonarCloudRestMethod -Method GET -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference foreach ($project in $response.components){ CalculateOutput $project } } } } catch [Exception] { throw } } } <# - Function: New-SonarCloudProject #> function New-SonarCloudProject { <# .SYNOPSIS Create a SonarCloud Project .DESCRIPTION Create a SonarCloud Project .PARAMETER organization SonarCloud Organization .PARAMETER projectName SonarCloud Project Name .PARAMETER projectKey Project Key, e.g. GitLab repo id .PARAMETER visibility Whether the created project should be visible to everyone, or only specific user/groups .INPUTS System.String. .OUTPUTS System.Management.Automation.PSObject .EXAMPLE New-SonarCloudProject -organization 'organization1' -projectName 'Project A' -projectKey '32959331' #> [CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low")][OutputType('System.Management.Automation.PSObject')] Param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$organization, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$projectName, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$projectKey, [parameter(Mandatory=$false)] [ValidateSet('private', 'public', IgnoreCase=$false)] [String]$visibility = 'private' ) begin { # --- Check for the presence of $Script:SonarCloudConnection xCheckScriptSonarCloudConnection $apiUrl = '/projects/create' function CalculateOutput([PSCustomObject]$project){ [PSCustomObject] @{ Name = $project.name Key = $project.Key Qualifier = $project.qualifier Visibility = $project.visibility } } } process { try { $queryParameters = @{ organization = $organization name = $projectName project = $projectKey visibility = $visibility } if ($PSCmdlet.ShouldProcess($projectName)){ $response = Invoke-SonarCloudRestMethod -Method POST -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference CalculateOutput $response.project } } catch [Exception] { throw } } } <# - Function: Add-SonarCloudUserGroupMember #> function Add-SonarCloudUserGroupMember { <# .SYNOPSIS Add a SonarCloud User to a Group .DESCRIPTION Add a SonarCloud User to a Group .PARAMETER organization SonarCloud Organization .PARAMETER groupName SonarCloud Group Name .PARAMETER userLogin SonarCloud User Login, e.g. testuser1@gitlab .INPUTS System.String. .OUTPUTS None .EXAMPLE Add-SonarCloudUserGroupMember -organization 'organization1' -groupName 'Group A' -userLogin 'testuser1@gitlab','testuser2@gitlab' #> [CmdletBinding(SupportsShouldProcess,ConfirmImpact="Low")] Param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$organization, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$groupName, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String[]]$userLogin ) begin { # --- Check for the presence of $Script:SonarCloudConnection xCheckScriptSonarCloudConnection $apiUrl = '/user_groups/add_user' } process { try { foreach ($user in $userLogin){ $queryParameters = @{ organization = $organization name = $groupName login = $user } if ($PSCmdlet.ShouldProcess($groupName)){ Invoke-SonarCloudRestMethod -Method POST -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference } } } catch [Exception] { throw } } } <# - Function: Get-SonarCloudUserGroup #> function Get-SonarCloudUserGroup { <# .SYNOPSIS Get SonarCloud UserGroups .DESCRIPTION Get SonarCloud UserGroups .PARAMETER organization SonarCloud Organization .PARAMETER groupName SonarCloud Group Name .PARAMETER pageSize Specify how many records to return .INPUTS System.String. System.Int .OUTPUTS System.Management.Automation.PSObject .EXAMPLE Get-SonarCloudUserGroup -organization 'organization1' .EXAMPLE Get-SonarCloudUserGroup -organization 'organization1' -groupName 'UserGroup A' #> [CmdletBinding(DefaultParameterSetName="Standard")][OutputType('System.Management.Automation.PSObject')] Param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$organization, [parameter(Mandatory=$false,ParameterSetName="ByName")] [ValidateNotNullOrEmpty()] [String[]]$groupName, [parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [Int]$pageSize = 100 ) begin { # --- Check for the presence of $Script:SonarCloudConnection xCheckScriptSonarCloudConnection $apiUrl = '/user_groups/search' function CalculateOutput([PSCustomObject]$userGroup){ [PSCustomObject] @{ Name = $userGroup.name Id = $userGroup.id Description = $userGroup.description MembersCount = $userGroup.membersCount Default = $userGroup.default } } } process { try { switch ($PsCmdlet.ParameterSetName) { # --- Get UserGroup by name 'ByName' { foreach ($name in $groupName){ $queryParameters = @{ organization = $organization q = $name ps = $pageSize } $response = Invoke-SonarCloudRestMethod -Method GET -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference foreach ($userGroup in $response.groups){ CalculateOutput $userGroup } } break } # --- No parameters passed so return all UserGroups 'Standard' { $queryParameters = @{ organization = $organization ps = $pageSize } $Response = Invoke-SonarCloudRestMethod -Method GET -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference foreach ($userGroup in $response.groups){ CalculateOutput $userGroup } } } } catch [Exception] { throw } } } <# - Function: Remove-SonarCloudUserGroupMember #> function Remove-SonarCloudUserGroupMember { <# .SYNOPSIS Remove a SonarCloud User from a Group .DESCRIPTION Remove a SonarCloud User from a Group .PARAMETER organization SonarCloud Organization .PARAMETER groupName SonarCloud Group Name .PARAMETER userLogin SonarCloud User Login, e.g. testuser1@gitlab .INPUTS System.String. .OUTPUTS None .EXAMPLE Remove-SonarCloudUserGroupMember -organization 'organization1' -groupName 'Group A' -userLogin 'testuser1@gitlab','testuser2@gitlab' #> [CmdletBinding(SupportsShouldProcess,ConfirmImpact="High")] Param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$organization, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$groupName, [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String[]]$userLogin ) begin { # --- Check for the presence of $Script:SonarCloudConnection xCheckScriptSonarCloudConnection $apiUrl = '/user_groups/remove_user' } process { try { foreach ($user in $userLogin){ $queryParameters = @{ organization = $organization name = $groupName login = $user } if ($PSCmdlet.ShouldProcess($groupName)){ Invoke-SonarCloudRestMethod -Method POST -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference } } } catch [Exception] { throw } } } <# - Function: Get-SonarCloudUser #> function Get-SonarCloudUser { <# .SYNOPSIS Get SonarCloud Users .DESCRIPTION Get SonarCloud Users .PARAMETER userName SonarCloud User Name - filter on login, name or email .PARAMETER pageSize Specify how many records to return .INPUTS System.String. System.Int .OUTPUTS System.Management.Automation.PSObject .EXAMPLE Get-SonarCloudUser -userName 'User A','User B' #> [CmdletBinding()][OutputType('System.Management.Automation.PSObject')] Param ( [parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String[]]$userName, [parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [Int]$pageSize = 100 ) begin { # --- Check for the presence of $Script:SonarCloudConnection xCheckScriptSonarCloudConnection $apiUrl = '/users/search' function CalculateOutput([PSCustomObject]$user){ [PSCustomObject] @{ Name = $user.name Login = $user.login Email = $user.email Active = $user.active Groups = $user.groups TokensCount = $user.tokensCount Local = $user.local ExternalIdentity = $user.externalIdentity ExternalProvider = $user.externalProvider LastConnectionDate = $user.lastConnectionDate } } } process { try { foreach ($name in $userName){ $queryParameters = @{ q = $name ps = $pageSize } $response = Invoke-SonarCloudRestMethod -Method GET -URI $apiUrl -queryParameters $queryParameters -Verbose:$VerbosePreference foreach ($user in $response.users){ CalculateOutput $user } } } catch [Exception] { throw } } } |