AWS Lambda Python Puzzle

I have an AWS Lambda function that is written in Python 3.8 and imports the following modules:

import ask_sdk_core.utils as ask_utils
import regex as re

I decided to include the package files for these modules in a Layer so that I could separate “their code” from “my code.” I ran the following at the command line:

md package\python\lib\python3.8\site-packages
cd package\python\lib\python3.8\site-packages
pip install -–target . ask_sdk_core 
pip install --target . regex

I zipped it all up into and uploaded it to the Layer, per these instructions: When I ran my test code it complained:

  "errorMessage": "Unable to import module 'lambda_function': No module named 'regex._regex'",
  "errorType": "Runtime.ImportModuleError"

I knew my Layer was configured properly because the ask_sdk_core module was found before the regex wasn’t. Somehow, I stumbled across this article: This was the solution.

So I navigated to and searched for regex. Then clicked downloads. Then found the Python 3.8 version of the manylinux1_x86_64.whl file, which was called:


I unzipped this file to my package\python\lib\python3.8\site-packages folder. Zipped it all up, uploaded to a new version of my Layer, removed the old Layer from the Lambda function and added the new one.

This time my test code worked like a charm.

Thank you to the Alexa Community ( for your unwavering support during this ordeal.

Open Letter to Job Seekers in Information Technology

Dear Job Seeker,

So you’re looking for a new job in I.T.?

First, how many users group and software groups do you visit each month? These are a GREAT way to meet potential co-workers and potential employers. To find them, search on for “software”, and, separately, “users groups”, and also “developer”.

There are tons of virtual events that are free that you can participate in.  Find your local vendor events.  For example, Microsoft, Oracle,, and  Speak to local recruiters and find out what events they will be attending.  I’ve had good luck finding jobs through TEKsystems, but there are hundreds of recruiters looking for you! Make sure they can find you.

Second, if you recently graduated, you are probably used to giving presentations.  Even if you didn’t, you should consider speaking at (virtual) events for the users’ groups or the development community.   Develop a 40-50-minute presentation that is code-heavy instead of PowerPoint heavy that shows an interesting thing.  Join a local Toastmasters club to hone your public speaking skills.

If you’ve done a challenging project or run into a thorny issue that was especially difficult to solve, those make great topics.  If you know Microsoft SQL or Azure, you should consider speaking at SQL Saturday events.  For example, I occasionally speak at SQL Saturday and for one of my sessions, I speak about Why Microsoft Developers need to learn Python because of my love for using Python to solve utility-type problems.  

A lot of firms are “not hiring” right now, but they will hire a candidate who is outstanding.  How do they find out you’re outstanding?  They see you at an event.  Use those events to ask questions, speak up, speak out, network, and meet people.

Third, learn a new skill.  Do you have a particular area of interest yet?  For example, I move data.  I am an SQL Expert.  I write C# and Python.  But I also create Alexa skills.  I’m not a web/HTML/CSS/JavaScript full stack developer.  I know this and so it lets me focus on backend technologies.  I’m also a Microsoft guy.  I don’t write Java.  Period.  And I don’t prefer to work with Oracle or DB2.  I’m (mostly) a SQL Server and Azure developer.  I’m also dipping my toe into the AWS pool.  Careers in I.T. require a commitment to life-long learning.  Some of that time is spent deepening and sharpening your skills in certain areas, but some of it should be spent learning new languages, new techniques, development patterns, unit testing tools, agile methods, and more.

Fourth, consider teaching.  Do you have Python skills?  Can you learn quickly?  Are you quick-witted and “fast on your feet”?  If so, practice teaching.  Put together a 5-minute video of you teaching something, anything technical, and put it on YouTube.  Then add the link to your resume and LinkedIn profile.  Check out Doodly for an alternative way to make training videos.

Fifth, start a technical blog.  As you learn a new skill, you will explore technologies and will probably have to “figure stuff out”.  When you do, blog about it.  I still get hits on one of the technical articles that I wrote years ago about a weird problem with Maven.

Finally, specialize.  Figure out what it is that gives you energy, jazzes you, or otherwise gets you motivated.  The aspect of computing that is so awesome for you that time passes and you don’t notice.  Focus on the languages and skills where time flies.  You don’t have to be great at it.  You can learn that.  But you can’t learn passion, you have to find it.  Whatever that thing is that inspires you, that is your strength.  For example, I always aspired to move up the corporate ladder, but that’s not my strength.  I am so much happier solving a complex computing problem.  I eat them up.  And that is my strength.  That and teaching.  I really enjoy sharing my skills with others so they don’t have to figure it out the hard way.

Well, that should be plenty for a start.

Good luck in your job search,
Simon Kingaby

P.S.  LinkedIn.  Make sure your LinkedIn profile is AWESOME.  It is the best way to get the attention of recruiters.  They spend hours googling and searching for people with specific skills.  Make sure they can find you for your specific skills.

SQL Saturday St. Louis – February 2020

I will be speaking at SQL Saturday St. Louis on Saturday, February 8th at 8:00 am and 10:20 am. The topics are:

8:00 am Moving Data to the Cloud (with Azure Data Factory)

You need to move data. A lot of data. To the cloud. You’ve got data in a variety of on- and off-site data sources. There are several ways to do it. Some of them can be quite easily implemented using Azure Data Factory. Learn how to use variables and looping in your Data Factory pipelines. Use the Integration Runtime to pull directly from on-site sources. See how to upload files to blob storage and import them. Learn how to trigger Data Factory activities. And, learn how to keep all those connection strings and passwords secret in Azure Vault. After this session, you will have tools that you can readily implement in your own data migrations.

10:20 am Why Learn Python? A Microsoft DB/ETL/BI Developer’s Answer

You’re a Microsoft Developer. C#, MSSQL, SSIS/SSRS, SSMS, and Azure are your tools of choice. Why would you want to learn Python? In this session, I will show you several take-home utilities that use Python. The first hunts through a folder structure full of SSIS packages looking for the one(s) that load(s) a specified table. The second executes the data sources in an SSRS report to identify performance problems and document them in Excel. The third GeoCodes the City/Country names from a SQL table, getting the Lat/Lng so you can use the data in maps. Familiarity with Python is not necessary to use the utilities, but we’re not going to do Hello World either. This is real Python for Microsoft Database, ETL and BI Developers. This all-demo session shows you how to use Python with the .Net CLR, XML, ODBC, Excel, SQL Server, and Web API calls.

  1. Which SSIS Package loads this
import os
import shutil
import xml.etree.ElementTree as et
from collections import OrderedDict
import pandas as pd
import fnmatch

# pathToSearch should be set to the root directory of your source code repo
# and, in Windows, will look something like this:
# "\\Users\\fred\\source\\Workspaces\\SQL\\SSIS"
pathToSearch = "F:\\_GIT\\SqlSaturday\\Python\\SSIS Packages"
# tableToFind should be set to the name of the table you want to find
tableToFind = "Listing"


# ParseFile parses the DTSX file looking for the occurence of tableToFind
def ParseFile(file, tableToFind):
    tableFound = []
    treeOrig = et.parse(file)
    rootOrig = treeOrig.getroot()
    nsDTS = ""
    DTS = {"DTS": nsDTS}
    nsSQLTask = ""
    SQLTask = {"SQLTask": nsSQLTask}
    executablesRoot = rootOrig.find("DTS:Executables", namespaces=DTS)
    if executablesRoot:
        executables = executablesRoot.findall("DTS:Executable", namespaces=DTS)
        # "SqlTaskData", namespaces={"SQLTask": nsSQLTask})
        for e in executables:
            od = e.find("DTS:ObjectData", namespaces=DTS)
            if od:
                pipelines = od.findall("pipeline")
                for pipeline in pipelines:
                    componentsElement = pipeline.find("components")
                    if componentsElement:
                        components = componentsElement.findall("component")
                        for c in components:
                            if c.attrib["componentClassID"] == "Microsoft.OLEDBDestination":
                                props = c.find("properties")
                                table = ""
                                tablevar = ""
                                for p in props:
                                    if p.attrib["name"] == "OpenRowset":
                                        table = p.text
                                    if p.attrib["name"] == "OpenRowsetVariable":
                                        tablevar = p.text
                                if table == "" and tablevar != "":
                                    table = GetTableFromVar(
                                        tablevar, rootOrig, file)
                                if table != "":
                                    if tableToFind in table.upper():
                                        cns = c.find("connections")
                                        cn = cns.find("connection")
                                        cnName = cn.attrib["connectionManagerRefId"]
                                            {"file": file,  "statementType": "OLEDB Destination", "connection": cnName})
                sqlTasks = od.findall(
                    "SQLTask:SqlTaskData", namespaces=SQLTask)
                for task in sqlTasks:
                    sql = task.attrib[f"{{{nsSQLTask}}}SqlStatementSource"].strip(
                    if sql.startswith("MERGE"):
                        words = sql[0:300].split(" ")
                        table = words[1]
                        if tableToFind in table:
                                {"file": file,  "statementType": "Merge", "sql": sql})
                    elif sql.startswith("INSERT INTO"):
                        words = sql[0:300].split(" ")
                        table = words[2]
                        if tableToFind in table:
                                {"file": file,  "statementType": "Insert Into", "sql": sql})
                    elif sql.startswith("TRUNCATE TABLE"):
                        words = sql[0:300].split(" ")
                        table = words[2]
                        if tableToFind in table:
                                {"file": file,  "statementType": "Truncate Table", "sql": sql})
                    elif sql.startswith("EXEC"):
                        words = sql[0:300].split(" ")
                        sproc = words[1]
                        result = SeeIfSprocUpdatesTable(
                            sproc, tableToFind, file)
                        if result:
                    elif "MERGE " in sql:
                        index = sql.find("MERGE ")
                        words = sql[index:index+300].split(" ")
                        table = words[1]
                        if tableToFind in table:
                                {"file": file,  "statementType": "Merge", "sql": sql})
                    elif "INSERT INTO " in sql:
                        index = sql.find("INSERT INTO ")
                        words = sql[index:index+300].split(" ")
                        table = words[2]
                        if tableToFind in table:
                                {"file": file,  "statementType": "Insert Into", "sql": sql})
                    elif "TRUNCATE TABLE " in sql:
                        index = sql.find("TRUNCATE TABLE ")
                        words = sql[index:index+300].split(" ")
                        table = words[2]
                        if tableToFind in table:
                                {"file": file,  "statementType": "Truncate Table", "sql": sql})
                    elif "INTO " in sql:
                        index = sql.find("INTO ")
                        words = sql[index:index+300].split(" ")
                        table = words[1]
                        if tableToFind in table:
                                {"file": file,  "statementType": "Select Into", "sql": sql})
    return tableFound

