Skip to content

Instantly share code, notes, and snippets.

@DocGreenRob
Last active January 11, 2026 21:14
Show Gist options
  • Select an option

  • Save DocGreenRob/a7f08d56bae684f7f00583f446c27e8a to your computer and use it in GitHub Desktop.

Select an option

Save DocGreenRob/a7f08d56bae684f7f00583f446c27e8a to your computer and use it in GitHub Desktop.
.Net Engineer Pro Tools
Windows Pro Tips
-----------------
powertoys - https://apps.microsoft.com/store/detail/microsoft-powertoys/XP89DCGQ3K6VLD
devtoys - https://apps.microsoft.com/store/detail/devtoys/9PGCV4V3BK4W
Visual Studio 2022 Pro Tips
---------------------------
vscoloroutput - https://marketplace.visualstudio.com/items?itemName=MikeWard-AnnArbor.VSColorOutput
solutionColor - https://marketplace.visualstudio.com/items?itemName=Wumpf.SolutionColor
save vs settings to apply to other computer - https://learn.microsoft.com/en-us/visualstudio/install/import-export-installation-configurations?view=vs-2022
Podcasts
--------
Dev interrupted
Hacking Humans
Cyber Security Headlines
Click Here
Malicious Life
The Stack Overflow Podcast
The Backend Engineering (with Hussein Nasser)
The Changelog: Software Development, Open Source
Tech Stuff
Cyberwire Daily
Techmeme Ride Home
Soft Skills Engineering
Syntax - Tasty Web Development Treats
Cyber Security Today
Software Engineering Daily
Developer Tea
Coding Blocks .NET
The Cloud Cast
JS Party: Javascript, CSS, Web Development
Go Time: Golang, Software Engineering
Cyber
Dev Questions with Tim Corey
Thoughtworks Technology Podcast
.NET Rocks!
Smashing Security
Hanselminutes with Scott Hanselman
Software Engineering
Talk Python To Me
Security Now
Darknet Diaries
Hacked
The .NET Core Podcast
The .NET MAUI Podcast
Kubernetes Podcast from Google
Adventures in .NET
Coding After Work
Base.cs Podcast
The Static Void Podcast
Tools
------
couchbase
honeycomb.io/changelog
firehydrant
logrocket
playwright
openmct
thundra.io
raygun
fly.io
appwrite
sentry.io
https://sourcegraph.com/
https://www.kolide.com/
https://entity.services/
WeekPlan
Docker Extensions
------------------
Ddosify - High-performance load testing tool
- https://github.com/ddosify/ddosify
BurpSuite
- https://portswigger.net/burp
- https://danaepp.com/
VS Tips
--------
Extract method from selected code
- Ctrl + R + M
Ctrl + K + D
Ctrl + R + G
Ctrl + M + Z (Code Maid)
Important
----------
ApplicationInsights SamplingSettings for AzFn
- https://learn.microsoft.com/en-us/azure/azure-functions/functions-host-json
Design Patterns in C#
- https://www.dofactory.com/net/factory-method-design-pattern
- https://github.com/DovAmir/awesome-design-patterns?utm_source=programmingdigest&utm_medium&utm_campaign=1493
Shopify Query
- https://shopify.engineering/reducing-bigquery-costs?utm_source=programmingdigest&utm_medium&utm_campaign=1403
Building Own Operating System
- https://o-oconnell.github.io/2023/01/12/p1os.html?utm_source=programmingdigest&utm_medium&utm_campaign=1493
Debugging Linq
- https://www.red-gate.com/simple-talk/development/dotnet-development/linq-secrets-revealed-chaining-and-debugging/
--> https://michaelscodingspot.com/debug-linq-in-csharp/
Bleeping Computer
- https://www.bleepingcomputer.com/
Utilities
---------
Handle v5.0
- https://learn.microsoft.com/en-us/sysinternals/downloads/handle?WT.mc_id=DT-MVP-5003978
Auto Increment Build #
- https://stackoverflow.com/questions/826777/how-to-have-an-auto-incrementing-version-number-visual-studio
Phylosophy
----------
1. Do I have to have a "purpose" to have an address in the USA?
- if yes, then as a Human being I must have a purpose? Seriously? Ok, a purpose to whom? To whom must I state my pupose or execute or report to about...???
2. System Failure - Zero Day Exploit
3. Good PR example - https://github.com/dotnet/aspnetcore/pull/45587/files
App Insights Log Queries
------------------------
availabilityResults
| where timestamp > datetime("2022-12-19T04:07:00.000Z") and timestamp < datetime("2022-12-20T04:07:00.000Z")
| where customDimensions["WebtestArmResourceName"] == "availability-test-1-app-notepad-physical-activity-dev-eastus"
| where true and true
| extend percentage = toint(success) * 100
| summarize avg(percentage) by bin(timestamp, 1h)
| render timechart
******************************************************************
@DocGreenRob
Copy link
Author

