Unpacking Software Livestream

Join our monthly Unpacking Software livestream to hear about the latest news, chat and opinion on packaging, software deployment and lifecycle management!

Learn More

Chocolatey Product Spotlight

Join the Chocolatey Team on our regular monthly stream where we put a spotlight on the most recent Chocolatey product releases. You'll have a chance to have your questions answered in a live Ask Me Anything format.

Learn More

Chocolatey Coding Livestream

Join us for the Chocolatey Coding Livestream, where members of our team dive into the heart of open source development by coding live on various Chocolatey projects. Tune in to witness real-time coding, ask questions, and gain insights into the world of package management. Don't miss this opportunity to engage with our team and contribute to the future of Chocolatey!

Learn More

Calling All Chocolatiers! Whipping Up Windows Automation with Chocolatey Central Management

Webinar from
Wednesday, 17 January 2024

We are delighted to announce the release of Chocolatey Central Management v0.12.0, featuring seamless Deployment Plan creation, time-saving duplications, insightful Group Details, an upgraded Dashboard, bug fixes, user interface polishing, and refined documentation. As an added bonus we'll have members of our Solutions Engineering team on-hand to dive into some interesting ways you can leverage the new features available!

Watch On-Demand
Chocolatey Community Coffee Break

Join the Chocolatey Team as we discuss all things Community, what we do, how you can get involved and answer your Chocolatey questions.

Watch The Replays
Chocolatey and Intune Overview

Webinar Replay from
Wednesday, 30 March 2022

At Chocolatey Software we strive for simple, and teaching others. Let us teach you just how simple it could be to keep your 3rd party applications updated across your devices, all with Intune!

Watch On-Demand
Chocolatey For Business. In Azure. In One Click.

Livestream from
Thursday, 9 June 2022

Join James and Josh to show you how you can get the Chocolatey For Business recommended infrastructure and workflow, created, in Azure, in around 20 minutes.

Watch On-Demand
The Future of Chocolatey CLI

Livestream from
Thursday, 04 August 2022

Join Paul and Gary to hear more about the plans for the Chocolatey CLI in the not so distant future. We'll talk about some cool new features, long term asks from Customers and Community and how you can get involved!

Watch On-Demand
Hacktoberfest Tuesdays 2022

Livestreams from
October 2022

For Hacktoberfest, Chocolatey ran a livestream every Tuesday! Re-watch Cory, James, Gary, and Rain as they share knowledge on how to contribute to open-source projects such as Chocolatey CLI.

Watch On-Demand

Downloads:

7,539

Downloads of v 2024.6.26:

145

Last Update:

26 Jun 2024

Package Maintainer(s):

Software Author(s):

  • Bill Curran
  • asheroto

Tags:

bcurran3 cnc choco unofficial nuspec checker validator script chocolateasy

(unofficial) Chocolatey .nuspec Checker (CNC) (Script)

  • 1
  • 2
  • 3

2024.6.26 | Updated: 26 Jun 2024

Downloads:

7,539

Downloads of v 2024.6.26:

145

Software Author(s):

  • Bill Curran
  • asheroto

(unofficial) Chocolatey .nuspec Checker (CNC) (Script) 2024.6.26

Legal Disclaimer: Neither this package nor Chocolatey Software, Inc. are affiliated with or endorsed by Bill Curran, asheroto. The inclusion of Bill Curran, asheroto trademark(s), if any, upon this webpage is solely to identify Bill Curran, asheroto goods or services and not for commercial purposes.

  • 1
  • 2
  • 3

This Package Contains an Exempted Check

Not All Tests Have Passed


Validation Testing Passed


Verification Testing Passed

Details

Scan Testing Exemption for this package version only:

This is an issue with package-scanner, and not with this particular package.

Details
Learn More

Deployment Method: Individual Install, Upgrade, & Uninstall

To install (unofficial) Chocolatey .nuspec Checker (CNC) (Script), run the following command from the command line or from PowerShell:

>

To upgrade (unofficial) Chocolatey .nuspec Checker (CNC) (Script), run the following command from the command line or from PowerShell:

>

To uninstall (unofficial) Chocolatey .nuspec Checker (CNC) (Script), run the following command from the command line or from PowerShell:

>

Deployment Method:

NOTE

This applies to both open source and commercial editions of Chocolatey.

1. Enter Your Internal Repository Url

