The crowd of 16,665 was the highest of the season and it is 31 years since Pompey won at Deepdale.
Portsmouth had an early chance when a Paul Merson inswinging corner fell to Primus who hit a right-foot volley wide of the post.
After just five minutes Portsmouth scored when Kevin Harper and Steve Stone, played a one-two and Stone found the 20-year-old Nigerian Yakubu Ayegbeni and he hit a left-foot shot into the bottom left-hand corner of the net.
After eight minutes Eddie Lewis found George Koumantarakis and he flicked a header wide of the right-hand post.
After a quarter of an hour Richard Cresswell shot wide after good play from Rob Edwards on the left-hand side and in the 28th minute Lewis hit a left-foot shot from 15 yards to Shaka Hislop's left and he saved after a great five-man move involving McKenna, Chris Lucketti, Koumantarakis and Dickson Etuhu.
McKenna had a right-foot shot on the half-hour mark after good work by Etuhu.
Merson hit a right-foot shot over the bar after Svetoslav Todorov had found Ayegbeni.
The fourth official signalled one minute but it was 1-0 to Portsmouth at half time.
Koumantarakis was replaced by Simon Lynch on 56 minutes and on 79 minutes Tyrone Mears came on for Lee Cartwright and Deon Burton replaced Todorov.
With three minutes to go Marlon Broomes was replaced by Brian O'Neil and he went to centre-back and Lucketti went to centre-forward.
Lucketti won a free-kick on the edge of the box on the left-hand side when he was fouled by Primus. Graham Alexander took the free-kick with a one-two with Lewis and found McKenna in a central position.
He hit a 20-yard right-foot shot into the bottom right-hand corner of the net with two minutes to go.