Skip to content

Commit

Permalink
Hydration kit updates (#826)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Watherston <[email protected]>
  • Loading branch information
anwather and Anthony Watherston authored Nov 20, 2024
1 parent 11aa107 commit 9b5162c
Show file tree
Hide file tree
Showing 52 changed files with 6,046 additions and 4,434 deletions.
19 changes: 4 additions & 15 deletions Module/EnterprisePolicyAsCode/EnterprisePolicyAsCode.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,6 @@

# Aliases to export from this module
AliasesToExport = ''

# RequiredModules = @(
# @{
# ModuleName = 'Az.Accounts'
# ModuleVersion = '2.19.0'
# },
# @{
# ModuleName = 'Az.ResourceGraph'
# ModuleVersion = '0.13.0'
# }
# )

# List of all files packaged with this module
FileList = @()
Expand All @@ -59,16 +48,16 @@
# Tags = @()

# A URL to the license for this module.
LicenseUri = 'https://github.com/Azure/enterprise-azure-policy-as-code/blob/main/LICENSE'
LicenseUri = 'https://github.com/Azure/enterprise-azure-policy-as-code/blob/main/LICENSE'

# A URL to the main website for this project.
ProjectUri = 'https://github.com/Azure/enterprise-azure-policy-as-code'
ProjectUri = 'https://github.com/Azure/enterprise-azure-policy-as-code'

# A URL to an icon representing this module.
# IconUri = ''
IconUri = 'https://raw.githubusercontent.com/Azure/enterprise-azure-policy-as-code/refs/heads/main/Docs/Images/10316-icon-service-Policy.svg'

# ReleaseNotes of this module
# ReleaseNotes = 'https://github.com/Azure/enterprise-azure-policy-as-code/releases'
ReleaseNotes = 'https://github.com/Azure/enterprise-azure-policy-as-code/releases'

} # End of PSData hashtable