(this should look similar to https://community.chocolatey.org/api/v2/)


2. Setup Your Environment

1. Ensure you are set for organizational deployment

Please see the organizational deployment guide

2. Get the package into your environment

  • Open Source or Commercial:
    • Proxy Repository - Create a proxy nuget repository on Nexus, Artifactory Pro, or a proxy Chocolatey repository on ProGet. Point your upstream to https://community.chocolatey.org/api/v2/. Packages cache on first access automatically. Make sure your choco clients are using your proxy repository as a source and NOT the default community repository. See source command for more information.
    • You can also just download the package and push it to a repository Download

3. Copy Your Script

choco upgrade choco-nuspec-checker -y --source="'INTERNAL REPO URL'" [other options]

See options you can pass to upgrade.

See best practices for scripting.

Add this to a PowerShell script or use a Batch script with tools and in places where you are calling directly to Chocolatey. If you are integrating, keep in mind enhanced exit codes.

If you do use a PowerShell script, use the following to ensure bad exit codes are shown as failures:


choco upgrade choco-nuspec-checker -y --source="'INTERNAL REPO URL'" 
$exitCode = $LASTEXITCODE

Write-Verbose "Exit code was $exitCode"
$validExitCodes = @(0, 1605, 1614, 1641, 3010)
if ($validExitCodes -contains $exitCode) {
  Exit 0
}

Exit $exitCode

- name: Install choco-nuspec-checker
  win_chocolatey:
    name: choco-nuspec-checker
    version: '2024.6.26'
    source: INTERNAL REPO URL
    state: present

See docs at https://docs.ansible.com/ansible/latest/modules/win_chocolatey_module.html.


chocolatey_package 'choco-nuspec-checker' do
  action    :install
  source   'INTERNAL REPO URL'
  version  '2024.6.26'
end

See docs at https://docs.chef.io/resource_chocolatey_package.html.


cChocoPackageInstaller choco-nuspec-checker
{
    Name     = "choco-nuspec-checker"
    Version  = "2024.6.26"
    Source   = "INTERNAL REPO URL"
}

Requires cChoco DSC Resource. See docs at https://github.com/chocolatey/cChoco.


package { 'choco-nuspec-checker':
  ensure   => '2024.6.26',
  provider => 'chocolatey',
  source   => 'INTERNAL REPO URL',
}

Requires Puppet Chocolatey Provider module. See docs at https://forge.puppet.com/puppetlabs/chocolatey.


4. If applicable - Chocolatey configuration/installation

See infrastructure management matrix for Chocolatey configuration elements and examples.

WARNING

This package is exempt from moderation. While it is likely safe for you, there is more risk involved.

Description


choco://choco-nuspec-checker

To use choco:// protocol URLs, install (unofficial) choco:// Protocol support


Screenshot of (unofficial) Chocolatey .nuspec Checker (CNC) (Script)

Original Author

CNC was originally created by Bill Curran. The original repo can be found here.

Description

choco-nuspec-checker (CNC) is a PowerShell script I designed for Chocolatey package maintainers/creators to check Chocolatey .nuspec files for common errors and omissions... and automatically fix most of them! Find out AND FIX what the Chocolatey validator is going to tell you BEFORE you submit your package. CNC also goes beyond it's original scope and checks for common Chocolatey install/uninstall script errors and omissions as well.

FEATURES:

  • CNC checks all .nuspec elements and reports any missing or template default values, now recursively too!
  • CNC checks for all verifier messages (guidelines, suggestions, and notes) and reports them if applicable
  • CNC checks for dead URLs and reports them
  • CNC checks for GitHub direct links, reports them, and can convert them to various CDN URLs (default=Staticaly)
  • CNC checks for RawGit CDN links, reports them, and can convert them to various CDN URLs (default=Staticaly)
  • CNC can open all your .nuspec element URLs in your default browser for quick viewing
  • CNC checks and reports current status of your package on chocolatey.org
  • CNC can add a standard template header, footer, and/or package notes to your .nuspec description with variables
  • CNC checks nuspec and PowerShell scripts for correct UTF-8 encoding and reports if the encoding is incorrect
  • CNC can re-write your nuspec in UTF-8 w/o BOM format
  • CNC can re-write your PowerShell scripts in UTF-8 w/ BOM format
  • CNC checks all your PowerShell scripts for syntax errors
  • CNC checks chocolateyInstall.ps1 for improper use of Install-ChocolateyPackage and Install-ChocolateyZipPackage when binaries are included
  • CNC checks for and can add $ErrorActionPreference = 'Stop' to your PowerShell scripts
  • CNC can optimize image files in your nuspec directory
  • CNC can be run from the Command Prompt AND PowerShell
  • CNC and more...

Helps make packaging Chocolateasy!

INSTRUCTIONS:

  • CNC -help for help with options and switches
  • Run CNC to check the .nuspec in your current directory or run CNC X:\SOMEWHERE to check the .nuspec in that directory. (Do not specify the file, just the directory.)

PACKAGE NOTES


tools\.SkipAutoUninstaller
 
tools\ChocolateyInstall.ps1
$ErrorActionPreference = 'Stop'

$toolsDir    = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
$scriptDir   = "$(Get-ToolsLocation)\BCURRAN3"
$script      = 'CNC.ps1'

# Setup
# New storage location moving forward for all my Chocolatey scripts
if (!(Test-Path "$(Get-ToolsLocation)\BCURRAN3")) { New-Item -Path "$(Get-ToolsLocation)" -Name "BCURRAN3" -ItemType "Directory" | Out-Null }

# Migration
# Move files before v2019.08.26 from old to new storage location
if (Test-Path "$ENV:ChocolateyInstall\bin\$script") { Remove-Item "$ENV:ChocolateyInstall\bin\$script" -Force }
if (Test-Path "$ENV:ChocolateyInstall\bin\CNCHeader.txt") { Move-Item "$ENV:ChocolateyInstall\bin\CNCHeader.txt" "$scriptDir" -Force }
if (Test-Path "$ENV:ChocolateyInstall\bin\CNCFooter.txt") { Move-Item "$ENV:ChocolateyInstall\bin\CNCFooter.txt" "$scriptDir" -Force }
if (Test-Path "$scriptDir\CNC.cmd") { Remove-Item "$scriptDir\CNC.cmd" -Force | Out-Null } # in v2019.08.26 only

# Install
# Move new files and support files (if applicable)
Move-Item "$toolsDir\$script" "$scriptDir" -Force
if (!(Test-Path "$scriptDir\CNC.config")) { Move-Item "$toolsDir\CNC.config" "$scriptDir" -Force }
Install-ChocolateyPowershellCommand -PackageName 'CNC' -PSFileFullPath "$scriptDir\$script"
# Below files not used after migrating to .config file
#if (!(Test-Path "$scriptDir\CNCHeader.txt")) { Move-Item "$toolsDir\CNCHeader.txt" "$scriptDir" -Force }
#if (!(Test-Path "$scriptDir\CNCFooter.txt")) { Move-Item "$toolsDir\CNCFooter.txt" "$scriptDir" -Force }
#if (!(Test-Path "$scriptDir\CNCPackageNotes.txt")) { Move-Item "$toolsDir\CNCPackageNotes.txt" "$scriptDir" -Force }

# Cleanup
Remove-Item "$toolsDir\CNC*.*" -Force -ErrorAction SilentlyContinue | Out-Null
tools\ChocolateyUninstall.ps1
$ErrorActionPreference = 'Stop'

$scriptDir = "$(Get-ToolsLocation)\BCURRAN3"

Remove-Item "$ENV:ChocolateyInstall\bin\CNC.bat" -Force | Out-Null
Remove-Item "$scriptDir\CNC*.*" -Force | Out-Null
if (!(Get-ChildItem -Path "$scriptDir" | Measure-Object | % { $_.Count })) {
    $ENV:Path.Replace("$scriptDir", "") | Out-Null
    Remove-Item "$scriptDir" | Out-Null
}
tools\CNC.config
<?xml version="1.0"?>
<Settings>
  <Preferences>
    <CDN>jsDelivr</CDN>
    <MakeBackups>false</MakeBackups>
    <Offline>false</Offline>
    <OptimizeImages>false</OptimizeImages>
    <ReduceOutput>false</ReduceOutput>
    <UpdateAll>false</UpdateAll>
    <UpdateImageURLs>false</UpdateImageURLs>
    <AddHeader>false</AddHeader>
    <AddFooter>false</AddFooter>
    <AddPackageNotes>false</AddPackageNotes>
    <Header>
---

###[choco://$NuspecID](choco://$NuspecID)
To use choco:// protocol URLs, install [(unofficial) choco:// Protocol support ](https://chocolatey.org/packages/choco-protocol-support)

--- 
    </Header>
    <Footer>
---

$NuspecTitle packaged with pride by $NuspecOwners.

---
    </Footer>
    <PackageNotes>
**[PACKAGE NOTES](https://github.com/$NuspecOwners/ChocolateyPackages/blob/master/$NuspecID/readme.md)**
    </PackageNotes>
  </Preferences>
</Settings>

<!--
LEGEND:

CDN             - Which CDN to convert image links to: jsDelivr (default), GitHack, GitCDN
MakeBackups     - Make filename.ext.CNC.BAK of all modified files. (true/false)
Offline         - Offline mode
OptimizeImages  - Automatically run PNGOptimizerCL on package image files. (true/false)
UpdateAll       - Automatically right all CNC correctable wrongs.
UpdateImageURLs - Automatically converts GitHub raw links to use a CDN
AddHeader       - Use the header. (true/false)
AddFooter       - Use the footer. (true/false)
AddPackageNotes - Use package notes. (true/false)
Header          - Header message to insert at top of package description
Footer          - Footer message to insert at bottom of package description.
PackageNotes    - Package notes message to insert near bottom of package description.
-->
tools\CNC.ps1
# $ErrorActionPreference = 'Stop'
# CNC.ps1 Copyleft 2018-2024 by Bill Curran (BCURRAN3) and asheroto
# LICENSE: GNU GPL v3 - https://www.gnu.org/licenses/gpl.html
# Open a GitHub issue at https://github.com/asheroto/choco-nuspec-checker/issues if you have suggestions for improvement.

# REF: https://docs.microsoft.com/en-us/nuget/reference/nuspec
# REF: https://docs.chocolatey.org/en-us/community-repository/moderation/package-validator/rules/

<#
.SYNOPSIS
   Script to check your Chocolatey .nuspec files for common errors and ommisions.
.DESCRIPTION
    CNC checks all .nuspec elements and reports any missing or template default values, now recursively too!
    CNC checks for all verifier messages (guidelines, suggestions, and notes) and reports them if applicable
    CNC checks for dead URLs and reports them
    CNC checks for GitHub direct links, reports them, and can convert them to various CDN URLs (default=Staticaly)
    CNC checks for RawGit CDN links, reports them, and can convert them to various CDN URLs (default=Staticaly)
    CNC can open all your .nuspec element URLs in your default browser for quick viewing
    CNC checks and reports current status of your package on chocolatey.org
    CNC can add a standard template header, footer, and/or package notes to your .nuspec description with variables
    CNC checks nuspec and PowerShell scripts for correct UTF-8 encoding and reports if the encoding is incorrect
    CNC can re-write your nuspec in UTF-8 w/o BOM format
    CNC can re-write your PowerShell scripts in UTF-8 w/ BOM format
    CNC checks all your PowerShell scripts for syntax errors
    CNC checks chocolateyInstall.ps1 for improper use of Install-ChocolateyPackage and Install-ChocolateyZipPackage when binaries are included
    CNC checks for and can add $ErrorActionPreference = 'Stop' to your PowerShell scripts
    CNC can optimize PNG files in your nuspec directory if PNGOptimizer.commandline is installed
    CNC can be run from the Command Prompt AND PowerShell
.EXAMPLE
    cnc
    To check the .nuspec file in your current directory
.EXAMPLE
    cnc -UpdateAll
    Fix the .nuspec file in your current directory
.EXAMPLE
    cnc -Recurse -Path C:\Path\To\Packages\Repo
    To check all the .nuspec files in a package sources repository

.PARAMETER help
   Displays this information.
.PARAMETER ?
   Displays this information.
.PARAMETER AddFooter
   Adds and saves a footer from $CNCFooter to your <description>.
.PARAMETER AddHeader
   Adds and saves a header from $CNCHeader to your <description>.
.PARAMETER AddPackageNotes
   Adds and saves a package notes link from $CNCPackageNotes to your <description>.
.PARAMETER EditFooter
   Edit $CNCFooter with Notepad++ or Notepad.
.PARAMETER EditHeader
   Edit $CNCHeader with Notepad++ or Notepad.
.PARAMETER EditPackageNotes
   Edit $CNCPackageNotes with Notepad++ or Notepad.
.PARAMETER MakeBackups
   Make filename.ext.CNC.BAK of all modified files.
.PARAMETER OpenURLs
   Opens all URLs in your browser for inspection when finished.
.PARAMETER OpenValidatorInfo
   Opens the Chocolatey package-validator info page on GitHub in your default browser.
.PARAMETER ShowFooter
   Displays $CNCFooter.
.PARAMETER ShowHeader
   Displays $CNCHeader.
.PARAMETER ShowPackageNotes
   Displays $PackageNotes.
.PARAMETER OptimizeImages
   Runs PNGOptimizerCL on PNG files and jpegoptim on JPG files.
.PARAMETER Recurse
   Runs CNC recursively.
.PARAMETER ReduceOutput
   Reduces output to just problems that will trigger the validator.
.PARAMETER ReducedOutput
   Reduces output to just problems that will trigger the validator.
.PARAMETER Update
   Re-writes your nuspec file; e.g. change to UTF-8 w/o BOM.
.PARAMETER UpdateAll
   Rights all wrongs!
.PARAMETER UpdateImageURLs
   Updates image URLs with Staticaly CDN URLs (default).
.PARAMETER UpdateScripts
   Re-writes your PowerShell scripts with fixes, e.g. change to UTF-8 w/BOM, and add ErrorActionPreference=Stop.
.PARAMETER UpdateXMLComment
   Updates the XML comment for UTF-8 checking.
.PARAMETER UpdateXMLDeclaration
   Updates the XML declaration.
.PARAMETER UpdateXMLNamespace
   Updates the XML Namespace
.PARAMETER UseGitHack
   Use GitHack for image URLs replacement, for use with -UpdateImageURLs or -UpdateAll.
.PARAMETER UseGitCDN
   Use GitCDN for image URLs replacement, for use with -UpdateImageURLs or -UpdateAll.
.PARAMETER UsejsDelivr
   Use jsDeliver for image URLs replacement, for use with -UpdateImageURLs or -UpdateAll.
.PARAMETER WhatIf
   Test run, don't save changes.

.LINK
   https://github.com/chocolatey/package-validator/wiki
.LINK
   https://docs.chocolatey.org/en-us/community-repository/moderation/package-validator/rules/

#>

param (
    [string]$Path = (Get-Location).path,
    [Alias("?")][switch]$Help,
    [switch]$AddFooter,
    [switch]$AddHeader,
    [switch]$AddPackageNotes,
    [switch]$Debug,
    [switch]$EditFooter,
    [switch]$EditHeader,
    [switch]$EditPackageNotes,
    [switch]$MakeBackups,
    [switch]$OpenURLs,
    [switch]$OpenValidatorInfo,
    [switch]$OptimizeImages,
    [switch]$Recurse,
    [switch]$ReduceOutput,
    [switch]$ReducedOutput,
    [switch]$ShowFooter,
    [switch]$ShowHeader,
    [switch]$ShowPackageNotes,
    [switch]$Update,
    [switch]$UpdateAll,
    [switch]$UpdateImageURLs,
    [switch]$UpdateScripts,
    [switch]$UpdateXMLComment,
    [switch]$UpdateXMLDeclaration,
    [switch]$UpdateXMLNamespace,
    [switch]$UseGitHack,
    [switch]$UsegitCDN,
    [switch]$UsejsDelivr,
    [switch]$WhatIf
)

Write-Host "CNC.ps1 v2024.06.26 - (unofficial) Chocolatey .nuspec Checker ""CNC - Run it through the Bill.""" -Foreground White
Write-Host "Copyleft 2018-2024 Bill Curran (BCURRAN3) & asheroto - free for personal and commercial use`n" -Foreground White

# Verify ChocolateyToolsLocation was created by Get-ToolsLocation during install and is in the environment
if (!($ENV:ChocolateyToolsLocation)) { $ENV:ChocolateyToolsLocation = "$ENV:SystemDrive\tools" }
if (!(Test-Path "$ENV:ChocolateyToolsLocation\BCURRAN3")) { Write-Warning "Configuration not found. Please re-install."; throw }

# parameters and variables -------------------------------------------------------------------------------------

$PSDefaultParameterValues['*:Encoding'] = 'utf8'
$AcceptableIconExts = @("png", "svg")
# All 7Zip supported formats plus EXE, MSU, MSP, APPX, APPXBUNDLE, IMG - What else is needed?
$BinaryExtensions = @("*.exe", "*.img", "*.msu", "*.msp", "*.appx", "*.appxbundle", "*.7z", "*.xz", "*.bzip2", "*.gzip", "*.tar", "*.zip", "*.wim", "*.ar", "*.arj", "*.cab", "*.chm", "*.cpio", "*.cramfs", "*.dmg", "*.ext", "*.fat", "*.gpt""*.hfs", "*.ihex", "*.iso", "*.lzh", "*.lzma", "*.mbr", "*.msi", "*.nsis", "*.ntfs", "*.qcow2", "*.rar", "*.rpm", "*.squashfs", "*.udf", "*.uefi", "*.vdi", "*.vhd", "*.vmdk", "*.xar", "*.z")
$CDNlist = "https://www.staticaly.com, https://raw.githack.com, https://gitcdn.link, or https://www.jsdelivr.com"
$CNCHeader = "$ENV:ChocolateyToolsLocation\BCURRAN3\CNCHeader.txt"
$CNCFooter = "$ENV:ChocolateyToolsLocation\BCURRAN3\CNCFooter.txt"
$CNCPackageNotes = "$ENV:ChocolateyToolsLocation\BCURRAN3\CNCPackageNotes.txt"
$JPGOptimizer = (Test-Path $ENV:ChocolateyInstall\bin\jpegoptim.exe)
$PNGOptimizer = (Test-Path $ENV:ChocolateyInstall\bin\PngOptimizerCL.exe)
$NewCDN = "Staticly"
$StaticlyCDN = $True
$XMLComment = "Do not remove this test for UTF-8: if `“Ω`” doesn`’t appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one."
$XMLNamespace = "http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"
# <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">

## Import preferences - see comments in CNC.config for settings
#[xml]$ConfigFile = Get-Content "$scriptDir\CNC.config"
#$UpdateAll       = $ConfigFile.Settings.Preferences.UpdateAll
#$CDN             = $ConfigFile.Settings.Preferences.CDN
#$MakeBackups     = $ConfigFile.Settings.Preferences.MakeBackups
#$OptimizeImages  = $ConfigFile.Settings.Preferences.OptimizeImages
#$Header          = $ConfigFile.Settings.Preferences.Header
#$Footer          = $ConfigFile.Settings.Preferences.Footer
#$PackageNotes    = $ConfigFile.Settings.Preferences.PackageNotes

#$UseHeader       = $ConfigFile.Settings.Preferences.UseHeader
#$UseFooter       = $ConfigFile.Settings.Preferences.UseFooter
#$UsePackageNotes = $ConfigFile.Settings.Preferences.UsePackageNotes

if ($help) {
    Get-Help $MyInvocation.MyCommand.Definition -Detailed
    return
}

if (Test-Path $ENV:ChocolateyInstall\bin\notepad++.exe) {
    $Editor = "notepad++.exe"
} else {
    $Editor = "notepad.exe"
}

if ($EditFooter) {
    Write-Host "  ** Editing contents of $CNCFooter." -Foreground Magenta
    &$Editor $CNCFooter
    return
}

if ($EditHeader) {
    Write-Host "  ** Editing contents of $CNCHeader." -Foreground Magenta
    &$Editor $CNCHeader
    return
}

if ($EditPackageNotes) {
    Write-Host "  ** Editing contents of $CNCPackageNotes." -Foreground Magenta
    &$Editor $CNCPackageNotes
    return
}

if ($ShowFooter) {
    Write-Host "  ** Displaying contents of $CNCFooter." -Foreground Magenta
    Write-Host ""
    Get-Content $CNCFooter
    return
}

if ($ShowHeader) {
    Write-Host "  ** Displaying contents of $CNCHeader." -Foreground Magenta
    Write-Host ""
    Get-Content $CNCHeader
    return
}

if ($ShowPackageNotes) {
    Write-Host "  ** Displaying contents of $CNCPackageNotes." -Foreground Magenta
    Write-Host ""
    Get-Content $CNCPackageNotes
    return
}

if ($OpenValidatorInfo) {
    Write-Host "  ** Opening https://docs.chocolatey.org/en-us/community-repository/moderation/package-validator/rules/." -Foreground Magenta
    Write-Host ""
    &start https://docs.chocolatey.org/en-us/community-repository/moderation/package-validator/rules/
    return
}

if ($ReducedOutput) { $ReduceOutput = $True }

if ($Update) { $GLOBAL:UpdateNuspec = $True }

if ($UpdateAll) {
    $UpdateAll = $True
    $UpdateImageURLs = $True
    $OptimizeImages = $True
    $UpdateScripts = $True
    $UpdateXMLComment = $True
    $UpdateXMLDeclaration = $True
    $UpdateXMLNamespace = $True
    $GLOBAL:AddPS1EAP = $True
    $GLOBAL:UpdateNuspec = $True
} else {
    $UpdateAll = $False
}

if ($UseGitHack) {
    $GitHackCDN = $True
    $StaticlyCDN = $False
    $NewCDN = "GitHack"
} else {
    $GitHackCDN = $False
}

if ($UsegitCDN) {
    $GitCDN = $True
    $StaticlyCDN = $False
    $NewCDN = "GitCDN"
} else {
    $GitCDN = $False
}

if ($UsejsDelivr) {
    $jsDelivrCDN = $True
    $StaticlyCDN = $False
    $NewCDN = "jsDelivr"
} else {
    $jsDelivrCDN = $False
}

if ($path -eq "\") {
    $path = (Get-Location).Drive.Name + ":" + "\"
}

if (!(Test-Path $path)) {
    Write-Host "           ** $path is an invalid path." -Foreground Red
    return
}

# BEGIN FUNCTIONS ------------------------------------------------------------------------------------------------

# Borrowed and slightly modified from
# https://blogs.technet.microsoft.com/samdrey/2014/03/26/determine-the-file-encoding-of-a-file-csv-file-with-french-accents-or-other-exotic-characters-that-youre-trying-to-import-in-powershell/
# UTF-8 w/o BOM reports as ASCII. ASCII is a subset of UTF-8.

function Get-FileEncoding {
    [CmdletBinding()] Param (
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [string]$Path
    )

    [byte[]]$byte = get-content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $Path

    if ($byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf)
    { Write-Output 'UTF-8 w/ BOM' }
    elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff)
    { Write-Output 'Unicode' }
    elseif ($byte[0] -eq 0 -and $byte[1] -eq 0 -and $byte[2] -eq 0xfe -and $byte[3] -eq 0xff)
    { Write-Output 'UTF-32' }
    elseif ($byte[0] -eq 0x2b -and $byte[1] -eq 0x2f -and $byte[2] -eq 0x76)
    { Write-Output 'UTF-7' }
    else
    { Write-Output 'ASCII or UTF-8 w/o BOM' }
}

# Get iconUrl dimensions
# Supports BMP, GIF, EXIF, JPG, PNG and TIFF
# Will error on URLs such as
# https://lh3.googleusercontent.com/n6kpA-xZE_0iEy9A8WkJpGT45XB6MEq09t9UdBoIrCfwIoBm3CA9gqI13AqbBN6yx7GwVDjx=s26-h26-e365-rw
function Get-ImageDimensions {
    if ($NuspecIconURL -Match '.SVG') {
        Write-Host "           ** <iconUrl> - SVG image found. It's a vector Victor - no dimensions. We have clearance, Clarence." -Foreground Green
        return
    }
    Write-Host "(Downloading icon)" -NoNewLine -Foreground Magenta
(New-Object System.Net.WebClient).DownloadFile($NuspecIconURL, "$pwd\iconURL.image")
    Write-Host "`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b                  `b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b" -NoNewLine
    if (Test-Path "$pwd\iconURL.image") {
        $ErrorAction = 'SilentlyContinue'
        add-type -AssemblyName System.Drawing
        $ErrorActionPreference = 'SilentlyContinue'
        $image = New-Object System.Drawing.Bitmap "$pwd\iconURL.image"
        $height = $image.height
        $width = $image.width
        $image.dispose()
        $ErrorActionPreference = 'Continue'
        if (($height -lt 128) -and ($width -lt 128)) {
            if (!$height) { $height = "?" }
            if (!$width) { $width = "?" }
            Write-Warning "  ** <iconUrl> - icon dimensions are h$height x w$width."
            if (!$ReduceOutput) {
                Write-Host "           ** Suggestion: Use package icons with at least 128 pixels in width or height if available." -Foreground Cyan
            }
            $GLOBAL:Suggestions++
        }
        Remove-Item "$pwd\iconURL.image" -Force
    }
}

# Borrowed from
# https://web.archive.org/web/20160430132409/http://powershell.org:80/wp/forums/topic/how-to-check-syntax-of-scripts-automatically/
function Test-PowerShellSyntax {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string[]]
        $Path
    )

    process {
        foreach ($scriptPath in $Path) {
            $contents = Get-Content -Path $scriptPath

            if ($null -eq $contents) {
                continue
            }

            $errors = $null
            $null = [System.Management.Automation.PSParser]::Tokenize($contents, [ref]$errors)

            New-Object psobject -Property @{
                Path              = $scriptPath
                SyntaxErrorsFound = ($errors.Count -gt 0)
            }
        }
    }
}

