Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @goodtocode
26 changes: 26 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copilot instructions: cloud-admin

This repo is a PowerShell and Markdown knowledge base for Azure cloud administration, engineering, and architecture (scripts, how-to docs, command references, T-SQL DBA scripts).

## PowerShell scripts
- Target PowerShell 7+ on Windows; use Windows paths in docs, forward slashes in `Import-Module` relative paths.
- Start each script with the existing header comment: synopsis line, parameter list, and an `Example:` line.
- Use `param()` with typed parameters; `$ErrorActionPreference = 'Stop'` for new scripts.
- Anything that creates, changes, or deletes resources must use `[CmdletBinding(SupportsShouldProcess)]` and honor `-WhatIf`.
- Prefer `az` CLI or `Az.*` modules. Do not depend on `az` extensions. Check `$LASTEXITCODE` after `az` calls and keep stderr out of parsed JSON.
- Always wrap `ConvertFrom-Json` results that may be single items in `@()` before indexing or counting.
- Shared helpers: import from `scripts/System.psm1` and `scripts/Azure.psm1` only (never copy the module into subfolders). Compute the relative path from the script's own folder.
- Install modules only when missing (`Get-Module -ListAvailable`), not on every run.
- Make bulk operations resilient: skip and report items that fail or are missing, then print a summary.

## Git workflow
- Do not run `git commit`, `git push`, or create pull requests. Leave changes uncommitted in the working tree so the repo owner can review them, then commit, push, and open the PR themselves.

## Security
- Never commit secrets, keys, tokens, real tenant/subscription/object IDs, or customer data. Use `00000000-0000-0000-0000-000000000000` placeholders.
- Default to least privilege in examples; call out destructive commands clearly.

## Documentation (docs/)
- Markdown how-tos use the naming pattern `How-to <Topic>.md` and `Commands - <Area>.md`.
- Show runnable commands in fenced `powershell`/`bash` blocks; state prerequisites and required permissions.
- Update `README.md` when adding a notable script or doc.
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
assignees:
- "goodtocode"
reviewers:
- "goodtocode"
8 changes: 8 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## Summary


## Checklist
- [ ] Script header/example updated; state-changing scripts support `-WhatIf`
- [ ] Tested against a non-production subscription/environment
- [ ] No secrets, real tenant/subscription/object IDs, or customer data
- [ ] README/docs updated if needed
32 changes: 32 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Validate

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
powershell:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Parse all PowerShell files
shell: pwsh
run: |
$failed = $false
Get-ChildItem -Recurse -Include *.ps1,*.psm1 -File | ForEach-Object {
$errors = $null
[void][System.Management.Automation.Language.Parser]::ParseFile($_.FullName, [ref]$null, [ref]$errors)
foreach ($e in $errors) { Write-Host "::error file=$($_.FullName),line=$($e.Extent.StartLineNumber)::$($e.Message)"; $failed = $true }
}
if ($failed) { exit 1 }
- name: PSScriptAnalyzer (errors only)
shell: pwsh
run: |
Install-Module PSScriptAnalyzer -Force -Scope CurrentUser
$r = Invoke-ScriptAnalyzer -Path . -Recurse -Severity Error
$r | Format-Table RuleName, ScriptName, Line, Message -AutoSize
if ($r) { exit 1 }
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"sarif-viewer.connectToGithubCodeScanning": "off"
}
46 changes: 42 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,46 @@ A collection of PowerShell scripts, Azure/DevOps tooling, and SQL utilities for
See [docs/How-to Setup - Dev Machine.md](docs/How-to%20Setup%20-%20Dev%20Machine.md) for the full manual walkthrough this script automates.

## Repository Structure
| Folder | Description |
Organized by intent: **know your estate** (governance), **reduce risk** (security), **change things safely** (resources), and **run the platform** (everything else).

