Simulating on the continuum from not overdispersed to over-dispersed is easy: you fix a rate $\lambda$ (no overdispersion) or you draw your rates from a gamma distribution (=overdispersion). This is one way of getting the negative binomial distribution. For example, if you want the negative binomial distribution with the parameterization that has a mean rate per time unit of $\mu$, a dispersion parameter $\kappa \in [0, \infty)$ ($\kappa=0$ = Poisson) and an observation time $t>0$, you can use functions like these:
# Simulate from NegBin(mu*t, kappa); mu>0, t>0, kappa>0
rnegbin = function(n, mu, kappa, t=1){ # Note: no protection against kappa <= 0
rpois(n=n, mu*t*rgamma(n=n, shape=1/kappa, rate=1/kappa))
}
# Density function for NegBin(mu, kappa); mu>0, kappa>=0
dnegbin = function(x, mu, kappa, log=FALSE){
if (kappa>0) {
tmp = lgamma(x+1/kappa) - lgamma(x+1) - lgamma(1/kappa) + x*log(kappa*mu) - (x+1/kappa)*log1p(kappa*mu)
} else { # no protection against kappa <0
tmp = x*log(mu)-mu-lgamma(x+1)
}
if (log==F) return(exp(tmp)) else return(tmp)
}
If you do not really mind whether your overdispersed counts are from a negative binomial, you can of course also draw your rates from a log-normal distribution (or log-rates from a normal distribution).
I don't have much experience with simulating underdispersed counts, but one I idea would be to simulate Poisson random variables and to draw a new set with increasing probability the further away from the mean you are. It's a bit tricky to keep the expected value constant though (if that matters to you).