# Validate that URL elements are actually URLs and verify the URLs are good
# Thanks https://stackoverflow.com/questions/23760070/the-remote-server-returned-an-error-401-unauthorized
function Validate-URL([string]$element, [string]$url) {
    if (($url -match 'http://') -or ($url -match 'https://')) {
        Write-Host "(Validating URL)" -NoNewLine -Foreground Magenta
        $HTTP_Response = $null
        $HTTP_Request = [System.Net.WebRequest]::Create($url)
        try {
            $HTTP_Response = $HTTP_Request.GetResponse()
            Write-Host "`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b                `b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b" -NoNewLine
            $HTTP_Status = [int]$HTTP_Response.StatusCode
            if ($HTTP_Status -eq 200) {
                $GLOBAL:ValidURL = $True
            } else {
                Write-Host "`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b                `b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b" -NoNewLine
                Write-Warning ("  ** $element - the URL:`n              $url`n site might be OK, status code:" + $HTTP_Status)
                if ($element -notmatch ".PS1") {
                    if (!$ReduceOutput) {
                        Write-Host "           ** Suggestion: Consider using CNC's -OpenURLs option to open and view all URLs in the .nuspec." -Foreground Cyan
                    }
                } else {
                    if (!$ReduceOutput) {
                        Write-Host "           ** Suggestion: Check your download link, it appears to be bad." -Foreground Cyan
                    }
                }
                $GLOBAL:Suggestions++
                $GLOBAL:ValidURL = $False
            }
            $HTTP_Response.Close()
        } catch {
            $HTTP_Status = [regex]::matches($_.exception.message, "(?<=\()[\d]{3}").Value
            Write-Host "`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b                `b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b" -NoNewLine
            if ($element -notmatch ".PS1") {
                Write-Host "WARNING:   ** $element - the URL:`n              $url`n              is possibly bad, status code: $HTTP_Status. This will trigger a message from the verifier:" -Foreground Red
                if (!$ReduceOutput) {
                    Write-Host "           ** Requirement: The $element element in the nuspec file should be a valid Url. Please correct this" -Foreground Cyan
                    Write-Host "           ** Suggestion: Consider using CNC's -OpenURLs option to open and view all URLs in the .nuspec." -Foreground Cyan
                }
                $GLOBAL:Required++
            } else {
                if ($url -match '\$') {
                    if (!$ReduceOutput) {
                        Write-Host "FYI:       ** $element - URL appears to have a script specfic variable in it, skipping URL validation..." -Foreground Yellow
                        Write-Host "           ** $element - $url" -Foreground Cyan
                    }
                    $GLOBAL:FYIs++
                    return
                }
                Write-Warning ("  ** $element - the URL:`n              $url`n              site might be OK, status code: $HTTP_Status.")
                if ($IncludedBinaries) {
                    Write-Host "           ** Suggestion: Check your download link, it appears to be bad." -Foreground Cyan
                }
                $GLOBAL:Suggestions++
            }
            $GLOBAL:ValidURL = $False
        }
        if ($url -match 'http://') {
            Write-Host "FYI:       ** $element - URL is using HTTP instead of HTTPS which is more secure." -Foreground Yellow
            if (!$ReduceOutput) {
                Write-Host "           ** $element - Suggestion: Consider checking if:" -Foreground Cyan
                Write-Host "              $url" -Foreground Cyan
                Write-Host "              is available using https:// instead." -Foreground Cyan
            }
            $GLOBAL:FYIs++
        }
    }
}

# Check for license files when binaries are included
function Check-LicenseFile {
    $LicenseFile = (Get-ChildItem -Path $path -Include *LICENSE* -Recurse)
    if ($LicenseFile) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** Binary files - $LicenseFile.Name file(s) found." -ForegroundColor Green
        }
        $GLOBAL:FYIs++
    } else {
        Write-Host "WARNING:   ** Binary files - LICENSE.txt file NOT found. This will trigger a message from the verifier:" -Foreground Red
        if ($IncludedBinaries) {
            Write-Host "           ** Requirements: Binary files (.exe, .msi, .zip, etc) have been included without including a LICENSE.txt`n              file. This file is required when including binaries " -Foreground Cyan
        }
        $GLOBAL:Required++
    }
}

# Check for verification file when binaries are included
function Check-VerificationFile {
    $VerificationFile = (Get-ChildItem -Path $path -Include *VERIFICATION* -Recurse)
    if ($VerificationFile) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** Binary files - $VerificationFile.Name file(s) found." -ForegroundColor Green

        }
        $GLOBAL:FYIs++
    } else {
        Write-Host "WARNING:   ** Binary files - VERIFICATION.txt file NOT found. This will trigger a message from the verifier:" -Foreground Red
        if ($IncludedBinaries) {
            Write-Host "           ** Requirements: Binary files (.exe, .msi, .zip) have been included without including a VERIFICATION.txt`n              file. This file is required when including binaries" -Foreground Cyan
        }
        $GLOBAL:Required++
    }
}

# check for binaries
function Check-Binaries {
    $IncludedBinaries = (Get-ChildItem -Path $path -Include $BinaryExtensions -Recurse)
    if ($IncludedBinaries) {
        Write-Warning "  ** Binary files found in package. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host "           ** Note: Binary files (.exe, .msi, .zip) have been included. The reviewer will ensure the maintainers have`n              distribution rights." -Foreground Cyan
        }
        $GLOBAL:Notes++
        Check-LicenseFile
        Check-VerificationFile
    }
}

# check for OS index files that should be excluded
function Check-OSIndexFiles {
    $NotWanted = (Get-ChildItem -Path $path -Include "*.ds_store", "thumbs.db" -Recurse)
    if ($NotWanted) {
        Write-Host "WARNING:   ** Operating System index files found in directory. If found in the package, this will trigger a message`n              from the verifier:" -Foreground Red
        if (!$ReduceOutput) {
            Write-Host "           ** Required: The package contains Operating System index files, .ds_store or thumbs.db. Please remove all`n              index files from the package. " -Foreground Cyan
        }
        $GLOBAL:Required++
    }
}

# check for JPG files for possible optimization
function Check-JPGs {
    $ImageFiles = (Get-ChildItem -Path $path -Include *.JPG, *.JPEG -Recurse)
    if ($ImageFiles) {
        if (!$ReduceOutput) {
            Write-Host 'FYI:       ** Binary files - JPG or JPEG image file(s) found.' -Foreground Yellow
        }
        $GLOBAL:FYIs++
        if (!$OptimizeImages) {
            if (!$ReduceOutput) {
                Write-Host '           ** Suggestion: Consider running CNC -OptimizeImages to optimize your image file(s).' -Foreground Cyan
            }
            $GLOBAL:Suggestions++
        }
    }
}

# check for PNG files for possible optimization
function Check-PNGs {
    $ImageFiles = (Get-ChildItem -Path $path -Include *.PNG, *.BMP, *.GIF, *.TGA -Recurse)
    if ($ImageFiles) {
        if (!$ReduceOutput) {
            Write-Host 'FYI:       ** Binary files - PNG, BMP, GIF, or TGA image file(s) found.' -Foreground Yellow
        }
        $GLOBAL:FYIs++
        if (!$OptimizeImages) {
            if (!$ReduceOutput) {
                Write-Host '           ** Suggestion: Consider running CNC -OptimizeImages to optimize your image file(s).' -Foreground Cyan
            }
            $GLOBAL:Suggestions++
        }
    }
}

# I'm making an educated guess that these are requirements to be fixed, not verified.
function Check-PackageInternalFilesIncluded {
    if (Test-Path '`[Content_Types`].xml') {
        Write-Host "WARNING:   ** [Content_Types].xml file found. This will trigger a message from the verifier:" -Foreground Red
        if (!$ReduceOutput) {
            Write-Host "           ** Required: You have repackaged an existing package that you unpacked without removing some of the `n              packaging files from the original." -Foreground Cyan
        }
        $GLOBAL:Required++
    }
    if (Test-Path *.psmd) {
        Write-Host "WARNING:   ** PSMD file(s) found. This will trigger a message from the verifier:" -Foreground Red
        if (!$ReduceOutput) {
            Write-Host "           ** Required: You have repackaged an existing package that you unpacked without removing some of the `n              packaging files from the original." -Foreground Cyan
        }
        $GLOBAL:Required++
    }
    if (Test-Path *.rels) {
        Write-Host "WARNING:   ** RELS file(s) found. This will trigger a message from the verifier:" -Foreground Red
        if (!$ReduceOutput) {
            Write-Host "           ** Required: You have repackaged an existing package that you unpacked without removing some of the `n              packaging files from the original." -Foreground Cyan
        }
        $GLOBAL:Required++
    }
    if (Test-Path _rels) {
        Write-Host "WARNING:   ** _RELS directory found. This will trigger a message from the verifier:" -Foreground Red
        if (!$ReduceOutput) {
            Write-Host "           ** Required: You have repackaged an existing package that you unpacked without removing some of the `n              packaging files from the original." -Foreground Cyan
        }
        $GLOBAL:Required++
    }
}

# check if header template is in the description
function Check-Header {
    $NuspecDescription = $NuspecDescription.Trim()
    if ($NuspecDescription.StartsWith("***") -or $NuspecDescription.StartsWith("---") -or $NuspecDescription.StartsWith("___")) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** <description> - header template found." -Foreground Green
        }
        $GLOBAL:FYIs++
        $GLOBAL:FoundHeader = $True
    } else {
        $GLOBAL:FoundHeader = $False
        $GLOBAL:Suggestions++
        if (!($AddPackageNotes) -and !($ReduceOutput)) {
            if (!$ReduceOutput) {
                Write-Host '           ** Suggestion: Consider adding a header and help propagate (unofficial) choco:// Protocol support' -Foreground Cyan
            }
        }
	   }
}

# add header template to <description>
function Add-Header {
    if ($GLOBAL:FoundHeader) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** <description> - header template previously added." -Foreground Cyan
        }
        $GLOBAL:FYIs++
        return $NuspecDescription
    }
    if (Test-Path $CNCHeader) {
        $Header = [IO.File]::ReadAllText($CNCHeader)
        if ($Header -match '\$NuspecAuthors') { $Header = $Header -replace '\$NuspecAuthors', "$NuspecAuthors" }
        if ($Header -match '\$NuspecID') { $Header = $Header -replace '\$NuspecID', "$NuspecID" }
        if ($Header -match '\$NuspecOwners') { $Header = $Header -replace '\$NuspecOwners', "$NuspecOwners" }
        if ($Header -match '\$NuspecTitle') { $Header = $Header -replace '\$NuspecTitle', "$NuspecTitle" }
        if ($Header -match '\$NuspecVersion') { $Header = $Header -replace '\$NuspecVersion', "$NuspecVersion" }
        $NuspecDescription = "`n" + $Header + $NuspecDescription + "`n"
        Write-Host "           ** <description> - ADDED header template." -Foreground Green
        $GLOBAL:UpdateNuspec = $True
        $GLOBAL:Fixes++
        return $NuspecDescription
    } else {
        Write-Warning "           ** $CNCHeader not found."
        return $NuspecDescription
    }
}

# check if footer template is in the description
function Check-Footer {
    $NuspecDescription = $NuspecDescription.Trim()
    if ($NuspecDescription.EndsWith("***") -or $NuspecDescription.EndsWith("---") -or $NuspecDescription.EndsWith("___")) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** <description> - footer template found." -Foreground Green
        }
        $GLOBAL:FYIs++
        $GLOBAL:FoundFooter = $True
    } else {
        $GLOBAL:FoundFooter = $False
    }
}

# add footer template to <description>
function Add-Footer {
    if ($GLOBAL:FoundFooter) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** <description> - footer template previously added." -Foreground Cyan
        }
        $GLOBAL:FYIs++
        return $NuspecDescription
    }
    if (Test-Path $CNCFooter) {
        $Footer = [IO.File]::ReadAllText($CNCFooter)
        if ($Footer -match '\$NuspecAuthors') { $Footer = $Footer -replace '\$NuspecAuthors', "$NuspecAuthors" }
        if ($Footer -match '\$NuspecID') { $Footer = $Footer -replace '\$NuspecID', "$NuspecID" }
        if ($Footer -match '\$NuspecOwners') { $Footer = $Footer -replace '\$NuspecOwners', "$NuspecOwners" }
        if ($Footer -match '\$NuspecTitle') { $Footer = $Footer -replace '\$NuspecTitle', "$NuspecTitle" }
        if ($Footer -match '\$NuspecVersion') { $Footer = $Footer -replace '\$NuspecVersion', "$NuspecVersion" }
        $NuspecDescription = $NuspecDescription + "`n" + $Footer + "`n"
        Write-Host "           ** <description> - ADDED footer template." -Foreground Green
        $GLOBAL:UpdateNuspec = $True
        $GLOBAL:Fixes++
        return $NuspecDescription
    } else {
        Write-Warning "           ** $CNCFooter NOT found."
        return $NuspecDescription
    }
}