import { AfterViewInit, Component, Input, OnInit } from '@angular/core';
import { CommunicationService } from '../../../services/_internal/communication/communication.service';
import { SessionDataService } from '../../../services/_internal/session-data/session-data.service';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-global-spinner',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './global-spinner.component.html',
  styleUrl: './global-spinner.component.scss'
})
export class GlobalSpinnerComponent implements OnInit, AfterViewInit {
  // *********************
  // variables declaration
  // *********************

  // private
  // ********

  // public
  // ******
  @Input() spinnerText: string = "Searching...";

  constructor(private sessionDataService: SessionDataService,
    private communicationService: CommunicationService) {
  }

  // ***************
  // lifecycle hooks
  // ***************
  ngOnInit(): void {
    this.housekeeping();
  }

  ngAfterViewInit(): void {
  }

  // *******
  // methods
  // *******

  // public
  // ******

  // private
  // *******
  private housekeeping() {
  }

}

@DocGreenRob
Copy link
Author

RxProcessManagerLocalTest

Set WshShell = CreateObject("WScript.Shell")
Do
WshShell.SendKeys "{SCROLLLOCK}"
WScript.Sleep 60000 ' 60 seconds
Loop

cscript //nologo RxProcessManagerLocalTest.vbs

@DocGreenRob
Copy link
Author

image

@DocGreenRob
Copy link
Author

DocGreenRob commented Nov 2, 2025

🧩 Overview

You’ll:

  1. List secrets from the source Key Vault
  2. Loop through each secret name
  3. Retrieve the latest value
  4. Write it into the destination Key Vault

This approach preserves names and values, but not version history (you almost never want to duplicate every historical version).


⚙️ Prerequisites

Make sure:

az login
az account set --subscription "<YourSubscriptionID>"

You’ll also need read access to the source Key Vault and set access to the destination Key Vault (via RBAC or access policy).


🧠 Script (Bash for Azure Cloud Shell)

# Replace with your vault names
SOURCE_VAULT="source-keyvault-name"
DEST_VAULT="destination-keyvault-name"

# Get all secret names (not versions)
for secret in $(az keyvault secret list --vault-name $SOURCE_VAULT --query "[].name" -o tsv)
do
  echo "Copying secret: $secret"
  
  # Get the latest secret value
  value=$(az keyvault secret show --vault-name $SOURCE_VAULT --name $secret --query "value" -o tsv)

  # Recreate the secret in the destination vault
  az keyvault secret set --vault-name $DEST_VAULT --name $secret --value "$value" >/dev/null
  
done

echo "✅ All secrets copied from $SOURCE_VAULT to $DEST_VAULT"

🧰 Notes

  • If you have disabled secrets in the source vault and want to skip them:

    az keyvault secret list --vault-name $SOURCE_VAULT --query "[?attributes.enabled==\`true\`].name" -o tsv
  • To handle secrets with special characters or newlines safely, consider using --query "value" -o json and proper quoting, e.g.:

    value=$(az keyvault secret show --vault-name $SOURCE_VAULT --name $secret --query "value" -o json | jq -r)
  • The script does not copy tags or contentType. To include those, you’d extend it:

    metadata=$(az keyvault secret show --vault-name $SOURCE_VAULT --name $secret)
    value=$(echo $metadata | jq -r '.value')
    contentType=$(echo $metadata | jq -r '.contentType')
    az keyvault secret set --vault-name $DEST_VAULT --name $secret --value "$value" --content-type "$contentType"

