Create editable powershell GUI for CSV data - csv

GOAL: Create a GUI form populated with CSV data, allow the user to edit the data, then save the data in an array for further manipulation.
NOTE: Using PowerShell Studio to generate a form with data from the CSV
CURRENT CODE:
- Calling code ($path is passed from the calling form):
$rows = Import-Csv -Path $path
$table = ConvertTo-DataTable -InputObject $rows
Load-DataGridView -DataGridView $datagridviewResults -Item $table
ConvertTo-DataTable function:
function ConvertTo-DataTable {
[OutputType([System.Data.DataTable])]
param(
[ValidateNotNull()]
$InputObject,
[ValidateNotNull()]
[System.Data.DataTable]$Table,
[switch]$RetainColumns,
[switch]$FilterWMIProperties
)
if($Table -eq $null) {
$Table = New-Object System.Data.DataTable
}
if($InputObject-is [System.Data.DataTable]) {
$Table = $InputObject
} else {
if(-not $RetainColumns -or $Table.Columns.Count -eq 0) {
#Clear out the Table Contents
$Table.Clear()
if($InputObject -eq $null){ return } #Empty Data
$object = $null
#find the first non null value
foreach($item in $InputObject) {
if($item -ne $null) {
$object = $item
break
}
}
if($object -eq $null) { return } #All null then empty
#Get all the properties in order to create the columns
foreach ($prop in $object.PSObject.Get_Properties()) {
if(-not $FilterWMIProperties -or -not $prop.Name.StartsWith('__')) { #filter out WMI properties
#Get the type from the Definition string
$type = $null
if($prop.Value -ne $null) {
try{ $type = $prop.Value.GetType() } catch {}
}
if($type -ne $null) { # -and [System.Type]::GetTypeCode($type) -ne 'Object')
[void]$table.Columns.Add($prop.Name, $type)
} else { #Type info not found
[void]$table.Columns.Add($prop.Name)
}
}
}
if($object -is [System.Data.DataRow]) {
foreach($item in $InputObject) {
$Table.Rows.Add($item)
}
return #(,$Table)
}
} else {
$Table.Rows.Clear()
}
foreach($item in $InputObject) {
$row = $table.NewRow()
if($item) {
foreach ($prop in $item.PSObject.Get_Properties()) {
if($table.Columns.Contains($prop.Name)) {
$row.Item($prop.Name) = $prop.Value
}
}
}
[void]$table.Rows.Add($row)
}
}
return #(,$Table)
}
Load-DataGridView function:
function Load-DataGridView {
Param (
[ValidateNotNull()]
[Parameter(Mandatory=$true)]
[System.Windows.Forms.DataGridView]$DataGridView,
[ValidateNotNull()]
[Parameter(Mandatory=$true)]
$Item,
[Parameter(Mandatory=$false)]
[string]$DataMember
)
$DataGridView.SuspendLayout()
$DataGridView.DataMember = $DataMember
$DataGridView.EditMode = 'EditOnEnter'
if ($Item -is [System.ComponentModel.IListSource]`
-or $Item -is [System.ComponentModel.IBindingList]`
-or $Item -is [System.ComponentModel.IBindingListView]) {
$DataGridView.DataSource = $Item
} else {
$array = New-Object System.Collections.ArrayList
if ($Item -is [System.Collections.IList]) {
$array.AddRange($Item)
} else {
$array.Add($Item)
}
$DataGridView.DataSource = $array
}
$DataGridView.ResumeLayout()
}
ADDITIONAL INFORMATION: Code is working in that it generates the Grid View and populates it with CSV data. However, I cannot edit it and need help coding the ability to capture changes once it is edited.
Thanks in advance.
12/5 EDIT: Added "$DataGridView.EditMode = 'EditOnEnter'" to the function "Load-DataGridView" above. Nothing changed. Tried to invoke the "BeginEdit" Event in a new RowCellClick event, but that didn't work either. Still struggling with this one.

For anyone else you has struggled with this ....
set-strictmode -Version 2.0
function EditCSV($title, $Instructions, $csvPath, $x = 100, $y=100, $Width=600, $Height=400, $SaveChangesToFile=$true, $ReturnStatusOrArray='Status') {
#Windows Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#LoadCSV
#Variables MUST have script scope to allow form to see them
$script:Updated = $false
$script:CsvData = New-Object System.Collections.ArrayList
$script:CsvData.AddRange((import-csv $csvPath))
#Helper Functions
function paint($form, $ctrl, $TablIndex, $name, $Text, $x, $y, $Width, $Height){
try{$form.Controls.Add($ctrl) }catch{}
try{$ctrl.TabIndex = $TablIndex }catch{}
try{$ctrl.Text = $Text }catch{}
try{$ctrl.name = $name }catch{}
try{$ctrl.Location = System_Drawing_Point $x $y }catch{}
try{$ctrl.size = System_Drawing_Size $Width $Height }catch{}
try{$ctrl.DataBindings.DefaultDataSourceUpdateMode = 0 }catch{}
$ctrl
}
function System_Drawing_Point($x, $Y) {$_ = New-Object System.Drawing.Point; $_.x = $X; $_.Y = $Y; $_}
function System_Drawing_Size( $Width, $Height){$_ = New-Object System.Drawing.Size; $_.Width = $Width; $_.Height = $Height; $_}
#Paint Form
$form1 = paint $null (New-Object System.Windows.Forms.Form) $null 'form1' $Title $x $y $Width $Height
$form1.add_Load({
$dataGrid1.DataSource = $script:CsvData;
$form1.refresh()
})
$label1 = paint $form1 (New-Object System.Windows.Forms.Label) $null "label1" "$Instructions" 12 13 ($width-100) 23
$label1.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",9.75,2,3,0)
$label1.ForeColor = [System.Drawing.Color]::FromArgb(255,0,102,204)
$buttonSave = paint $form1 (New-Object System.Windows.Forms.Button) 1 "button1" "Save" ($width-200) ($Height-75) 75 23
$buttonSave.UseVisualStyleBackColor = $True
$buttonSave.add_Click({
$script:Updated = $true
$Form1.Close()
})
$buttonClose = paint $form1 (New-Object System.Windows.Forms.Button) 2 'button2' 'Close' ($width-105) ($Height-75) 75 23
$buttonClose.UseVisualStyleBackColor = $True
$buttonClose.add_Click({
$Form1.Close()
})
$dataGrid1 = paint $form1 (New-Object System.Windows.Forms.DataGrid) 0 "dataGrid0" $Null 12 40 ($width-40) ($Height-125)
$dataGrid1.HeaderForeColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
#Show and Wait till complete
$form1.ShowDialog()| Out-Null
#Save CSV
if( $SaveChangesToFile -eq $true -and $script:Updated ){
$script:CsvData| export-csv -NoTypeInformation -path $csvPath
}
if( $ReturnStatusOrArray -eq 'Status'){
return $script:Updated
}else{
return $script:CsvData
}
}
## Unit Test
cls
function script:Indent-ConsoleOutput($output, $indent = ' '){
if(!($output -eq $null)){
if(!( $indent -is [string])){
$indent = ''.PadRight($indent)
}
$width = (Get-Host).UI.RawUI.BufferSize.Width - $indent.length
($output| out-string).trim().replace( "`r", "").split("`n").trimend()| %{
for($i=0; $i -le $_.length; $i+=$width){
if(($i+$width) -le $_.length){
"$indent"+$_.substring($i, $width)
}else{
"$indent"+$_.substring($i, $_.length - $i)
}
}
}
}
}
Write-Host '## Before '.PadRight(120, '#')
$filePath = 'C:\temp\Text.csv'
$d = (dir c: |select-object -property Directory, Mode, LastWriteTime, Length, Name)[0..5]
$d |export-csv -path $filePath -NoTypeInformation
Indent-ConsoleOutput (import-csv $filePath |format-table) 4
Write-Host '## Edit - Save to File '.PadRight(120, '#')
Indent-ConsoleOutput (EditCSV 'Example of PS Editable Grid' '[SAVE] - To Save Changes' $filePath ) 4
Write-Host '## After '.PadRight(120, '#')
Indent-ConsoleOutput (import-csv $filePath |format-table) 4
Write-Host '## Edit - Return Array '.PadRight(120, '#')
Indent-ConsoleOutput (EditCSV 'Example of PS Editable Grid' '[SAVE] - To Save Changes' $filePath -SaveChangesToFile $false -ReturnStatusOrArray 'Array'|format-table) 4
Indent-ConsoleOutput (import-csv $filePath |format-table) 4
Enjoy