# GetTableFromVar is not implented yet
# The intention is to lookup the value(s) of the variable and see if it's == tableToFind

def GetTableFromVar(tablevar, rootOrig, file):
    if tablevar == "NOT IMPLEMENTED":
        return "tableName"
        return None

# SeeIfSprocUpdatesTable is not implented yet
# The intention is to look at the sproc source and see if it's == tableToFind

def SeeIfSprocUpdatesTable(sproc, tableToFind, file):
    if sproc == "NOT IMPLEMENTED":
        return {"file": file,  "statementType": "EXEC", "proc": sproc, "sql": "???"}
        return None

# Code Execution starts here
tableToFind = tableToFind.upper()
print(f"Looking for: {tableToFind}")

# Finding *.dtsx files in the supplied folder and its subfolders
allDtsxFiles = []
for dirpath, dirnames, filenames in os.walk(pathToSearch):
    if not filenames:
    dtsxFiles = fnmatch.filter(filenames, "*.dtsx")
    if dtsxFiles:
        for file in dtsxFiles:
if len(allDtsxFiles) == 0:
    print('No *.dtsx files found')
    print(f"First *.dtsx file found: {allDtsxFiles[0]}")

# Examining each file to see if the tableToFind is in there
tableFound = []
for file in allDtsxFiles:
    print(f"Checking file {file}")
    tableFound.extend(ParseFile(file, tableToFind))

