I am trying to make it so people can’t use the function/target people who are higher than them. This is what I have.

AddStickTool("Freeze Player", {
	Description = "Freezes the target.",
	Icon = "icon16/control_pause_blue.png",
	CanTarget = targetply,
	OnRun = function(Player, Trace)
		local ply = Trace.Entity
		if ply:table.HasValue({"donoradmin", "developer", "trialadmin", "admin", "superadmin", "management", "owner", "coowner"}, ply:GetNWString("usergroup")) then -- Now NOBODY can target them (dont even know if this works havent tested)
			Stick_SendChat(Player, "That person has immunity to you!")
	elseif (ply:IsFrozen()) then
			Stick_SendChat(Player, "Unfrozen " .. tostring(ply))
			Stick_SendChat(ply, "You have been unfrozen")
			Stick_SendChat(Player, "Frozen " .. tostring(ply))
			Stick_SendChat(ply, "You have been frozen")

How would I get the players usergroup then apply the immunity based on what rank they are?

local ranks = {["donoradmin"]=7, ["developer"]=6, ["trialadmin"]=5, ["admin"]=4, ["superadmin"]=3, ["management"]=2, ["owner"]=0, ["coowner"]=1}

if ranks[selfplayer:GetRank()] <= ranks[target:GetRank()] then -- (if caller's rank is less administrative or equal to than target's rank do...) 
--put your freezing code here
--put a warning saying you can't target that person

GetRank() doesn’t exist so substitute something into it so that will return player’s rank

Here’s a simple bit of code I wrote for this: - remove .html to view .lua

Use as _p:IsHigherLevel( x ) where x can be a player or a user-level… I skip a few between ranks so that variations can be created such as senior admin, senior super admin, developer, etc… Obviously they don’t need to be this far apart…

This is essentially the same thing as what baldursgate3 posted, only with one list needing to exist with helper-functions to check the level instead of using that code in each place which needs it or writing functions for that code…