Expand Down
18 changes: 11 additions & 7 deletions Module/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,21 @@ $functionNames | Foreach-Object {

# Hydration Kit

$functionNames = (Get-ChildItem .\Scripts\HydrationKit\* -File -Include *.ps1).BaseName
Get-ChildItem -Path .\Scripts\HydrationKit\*.ps1 -Recurse -File | Copy-Item -Destination .\Module\EnterprisePolicyAsCode\functions

# $functionNames = (Get-ChildItem .\Scripts\HydrationKit\* -File -Include *.ps1).BaseName

# $functionNames | Foreach-Object {
# "function $_ {" | Set-Content ".\Module\EnterprisePolicyAsCode\functions\$_.ps1" -Force
# Get-Content .\Scripts\HydrationKit\$_.ps1 | Where-Object { $_ -notmatch "^#Requires" } | Add-Content ".\Module\EnterprisePolicyAsCode\functions\$_.ps1" -Force
# "}" | Add-Content ".\Module\EnterprisePolicyAsCode\functions\$_.ps1" -Force
# }


$functionNames | Foreach-Object {
"function $_ {" | Set-Content ".\Module\EnterprisePolicyAsCode\functions\$_.ps1" -Force
Get-Content .\Scripts\HydrationKit\$_.ps1 | Where-Object { $_ -notmatch "^#Requires" } | Add-Content ".\Module\EnterprisePolicyAsCode\functions\$_.ps1" -Force
"}" | Add-Content ".\Module\EnterprisePolicyAsCode\functions\$_.ps1" -Force
}

Copy-Item -Path .\Scripts\CloudAdoptionFramework\policyAssignments -Destination .\Module\EnterprisePolicyAsCode -Force -Recurse

(Get-Content -Path .\Module\EnterprisePolicyAsCode\EnterprisePolicyAsCode.psd1) -replace "FunctionsToExport = ''", "FunctionsToExport = @($((gci -Path .\Module\EnterprisePolicyAsCode\functions | Select-Object -ExpandProperty BaseName) | Join-String -Separator "," -DoubleQuote))" | Set-Content .\Module\EnterprisePolicyAsCode\EnterprisePolicyAsCode.psd1
(Get-Content -Path .\Module\EnterprisePolicyAsCode\EnterprisePolicyAsCode.psd1) -replace "FunctionsToExport = ''", "FunctionsToExport = @($((Get-ChildItem -Path .\Module\EnterprisePolicyAsCode\functions | Select-Object -ExpandProperty BaseName) | Join-String -Separator "," -DoubleQuote))" | Set-Content .\Module\EnterprisePolicyAsCode\EnterprisePolicyAsCode.psd1

$tag_name = $env:TAG_NAME -replace "v", ""

Expand Down
596 changes: 596 additions & 0 deletions Scripts/Helpers/Build-HydrationAssignmentPlan.ps1

Large diffs are not rendered by default.

393 changes: 393 additions & 0 deletions Scripts/Helpers/Build-HydrationPolicyPlan.ps1

Large diffs are not rendered by default.

449 changes: 449 additions & 0 deletions Scripts/Helpers/Build-HydrationPolicySetPlan.ps1

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions Scripts/Helpers/Convert-HashtableToFlatPsObject.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
function Convert-HashtableToFlatPsObject {
param (
[Parameter(Mandatory = $true)]
$Hashtable
)
$newObject = @()
Remove-Variable valueObject -ErrorAction SilentlyContinue
foreach ($hash in $Hashtable) {
$valueObject = New-Object PSObject
foreach ($hKey in $Hash.Keys) {
if (!($Hash.$hKey -is [string] -or $Hash.$hKey -is [int] -or $Hash.$hKey -is [double] -or $Hash.$hKey -is [decimal] -or $Hash.$hKey -is [datetime] -or $Hash.$hKey -is [char] -or $Hash.$hKey -is [bool])) {
if (!($valueObject)) {
$valueObject = New-Object PSObject -Property @{$hkey = $(ConvertTo-Json -InputObject $Hash.$hKey -depth 100 -Compress) }
}
else {
Add-Member -InputObject $valueObject -MemberType NoteProperty -Name $hKey -Value $(ConvertTo-Json -InputObject $Hash.$hKey -depth 100 -Compress)
}

}
else {
if (!($valueObject)) {
$valueObject = New-Object PSObject -Property @{$hkey = $hash.$hkey }
}
else {
Add-Member -InputObject $valueObject -MemberType NoteProperty -Name $hKey -Value $Hash.$hKey
}
}
$newObject += $valueObject
Remove-Variable hKey -ErrorAction SilentlyContinue
}
Remove-Variable hash -ErrorAction SilentlyContinue
Remove-Variable valueObject -ErrorAction SilentlyContinue
}
return $newObject
}
45 changes: 45 additions & 0 deletions Scripts/Helpers/Get-HydrationUserObjectId.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
function Get-HydrationUserObjectId {
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[string]
$Output = "./Output"
)
# TODO: Logging
$debugLogContents = & { Connect-AzAccount -Force -Debug -TenantId $(Get-AzContext).Tenant.Id -SubscriptionId $(Get-AzContext).Subscription.Id -AccountId $(Get-AzContext).Account.Id -Confirm:$False } *>&1
$accountId = ""
$jsonObject = ""
foreach ($line in $debugLogContents) {
if ($line -match ".*wam_telemetry.*") {
if ($debug) {
#TODO: Logging which line is being evaluated
}
if ($matches[0] -match "Value: (.*)") {
if ($debug) {
#TODO: Logging which match is being evaluated
}
#TODO: If null then throw/log error
$jsonObject = ($matches[1] | convertfrom-json -depth 100)
#TODO: If null then throw/log error
$accountId = $jsonObject.account_id
#TODO: If null then throw/log error
if ($debug) {
#TODO: Logging compressed json object
}
break
}
}
#TODO: If null then throw/log error
}
if (-not [string]::IsNullOrEmpty($accountId)) {
#TODO: Logging success value
#TODO: Logging success status
return $accountId
}
else {
if ($debug -and (-not [string]::IsNullOrEmpty($jsonObject))) {
#TODO Add error information that json object was empty
}
throw "Failed to retrieve the account id from the Connect-AzAccount debug log.`nConfirm active connection, and if this is confirmed then run with the -debug flag for additional logging information."
}
}
109 changes: 109 additions & 0 deletions Scripts/Helpers/New-HydrationAnswerSet.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
function New-HydrationAnswerSet {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]
$LoopId,
[Parameter(Mandatory = $true)]
[string]
$QuestionsFilePath,
[Parameter(Mandatory = $true)]
[string]
$LogFilePath,
[Parameter(Mandatory = $false)]
[array]
$Notes, # This allows dynamic data to be passed for display in the loop to guide the user in their responses.
[Parameter(Mandatory = $false)]
[Int32]
$TerminalWidth = 80,
[Parameter(Mandatory = $false)]
[switch]
$UseUtc
)
if (!(Test-Path $QuestionsFilePath)) {
Write-Error "Questions file not found at $QuestionsFilePath"
return "Failed, Questions file not found at $QuestionsFilePath...."
}
else {
$fullQuestionsList = Get-Content $QuestionsFilePath | ConvertFrom-Json -Depth 10 -AsHashtable
$questionsList = @{}
foreach ($questionKey in $fullQuestionsList.Keys) {
if ($fullQuestionsList.$questionKey.loopId -eq $LoopId) {
$questionsList.Add($questionKey, $fullQuestionsList.$questionKey)
}
}
}
$responseList = [ordered]@{}
foreach ($question1 in $questionsList.Keys) {
$responseList.Add($questionsList.$question1.outputVariableName, "Skipped")
}
$responseIncrement = 1
$responseMax = $responseList.Keys.Count
foreach ($questionIncrement in $responseIncrement..$responseMax) {
# Outer loop to set order of questions
foreach ($question in $questionsList.Keys) {
# Clear-Host
if ($questionIncrement -eq $questionsList.$question.questionIncrement) {
$questionData = $questionsList.$question
$blockData = @{
DisplayText = $questionData.displayText
Location = "Middle"
TextRowCharacterColor = "Blue"
RowCharacterColor = "Yellow"
LargeRowCharacter = "-"
SmallRowCharacter = "-"
TerminalWidth = $TerminalWidth
}
# Display the question as a UI
New-HydrationSeparatorBlock @BlockData
Write-Host "$($questionData.bodyHeader)`n" -ForegroundColor Yellow
Write-Host " $($questionData.bodyText)"
if ($Notes) {
Write-Host "Notes:" -ForegroundColor Yellow
foreach ($note in $Notes) {
Write-Host " - $note" -ForegroundColor Yellow
}
}
if ($questionData.links) {
Write-Host "`nLinks:" -ForegroundColor Yellow
foreach ($link in $questionData.links) {
Write-Host " - $link"
}
if (!($questionData.inputType -eq "optionList")) {
# Evens out the presentation formatting for the blank line left in the optionList section due to format of .Net output
Write-Host "`n"
}
}
# Get the response
do {
if ($questionData.inputType -eq "optionList") {
$questionResponse = New-HydrationMenuResponse -OptionHashtable $questionData.menuOptions -DataRequest $questionData.dataRequest
}
else {
$questionResponse = Read-Host $questionData.dataRequest
}
}until(($questionResponse -or $questionData.allowNull) -or $responseIncrement -eq 5)

if ($questionResponse) {
$responseList.$($questionData.outputVariableName) = $questionResponse
}
elseif ($questionData.allowNull) {
$responseList.$($questionData.outputVariableName) = ""
}
else {
Write-Error "Responses are required for all questions. Exiting script."
return "Failed, please respond to all questions...."
}
$responseIncrement++
}
}
}

