ExecutechUtilities.psm1
<#
.SYNOPSIS PowerShell Module for Shared and Frequently Used Utility Functions .DESCRIPTION Collection of frequently used helper functions. Required by other Executech scripts and modules. .NOTES Version: 1.0.22 Author: Josiah McCall Website: executech.com Creation Date: 09/12/2023 Purpose/Change: Initial script development Update Date: 2025.01.15 Purpose/Change: Minor formatting changes. Publishing to PS Gallery. PREVIOUS CHANGELOG: 2024.12.11 Revised the Get-ExceptionReport function to address issues found in testing. Updated the New-TimeStamp function to add a -fileName switch to use file-appropriate characters. 2024.11.12 Adjusted the Initialize-Module function to resolve errors related to pre-release modules and versions with '-betaXYZ' on the end. Added a modified version of the Get-WiFiProfile function from the WiFiProfileManagement module (source: https://github.com/jcwalker/WiFiProfileManagement) - Cleaned up function code, replaced inefficient array structures with collections, and bundled all necessary Private functions inside the main function 2024.11.04 Added new function Get-ExceptionReport 2024.10.31 Added new function 'ConvertFrom-DistinguishedName'. Updated the exported functions and aliases in the PSD1 file. 2024.10.14 Updated Get-MySQLEncodedString function to fix PS 7.x error. Updated Get-CleanFileName/Base64/Compress string functions to add pipeline input. 2024.10.03 Added new function: Get-CleanFileName 2024.09.26 Added option to New-LogEntry function to suppress the timestamp. Added additional logic to the Get-LocalTime function to simplify the calls and support input string already in UTC format. 2024.09.17 Add new functions for the IGatherDataSet and IGatherEntry classes; when executing via Import-Module, the classes are not accessible directly. 2024.09.13 Removed all references to the LabTechCommon DLL files. Get/Set CompressedString, AutomateEncryptedString, CleanString, and MySQLEncodedString functions rewritten in native PowerShell code. 2024.08.16 Added Get-MySQLEncodedString function. 03/05/2024 Added function for converting datetime to MySQL string, separate from Get-LocalTime which assumes UTC value. 02/28/2024 Added new CWADataSet class code and functions to initialize. 02/06/2024 Added aliases for several commands. 01/25/2024 Rebuilt the Initialize-Module functions to make them cleaner and more resilient. 01/10/2024 Added IGatherDataSet class. 11/14/2023 Added regions for standard verbs in use (Copy, Get, Set, etc.). Added Copy-ACL and CopyFileTimestamps functions. #> $ModuleVersion = "1.0.22" $ModuleGuid = 'dd8bdf00-aab6-4efc-971a-c0bbe32d1c5c'; Set-Variable -Name HeaderLine -Value '==================================================================================================' -Visibility Public -Scope Local -Option ReadOnly -Force; Set-Variable -Name FooterLine -Value '--------------------------------------------------------------------------------------------------' -Visibility Public -Scope Local -Option ReadOnly -Force; Set-Variable -Name Symbols -Visibility Public -Scope Local -Option ReadOnly -Force -Value $([PSCustomObject]@{ ArrowDown = [char]11107 ArrowDualH = [char]11136 ArrowDualV = [char]11137 ArrowLeft = [char]11104 ArrowRight = [char]11106 ArrowUp = [char]11105 ArrowBiDirH = [char]11108 ArrowBiDirV = [char]11109 Cancel = [char]9747 CancelCircle = [char]11198 CancelSquare = [char]10062 CheckMark = [char]10003 CheckSquare = [char]9989 Crossbones = [char]9760 DblArrowDown = [char]11143 DblArrowLeft = [char]11140 DblArrowRight = [char]11142 DblArrowUp = [char]11141 DottedX = [char]8251 FingerPointL = [char]9754 FingerPointR = [char]9755 Hourglass = [char]8987 Infinity = [char]8734 Information = [char]8505 Keyboard = [char]9000 Recycle = [char]9851 Refresh = [char]11119 Stop = [char]9940 Warning = [char]9888 Watch = [char]8986 }) function Import-LabTechCommon { Write-Verbose "NOTICE: The Import-LabTechCommon function has been deprecated and no longer does anything."; Write-Verbose "NOTICE: All functions that previously relied upon the external DLL files have been rewritten in native PS code."; } # These two are required for the New-MessageBox function. function Import-Presentation { if ($null -eq ([appdomain]::currentdomain.getassemblies() | Where-Object { $_ -match "PresentationCore" })) { try { Add-Type -AssemblyName PresentationCore -ErrorAction Stop; } catch { Write-Warning -Message "WARNING: Failed to import PresentationCore assembly."; Write-Error $_.Exception.Message; } } if ($null -eq ([appdomain]::currentdomain.getassemblies() | Where-Object { $_ -match "PresentationFramework" })) { try { Add-Type -AssemblyName PresentationFramework -ErrorAction Stop; } catch { Write-Warning -Message "WARNING: Failed to import PresentationFramework assembly."; Write-Error $_.Exception.Message; } } } # For the New-InputBox function. function Import-VisualBasic { if ($null -eq ([appdomain]::currentdomain.getassemblies() | Where-Object { $_ -match "Microsoft.VisualBasic" })) { try { Add-Type -AssemblyName Microsoft.VisualBasic -ErrorAction Stop; } catch { Write-Warning -Message "WARNING: Failed to import Microsoft.VisualBasic assembly."; Write-Error $_.Exception.Message; } } } #region Custom Classes #public class IGatherDataSet { [int] $ComputerID [string] $Category [System.Collections.Generic.List[IGatherEntry]] $Data [string] $Log [string] $Errors [bool] $Process IGatherDataSet([int] $computerId, [string] $category, [System.Collections.Generic.List[IGatherEntry]] $gatherEntries, [string] $logs, [string] $errors, [bool] $shouldprocess = $false) { $this.ComputerID = $computerId; $this.Category = $category; $this.Data = $gatherEntries; $this.Log = $logs; $this.Errors = $errors; $this.Process = $shouldprocess; } IGatherDataSet([int] $computerId, [string] $category) { $this.ComputerID = $computerId; $this.Category = $category; $this.Data = [System.Collections.Generic.List[IGatherEntry]]::new(); } IGatherDataSet([System.Management.Automation.PSObject] $psobject) { foreach ($prop in $this.GetType().GetProperties()) { $prop.SetValue($this, $(if ($null -eq $psobject[$prop.Name]) { "" } else { $psobject[$prop.Name] })); } } IGatherDataSet() { $this.Data = [System.Collections.Generic.List[IGatherEntry]]::new(); } } #public class IGatherEntry { [string] $Table [string] $InsertString [string] $DeleteFilter [string] $DuplicateString IGatherEntry([string] $table, [string] $insert, [string] $delete, [string] $dupe) { $this.Table = $table; $this.InsertString = $insert; $this.DeleteFilter = $delete; $this.DuplicateString = $dupe; } IGatherEntry([string] $table, [string] $insert, [string] $delete) { $this.Table = $table; $this.InsertString = $insert; $this.DeleteFilter = $delete; $this.DuplicateString = "NONE"; } IGatherEntry([System.Management.Automation.PSObject] $psobject) { foreach ($prop in $this.GetType().GetProperties()) { $prop.SetValue($this, $(if ($null -eq $psobject[$prop.Name]) { "" } else { $psobject[$prop.Name] })); } } IGatherEntry() { } } $IGatherDataSetCode = @" [System.ComponentModel.TypeConverter(typeof(IGatherDataSet))] public class IGatherDataSet { public int ComputerID { get; set; } public string Category { get; set; } public System.Collections.Generic.List<IGatherEntry> Data { get; set; } public string Log { get; set; } public string Errors { get; set; } public bool Process { get; set; } public IGatherDataSet(int computerId, string category, System.Collections.Generic.List<IGatherEntry> gatherEntries, string logs, string errors, bool shouldprocess = false) { ComputerID = computerId; Category = category; Data = gatherEntries; Log = logs; Errors = errors; Process = shouldprocess; } public IGatherDataSet(System.Management.Automation.PSObject psobject) { foreach (var prop in this.GetType().GetProperties()) { prop.SetValue(this, (psobject.Members[prop.Name] == null ? "" : psobject.Members[prop.Name].Value)); } } public IGatherDataSet(int computerId, string category) { ComputerID = computerId; Category = category; Data = new System.Collections.Generic.List<IGatherEntry> { }; } public IGatherDataSet() { Data = new System.Collections.Generic.List<IGatherEntry> { }; } } [System.ComponentModel.TypeConverter(typeof(IGatherEntry))] public class IGatherEntry { public string Table { get; set; } public string InsertString { get; set; } public string DeleteFilter { get; set; } public string DuplicateString { get; set; } public IGatherEntry(string table, string insert, string delete) { Table = table; InsertString = insert; DeleteFilter = delete; DuplicateString = "NONE"; } public IGatherEntry(string table, string insert, string delete, string dupe) { Table = table; InsertString = insert; DeleteFilter = delete; DuplicateString = dupe; } public IGatherEntry(System.Management.Automation.PSObject psobject) { foreach (var prop in this.GetType().GetProperties()) { prop.SetValue(this, (psobject.Members[prop.Name] == null ? "" : psobject.Members[prop.Name].Value)); } } public IGatherEntry() { } } "@ Set-Variable -Name IGatherDataSet -Value $IGatherDataSetCode -Visibility Public -Scope Local -Option ReadOnly -Force; function Initialize-IGatherDataSet() { $ErrorActionPreference = 'SilentlyContinue'; if (-not ([System.Management.Automation.PSTypeName]'IGatherDataSet').Type) { try { Add-Type -TypeDefinition $IGatherDataSet -Language CSharp -ErrorAction Stop; } catch { throw $_.Exception; } } } $CWADataSetCode = @" public class CWADataSet { public string Task { get; set; } public System.Collections.Generic.List<CWADataEntry> DataQueries { get; set; } public string Logs { get; set; } public string Errors { get; set; } public bool Process { get; set; } public CWADataSet(string task, System.Collections.Generic.List<CWADataEntry> queries, string logs, string errors, bool process) { Task = task; Process = process; DataQueries = queries; Logs = logs; Errors = errors; } public CWADataSet(System.Management.Automation.PSObject psobject) { foreach (var prop in this.GetType().GetProperties()) { prop.SetValue(this, (psobject.Members[prop.Name] == null ? "" : psobject.Members[prop.Name].Value)); } } public CWADataSet(string task) { Task = task; DataQueries = new System.Collections.Generic.List<CWADataEntry> { }; } public CWADataSet() { DataQueries = new System.Collections.Generic.List<CWADataEntry> { }; } } public class CWADataEntry { public string Table { get; set; } public string Insert { get; set; } public string Delete { get; set; } public CWADataEntry(string table, string insert, string delete) { Table = table; Insert = insert; Delete = delete; } public CWADataEntry(System.Management.Automation.PSObject psobject) { foreach (var prop in this.GetType().GetProperties()) { prop.SetValue(this, (psobject.Members[prop.Name] == null ? "" : psobject.Members[prop.Name].Value)); } } public CWADataEntry(string table) { Table = table; Insert = "NONE"; Delete = "NONE"; } public CWADataEntry() { } } "@ Set-Variable -Name CWADataSet -Value $CWADataSetCode -Visibility Public -Scope Local -Option ReadOnly -Force; function Initialize-CWADataSet() { $ErrorActionPreference = 'SilentlyContinue'; if (-not ([System.Management.Automation.PSTypeName]'CWADataSet').Type) { try { Add-Type -TypeDefinition $CWADataSet -Language CSharp; } catch { throw $_.Exception; } } } #endregion Custom Classes #region Copy function Copy-ACL() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)] [ValidateNotNullorEmpty()] [String]$sourcePath, [Parameter(Position = 1, Mandatory)] [ValidateNotNullorEmpty()] [string]$destinationPath ) try { $SourceACL = Get-Acl -Path $sourcePath; $DestinationACL = Get-Acl -Path $destinationPath; $Differences = Compare-Object -ReferenceObject $SourceACL -DifferenceObject $DestinationACL; if (-not($null -eq $Differences)) { Set-Acl -Path $destinationPath -AclObject $SourceACL; return "Copied ACL from $($sourcePath) to $($destinationPath)"; } else { return "$($destinationPath) ACL matches $($sourcePath)"; } } catch { return "ERROR: Failed to copy ACL from $($sourcePath) to $($destinationPath): $($_.Exception.Message)"; } } function Copy-FileTimestamps() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)] [ValidateNotNullorEmpty()] [System.IO.FileInfo]$sourceFile, [Parameter(Position = 1, Mandatory)] [ValidateNotNullorEmpty()] [string]$targetFilePath ) try { $newFile = Get-Item -Path $targetFilePath; if (-not($null -eq $sourceFile.LastAccessTime)) { $newFile.LastAccessTime = $sourceFile.LastAccessTime; } if (-not($null -eq $sourceFile.LastAccessTime)) { $newFile.LastAccessTime = $sourceFile.LastAccessTime; } return "Copied file timestamps from $($sourceFile.FullName) to $($newFile.FullName)"; } catch { return "ERROR: Failed to copy file timestamps from $($sourceFile.FullName) to $($targetFilePath): $($_.Exception.Message)"; } } #endregion Copy #region Convert function ConvertTo-Hashtable { [cmdletbinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] [OutputType([System.Collections.Hashtable])] Param( [Parameter(Position = 0, Mandatory, HelpMessage = "Please specify an object", ValueFromPipeline)] [ValidateNotNullOrEmpty()][object]$InputObject, [switch]$NoEmpty, [string[]]$Exclude, [switch]$Alphabetical, [Parameter(HelpMessage = "Create an ordered hashtable instead of a plain hashtable.")] [switch]$Ordered ) Process { # Get type using the [Type] class because deserialized objects won't have a GetType() method which is what I would normally use. $TypeName = [system.type]::GetTypeArray($InputObject).name Write-Verbose "Converting an object of type $TypeName" #get property names using Get-Member $PropertyNames = $InputObject | Get-Member -MemberType properties | Select-Object -ExpandProperty name if ($Alphabetical) { Write-Verbose "Sort property PropertyNames alphabetically" $PropertyNames = $PropertyNames | Sort-Object } #define an empty hash table if ($Ordered) { Write-Verbose "Creating an ordered hashtable" $hash = [ordered]@{ } } else { $hash = @{ } } #go through the list of PropertyNames and add each property and value to the hash table $PropertyNames | ForEach-Object { if ($Exclude -NotContains $_) { if ($NoEmpty -AND -Not ($InputObject.$_)) { Write-Verbose "Skipping $_ as empty" } else { Write-Verbose "Adding property $_" $hash.Add($_, $InputObject.$_) } } else { Write-Verbose "Excluding $_" } } Write-Verbose "Writing the result to the pipeline" return $hash; } } function ConvertFrom-DistinguishedName { param ( [Parameter(Mandatory, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] [ValidateNotNullOrEmpty()] [alias('dn')] [string]$distinguishedName ) process { $d = [System.Text.StringBuilder]::new(); $p = [System.Text.StringBuilder]::new(); $distinguishedName -split '(?<!\\),' | ForEach-Object { if ($_ -match '^DC=') { [void]$d.Append($_.Substring(3)).Append('.'); } else { [void]$p.Append($('{0}\{1}' -f $_.Substring(3), $p.ToString())); } } return $($('{0}\{1}' -f $d.ToString().Trim('.'), ($p.ToString().TrimEnd('\') -replace '\\,', ','))); } } Set-Alias -Name 'ConvertFrom-DN' -Value ConvertFrom-DistinguishedName -Option ReadOnly -Scope Global -Force; #endregion Convert #region Find function Find-ReplaceStringInFile { [OutputType()] param ( [Parameter(Position = 0, Mandatory)] [ValidateScript({ if (-Not (($_ | Test-Path -PathType Leaf) -or ( Test-Path -LiteralPath $_ ))) { throw "The Path argument must be a file. Folder paths are not allowed." } return $true })] [string]$Path, [Parameter(Position = 1, Mandatory)] [string]$Find, [Parameter(Position = 2, Mandatory)] [string]$Replace, [Parameter(Position = 3, Mandatory = $false)] [bool]$Backup = $true ) begin { $Search = [regex]::Escape($Find); Write-Verbose "Find string: $Search"; } process { try { if (Select-String -LiteralPath $Path -Pattern $Search) { Write-Verbose "Replacing $Find with $Replace in file $Path"; $NewContent = [System.IO.File]::ReadAllText($Path).Replace($Find, $Replace); if (-not([string]::IsNullOrEmpty($NewContent))) { if ($Backup) { Write-Verbose "Copying $Path to $Path.bak"; Move-Item -LiteralPath $Path -Destination "$Path.bak" -Force; } Write-Verbose "Saving changes to $Path"; [System.IO.File]::WriteAllText($Path, $NewContent); return "SUCCESS: $Path updated."; } else { return "ERROR: Failed to read contents of $Path or file is empty." } } else { return "Skipped: $Find was not found in $($Path)." } } catch { return "ERROR: $($_.Exception.Message)"; } } } #endregion Find #region Get function Get-SelfSignedAppCertificate() { Param( [Parameter(Mandatory = $true)] [string]$CommonName, [Parameter(Mandatory = $true)] [DateTime]$StartDate, [Parameter(Mandatory = $true)] [DateTime]$EndDate, [Parameter(Mandatory = $false, HelpMessage = 'Will overwrite existing certificates')] [Switch]$Force, [Parameter(Mandatory = $false)] [SecureString]$Password ) # DO NOT MODIFY BELOW function Remove-LocalCertificate() { # Once the certificates have been been exported we can safely remove them from the store if ($CommonName.ToLower().StartsWith('cn=')) { # Remove CN from common name $CommonName = $CommonName.Substring(3) } $certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object { $_.Subject -eq "CN=$CommonName" } foreach ($c in $certs) { Remove-Item $c.PSPath } } function New-SelfSignedAppCertificate() { #Remove and existing certificates with the same common name from personal and root stores #Need to be very wary of this as could break something if ($CommonName.ToLower().StartsWith('cn=')) { # Remove CN from common name $CommonName = $CommonName.Substring(3) } $certs = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object { $_.Subject -eq "CN=$CommonName" } if ($null -ne $certs -and $certs.Length -gt 0) { if ($Force) { foreach ($c in $certs) { Remove-Item $c.PSPath } } else { LOG $sbERROR "One or more certificates with the same common name (CN=$CommonName) are already located in the local certificate store. Use -Force to remove them"; return $false } } $name = New-Object -com 'X509Enrollment.CX500DistinguishedName.1' $name.Encode("CN=$CommonName", 0) $key = New-Object -com 'X509Enrollment.CX509PrivateKey.1' $key.ProviderName = 'Microsoft RSA SChannel Cryptographic Provider' $key.KeySpec = 1 $key.Length = 2048 $key.SecurityDescriptor = 'D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)' $key.MachineContext = 1 $key.ExportPolicy = 1 # This is required to allow the private key to be exported $key.Create() $serverauthoid = New-Object -com 'X509Enrollment.CObjectId.1' $serverauthoid.InitializeFromValue('1.3.6.1.5.5.7.3.1') # Server Authentication $ekuoids = New-Object -com 'X509Enrollment.CObjectIds.1' $ekuoids.add($serverauthoid) $ekuext = New-Object -com 'X509Enrollment.CX509ExtensionEnhancedKeyUsage.1' $ekuext.InitializeEncode($ekuoids) $cert = New-Object -com 'X509Enrollment.CX509CertificateRequestCertificate.1' $cert.InitializeFromPrivateKey(2, $key, '') $cert.Subject = $name $cert.Issuer = $cert.Subject $cert.NotBefore = $StartDate $cert.NotAfter = $EndDate $cert.X509Extensions.Add($ekuext) $cert.Encode() $enrollment = New-Object -com 'X509Enrollment.CX509Enrollment.1' $enrollment.InitializeFromRequest($cert) $certdata = $enrollment.CreateRequest(0) $enrollment.InstallResponse(2, $certdata, 0, '') return $true } function Export-PfxFile() { if ($CommonName.ToLower().StartsWith('cn=')) { # Remove CN from common name $CommonName = $CommonName.Substring(3) } if ($null -eq $Password) { $Password = Read-Host -Prompt 'Enter Password to protect private key' -AsSecureString } $cert = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object { $_.Subject -eq "CN=$CommonName" } $null = Export-PfxCertificate -Cert $cert -Password $Password -FilePath "c:\Windows\Temp\$($CommonName).pfx" $null = Export-Certificate -Cert $cert -Type CERT -FilePath "c:\Windows\Temp\$CommonName.cer" } if (New-SelfSignedAppCertificate) { $cert = Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object { $_.Subject -eq "CN=$CommonName" } Export-PfxFile; return $cert.Thumbprint; } else { return 'ERROR: Failed to generate certificate.'; } } function Get-NewComplexPassword([int]$passwordNrChars) { Process { $iterations = 0 Do { if ($iterations -ge 20) { return 'ERROR: Complex password generation failed' } $iterations++ $pwdBytes = @() $rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider Do { [byte[]]$byte = [byte]1 $rng.GetBytes($byte) if ($byte[0] -lt 33 -or $byte[0] -gt 126) { CONTINUE } $pwdBytes += $byte[0] } While ($pwdBytes.Count -lt $passwordNrChars) $newPswd = ([char[]]$pwdBytes) -join '' } Until (Test-PasswordComplexity $newPswd) return $newPswd } } function Get-Base64EncodedString() { [Parameter(Mandatory = $false, ValueFromPipeline, HelpMessage = 'String to convert to Base64.')] param([string]$inputString) try { return [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($inputString)) } catch { return $inputString } } Set-Alias -Name 'Encode-String' -Value Get-Base64EncodedString -Option ReadOnly -Scope Global -Force; function Get-Base64DecodedString() { [Parameter(Mandatory = $false, ValueFromPipeline, HelpMessage = 'String to convert from Base64.')] param([string]$inputString) try { return [System.Text.Encoding]::Utf8.GetString([System.Convert]::FromBase64String($inputString)) } catch { return $inputString } } Set-Alias -Name 'Decode-String' -Value Get-Base64DecodedString -Option ReadOnly -Scope Global -Force; function Get-CompressedString() { [Parameter(Mandatory = $false, ValueFromPipeline, HelpMessage = 'String to compress using gzip.')] param([string]$inputString) begin { $memoryStream = [System.IO.MemoryStream]::new(); $gzipStream = [System.IO.Compression.GZipStream]::new($memoryStream, [System.IO.Compression.CompressionMode]::Compress); $streamWriter = [System.IO.StreamWriter]::new($gzipStream); } process { if (-not([string]::IsNullOrEmpty($inputString))) { $streamWriter.WriteLine($inputString) $streamWriter.Flush() $streamWriter.Close() $gzipStream.Close() $memoryStream.Close() return [System.Convert]::ToBase64String($memoryStream.ToArray()); } else { return $null; } } } Set-Alias -Name 'Compress-String' -Value Get-CompressedString -Option ReadOnly -Scope Global -Force; function Get-UnCompressedString() { [Parameter(Mandatory = $false, ValueFromPipeline, HelpMessage = 'String to uncompress using gzip.')] param([string]$inputString) if (-not([string]::IsNullOrEmpty($inputString))) { $memoryStream = [System.IO.MemoryStream]::new([Convert]::FromBase64String($inputString)); $gzipStream = [System.IO.Compression.GZipStream]::new($memoryStream, [System.IO.Compression.CompressionMode]::Decompress); $streamReader = [System.IO.StreamReader]::new($gzipStream); $result = $streamReader.ReadToEnd(); $streamReader.Close(); $gzipStream.Close(); $memoryStream.Close(); return $result; } else { return $null; } } Set-Alias -Name 'Expand-String' -Value Get-UnCompressedString -Option ReadOnly -Scope Global -Force; function Get-AutomateEncryptedString() { param( [Parameter()] [ValidateNotNullOrEmpty()] [string]$InputString = $(throw 'ERROR: Missing the InputString parameter'), [Parameter()] [ValidateNotNullOrEmpty()] [string]$SaltString = $(throw 'ERROR: Missing the SaltString parameter') ) begin { $_initializationVector = [byte[]](240, 3, 45, 29, 0, 76, 173, 59); $result = $null; } process { try { try { $numarray = [System.Text.Encoding]::UTF8.GetBytes($InputString) } catch { try { $numarray = [System.Text.Encoding]::ASCII.GetBytes($InputString) } catch { $result = "ERROR: Failed to parse input string: $($_.Exception.Message)" } } $ddd = New-Object System.Security.Cryptography.TripleDESCryptoServiceProvider; $ddd.key = (New-Object Security.Cryptography.MD5CryptoServiceProvider).ComputeHash([Text.Encoding]::UTF8.GetBytes($SaltString)); $ddd.IV = $_initializationVector; $dd = $ddd.CreateEncryptor(); $result = [System.Convert]::ToBase64String($dd.TransformFinalBlock($numarray, 0, ($numarray.Length))) } catch { $result = "ERROR: Failed to encrypt string: $($_.Exception.Message)"; } finally { if ($dd) { try { $dd.Dispose() } catch { $dd.Clear() } } if ($ddd) { try { $ddd.Dispose() } catch { $ddd.Clear() } } } } end { return $result; } } Set-Alias -Name 'Encrypt-String' -Value Get-AutomateEncryptedString -Option ReadOnly -Scope Global -Force; function Get-AutomateDecryptedString() { param( [Parameter()] [ValidateNotNullOrEmpty()] [string]$InputString = $(throw 'ERROR: Missing the InputString parameter'), [Parameter()] [ValidateNotNullOrEmpty()] [string]$SaltString = $(throw 'ERROR: Missing the SaltString parameter') ) begin { $_initializationVector = [byte[]](240, 3, 45, 29, 0, 76, 173, 59); $result = $null; } process { try { $numarray = [System.Convert]::FromBase64String($InputString) $ddd = New-Object System.Security.Cryptography.TripleDESCryptoServiceProvider $ddd.key = (New-Object Security.Cryptography.MD5CryptoServiceProvider).ComputeHash([Text.Encoding]::UTF8.GetBytes($SaltString)) $ddd.IV = $_initializationVector $dd = $ddd.CreateDecryptor() $result = [System.Text.Encoding]::UTF8.GetString($dd.TransformFinalBlock($numarray, 0, ($numarray.Length))) } catch { $result = "ERROR: Failed to decrypt string: $($_.Exception.Message)" } finally { if ($dd) { try { $dd.Dispose() } catch { $dd.Clear() } } if ($ddd) { try { $ddd.Dispose() } catch { $ddd.Clear() } } } } end { return $result; } } Set-Alias -Name 'Decrypt-String' -Value Get-AutomateDecryptedString -Option ReadOnly -Scope Global -Force; function Get-MySQLEscapedString() { [Parameter(Mandatory = $false, ValueFromPipeline, HelpMessage = 'String to escape for MySQL insert.')] param([string]$inputString) if (-not([string]::IsNullOrEmpty($inputString))) { $stringBuilder = [System.Text.StringBuilder]::new(); try { for ($index = 0; $index -lt $inputString.Length; $index++) { $char = $inputString[$index] switch ($char) { "`0" { [void]$stringBuilder.Append("\0"); } "`b" { [void]$stringBuilder.Append("\b"); } "`t" { [void]$stringBuilder.Append("\t"); } "`n" { [void]$stringBuilder.Append("\n"); } "`r" { [void]$stringBuilder.Append("\r"); } "`u{001A}" { [void]$stringBuilder.Append("\Z"); } "#" { [void]$stringBuilder.Append("\#"); } ";" { [void]$stringBuilder.Append("\;"); } "\" { [void]$stringBuilder.Append("\").Append($char); } "'" { [void]$stringBuilder.Append("\").Append($char); } '"' { [void]$stringBuilder.Append("\").Append($char); } '`' { [void]$stringBuilder.Append("\").Append($char); } "´" { [void]$stringBuilder.Append("\").Append($char); } "’" { [void]$stringBuilder.Append("\").Append($char); } "‘" { [void]$stringBuilder.Append("\").Append($char); } default { if ($char -match "[\u0096\u0097\u0092\u0093\u0094\u0091\u0090]") { [void]$stringBuilder.Append("\").Append($char); } else { [void]$stringBuilder.Append($char); } } } } } catch { return $inputString -replace '\\', '\\' -replace '[''��]', "\'" } return $stringBuilder.ToString().Trim(); } else { return $null; } } Set-Alias -Name 'Get-CS' -Value Get-MySQLEscapedString -Option ReadOnly -Scope Global -Force; Set-Alias -Name 'Get-CleanString' -Value Get-MySQLEscapedString -Option ReadOnly -Scope Global -Force; function Get-CleanFileName { param( [Parameter(Mandatory, ValueFromPipeline)][String]$Filename ) try { $InvalidCharacters = [IO.Path]::GetInvalidFileNameChars() -join ''; $ReplacePattern = '[{0}]' -f [RegEx]::Escape($InvalidCharacters); return ($Filename -replace $ReplacePattern, '_'); } catch { Write-Warning "Failed to parse filename $($Filename) for invalid characters: $($_.Exception.Message)"; return $Filename; } } Set-Alias -Name 'Get-CF' -Value Get-CleanFileName -Option ReadOnly -Scope Global -Force; function Get-RealDate($string) { if ((-not([string]::IsNullOrEmpty($string))) -and $string -ne '1/1/0001 8:00:00 AM') { return $string } else { return '' } } function Get-LocalTime { [cmdletbinding()] [Outputtype([System.Datetime])] Param( [alias('dt')] [string]$Time ) if (-not([string]::IsNullOrEmpty($Time))) { try { # This assumes that input string is in UTC format return $([TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($([datetime]::Parse($time)), 'Pacific Standard Time')).ToString("yyyy-MM-dd HH:mm:ss"); } catch { try { # If that fails, this converts the parsed string to UTC return [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($(([DateTime]$Time).ToUniversalTime()), 'Pacific Standard Time').ToString('yyyy-MM-dd HH:mm:ss'); } catch { Write-Warning "WARNING: Failed to parse or convert string '$($Time)' to Local Time."; return $Time; } } } else { return '0000-00-00 00:00:00' } } function Get-SQLDateTime([DateTime]$Time) { return $Time.ToString("yyyy-MM-dd HH:mm:ss"); } function Get-TitleCase([string]$string) { if (-not([string]::IsNullOrEmpty($string))) { return [cultureinfo]::GetCultureInfo("en-US").TextInfo.ToTitleCase($string) } else { return $null; } } function Get-FirstCharacterUpperCase([string]$string) { if (-not([string]::IsNullOrEmpty($string))) { return $string.Replace($string[0], $string[0].ToString().ToUpper()) } else { return $null; } } Set-Alias -Name 'Get-FCUC' -Value Get-FirstCharacterUpperCase -Option ReadOnly -Scope Global -Force; function Get-HTMLOuterText([string]$htmlString) { try { $html = New-Object -ComObject "HTMLFile"; $html.IHTMLDocument2_write($htmlString); return $html.body.outerText.Trim(); } catch { return $htmlString; } } # Source: https://blog.idera.com/database-tools/get-text-file-encoding function Get-FileEncoding { [cmdletbinding()] param ( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('FullName')] [ValidateScript({ if (-Not ($_ | Test-Path -PathType Leaf) ) { throw "The Path argument must be a file. Folder paths are not allowed." } return $true })] [string]$Path ) begin { $bom = New-Object -TypeName System.Byte[](4); $file = New-Object System.IO.FileStream($Path, 'Open', 'Read'); } process { try { $null = $file.Read($bom, 0, 4) $file.Close() $file.Dispose() $enc = [Text.Encoding]::ASCII; if ($bom[0] -eq 0x2b -and $bom[1] -eq 0x2f -and $bom[2] -eq 0x76) { $enc = [Text.Encoding]::UTF7 } elseif ($bom[0] -eq 0xff -and $bom[1] -eq 0xfe) { $enc = [Text.Encoding]::Unicode } elseif ($bom[0] -eq 0xfe -and $bom[1] -eq 0xff) { $enc = [Text.Encoding]::BigEndianUnicode } elseif ($bom[0] -eq 0x00 -and $bom[1] -eq 0x00 -and $bom[2] -eq 0xfe -and $bom[3] -eq 0xff) { $enc = [Text.Encoding]::UTF32 } elseif ($bom[0] -eq 0xef -and $bom[1] -eq 0xbb -and $bom[2] -eq 0xbf) { $enc = [Text.Encoding]::UTF8 } return $Enc } catch { throw $_.Exception; } } } function Get-FolderSize { [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipeline)]$Path, [ValidateSet('KB', 'MB', 'GB')]$Units = 'MB' ) try { if ((Test-Path $Path) -and (Get-Item $Path).PSIsContainer) { $Measure = Get-ChildItem $Path -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum $Sum = $Measure.Sum / "1$Units" [pscustomobject]@{ 'Path' = $Path "Size($Units)" = $Sum } } } catch { throw $_ } } Set-Alias -Name 'GFS' -Value Get-FolderSize -Option ReadOnly -Scope Global -Force; # Simple function for parsing a value that could be null, boolean, or string function Get-TrueFalseInteger($InputValue) { if ($null -eq $InputValue) { return 0; } else { if ($InputValue -is [Boolean]) { return [int]$InputValue; } else { return [int]($InputValue.ToLower() -eq 'true'); } } } Set-Alias -Name 'TFINT' -Value Get-TrueFalseInteger -Option ReadOnly -Scope Global -Force; function Get-UsernameFromSID($userNameOrSID) { if ($userNameOrSID -match 'S-1-.*') { try { $objSID = New-Object System.Security.Principal.SecurityIdentifier($userNameOrSID); $objUser = $objSID.Translate( [System.Security.Principal.NTAccount]); if (-not($null -eq $objUser)) { return $objUser.Value -replace '\\', '\\' ; } else { return ($userNameOrSID -replace '\\', '\\'); } } catch { return ($userNameOrSID -replace '\\', '\\'); } } else { return ($userNameOrSID -replace '\\', '\\'); } } # Print a more detailed, readable exception message. function Get-ExceptionReport { param( [Parameter(Mandatory, ValueFromPipeline)][object]$Exception, [switch]$includeStackTrace ) $report = [System.Text.StringBuilder]::new(); $IndentPadding = ''; $IndentPadding = $IndentPadding.PadRight(18, ' '); [void]$report.AppendLine($('{0} {1}' -f $(("Message:").PadRight(18)), $Error[0].Exception.Message.Replace("`n", "`n$($IndentPadding)"))); [void]$report.AppendLine($('{0} {1}' -f $(("Category:").PadRight(18)), $Error[0].CategoryInfo.Category)); [void]$report.AppendLine($('{0} {1} ({2})' -f $(("Parameter:").PadRight(18)), $Error[0].Exception.ParameterName, $Error[0].ParameterType)); [void]$report.AppendLine($('{0} {1}' -f $(("Error Id:").PadRight(18)), $Error[0].Exception.ErrorId)); if(-not($null -eq $Error[0].InvocationInfo)){ [void]$report.AppendLine($('{0} {1}' -f $(("Command:").PadRight(18)), $Error[0].InvocationInfo.MyCommand.Name)); [void]$report.AppendLine($('{0} {1}' -f $(("Line:").PadRight(18)), $Error[0].InvocationInfo.Line.Replace("`n", "`n$($IndentPadding)"))); [void]$report.AppendLine($('{0} {1}' -f $(("Source:").PadRight(18)), $Error[0].InvocationInfo.MyCommand.Source)); [void]$report.AppendLine($('{0} {1}' -f $(("Position:").PadRight(18)), $Error[0].InvocationInfo.PositionMessage.Replace("`n", "`n$($IndentPadding)"))); } elseif (-not($null -eq $Error[0].Exception.CommandInvocation)){ [void]$report.AppendLine($('{0} {1}' -f $(("Command:").PadRight(18)), $Error[0].Exception.CommandInvocation.MyCommand.Name)); [void]$report.AppendLine($('{0} {1}' -f $(("Line:").PadRight(18)), $Error[0].Exception.CommandInvocation.Line.Replace("`n", "`n$($IndentPadding)"))); [void]$report.AppendLine($('{0} {1}' -f $(("Source:").PadRight(18)), $Error[0].Exception.CommandInvocation.MyCommand.Source)); [void]$report.AppendLine($('{0} {1}' -f $(("Position:").PadRight(18)), $Error[0].Exception.CommandInvocation.PositionMessage.Replace("`n", "`n$($IndentPadding)"))); } if(($includeStackTrace.IsPresent) -and -not($null -eq $Error[0].Exception.StackTrace)){ [void]$report.AppendLine($('{0} {1}' -f $(("Stack Trace:").PadRight(18)), $Error[0].Exception.StackTrace.Replace("`n", "`n$($IndentPadding)"))); } if(-not($null -eq $Error[0].Exception.InnerException)){ if(-not($null -eq $Error[0].Exception.InnerException.ErrorRecord.FullyQualifiedErrorId)){ [void]$report.AppendLine($('{0} {1}' -f $(("Inner Error:").PadRight(18)), $Error[0].Exception.InnerException.ErrorRecord.FullyQualifiedErrorId)); } if(-not($null -eq $Error[0].Exception.InnerException.Message)){ [void]$report.AppendLine($('{0} {1}' -f $(("Inner Message:").PadRight(18)), $Error[0].Exception.InnerException.Message.Replace("`n", "`n$($IndentPadding)"))); } } return $report.ToString(); } $WlanGetProfileListSig = @' [DllImport("wlanapi.dll")] public static extern uint WlanOpenHandle( [In] UInt32 clientVersion, [In, Out] IntPtr pReserved, [Out] out UInt32 negotiatedVersion, [Out] out IntPtr clientHandle ); [DllImport("Wlanapi.dll")] public static extern uint WlanCloseHandle( [In] IntPtr ClientHandle, IntPtr pReserved ); [DllImport("wlanapi.dll", SetLastError = true, CallingConvention=CallingConvention.Winapi)] public static extern uint WlanGetProfileList( [In] IntPtr clientHandle, [In, MarshalAs(UnmanagedType.LPStruct)] Guid interfaceGuid, [In] IntPtr pReserved, [Out] out IntPtr profileList ); [DllImport("wlanapi.dll")] public static extern uint WlanGetProfile( [In]IntPtr clientHandle, [In, MarshalAs(UnmanagedType.LPStruct)] Guid interfaceGuid, [In, MarshalAs(UnmanagedType.LPWStr)] string profileName, [In, Out] IntPtr pReserved, [Out, MarshalAs(UnmanagedType.LPWStr)] out string pstrProfileXml, [In, Out, Optional] ref uint flags, [Out, Optional] out uint grantedAccess ); [DllImport("wlanapi.dll", EntryPoint = "WlanFreeMemory")] public static extern void WlanFreeMemory( [In] IntPtr pMemory ); [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)] public struct WLAN_CONNECTION_PARAMETERS { public WLAN_CONNECTION_MODE wlanConnectionMode; public string strProfile; public DOT11_SSID[] pDot11Ssid; public DOT11_BSSID_LIST[] pDesiredBssidList; public DOT11_BSS_TYPE dot11BssType; public uint dwFlags; } public struct DOT11_BSSID_LIST { public NDIS_OBJECT_HEADER Header; public ulong uNumOfEntries; public ulong uTotalNumOfEntries; public IntPtr BSSIDs; } public struct NDIS_OBJECT_HEADER { public byte Type; public byte Revision; public ushort Size; } public struct WLAN_PROFILE_INFO_LIST { public uint dwNumberOfItems; public uint dwIndex; public WLAN_PROFILE_INFO[] ProfileInfo; public WLAN_PROFILE_INFO_LIST(IntPtr ppProfileList) { dwNumberOfItems = (uint)Marshal.ReadInt32(ppProfileList); dwIndex = (uint)Marshal.ReadInt32(ppProfileList, 4); ProfileInfo = new WLAN_PROFILE_INFO[dwNumberOfItems]; IntPtr ppProfileListTemp = new IntPtr(ppProfileList.ToInt64() + 8); for (int i = 0; i < dwNumberOfItems; i++) { ppProfileList = new IntPtr(ppProfileListTemp.ToInt64() + i * Marshal.SizeOf(typeof(WLAN_PROFILE_INFO))); ProfileInfo[i] = (WLAN_PROFILE_INFO)Marshal.PtrToStructure(ppProfileList, typeof(WLAN_PROFILE_INFO)); } } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct WLAN_PROFILE_INFO { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string strProfileName; public WlanProfileFlags ProfileFLags; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct DOT11_SSID { /// ULONG->unsigned int public uint uSSIDLength; /// UCHAR[] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string ucSSID; } public enum DOT11_BSS_TYPE { Infrastructure = 1, Independent = 2, Any = 3, } public enum DOT11_PHY_TYPE { dot11_phy_type_unknown = 0, dot11_phy_type_any = 0, dot11_phy_type_fhss = 1, dot11_phy_type_dsss = 2, dot11_phy_type_irbaseband = 3, dot11_phy_type_ofdm = 4, dot11_phy_type_hrdsss = 5, dot11_phy_type_erp = 6, dot11_phy_type_ht = 7, dot11_phy_type_vht = 8, dot11_phy_type_IHV_start = -2147483648, dot11_phy_type_IHV_end = -1, } public enum DOT11_AUTH_ALGORITHM { DOT11_AUTH_ALGO_80211_OPEN = 1, DOT11_AUTH_ALGO_80211_SHARED_KEY = 2, DOT11_AUTH_ALGO_WPA = 3, DOT11_AUTH_ALGO_WPA_PSK = 4, DOT11_AUTH_ALGO_WPA_NONE = 5, DOT11_AUTH_ALGO_RSNA = 6, DOT11_AUTH_ALGO_RSNA_PSK = 7, DOT11_AUTH_ALGO_WPA3 = 8, DOT11_AUTH_ALGO_WPA3_SAE = 9, DOT11_AUTH_ALGO_OWE = 10, DOT11_AUTH_ALGO_WPA3_ENT = 11, DOT11_AUTH_ALGO_IHV_START = -2147483648, DOT11_AUTH_ALGO_IHV_END = -1, } public enum DOT11_CIPHER_ALGORITHM { /// DOT11_CIPHER_ALGO_NONE -> 0x00 DOT11_CIPHER_ALGO_NONE = 0, /// DOT11_CIPHER_ALGO_WEP40 -> 0x01 DOT11_CIPHER_ALGO_WEP40 = 1, /// DOT11_CIPHER_ALGO_TKIP -> 0x02 DOT11_CIPHER_ALGO_TKIP = 2, /// DOT11_CIPHER_ALGO_CCMP -> 0x04 DOT11_CIPHER_ALGO_CCMP = 4, /// DOT11_CIPHER_ALGO_WEP104 -> 0x05 DOT11_CIPHER_ALGO_WEP104 = 5, /// DOT11_CIPHER_ALGO_BIP -> 0x06 DOT11_CIPHER_ALGO_BIP = 6, /// DOT11_CIPHER_ALGO_GCMP -> 0x08 DOT11_CIPHER_ALGO_GCMP = 8, /// DOT11_CIPHER_ALGO_GCMP_256 -> 0x09 DOT11_CIPHER_ALGO_GCMP_256 = 9, /// DOT11_CIPHER_ALGO_CCMP_256 -> 0x0a DOT11_CIPHER_ALGO_CCMP_256 = 10, /// DOT11_CIPHER_ALGO_BIP_GMAC_128 -> 0x0b DOT11_CIPHER_ALGO_BIP_GMAC_128 = 11, /// DOT11_CIPHER_ALGO_BIP_GMAC_256 -> 0x0c DOT11_CIPHER_ALGO_BIP_GMAC_256 = 12, /// DOT11_CIPHER_ALGO_BIP_CMAC_256 -> 0x0d DOT11_CIPHER_ALGO_BIP_CMAC_256 = 13, /// DOT11_CIPHER_ALGO_WPA_USE_GROUP -> 0x100 DOT11_CIPHER_ALGO_WPA_USE_GROUP = 256, /// DOT11_CIPHER_ALGO_RSN_USE_GROUP -> 0x100 DOT11_CIPHER_ALGO_RSN_USE_GROUP = 256, /// DOT11_CIPHER_ALGO_WEP -> 0x101 DOT11_CIPHER_ALGO_WEP = 257, /// DOT11_CIPHER_ALGO_IHV_START -> 0x80000000 DOT11_CIPHER_ALGO_IHV_START = -2147483648, /// DOT11_CIPHER_ALGO_IHV_END -> 0xffffffff DOT11_CIPHER_ALGO_IHV_END = -1, } public enum WLAN_CONNECTION_MODE { wlan_connection_mode_profile, wlan_connection_mode_temporary_profile, wlan_connection_mode_discovery_secure, wlan_connection_mode_discovery_unsecure, wlan_connection_mode_auto, wlan_connection_mode_invalid, } [Flags] public enum WlanConnectionFlag { Default = 0, HiddenNetwork = 1, AdhocJoinOnly = 2, IgnorePrivayBit = 4, EapolPassThrough = 8, PersistDiscoveryProfile = 10, PersistDiscoveryProfileConnectionModeAuto = 20, PersistDiscoveryProfileOverwriteExisting = 40 } [Flags] public enum WlanProfileFlags { AllUser = 0, GroupPolicy = 1, User = 2 } public class ProfileInfo { public string ProfileName; public string ConnectionMode; public string Authentication; public string Encryption; public string Password; public bool ConnectHiddenSSID; public string EAPType; public string ServerNames; public string TrustedRootCA; public string Xml; } [DllImport("Wlanapi.dll", SetLastError = true)] public static extern uint WlanEnumInterfaces ( [In] IntPtr hClientHandle, [In] IntPtr pReserved, [Out] out IntPtr ppInterfaceList ); public struct WLAN_INTERFACE_INFO_LIST { public uint dwNumberOfItems; public uint dwIndex; public WLAN_INTERFACE_INFO[] wlanInterfaceInfo; public WLAN_INTERFACE_INFO_LIST(IntPtr ppInterfaceInfoList) { dwNumberOfItems = (uint)Marshal.ReadInt32(ppInterfaceInfoList); dwIndex = (uint)Marshal.ReadInt32(ppInterfaceInfoList, 4); wlanInterfaceInfo = new WLAN_INTERFACE_INFO[dwNumberOfItems]; IntPtr ppInterfaceInfoListTemp = new IntPtr(ppInterfaceInfoList.ToInt64() + 8); for (int i = 0; i < dwNumberOfItems; i++) { ppInterfaceInfoList = new IntPtr(ppInterfaceInfoListTemp.ToInt64() + i * Marshal.SizeOf(typeof(WLAN_INTERFACE_INFO))); wlanInterfaceInfo[i] = (WLAN_INTERFACE_INFO)Marshal.PtrToStructure(ppInterfaceInfoList, typeof(WLAN_INTERFACE_INFO)); } } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct WLAN_INTERFACE_INFO { public Guid Guid; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string Description; public WLAN_INTERFACE_STATE State; } public enum WLAN_INTERFACE_STATE { not_ready = 0, connected = 1, ad_hoc_network_formed = 2, disconnecting = 3, disconnected = 4, associating = 5, discovering = 6, authenticating = 7 } [DllImport("Wlanapi.dll",SetLastError=true)] public static extern uint WlanScan( IntPtr hClientHandle, ref Guid pInterfaceGuid, IntPtr pDot11Ssid, IntPtr pIeData, IntPtr pReserved ); [DllImport("Wlanapi.dll")] public static extern uint WlanSetInterface( IntPtr hClientHandle, ref Guid pInterfaceGuid, WLAN_INTF_OPCODE OpCode, uint dwDataSize, IntPtr pData , IntPtr pReserved ); public enum WLAN_INTF_OPCODE { /// wlan_intf_opcode_autoconf_start -> 0x000000000 wlan_intf_opcode_autoconf_start = 0, wlan_intf_opcode_autoconf_enabled, wlan_intf_opcode_background_scan_enabled, wlan_intf_opcode_media_streaming_mode, wlan_intf_opcode_radio_state, wlan_intf_opcode_bss_type, wlan_intf_opcode_interface_state, wlan_intf_opcode_current_connection, wlan_intf_opcode_channel_number, wlan_intf_opcode_supported_infrastructure_auth_cipher_pairs, wlan_intf_opcode_supported_adhoc_auth_cipher_pairs, wlan_intf_opcode_supported_country_or_region_string_list, wlan_intf_opcode_current_operation_mode, wlan_intf_opcode_supported_safe_mode, wlan_intf_opcode_certified_safe_mode, /// wlan_intf_opcode_autoconf_end -> 0x0fffffff wlan_intf_opcode_autoconf_end = 268435455, /// wlan_intf_opcode_msm_start -> 0x10000100 wlan_intf_opcode_msm_start = 268435712, wlan_intf_opcode_statistics, wlan_intf_opcode_rssi, /// wlan_intf_opcode_msm_end -> 0x1fffffff wlan_intf_opcode_msm_end = 536870911, /// wlan_intf_opcode_security_start -> 0x20010000 wlan_intf_opcode_security_start = 536936448, /// wlan_intf_opcode_security_end -> 0x2fffffff wlan_intf_opcode_security_end = 805306367, /// wlan_intf_opcode_ihv_start -> 0x30000000 wlan_intf_opcode_ihv_start = 805306368, /// wlan_intf_opcode_ihv_end -> 0x3fffffff wlan_intf_opcode_ihv_end = 1073741823, } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct WlanPhyRadioState { public int dwPhyIndex; public Dot11RadioState dot11SoftwareRadioState; public Dot11RadioState dot11HardwareRadioState; } public enum Dot11RadioState : uint { Unknown = 0, On, Off } public enum WLAN_OPCODE_VALUE_TYPE { /// wlan_opcode_value_type_query_only -> 0 wlan_opcode_value_type_query_only = 0, /// wlan_opcode_value_type_set_by_group_policy -> 1 wlan_opcode_value_type_set_by_group_policy = 1, /// wlan_opcode_value_type_set_by_user -> 2 wlan_opcode_value_type_set_by_user = 2, /// wlan_opcode_value_type_invalid -> 3 wlan_opcode_value_type_invalid = 3 } [DllImport("Wlanapi", EntryPoint = "WlanQueryInterface")] public static extern uint WlanQueryInterface( [In] IntPtr hClientHandle, [In] ref Guid pInterfaceGuid, WLAN_INTF_OPCODE OpCode, IntPtr pReserved, [Out] out uint pdwDataSize, ref IntPtr ppData, IntPtr pWlanOpcodeValueType ); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct WLAN_CONNECTION_ATTRIBUTES { /// WLAN_INTERFACE_STATE->_WLAN_INTERFACE_STATE public WLAN_INTERFACE_STATE isState; /// WLAN_CONNECTION_MODE->_WLAN_CONNECTION_MODE public WLAN_CONNECTION_MODE wlanConnectionMode; /// WCHAR[256] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string strProfileName; /// WLAN_ASSOCIATION_ATTRIBUTES->_WLAN_ASSOCIATION_ATTRIBUTES public WLAN_ASSOCIATION_ATTRIBUTES wlanAssociationAttributes; /// WLAN_SECURITY_ATTRIBUTES->_WLAN_SECURITY_ATTRIBUTES public WLAN_SECURITY_ATTRIBUTES wlanSecurityAttributes; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DOT11_MAC_ADDRESS { public byte one; public byte two; public byte three; public byte four; public byte five; public byte six; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct WLAN_ASSOCIATION_ATTRIBUTES { /// DOT11_SSID->_DOT11_SSID public DOT11_SSID dot11Ssid; /// DOT11_BSS_TYPE->_DOT11_BSS_TYPE public DOT11_BSS_TYPE dot11BssType; /// DOT11_MAC_ADDRESS->UCHAR[6] //// public DOT11_MAC_ADDRESS dot11Bssid; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte[] _dot11Bssid; /// DOT11_PHY_TYPE->_DOT11_PHY_TYPE public DOT11_PHY_TYPE dot11PhyType; /// ULONG->unsigned int public uint uDot11PhyIndex; /// WLAN_SIGNAL_QUALITY->ULONG->unsigned int public uint wlanSignalQuality; /// ULONG->unsigned int public uint ulRxRate; /// ULONG->unsigned int public uint ulTxRate; } [StructLayout(LayoutKind.Sequential)] public struct WLAN_SECURITY_ATTRIBUTES { /// <summary> /// BOOL->int /// </summary> [MarshalAs(UnmanagedType.Bool)] public bool bSecurityEnabled; /// <summary> /// BOOL->int /// </summary> [MarshalAs(UnmanagedType.Bool)] public bool bOneXEnabled; /// <summary> /// DOT11_AUTH_ALGORITHM->_DOT11_AUTH_ALGORITHM /// </summary> public DOT11_AUTH_ALGORITHM dot11AuthAlgorithm; /// <summary> /// DOT11_CIPHER_ALGORITHM->_DOT11_CIPHER_ALGORITHM /// </summary> public DOT11_CIPHER_ALGORITHM dot11CipherAlgorithm; } '@ $WlanGetProfileListErrorCodes = @' ErrorOpeningHandle = Error opening WiFi handle. Message {0} HandleClosed = Handle successfully closed. ErrorClosingHandle = Error closing handle. Message {0} ErrorGettingProfile = Error getting profile info. Error code: {0} ProfileNotFound = Profile {0} not found. Note ProfileName is case sensitive. ErrorDeletingProfile = Error deleting profile. Message {0} ShouldProcessDelete = Deletion of profile {0} ErrorWlanConnect = Error connecting to {0} : {1} SuccessWlanConnect = Successfully connected to {0} : {1} ErrorReasonCode = Failed to format reason code. Error message: {0} ErrorFreeMemory = Failed to free memory. Error message: {0} ErrorGetAvailableNetworkList = Error invoking WlanGetAvailableNetworkList. Message {0} ErrorWiFiInterfaceNotFound = Wi-Fi interface not found on the system. ErrorNotWiFiAdapter = Adapter with name: {0} is not a WiFi capable. ErrorNoWiFiAdaptersFound = No wifi interfaces found. ErrorMoreThanOneInterface = More than one Wi-Fi interface found. Please specify a specific interface. ErrorNeedSingleAdapterName = More than one Wi-Fi adapter found. Please specify a single adapter name. ErrorFailedWithExitCode = Failed with exit code {0}. '@; function Get-WiFiProfile { [CmdletBinding()] [OutputType([System.Management.Automation.PSCustomObject])] param ( [Parameter(Position = 0)][System.String[]]$ProfileName, [Parameter()][System.String]$WiFiAdapterName, [Parameter()][Switch]$ClearKey ) $ErrorCodes = ConvertFrom-StringData $WlanGetProfileListErrorCodes; $null = Add-Type -MemberDefinition $WlanGetProfileListSig -Name ProfileManagement -Namespace WiFi -Using System.Text -PassThru; function New-WiFiHandle { [CmdletBinding()] [OutputType([System.IntPtr])] param() $maxClient = 2; [Ref]$negotiatedVersion = 0; $clientHandle = [IntPtr]::zero; $result = [WiFi.ProfileManagement]::WlanOpenHandle($maxClient, [IntPtr]::Zero, $negotiatedVersion, [ref] $clientHandle); if ($result -eq 0) { return $clientHandle; } else { throw $($ErrorCodes.ErrorOpeningHandle -f $(Format-Win32Exception -ReturnCode $result)); } } function Remove-WiFiHandle { [OutputType([void])] [CmdletBinding()] param( [Parameter()][System.IntPtr]$ClientHandle ) $result = [WiFi.ProfileManagement]::WlanCloseHandle($ClientHandle, [IntPtr]::zero); if ($result -eq 0) { Write-Verbose -Message ($ErrorCodes.HandleClosed); } else { throw $($ErrorCodes.ErrorClosingHandle -f $(Format-Win32Exception -ReturnCode $result)); } } function Format-Win32Exception { [OutputType([System.String])] [CmdletBinding()] param( [Parameter(Mandatory = $true)][System.Int32]$ReturnCode ) return [System.ComponentModel.Win32Exception]::new($ReturnCode).Message; } function Format-WiFiReasonCode { [OutputType([System.String])] [Cmdletbinding()] param( [Parameter()][System.IntPtr]$ReasonCode ) $stringBuilder = New-Object -TypeName Text.StringBuilder; $stringBuilder.Capacity = 1024; $result = [WiFi.ProfileManagement]::WlanReasonCodeToString($ReasonCode.ToInt32(), $stringBuilder.Capacity, $stringBuilder, [IntPtr]::zero); if ($result -ne 0) { Write-Error -Message ($ErrorCodes.ErrorReasonCode -f $(Format-Win32Exception -ReturnCode $result)); } return $stringBuilder.ToString(); } function Invoke-WlanFreeMemory { [OutputType([void])] [CmdletBinding()] param ( [Parameter(Mandatory = $true)][System.IntPtr[]]$Pointer ) foreach ($ptr in $Pointer) { if ($ptr -ne 0) { try { [WiFi.ProfileManagement]::WlanFreeMemory($ptr); } catch { throw $($ErrorCodes.ErrorFreeMemory -f $errorMessage); } } } } function Get-WiFiProfileInfo { [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding()] param( [Parameter()][System.String]$ProfileName, [Parameter()][System.Guid]$InterfaceGuid, [Parameter()][System.IntPtr]$ClientHandle, [System.Int16]$WlanProfileFlags ) begin { [String] $pstrProfileXml = $null; $wlanAccess = 0; $WlanProfileFlagsInput = $WlanProfileFlags; } process { $result = [WiFi.ProfileManagement]::WlanGetProfile($ClientHandle, $InterfaceGuid, $ProfileName, [IntPtr]::Zero, [ref] $pstrProfileXml, [ref] $WlanProfileFlags, [ref] $wlanAccess); if ($result -ne 0) { throw $($ErrorCodes.ErrorGettingProfile -f $(Format-Win32Exception -ReturnCode $result)); } $wlanProfile = [xml] $pstrProfileXml; $password = $null; if ($WlanProfileFlagsInput -eq 13) { $password = $wlanProfile.WLANProfile.MSM.security.sharedKey.keyMaterial; } $connectHiddenSSID = $false; if ([bool]::TryParse($wlanProfile.WLANProfile.SSIDConfig.nonBroadcast, [ref] $null)) { $connectHiddenSSID = [bool]::Parse($wlanProfile.WLANProfile.SSIDConfig.nonBroadcast); } $eapType = $null; if ($wlanProfile.WLANProfile.MSM.security.authEncryption.useOneX -eq 'true') { switch ($wlanProfile.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig.EapMethod.Type.InnerText) { '25' { $eapType = 'PEAP'; #EAP-PEAP (MSCHAPv2) } '13' { $eapType = 'TLS'; #EAP-TLS } Default { $eapType = 'Unknown'; } } } # Parse Validation Server Name if ($null -ne $eapType) { switch ($eapType) { 'PEAP' { $serverNames = $wlanProfile.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig.Config.Eap.EapType.ServerValidation.ServerNames; } 'TLS' { $node = $wlanProfile.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig.Config.SelectNodes("//*[local-name()='ServerNames']"); $serverNames = $node[0].InnerText; } } } # Parse Validation TrustedRootCA if ($null -ne $eapType) { switch ($eapType) { 'PEAP' { $trustedRootCa = ([string] ($wlanProfile.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig.Config.Eap.EapType.ServerValidation.TrustedRootCA -replace ' ', [string]::Empty)).ToLower(); } 'TLS' { $node = $wlanProfile.WLANProfile.MSM.security.OneX.EAPConfig.EapHostConfig.Config.SelectNodes("//*[local-name()='TrustedRootCA']"); $trustedRootCa = ([string] ($node[0].InnerText -replace ' ', [string]::Empty)).ToLower(); } } } [WiFi.ProfileManagement+ProfileInfo]@{ ProfileName = $wlanProfile.WLANProfile.SSIDConfig.SSID.name ConnectionMode = $wlanProfile.WLANProfile.connectionMode Authentication = $wlanProfile.WLANProfile.MSM.security.authEncryption.authentication Encryption = $wlanProfile.WLANProfile.MSM.security.authEncryption.encryption Password = $password ConnectHiddenSSID = $connectHiddenSSID EAPType = $eapType ServerNames = $serverNames TrustedRootCA = $trustedRootCa Xml = $pstrProfileXml } } end { $xmlPtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalAuto($pstrProfileXml); Invoke-WlanFreeMemory -Pointer $xmlPtr; } } function Get-WiFiInterface { [CmdletBinding()] [OutputType([WiFi.ProfileManagement+WLAN_INTERFACE_INFO])] param () $interfaceListPtr = 0; $clientHandle = New-WiFiHandle; try { [void] [WiFi.ProfileManagement]::WlanEnumInterfaces($clientHandle, [IntPtr]::zero, [ref] $interfaceListPtr); $wiFiInterfaceList = [WiFi.ProfileManagement+WLAN_INTERFACE_INFO_LIST]::new($interfaceListPtr); foreach ($wlanInterfaceInfo in $wiFiInterfaceList.wlanInterfaceInfo) { [WiFi.ProfileManagement+WLAN_INTERFACE_INFO] $wlanInterfaceInfo; } } catch { Write-Error $PSItem; } finally { Remove-WiFiHandle -ClientHandle $clientHandle; } } function Get-InterfaceInfo { [CmdletBinding()] param( [Parameter()][System.String]$WiFiAdapterName ) $result = [System.Collections.Generic.List[System.Object]]::new(); $wifiAdapters = [System.Collections.Generic.List[System.Object]]::new(); $getNetAdapterParams = [System.Collections.Generic.List[hashtable]]::new(); $wifiInterfaces = Get-WiFiInterface; if ([string]::IsNullOrWhiteSpace($WiFiAdapterName)) { foreach ($wifiInterface in $wifiInterfaces) { $getNetAdapterParams.Add(@{InterfaceDescription = $wifiInterface.Description }); } } else { $getNetAdapterParams.Add(@{Name = $WiFiAdapterName }); } foreach ($getNetAdapterParam in $getNetAdapterParams) { $wifiAdapters = Get-NetAdapter @getNetAdapterParam; } # ensure we are using wifi adaptors foreach ($wifiAdapter in $wifiAdapters) { if ($wifiAdapter.InterfaceGuid -notin $wifiInterfaces.Guid) { Write-Error -Message ($ErrorCodes.ErrorNotWiFiAdapter -f $wifiAdapter.Name); } else { $result.Add($wifiAdapter); } } if ($result.Count -eq 0) { throw $ErrorCodes.ErrorNoWiFiAdaptersFound; } return $result; } function Add-DefaultProperty { [CmdletBinding()] param( [Parameter(Mandatory)][object]$InputObject, [Parameter(Mandatory)][object]$InterfaceInfo ) Add-Member -InputObject $InputObject -MemberType 'NoteProperty' -Name 'WiFiAdapterName' -Value $InterfaceInfo.Name -Force; Add-Member -InputObject $InputObject -MemberType 'NoteProperty' -Name 'InterfaceGuid' -Value $InterfaceInfo.InterfaceGuid -Force; if ($InputObject -is [WiFi.ProfileManagement+WLAN_CONNECTION_ATTRIBUTES]) { $apMac = [System.BitConverter]::ToString($InputObject.wlanAssociationAttributes._dot11Bssid); Add-Member -InputObject $InputObject -MemberType 'NoteProperty' -Name 'APMacAddress' -Value $apMac -Force; } return $InputObject; } try { $result = [System.Collections.Generic.List[System.Object]]::new(); $profileListPointer = 0; $interfaceInfo = Get-InterfaceInfo -WiFiAdapterName $WiFiAdapterName; $clientHandle = New-WiFiHandle; if ($ClearKey) { $wlanProfileFlags = 13; } else { $wlanProfileFlags = 0; } if (!$ProfileName) { foreach ($interface in $interfaceInfo) { [void] [WiFi.ProfileManagement]::WlanGetProfileList($clientHandle, $interface.InterfaceGuid, [IntPtr]::zero, [ref] $profileListPointer); $wiFiProfileList = [WiFi.ProfileManagement+WLAN_PROFILE_INFO_LIST]::new($profileListPointer); $ProfileName = ($wiFiProfileList.ProfileInfo).strProfileName; } } foreach ($wiFiProfile in $ProfileName) { foreach ($interface in $interfaceInfo) { $profileInfo = Get-WiFiProfileInfo -ProfileName $wiFiProfile -InterfaceGuid $interface.InterfaceGuid -ClientHandle $clientHandle -WlanProfileFlags $wlanProfileFlags; $result.Add($(Add-DefaultProperty -InputObject $profileInfo -InterfaceInfo $interface)); } } return $result; } catch { Write-Error $PSItem; } finally { if (-not($null -eq $clientHandle)) { Remove-WiFiHandle -ClientHandle $clientHandle; } } } #endregion Get #region Initialize function Initialize-ModulePreReqs() { try { $null = if (!(Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue)) { $null = Install-PackageProvider -Name NuGet -Confirm:$false -Force; } else { Write-Verbose 'NuGet is installed.' } try { $null = if ((Get-PSRepository -Name PSGallery -ErrorAction Stop).InstallationPolicy -ne 'Trusted') { Set-PSRepository -Name PSGallery -InstallationPolicy Trusted -ErrorAction Stop; } else { Write-Verbose 'PSGallery is trusted.' } } catch { if ($_.Exception.Message -match "No repository with the name 'PSGallery' was found") { Remove-Item -Path C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\PowerShell\PowerShellGet\PSRepositories.xml -Force -Confirm:$false; $null = if ($null -eq $(Get-PSRepository -WarningAction SilentlyContinue | Select-Object -ExpandProperty Name)) { $null = Register-PSRepository -Default; Set-PSRepository -Name PSGallery -InstallationPolicy Trusted -ErrorAction Stop; } else { Write-Verbose 'PSGallery is trusted.' } } } $null = if (-not(Get-Module PowerShellGet -ListAvailable -ErrorAction SilentlyContinue | Where-Object { ($_.Version.Major -ge 2) -and ($_.Version.Minor -ge 2) })) { $null = Install-Module PowerShellGet -Scope AllUsers -Force -Confirm:$false; } else { Write-Verbose 'PowerShellGet is installed.' } $null = if (-not(Get-Module PackageManagement -ListAvailable -ErrorAction SilentlyContinue | Where-Object { ($_.Version.Minor -ge 4) -and ($_.Version.Build -ge 8) })) { $null = Install-Module PackageManagement -Scope AllUsers -Force -Confirm:$false; } else { Write-Verbose 'PackageManagement is installed.' } return $true; } catch { return $false; } } function Initialize-Module() { [cmdletbinding()] Param( [Parameter(Position = 0, Mandatory, HelpMessage = 'Module that should be installed or updated.')] [ValidateNotNullorEmpty()] [string]$moduleName, [Parameter(Position = 1, Mandatory = $false, HelpMessage = 'Minimum version. If specified, outdated modules will be updated.')] [ValidateNotNullorEmpty()] [string]$minVersion, [Parameter(Mandatory = $false, HelpMessage = "Perform the import command with the -Force flag.")] [switch]$Force ) begin { $Action = $null; if ([string]::IsNullOrEmpty($minVersion)) { $Existing = Get-InstalledModule -Name $moduleName -ErrorAction SilentlyContinue; $ModuleInfo = Find-Module -Name $moduleName -AllowPrerelease -ErrorAction SilentlyContinue; if ($null -eq $Existing) { $Action = "INSTALL"; Write-Verbose "$moduleName is NOT installed."; } else { $Action = "IMPORT"; Write-Verbose "$moduleName is installed. Version: $($Existing.Version)"; } } else { $Existing = Get-InstalledModule -Name $moduleName -MinimumVersion $minVersion -AllowPrerelease -ErrorAction SilentlyContinue; $ModuleInfo = Find-Module -Name $moduleName -MinimumVersion $minVersion -AllowPrerelease -ErrorAction SilentlyContinue; if ($null -eq $Existing) { $Existing = Get-InstalledModule -Name $moduleName -ErrorAction SilentlyContinue; if ($null -eq $ModuleInfo) { $ModuleInfo = Find-Module -Name $moduleName -AllowPrerelease -ErrorAction SilentlyContinue; } if ($null -eq $Existing) { $Action = "INSTALL"; Write-Verbose "$moduleName is NOT installed."; } else { $Action = "UPDATE"; Write-Verbose "$moduleName IS installed but OUTDATED."; } } else { $Action = "IMPORT"; Write-Verbose "$moduleName is installed. Version: $($Existing.Version)"; } } } process { switch ($Action) { 'INSTALL' { try { if ($null -eq $ModuleInfo) { return "ERROR: No matched found for module $moduleName" } else { if ($ModuleInfo.AdditionalMetadata.requireLicenseAcceptance) { Install-Module -Name $moduleName -Scope AllUsers -AllowPrerelease -AllowClobber -AcceptLicense -ErrorAction Stop; } else { Install-Module -Name $moduleName -Scope AllUsers -AllowPrerelease -AllowClobber -ErrorAction Stop; } } $Existing = Get-Module -FullyQualifiedName @{ ModuleName = $moduleName; ModuleVersion = $($ModuleInfo.Version -replace '-beta\d+') } -ListAvailable -ErrorAction SilentlyContinue; } catch { return "ERROR: Failed to install required module: $($moduleName) : $($_.Exception.Message)" } } 'UPDATE' { # Check if the module is loaded and unload it to try and make sure it updates correctly. if (Get-Module $moduleName) { Remove-Module -Name $moduleName -Force -ErrorAction SilentlyContinue; } $Existing = $null; try { if ($ModuleInfo.AdditionalMetadata.requireLicenseAcceptance) { Update-Module -Name $moduleName -Scope AllUsers -AllowPrerelease -AcceptLicense -RequiredVersion $ModuleInfo.Version -ErrorAction Stop } else { Update-Module -Name $moduleName -Scope AllUsers -AllowPrerelease -RequiredVersion $ModuleInfo.Version -ErrorAction Stop; } $Existing = Get-Module -FullyQualifiedName @{ ModuleName = $moduleName; ModuleVersion = $ModuleInfo.Version } -ListAvailable -ErrorAction SilentlyContinue; if (-not($null -eq $Existing)) { try { # Attempt to clean up old versions, may or may not work. Get-InstalledModule -Name $moduleName -AllVersions | Where-Object { $_.Version -ne $Existing.Version } | ForEach-Object { Uninstall-Module -InputObject $_ -ErrorAction SilentlyContinue } } catch { Write-Verbose "Failed to uninstall outdated version(s) of $modulename. Errors were suppressed."; } } } catch { return "ERROR: Failed to update required module: $($moduleName) : $($_.Exception.Message)"; } } default { $ModuleInfo = $Existing; $Existing = try { Get-Module -FullyQualifiedName @{ ModuleName = $ModuleInfo.Name; ModuleVersion = $($ModuleInfo.Version -replace '-beta\d+') } -ListAvailable -ErrorAction SilentlyContinue; } catch { Get-Module -Name $ModuleInfo.Name -ListAvailable } } } try { if ($Force.IsPresent) { Write-Verbose "The Force flag was set."; Import-Module -Name $Existing.Name -Force -ErrorAction Stop; } else { Import-Module -ModuleInfo $Existing -ErrorAction Stop; } return "Imported $($moduleName) version $($Existing.Version)"; } catch { return "ERROR: Failed to import required module: $($moduleName) : $($_.Exception.Message)" } } } function Initialize-ModuleCurrentUser() { [cmdletbinding()] Param( [Parameter(Position = 0, Mandatory, HelpMessage = 'Module that should be installed or updated.')] [ValidateNotNullorEmpty()] [string]$moduleName, [Parameter(Position = 1, Mandatory = $false, HelpMessage = 'Minimum version. If specified, outdated modules will be updated.')] [ValidateNotNullorEmpty()] [string]$minVersion ) begin { $Action = $null; if ([string]::IsNullOrEmpty($minVersion)) { $Existing = Get-Module -Name $moduleName -ListAvailable -ErrorAction SilentlyContinue; $ModuleInfo = Find-Module -Name $moduleName -AllowPrerelease -ErrorAction SilentlyContinue; if ($null -eq $Existing) { $Action = "INSTALL"; Write-Verbose "$moduleName is NOT installed."; } else { $Action = "IMPORT"; } } else { $Existing = Get-Module -FullyQualifiedName @{ ModuleName = $moduleName; ModuleVersion = $minVersion }; $ModuleInfo = Find-Module -Name $moduleName -MinimumVersion $minVersion -AllowPrerelease -ErrorAction SilentlyContinue; if ($null -eq $Existing) { $Existing = Get-Module -Name $moduleName -ListAvailable -ErrorAction SilentlyContinue; if ($null -eq $ModuleInfo) { $ModuleInfo = Find-Module -Name $moduleName -AllowPrerelease -ErrorAction SilentlyContinue; } if ($null -eq $Existing) { $Action = "INSTALL"; Write-Verbose "$moduleName is NOT installed."; } else { $Action = "UPDATE"; Write-Verbose "$moduleName IS installed but OUTDATED."; } } else { $Action = "IMPORT"; # Correct version is already installed. } } } process { switch ($Action) { 'INSTALL' { try { if ($null -eq $ModuleInfo) { return "ERROR: No matched found for module $moduleName" } else { if ($ModuleInfo.AdditionalMetadata.requireLicenseAcceptance) { Install-Module -Name $moduleName -Scope CurrentUser -AllowPrerelease -AllowClobber -AcceptLicense -ErrorAction Stop; } else { Install-Module -Name $moduleName -Scope CurrentUser -AllowPrerelease -AllowClobber -ErrorAction Stop; } } $Existing = Get-Module -FullyQualifiedName @{ ModuleName = $moduleName; ModuleVersion = $ModuleInfo.Version } -ListAvailable -ErrorAction SilentlyContinue; } catch { return "ERROR: Failed to install required module: $($moduleName) : $($_.Exception.Message)" } } 'UPDATE' { # Check if the module is loaded and unload it to try and make sure it updates correctly. if (Get-Module $moduleName) { Remove-Module -Name $moduleName -Force -ErrorAction SilentlyContinue } try { if ($ModuleInfo.AdditionalMetadata.requireLicenseAcceptance) { Update-Module -Name $moduleName -Scope CurrentUser -AllowPrerelease -AcceptLicense -RequiredVersion $ModuleInfo.Version -ErrorAction Stop } else { Update-Module -Name $moduleName -Scope CurrentUser -AllowPrerelease -RequiredVersion $ModuleInfo.Version -ErrorAction Stop; } $Existing = Get-Module -FullyQualifiedName @{ ModuleName = $moduleName; ModuleVersion = $ModuleInfo.Version } -ListAvailable -ErrorAction SilentlyContinue; if (-not($null -eq $Existing)) { try { # Attempt to clean up old versions, may or may not work. Get-Module -Name $moduleName -ListAvailable | Where-Object { $_.Version -ne $Existing.Version } | Uninstall-Module -ErrorAction SilentlyContinue; } catch { Write-Verbose "Failed to uninstall outdated version(s) of $modulename. Errors were suppressed."; } } } catch { return "ERROR: Failed to update required module: $($moduleName) : $($_.Exception.Message)"; } } default { $ModuleInfo = $Existing; $Existing = Get-Module -FullyQualifiedName @{ ModuleName = $moduleName; ModuleVersion = $ModuleInfo.Version } -ListAvailable -ErrorAction SilentlyContinue; } } try { Import-Module -ModuleInfo $Existing -ErrorAction Stop; $Module = Get-Module -Name $moduleName; if (-not($null -eq $Module)) { return "Imported $($moduleName) version $($Existing.Version)"; } else { return "ERROR: Failed to import required module: $($moduleName)" } } catch { return "ERROR: Failed to import required module: $($moduleName) : $($_.Exception.Message)" } } } function Initialize-EventLog { param( [Parameter(Mandatory = $true)][string]$logSource, [Parameter(Mandatory = $true)][string]$logName ) try { if (-not([System.Diagnostics.EventLog]::Exists($logName))) { if ([System.Diagnostics.EventLog]::SourceExists($logSource)) { $existing = [System.Diagnostics.EventLog]::LogNameFromSourceName($logSource, '.') if ($existing -ne $logName) { [System.Diagnostics.EventLog]::DeleteEventSource($logSource) [System.Diagnostics.EventLog]::Delete($existing) } } New-EventLog -LogName $logName -Source $logSource -ErrorAction Stop Write-EventLog -log $logName -Source $logSource -EntryType Information -EventId 1 -Message "$logName Event Log Initialized" } if (-not([System.Diagnostics.EventLog]::SourceExists($logSource))) { [System.Diagnostics.EventLog]::CreateEventSource($logSource, $logName) } return "Event log $logName and source $logSource prepared." } catch { return $("Failed to add $logName event log: {0}" -f $_.Exception.Message) } } #endregion Initialize #region Invoke function Invoke-Process { [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$FilePath, [Parameter(Mandatory = $false)][ValidateNotNullOrEmpty()][string]$ArgumentList ) $ErrorActionPreference = 'Stop'; try { $stdOutTempFile = "$env:TEMP\$((New-Guid).Guid)"; $stdErrTempFile = "$env:TEMP\$((New-Guid).Guid)"; Write-Verbose "StdOut Temp: $stdOutTempFile" Write-Verbose "StdErr Temp: $stdErrTempFile" [hashtable]$startProcessParams = @{} $startProcessParams.FilePath = $FilePath $startProcessParams.RedirectStandardError = $stdErrTempFile $startProcessParams.RedirectStandardOutput = $stdOutTempFile $startProcessParams.Wait = $true; $startProcessParams.PassThru = $true; $startProcessParams.NoNewWindow = $true; if (-not $null -eq $ArgumentList) { $startProcessParams.ArgumentList = $ArgumentList; Write-Verbose "Arguments: $ArgumentList" } if ($PSCmdlet.ShouldProcess("Process [$($FilePath)]", "Run with args: [$($ArgumentList)]")) { $cmd = Start-Process @startProcessParams; $cmdOutput = Get-Content -Path $stdOutTempFile -Raw; $cmdError = Get-Content -Path $stdErrTempFile -Raw; $Results = @{ ExitCode = $cmd.ExitCode; Error = $(if (-not([string]::IsNullOrEmpty($cmdError))) { $cmdError.Trim() } else { $null }) Output = $(if (-not([string]::IsNullOrEmpty($cmdOutput))) { $cmdOutput.Trim() } else { $null }) } return $(New-Object PSObject -Property $Results) } } catch { $PSCmdlet.ThrowTerminatingError($_) } finally { Remove-Item -Path $stdOutTempFile, $stdErrTempFile -Force -ErrorAction Ignore } } #endregion Invoke #region New function New-LogEntry() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][System.Text.StringBuilder]$stringBuilder, [Parameter(Position = 1, Mandatory)][string]$dataToLog, [Parameter(Position = 2)][bool]$simple = $false, [switch]$NoTime ) if ($NoTime.IsPresent) { [void]$stringBuilder.AppendFormat(':: {0}', $dataToLog.Trim()).AppendLine(); } else { [void]$stringBuilder.AppendFormat('[{0}] : {1}', $(New-TimeStamp -simple $simple), $dataToLog.Trim()).AppendLine(); } } Set-Alias -Name 'LOG' -Value New-LogEntry -Option ReadOnly -Scope Global -Force; function New-LogHeader() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][System.Text.StringBuilder]$stringBuilder, [Parameter(Position = 1, Mandatory)][string]$HeaderText, [Parameter(Position = 2)][bool]$simple = $false ) New-LogEntry $stringBuilder $HeaderLine $simple; New-LogEntry $stringBuilder $HeaderText $simple; New-LogEntry $stringBuilder $HeaderLine $simple; } Set-Alias -Name 'LOGH' -Value New-LogHeader -Option ReadOnly -Scope Global -Force; function New-LogFooter() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][System.Text.StringBuilder]$stringBuilder, [Parameter(Position = 1, Mandatory)][string]$FooterText, [Parameter(Position = 2)][bool]$simple = $false ) New-LogEntry $stringBuilder $FooterLine $simple; New-LogEntry $stringBuilder $FooterText $simple; New-LogEntry $stringBuilder $FooterLine $simple; } Set-Alias -Name 'LOGF' -Value New-LogFooter -Option ReadOnly -Scope Global -Force; function New-LogEntryConsole() { [cmdletbinding(DefaultParameterSetName = 'Single')] param( [Parameter(Position = 0, Mandatory)][System.Text.StringBuilder]$stringBuilder, [Parameter(Position = 1, Mandatory)][string]$dataToLog, [Parameter(Position = 2, Mandatory = $false, ParameterSetName = 'Single')] [Parameter(Position = 2, Mandatory, ParameterSetName = 'Multi')] [System.ConsoleColor]$lineColor, [Parameter(Position = 3, Mandatory, ParameterSetName = 'Multi', HelpMessage = "Color to highlight the delimited text.")] [System.ConsoleColor]$highlightColor, [Parameter(Position = 4, Mandatory = $false, ParameterSetName = 'Multi', HelpMessage = "Character to split the input dataToLog string on for highlighting. Defaults to pipe (|) character.")] [char]$delimiter = '|', [bool]$simple = $false ) [void]$stringBuilder.AppendFormat('[{0}] : {1}', $(New-TimeStamp $simple), $dataToLog.Replace($delimiter, ' ').Trim()).AppendLine(); Write-Host "[" -NoNewline; Write-Host $(New-TimeStamp $simple) -ForegroundColor White -NoNewline; Write-Host "] : " -NoNewline; if ($null -eq $lineColor) { Write-Host $dataToLog; } else { if ($null -eq $highlightColor) { Write-Host $dataToLog -ForegroundColor $lineColor; } else { $split = $dataToLog.Split($delimiter); $final = $split.Count - 1; for ($i = 0; $i -lt $split.Count; $i++) { if ($i % 2 -eq 0) { if ($i -eq $final) { Write-Host $(" {0}" -f $split[$i]) -ForegroundColor $lineColor; } else { if ($i -eq 0) { Write-Host $("{0} " -f $split[$i]) -ForegroundColor $lineColor -NoNewline; } else { Write-Host $(" {0} " -f $split[$i]) -ForegroundColor $lineColor -NoNewline; } } } else { if ($i -eq $final) { Write-Host $split[$i] -ForegroundColor $highlightColor; } else { Write-Host $split[$i] -ForegroundColor $highlightColor -NoNewline; } } } } } } function New-LogEntryConsoleHeader() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][System.Text.StringBuilder]$stringBuilder, [Parameter(Position = 1, Mandatory)][ValidateNotNullorEmpty()][string]$HeaderText, [Parameter(Position = 2, Mandatory = $false)] [System.ConsoleColor]$lineColor = [System.ConsoleColor]::White, [Parameter(Position = 3, Mandatory = $false)] [System.ConsoleColor]$highlightColor = [System.ConsoleColor]::Yellow, [Parameter(Position = 4, Mandatory = $false)] [System.ConsoleColor]$borderColor = [System.ConsoleColor]::Cyan, [bool]$simple = $false ) New-LogEntryConsole $stringBuilder $HeaderLine $borderColor -simple $simple; New-LogEntryConsole $stringBuilder $(New-CenteredString $HeaderText -consoleLog) $lineColor $highlightColor -simple $simple; New-LogEntryConsole $stringBuilder $HeaderLine $borderColor -simple $simple; } function New-LogEntryConsoleFooter() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][System.Text.StringBuilder]$stringBuilder, [Parameter(Position = 1, Mandatory)][ValidateNotNullorEmpty()][string]$FooterText, [Parameter(Position = 2, Mandatory = $false)] [System.ConsoleColor]$lineColor = [System.ConsoleColor]::Gray, [Parameter(Position = 3, Mandatory = $false)] [System.ConsoleColor]$highlightColor = [System.ConsoleColor]::DarkGreen, [Parameter(Position = 4, Mandatory = $false)] [System.ConsoleColor]$borderColor = [System.ConsoleColor]::DarkGreen, [bool]$simple = $false ) New-LogEntryConsole $stringBuilder $FooterLine $borderColor -simple $simple; New-LogEntryConsole $stringBuilder $(New-CenteredString $FooterText -consoleLog) $highlightColor $lineColor -simple $simple; New-LogEntryConsole $stringBuilder $FooterLine $borderColor -simple $simple; } function New-ConsoleLog() { [cmdletbinding(DefaultParameterSetName = 'Single')] param( [Parameter(Position = 0, Mandatory)][string]$dataToLog, [Parameter(Position = 1, Mandatory = $false, ParameterSetName = 'Single')] [Parameter(Position = 1, Mandatory, ParameterSetName = 'Multi')] [System.ConsoleColor]$lineColor, [Parameter(Position = 2, Mandatory, ParameterSetName = 'Multi', HelpMessage = "Color to highlight the delimited text.")] [System.ConsoleColor]$highlightColor, [Parameter(Position = 3, Mandatory = $false, ParameterSetName = 'Multi', HelpMessage = "Character to split the input dataToLog string on for highlighting. Defaults to pipe (|) character.")] [char]$delimiter = '|', [Parameter(Mandatory = $false)][string]$FilePath = $(if (-not([string]::IsNullOrEmpty($global:logFilePath))) { $global:logFilePath } else { $null }), [Parameter(Mandatory = $false)][bool]$simple = $true ) Write-Host "[" -NoNewline; Write-Host $(New-TimeStamp -simple $simple ) -ForegroundColor White -NoNewline; Write-Host "] : " -NoNewline; if ($null -eq $lineColor) { Write-Host $dataToLog; } else { if ($null -eq $highlightColor) { Write-Host $dataToLog -ForegroundColor $lineColor; } else { $split = $dataToLog.Split($delimiter); $final = $split.Count - 1; for ($i = 0; $i -lt $split.Count; $i++) { if ($i % 2 -eq 0) { if ($i -eq $final) { Write-Host $(" {0}" -f $split[$i]) -ForegroundColor $lineColor; } else { if ($i -eq 0) { Write-Host $("{0} " -f $split[$i]) -ForegroundColor $lineColor -NoNewline; } else { Write-Host $(" {0} " -f $split[$i]) -ForegroundColor $lineColor -NoNewline; } } } else { if ($i -eq $final) { Write-Host $split[$i] -ForegroundColor $highlightColor; } else { Write-Host $split[$i] -ForegroundColor $highlightColor -NoNewline; } } } } } if (-not([string]::IsNullOrEmpty($FilePath))) { New-FileLogEntry $FilePath $dataToLog.Replace('|', ' '); } } Set-Alias -Name 'LOGC' -Value New-ConsoleLog -Option ReadOnly -Scope Global -Force; function New-ConsoleLogHeader() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)] [ValidateNotNullorEmpty()] [string]$HeaderText, [Parameter(Position = 1, Mandatory = $false)] [System.ConsoleColor]$lineColor = [System.ConsoleColor]::White, [Parameter(Position = 2, Mandatory = $false)] [System.ConsoleColor]$highlightColor = [System.ConsoleColor]::Yellow, [Parameter(Position = 3, Mandatory = $false)] [System.ConsoleColor]$borderColor = [System.ConsoleColor]::Cyan ) New-ConsoleLog $HeaderLine $borderColor; New-ConsoleLog $(New-CenteredString $HeaderText -consoleLog) $lineColor $highlightColor; New-ConsoleLog $HeaderLine $borderColor; } Set-Alias -Name 'LOGCH' -Value New-ConsoleLogHeader -Option ReadOnly -Scope Global -Force; function New-ConsoleLogFooter() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)] [ValidateNotNullorEmpty()] [string]$FooterText, [Parameter(Position = 1, Mandatory = $false)] [System.ConsoleColor]$lineColor = [System.ConsoleColor]::Gray, [Parameter(Position = 2, Mandatory = $false)] [System.ConsoleColor]$highlightColor = [System.ConsoleColor]::DarkGreen, [Parameter(Position = 3, Mandatory = $false)] [System.ConsoleColor]$borderColor = [System.ConsoleColor]::DarkGreen ) New-ConsoleLog $FooterLine $borderColor; New-ConsoleLog $(New-CenteredString $FooterText -consoleLog) $highlightColor $lineColor; New-ConsoleLog $FooterLine $borderColor; } Set-Alias -Name 'LOGCF' -Value New-ConsoleLogFooter -Option ReadOnly -Scope Global -Force; function New-FileLogEntry() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][string]$LogFileFullPath, [Parameter(Position = 1, Mandatory)][string]$dataToLog ) Out-File -FilePath "$LogFileFullPath" -Append -InputObject $('[{0}] : {1}' -f $(New-TimeStamp -simple $simple), $dataToLog.Trim()) } Set-Alias -Name 'FLOG' -Value New-FileLogEntry -Option ReadOnly -Scope Global -Force; function New-CenteredString { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)] [ValidateNotNullorEmpty()] [string]$stringToCenter, [Parameter(Position = 1, Mandatory = $false)] [switch]$consoleLog ) if ($consoleLog) { return $("{0}{1}" -f (' ' * (([Math]::Max(0, 98 / 2) - ([Math]::Floor(($stringToCenter.Length) / 2))))), $stringToCenter); } else { return $("{0}{1}" -f (' ' * (([Math]::Max(0, $Host.UI.RawUI.BufferSize.Width / 2) - [Math]::Floor($stringToCenter.Length / 2)))), $stringToCenter); } } Set-Alias -Name 'CENTER' -Value New-CenteredString -Option ReadOnly -Scope Global -Force; function New-InsertString() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][AllowNull()] [Object[]]$InputArray, [switch]$CleanStrings, [switch]$LocalTime ) $StringBuilder = [System.Text.StringBuilder]::new(); [void]$StringBuilder.Append("("); $i = 0; foreach ($item in $InputArray) { if ($i -gt 0) { [void]$StringBuilder.Append(", "); } if ($null -eq $item) { [void]$StringBuilder.Append("''"); } else { switch -Regex ($item.GetType().Name) { 'String' { if ($item -eq 'NOW()') { [void]$StringBuilder.AppendFormat("{0}", $item); } else { if ($CleanStrings.IsPresent -and -not([string]::IsNullOrWhiteSpace($item))) { [void]$StringBuilder.AppendFormat("'{0}'", $(Get-CleanString $item)); } else { [void]$StringBuilder.AppendFormat("'{0}'", $item); } } } 'Int|Decimal|Double|Single|Float' { [void]$StringBuilder.AppendFormat("{0}", $item); } 'Boolean' { [void]$StringBuilder.AppendFormat("{0}", [int]$item) } 'DateTime' { if ($LocalTime.IsPresent) { [void]$StringBuilder.AppendFormat("'{0}'", $(Get-SQLDateTime $item)); } else { [void]$StringBuilder.AppendFormat("'{0}'", $(Get-LocalTime $item)); } } default { [void]$StringBuilder.AppendFormat("'{0}'", $item); } } } $i++; } [void]$StringBuilder.Append(")"); return $StringBuilder.ToString(); } Set-Alias -Name 'INSSTR' -Value New-InsertString -Option ReadOnly -Scope Global -Force; function New-PaddedString() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)] [ValidateNotNullorEmpty()] [string]$stringToPad, [Parameter(Position = 1, Mandatory)] [ValidateNotNullorEmpty()] [int]$padLength, [Parameter(Position = 2, Mandatory = $false)] [char]$padChar, [Parameter(Position = 3, Mandatory = $false)] [switch]$padLeft = $false ) if ($padLeft) { if (-not($null -eq $padChar)) { $paddedString = $stringToPad.PadLeft($padLength, $padChar); } else { $paddedString = $stringToPad.PadLeft($padLength); } } else { if (-not($null -eq $padChar)) { $paddedString = $stringToPad.PadRight($padLength, $padChar); } else { $paddedString = $stringToPad.PadRight($padLength); } } return $paddedString; } Set-Alias -Name 'PAD' -Value New-PaddedString -Option ReadOnly -Scope Global -Force; function New-TimeStamp { param( [Parameter(Position = 0)] [bool]$simple = $false, [switch]$fileName ) if ($simple) { if ($fileName.IsPresent) { return '{0:yyyy.MM.dd HH.mm.ss}' -f (Get-Date); } else { return '{0:yyyy.MM.dd HH:mm:ss}' -f (Get-Date); } } else { if ($fileName.IsPresent) { return '{0:yyyy.MM.dd HH.mm.ss.ffff}' -f (Get-Date); } else { return '{0:yyyy.MM.dd HH:mm:ss:ffff}' -f (Get-Date); } } } Set-Alias -Name 'TS' -Value New-TimeStamp -Option ReadOnly -Scope Global -Force; function New-InputPrompt() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory = $false, HelpMessage = "Text for First Button")] [string]$FirstButton = '&Yes', [Parameter(Position = 1, Mandatory = $false, HelpMessage = "Text for Second Button")] [string]$SecondButton = '&No', [Parameter(Position = 2, Mandatory = $false, HelpMessage = "Descriptive text for First Button mouseover.")] [string]$FirstDesc = '', [Parameter(Position = 3, Mandatory = $false, HelpMessage = "Descriptive text for Second Button mouseover.")] [string]$SecondDesc = '', [Parameter(Position = 4, Mandatory, HelpMessage = "Message box title.")] [string]$Title, [Parameter(Position = 5, Mandatory, HelpMessage = "Message box text.")] [string]$Message ) $BTN1 = New-Object System.Management.Automation.Host.ChoiceDescription $FirstButton, $FirstDesc; $BTN2 = New-Object System.Management.Automation.Host.ChoiceDescription $SecondButton, $SecondDesc; $OPT = [System.Management.Automation.Host.ChoiceDescription[]]($BTN1, $BTN2) return $host.ui.PromptForChoice($Title, $Message, $OPT, 1); } function New-MessageBox() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][string]$Title, [Parameter(Position = 1, Mandatory)][string]$Message, [Parameter(Position = 2, Mandatory)][System.Windows.MessageBoxButton]$ButtonType, [Parameter(Position = 3, Mandatory)][System.Windows.MessageBoxImage]$MessageBoxImage ) Import-Presentation; $Result = [System.Windows.MessageBox]::Show($Message, $Title, $ButtonType, $MessageBoxImage); Write-Verbose "MessageBox response: $Result"; return $Result; } function New-InputBox() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][string]$Title, [Parameter(Position = 1, Mandatory)][string]$Message ) Import-VisualBasic; $Result = [Microsoft.VisualBasic.Interaction]::InputBox($Message, $Title); Write-Verbose "MessageBox response: $Result"; return $Result; } function New-IGatherDataSet() { return [IGatherDataSet]::New(); } function New-IGatherEntry() { return [IGatherEntry]::New(); } function New-IGatherDataSet() { param( [int]$ComputerID, [string]$Category ) $DataSet = [IGatherDataSet]::New(); $DataSet.ComputerID = $ComputerID; $DataSet.Category = $Category; return $DataSet; } function New-IGatherEntry() { param( [string] $Table, [string] $InsertString, [string] $DeleteFilter ) $Entry = [IGatherEntry]::New(); $Entry.Table = $Table; $Entry.InsertString = $InsertString; $Entry.DeleteFilter = $DeleteFilter; return $Entry; } function New-IGatherEntry() { param( [string] $Table, [string] $InsertString, [string] $DeleteFilter, [string] $DuplicateString ) $Entry = [IGatherEntry]::New(); $Entry.Table = $Table; $Entry.InsertString = $InsertString; $Entry.DeleteFilter = $DeleteFilter; $Entry.DuplicateString = $DuplicateString; return $Entry; } #endregion New #region Set function Set-RegistryProperty() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][string]$RegistryPath, [Parameter(Position = 1, Mandatory)][string]$PropertyName, [Parameter(Position = 2, Mandatory)][AllowEmptyString()][string]$PropertyValue, [Parameter(Position = 4, Mandatory = $false)][bool]$IsString = $false, [Parameter(Position = 4, Mandatory)][System.Text.StringBuilder]$sbError, [Parameter(Position = 5, Mandatory)][System.Text.StringBuilder]$sbSuccess ) if (-not(Test-Path $RegistryPath -ErrorAction SilentlyContinue)) { try { $null = New-Item $RegistryPath -Force; New-LogEntry $sbSuccess "Added registry key: $RegistryPath"; } catch { New-LogEntry $sbError "Failed to add registry key $($RegistryPath): $($_.Exception.Message)"; return; } } try { if (-not(Get-ItemProperty -Path $RegistryPath -Name $PropertyName -ErrorAction SilentlyContinue)) { if ($IsString) { $null = New-ItemProperty -Path $RegistryPath -Name $PropertyName -Value $PropertyValue -PropertyType String -Force; } else { $null = New-ItemProperty -Path $RegistryPath -Name $PropertyName -Value $PropertyValue -PropertyType DWord -Force; } New-LogEntry $sbSuccess "Added $RegistryPath property $PropertyName and set value to $PropertyValue"; } else { $CurrentValue = Get-ItemPropertyValue -Path $RegistryPath -Name $PropertyName -ErrorAction SilentlyContinue; if ($CurrentValue -ne $PropertyValue) { Write-Verbose "$RegistryPath property $PropertyName | CURRENT : $CurrentValue | EXPECTED: $PropertyValue"; $null = Set-ItemProperty -Path $RegistryPath -Name $PropertyName -Value $PropertyValue -Force; New-LogEntry $sbSuccess "Set $RegistryPath property $PropertyName value to $PropertyValue"; } } } catch { New-LogEntry $sbError "Failed to Add/Set $RegistryPath property $PropertyName to $($PropertyValue): $($_.Exception.Message)"; } } #endregion Set #region Remove function Remove-RegistryProperty() { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)][string]$RegistryPath, [Parameter(Position = 1, Mandatory)][string]$PropertyName, [Parameter(Position = 2, Mandatory)][System.Text.StringBuilder]$sbError, [Parameter(Position = 3, Mandatory)][System.Text.StringBuilder]$sbSuccess ) try { if (Get-ItemProperty -Path $RegistryPath -Name $PropertyName -ErrorAction SilentlyContinue) { Remove-ItemProperty -Path $RegistryPath -Name $PropertyName -ErrorAction Stop; New-LogEntry $sbSuccess "Removed registry property $PropertyName from key $RegistryPath."; } } catch { New-LogEntry $sbError "Failed to remove property $PropertyName from key $($RegistryPath): $($_.Exception.Message)"; } } #endregion Remove #region Test function Test-PasswordComplexity($newComplexPswd) { Process { $criteriaMet = 0 # Upper Case Characters (A through Z, with diacritic marks, Greek and Cyrillic characters) if ($newComplexPswd -cmatch '[A-Z]') { $criteriaMet++ } # Lower Case Characters (a through z, sharp-s, with diacritic marks, Greek and Cyrillic characters) if ($newComplexPswd -cmatch '[a-z]') { $criteriaMet++ } # Numeric Characters (0 through 9) if ($newComplexPswd -match '\d') { $criteriaMet++ } # Special Chracters (Non-alphanumeric characters, currency symbols such as the Euro or British Pound are not counted as special characters for this policy setting) if ($newComplexPswd -match '[\^~!@#$%^&*_+=`|\\(){}\[\]:;"''<>,.?/]') { $criteriaMet++ } # Check if It Matches Default Windows Complexity Requirements if ($criteriaMet -lt 3) { return $false } if ($newComplexPswd.Length -lt 8) { return $false } return $true } } #endregion Test #region Write function Write-HostCenter { [cmdletbinding()] param( [Parameter(Position = 0, Mandatory)] [ValidateNotNullorEmpty()] [string]$Message ) Write-Host ("{0}{1}" -f (' ' * (([Math]::Max(0, $Host.UI.RawUI.BufferSize.Width / 2) - [Math]::Floor($Message.Length / 2)))), $Message); } Set-Alias -Name Write-Center -Value Write-HostCenter -Option ReadOnly -Scope Global -Force; #endregion Write <# Borrowed from https://github.com/LabtechConsulting/LabTech-Powershell-Module #> If (($MyInvocation.Line -match 'Import-Module' -or $MyInvocation.MyCommand -match 'Import-Module') -and -not ($MyInvocation.Line -match $ModuleGuid -or $MyInvocation.MyCommand -match $ModuleGuid)) { Import-Presentation; Import-VisualBasic; # Only export module members when being loaded as a module Export-ModuleMember -Function * -Alias * -Variable @('FooterLine', 'HeaderLine', 'IGatherDataSet', 'CWADataSet', 'Symbols') -EA 0 -WA 0; } |