# Save results as Excel file
if len(tableFound) == 0:
    print(f"{tableToFind} not found in any files")
    df = pd.DataFrame(tableFound)
    excelFile = os.path.join(pathToSearch, tableToFind + '-found.xlsx')
    print(f"Saving {excelFile}")


2) Which SSRS Data Sources are

import clr
from Microsoft.AnalysisServices.AdomdClient import (
    AdomdConnection, AdomdDataAdapter)
import datetime
import os
import shutil
import time
import xml.etree.ElementTree as et
from collections import OrderedDict
import numpy as np
import pandas as pd
import pyodbc
from System.Data import DataSet

from systemconfig import pwd, sqlserver, uid

# path should be set to the directory where the report .RDL file is
# and, in Windows, will look something like this:
# "\\Users\\fred\\source\\Workspaces\\SQL\\SSRS"
path = "F:\\_GIT\\SqlSaturday\\Python\\SSRS Reports\Report Project1"
# reportFile should be set to the name of the .RDL you want to analyze
reportFile = 'ReportWithALotOfDatasets.rdl'
# sqlServerName should be set to the name of the SQL Server the queries run against
sqlServerName = sqlserver
# ssasServerName should be set to the name of the SSAS Server the MDX queries run against
ssasServerName = "(local)"
# ssasDatabaseNames should be set to a List of the SSAS Databases the MDX queries run against
ssasDatabaseNames = ["TheCube", "TheOtherCube"]