# check if package release notes are in the description
function Check-PackageNotes {
    $NuspecDescription = $NuspecDescription.Trim()
    if (($NuspecDescription -match 'PACKAGE NOTES') -or ($NuspecDescription -match 'PACKAGE RELEASE NOTES')) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** <description> - package release notes found." -Foreground Green
        }
        $GLOBAL:FYIs++
        $GLOBAL:FoundPackageNotes = $True
    } else {
        $GLOBAL:FoundPackageNotes = $False
        $GLOBAL:Suggestions++
        if (!($AddPackageNotes) -and (!$ReduceOutput) ) {
            Write-Host '           ** Suggestion: Consider adding PACKAGE NOTES to inform users of any special information about the package.' -Foreground Cyan
        }
    }
}

# add package notes template to <description>
function Add-PackageNotes {
    if ($GLOBAL:FoundPackageNotes) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** <description> - package notes template previously added." -Foreground Cyan
        }
        $GLOBAL:FYIs++
        return $NuspecDescription
    }
    if (Test-Path $CNCPackageNotes) {
        $PackageNotes = [IO.File]::ReadAllText($CNCPackageNotes)
        if ($PackageNotes -match '\$NuspecAuthors') { $PackageNotes = PackageNotes -replace '\$NuspecAuthors', "$NuspecAuthors" }
        if ($PackageNotes -match '\$NuspecID') { $PackageNotes = $PackageNotes -replace '\$NuspecID', "$NuspecID" }
        if ($PackageNotes -match '\$NuspecOwners') { $PackageNotes = $PackageNotes -replace '\$NuspecOwners', "$NuspecOwners" }
        if ($PackageNotes -match '\$NuspecTitle') { $PackageNotes = $PackageNotes -replace '\$NuspecTitle', "$NuspecTitle" }
        if ($PackageNotes -match '\$NuspecVersion') { $PackageNotes = $PackageNotes -replace '\$NuspecVersion', "$NuspecVersion" }
        $NuspecDescription = $NuspecDescription + "`n" + $PackageNotes + "`n"
        Write-Host "           ** <description> - ADDED package notes template." -Foreground Green
        $GLOBAL:UpdateNuspec = $True
        $GLOBAL:Fixes++
        return $NuspecDescription
    } else {
        Write-Warning "           ** $CNCPackageNotes NOT found."
        return $NuspecDescription
    }
}

# check Markdown header problems after chocolatey.org Sept. 2019 updates
function Check-Markdown([string]$element, [string]$text) {
    if ($text -match "#\w") {
        # alphanumeric whitespace only (no /, [, etc)
        Write-Host "WARNING:   ** $element - invalid Markdown heading syntax found. This will trigger a message from the verifier:" -Foreground Red
        if (!$ReduceOutput) {
            Write-Host "           ** Required: nuspec should not contain invalid Markdown Headings." -Foreground Cyan
        }
        $lines = $text.Split([Environment]::NewLine)
        $lines | % { if ($_ -match '#\w') { Write-Host "           ** $element - $_" -Foreground Red } }
        $GLOBAL:Required++
    }
}

# TDL
# Add whitespace after #, ##, and ### when found followed by characters, need to verify # is not part of a URL first
function Fix-Markdown {
}

# Check package current status on chocolatey.org
function Check-OnlineStatus {
    $PackagePageInfo = try { (Invoke-WebRequest -Uri "https://chocolatey.org/packages/$NuspecID" -UseBasicParsing -DisableKeepAlive).StatusCode }catch [Net.WebException] { [int]$_.Exception.Response.StatusCode }
    if ($PackagePageInfo -eq '404') {
        Write-Host "FYI:       ** This appears to be a brand new package. Cool!" -Foreground Green
        $GLOBAL:FYIs++
        return
    }
    $PackagePageInfo = (Invoke-WebRequest -DisableKeepAlive -Uri "https://chocolatey.org/packages/$NuspecID")
    if ($PackagePageInfo -match 'a trusted package') {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** $NuspecID is a trusted package. (Congrats!)" -Foreground Green
        }
        $GLOBAL:FYIs++
    }
    if ($PackagePageInfo -match 'Verification Testing Exemption') {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** $NuspecID is exempted from verification testing." -Foreground Green
        }
        $GLOBAL:FYIs++
    }
    if ($PackagePageInfo -match 'All Checks are Passing') {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** $NuspecID current status: All Checks are Passing" -Foreground Green
        }
        $GLOBAL:FYIs++
    }
    if (($NuspecID -ne 'choco-nuspec-checker') -and ($PackagePageInfo -match '
Some Checks Have Failed or Are Not Yet Complete')) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** $NuspecID current status:
Some Checks Have Failed or Are Not Yet Complete" -Foreground Red
        }
        $GLOBAL:FYIs++
    }
    if ($PackagePageInfo -match 'There are versions of this package awaiting moderation') {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** $NuspecID has submitted versions pending moderation." -Foreground Yellow
        }
        $GLOBAL:FYIs++
    }
    if ($PackagePageInfo -match 'Waiting for Maintainer') {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** $NuspecID may have a version waiting for corrective action." -Foreground Yellow
        }
        $GLOBAL:FYIs++
    }
}

# Open all .nuspec URLs for viewing
function Open-URLs {
    if ($NuspecBugTrackerURL) { &start $NuspecBugTrackerURL }
    if ($NuspecDocsURL) { &start $NuspecDocsURL }
    if ($NuspecIconURL) { &start $NuspecIconURL }
    if ($NuspecLicenseURL) { &start $NuspecLicenseURL }
    if ($NuspecMailingListURL) { &start $NuspecMailingListURL }
    if ($NuspecPackageSourceURL) { &start $NuspecPackageSourceURL }
    if ($NuspecProjectSourceURL) { &start $NuspecProjectSourceURL }
    if ($NuspecProjectURL) { &start $NuspecProjectURL }
}

# Run jpegoptim on jpeg/jpg files
function Run-JPGOptimizer {
    if ($OptimizeImages) {
        if (!$JPGOptimizer) {
            Write-Warning "  ** -OptimizeImages parameter given but jpegoptim.exe not found."
            Write-Host "           ** Run choco install jpegoptim to optimize JPG files." -Foreground Cyan
            return
        }
        $ImageFiles = (Get-ChildItem -Path $path -Include *.JPG, *.JPEG -Recurse)
        if ($ImageFiles) {
            Write-Host "           ** Running jpegoptim on supported image files." -Foreground Green
            if ($WhatIf) {
                Write-Host "CNC did NOT optimize your image files, -WhatIf parameter was used." -Foreground Magenta
            } else {
                $ImageFiles | % { jpegoptim $_ }
            }
            $GLOBAL:Fixes++
        }
    }
}

# Run PNGOptimizerCL on supported image files
function Run-PNGOptimizer {
    if ($OptimizeImages) {
        if (!$PNGOptimizer) {
            Write-Warning "  ** -OptimizeImages parameter given but PNGOptimizerCL.exe not found."
            Write-Host "           ** Run choco install pngoptimizer.commandline to optimize PNG/BMP/GIF/TGA files." -Foreground Cyan
            return
        }
        $ImageFiles = (Get-ChildItem -Path $path -Include *.PNG, *.BMP, *.GIF, *.TGA -Recurse)
        if ($ImageFiles) {
            Write-Host "           ** Running PNGOptimzerCL on supported image files." -Foreground Green
            if ($WhatIf) {
                Write-Host "CNC did NOT optimize your image files, -WhatIf parameter was used." -Foreground Magenta
            } else {
                if ($MakeBackups) {
                    &pngoptimizercl.exe -file:""$path/"" -recurs -BackupOldPngFiles
                } else {
                    &pngoptimizercl.exe -file:""$path/"" -recurs
                }
                $GLOBAL:Fixes++
            }
        }
    }
}

# TODO check for "main" when GH stops making new repos with "master" in 10/2020
# Convert RawGit and non-CDN URLs to supported CDN URLs
function Update-CDNURL([string]$oldURL) {
    if ($StaticlyCDN) {
        if ($oldURL -match 'https://raw.githubusercontent.com') { $StaticalyURL = ($oldURL -replace 'https://raw.githubusercontent.com', 'https://cdn.staticaly.com/gh') }
        if ($oldURL -match 'https://cdn.rawgit.com') { $StaticalyURL = ($oldURL -replace 'https://cdn.rawgit.com', 'https://cdn.staticaly.com/gh') }
        $GLOBAL:UpdateNuspec = $True
        $GLOBAL:Fixes++
        return $StaticalyURL
    }
    if ($GitCDN) {
        if ($oldURL -match 'https://raw.githubusercontent.com') { $GitCNDURL = ($oldURL -replace 'https://raw.githubusercontent.com', 'https://gitcdn.link/repo') }
        if ($oldURL -match 'https://cdn.rawgit.com') { $GitCNDURL = ($oldURL -replace 'https://cdn.rawgit.com', 'https://gitcdn.link/repo') }
        $GLOBAL:UpdateNuspec = $True
        $GLOBAL:Fixes++
        return $GitCNDURL
    }
    if ($GitHackCDN) {
        if ($oldURL -match 'https://raw.githubusercontent.com') { $GitHackURL = ($oldURL -replace 'https://raw.githubusercontent.com', 'https://rawcdn.githack.com') }
        if ($oldURL -match 'https://cdn.rawgit.com') { $GitHackURL = ($oldURL -replace 'https://cdn.rawgit.com', 'https://rawcdn.githack.com') }
        $GLOBAL:UpdateNuspec = $True
        $GLOBAL:Fixes++
        return $GitHackURL
    }
    if ($jsDelivrCDN) {
        # this will fail if link is not to the master branch
        if ($oldURL -match 'https://raw.githubusercontent.com') {
            $jsDelivrURL = ($oldURL -replace 'https://raw.githubusercontent.com', 'https://cdn.jsdelivr.net/gh')
            $jsDelivrURL = ($jsDelivrURL -replace 'master/', '')
        }
        if ($oldURL -match 'https://cdn.rawgit.com') {
            $jsDelivrURL = ($oldURL -replace 'https://cdn.rawgit.com', 'https://cdn.jsdelivr.net/gh')
            $jsDelivrURL = ($jsDelivrURL -replace 'master/', '')
        }
        $GLOBAL:UpdateNuspec = $True
        $GLOBAL:Fixes++
        return $jsDelivrURL
    }
}

# Update the nuspec XML declaration with encoding info
function Update-XMLDeclaration {
    Write-Host "           ** XML declaration changed to version=""1.0"" encoding=""utf-8""" -Foreground Green
    $nuspecFile.xml = "version=""1.0"" encoding=""utf-8"""
    $GLOBAL:Fixes++
    $GLOBAL:UpdateNuspec = $True
}

# Update the nuspec with any changes and save as UTF-8 w/o BOM
# Thanks https://stackoverflow.com/questions/8160613/powershell-saving-xml-and-preserving-format
function Update-nuspec {
    if ($GLOBAL:UpdateNuspec) {
        $UpdatednuspecFile = [xml]([System.IO.File]::ReadAllText($LocalnuspecFile))
        $UpdatednuspecFile.PreserveWhitespace = $true
        $settings = New-Object System.Xml.XmlWriterSettings
        $settings.Indent = $true
        $settings.NewLineChars = "`r`n"
        $settings.Encoding = New-Object System.Text.UTF8Encoding($false)

        # changes
        if ($UpdateXMLComment -and !$nuspecFile.'#comment') {
            $UpdatednuspecFile.InsertAfter($UpdatednuspecFile.CreateComment($XMLComment), $UpdatednuspecFile.FirstChild) | Out-Null
        }
        if ($nuspecFile.xml) {
            $UpdatednuspecFile.xml = $nuspecFile.xml
        }
        if ($nuspecFile.package.metadata.description.'#cdata-section') {
            # CDATA section found, not changing it
        } else {
            $UpdatednuspecFile.package.metadata.description = $NuspecDescription
        }
        if ($NuspecIconURL) {
            $UpdatednuspecFile.package.metadata.iconurl = $NuspecIconURL
        }
        if ($MakeBackups) {
            Copy-Item "$LocalnuspecFile" "$LocalnuspecFile.CNC.bak" -Force
        }

        $xfile = [System.Xml.XmlWriter]::Create($LocalnuspecFile, $settings)
        try {
            $UpdatednuspecFile.Save($xfile)
        } finally {
            $xfile.Dispose()
        }
    }
}

# checks PowerShell scripts for $ErrorActionPreference statement
function Check-PS1EAP($ScriptFile) {
    if ($scriptFile -match "UPDATE.PS1") { return }
    $CheckEAP = Get-Content $ScriptFile -First 5
    if ($checkEAP -match '\$ErrorActionPreference') {
        return $True
    } else {
        $ScriptFile = (Get-Item $ScriptFile).Name
        $ScriptFile = $ScriptFile.toupper()
        if ($UpdateScripts) {
            Write-Host "           ** $ScriptFile - recommended ErrorActionPreference statement has been added." -Foreground Green
        } else {
            Write-Warning "  ** $ScriptFile - is missing the recommended ErrorActionPreference statement."
            if (!$ReduceOutput) {
                Write-Host "           ** Suggestion: Consider running CNC -UpdateScripts to add it." -Foreground Cyan
            }
            $GLOBAL:Suggestions++
            return $False
        }
    }
}

# Add EAP statement to top of PowerShell script
function Add-PS1EAP($ScriptFile) {
    if ($scriptFile -match "UPDATE.PS1") { return }
    if ($UpdateScripts -and !$WhatIf) {
        if ($MakeBackups) { Copy-Item "$ScriptFile" "$ScriptFile.CNC.bak" -Force }
        $header = "`$ErrorActionPreference = 'Stop'"
        $Body = Get-Content $ScriptFile
        $NewContent = $header + $Body
        Write-Output $header $body | Out-File $ScriptFile
        $GLOBAL:Fixes++
    } else {
        if ($WhatIf -and !$ReduceOutput) {
            Write-Host "CNC did not add ErrorActionPreference statement, -WhatIf parameter was used." -Foreground Magenta
        }
    }
}

