Skip to content

Instantly share code, notes, and snippets.

@tsmarvin
Last active November 10, 2023 03:46
Show Gist options
  • Save tsmarvin/823b52ee8a827bd177bc9584f717319b to your computer and use it in GitHub Desktop.
Save tsmarvin/823b52ee8a827bd177bc9584f717319b to your computer and use it in GitHub Desktop.
TM-ValidationUtility

TM-ValidationUtility Module

Introduction

TM-ValidationUtility is a PowerShell module that provides custom validation attributes for enhanced parameter validation. It offers attributes for checking the existence of paths, validating IPv4 addresses, and ensuring the correct format for GitHub Gist URIs.

This module is part of a suite of tools designed to improve and streamline the PowerShell commandline and scripting experience.
Check out the rest of the modules by visiting my page on the PowerShell Gallery.

Features

  • ValidatePathExistsAttribute: Ensures file or directory paths exist, with the ability to specify files, folders, or any.
  • ValidateIPv4FormatAttribute: Validates strings to ensure they are in a valid IPv4 address format.
  • ValidateGistUriFormatAttribute: Validates that a string conforms to the GitHub Gist URI format.

Requirements

  • Windows PowerShell 5.1+, or PowerShell Core 7+.

Installation

Install TM-ValidationUtility from the PowerShell Gallery:

Install-Module TM-ValidationUtility -Scope CurrentUser -Repository PSGallery

For manual installation, download the module files and place them in a "TM-ValidationUtility" folder in your PowerShell modules directory ($Env:PSModulePath).

MIT License
Copyright (c) 2023 Taylor Marvin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@{
# Script module or binary module file associated with this manifest.
RootModule = 'TM-ValidationUtility.psm1'
# Version number of this module.
ModuleVersion = '0.0.4'
# Supported PSEditions
CompatiblePSEditions = @('Desktop','Core')
# ID used to uniquely identify this module
GUID = '1f1eebe8-7a0b-49ae-901e-c877f090a7fc'
# Author of this module
Author = 'Taylor Marvin'
# Company or vendor of this module
CompanyName = 'N/A'
# Copyright statement for this module
Copyright = 'Taylor Marvin (2023)'
# Description of the functionality provided by this module
Description = 'This is a PowerShell module that provides various validation attributes that add additional parameter validation functionality.'
# Minimum version of the PowerShell engine required by this module
PowerShellVersion = '5.1'
# Modules that must be imported into the global environment prior to importing this module
#RequiredModules = @()
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
FunctionsToExport = @()
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
AliasesToExport = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{
PSData = @{
# Tags applied to this module. These help with module discovery in online galleries.
Tags = @('Profile', 'Utility', 'Validation', 'Attributes')
# A URL to the license for this module.
LicenseUri = 'https://gist.github.com/tsmarvin/823b52ee8a827bd177bc9584f717319b#file-license'
# A URL to the main website for this project.
ProjectUri = 'https://gist.github.com/tsmarvin/823b52ee8a827bd177bc9584f717319b'
# Prerelease string of this module
# Prerelease = ''
# Flag to indicate whether the module requires explicit user acceptance for install/update/save
RequireLicenseAcceptance = $false
}
}
}
using namespace System.IO
using namespace System.Management.Automation
try {
Add-Type -ErrorAction Stop -TypeDefinition @'
using System;
using System.IO;
using System.Management.Automation;
using System.Text.RegularExpressions;
namespace Validation {
#region Exceptions
public class PathNotFound : IOException {
public PathNotFound() :base() { }
public PathNotFound(string message) :base(message) { }
}
public class PathFound : IOException {
public PathFound() :base() { }
public PathFound(string message) :base(message) { }
}
public class InvalidFormat : Exception {
public InvalidFormat() :base() { }
public InvalidFormat(string message) :base(message) { }
}
#endregion Exceptions
#region ValidatePathExistsAttribute
public enum PathType {
File,
Folder,
Any,
None
}
public class ValidatePathExistsAttribute : ValidateArgumentsAttribute {
private PathType _pathType = PathType.Any;
public ValidatePathExistsAttribute() { }
public ValidatePathExistsAttribute(PathType pathType ) { _pathType = pathType ; }
protected override void Validate(object obj, EngineIntrinsics engineIntrinsics) {
string path = string.Empty;
if (obj is FileSystemInfo) {
path = ((FileSystemInfo)obj).FullName;
} else {
path = obj.ToString( ) ?? string.Empty;
}
// Check if path exists.
bool fileExists = File.Exists(path);
bool directoryExists = Directory.Exists(path);
// Build Exception Message String
string msg = (
(_pathType != PathType.Any && _pathType != PathType.None)
? "Path"
: Enum.GetName(typeof(PathType), _pathType
) +
'"' + path + '"' +
(
(_pathType == PathType.None)
? "already exists!"
: "does not exist!")
);
// Validate path
if (string.IsNullOrWhiteSpace(path)) {
throw new ArgumentNullException("Argument cannot be null or whitespace");
} else if (
(_pathType == PathType.Any) &&
(fileExists == false) &&
(directoryExists == false)
) {
throw new PathNotFound(msg);
} else if (_pathType == PathType.Folder && directoryExists == false) {
throw new DirectoryNotFoundException(msg);
} else if (_pathType == PathType.File && fileExists == false) {
throw new FileNotFoundException(msg);
} else if (_pathType == PathType.None && (fileExists || directoryExists)) {
throw new PathFound(msg);
}
}
}
#endregion ValidatePathExistsAttribute
public class ValidateIPv4FormatAttribute : ValidateArgumentsAttribute {
private static Regex _regex = new Regex(@"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
public ValidateIPv4FormatAttribute() { }
protected override void Validate(object obj, EngineIntrinsics engineIntrinsics) {
if ((obj is string) == false) {
throw new InvalidOperationException("Cannot validate non-string arguments.");
} else if (string.IsNullOrWhiteSpace(obj.ToString())) {
throw new ArgumentNullException("Argument cannot be null or whitespace");
} else if (_regex.IsMatch(obj.ToString()) == false) {
throw new InvalidFormat(string.Format("Invalid format for '{0]'. Does not match Gist Uri format.", obj));
}
}
}
public class ValidateGistUriFormatAttribute : ValidateArgumentsAttribute {
private static Regex _regex = new Regex(@"^(https://gist\.github\.com/[[a-zA-Z0-9-_]+|https://api\.github\.com/gists)/[a-zA-Z0-9]{32}$");
public ValidateGistUriFormatAttribute() { }
protected override void Validate(object obj, EngineIntrinsics engineIntrinsics) {
if ((obj is string) == false) {
throw new InvalidOperationException("Cannot validate non-string arguments.");
} else if (string.IsNullOrWhiteSpace(obj.ToString())) {
throw new ArgumentNullException("Argument cannot be null or whitespace");
} else if (_regex.IsMatch(obj.ToString()) == false) {
throw new InvalidFormat(string.Format("Invalid format for '{0]'. Does not match Gist Uri format.", obj));
}
}
}
}
'@
} catch {
if ($_.Exception.Message -notmatch "Cannot add type\. The type name 'Validation\..*' already exists\."){
throw
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment