HelperFunctions.psm1
<#------------------------------------------------------------------------------------------------------------------
Helper Functions --------------------------------------------------------------------------------------------------------------------#> <# helper function Get-StringHash Credits : Jeff Wouters ref: http://jeffwouters.nl/index.php/2013/12/Get-StringHash-for-files-or-strings/ #> function Get-StringHash { [cmdletbinding()] param ( [parameter(mandatory=$false,parametersetname="String")]$String, [parameter(mandatory=$false,parametersetname="File")]$File, [parameter(mandatory=$false,parametersetname="String")] [validateset("MD5","SHA1","SHA256","SHA384","SHA512","RIPEMD160")] [parameter(mandatory=$false,parametersetname="File")] [validateset("MD5","SHA1","SHA256","SHA384","SHA512","RIPEMD160")] [string]$HashType = "MD5" ) switch ($PsCmdlet.ParameterSetName) { "String" { $StringBuilder = New-Object System.Text.StringBuilder [System.Security.Cryptography.HashAlgorithm]::Create($HashType).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String))| ForEach-Object { [Void]$StringBuilder.Append($_.ToString("x2")) } $Object = New-Object -TypeName PSObject $Object | Add-Member -MemberType NoteProperty -Name 'String' -value $String $Object | Add-Member -MemberType NoteProperty -Name 'HashType' -Value $HashType $Object | Add-Member -MemberType NoteProperty -Name 'Hash' -Value $StringBuilder.ToString() $Object } "File" { $StringBuilder = New-Object System.Text.StringBuilder $InputStream = New-Object System.IO.FileStream($File,[System.IO.FileMode]::Open) switch ($HashType) { "MD5" { $Provider = New-Object System.Security.Cryptography.MD5CryptoServiceProvider } "SHA1" { $Provider = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider } "SHA256" { $Provider = New-Object System.Security.Cryptography.SHA256CryptoServiceProvider } "SHA384" { $Provider = New-Object System.Security.Cryptography.SHA384CryptoServiceProvider } "SHA512" { $Provider = New-Object System.Security.Cryptography.SHA512CryptoServiceProvider } "RIPEMD160" { $Provider = New-Object System.Security.Cryptography.CryptoServiceProvider } } $Provider.ComputeHash($InputStream) | Foreach-Object { [void]$StringBuilder.Append($_.ToString("X2")) } $InputStream.Close() $Object = New-Object -TypeName PSObject $Object | Add-Member -MemberType NoteProperty -Name 'File' -value $File $Object | Add-Member -MemberType NoteProperty -Name 'HashType' -Value $HashType $Object | Add-Member -MemberType NoteProperty -Name 'Hash' -Value $StringBuilder.ToString() $Object } } } <# Helper function to get the script and the line number of the calling function #> function getCallerInfo { [CmdletBinding()] param( #number of levels to go back in the call stack [ValidateRange(1, 99)] [int]$level = 2, [Switch]$FullStack ) $dict = New-Object 'system.collections.generic.dictionary[[string],[string]]' try { #Get the caller info $Stack = Get-PSCallStack #The level to track back should not exceed the depth of the callstack, so limit it where needed $level = [Math]::Min( $level, $Stack.Count -1 ) #$caller = $Stack[$level] #Get Base information straight from the Stack $dict.Add('Command', $Stack[$level].Command ) $dict.Add('ScriptLineNumber', $Stack[$level].ScriptLineNumber) $dict.Add('Position', $Stack[$level].Position) $dict.Add('FunctionName', $Stack[$level].FunctionName) $dict.Add('Location', $Stack[$level].Location) #Extract the scriptname from the location $Scriptname = $Stack[$level].Location if ( [string]::IsNullOrEmpty( $Scriptname ) -ne $true ) { #Split on : and take the first node only $dict.Add('Script', $Scriptname.Split(':')[0]) } # Also Add the complete Stack If ($FullStack) { #$ReportLevels = 1 + $Stack.Count - $level $StackTrace = $Stack | Select -Skip $level -Property ScriptName,ScriptLineNumber,FunctionName,Command,Location,Arguments | ConvertTo-Json -Compress $dict.Add( 'PSCallStack', $StackTrace) } return $dict } catch { return $null} } <# Helper function to get the calling script or module version #> function getCallerVersion { [CmdletBinding()] param( #Get version from X levels up in the call stack [int]$level = 2 #Use 2 as default as this is mostly an internal function ) #Get the caller info $Stack = Get-PSCallStack #The level to track back should not exceed the depth of the callstack, so limit it where needed $level = [Math]::Min( $level, $Stack.Count -1 ) Write-Verbose "getCallerVersion -level $level" #Default Caller Version to 0.0 [Version]$CallerVersion = '0.0' try { #Get the caller info $caller = $Stack[$level] #if script if ( -NOT [string]::IsNullOrEmpty( $caller.ScriptName)){ $info = Test-ScriptFileInfo -Path $caller.ScriptName -ErrorAction SilentlyContinue if ( $info ) { $CallerVersion = $info.Version Write-Verbose "getCallerVersion found script version $CallerVersion" return $CallerVersion } } } catch { } Try { #try module info based on the name, but with a psd1 extention $Filename = [System.IO.Path]::ChangeExtension( $caller.ScriptName, 'psd1') $info = Test-ModuleManifest -Path $Filename -ErrorAction SilentlyContinue if ( $info ) { $CallerVersion = $info.Version Write-Verbose "getCallerVersion found Module version $CallerVersion" return $CallerVersion break; } } catch {} # Continue try { #try to find a version from the path and folder names $Folders= @( $Filename.Split('\') ) $found = $false foreach( $f in $Folders ) { Try { $CallerVersion = [version]$f ; $found = $true} catch {} } if ($found) { #return last found version Write-Verbose "getCallerVersion found Folder version $CallerVersion" return $CallerVersion } } catch { Write-Verbose "getCallerVersion no version found" return $CallerVersion } Write-Verbose "no version found" return $CallerVersion } <# # Credits: Joel Bennet # http://poshcode.org/4968 Changed to not allow Nulls by default #> function ConvertTo-Hashtable { #.Synopsis # Converts an object to a hashtable of property-name = value PARAM( # The object to convert to a hashtable [Parameter(ValueFromPipeline=$true, Mandatory=$true)] $InputObject, # Forces the values to be strings and converts them by running them through Out-String [switch]$AsString, # If set, allows each hashtable to have it's own set of properties, otherwise, # each InputObject is normalized to the properties on the first object in the pipeline [switch]$jagged, # If set, empty properties are Included [switch]$AllowNulls ) BEGIN { $headers = @() } PROCESS { if(!$headers -or $jagged) { $headers = $InputObject | get-member -type Properties | select -expand name } $output = @{} if($AsString) { foreach($col in $headers) { if($AllowNulls -or ($InputObject.$col -is [bool] -or ($InputObject.$col))) { $output.$col = $InputObject.$col | out-string -Width 9999 | % { $_.Trim() } } } } else { foreach($col in $headers) { if($AllowNulls -or ($InputObject.$col -is [bool] -or ($InputObject.$col))) { $output.$col = $InputObject.$col } } } $output } } |