# Re-write PS script as UTF-8 w/BOM
function Update-PS1($ScriptFile) {
    if ($scriptFile -match "UPDATE.PS1") { return }
    if ($UpdateScripts -and !$WhatIf) {
        if ($MakeBackups) { Copy-Item "$ScriptFile" "$ScriptFile.CNC.bak" -Force }
        $Body = Get-Content $ScriptFile
        Write-Output $Body | Out-File $ScriptFile
        $GLOBAL:Fixes++
    } else {
        if ($WhatIf -and !$ReduceOutput) {
            Write-Host "CNC did not update your scripts, -WhatIf parameter was used." -Foreground Magenta
        }
    }
}

# Check chocolateyInstall.ps1 for SourceForge download links
function Check-DiscouragedDownloadLinks {
    if (Test-Path $path\tools\chocolateyInstall.ps1) {
        [string]$test = Get-Content $path\tools\chocolateyInstall.ps1
        if (($test -match 'sourceforge') -and ($test -match 'url')) {
            Write-Warning "  ** CHOCOLATEYINSTALL.PS1 uses SourceForge as download source. This will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host "           ** Guideline: Using SourceForge as the download source of installers is not recommended. Please consider an`n              alternative, official distribution location if one is available." -Foreground Cyan
            }
            $GLOBAL:Guidelines++
        }
        if (($test -match 'fosshub') -and ($test -match 'url')) {
            Write-Warning "  ** CHOCOLATEYINSTALL.PS1 uses FossHub as download source."
            if (!$ReduceOutput) {
                Write-Host "           ** Guideline: In Dec. 2016 FossHub requested ""Please help us keep our costs down by not using scripts`n              to download software from our site.""" -Foreground Cyan
            }
            $GLOBAL:Guidelines++
        }
    }
}

function Check-ScriptNames {
    $ChocoInstallScript = Get-ChildItem "$path\chocolateyinstall.ps1" -Recurse
    $NugetInstallScript = Get-ChildItem "$path\install.ps1" -Recurse
    if (!$ChocoInstallScript -and $NugetInstallScript) {
        Write-Host "WARNING:   ** Install Script Named Incorrectly." -Foreground Red
        if (!$ReduceOutput) {
            Write-Host "           ** Your script is named incorrectly and will need to be renamed. A script named chocolateyInstall.ps1 was`n              not found in your package, but another script ending in install.ps1 was found. The install script should`n              be named chocolateyInstall.ps1 and be found in the tools folder." -Foreground Cyan
        }
        $GLOBAL:Required++
    }

}

# borrowed from https://www.jonathanmedd.net/2012/05/quick-and-easy-powershell-test-xmlfile.html
function Test-XMLFile {
    <#
        .SYNOPSIS
        Test the validity of an XML file
    #>
    [CmdletBinding()]
    param (
        [parameter(mandatory = $true)][ValidateNotNullorEmpty()][string]$xmlFilePath
    )

    # Check the file exists
    if (!(Test-Path -Path $xmlFilePath)) {
        throw "$xmlFilePath is not valid. Please provide a valid path to the .xml fileh"
    }
    # Check for Load or Parse errors when loading the XML file
    $xml = New-Object System.Xml.XmlDocument
    try {
        $xml.Load((Get-ChildItem -Path $xmlFilePath).FullName)
        return $true
    } catch [System.Xml.XmlException] {
        Write-Verbose "$xmlFilePath : $($_.toString())"
        return $false
    }
}

# Update the nuspec XML namespace declaration
# Only checks for the common 2010/07 and 2011/08 namespaces, could be much better using regex.
# Messages related to this happening or not (-WhatIf) are difficult to implement because this change happens independly of other changes to the .nuspec, notifications need to be implemented in most cases.
function Update-XMLnsDeclaration {
    if ($MakeBackups) { Copy-Item "$LocalnuspecFile" "$LocalnuspecFile.CNC.XMLnamespace.bak" -Force }
  ((Get-Content -Path $LocalnuspecFile -Raw) -Replace 'http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd', 'http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd') | Set-Content -Path $LocalnuspecFile
  ((Get-Content -Path $LocalnuspecFile -Raw) -Replace 'http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd', 'http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd') | Set-Content -Path $LocalnuspecFile
    $GLOBAL:DelayedUpdateXMLnsDeclarationMessage = $True
    $GLOBAL:Fixes++
}

# END FUNCTIONS ------------------------------------------------------------------------------------------------
# BEGIN PROCESSING ---------------------------------------------------------------------------------------------

if ($recurse) {
    $ErrorActionPreference = 'SilentlyContinue'
    $folderlist = Split-Path (Get-ChildItem -Path $path -Recurse -Filter "*.nuspec").fullname
} else {
    $folderlist = $path
}

ForEach ($path in $folderlist) {
    # Finds nuspec file for processing. Defaults to current working directory.
    # You can specify a directory path, but do NOT specify the file itself, just the directory.
    if ($path) { $LocalnuspecFile = Get-Item $path\*.nuspec }
    if (!($LocalnuspecFile)) {
        Write-Host "ERROR:   ** No .nuspec file found in $path" -Foreground Red
        if (!$recurse) { return }
    }
    if ($LocalnuspecFile.count -gt 1) {
        Write-Host "ERROR:   ** Multiple .nuspec files found in $path. Please remove the old ones." -Foreground Red
        if (!$recurse) { return }
    }
    if ($LocalnuspecFile.length -lt 168) {
        # approximate value of a minimal blank nuspec template
        Write-Host "ERROR:   ** $LocalnuspecFile file appears to be blank or corrupt." -Foreground Red
        if (!$recurse) { return }
    }

    if (!(Test-XMLFile $LocalnuspecFile)) {
        Write-Host "ERROR:   ** $LocalnuspecFile is not a valid XML file." -Foreground Red
        if (!$ReduceOutput) {
            Write-Host "FYI:     ** Common problems:" -Foreground Cyan
            Write-Host "            choco pack will report: ""An error occurred while parsing EntityName."" for unexpected/malformed ""&""'s." -Foreground Cyan
            Write-Host "            choco pack will report: ""'<' is an unexpected token. The expected token is '>'."" for bad/unclosed elements." -Foreground Cyan
            Write-Host "            choco pack will report: ""The <tag> start tag on line x position x does not match the end tag of <tag>`n.                                    Line x, position x."" for elements with mismatched case.`n" -Foreground Cyan
            if (!$recurse) { break }
        }
    }

    if ($UpdateXMLNamespace) {
        if ($WhatIf) {
            $GLOBAL:DelayedUpdateXMLnsDeclarationMessage = $False
        } else {
            Update-XMLnsDeclaration
        }
    }

    # variables for findings report
    $GLOBAL:Required = 0
    $GLOBAL:Guidelines = 0
    $GLOBAL:Suggestions = 0
    $GLOBAL:Notes = 0
    $GLOBAL:Fixes = 0
    $GLOBAL:FYIs = 0
    #$GLOBAL:UpdateNuspec = $False # Not sure why this was here, it interferes with the -Update param
    $GLOBAL:TemplateError = 0
    $GLOBAL:DelayedUpdateXMLnsDeclarationMessage = $False

    # Import package.nuspec file to get values
    $nuspecXML = $LocalnuspecFile
    [xml]$nuspecFile = Get-Content $nuspecXML
    $NuspecAuthors = $nuspecFile.package.metadata.authors
    $NuspecBugTrackerURL = $nuspecFile.package.metadata.bugtrackerurl
    $NuspecConflicts = $nuspecFile.package.metadata.conflicts # Built for the future
    $NuspecCopyright = $nuspecFile.package.metadata.copyright
    $NuspecDependencies = $nuspecFile.package.metadata.dependencies
    $NuspecDescription = $nuspecFile.package.metadata.description
    $NuspecDocsURL = $nuspecFile.package.metadata.docsurl
    $NuspecFiles = $nuspecFile.package.files.file
    $NuspecIconURL = $nuspecFile.package.metadata.iconurl
    $NuspecID = $nuspecFile.package.metadata.id
    $NuspecLicenseURL = $nuspecFile.package.metadata.licenseurl
    $NuspecMailingListURL = $nuspecFile.package.metadata.mailinglisturl
    $NuspecOwners = $nuspecFile.package.metadata.owners
    $NuspecPackageSourceURL = $nuspecFile.package.metadata.packagesourceurl
    $NuspecProjectSourceURL = $nuspecFile.package.metadata.projectsourceurl
    $NuspecProjectURL = $nuspecFile.package.metadata.projecturl
    $NuspecProvides = $nuspecFile.package.metadata.provides # Built for the future
    $NuspecReleaseNotes = $nuspecFile.package.metadata.releasenotes
    $NuspecReplaces = $nuspecFile.package.metadata.replaces # Built for the future
    $NuspecRequireLicenseAcceptance = $nuspecFile.package.metadata.requirelicenseacceptance
    $NuspecSummary = $nuspecFile.package.metadata.summary
    $NuspecTags = $nuspecFile.package.metadata.tags
    $NuspecTitle = $nuspecFile.package.metadata.title
    $NuspecVersion = $nuspecFile.package.metadata.version
    $NuspecXMLComment = $nuspecFile.'#comment'
    $NuspecXMLNamespace = $nuspecFile.package.xmlns

    $NuspecDisplayName = $LocalnuspecFile.Name
    $NuspecDisplayName = $NuspecDisplayName.ToUpper()
    $ENV:ChocolateyPackageVersion = $NuspecVersion


    # Start outputting check results
    Write-Host "CNC Summary of $NuspecDisplayName (v$NuspecVersion):" -Foreground Magenta

    # Open all .nuspec URLs for viewing if -OpenURLs is passed
    if ($OpenURLs) {
        Write-Host "           ** Opening all .nuspec URLs in your default browser for viewing." -Foreground Magenta
        Open-URLs
    }

    # CHECKS ------------------------------------------------------------------------------------------------

    # Trusted package check
    Check-OnlineStatus

    if (Test-Path 'update.ps1') {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** UPDATE.PS1 found. You must be smarter than the average bear..." -Foreground Green
        }
        $GLOBAL:FYIs++
    }

    # check for UTF8 encoding
    # UTF-8 w/BOM is not desired per "You must save your files with UTF–8 character encoding without BOM."
    $NuspecEncoding = (Get-FileEncoding -Path $LocalnuspecFile)
    if ($NuspecEncoding -ne 'ASCII or UTF-8 w/o BOM') {
        Write-Warning "  ** $NuspecDisplayName is encoded using $NuspecEncoding."
        if ($GLOBAL:UpdateNuspec) {
            Write-Host "           ** $NuspecDisplayName will be converted to UTF-8 w/o BOM and saved." -Foreground Green
            $GLOBAL:Fixes++
        } else {
            if (!$ReduceOutput) {
                Write-Host "           ** Guideline: You must save your files with UTF–8 character encoding without BOM." -Foreground Cyan
            }
            $GLOBAL:Guidelines++
            if (!$ReduceOutput) {
                Write-Host "           ** Suggestion: Consider running CNC -Update to re-write`n              $NuspecDisplayName to UTF-8 w/o BOM." -Foreground Cyan
            }
            $GLOBAL:Suggestions++
        }
    }

    # check XML declaration
    if ($nuspecFile.xml -eq "version=""1.0""") {
        Write-Warning "  ** XML declaration is version=""1.0"""
        if ($UpdateXMLDeclaration) {
            Update-XMLDeclaration
        } else {
            if (!$ReduceOutput) {
                Write-Host "           ** Suggestion: Consider running CNC -UpdateXMLDeclaration to add a UTF-8 encoding statement." -Foreground Cyan
            }
            $GLOBAL:Suggestions++
        }
    }

    # check XML comment
    if (!$nuspecFile.'#comment') {
        if ($UpdateXMLComment) {
            Write-Host "           ** XML comment to test UTF-8 encoding added." -Foreground Green
            $GLOBAL:Fixes++
            $GLOBAL:UpdateNuspec = $True
        } else {
            Write-Warning "  ** The recommended XML comment to test UTF-8 encoding was not found."
            if (!$ReduceOutput) {
                Write-Host "           ** Suggestion: Consider running CNC -UpdateXMLComment to add a UTF-8 encoding test XML comment." -Foreground Cyan
            }
            $GLOBAL:Suggestions++
            if ($nuspecFile.'#comment' -match 'Read this before creating packages') {
                Write-Host "WARNING:   ** XML comment contains templated values. This will trigger a message from the verifier:" -Foreground Red
                if (!$ReduceOutput) {
                    Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
                }
                $GLOBAL:Required++
            }
        }
    }

    # check XML Namespace
    if ($NuspecXMLNamespace -ne "$XMLNamespace") {
        Write-Warning "  ** XML namespace declaration is $NuspecXMLNamespace"
        if (!$ReduceOutput) {
            Write-Host "           ** The current schema is $XMLNamespace" -Foreground Cyan
            Write-Host "           ** Suggestion: Consider running CNC -UpdateXMLNamespace to update the XML namespace declaration." -Foreground Cyan
        }
        $GLOBAL:Suggestions++
    }

    if ($GLOBAL:DelayedUpdateXMLnsDeclarationMessage -and !$WhatIf) {
        Write-Host "           ** XML namespace declaration changed to http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd" -Foreground Green
    } else {
        if ($WhatIf -and !$ReduceOutput) {
            Write-Host "           ** XML namespace declaration NOT changed, due to -WhatIf" -Foreground Magenta
        }
    }

    # <authors> checks
    if (!($NuspecAuthors)) {
        Write-Host "WARNING:   ** <authors> element is empty, this element is a requirement." -Foreground Red
        $GLOBAL:Required++
    } else {
        if ($NuspecAuthors -match "@") {
            Write-Host "WARNING:   ** <authors> - contains an e-mail address. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host '           ** Requirements: Email address should not be used in the Author and Copyright fields of the nuspec file. ' -Foreground Cyan
            }
            $GLOBAL:Required++
        }
        if ($NuspecAuthors -cmatch '__REPLACE_AUTHORS_OF_SOFTWARE_COMMA_SEPARATED__') {
            Write-Host "WARNING:   ** <authors> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
    }

    # <bugTrackerUrl> checks
    if (!($NuspecBugTrackerURL)) {
        Write-Warning "  ** <bugTrackerUrl> - element is empty. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host '           ** Suggestion: bugTrackerUrl - points to the location where issues and tickets can be accessed' -Foreground Cyan
        }
        $GLOBAL:Suggestions++
    } else {
        Validate-URL "<bugTrackerUrl>" $NuspecBugTrackerURL
    }

    # <conflicts> checks - Built for the future
    #if (!($NuspecConflicts)) {Write-Warning "  ** <conflicts> element is empty."}

    # <copyright> checks
    if (!($NuspecCopyright)) {
        Write-Host "FYI:       ** <copyright> - element is empty." -Foreground Yellow
        $GLOBAL:FYIs++
    } else {
        if ($NuspecCopyright.Length -lt 5) {
            Write-Host "WARNING:   ** <copyright> - is less than 5 characters. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host '           ** Requirements: If you are going to use copyright in the nuspec, please use more than 4 characters.' -Foreground Cyan
            }
            $GLOBAL:Required++
        }
        if ($NuspecAuthors -match "@") {
            Write-Host "WARNING:   ** <copyright> - contains an e-mail address. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host '           ** Requirements: Email address should not be used in the Author and Copyright fields of the nuspec file. ' -Foreground Cyan
            }
            $GLOBAL:Required++
        }
        if ($NuspecCopyright -eq 'Year Software Vendor') {
            Write-Host "WARNING:   ** <copyright> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
    }

    # <dependencies> checks
    if (!($NuspecDependencies)) {
        if (!$ReduceOutput) {
            Write-Host "FYI:       ** <dependencies> - element is empty." -Foreground Yellow
        }
        $GLOBAL:FYIs++
    } else {
        if ((!$NuspecDependencies) -and ($NuspecTitle -match "deprecated")) {
            Write-Host "WARNING:   ** <dependencies> - Deprecated packages must have a dependency." -Foreground Red
            $GLOBAL:Required++
        }
        if ($NuspecDependencies.dependency.id -eq 'chocolatey') {
            Write-Warning "  ** <dependencies> - ""chocolatey"" is a dependency. This will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host "           ** Note: The package takes a dependency on Chocolatey. The reviewer will ensure the package uses a specific`n              Chocolatey feature that requires a minimum version." -Foreground Cyan
            }
            $GLOBAL:Notes++
        }
        $DependencyName = $NuspecDependencies.dependency.id
        if ($NuspecDependencies.dependency.id.count -eq 1) {
            if ($null -eq $NuspecDependencies.dependency.version) {
                Write-Warning "  ** <dependencies> - $DependencyName has no version. This will trigger a message from the verifier:"
                if (!$ReduceOutput) {
                    Write-Host "           ** Guideline: Package contains dependencies with no specified version. You should at least specify`n              a minimum version of a dependency." -Foreground Cyan
                }
                $GLOBAL:Guidelines++
            }
        } else {
            $DependencyNumber = 0
            do {
                $DependencyName = $NuspecDependencies.dependency.id[$DependencyNumber]
                if ($null -eq $NuspecDependencies.dependency[$DependencyNumber].version) {
                    Write-Warning "  ** <dependencies> - ""$DependencyName"" has no version. This will trigger a message from the verifier:"
                    if (!$ReduceOutput) {
                        Write-Host "           ** Guideline: Package contains dependencies with no specified version. You should at least specify`n              a minimum version of a dependency." -Foreground Cyan
                    }
                    $GLOBAL:Guidelines++
                }
                $DependencyNumber++
            }while ($DependencyNumber -lt $NuspecDependencies.dependency.id.count)
        }
    }

    # <description> checks
    if ($NuspecDescription.'#cdata-section') {
        $NuspecDescription = $nuspecFile.package.metadata.description.'#cdata-section'
    }
    if (!$NuspecDescription) {
        Write-Host "WARNING:   ** <description> - element is empty, this element is a requirement." -Foreground Red
        $GLOBAL:Required++
    } else {
        Check-Header
        if ($AddHeader) {
            $NuspecDescription = (Add-Header)
        }
        Check-PackageNotes
        if ($AddPackageNotes) {
            $NuspecDescription = (Add-PackageNotes)
        }
        Check-Footer
        if ($AddFooter) {
            $NuspecDescription = (Add-Footer)
        }
        Check-Markdown "<description>" $NuspecDescription
        if ($NuspecDescription.Length -lt 30) {
            Write-Warning "  ** <description> - is less than 30 characters."
            if (!$ReduceOutput) {
                Write-Host "           ** Guideline: Description should be sufficient to explain the software. Please fill in the description`n              with more information about the software. Feel free to use use markdown." -Foreground Cyan
            }
            $GLOBAL:Guidelines++
        }
        if ($NuspecDescription.Length -gt 4000) {
            $TotalChars = $NuspecDescription.Length
            Write-Host "WARNING:   ** <description> - is $TotalChars characters. Pushing the package will generate the error:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Failed to process request. 'This package had an issue pushing: A nuget package's Description property may`n              not be more than 4000 characters long.'. The remote server returned an error: (409) Conflict.." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
        if ($NuspecDescription -match "raw.githubusercontent") {
            if ($UpdateImageURLs) {
                Write-Host "           ** <description> - URL(s) updated to use $NewCDN." -Foreground Green
                $NuspecDescription = (Update-CDNURL "$NuspecDescription")
            } else {
                Write-Warning "  ** <description> - includes a GitHub raw link. Please change to a CDN such as:"
                if (!$ReduceOutput) {
                    Write-Host "           ** $CDNlist" -Foreground Cyan
                    Write-Host "           ** Suggestion: Consider running CNC -UpdateImageURLs to update it." -Foreground Cyan
                }
                $GLOBAL:Suggestions++
            }
        }
        if ($NuspecDescription -match "cdn.rawgit.com") {
            if ($UpdateImageURLs) {
                Write-Host "           ** <description> - URL(s) updated to use $NewCDN." -Foreground Green
                $NuspecDescription = (Update-CDNURL "$NuspecDescription")
            } else {
                Write-Warning "  ** <description> - includes a link to RawGit which will be going offline October 2019. Please change to a`n              CDN such as:"
                if (!$ReduceOutput) {
                    Write-Host "           ** $CDNlist" -Foreground Cyan
                    Write-Host "           ** Suggestion: Consider running CNC -UpdateImageURLs to update it." -Foreground Cyan
                }
                $GLOBAL:Suggestions++
            }
        }
        if ($NuspecDescription -cmatch '__REPLACE__MarkDown_Okay') {
            Write-Host "WARNING:   ** <description> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
        # below checking doesn't work as PowerShell will already give an error reading the nuspec
        # Cannot convert value "System.Object[]" to type "System.Xml.XmlDocument". Error: "An error occurred while parsing
        # EntityName.
        # TDL: this can be accomplished by reading in the file ina function and parsing it line by line for & with &amp;
        if ($NuspecDescription -match ' `& ') {
            Write-Warning "  ** <description> - `& found and needs to be replaced with `&amp;"
            Write-Host "           ** Packing will error: ""An error occurred while parsing EntityName.""" -Foreground Red
            if ($UpdateAll) {
                $NuspecDescription = $NuspecDescription -replace "`&", "`&amp;"
                Write-Host "           ** <description> - `& replaced with `&amp;" -Foreground Green
                $GLOBAL:Fixes++
            } else {
                Write-Host "           ** Suggestion: Consider running CNC -UpdateAll to update it." -Foreground Cyan
                $GLOBAL:Suggestions++
                $GLOBAL:Required++
            }
        }
        if (($nuspecFile.package.metadata.description.'#cdata-section') -and ($GLOBAL:UpdateNuspec)) {
            if (!$ReduceOutput) {
                Write-Host "           ** <description> - CDATA found, not saving description changes." -Foreground Magenta
            }
        }
    }

    # <docsUrl> checks
    if (!($NuspecDocsURL)) {
        Write-Warning "  ** <docsUrl> - element is empty. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host '           ** Suggestion: docsUrl - points to the location of the wiki or docs of the software' -Foreground Cyan
        }
        $GLOBAL:Suggestions++
    } else {
        if ($NuspecDocsURL -match 'At what url are the software docs located') {
            Write-Host "WARNING:   ** <docsUrl> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        } else {
            Validate-URL "<docsUrl>" $NuspecDocsURL
        }
    }

    # <files> checks
    if (!($NuspecFiles)) {
        Write-Host 'FYI:       ** <files> - element is empty or missing. If missing, all of the following files will be packaged:' -Foreground Yellow
        if (!$ReduceOutput) {
            Get-ChildItem -Path $path -Recurse -Exclude *.nupkg, tools | % $_.file { Write-Host "           ** $_" -Foreground Cyan -ea SilentlyContinue }
            Write-Host '           ** <files> - It is best practice to add:' -Foreground Yellow
            Write-Host '                        <files>' -Foreground Yellow
            Write-Host '                          <file src="tools\**" target="tools" />' -Foreground Yellow
            Write-Host '                        <files>' -Foreground Yellow
        }
        $GLOBAL:FYIs++
    }

    # <iconUrl> checks
    if (!($NuspecIconURL)) {
        Write-Warning "  ** <iconUrl> - element is empty. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host '           ** Guideline: The iconUrl should be added if there is one. Please correct this in the nuspec, if applicable.' -Foreground Cyan
        }
        $GLOBAL:Guidelines++
    } else {
        if ($NuspecIconURL -cmatch 'REPLACE_YOUR_REPO') {
            Write-Host "WARNING:   ** <iconUrl> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
        Validate-URL "<iconUrl>" $NuspecIconURL
        if ($GLOBAL:ValidURL) {
            Get-ImageDimensions
        }
        $IconExt = ($NuspecIconURL | Select-String -Pattern $AcceptableIconExts)
        if (!($IconExt)) {
            Write-Warning "  ** <iconUrl> - Your package icon is NOT a .PNG or .SVG. This will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host '           ** Suggestion: As per the packaging guidelines icons should be either a png or svg file.' -Foreground Cyan
            }
            $GLOBAL:Suggestions++
        }
        if ($NuspecIconURL -match "raw.githubusercontent") {
            if ($UpdateImageURLs) {
                $NuspecIconURL = (Update-CDNURL "$NuspecIconURL")
                Write-Host "           ** <iconUrl> - URL updated to: `n              $NuspecIconURL" -Foreground Green
            } else {
                Write-Warning "  ** <iconUrl> - uses a GitHub raw link. Please use a CDN such as:"
                if (!$ReduceOutput) {
                    Write-Host "           ** $CDNlist" -Foreground Cyan
                    Write-Host "           ** Suggestion: Consider running CNC -UpdateImageURLs to update it." -Foreground Cyan
                }
                $GLOBAL:Suggestions++
            }
        }
        if ($NuspecIconURL -match "cdn.rawgit.com") {
            if ($UpdateImageURLs) {
                $NuspecIconURL = (Update-CDNURL "$NuspecIconURL")
                Write-Host "           ** <iconUrl> - URL updated to: `n              $NuspecIconURL" -Foreground Green
            } else {
                Write-Warning "  ** <iconUrl> - uses RawGit which will be going offline October 2019. Please change to a CDN such as:"
                if (!$ReduceOutput) {
                    Write-Host "           ** $CDNlist" -Foreground Cyan
                    Write-Host "           ** Suggestion: Consider running CNC -UpdateImageURLs to update it." -Foreground Cyan
                }
                $GLOBAL:Suggestions++
            }
        }
    }

    # <id> checks
    if (!($NuspecID)) {
        Write-Host "WARNING:   ** <id> - element is empty, this element is a requirement." -Foreground Red
        $GLOBAL:Required++
    } else {
        if (($NuspecID.Length -gt 20) -and (!$NuspecID.Contains("-")) -and (!$NuspecID.Contains("."))) {
            Write-Warning "  ** <id> - is greater than 20 characters. This will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host "           ** Note: If this is a new package that has never been approved, moderators will review and reject the`n              package for one that will be pushed with a new id that meets the package naming guidelines." -Foreground Cyan
            }
            $GLOBAL:Notes++
        }
        if ($NuspecID -cmatch "[A-Z]") {
            Write-Warning "  ** <id> - includes UPPERcase letters."
            $GLOBAL:Guidelines++
        }
        if (($NuspecID.Contains(".")) -and (!$NuspecID.Contains(".install")) -and (!$NuspecID.Contains(".portable")) -and (!$NuspecID.Contains(".extension"))) {
            Write-Warning "  ** <id> - includes a '.'. This will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host "           ** Note: The package id includes dots (.). Usually the package id is separated by '-' instead of dots`n              (except in the case of *.install and *.portable). The reviewer will ensure this is not a new package." -Foreground Cyan
            }
            $GLOBAL:Notes++
        }
        if ($NuspecID.Contains(".config")) {
            Write-Host "WARNING:   ** <id> - includes a '.config'. This is not allowed." -Foreground Red
            $GLOBAL:Required++
        }
    }

    # <licenseUrl> checks
    if (!($NuspecLicenseURL)) {
        Write-Warning "  ** <licenseUrl> - element is empty. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host "           ** Guideline: The licenseUrl should be added if there is one. Please correct this in the nuspec,`n              if applicable." -Foreground Cyan
        }
        $GLOBAL:Guidelines++
    } else {
        if ($NuspecLicenseURL -eq $NuspecprojectUrl) {
            Write-Warning "  ** <licenseUrl> - is the same as <projectUrl>. This will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host "           ** Guideline: The licenseUrl should not usually be an exact match to softwareUrl. Please correct this in the`n              nuspec, if applicable. ." -Foreground Cyan
            }
            $GLOBAL:Guidelines++
        }
        if ($NuspecLicenseURL -cmatch 'REMOVE_OR_FILL_OUT') {
            Write-Host "WARNING:   ** <licenseUrl> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        } else {
            Validate-URL "<licenseUrl>" $NuspecLicenseURL
        }
    }

    # <mailingListUrl> checks
    if (!($NuspecMailingListURL)) {
        Write-Warning "  ** <mailingListUrl> - element is empty. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host '           ** Suggestion: mailingListUrl - points to the forum or email list group for the software' -Foreground Cyan
        }
        $GLOBAL:Suggestions++
    } else {
        Validate-URL "<mailingListUrl>" $NuspecMailingListURL
    }

    # <owners> checks
    if (!($NuspecOwners)) {
        Write-Host "WARNING:   ** <owners> element is empty, this element is a requirement." -Foreground Red
        $GLOBAL:Required++
    } else {
        if ($NuspecOwners -cmatch 'REPLACE_YOUR_NAME') {
            Write-Host "WARNING:   ** <owners> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
        if ($NuspecAuthors -eq $NuspecOwners) {
            Write-Warning "  ** <owners> and <authors> elements are the same. This will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host "           ** Note: The package maintainer field (owners) matches the software author field (authors) in the nuspec.`n              The reviewer will ensure that the package maintainer is also the software author." -Foreground Cyan
            }
            $GLOBAL:Notes++
        }
    }

    # <packageSourceUrl> checks
    if (!($NuspecPackageSourceURL)) {
        Write-Warning "  ** <packageSourceUrl> - element is empty. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host "           ** Guideline: The nuspec has been enhanced to allow packageSourceUrl, pointing to the url where the package`n              source resides. This is a strong guideline because it simplifies collaboration.`n              Please add it to the nuspec." -Foreground Cyan
        }
        $GLOBAL:Guidelines++
    } else {
        if ($NuspecPackageSourceURL -cmatch 'Where is this Chocolatey package located') {
            Write-Host "WARNING:   ** <packageSourceUrl> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        } else {
            Validate-URL "<packageSourceUrl>" $NuspecPackageSourceURL
        }
    }

    # <projectSourceUrl> checks
    if (!$NuspecProjectSourceURL) {
        Write-Warning "  ** <projectSourceUrl> - element is empty. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host '           ** Suggestion: projectSourceUrl - points to the location of the underlying software source' -Foreground Cyan
        }
        $GLOBAL:Suggestions++
    } else {
        if ($NuspecProjectSourceURL -match 'Software Source Location') {
            Write-Host "WARNING:   ** <projectSourceUrl> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        } else {
            Validate-URL "<projectSourceUrl>" $NuspecProjectSourceURL
        }
        if ($NuspecProjectURL -eq $NuspecProjectSourceURL) {
            Write-Warning "  ** <projectUrl> and <projectSourceUrl> elements are the same. This will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host "           ** Guideline: ProjectUrl and ProjectSourceUrl are typically different, but not always. Please ensure`n              that projectSourceUrl is pointing to software source code or remove the field from the nuspec." -Foreground Cyan
            }
            $GLOBAL:Guidelines++
        }
    }

    # <projectUrl> checks
    if (!($NuspecProjectURL)) {
        Write-Host "WARNING:   ** <projectUrl> - element is empty. This will trigger a message from the verifier:" -Foreground Red
        if (!$ReduceOutput) {
            Write-Host "           ** Requirement: ProjectUrl (projectUrl) in the nuspec file is required. Please add it to the nuspec." -Foreground Cyan
        }
        $GLOBAL:Required++
    } else {
        if ($NuspecProjectURL -cmatch 'REMOVE_OR_FILL_OUT') {
            Write-Host "WARNING:   ** <projectUrl> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        } else {
            Validate-URL "<projectUrl>" $NuspecProjectURL
        }
    }

    # <provides> checks - Built for the future
    #if (!($NuspecProvides)) {Write-Warning "  ** <provides> element is empty"}

    # <releaseNotes> checks
    if (!($NuspecReleaseNotes)) {
        Write-Warning "  ** <releaseNotes> - element is empty. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host "           ** Guideline: Release Notes (releaseNotes) are a short description of changes in each version of a package.`n              Please include releasenotes in the nuspec. NOTE: To prevent the need to continually update this field,`n              providing a URL to an external list of Release Notes is perfectly acceptable." -Foreground Cyan
        }
        $GLOBAL:Guidelines++
    } else {
        Check-Markdown "<releaseNotes>" $NuspecReleaseNotes
        if ($NuspecReleaseNotes -cmatch 'REPLACE_OR_REMOVE') {
            Write-Host "WARNING:   ** <releaseNotes> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
    }

    # <replaces> checks - Built for the future
    #if (!($NuspecReplaces)) {Write-Warning "  ** <replaces> element is empty."}

    # <requireLicenseAcceptance> checks
    if (!($NuspecRequireLicenseAcceptance)) {
        Write-Host "FYI:       ** <requireLicenseAcceptance> - element is empty." -Foreground Yellow
        $GLOBAL:FYIs++
    } else {
        if (($NuspecRequireLicenseAcceptance -eq "true") -and (!($NuspecLicenseURL))) {
            Write-Host "WARNING:   ** <requireLicenseAcceptance> is set to true but <licenseUrl> is empty." -Foreground Red
            $GLOBAL:Required++
        }
    }

    # <summary> checks
    if (!($NuspecSummary)) {
        Write-Warning "  ** <summary> - element is empty. This will trigger a message from the verifier:"
        if (!$ReduceOutput) {
            Write-Host '           ** Guideline: Summary (summary) is a short explanation of the software. Please include summary in the nuspec.' -Foreground Cyan
        }
        $GLOBAL:Guidelines++
    } else {
        if ($NuspecSummary -cmatch '__REPLACE__') {
            Write-Host "WARNING:   ** <summary> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
    }

    # <tags> checks
    if (!($NuspecTags)) {
        Write-Host "WARNING:   ** <tags> - element is empty." -Foreground Red
        $GLOBAL:Required++
    } else {
        if ($NuspecTags -match ",") {
            Write-Host "WARNING:   ** <tags> - tags are separated with commas. They should only be separated with spaces." -Foreground Red
            $GLOBAL:Required++
        }
        if ($NuspecTags -match "admin") {
            Write-Host "FYI:       ** <tags> - there is a tag named ""admin"" which is now deemed unnecessary." -Foreground Yellow
            if (!$ReduceOutput) {
                Write-Host '           ** The majority of Chocolatey packages require admin rights to install, this is considered default behavior.' -Foreground Cyan
            }
            $GLOBAL:FYIs++
        }
        if ($NuspecTags -match "chocolatey") {
            Write-Warning "  ** <tags> - there is a tag named ""chocolatey"" which will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host '           ** Guideline: Tags (tags) should not contain 'chocolatey' as a tag. Please remove that in the nuspec.' -Foreground Cyan
            }
            $GLOBAL:Guidelines++
        }
        if ($NuspecTags -match "notsilent") {
            Write-Warning "  ** <tags> - there is a tag named ""notsilent"" which will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host '           ** Note: notSilent tag is being used. The reviewer will ensure this is being used appropriately. ' -Foreground Cyan
            }
            $GLOBAL:Notes++
        }
        if ($NuspecTags -cmatch 'SPACE_SEPARATED') {
            Write-Host "WARNING:   ** <tags> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
    }

    # <title> checks
    if (!($NuspecTitle)) {
        Write-Warning "  ** <title> - element is empty."
        $GLOBAL:Guidelines++
    } else {
        if ($NuspecTitle -eq $NuspecID) {
            Write-Warning "  ** <title> and <id> are the same which will trigger a message from the verifier:"
            if (!$ReduceOutput) {
                Write-Host "           ** Guideline: Title (title) matches id exactly. Please consider using something slightly more descriptive`n              for the title in the nuspec." -Foreground Cyan
            }
            $GLOBAL:Guidelines++
        }
    }

    # <version> checks
    if (!($NuspecVersion)) {
        Write-Host "WARNING:   ** <version> - element is empty, this element is a requirement." -Foreground Red
        $GLOBAL:Required++
    } else {
        if ($NuspecVersion -match "REPLACE") {
            Write-Host "WARNING:   ** <version> - contains templated values. This will trigger a message from the verifier:" -Foreground Red
            if (!$ReduceOutput) {
                Write-Host "           ** Requirement: Nuspec file contains templated values which should be removed." -Foreground Cyan
            }
            $GLOBAL:Required++
        }
    }

    # *.ps1 file checks
    Get-ChildItem "$path\*.ps1" -Recurse | % $_ {
        if ($debug) {
            write-host "PATH = $path" -foreground red -background white
            write-host "FOREACH = $_" -foreground red -background white
        }
        $ScriptFile = (Get-Item $_).Name
        $ScriptFile = $ScriptFile.toupper()
        $HasPS1EAP = Check-PS1EAP $_
        if (!$HasPS1EAP) {
            Add-PS1EAP $_
        }
        $PS1Encoding = Get-FileEncoding $_
        if ($PS1Encoding -ne 'UTF-8 w/ BOM') {
            if (!$UpdateScripts) {
                if ($scriptFile -match "UPDATE.PS1") { return }
                Write-Warning "  ** $ScriptFile - is encoded using $PS1Encoding."
                if (!$ReduceOutput) {
                    Write-Host "           ** PowerShell scripts need to be saved in UTF–8 with BOM." -Foreground Cyan
                    Write-Host "           ** Suggestion: Consider running CNC -UpdateScripts to re-write $ScriptFile to UTF-8 w/ BOM." -Foreground Cyan
                }
                $GLOBAL:Suggestions++
            } else {
                if (!$WhatIf) {
                    if (!$ReduceOutput) {
                        Write-Host "           ** $ScriptFile - will be converted to UTF-8 w/ BOM and saved." -Foreground Green
                        Update-PS1 $_
                    }
                } else {
                    if (!$ReduceOutput) {
                        Write-Host "           ** $ScriptFile - will NOT be converted to UTF-8 w/ BOM and saved, -WhatIf option used." -Foreground Green
                    }
                }
            }
        }
        $ScriptError = Test-PowerShellSyntax ($_)
        if ($ScriptError.SyntaxErrorsFound) {
            Write-Host "WARNING:   ** $ScriptFile - has PowerShell syntax errors." -Foreground Red
            $GLOBAL:Required++
        }
        if ($_ -match "install") {
            $urlcount = 0
            $InstallScript = Get-Content $_
            $urlsfound = @()
            $InstallScript | ForEach-Object {
                if ($_ -match "\b(?:(?:https?|ftp|file)://|www\.|ftp\.)(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[A-Z0-9+&@#/%=~_|$])") {
                    $urlsfound += $matches[0]
                    $validateurl = $urlsfound[$urlcount]
                    Validate-URL "$ScriptFile" "$validateurl"
                    $urlcount++
                }
            }
            # This could be changed to a loop instead so the line can be displayed
            $InstallScript = [string]$InstallScript
            if ($InstallScript -match "msiexec") {
                Write-Warning "  ** $ScriptFile calls msiexec - This will trigger a message from the verifier:"
                if (!$ReduceOutput) {
                    Write-Host "           ** Note: Package automation scripts make use of msiexec. The reviewer will ensure there is a valid reason`n              the package has not used the built-in helpers." -Foreground Cyan
                }
                $GLOBAL:Notes++
            }
            if (($InstallScript -match 'cinst ') -or ($InstallScript -match 'choco install') -or ($InstallScript -match 'choco upgrade') -or ($InstallScript -match ' cup ')) {
                Write-Host "WARNING:   ** $ScriptFile - uses a cinst, choco install, cup, or choco upgrade command." -Foreground Red
                if (!$ReduceOutput) {
                    Write-Host "           ** In automation scripts (.ps1/.psm1), the package has used a chocolatey command that should not be used.`n              Rather a dependency should be taken on a package. Please add dependencies to the nuspec." -Foreground Cyan
                }
                $GLOBAL:Required++
            }
            if (($InstallScript -match '-url' -or $InstallScript -match '$url') -and ($InstallScript -notmatch 'checksum')) {
                Write-Host "WARNING:   ** $ScriptFile downloads files but doesn't include checksums." -Foreground Red
                # TDL: Most likely causes a validator error but I need to find and quote it.
                $GLOBAL:Suggestions++
            }
            if ($InstallScript -match 'chocolateyToolsLocation' -or $InstallScript -match 'chocolateyBinRoot' -or $InstallScript -match 'chocolatey_bin_root' -or $InstallScript -match 'chocolateyPackageFolder' -or $InstallScript -match 'packageFolder' -or $InstallScript -match 'chocolateyChecksum32' -or $InstallScript -match 'chocolateyChecksum64' -or $InstallScript -match 'chocolateyChecksumType32' -or $InstallScript -match 'chocolateyChecksumType64' -or $InstallScript -match 'downloadCacheAvailable') {
                Write-Host "WARNING:   ** $ScriptFile uses private enviroment variables. This will trigger a message from the verifier:" -Foreground Red
                if (!$ReduceOutput) {
                    Write-Host "           ** Required: Private environment variables are used in automation scripts. Please correct this..." -Foreground Cyan
                }
                $GLOBAL:Required++
            }
            $IncludedBinaries = (Get-ChildItem -Path $path -Include $BinaryExtensions -Recurse)
            if ($IncludedBinaries) {
                if (($urlcount) -and ($InstallScript -match 'Install-ChocolateyPackage')) {
                    Write-Host "FYI:       ** $ScriptFile uses Install-ChocolateyPackage (for downloading files to install) instead of`n              Install-ChocolateyInstallPackage (for installing embedded files)." -Foreground Yellow
                    $GLOBAL:Suggestions++
                }
                if (($urlcount) -and ($InstallScript -match 'Install-ChocolateyZipPackage')) {
                    Write-Host "FYI:       ** $ScriptFile uses Install-ChocolateyZipPackage (for downloading files to unzip) instead of`n              Get-ChocolateyUnzip (for unzipping embedded files)." -Foreground Yellow
                    $GLOBAL:Suggestions++
                }
            }
        }
    }

    # Check for correctly named install script
    Check-ScriptNames

    # FossHub and SourceForge DL links check
    Check-DiscouragedDownloadLinks

    # Binaries checks
    Check-Binaries

    # OS index files check
    Check-OSIndexFiles

    # check for JPG files
    Check-JPGs

    # check for PNG files
    Check-PNGs

    # Check for internal packaging Files
    Check-PackageInternalFilesIncluded

    # Git 'er done ------------------------------------------------------------------------------------------------

    # Optimize any images files supported by PngOptimizerCL.exe
    Run-JPGOptimizer
    Run-PNGOptimizer

    # End outputting check results
    Write-Host "CNC found " -NoNewLine -Foreground Magenta
    Write-Host "$GLOBAL:Required REQUIRED changes, " -NoNewLine -Foreground Red
    Write-Host "$GLOBAL:Guidelines GUIDELINE changes, " -NoNewLine -Foreground Yellow
    Write-Host "$GLOBAL:Suggestions SUGGESTED changes, " -NoNewLine -Foreground Yellow
    Write-Host "$GLOBAL:Notes NOTES, " -NoNewLine -Foreground Yellow
    Write-Host "$GLOBAL:FYIs FYIs, " -NoNewLine -Foreground Yellow
    Write-Host "and made $GLOBAL:Fixes changes." -ForeGround Green

    if ($GLOBAL:UpdateNuspec) {
        if ($WhatIf) {
            Write-Host "FYI:       ** CNC did NOT update $LocalnuspecFile, -WhatIf parameter was used." -Foreground Magenta
        } else {
            Update-nuspec
        }
    }

    if ($UpdateScripts) {
        if ($WhatIf) {
            Write-Host "FYI:       ** CNC did NOT update your scripts, -WhatIf parameter was used." -Foreground Magenta
        }
    }

    $ENV:ChocolateyPackageVersion = ''

    # leave space between output when recursing
    if ($recurse) {
        Write-Host "`n"
    }

    # main recurse foreach loop ends here
    $exitcode = $exitcode + $GLOBAL:Required
}

if ($recurse) {
    Write-Host "CNC -Recurse found " -NoNewLine -Foreground Magenta
    Write-Host "$exitcode TOTAL REQUIRED changes." -Foreground Red
}

Write-Host "`nFound CNC.ps1 useful?" -Foreground White
Write-Host "Buy me a beer at https://www.paypal.me/bcurran3donations" -Foreground White
Write-Host "Become a patron at https://www.patreon.com/bcurran3" -Foreground White
exit $exitcode

# TDL
# Update CDN checking for "main" as well as "master" post 10/2020 (did this happen?)
# Check validity of URLs in description, checked by the package verifier as of 01/11/2020
# ^ ALMOST: $NuspecDescription | Select-String -Pattern 'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)' -AllMatches   | % { $_.Matches }`  | % { $_.Value }`  | Sort-Object ` | Get-Unique
# ^ doesn't strip ) end of markdown [](), strips * in urls
# Reformat invalid Markdown headings automagically (Need to parse out and skip URLs.)
# Move header, footer, and package notes into one XML config file
# Add option of displaying useful tips and tweaks (AutoHotKey, BeCyIconGrabber, PngOptimizer, Regshot, service viewer program, Sumo, etc)
# Add logging option when recursivly checking files
# MAYBE edit and re-write handling CDATA in description (not sure if there is a need)
# Address new Validator changes: https://blog.chocolatey.org/2022/08/upcoming-changes-validator/ - HIGH PRIORITY
# Possibly add option to run scripts through PSScriptAnalyzer
# What else?

