diff --git a/Check-AppRoles.ps1 b/Check-AppRoles.ps1 new file mode 100644 index 0000000..025f130 --- /dev/null +++ b/Check-AppRoles.ps1 @@ -0,0 +1,117 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory=$true)] + [string]$InputFile +) + +# Ensure you're logged into Azure CLI +try { + $null = az account show +} +catch { + Write-Host "Please log in to Azure CLI first using 'az login'" + exit +} + +# Function to get all role definitions +function Get-AllRoleDefinitions { + $roles = az role definition list | + ConvertFrom-Json | + ForEach-Object { $_ } | +# Where-Object { $_.roleName -eq "Website Contributor" } + Where-Object { $_.roleType -ne "CustomRole" -and $_.roleName -ne "Contributor" -and $_.roleName -ne "Owner" } + return $roles +} + +# Function to check if a string matches a resource type pattern +function Test-ResourceTypeMatch { + param ( + [string]$Pattern, + [string]$ResourceType + ) + $patternParts = $Pattern -split '/' + $resourceTypeParts = $ResourceType -split '/' + + for ($i = 0; $i -lt $patternParts.Count; $i++) { + if ($i -ge $resourceTypeParts.Count -and $patternParts[$i] -ne "*") { + return $false + } + + if ($patternParts[$i] -eq '*') { + if ($i -eq $patternParts.Count - 1) { + return $true + } + continue + } + + if ($patternParts[$i] -ne $resourceTypeParts[$i]) { + return $false + } + } + + # If the pattern is shorter than the resource type, it's only a match if the last part was a wildcard + return ($patternParts.Count -eq $resourceTypeParts.Count) -or ($patternParts[-1] -eq '*') +} + +# Function to check if a role grants access to a resource type +function Test-RoleAccess { + param ( + $Role, + $ResourceType + ) + $hasAccess = $false + foreach ($permission in $Role.permissions) { + # Check actions and dataActions + foreach ($action in ($permission.actions + $permission.dataActions)) { + if (Test-ResourceTypeMatch -Pattern $action -ResourceType $ResourceType) { + $hasAccess = $true + break + } + } + + # Check notActions and notDataActions + foreach ($notAction in ($permission.notActions + $permission.notDataActions)) { + if (Test-ResourceTypeMatch -Pattern $notAction -ResourceType $ResourceType) { + return $false # Explicitly not allowed + } + } + + if ($hasAccess) { + break + } + } + return $hasAccess +} + +# Get all role definitions +$allRoles = Get-AllRoleDefinitions + +# Read the file with resource types +try { + $resourceTypes = Get-Content -Path $InputFile -ErrorAction Stop + $resourceTypes = $resourceTypes | Sort-Object +} +catch { + Write-Host "Error reading input file: $_" + exit +} + +# Process each resource type +foreach ($resourceType in $resourceTypes) { + Write-Host "Resource Type: $resourceType" + $matchingRoles = @() + + foreach ($role in $allRoles) { + if (Test-RoleAccess -Role $role -ResourceType $resourceType) { + $matchingRoles += $role.roleName + } + } + + if ($matchingRoles.Count -gt 0) { + Write-Host "Roles granting access:" + $matchingRoles | ForEach-Object { Write-Host " - $_" } + } else { + Write-Host "No roles found granting access to this resource type." + } + Write-Host "" +} \ No newline at end of file diff --git a/Get-AzureRoles.ps1 b/Get-AzureRoles.ps1 new file mode 100644 index 0000000..05cbd7c --- /dev/null +++ b/Get-AzureRoles.ps1 @@ -0,0 +1,30 @@ +# NOTE: +# Make sure you are logged into the az cli before running this +# Command: az login + +# Get the JSON data from Azure CLI +$jsonData = az role definition list | ConvertFrom-Json + +# Create an empty array to store the formatted strings +$formattedRoles = @() + +foreach ($role in $jsonData) { + $roleType = if ($role.roleType -eq "BuiltInRole") { "Built-in role" } else { "Custom role" } + + $formattedRole = @" + +$roleType $($role.roleName) +Description $($role.description) +ID $($role.name) +"@ + + $formattedRoles += $formattedRole +} + +# Join all formatted roles into a single string +$output = $formattedRoles -join "`n" + +# Write the output to a text file +$output | Out-File -FilePath "azure_roles.txt" -Encoding UTF8 + +Write-Host "Azure roles have been written to azure_roles.txt" \ No newline at end of file diff --git a/Hello.ps1 b/Hello.ps1 new file mode 100644 index 0000000..eff826d --- /dev/null +++ b/Hello.ps1 @@ -0,0 +1 @@ +Write-Host "Hello World!" -ForegroundColor Blue \ No newline at end of file diff --git a/clean_csv.ps1 b/clean_csv.ps1 new file mode 100644 index 0000000..a25003d --- /dev/null +++ b/clean_csv.ps1 @@ -0,0 +1,14 @@ +# Parameters +$inputFilePath = "./QueryResult.csv" +$outputFilePath = "./CleanResults.csv" + +# Read the content of the file +$content = Get-Content -Path $inputFilePath -Raw + +# Remove all double quotes +$contentWithoutQuotes = $content -replace '"', '' + +# Write the modified content to a new file +$contentWithoutQuotes | Set-Content -Path $outputFilePath -NoNewline + +Write-Output "Quotes removed. New file saved as: $outputFilePath" \ No newline at end of file diff --git a/parse_logs.ps1 b/parse_logs.ps1 new file mode 100644 index 0000000..194d6ec --- /dev/null +++ b/parse_logs.ps1 @@ -0,0 +1,95 @@ +param( + [string]$CsvPath = "path_to_your_csv_file.csv", + [int]$RowLimit = -1, # -1 means process all rows + [string]$ApplicationName = "" +) + +# Function to import CSV data with optional row limit +function Import-LimitedCsv { + param( + [string]$Path, + [int]$Limit = -1 + ) + + $csv = Import-Csv -Path $Path + if ($Limit -gt 0) { + return $csv | Select-Object -First $Limit + } + return $csv +} + +function Write-OutputBoth { + param( + [string]$Message, + [System.IO.StreamWriter]$Writer + ) + Write-Host $Message + $Writer.WriteLine($Message) +} + +$outputFileName = if ($ApplicationName) { + "$($ApplicationName.Replace(' ', '_').ToLower())_results.txt" +} else { + "all_applications_results.txt" +} + +$outputDir = "output" +if (-not (Test-Path -Path $outputDir)) { + New-Item -ItemType Directory -Force -Path $outputDir +} + +$outputFilePath = Join-Path $outputDir $outputFileName + +# Import the CSV file with optional row limit +$csvData = Import-LimitedCsv -Path $CsvPath -Limit $RowLimit + +# Define operations to ignore +$ignoredOperations = @("Resume Databases", "UpdateWebSite") + +# Filter out items with "Started" status and group by "Event initiated by" +$groupedData = $csvData | + Where-Object { $_."Status" -ne "Started" -and $_."Operation name" -notin $ignoredOperations } | + Group-Object -Property "Event initiated by" + +if ($ApplicationName) { + $groupedData = $groupedData | Where-Object { $_.Name -eq $ApplicationName } +} + +$writer = [System.IO.StreamWriter]::new("$OutputFilePath.raw") + +try { + # Process each group + foreach ($group in $groupedData) { + Write-Host "Application: $($group.Name)" + Write-Host "------------------------" + + $resourceTypes = $group.Group | + Select-Object "Resource type", "Operation name" -Unique | + Group-Object -Property "Resource type" + + foreach ($resourceType in $resourceTypes) { + Write-OutputBoth "$($resourceType.Name)" $writer + } + Write-Host "" + } + + $totalRows = $csvData.Count + $processedRows = ($csvData | Where-Object { $_."Status" -ne "Started" -and $_."Operation name" -notin $ignoredOperations}).Count + if ($ApplicationName) { + $processedRows = ($groupedData | Where-Object { $_.Name -eq $ApplicationName }).Group.Count + } + $skippedRows = $totalRows - $processedRows + + Write-Host "Total rows in CSV: $totalRows" + Write-Host "Rows processed: $processedRows" + Write-Host "Rows skipped (Started status, ignored operations, or non-matching application): $skippedRows" + Write-Host "Ignored operations: $($ignoredOperations -join ', ')" + if ($ApplicationName) { + Write-Host "Filtered by application: $ApplicationName" + } + Write-Host "" + Write-Host "Results have been saved to: $outputFileName" +} +finally { + $writer.Close() +} \ No newline at end of file diff --git a/permissions_analysis_results.txt b/permissions_analysis_results.txt new file mode 100644 index 0000000..9368900 Binary files /dev/null and b/permissions_analysis_results.txt differ diff --git a/required_roles.txt b/required_roles.txt new file mode 100644 index 0000000..c0dcc72 --- /dev/null +++ b/required_roles.txt @@ -0,0 +1,14 @@ +Minimal set of Azure roles required: +----------------------------------- +Role Name: Disk Encryption Set Operator for Managed Disks +Description: Provides permissions to read, write or delete disk encryption sets which are used for encrypting managed disks with customer managed keys +ID: 136d308c-0937-4a49-9bd7-edfb42adbffc + +Role Name: Managed Identity Contributor +Description: Create, Read, Update, and Delete User Assigned Identity +ID: e40ec5ca-96e0-45a2-b4ff-59039f2c2b59 + +Role Name: Desktop Virtualization Power On Contributor +Description: Provide permission to the Azure Virtual Desktop Resource Provider to start virtual machines. +ID: 489581de-a3bd-480d-9518-53dea7416b33 +