For junior positions, I tend to ask very simple questions. Reverse a string or given an array and an int count how many times that number occurs (or variants thereof). Something that requires a loop and some ifs. It opens the posibility of endless discussions about extensions, refactoring, runtime, edgecases - it gives a solid bases on which to judge their ability.
For senior positions, it's slightly more advanced. But if they make it through to second round, we have them bug hunt and refactor some piece of code.
Programming is a craft and I need to evaluate that craft.
The questions I prefer to ask are about writing a basic but readable and maintainable piece of code, maybe 50-100 lines long, that requires the candidate to talk about why they are making certain trade-offs, questions that look at when they would involve other team members in decisions (when do you ask a Product Manager or Designer for help?), questions that try to understand whether they can solve problems rather than the one problem in one language given to them in the interview. I typically do those interviews in Python but some of the best candidates have never written any Python – but their communication, intuition, and problem solving abilities were great.