I need to support nesting so none of these worked for me.  I gave up trying to do it via Regex and just coded:
  public static Argument[] ParseCmdLine(string args) {
    List<string> ls = new List<string>();
    StringBuilder sb = new StringBuilder(128);
    // support quoted text nesting up to 8 levels deep
    Span<char> quoteChar = stackalloc char[8];
    int quoteLevel = 0;
      
    for (int i = 0; i < args.Length; ++i) {
      char ch = args[i];
      switch (ch) {
        case ' ':
          if (quoteLevel == 0) {
            ls.Add(sb.ToString());
            sb.Clear();
            break;
          } 
          goto default; 
        case '"':
        case '\'':
          if (quoteChar[quoteLevel] == ch) {
            --quoteLevel;
          } else {
            quoteChar[++quoteLevel] = ch;
          }
          goto default; 
        default:
          sb.Append(ch);
          break;
      }
    }
    if (sb.Length > 0) { ls.Add(sb.ToString()); sb.Clear(); }
    return Arguments.ParseCmdLine(ls.ToArray());
  }
And here's some additional code to parse the command line arguments to objects:
  public struct Argument {
    public string Prefix;
    public string Name;
    public string Eq;
    public string QuoteType;
    public string Value;
    public string[] ToArray() => this.Eq == " " ? new string[] { $"{Prefix}{Name}", $"{QuoteType}{Value}{QuoteType}" } : new string[] { this.ToString() };
    public override string ToString() => $"{Prefix}{Name}{Eq}{QuoteType}{Value}{QuoteType}";
  }
  private static readonly Regex RGX_MatchArg = new Regex(@"^(?<prefix>-{1,2}|\/)(?<name>[a-zA-Z][a-zA-Z_-]*)(?<assignment>(?<eq>[:= ]|$)(?<quote>[""'])?(?<value>.+?)(?:\k<quote>|\s*$))?");
  private static readonly Regex RGX_MatchQuoted = new Regex(@"(?<quote>[""'])?(?<value>.+?)(?:\k<quote>|\s*$)");
  public static Argument[] ParseCmdLine(string[] rawArgs) {
    int count = 0;
    Argument[] pairs = new Argument[rawArgs.Length];
    int i = 0;
    while(i < rawArgs.Length) {
      string current = rawArgs[i];
      i+=1;
      Match matches = RGX_MatchArg.Match(current);
      Argument arg = new Argument();
      arg.Prefix = matches.Groups["prefix"].Value;
      arg.Name = matches.Groups["name"].Value;
      arg.Value = matches.Groups["value"].Value;
      if(!string.IsNullOrEmpty(arg.Value)) {
        arg.Eq = matches.Groups["eq"].Value;
        arg.QuoteType = matches.Groups["quote"].Value;
      } else if ((i < rawArgs.Length) && !rawArgs[i].StartsWith('-') && !rawArgs[i].StartsWith('/')) {
        arg.Eq = " ";
        Match quoted = RGX_MatchQuoted.Match(rawArgs[i]);
        arg.QuoteType = quoted.Groups["quote"].Value;
        arg.Value = quoted.Groups["value"].Value;
        i+=1;
      }
      if(string.IsNullOrEmpty(arg.QuoteType) && arg.Value.IndexOfAny(new char[] { ' ', '/', '\\', '-', '=', ':' }) >= 0) {
        arg.QuoteType = "\"";
      }
      pairs[count++] = arg;
    }
    return pairs.Slice(0..count);
  }
  public static ILookup<string, Argument> ToLookup(this Argument[] args) => args.ToLookup((arg) => arg.Name, StringComparer.OrdinalIgnoreCase);
}
It's able to parse all different kinds of argument variants:
-test -environment staging /DEqTest=avalue /Dcolontest:anothervalue /DwithSpaces="heys: guys" /slashargflag -action="Do: 'The Thing'" -action2 "do: 'Do: \"The Thing\"'" -init
Nested quotes just need to be alternated between different quote types.