def parseQueries(file):
    treeOrig = et.parse(file)
    rootOrig = treeOrig.getroot()

    dsnames = []
    dsns = []
    parms = []
    cmds = []
    fields = []

    i = 1
    datasets = rootOrig.find(
    for dataset in datasets.findall(
        query = dataset[0]
        dsn = query[0].text
        parm = ""
        cmd = ""
        if query[1].tag == '{}QueryParameters':
            parm = query[1].text
            cmd = query[2].text
            cmd = query[1].text
        field = dataset[1].text


        i += 1
        # This is a debugging technique.  It limits the loop to one iteration.
        # if i > 1:
        # break
    df = pd.DataFrame({"DataSets": dsnames, "DSNs": dsns, "Parms": parms,
                       "Commands": cmds, "Fields": fields})
    return df

def test_MDX(name, server, database, mdx):
    conn = AdomdConnection("Data Source=" + server + ";Catalog=" + database)
    cmd = conn.CreateCommand()
    # you might need to add parameters here
    cmd.CommandText = mdx

        print("Trying: " + name)
        start = time.time_ns()
        adp = AdomdDataAdapter(cmd)
        datasetParam = DataSet()
        end = time.time_ns()
        result = {"Name": name, "DB": database,
                  "SQL": sql, "Time": end - start, "Missing": False,
                  "Rows": datasetParam.Tables[0].Rows.Count}
        result = {"Name": name, "DB": database,
                  "SQL": sql, "Time": -1, "Missing": True,
                  "Rows": 0}
    return result

def test_SQL(name, server, database, sql):
    connstring = "Driver={ODBC Driver 17 for SQL Server};Server=" + \
        server + ";Database=" + database + ";UID=" + uid + ";PWD=" + pwd
    conn = pyodbc.connect(connstring)
    cursor = conn.cursor()
    result = ""
        print("Trying: " + name)
        start = time.time_ns()
        rows = cursor.fetchall()
        end = time.time_ns()
        result = {"Name": name, "DB": database,
                  "SQL": sql, "Time": end - start, "Missing": False,
                  "Rows": len(rows)}
        result = {"Name": name, "DB": database,
                  "SQL": sql, "Time": -1, "Missing": True, "Rows": 0}
    return result

# Code Execution starts here
file = os.path.join(path, reportFile)
df = parseQueries(file)
date1 = str(
# Uncomment the next line to save a list of the Datasets and their SQL to an Excel file
# df.to_excel(os.path.join(path, date1 + f"_{reportFile}_ReportQueries.xlsx"))
print("Number of Datasets to Check: " + str(df["DataSets"].count()))

commands = []
for i in range(0, df["DataSets"].count()):
    row = df.iloc[i, :]
    name = row["DataSets"]
    database = row["DSNs"]
    sql = row["Commands"]

    if database in ssasDatabaseNames:
        server = ssasServerName
        commands.append(test_MDX(name, server, database, sql))
        server = sqlServerName
        commands.append(test_SQL(name, server, database, sql))

dfSql = pd.DataFrame(commands)
dfSql["Seconds"] = dfSql['Time'] / 1000000000
excelFile = os.path.join(
    path, date1 + f"_{reportFile}_ReportQueryResults.xlsx")
print(f"Saving {excelFile}")

3. Geocoding

import clr
import os
import shutil
import xml.etree.ElementTree as et
from collections import OrderedDict
import numpy as np
import pandas as pd
import datetime
import pyodbc
import time
import json
import requests
from Microsoft.AnalysisServices.AdomdClient import AdomdConnection, AdomdDataAdapter
from System.Data import DataSet

from systemconfig import api_key, sqlserver, uid, pwd

database = "AdventureWorks2016"
# The Places Table/View should have 6 columns:
# PrimaryKeyField, City, State, Country, Latitude and Longitude
placesTable = "dbo.Places"
# This is the Primary Key Field for the placesTable
placesPKField = "PlaceId"
# Set this parameter to a small number for debugging,
# and set it larger than the number of rows in your placesTable to do them all
maxGeocodingCalls = 25


connstring = "Driver={ODBC Driver 17 for SQL Server};Server=" + \
    sqlserver+";Database="+database+";UID=omwtm-sa;Pwd=" + pwd
baseurl = f'{api_key}'

def LoadCities():
    sql = f"SELECT * FROM {placesTable} WHERE ISNULL(Latitude, 0) = 0"
    rows = LoadDataSet(sql)
    cities = []
    for row in rows:
        cities.append([row[0], row[1], row[2], row[3], 0, 0, False])
    return cities

def LoadDataSet(sql):
    conn = pyodbc.connect(connstring)
    cursor = conn.cursor()
    rows = cursor.fetchall()
    return rows

def ExecuteSql(conn, sql):
    cursor = conn.cursor()

def GeocodeCities(cities):
    i = 1
    for c in cities:
        print(f"Geocoding: {c[1]}, {c[2]}, {c[3]}")
        url = baseurl + f'&address={c[1]},{c[2]},{c[3]}&components=country:{c[3]}'
        geo_data = requests.get(url).json()
        if geo_data["status"] == "OK":
            lat = geo_data["results"][0]["geometry"]["location"]["lat"]
            lng = geo_data["results"][0]["geometry"]["location"]["lng"]
            c[4] = lat
            c[5] = lng
            i += 1
            # this break statement aborts the loop so it only calls
            # the google API maxGeocodingCalls number of times
            if i > maxGeocodingCalls:

def UpdateCities(cities):
    conn = pyodbc.connect(connstring)
    conn.autocommit = True
    for c in cities:
        if (c[4] != 0 or c[5] != 0) and c[6] == False:
            print(f"Updating: {c[1]}, {c[2]}, {c[3]}")
            placeId = c[0]
            sql = f"UPDATE {placesTable} " + \
                f"SET Latitude = {c[4]}, Longitude = {c[5]} " + \
                f"WHERE {placesPKField} = {placeId}"
            ExecuteSql(conn, sql)
            c[6] = True

# Code Execution starts here
cities = LoadCities()
# for Debugging:  print(cities)
# print(cities[0])

# for Debugging:  print(cities)
# print(cities[0])

# for Debugging:  print(cities)
# print(cities[0])



create table Places (
  PlaceId int not null identity constraint PlacesPK primary key,
  City nvarchar(50),
  StateProvince nvarchar(50),
  CountryRegion nvarchar(50),
  Latitude numeric(18, 6),
  Longitude numeric(18, 6)
insert into Places (City, StateProvince, CountryRegion)
  distinct City,
  s.Name as StateProvince,
  c.Name as CountryRegion
from Person.Address a
inner join Person.StateProvince s on a.StateProvinceID = s.StateProvinceID
inner join Person.CountryRegion c on s.CountryRegionCode = c.CountryRegionCode

api_key = ""
sqlserver = ""
uid = ""
pwd = ""

SQL Saturday Nashville – January 2020

I will be speaking at SQL Saturday Nashville on Saturday, January 18th at 8:30 am. The topic is:

Data Bricks, Spark, Machine Learning and Azure Synapse Analytics

An end-to-end example of Data in the cloud.

You’ve heard about Azure Data Lake and Azure Data Warehouse, now called Azure Synapse Analytics. You’ve also heard about Azure Data Factory and Azure Data Bricks. You might even have heard about Python, Spark, and Azure Machine Learning. In this fast-paced, all-demo session, we will walk through the process of ingesting data into the Data Lake, analyzing it with Spark and Machine Learning, outputting it to the Data Warehouse and reporting on it in Power BI. You will walk away with working code and an overall understanding of how all these tools can help you develop advanced analytics solutions in the modern data landscape.


The sample data file created in Exercise 1 and used in the remaining Exercises:

Data bricks, Spark, Machine Learning and Azure Synapse Analytics Slide Deck and Step-by-step instructions:

2019 University of Scouting – Dutch Oven Cooking

Cast Iron Cookware

What is a Dutch Oven?

Dutch oven is a thick-walled cooking pot with a tight-fitting lid. Dutch ovens are usually made of seasoned cast iron; however, some Dutch ovens are instead made of cast aluminium, or ceramic. Some metal varieties are enameled rather than being seasoned (see next section).

Acquiring a Dutch Oven

You can start your Dutch Oven journey at Walmart or Amazon.

Dutch Ovens come in many shapes and sizes. Typically, in Scouting, we use standard 10-inch diameter (4 Quart) and 12-inch (6 Quart) ovens.

You want to make sure you get a flanged lid for putting coals on top. Some dutch ovens are for home use and have dome style lids.

What else do I need?

How much money do you have to spend?

In order of preference, I recommend the following:

  • A Lid Lifter $5-10 (while the right stick can work, a lid lifter is very handy)
  • Charcoal Starter/Chimney $10-20
  • Welding gloves $15-20
  • Dutch Oven Care Kit – Scrubber, Scraper, Oil, Cast Iron Soap $15-50
  • A Boy Scout Firestarter $40

Preparing your Dutch Oven for Use

Great news! Your cast iron cookware is probably pre-seasoned at the factory so you can just dive in and use it. If it is, skip ahead the next part

Seasoning your Dutch Oven

Seasoning is the process of treating the surface of a cooking vessel with heated fat in order to produce a corrosion-resistant and stick-resistant coating.

Food sticks easily to a new bare metal pan; it must either be oiled before use, or seasoned. The coating known as seasoning is initially created by a process of layering a very thin coat of oil on the pan. Then, the oil is polymerized to the metal’s surface with high heat for a time. The base coat will darken with use. This process is known as “seasoning”; the color of the coating is commonly known as its “patina”.

To season a pan (e.g., to season a new pan, or to replace damaged seasoning on an old pan), the following is a typical process:

  1. cleaning the cookware to remove residues from manufacturing or manufacturer-applied anti corrosion coating and expose the bare metal,
  2. applying a thin layer of animal fat or cooking oil (ranging from vegetable oil to lard, including many common food-grade oils), and
  3. heating the cookware to generate the seasoned coating.[5][6][7][8]

If it is not pre-seasoned, a new cast iron skillet or dutch oven typically comes from the manufacturer with a protective coating of wax or shellac, otherwise it would rust. This needs to be removed before the item is used.[9] An initial scouring with hot soapy water will usually remove the protective coating. Alternatively, for woks, it is common to burn off the coating over high heat (outside or under a vent hood) to expose the bare metal surface. For already-used pans that are to be re-seasoned, the cleaning process can be more complex, involving rust removal and deep cleaning (with strong soap or lye,[10] or by burning in a campfire or self-cleaning oven[11]) to remove existing seasoning and build-up. Once the pan has been heated, dried, and thinly layered with oil or fat, it is placed in an oven, grill, or other heating enclosure for the oil to be polymerized onto the metal’s surface. The process of polymerization is dependent on the oil, temperature of the enclosure, and the duration. The precise details of the seasoning process differ from one source to another, and there is much disagreement regarding the correct oil to use. There is also no clear consensus about the best temperature and duration. Lodge Manufacturing uses a proprietary soybean blend in their base coats as stated on their website. Others use lard, or animal fats. Some advocate the use of food-grade flaxseed oil (a drying oil).[12] The temperature recommended for seasoning varies from high temperatures above 260 °C (500 °F) to temperatures below 150 °C (302 °F). Some say that a temperature around the smoke point of the oil or fat should be targeted since this will allow vaporization of the lighter hydrocarbons from the oil, leaving behind heavier molecules for optimal polymerization and carbonization to occur. And, there is also no consensus on the correct duration of heating: from half an hour to an hour is often recommended.

Storing your Dutch Oven

After use Dutch ovens are typically cleaned like other cast-iron cookware: with boiling water, and a soft brush or sponge. Where possible, a cleaned and freshly oiled Dutch oven should be stored in a clean, dry location with the lid ajar or off to promote air circulation and to avoid the smell and taste of rancid oil. If the Dutch oven must be stored with the lid on, a paper towel or piece of newspaper should be placed inside the oven to absorb any moisture.

Cooking in a Dutch Oven

The Dutch Oven Dude’s advice about Cooking temperature is excellent.


Here are some links to Dutch Oven Recipes:

Master Chef Contest Winners

Drum roll, please … find the winners of the Scouting magazine Dutch Oven Master Chef Contest below. Click on each winning recipe to see photos and find instructions on how to make these on your next campout.

SAVORY Category

SWEET Category


Here are some links to useful Dutch Oven articles:

Byron’s Dutch Oven Cooking

Apparently, Byron’s Dutch Oven Cooking site (without a doubt the best resource for Dutch Oven cooking) has been removed from the internet. There are some pages archived in the Internet Way Back Machine here.

The entire site has been reconstituted into a PDF file, downloadable here.

2019 University of Scouting – Winter Camping Fun

Troop Camping in the Winter Months


1st Rule:  Be prepared for any weather in any extreme.

2nd Rule:  Plan for cold, wet, windy weather.  (And be grateful when it’s not.)

3rd Rule:  Plan for the Scouts to be under-prepared for extreme (especially wet) conditions.


There are three key principles to keep in mind when planning a winter campout:

  1. Stay dry – wear waterproof outer layer; change clothes before going to sleep; wet clothes + cold weather = uncomfortably cold Scout, and serious risk of Hypothermia.
  2. Dress in layers – wear a wicking base layer (polyester), insulating middle layer (fleece or wool), and water/wind resistant outer layer (ideally Gore-Tex material).
  3. Avoid cotton material – it absorbs moisture and dries too slowly, and wet clothes draw heat away from the body at an alarming rate.


Stay Warm, Stay Dry, Stay Hydrated



Sun/wind burn

Make sure that you have a good knowledge of the signs of frostbite and hypothermia. You should be able to recognize it in others and in yourself. Tell someone right away if you or another scout is showing signs of cold-related problems.

Keep out of the wind if you can. A rain fly for a tent can be pitched to serve as a wind break. The wind chill factor can often be considerable and can result in effective temperatures being much lower than nominal.

Bring extra WATER. It’s easy to get dehydrated in the winter. You aren’t visibly sweating, so you don’t think to drink water, but since the air is so dry, you lose a LOT of water through breathing. Drink lots of water!


Polyester materials are intended to wick sweat away from the skin (e.g., Under Armor T-Shirts).  Sweat wicking material is often disguised under other material names such as: nylon, polypropylene, capilene, spandex, and lycra. If it is made with more than 40% cotton, it is NOT a satisfactory wicking material.

The key to cold weather camping is to stay warm and dry. Bring both light and heavy weight clothing in order to “layer” if the weather is cold. Scouts should remove layers if they start to overheat and sweat. For base layer (i.e., underwear, socks, t-shirt), bring at least one change per full day of camping.

Everyone must be dry by sundown. No wet (sweaty) bodies or wet inner clothing.

Dress in layers, the trapped air helps keep you warm, and you can shed layers if you warm up.

STAY DRY!! If you get wet, make sure you change into dry clothes as soon as possible. In order to do that, you must have more than 1 article of clothing with you. For example, 3 pairs of wool socks, 2 pairs of pants, etc.

NO COTTON clothing as your primary clothing. NO JEANS!  (This is especially true in the snow or icy cold rain.)

Make sure you have snow pants, nylon wind pants, or wool pants, and polypropylene or wool long underwear.


Dress right while sleeping. Change into clean, dry clothes before bed. Your body makes moisture and your clothes hold it in – by changing into dry clothes you will stay warmer and it will help keep the inside of your sleeping bag dry. Wearing wool socks and long underwear (tops and bottoms) in the sleeping bag is OK.

Put on tomorrow’s t- shirt and underwear at bedtime. That way you won’t be starting with everything cold next to your skin in the morning.  Put tomorrow’s clothes in your bag with you to take up space in the bag and to warm them for the morning.

Put a couple of long-lasting hand warmers into your boots after you take them off. Your boots will dry out during the night.

Don’t sleep directly on the ground. Get a closed cell foam pad to provide insulation between your sleeping bag and the ground. A foam pad cushions and insulates. The air pockets are excellent in providing good insulation properties. Use more than one insulating layer below you – it’s easy to slide off the first one.

No cots! Better to lay on 30F earth instead of -10F air.

If in tents, leave the tent flaps/zippers vented a bit, it cuts down on interior frost.

Drain your bladder before you go to bed. Having to go in the middle of the night when it is 5 degrees out chills your entire body. Drink all day but stop one hour before bed.


Bring extra food that doesn’t need to be heated or cooked. Granola bars, trail mix, etc.

Keep a pot of hot water available for cocoa or Cup-a-Soup – these warm from the inside.

Always eat hot meals (breakfast, lunch, & dinner.) Dutch ovens are the best – they keep the food hot longer. It doesn’t need to be fancy DO cooking. Meals should be 1-pot meals to keep cleanup to a minimum. Don’t get too fancy with the meals – it’s hard to chop onions & carrots at -10F with gloves on. Prep all meals at home in the warmth of the kitchen.

Shelter the cooking area from wind (walls of tarps, etc.)

Fill coffee/cook pots with water before bed. It’s hard to pour frozen water, but easy to thaw it if it’s already in the pot.

Eat a high-energy snack before bed, then brush your teeth. The extra fuel will help your body stay warm. Take a Snickers bar to bed and eat it if you wake up chilly in the night.


Always bring a bit more than what you think you’ll need – water, food, clothes.

Winter Camping Games and Fun

Broom Hockey:  play hockey on a lake or pond using brooms for hockey sticks and a tennis ball for a puck.

Water Machine Contest:  a water machine is simply a old burlap bag or other porous material (tarp).  Gather snow in the bag or on a tarp, gather the top or the corners and tie off the too.  Then hang the bag or tarp with the snow in it near a fire.  Put a pot or No. 10 can below to catch.  Have Scouts start from scratch by gathering wood and building a tire as well as gathering snow.  This promotes teamwork and gives everyone in the Patrol something to do.  The first  patrol to “make” a quart (or gallon) of water wins.  The water machine is also an excellent technique for maintaining a continual water supply while winter camping.

Snow Golf:  the same as miniature golf, except that the fairways are snow covered and the greens are packed down areas with a tin can buried in the snow for the hole.  The golf balls are hockey pucks hit with old golf clubs. 

Learn the Basics of Winter Photography: sponsor a winter photography contest by Patrols or individuals.

Exploring:  no phase of Scoutcraft can better form motive for a long hike than exploring the Woods in Winter.  Exploring (and mapping) a given tract of woodland will prove rich in all around Scout training.  It will furnish instruction, recreation and exercise.  It will involve not only technical practice in surveying and map-making but also cooking, camping and woodcraft in general.  The instructive side will be interesting in itself and one may rest assured that the games, stunts and story-telling contests around the campfire will have unusual energy.  

Patrol Animals Snow Sculpture Contest:  The actual carving of statuary is another fascinating pastime.

Mystery games like Murder in the Dark and Mafia are a great option when you’re sitting around the campfire at night. No cards or table needed and the darkness and night noises will help make the game more mysterious.

Corn Hole, Ladder Toss, Bocce Ball are all good choices for no snow winter camping. Anything that keeps the gloves on and keeps the Scouts active will be enjoyable.

Winter Camping in Middle Tennessee

Expect the Scouts to wear jeans and a hoodie in cold weather.  This is plenty to get them from the front door to the bus stop in cold weather, it should be fine for Scout camp too, right?

Except it’s not.  Encourage them to pack and wear warmer clothing, in layers, and to at least bring a waterproof layer in case it rains, sleets, or snows over the campout.  Also, be certain to build a fire, not a pretty fire that’s nice to look at, a warm fire that can heat up cold hands and cold, wet bodies.

Winter Camping “up North”

If you’re camping in the snow, wear snow pants over your regular clothing

Bring extra hand covering – mittens are warmer than gloves.

Bring 2 changes of socks per day.

Fill a couple of Nalgene water bottles with warm water and sleep with one between your legs (warms the femoral artery) and with one at your feet. Or use toe/hand warmers. Toss them into your sleeping bag before you get in. Some of the toe/hand warmers will last 8 hours.


Use a sleeping bag that is appropriate for the conditions. Two +20F sleeping bags, one inside the other will work to lower the rating of both bags.

Use a bivvy sack to wrap around your sleeping bag. You can make a cheap version of this by getting an inexpensive fleece sleeping bag. It isn’t much more than a blanket with a zipper, but it helps lower the rating by as much as 10 degrees.

Use a sleeping bag liner. There are silk and fleece liners that go inside the sleeping bag. They will lower your sleeping bag’s rating by up to 10 degrees. Or buy an inexpensive fleece throw or blanket and wrap yourself in it inside the sleeping bag.

Most cold weather bags are designed to trap heat. The proper way to do this is to pull the drawstrings until the sleeping bag is around your face, not around your neck. If the bag also has a draft harness, make sure to use it above the shoulders and it snugs up to your neck to keep cold air from coming in and warm air from going out.

Don’t burrow in – keep your mouth and nose outside the bag. Moisture from your breath collecting in your bag is a quick way to get really cold. Keep the inside of the bag dry.

A zipped-up coat pulled over the foot of a sleeping bag makes an extra layer of insulation.

Winter Camping Kit List


  • Sleeping bag – warm bag, ideally rated as a “zero degree” bag or better
  • Wool or fleece blankets – to put over and under sleeping bag as extra insulation if sleeping bag is not rated as “zero degree” (adds 10-20 degrees of warmth)
  • Pillow (optional)
  • Ground pad – either foam pad or Therm-A-Rest pad
  • Stuff sack for sleeping bag (preferably waterproof sack)


  • At least 3 polyester underwear
  • At least 3 pairs of heavy socks with liner socks.  NOT cotton sweat socks.
  • At least 3 polyester base shirts – long or short sleeve (worn against skin)
  • 1-2 insulating fleece pullovers or wool sweaters
  • Hooded sweat shirt and sweat pants to sleep in (this can be cotton for sleeping at night)
  • Insulated coat/ jacket that is wind/water resistant – suitable for camping environment
  • Winter stocking cap that covers entire head and ears
  • Balaclava or ski mask to cover head and face (optional)
  • Bandana or handkerchief
  • 2 pair warm gloves or mittens (outer material should be wind/water resistant)
  • Winter boots (with adequate insulation and waterproof material)
  • Extra Pair of footwear – sneakers are OK as supplement to winter boots; Crocks/sandals are NOT appropriate footwear for winter camping
  • Rain gear (poncho or water-resistant pants/top shell)

Other Items

  • Back pack or duffel bag for personal gear
  • Garbage bags to store your clothes (and keep them dry)
  • Wash kit – Soap, wash cloth, towel, comb, deodorant, toothbrush, toothpaste, sunscreen, lip balm, toilet paper, feminine hygiene products
  • Mess kit – drinking cup, bowl, plate, and utensils with your name on it
  • Boy Scout Handbook (in a plastic, zip-lock bag)
  • Water bottle or canteen
  • Headlamp (preferred), or Flashlight, with extra batteries
  • Compass (optional)
  • Camping chair (optional)
  • Sunglasses
  • Personal first-aid kit
  • Medicines and medical supplies (Must co-ordinate with adult leader)
  • Toboggan/sled (Optional)
  • Pocket knife (Optional)
  • Whistle

Troop Provided Items

  • Tents
  • Cooking equipment, food and cleaning supplies
  • First-aid kit
  • Snow shovel
  • Rope, twine
  • Ground sheet, tarps for under tents
  • Fire starter, fuel, firewood, etc.
  • Toilet paper
  • Duct tape
  • Trash bags
  • Rubber gloves
  • Cards


Winter Camping Tips, Checklists and Preparation

Winter Camping Games and Fun