Log in or click on link to see number of positives.

In cases where actual malware is found, the packages are subject to removal. Software sometimes has false positives. Moderators do not necessarily validate the safety of the underlying software, only that a package retrieves software from the official distribution point and/or validate embedded software against official distribution point (where distribution rights allow redistribution).

Chocolatey Pro provides runtime protection from possible malware.

Add to Builder Version Downloads Last Updated Status
(unofficial) Chocolatey .nuspec Checker (CNC) (Script) 2024.1.14-pre 45 Sunday, January 14, 2024 Exempted
(unofficial) Chocolatey .nuspec Checker (Script) 2023.9.10 197 Sunday, September 10, 2023 Exempted
(unofficial) Chocolatey .nuspec Checker (Script) 2023.05.17 163 Wednesday, May 17, 2023 Exempted
(unofficial) Chocolatey .nuspec Checker (Script) 2023.05.15 64 Wednesday, May 17, 2023 Exempted
(unofficial) Chocolatey .nuspec Checker (Script) 2020.09.21 683 Monday, September 21, 2020 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2020.09.20 162 Sunday, September 20, 2020 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2020.09.15 164 Wednesday, September 16, 2020 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2020.04.06.0001 431 Monday, April 6, 2020 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2020.04.06 163 Monday, April 6, 2020 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2020.01.16 308 Thursday, January 16, 2020 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.12.14 193 Saturday, December 14, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.09.01 322 Monday, September 2, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.08.26 254 Tuesday, August 27, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.03.04 329 Monday, March 4, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.02.22 239 Sunday, March 3, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.02.18 252 Tuesday, February 19, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.02.16 217 Sunday, February 17, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.02.04 240 Tuesday, February 5, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.29 231 Wednesday, January 30, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.26 198 Sunday, January 27, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.22 246 Wednesday, January 23, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.15 269 Wednesday, January 16, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.13 253 Monday, January 14, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.12 260 Saturday, January 12, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.09 228 Thursday, January 10, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.07 222 Tuesday, January 8, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.04 216 Saturday, January 5, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2019.01.03 246 Friday, January 4, 2019 Approved
(unofficial) Chocolatey .nuspec Checker (Script) 2018.12.22 253 Friday, December 28, 2018 Approved

