Assining cmdlet to variable and printing full, literal value in powershell - powershell-7.0

I've been trying to assign a cmdlet to a variable and then being able to inspect the variable's value as [it was] in the original cmdlet; as opposed to just executing it or only seeing its usual properties with commands like:
get-variable $seevars | fl *
or:
get-childitem -path variable:\$seevars | fl *
E.g. I create a variable:
$seevars = get-childitem variable: | where-object -property name -match somePrefix*
After a while, I may forget what $seevars contains or may want to modify it and so will want to inspect $seevars, expecting to see the value of :
'get-childitem variable: | where-object -property name -match somePrefix*'
Instead I get, undesirably, its properties in its technical format (I assume); out of which it will be hard for me to reconstruct its original, literal cmdlet.
Is this at all possible?

Related

Cannot read specific key from JSON file with Powershell

I have a large JSON file (vehicle data) from which I want to read 1 specific value (vehicle identification number, for example). So, following this answer, I have this code with debug output:
$json = Get-Content $responsefilepath | ConvertFrom-Json
Write-Host $json
Write-Host $json.values | Where-Object key -eq "coc_VIN"
The first line puts my inputs file into an object;
the second line outputs the content of my file:
the third line should provide the value YV1DZ8256D2390218, but it's just blank.
On the PS command line, this provides a nice table of all values:
Get-Content .\data\02-returned\sample.json | ConvertFrom-Json
I would extend that command to filter on the desired key:
Get-Content .\data\02-returned\sample.json | ConvertFrom-Json | Where-Object key -eq "coc_VIN"
and again, that returns a blank line. Why?
Input file:
I figured it out myself:
Where-Object key presumes that there is a key/value pair where the name of the key is literally key. My data does not have that, so that's why it does not work.
Instead, I can use the dot notation to select the value of the key named "coc_VIN":
$json = Get-Content $responsefilepath | ConvertFrom-Json
$myvalue = $json.coc_VIN
...and that works!

use where-object to find data, but want to add data to every row also the export to csv

Hi I have a script that reads a csv file, creates a json file, checks the users in the file against a service, then i get the result as a json file.
I take that result and finds the users i csv file and creates a new file.
I do that with a where-object
But i need to add some extra values on every user before i export it to csv
This is my 2 lines for finding users and then export
$matches = $users | where-object { $_.number -in $response.allowedItemIds } | Select-Object -Property Number,Surname,Forename,Emailaddress
$matches | Export-Csv -path $Saved$savefile -NoTypeInformation -Append
Is that possible or do i need to do a for each?
Cheers
Assuming I've interpretted your question correctly, you should be able to use PowerShell's Calculated Properties for this purpose.
For example, if you wanted to add a field called "Date" and set the current Date/Time to each user row, you could do the following:
$matches = $users | where-object { $_.number -in $response.allowedItemIds } | Select-Object -Property Number,Surname,Forename,Emailaddress, #{Name="Date";Expression={Get-Date}}
The Expression value can either be a static value such as "StaticValue", a variable such as $i (useful if used as part of a loop, for example) or more complex value that is returned from other cmdlets (as in my example above)

Why does ConvertFrom-Json produce an Object which turns into a PSCustomObject after assignment? And how do I shortcut that?

I have a simple json file as follows:
[
{"ClientName": "Test Site 1", "ClientID": "000001"},
{"ClientName": "Test Site 2", "ClientID": "000002"},
{"ClientName": "Test Site 3", "ClientID": "000003"}
]
When I use the following PowerShell command:
ConvertFrom-Json (Get-Content TestSites.json -Raw)
I get back a System.Object[]. This doesn't allow me to pipe the output to another function I have which accepts "ClientName" and "ClientID" parameters.
However, when I assign that object to another variable, like this:
$myobj = ConvertFrom-Json (Get-Content TestSites.json -Raw)
$myobj is actually a System.Management.Automation.PSCustomObject which is capable of being passed to my function.
How can I just pipe the results of the original command without having to assign it to another variable first?
I hope that makes sense.
Your JSON is an array correct? PowerShell will unroll arrays in the pipeline unless you explicity change that behavior. Assuming your JSON is stored in the variable $json as a single string consider the following examples.
ConvertFrom-Json $json | ForEach-Object{$_.gettype().fullname}
System.Object[]
(convertFrom-Json $json) | ForEach-Object{$_.gettype().fullname}
System.Management.Automation.PSCustomObject
System.Management.Automation.PSCustomObject
System.Management.Automation.PSCustomObject
You should be able to wrap the expression in brackets to change the outcome. In the second example it should be sending the 3 objects individually down the pipe. In the first it is being sent as a single object array.
My explanation needs work but I am sure of the cause is how PowerShell deals with arrays and the pipeline. Unrolling being a common word used to describe it.
So depending on your use case you might just be able to wrap the expression in brackets so it gets processed before the pipe to ForEach in my example.
If you have an array such as System.Object[] you could try piping via foreach:
ConvertFrom-Json (Get-Content TestSites.json -Raw) | %{ $_ | your-function }
If you want to pass the whole array down the pipe as-is, you can try adding a comma (aka a unary comma before the variable:
,$myobj | whatever
You can probably see how the latter works by comparing the following:
$myobj | Get-Member # Shows the type of the elements of the array
Get-Member -InputObject $myobj # Shows the type of the array
,$myobj | Get-Member # Shows the type of the array

Reading from CSV produces duplicate entries in variable

I have this bit of code :
$servers = Import-Csv "sources.csv"
$computername = $servers.server
$ServiceName = $servers.services
sources.csv contains the following..
Server,Services
BRWS40,winrm
BRWS84,winrm
I have then a foreach, and the Write-Host is within that, it output this:
Write-Host "$computername - $ServiceName" -ForegroundColor black -BackgroundColor red
Output from above I get is:
BRWS40 BRWS84 - winrm winrm
Whereas I was wanting to have one computer and service per line.
BRWS40 - winrm
What am I doing wrong?
I amended the code from here.
$servers = Import-Csv "sources.csv" imports the content of sources.csv as a list of custom objects into the variable $servers.
$computername = $servers.server selects the value of the server property of each object into the variable $computername, thus generating a list of computer names.
$ServiceName = $servers.services selects the value of the services property of each object into the variable $ServiceName, thus generating a list of service names.
Note that $array.property will only work in PowerShell v3 and newer, because earlier versions don't automatically unroll the array to get the element properties, but try to access the property of the array object itself. If the array doesn't have such a property, the result will be $null, otherwise it will be the value of the property of the array. Either way it won't be what you want. To make the property expansion work across all PowerShell versions use Select-Object -Expand or echo the property in a ForEach-Object statement:
$computername = $servers | Select-Object -Expand server
$computername = $servers | ForEach-Object { $_.server }
When you put array variables in a string ("$computername - $ServiceName") the array elements are joined by the $OFS character (space by default), so "$computername" becomes BRWS40 BRWS84 and "$ServiceName" becomes winrm winrm.
To get the corresponding service name for each computer you need to process $servers in a loop, for instance:
foreach ($server in $servers) {
Write-Host ('{0} - {1}' -f $server.Server, $server.Services) ...
}
If you don't need a specific output format you could also use one of the Format-* cmdlets, for instance Format-Table:
Import-Csv "sources.csv" | Format-Table -AutoSize
You actually have to loop through your result:
$servers = Import-Csv "sources.csv"
$servers | %{
$computername = $_.server
$ServiceName = $_.services
write-host "$computername - $ServiceName" -foregroundcolor black -backgroundcolor red
}
or use the Format-Table cmdlet:
$servers | Format-Table

Creating a Csv using Powershell

I am trying to take a filename such as: John_Doe_E_DOB_1/1/46_M(This is the gender)_ID_0000000_IMG_FileName_Date-of-File_1/1/15_Doc-page-1 And create a CSV file to open in Excel with column headers for: Last Name, First Name, MI, ID No, File Name, Date of File along with doc type. Here's my code so far:
Get-ChildItem -Path C:\Users\name\desktop\test -Recurse | ForEach-Object {$_ | add-member -name "Owner" -membertype noteproperty -value (get-acl $_.fullname).owner -passthru} | Sort-Object fullname | Select BaseName,Name,Owner | Export-Csv -Force -NoTypeInformation C:\Users\name\desktop\test\thing.csv
All this is doing is dropping that really long file name in at the top, and then adding the ext at the end in another column. Example:
John_Doe_E_DOB_1/1/46_M(This is the gender)_ID_0000000_IMG_FileName_Date-of-File_1/1/15_Doc-page-1 Would be in column 1 and
John_Doe_E_DOB_1/1/46_M(This is the gender)_ID_0000000_IMG_FileName_Date-of-File_1/1/15_Doc-page-1.txt <----- Would be the only difference in column 2
How can I split this up for over a million files, all different lengths, and sizes, and get it to break up into the categories listed above? All help would be greatly appreciated.
I would replace the Select stage of your pipeline with a call to a filter function like this:
filter GenObj {
$parts = $_.FullName.Split('_')
new-object pscustomobject -property #{
Owner = (get-acl $_.fullname).owner
FirstName = $parts[0]
LastName = $parts[1]
MiddleInitial = $parts[2]
# Fill in the rest
}
}
Get-ChildItem -Path C:\Users\name\desktop\test -Recurse |
Sort-Object fullname |
GenObj |
Export-Csv -Force -NoTypeInformation C:\Users\name\desktop\test\thing.csv
This will create a new custom object with all the properties on it that correspond to the parts of the filename you want to extract.
This string splitting approach may not work depending on how you handle names with no middle initial.
Also be aware that if you are processing a million files, the use of Sort-Object will cause every single FileInfo object (one for every file) to get buffered in memory so the sort can be performed. You may likely run out of memory and the command will fail. I would consider removing Sort-Object in this scenario.