Related

Replace parameters in JSON with given Values from .csv

I have a JSON-File where I want to replace several values with a placeholder.
So i made a .csv with the parameters to replace. line[0] (if existing) is the path in the file, line[1] the element, line[2] the placeholder.
journeys.legs.origin.properties.downloads;url;placeholder;
;url;placeholder;
download;url;placeholder;
;psFileName;placeholder;
;serverTime;placeholder;
;calcTime;placeholder;
now I defined the following functions, to get the file, read the csv and replace the stuff.
$storage = "D:\Service\test.json"
$parameters2replace = "D:\Service\parameters2replace.csv"
function Get-JSONProperty([object] $InputObject, [string] $Property) {
$path = $Property -split '\.'
$obj = $InputObject
$path | %{ $obj = $obj.$_ }
$obj
}
function setParameter(){
foreach ($parameter in Get-Content $parameters2replace){
$line=$parameter.split(";")
$path = $line[0]
$elementName = $line[1]
$newValue = $line[2]
replaceElement $path $elementName $newValue
}
}
function replaceElement($path, $elementName, $newValue){
ForEach($JSONPath in Get-JSONProperty $JSON $path){
if (!$line[0]){
if($JSON.$elementName){
$JSON.$elementName = $newValue
}
}
else{
if($JSON.$path.$elementName){
echo $JSON.$path.$elementName
$JSON.$path.$elementName = $newValue
}
}
}
$JSON | ConvertTo-Json -depth 32| set-content $storage
}
$JSON = Get-Content $storage -raw | ConvertFrom-Json
setParameter
My problem now is, that the following if-argument won't work with the $path variable. If i put it in hardcoded it works just fine.
if($JSON.$path.$elementName)
I hope i could make everything clear, this was my first post.
$JSON.$path makes PowerShell look for a property with the literal name 'journeys.legs.origin.properties.downloads'. You need to split the string into it's individual parts and iterate (or recurse) through the path:
function Get-JSONPropertyValue {
param(
$JSON,
[string]$Path,
[string]$Name
)
$object = $JSON
foreach($propName in $Path.Split('.')){
$object = $object.$propName
}
return $object.$Name
}
function Set-JSONPropertyValue
{
param(
$JSON,
[string]$Path,
[string]$Name,
$Value
)
$object = $JSON
foreach($propName in $Path.Split('.')){
$object = $object.$propName
}
$object.$Name = $Value
}
Now you can do:
if($value = Get-JSONPropertyValue $JSON -Path $path -Name $elementName){
echo "Old value: $value"
Set-JSONPropertyValue $JSON -Path $path -Name $elementName -Value $newValue
}

Recursive JSON Compare Function too slow