| Folder | Purpose |
|---|---|
| [docs/](docs) | How-to guides and command references (AD, SQL, SSL, web, build server, Azure CLI). |
| [scripts/azure-governance/](scripts/azure-governance) | Estate-wide inventory and FinOps hygiene via Azure Resource Graph (read-only). |
| [scripts/azure-security/](scripts/azure-security) | Posture and identity-hygiene reports: Key Vault audit, expiring app credentials (read-only). |
| [scripts/azure-resources/](scripts/azure-resources) | Create/change/remove Azure resources: Key Vault, storage, SQL, Front Door, Logic Apps, Entra, Monitor. |
| [scripts/azure-devops/](scripts/azure-devops) | Azure DevOps helpers (branch names, library variables, pull requests). |
| [scripts/azure-functions/](scripts/azure-functions) | Local Azure Functions host and certificate helpers. |
| [scripts/cybersecurity/](scripts/cybersecurity) | Tokens, certificates, cryptography, TLS readiness, PCI DSS tests, event logs. |
| [scripts/dev-experience/](scripts/dev-experience) | Developer machine bootstrap and terminal profile. |
| [scripts/dns/](scripts/dns), [scripts/iis-web-server/](scripts/iis-web-server), [scripts/windows-servers/](scripts/windows-servers) | Classic infrastructure and server administration. |
| [scripts/dotnet/](scripts/dotnet), [scripts/sitecore/](scripts/sitecore), [scripts/imperva/](scripts/imperva) | App-specific build, publish, and load-balancer tooling. |
| [t-sql/](t-sql) | SQL Server DBA scripts. |

Shared modules: [scripts/AzureCli.psm1](scripts/AzureCli.psm1) (az CLI + Resource Graph helpers), [scripts/Azure.psm1](scripts/Azure.psm1), [scripts/System.psm1](scripts/System.psm1).

## Modern Azure scripts (start here)
All read-only unless noted, `az` CLI only (no extensions), work across every subscription you can access, and export CSV with `-OutputPath`.

| Script | Use it to |
|---|---|
| [docs/](docs) | How-to guides and command references |
| [scripts/](scripts) | PowerShell scripts for Azure, DevOps, dev machine setup, and Windows servers |
| [t-sql/](t-sql) | SQL Server DBA scripts |
| [Get-AzKeyVaultSecurityAudit.ps1](scripts/azure-security/Get-AzKeyVaultSecurityAudit.ps1) | Find vaults on legacy access policies, without purge protection, or open to the public internet. |
| [Get-AzAppCredentialExpiry.ps1](scripts/azure-security/Get-AzAppCredentialExpiry.ps1) | Prevent outages from expired Entra app secrets/certificates. |
| [Get-AzOrphanedResources.ps1](scripts/azure-governance/Get-AzOrphanedResources.ps1) | Find unattached disks, idle public IPs, orphaned NICs and other waste. |
| [Convert-AzKeyVaultToRbac.ps1](scripts/azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1) | **Changes state.** Migrate access-policy vaults to RBAC with equivalent built-in roles. Run with `-WhatIf` first. |

```powershell
./scripts/azure-security/Get-AzKeyVaultSecurityAudit.ps1 -OutputPath ./kv-audit.csv
./scripts/azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1 -SubscriptionId "<name-or-id>" -WhatIf
```

[Set-AzKeyVaultAclGroup.ps1](scripts/azure-resources/key-vault/Set-AzKeyVaultAclGroup.ps1) grants groups access-policy permissions on legacy vaults. Use it only as a short-term bridge (for example, data migrations) until vaults are moved to RBAC.

## Modernization backlog
Older scripts predate current practice. When touching them, prefer: Microsoft Graph / `az ad` over the retired `AzureAD` module (for example [Add-ManagedIdentityRole.ps1](scripts/azure-resources/azure-ad/Add-ManagedIdentityRole.ps1)), `[Parameter(Mandatory)]` over `$(throw ...)` defaults, no `Set-ExecutionPolicy Unrestricted`, and `-WhatIf` on every destructive script.

## Conventions
- Shared modules live only in [scripts/](scripts). Import them with `Join-Path $PSScriptRoot` (new scripts) or a relative path (older scripts).
- Scripts that change state support `-WhatIf` (`SupportsShouldProcess`). Run with `-WhatIf` first.
- No secrets, tenant/subscription IDs, or customer data in the repo; use placeholders (`00000000-...`).
- See [.github/copilot-instructions.md](.github/copilot-instructions.md) for full authoring guidance.
Loading
Loading