CHANGELOG:

  • 2024.06.26 - Fixed a bug where the -Update switch was not working correctly (specifically when saving nuspec file as UTF-8 w/o BOM).
  • 2024.xx.xx - New CNC.config file for setting your preferences/defaults. New offline mode. BREAKING CHANGES: CNCFooter.txt, CNCHeader.txt, and CNCPackageNotes.txt are no longer used. Functionality is replaced with contents in CNC.config. When using a UseCDN switch -UpdateImageURLs defaults to true. Can now replace defunct Staticaly CDN URLs with other CDN URLs.
  • 2023.09.10 - -OptimizeImages works again, added optimization of JPG files if jpegoptim is installed when using the -OptimizeImages feature, -UpdateXMLNamespace works again
  • 2023.05.17 - CNC now returns a non-zero exit code if there are any required changes and displays the total required changes of all nuspec files when the -Recurse switch is used
  • 2023.05.15 - display # of characters when description is >4000, more specific template value checking, fix empty/missing files element message, skip dimension checking of SVG files, prep for moving some options to config file, added TheCakeIsNaOH's (Thanks!) move args to params and add help comments merge, minor updates to package URL checking and noficiations, no longer checks URLs with variables baked in, don't display PS error when non-image icon files are downloaded, less false positives checking for sourceforge and fosshub links in chocolateyinstall.ps1, updated markdown checking to display error line(s), checks chocolateyinstall.ps1 for improper use of Install-ChocolateyPackage and Install-ChocolateyZipPackage when binaries are included, new -ReduceOutput option to only show problems/errors (no blue or green informational messages), checks chocolateyinstall.ps1 for use of checksums, added checking for private enviroment variables, reports when http instead of https links are used, fixed bug where releaseNotes wasn't being checked for invalid Markdown
  • 2020.09.21 - recurse switch has been added, thanks TheCakeIsNaOH!
  • 2020.09.20 - An AddPackageNotes feature has been added, works the same as the AddHeader and AddFooter options. Updated nuspec URL errors as requirements to be fixed. Updated online package status messages. Added "PackageInternalFilesIncluded" checking. Minor cosmetic updates.
  • 2020.09.15 - CNC will now ignore update.ps1 files.
  • 2020.04.06.0001 - Updated CNC.cmd for ChocolateyToolsLocation handling. Fixed markdown heading error in CNCHeader.txt.
  • 2020.04.06 - Better error handling when $env:ChocolateyToolsLocation is not defined. (Usually due to running under a different account than installed from.)
  • 2020.01.16 - Updated message related to Markdown heading issues (now a requirement to fix), added Operating System index files checking, added verification that $env:ChocolateyToolsLocation exists (variable, not location)
  • 2019.12.14 - Added checking for Markdown heading declarations that are incompatible with the Sept. 2019 changes to chocolatey.org. (Plan to autofix in a future update.)
  • 2019.09.01 - Added Powershell v3 as a dependency due to Invoke-WebRequest use. Eliminated iwr error for new packages that weren't pushed to chocolatey.org yet, added reporting for packages that are in submitted or waiting for maintainer status, added to the common problems for not a valid XML file messages.
  • 2019.08.26 - "Kicked out of bin release" - script installation endpoint changed. Now works from Command Prompt as well as PowerShell. Additional 7Zip supported formats checked for as binaries.
  • 2019.08.22 - -UpdateXMLNamespace implemented (unreleased due to new moderation demands)
  • 2019.08.21 - added checking for package release notes in description (unreleased due to new moderation demands)
  • 2019.08.14 - now validates the nuspec as a valid XML file and reports common errors, notifies if there is a submitted/unapproved version on chocolatey.org, better checking for failed and trusted package notifications (unreleased due to new moderation demands)
  • 2019.08.13 - minor fix to cinst checking in chocolateyinstall.ps1 (unreleased due to new moderation demands)
  • 2019.03.04 - now checks for msiexec calls in scripts, checks for correctly named install script, checks that install scripts don't use choco commands, checks the XML namespace/schema, cosmetic changes
  • 2019.02.22 - now notifies if the package is trusted and if the package is failing tests on chocolatey.org, -OptimizePNGs superseded by -OptimizeImages which will now optimize BMP, GIF, and TGA files as well as PNG files, added checking for FossHub download links in chocolateyInstall.ps1, more minor tweaks
  • 2019.02.18 - now checks download URLs in install scripts, minor message updates
  • 2019.02.16 - -UpdateScripts will re-write PowerShell scripts to UTF-8 w/BOM (even if EAP statement doesn't need to be added), now checks for and reports templated values, adding the XML UTF-8 check comment now implemented, more updates to summary, added checking for SourceForge download links in chocolateyInstall.ps1, -MakeBackups option to create *.CNC.bak files - this is a breaking change from v2019.01.29 where making backups was default, check for CDATA in description and parse it for problems but not change it when saving, some more tweaks that I forgot before writing this
  • 2019.02.04 - New -UpdateScripts will add EAP statement to script files and re-write out to UTF-8 w/BOM, New -UseGitHack, -UseGitCDN, and -UsejsDelivr allows you to use image CDNs other than Staticaly (default), CNC now gives a summary count of warnings and fixes, now checks for header/footer before adding so duplicates aren't created, now checks all PowerShell scripts (previously only chocolateyinstall/uninstall), cosmetic changes to highlight required changes
  • 2019.01.29 - you can now use the following tokens in your header and footer files: $NuspecAuthors, $NuspecID, $NuspecOwners, $NuspecTitle, and $NuspecVersion - they will be parsed and replaced with the values from your nuspec file, added checking iconUrl image dimensions, new -OptimizePNGs option to run PNGOptimizerCL (if installed via Chocolatey) on PNG files in nuspec dir, added checking for lack of BOM in install/uninstall scripts, added checking for $ErrorActionPreference statement in install/uninstall scripts, now aborts when there are multiple nuspec files found in the same directory, now aborts if nuspec appears corrupt, cosmetic enhancements, now makes a backup file upon updates.
  • 2019.01.26 - "Birthday Release" CNC is now considered "Ready for Prime Time." (I still have more updates planned.) CNC can now write changes to your nuspec file including the iconUrl, description, and XML declaration (Finally!!!), added ability to update the XML declaration, added -UpdateAll and -Update options, updates are written as UTF-8 w/o BOM, cleaned up UTF-8 reporting, added PowerShell syntax error checking of chocolateyInstall.ps1 and chocolateyUninstall.ps1, new -WhatIf option for testing without saving changes, the normal minor tweaks and cosmetic changes. I will keep making it better though, of course.
  • 2019.01.22 - added XML declaration and UTF-8 comment checking, better dependency version checking, a rare verifier message I missed
  • 2019.01.15 - you can now specify a path to a directory containing a .nuspec file to check, misc minor tweaks
  • 2019.01.13 - finished the dependencies checking, all verifier messages (guidelines, suggestions, and notes) now reporting in CNC
  • 2019.01.12 - minor fixes
  • 2019.01.09 - many more checks and warnings added, almost all known verifier guidelines, suggestions and notes added, some beautifications, added option to view Chocolatey validator info page, added optional image GitHub direct and RawGit URL conversions to Staticaly CDN URLs
  • 2019.01.07 - added help, added option to open and view all URLs in your default browser, added options to view, edit, and add "standard" (template) headers and footers to the description (can't save yet), added reporting of standard header and footer if found, added more verifier messages, added checking for descriptions that are too large (>4,000), now checks for license files other than LICENSE.txt, probably more I don't remember :)
  • 2019.01.04 - implemented included binary files checking and messages, laid out the groundwork for the future enhancements
  • 2019.01.03 - fixed some URL checking handling that could cause PS errors, updated list of CDN recommendations, added checking for RawGit URLs in description, cosmetic updates
  • 2018.12.22-2018-12.28 - initial release

ROADMAP:

  • Address new Validator changes: https://blog.chocolatey.org/2022/08/upcoming-changes-validator/ - HIGH PRIORITY
  • Update CDN checking for "main" as well as "master" post 10/2020 (did this happen?)
  • Check validity of URLs in description, checked by the package verifier as of 01/11/2020
  • Reformat invalid Markdown headings automagically (Need to parse out and skip URLs.)
  • Add option of displaying useful tips and tweaks (AutoHotKey, BeCyIconGrabber, PngOptimizer, Regshot, service viewer program, etc)
  • MAYBE edit and re-write handling CDATA in description (not sure if there is a need)
  • Possibly add option to run scripts through PSScriptAnalyzer
  • What else? (PRs accepted)

Discussion for the (unofficial) Chocolatey .nuspec Checker (CNC) (Script) Package

Ground Rules:

  • This discussion is only about (unofficial) Chocolatey .nuspec Checker (CNC) (Script) and the (unofficial) Chocolatey .nuspec Checker (CNC) (Script) package. If you have feedback for Chocolatey, please contact the Google Group.
  • This discussion will carry over multiple versions. If you have a comment about a particular version, please note that in your comments.
  • The maintainers of this Chocolatey Package will be notified about new comments that are posted to this Disqus thread, however, it is NOT a guarantee that you will get a response. If you do not hear back from the maintainers after posting a message below, please follow up by using the link on the left side of this page or follow this link to contact maintainers. If you still hear nothing back, please follow the package triage process.
  • Tell us what you love about the package or (unofficial) Chocolatey .nuspec Checker (CNC) (Script), or tell us what needs improvement.
  • Share your experiences with the package, or extra configuration or gotchas that you've found.
  • If you use a url, the comment will be flagged for moderation until you've been whitelisted. Disqus moderated comments are approved on a weekly schedule if not sooner. It could take between 1-5 days for your comment to show up.
comments powered by Disqus