ORCHARD PARK, N.Y. – The Vikings walked out of New Era Field as preseason winners, 17-10 over the Bills on Thursday night, despite some all-too-familiar performances from a sputtering offense.

In near-perfect conditions on a sunny evening in Buffalo, quarterback Sam Bradford was sacked twice on nine dropbacks. Rookie running back Dalvin Cook averaged 2.6 yards on five carries. Yet the Vikings won with touchdown drives from both backup quarterbacks, Case Keenum and Taylor Heinicke.

"We still got a lot of work to do. My expectations for this team are a lot higher than that," head coach Mike Zimmer said. "I didn't feel like we covered well enough defensively — especially early in the ballgame, we gave up too many easy catches. Offensively, two sacks were disappointing, but we had only three penalties on the night and they had 10."

Bradford and the starting offense took a seat after zero points in three series, picking up just 24 yards. Bradford completed five of seven passes for 35 yards.

Zimmer spent much of the offseason lamenting "negative plays" the Vikings created on offense, whether by penalty, sack or a failed run. The Vikings had one from each category against the Bills, stacking up five of those "negative plays" within the first 25 snaps on offense.

First came the third-down sack on Bradford. Right tackle Mike Remmers, one of two key free-agency signings for the offensive line, quickly surrendered the pressure to Bills defensive end Eddie Yarbrough to end the Vikings' first series. Then the Bills overloaded the left side, where tackle Rashod Hill started for injured Riley Reiff (back), and the young Cook appeared to miss a block, to sack Bradford on the following series.

Then Cook's biggest gain, a 9-yard catch and run, was called back when guard Alex Boone drew a flag for holding.

"The first two runs were good, and after that it kind of drifted down," Boone said. "As an O-line, we have to clean it up. We have to make it better. I think we rushed for only 90 yards today."

The starters' only first down of the night came on a third-down swing pass to Cook for 8 yards.

"I expect us to go out, take the ball and score — we didn't do that," Zimmer said. "The sack stopped the first one, and then we had a couple pressures [defensively] where we ran up the field, and it was a run. We allowed runs to occur. That's an easy, correctable thing we'll get corrected."

NFL preseason scoreboard and statistics

Still, the first test run was limited to a partial look at the expected 2017 offense. Cook, who turned 22 years old on Thursday, was the clear focal point for an offense without a handful of starters due to injury. Reiff, receiver Laquon Treadwell and running backs Latavius Murray and Jerick McKinnon did not play.

So coordinator Pat Shurmur fed Cook with four touches on the opening five plays. The Vikings deployed Cook in a variety of looks, whether the quarterback was under center or in the pistol or shotgun formations.

"I'm sure he feels like he could've done more," Zimmer said of Cook, who managed 43 yards on nine touches. "He will in the future."

One positive takeaway was Cook's fluid receiving ability out of the backfield, a departure from the often clunky play from Adrian Peterson in that area. Cook gained 30 yards on four catches.

"I think he's going to be a valuable asset not only in the run game, but I think we're going to be able to utilize him in the pass game," Bradford said. "You saw it one time tonight, we moved him out wide in an empty set."

The Vikings defense held the Bills in check until starters sat after two series. Then Bills running backs Jamaal Williams and Mike Tolbert went to work with gashing runs and catches, setting up Steven Hauschka's 42-yard field goal to give the Bills a 3-0 lead.

Vikings rookie receiver Stacy Coley got the offense out of the mud by turning a short crossing route into a speedy 38-yard gain from backup quarterback Case Keenum. Coley, who led all receivers with 67 yards on three grabs, set up Kai Forbath's 36-yard field goal to tie the score 3-3 in the first half.

With a more consistent outing, Keenum might have separated himself in the backup quarterback competition with Heinicke. After Keenum and Coley connected on a 24-yard grab, fullback C.J. Ham barreled into the end zone for a 2-yard touchdown run and 10-3 lead.

Keenum completed 11 of 16 passes for 121 yards, not including a disappearing act when he ducked two Bills defenders to avoid a sack. A mobile Keenum instead gained 7 yards on a scramble.

Heinicke, playing his first game in two years, showed off his legs with a 19-yard scamper. He orchestrated a messy 14-play, 71-yard touchdown drive, which included a deflected pass by a Bills defender into the arms of running back Terrell Newby near the goal line. The Vikings took a 17-3 lead after Heinicke found receiver Rodney Adams for a 2-yard touchdown catch.

When the Bills cut into the Vikings' lead with a touchdown, Heinicke then threw a head-scratching interception while on the run. Buffalo squandered its three fourth-quarter chances with two turnovers on downs and a fumble recovered by Vikings linebacker Elijah Lee.