🔐 Alternative (PowerShell in Cloud Shell)

If you prefer PowerShell syntax:

$sourceVault = "source-keyvault-name"
$destVault   = "destination-keyvault-name"

$secrets = az keyvault secret list --vault-name $sourceVault | ConvertFrom-Json
foreach ($secret in $secrets) {
    $name = $secret.name
    $value = az keyvault secret show --vault-name $sourceVault --name $name --query value -o tsv
    az keyvault secret set --vault-name $destVault --name $name --value $value | Out-Null
    Write-Host "Copied secret: $name"
}

Would you like me to include copying certificates and keys as well (not just secrets)? It’s a slightly different process involving az keyvault certificate and az keyvault key commands.

@DocGreenRob
Copy link
Author

What you’re seeing is normal internet “background radiation”: bots trawling every public site for WordPress/PHP holes (/wp-admin/*, random *.php, xmlrpc.php, etc.). Since your app isn’t PHP, they’re just probing. 46 requests in 24 hours is not a DDoS—a real DoS is usually thousands+ per minute—but you’re right to stop it from ever touching your app.

Here’s the clean playbook (Azure-native), in the order that actually reduces load.

1) Stop it at the edge (best ROI): Azure Front Door Premium + WAF

Front Door (Std/Premium) + WAF is what you want if your goal is “don’t let garbage reach my App Service.”

WAF rules to add (immediately)

Custom “Block PHP/WordPress scans” rule:

  • Block if URL path ends with .php

  • Block if URL path contains:

    • /wp-admin
    • /wp-content
    • /wp-includes
    • /xmlrpc.php

Rate limit rule (basic bot throttling):

  • If a single IP hits you more than (example) 100 requests in 1 minute, block for 5–10 minutes.

This removes noise before your app even sees it.

2) Prevent bypass: lock down the App Service origin

Once Front Door is in place, make sure attackers cannot hit your App Service URL directly.

In App Service → Networking → Access Restrictions:

  • Allow the AzureFrontDoor.Backend service tag (Front Door to origin)
  • Deny all else

That forces all traffic through WAF.

3) Don’t use APIM just to block bots

API Management is not the right tool for random internet scans.

  • Use APIM when you want: API products, subscriptions, quotas for real clients, versioning, developer portal, etc.
  • For bot junk and path probing: WAF is the tool.

(You can rate-limit in APIM, but you’ll pay more and the junk still has a chance to reach the gateway.)

4) Quick app-side safety net (so even without WAF you’re fine)

Add a tiny middleware early in the pipeline to short-circuit obvious garbage fast (no auth, no DB, no logging spam):

app.Use(async (ctx, next) =>
{
    var p = ctx.Request.Path.Value ?? "";

    if (p.EndsWith(".php", StringComparison.OrdinalIgnoreCase) ||
        p.StartsWith("/wp-", StringComparison.OrdinalIgnoreCase) ||
        p.Contains("/wp-admin", StringComparison.OrdinalIgnoreCase) ||
        p.Contains("/wp-content", StringComparison.OrdinalIgnoreCase) ||
        p.Contains("/wp-includes", StringComparison.OrdinalIgnoreCase) ||
        p.EndsWith("/xmlrpc.php", StringComparison.OrdinalIgnoreCase))
    {
        ctx.Response.StatusCode = StatusCodes.Status404NotFound;
        return;
    }

    await next();
});

Even if you later add Front Door/WAF, this keeps your origin resilient.

5) Fix robots.txt returning 400

A 400 for /robots.txt is unnecessary noise. Just serve a static robots.txt and return 200:

wwwroot/robots.txt

User-agent: *
Disallow:

Or if you want to discourage crawling:

User-agent: *
Disallow: /

6) Prove whether it’s actually “load” (App Insights check)

Run a quick KQL to see if these are cheap 404s or expensive requests:

requests
| where timestamp > ago(24h)
| where url has ".php" or url has "/wp-"
| summarize count(), avg(duration), max(duration) by resultCode, client_CountryOrRegion, client_IP
| order by count_ desc

If duration is tiny and counts are low, it’s noise. If duration is high, your app pipeline is doing too much before rejecting—then the middleware above matters a lot.


Bottom line

  • This is bot scanning, not a real DoS.
  • The “adult” solution is Front Door Premium + WAF + lock down origin.
  • APIM is optional and usually not the fix for this problem.

If you tell me what you’re hosting on (Azure App Service? Container Apps? AKS?) and whether you already have Front Door/Cloudflare, I’ll give you the exact click-path + the exact WAF rule patterns to paste in.

@DocGreenRob
Copy link
Author

Best practice: use Microsoft Entra ID (Azure AD) authentication + groups, then create database users only in the 1–2 databases they’re allowed to access. That avoids shared passwords and keeps access clean and revocable. ([Microsoft Learn]1)

Option A (recommended): Entra ID group → DB user → least-privilege role

1) Set an Entra admin on the Azure SQL logical server (required to create Entra principals). ([Microsoft Learn]1)
2) Create an Entra security group (e.g., HomeaZZon-DB-Readonly) and add your guys to it.
3) In EACH allowed database, run (connected as Entra admin):

-- In DatabaseA (repeat for DatabaseB). Do NOT run in other DBs.
CREATE USER [HomeaZZon-DB-Readonly] FROM EXTERNAL PROVIDER;

-- simplest built-in role:
ALTER ROLE db_datareader ADD MEMBER [HomeaZZon-DB-Readonly];

-- optional: if they need writes too
-- ALTER ROLE db_datawriter ADD MEMBER [HomeaZZon-DB-Readonly];

If you want tighter than “all tables”, create a custom role and grant only what you want (schema/table/proc-level grants). Microsoft recommends managing permissions via roles (not direct grants to users). ([Microsoft Learn]1)

Why this limits them to 1–2 DBs: if there’s no user created in other databases, they can’t access those DBs (they’ll get permission denied). ([Microsoft Learn]2)

If they’re external contractors: invite them as Entra guest users, then add them to the group. ([Microsoft Learn]3)


Option B: SQL authentication without server-level login (contained database users)

If you don’t want Entra (or you need SQL logins), create contained users with passwords inside only the allowed databases:

-- Run inside DatabaseA only (repeat in DatabaseB if needed)
CREATE USER [Contractor1] WITH PASSWORD = 'UseARealStrongPasswordHere!';

ALTER ROLE db_datareader ADD MEMBER [Contractor1];

Important gotcha: for contained users without a master login, the connection must specify the database (Initial Catalog). ([Microsoft Learn]4)


What I’d do in real life

  • Entra group auth (Option A)
  • Custom DB role with explicit GRANT (don’t hand out db_owner)
  • Add network controls (firewall / private endpoint) if this is sensitive data

If you tell me whether you’re on Azure SQL Database (PaaS) vs Managed Instance (or SQL VM), I’ll give you the exact script set and the cleanest role design for “read-only” vs “read/write” vs “stored-proc-only.”

@DocGreenRob
Copy link
Author

Got it — on SQL Managed Instance you should do the classic SQL login (instance-level) + database user (per DB) + roles/GRANTs. That gives you username/password now, and later you can swap the user mapping to Entra without redesigning your permissions model. ([Microsoft Learn]1)

1) Create one SQL Login per person (don’t share)

Run in master:

USE [master];
GO

CREATE LOGIN [dev_john] WITH
  PASSWORD = 'Use-A-Long-Random-Password-Here!',
  CHECK_POLICY = ON,
  CHECK_EXPIRATION = ON,
  DEFAULT_DATABASE = [HomeaZZonDb1];
GO

(Repeat for each guy.) Managing logins/users is standard for Managed Instance. ([Microsoft Learn]1)


2) Create a user only in the 1–2 databases they’re allowed to access

Database #1:

USE [HomeaZZonDb1];
GO

CREATE USER [dev_john] FOR LOGIN [dev_john];
GO

-- Simple broad read-only:
ALTER ROLE db_datareader ADD MEMBER [dev_john];
GO

Database #2 (optional):

USE [HomeaZZonDb2];
GO

CREATE USER [dev_john] FOR LOGIN [dev_john];
GO

ALTER ROLE db_datareader ADD MEMBER [dev_john];
GO

Database roles (like db_datareader) are the clean way to manage permissions. ([Microsoft Learn]2)


3) If “read-only to the whole DB” is too broad, do least-privilege (recommended)

Instead of db_datareader, create a custom role and grant only what you want:

USE [HomeaZZonDb1];
GO

CREATE ROLE [AppReadOnly];
GO

-- Option A: all tables in dbo schema
GRANT SELECT ON SCHEMA::dbo TO [AppReadOnly];
GO

-- Option B: only specific tables
-- GRANT SELECT ON dbo.Table1 TO [AppReadOnly];
-- GRANT SELECT ON dbo.Table2 TO [AppReadOnly];

ALTER ROLE [AppReadOnly] ADD MEMBER [dev_john];
GO

(If they need stored procs only, grant EXECUTE instead of SELECT.)


4) How this prevents access to other databases

If you don’t create a user for that login in other databases, they can’t access them (they’ll get “not authorized” when trying to USE OtherDb). To avoid any accidental access via guest in user databases, you can revoke guest connect in databases you don’t want anyone drifting into: ([Microsoft Learn]3)

-- Run inside EACH user database you want locked down (NOT master/tempdb; be careful with msdb)
REVOKE CONNECT FROM GUEST;
GO

Note: Disabling guest in msdb can break features (SQL Agent-related behavior), so don’t do it there. ([Microsoft Learn]4)


5) Operational tips (worth doing)

  • Disable the login when you’re done (instant cutoff):

    ALTER LOGIN [dev_john] DISABLE;
  • Keep them out of server roles (don’t add to anything like sysadmin).

  • Use separate logins per person so auditing is real.

If you tell me what “access” means (read-only vs read/write vs execute-only, and whether they need migrations/scaffolding), I’ll tailor the exact role + GRANT script for those 1–2 databases.

@DocGreenRob
Copy link
Author

Yes. What you’re seeing is normal: by default, SQL Server grants database name visibility broadly via the server permission VIEW ANY DATABASE (it’s granted to the public server role by default), so logins can see all DBs even if they can’t use them. ([Database Administrators Stack Exchange]1)

Best fix (per-login): deny “view any database”

Run in master:

USE [master];
GO
DENY VIEW ANY DATABASE TO [dev_john];
GO

After this, in SSMS Object Explorer they should only see databases they can actually connect to (i.e., the 1–2 DBs where you created a user/mapped permissions), plus some system DB behavior depending on SSMS. ([Stack Overflow]2)

Cleaner at scale: create a server role and deny once

USE [master];
GO

CREATE SERVER ROLE [LimitedDbVisibility];
DENY VIEW ANY DATABASE TO [LimitedDbVisibility];

ALTER SERVER ROLE [LimitedDbVisibility] ADD MEMBER [dev_john];
ALTER SERVER ROLE [LimitedDbVisibility] ADD MEMBER [dev_mike];
GO

This is easier than managing DENY statements on each login.

Important notes

  • If they’re sysadmin (or in powerful server roles), you won’t be able to hide anything — they’ll see all DBs. ([Server Fault]3)
  • You generally can’t fully hide system databases at the engine level; SSMS may still show them. That’s by design. ([Microsoft Learn]4)
    (SSMS has a client-side option “Hide system objects,” but that’s per workstation, not security.) ([Database Administrators Stack Exchange]5)

Undo (if needed)

USE [master];
GO
REVOKE VIEW ANY DATABASE TO [dev_john];
GO

If you want, paste one login name and your allowed DB names and I’ll give you a single script that: creates login, maps user in only those DBs, grants read/write, and applies the “don’t show other DBs” setting.

@DocGreenRob
Copy link
Author

image

@DocGreenRob
Copy link
Author

Use benchmark.net to do performance testing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment