Your ^((?!Drive).)*$ did not work at all because you tested against a multiline input.
You should use /m modifier to see what the regex matches. It just matches lines that do not contain Drive, but that tempered greedy token does not check if EFI is inside the string.
Actually, the $ anchor is redundant here since .* matches any zero or more characters other than line break characters. You may simply remove it from your pattern.
(NOTE: In .NET, you will need to use [^\r\n]* instead of .* since . in a .NET pattern matches any char but a newline, LF, char, and matches all other line break chars, like a carriage return, CR, etc.).
Use something like
^(?!.*Drive).*EFI.*
Or, if you need to only fail the match if a Drive is present as a whole word:
^(?!.*\bDrive\b).*EFI.*
Or, if there are more words you want to signal the failure with:
^(?!.*(?:Drive|SomethingElse)).*EFI.*
^(?!.*\b(?:Drive|SomethingElse)\b).*EFI.*
See regex demo
Here,
^ - matches start of string
(?!.*Drive) - makes sure there is no "Drive" in the string (so, Drives are NOT allowed)
(?!.*\bDrive\b) - makes sure there is no "Drive" as a whole word in the string (so, Drives are allowed)
.* - any 0+ chars other than line break chars, as many as possible
EFI - anEFI substring
.* - any 0+ chars other than line break chars, as many as possible.
If your string has newlines, either use a /s dotall modifier or replace . with [\s\S].