return $responseList
}

# $lid = "optionalCreatePrimaryIntermediateRoot"
# $qfp = ".\StarterKit\HydrationKit\questions.jsonc"
# $lfp = ".\Output\Logs\Install-HydrationEpac.log"
# $n = @("Temporary nonsense")
# New-HydrationAnswerSet -LoopId $lid -QuestionsFilePath $qfp -LogFilePath $lfp -Notes $n
25 changes: 25 additions & 0 deletions Scripts/Helpers/New-HydrationContinuePrompt.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
function New-HydrationContinuePrompt {
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[switch]
$Interactive,
[Parameter(Mandatory = $false)]
[int]
$SleepTime = 10
)
Write-Host "`n"
if ($Interactive) {
$message = "Press any key to continue..."
Write-Host $message -ForegroundColor Yellow
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Remove-Variable x
Remove-Variable message
}`
else {
$message = "Continuing in $($Sleeptime.ToString()) seconds..."
Write-Host $message -ForegroundColor Yellow
Start-Sleep -Seconds $SleepTime
}
Write-Host "`n`n"
}
21 changes: 21 additions & 0 deletions Scripts/Helpers/New-HydrationMenuResponse.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
function New-HydrationMenuResponse {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[System.Management.Automation.OrderedHashtable]
$OptionHashtable,
[Parameter(Mandatory = $false)]
[string]
$DataRequest = "Please select an option from the list below:"
)

$choices = @()
foreach ($key in $OptionHashtable.Keys) {
$choices += [System.Management.Automation.Host.ChoiceDescription]::new($( -join ("&", $key)), $OptionHashtable.$key)
}

$caption = ""
$message = "`n$DataRequest"
$result = $host.ui.PromptForChoice($caption, $message, $choices, 0)
return ($choices[$result].Label | Select-String -Pattern "^&(.+)" -AllMatches).Matches[0].Groups[1].Value
}
72 changes: 72 additions & 0 deletions Scripts/Helpers/New-HydrationMultipleChoicePrompt.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
function New-HydrationMultipleChoicePrompt {
[CmdletBinding()]
param (
[Parameter()]
[System.Management.Automation.OrderedHashtable]
$List # = [ordered]@{}
)
# TODO: Move to file, test block
# $List = [ordered]@{
# "Option1" = @{
# title = "First Title"
# returnData = "returnValue1"
# description = "This is the first option"
# }
# "Option2" = @{
# title = "Second Title"
# returnData = "returnValue2"
# description = "This is the second option"
# }
# "Option3" = @{
# title = "Third Title"
# returnData = "returnValue3"
# description = "This is the third option"
# }
# }
$scriptReturn = $null
# Build the question prompt
$choiceList = [ordered]@{}
$keyString = ""
foreach ($item in $List.keys) {
# Write-Host $item
# $List.$item.title
New-Variable -Name $item -Value $(New-Object System.Management.Automation.Host.ChoiceDescription `
"`&$($List.$item.title)",
"$($List.$item.description)")
$choiceList.add($item, $(Get-Variable $item -ValueOnly))
if ($keyString -eq "") {
$keyString = "`$$item"
}
else {
$keyString = -join ($keyString, ", `$", $item)
}
Write-Host "TODO: DEBUG:"
# $questionPrompt = $questionPrompt + "`n$($item.Key): $($item.Value.description)"
}
$multipleChoiceOptions = [System.Management.Automation.Host.ChoiceDescription[]]($choiceList.values)
$multipleChoiceMessage = "The current user does not have the necessary rights to create or read Management Groups. This will prevent much of the guidance provided as part of this deployment tool, as well as leave management group creation to manual operations. For these reasons, continuing is not recommended."
$multipleChoiceTitle = "Consider whether or not you wish to proceed (not recommended)..."

# Ask the question
$scriptResponse = $host.ui.PromptForChoice($multipleChoiceTitle, $multipleChoiceMessage, $multipleChoiceOptions, 0)

# Dynamically build the switch cases based on the number of items in $List so that we can evaluate the choice made
$index = 0
$switchCases = $List.GetEnumerator() | ForEach-Object {
"`"$index`" { `$scriptReturn = `"$($_.Value.returnData)`" }"
$index++
}
# Removing this as it won't be useful anywhwere else, and we don't want anyone to think otherwise.
Remove-Variable index
# Combine the switch cases into a single script block
# $scriptBlock = [scriptblock]::Create("switch -Regex (`"^" + (1..$foo.Count -join "|") + "`$") { $($switchCases -join "`n") default { `$scriptReturn = 'Not found' } }")
# Corrected what appeared to be a typo, if this errors, go ahead and set it back
Write-Host "TODO: Do a log entry."
$scriptBlock = [scriptblock]::Create("switch (`$scriptResponse) { $($switchCases -join "`n") default { `$scriptReturn = 'Error: Not found' } }")
# Execute the script block to evaluate the response
. $scriptBlock
# Return the result
# TODO: Change line below to log entry
Write-Host "$scriptReturn"
return $scriptReturn
}
Loading

0 comments on commit 9b5162c

Please sign in to comment.