I found a powershell deep compare object (https://github.com/kjelderg/Compare-DeepObject) and derived a recursive Json Compare Function for powershell.
The function generally seems to work fine, but its too slow for my purpose. For a batch compare it needs 8 minutes.
How can I speed up the processs?
Thanks
Alex
# walk through the two objects and generate a diff
# This extends compare-object which itself only does shallow comparisons.
# To use, impor t-module <thisFileName>
# Compare-DeepObject $foo $istar
function Compare-Json2 {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)][AllowNull()]$soll,
[Parameter(Mandatory=$true)][AllowNull()]$ist,
$isFile
# TODO: max-depth
)
PROCESS {
$diff = [PSCustomObject]#{
istJson = '{}'
sollJson = '{}'
difference = #()
}
if($isFile) {
if ($ist -eq $soll) {
$diff.difference += 'istFile == Soll File! Big Error in Testskript!'
return $diff
}
if(Test-Path $ist) {
$ist = Get-Content $ist
}
else {
if(Test-Path $soll) {
$diff.difference += 'istFileDoesNotExists'
}
return $diff
}
if(Test-Path $soll) {
$soll = Get-Content $soll
}
else {
$diff.difference += 'sollFileDoesNotExists'
return $diff
}
}
$diff.istJson = ($ist | ConvertFrom-Json) | ConvertTo-Json -Depth 100 -Compress
$diff.sollJson = ($soll | ConvertFrom-Json) | ConvertTo-Json -Depth 100 -Compress
$ist = $ist | ConvertFrom-Json -Depth 100
$soll = $soll | ConvertFrom-Json -Depth 100
$diff.difference = Compare-JsonObjectRecursive -soll $soll -ist $ist -node $null
# }
return $diff
} # End PROCESS
} # End function$
function Compare-JsonObjectRecursive {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)][AllowNull()]$soll,
[Parameter(Mandatory=$true)][AllowNull()]$ist,
$node
# TODO: max-depth
)
PROCESS {
# if one side is null, return the other side.
if($soll -eq $null -and $ist -ne $null) { return #{ soll=$null; ist=$ist} }
if($ist -eq $null -and $soll -ne $null) { return #{ ist=$null; soll=$soll} }
if($soll -eq $null -and $ist -eq $null) { return }
# compare data types
$differences = #{}
#$differences = New-Object PSCustomObject
if (($ist -is [PsCustomObject]) -and ($soll -is [array])) {
[array]$ist = $ist
}
if (($ist -is [array]) -and ($soll -is [PsCustomObject])) {
[array]$soll = $soll
}
if($soll -is [array]) { # Recurse for each element of an array
for($i = 0; $i -lt [math]::max($soll.length, $ist.length); $i++) {
if ($node) {$node = "$node[$i]"}
else {$node = "[$i]"}
Compare-JsonObjectRecursive -soll $soll[$i] -ist $ist[$i] -node $node
}
}
elseif ($soll -is [PSCustomObject]) { # Recurse for each property of a PSCustomObject
# walk both sets of keys^Wproperty names with this cool get-unique magic.
$keys = (#($soll.PSObject.properties.name) + #($ist.PSObject.properties.name)) | Sort-Object | get-unique
if ($node) {$node = "$node."}
else {$node = ""}
foreach($key in $keys) {
Compare-JsonObjectRecursive -soll $soll.$key -ist $ist.$key -node "$node$key"
}
}
else {
if($soll -ne $ist) {
$differences[$node] = #{soll = $soll; ist = $ist}
return $differences
}
}
} # End PROCESS
} # End function$

Having a hard time building PowerShell function to unflatten a JSON doc table

I built a recursive solution to read in a JSON doc and output a flattened table. Now I want to reverse the operation but am having a hard time figuring out a soliton. I need it to be in PowerShell as I just want to add it to my existing module.
I posted about my flatten code here: https://stackoverflow.com/a/63499156/13224569
I have a partial solution, but it falling well short. Here's that code:
$a = '.person.pets[0].color.black.toy.foo' -split '\.'
$b = '.john.harold.cravener' -split '\.'
$z = '.john.is.content' -split '\.'
$m = #{}
$c = #{}
$p = #{}
$pk = $null
$firstTime = $true
foreach($i in $a[1..($a.Count-1)]) {
$c = #{$i = $null}
if($firstTime){
$m = $c
$firstTime = $false
}
if($p -and $pk) {
$p[$pk] = $c
}
$p = $c
$pk = $i
}
$m
exit
And here's its output:
PS D:\> .\tester.ps1 | ConvertTo-Json -Depth 20
{
"person": {
"pets[0]": {
"color": {
"black": {
"toy": {
"foo": null
}
}
}
}
}
}
My first challenge, I can't figure out how to move on to the next row and store it to the exiting $m variable. I'm getting tripped up with the way this var is being referenced in PowerShell / .Net Core.
The second challenge is how to deal with arrays, but I haven't even started on this part yet.
Any and all help / suggestions would be greatly appreciated!
After some research, and a lot of work and debugging, I came to a solution. From my testing so far, it works quite well. It's based on simonw's python code here. And while my solution needed to be in PowerShell, it's not a straight port but pretty close. Most of the modifications are based on differences in how PowerShell and Python handles certain things. The main function is ConvertFrom-JhcUtilJsonTable which in turn depends on three helper functions. Here's all of them.
function ConvertFrom-JhcUtilJsonTable {
param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[System.Collections.Hashtable]
$jsonHashTable
)
begin {}
process {
foreach ($h in $jsonHashTable) {
$m = #{}
foreach ($k in $h.Keys) {
$current = $m
$val = $h[$k]
$k = ($k -replace '\]', '') -replace '\[', '.'
$bits = $k.split('.')
$path = $bits[1..($bits.Count - 1)]
$count = 0
foreach ($bit in $path) {
$count++
if ($v = $current.item($bit)) {
$current[$bit] = $v
}
else {
if ($count -eq $path.Count) {
$current[$bit] = $val
}
else {
$current[$bit] = #{}
}
}
$current = $current[$bit]
}
}
intKeyHashToLists -obj $m
#--python code had a buit about handling root units e.g. {'$empty': '{}'} - need to add that
}
}
end {}
}
#---helper function for ConvertFrom-JhcUtilJsonTable
#
function isType {
param (
[Parameter(Mandatory)]
[System.Object]
$obj,
[Parameter(Mandatory)]
[ValidateSet('Hashtable', 'Object[]')]
[System.String]
$typeName
)
$t = $obj.GetType()
if ($t.Name -eq $typeName) {
return $true
}
return $false
}
#---helper function for ConvertFrom-JhcUtilJsonTable
#
function allKeysDigits {
param (
[Parameter(Mandatory)]
[System.Collections.Hashtable]
$h
)
foreach ($k in $h.Keys) {
if ($k -match '^0\d') {
return $false
}
if ($k -notmatch '^\d+$') {
return $false
}
}
return $true
}
#---helper function for ConvertFrom-JhcUtilJsonTable
#
function intKeyHashToLists {
param (
[Parameter(Mandatory)]
[System.Object]
$obj
)
if (isType -obj $obj -typeName 'Hashtable') {
if ($obj -and (allKeysDigits -h $obj)) {
$a = #()
foreach ($k in ($obj.Keys | Sort-Object) ) {
$a += intKeyHashToLists -obj $obj.item($k)
}
return ,$a #--- adding the comma forces this to retun an array even when it's a single element
}
else {
$h = #{}
foreach ($k in $obj.Keys) {
$h[$k] = intKeyHashToLists -obj $obj.item($k)
}
return $h
}
}
elseif (isType -obj $obj -typeName 'Object[]') {
return ( $obj | ForEach-Object { intKeyHashToLists -obj $_ } )
}
else {
return $obj
}
}

powershell convert json to hashtable recursively [duplicate]

What is the easiest way to convert a PSCustomObject to a Hashtable? It displays just like one with the splat operator, curly braces and what appear to be key value pairs. When I try to cast it to [Hashtable] it doesn't work. I also tried .toString() and the assigned variable says its a string but displays nothing - any ideas?
Shouldn't be too hard. Something like this should do the trick:
# Create a PSCustomObject (ironically using a hashtable)
$ht1 = #{ A = 'a'; B = 'b'; DateTime = Get-Date }
$theObject = new-object psobject -Property $ht1
# Convert the PSCustomObject back to a hashtable
$ht2 = #{}
$theObject.psobject.properties | Foreach { $ht2[$_.Name] = $_.Value }
Keith already gave you the answer, this is just another way of doing the same with a one-liner:
$psobject.psobject.properties | foreach -begin {$h=#{}} -process {$h."$($_.Name)" = $_.Value} -end {$h}
Here's a version that works with nested hashtables / arrays as well (which is useful if you're trying to do this with DSC ConfigurationData):
function ConvertPSObjectToHashtable
{
param (
[Parameter(ValueFromPipeline)]
$InputObject
)
process
{
if ($null -eq $InputObject) { return $null }
if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string])
{
$collection = #(
foreach ($object in $InputObject) { ConvertPSObjectToHashtable $object }
)
Write-Output -NoEnumerate $collection
}
elseif ($InputObject -is [psobject])
{
$hash = #{}
foreach ($property in $InputObject.PSObject.Properties)
{
$hash[$property.Name] = ConvertPSObjectToHashtable $property.Value
}
$hash
}
else
{
$InputObject
}
}
}
My extremely lazy approach, enabled by a new feature in PowerShell 6:
$myhashtable = $mypscustomobject | ConvertTo-Json | ConvertFrom-Json -AsHashTable
This works for PSCustomObjects created by ConvertFrom_Json.
Function ConvertConvertFrom-JsonPSCustomObjectToHash($obj)
{
$hash = #{}
$obj | Get-Member -MemberType Properties | SELECT -exp "Name" | % {
$hash[$_] = ($obj | SELECT -exp $_)
}
$hash
}
Disclaimer: I barely understand PowerShell so this is probably not as clean as it could be. But it works (for one level only).
My code:
function PSCustomObjectConvertToHashtable() {
param(
[Parameter(ValueFromPipeline)]
$object
)
if ( $object -eq $null ) { return $null }
if ( $object -is [psobject] ) {
$result = #{}
$items = $object | Get-Member -MemberType NoteProperty
foreach( $item in $items ) {
$key = $item.Name
$value = PSCustomObjectConvertToHashtable -object $object.$key
$result.Add($key, $value)
}
return $result
} elseif ($object -is [array]) {
$result = [object[]]::new($object.Count)
for ($i = 0; $i -lt $object.Count; $i++) {
$result[$i] = (PSCustomObjectConvertToHashtable -object $object[$i])
}
return ,$result
} else {
return $object
}
}
For simple [PSCustomObject] to [Hashtable] conversion Keith's Answer works best.
However if you need more options you can use
function ConvertTo-Hashtable {
<#
.Synopsis
Converts an object to a hashtable
.DESCRIPTION
PowerShell v4 seems to have trouble casting some objects to Hashtable.
This function is a workaround to convert PS Objects to [Hashtable]
.LINK
https://github.com/alainQtec/.files/blob/main/src/scripts/Converters/ConvertTo-Hashtable.ps1
.NOTES
Base ref: https://community.idera.com/database-tools/powershell/powertips/b/tips/posts/turning-objects-into-hash-tables-2
#>
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, empty properties are Included
[switch]$AllowNulls,
# Make each hashtable to have it's own set of properties, otherwise,
# (default) each InputObject is normalized to the properties on the first object in the pipeline
[switch]$DontNormalize
)
BEGIN {
$headers = #()
}
PROCESS {
if (!$headers -or $DontNormalize) {
$headers = $InputObject | Get-Member -type Properties | Select-Object -expand name
}
$OutputHash = #{}
if ($AsString) {
foreach ($col in $headers) {
if ($AllowNulls -or ($InputObject.$col -is [bool] -or ($InputObject.$col))) {
$OutputHash.$col = $InputObject.$col | Out-String -Width 9999 | ForEach-Object { $_.Trim() }
}
}
} else {
foreach ($col in $headers) {
if ($AllowNulls -or ($InputObject.$col -is [bool] -or ($InputObject.$col))) {
$OutputHash.$col = $InputObject.$col
}
}
}
}
END {
return $OutputHash
}
}
Maybe this is overkill but I hope it Helps
Today, the "easiest way" to convert PSCustomObject to Hashtable would be so:
$custom_obj | ConvertTo-HashtableFromPsCustomObject
OR
[hashtable]$custom_obj
Conversely, you can convert a Hashtable to PSCustomObject using:
[PSCustomObject]$hash_table
Only snag is, these nifty options may not be available in older versions of PS

Powershell: Hash table containing functions to be called with parameter

I have a dictionary like this:
function HashHandlerSHA256
{
param($Path, $Checksum)
$csp = new-object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider
$ComputedHash = $csp.ComputeHash([System.IO.File]::ReadAllBytes($Path))
$ComputedHash = [System.BitConverter]::ToString($ComputedHash).Replace("-", "").ToLower()
$result = $ComputedHash.CompareTo($Checksum)
return $result -eq 0
}
$HashHandler = #{"SHA256" = HashHandlerSHA256}
containing validation algorithms and the functions to be called for validation. The functions should all have the same parameter and return type.
Now when I have:
$Checksums = #{"SHA256" = "..."}
I'd like to call the correct function depending on which algorithms and values I have available. In this case I'd have a valid sha256 hash.
Now I want to do:
function Validate
{
param($Path, $Checksums)
foreach($Hash in $Checksums) {
$Type = $Hash.Name
$Value = $Hash.Value
if ($HashHandler.ContainsKey($Type)) {
$Handler = $HashHandler.Get_Item($Type)
if (-Not ($Handler -Path $Path -Checksum $Value)) {
return $FALSE
}
}
}
return $TRUE
}
The errormessage I get is:
At C:\Users\username\Desktop\hashtest.ps1:27 char:23
+ if (-Not ($Handler -Path $Path -Checksum $Value)) {
+ ~~~~~
Unexpected token '-Path' in expression or statement.
I am relatively new to PowerShell. I know how to call functions with parameters, but when stored in a variable, I didn't manage to solve this and when searching online for this, I didn't get the answers I needed.
Thanks for help.
if i understand you want Something like this
function HashHandlerSHA256
{
param($Path, $Checksum)
$csp = new-object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider
$ComputedHash = $csp.ComputeHash([System.IO.File]::ReadAllBytes($Path))
$ComputedHash = [System.BitConverter]::ToString($ComputedHash).Replace("-", "").ToLower()
$result = $ComputedHash.CompareTo($Checksum)
return $result -eq 0
}
function Validate
{
param($Path, $Checksums)
foreach($Hashkey in $Checksums.Keys)
{
$Value = $Checksums[$Hashkey]
if ($script:HashHandler.ContainsKey($Hashkey))
{
if (-Not (&$script:HashHandler[$Hashkey] -Path $Path -Checksum $Value)) { return $false}
}
}
return $TRUE
}
#add here your couples of algo/function
$script:HashHandler = #{"SHA256" = 'HashHandlerSHA256'}
#checksum to test
$Checksums=#{}
$Checksums["SHA256"]= 'd6a0a09fb1a7971b497674675d5b5621d865d6020e384137548de9c4ac6d4994'
$Checksums["MD5"]= 'xxxx'
#test list checksum and algo
Validate -Path "c:\temp\hello.csv" -Checksums $Checksums
an other solution
$file="C:\temp\exludevalue.txt"
$Checksums=#{}
$Checksums["SHA256"]= 'd6a0a09fb1a7971b497674675d5b5621d865d6020e384137548de9c4ac6d4994'
$Checksums["MD5k"]= '11A8D99F80F9B29FCF6A995D2F17B2E3'
$Checksums.Keys |
%{
if ($(gcm Get-FileHash).Parameters.Algorithm.Attributes.ValidValues -contains $_)
{
$algocalc=(Get-FileHash -path $file -Algorithm $_).Hash;
}
else
{
$algocalc='ALGO NOT FOUNDED'
}
new-object psobject -Property #{
Algo=$_
OldValue=$Checksums[$_]
CalculedValue=$algocalc
ResultComparison= $algocalc -eq $Checksums[$_]
}
}