Getting a path and then converting it to a string? - powershell

$getusers = Get-ChildItem \\pc-name\c$\users\ | Select-Object Fullname
I'm running that line to get all the users who have logged into a pc.
Then I am checking every documents folder for files. I assumed it would be as simple as this:
foreach ($user in $getusers) {
Get-ChildItem "$user\documents"
}
but it seems that I have to convert the $getusers to string? Can someone help and explain what needs to be done? I think its simple I'm just not getting.

$dirs = Get-ChildItem \\pc-name\c$\users\ | Select-Object FullName | Where-Object {!($_.psiscontainer)} | foreach {$_.FullName}
This ended up working. I was able to figure it out.

In case someone else finds this in there search for help I wanted to add what I think the actual issue is. Consider the following line:
$getusers = Get-ChildItem \\pc-name\c$\users\ | Select-Object Fullname
That would return an object of fullnames.
FullName
--------
\\localhost\c$\users\jpilot
\\localhost\c$\users\matt
\\localhost\c$\users\misapps
\\localhost\c$\users\mm
The issue is that $getusers is a System.Object[] that has FullName NoteProperty and not a System.String[] as the loop would be expecting. What should be done in the following
$getusers = Get-ChildItem \\pc-name\c$\users\ | Select-Object -ExpandProperty Fullname
Now $getusers will contain an array of string
\\localhost\c$\users\jpilot
\\localhost\c$\users\matt
\\localhost\c$\users\misapps
\\localhost\c$\users\mm
That would make the rest of the script function as expected.

Related

Is there a way to display the latest file of multiple paths with information in a table format?

I check every day, whether a CSV-File has been exported to a specific folder (path). At the moment there are 14 different paths with 14 different files to check. The files are being stored in the folder and are not deleted. So i have to differ between a lot of files with "lastwritetime". I would like a code to display the results in table format. I would be happy with something like this:
Name LastWriteTime Length
ExportCSV1 21.09.2022 00:50 185
ExportCSV2 21.09.2022 00:51 155
My code looks like this:
$Paths = #('Path1', 'Path2', 'Path3', 'Path4', 'Path5', 'Path6', 'Path7', 'Path8', 'Path9', 'Path10', 'Path11', 'Path12', 'Path13', 'Path13')
foreach ($Path in $Paths){
Get-ChildItem $path | Where-Object {$_.LastWriteTime}|
select -last 1
Write-host $Path
}
pause
This way i want to make sure, that the files are being sent each day.
I get the results that i want, but it is not easy to look at the results individually.
I am new to powershell and would very much appreciate your help. Thank you in advance.
Continuing from my comments, here is how you could do this:
$Paths = #('Path1', 'Path2', 'Path3', 'Path4', 'Path5', 'Path6', 'Path7', 'Path8', 'Path9', 'Path10', 'Path11', 'Path12', 'Path13', 'Path13')
$Paths | ForEach-Object {
Get-ChildItem $_ | Where-Object {$_.LastWriteTime} | Select-Object -Last 1
} | Format-Table -Property Name, LastWriteTime, Length
If you want to keep using foreach() instead, you have to wrap it in a scriptblock {…} to be able to chain everything to Format-Table:
. {
foreach ($Path in $Paths){
Get-ChildItem $path | Where-Object {$_.LastWriteTime} | Select-Object -Last 1
}
} | Format-Table -Property Name, LastWriteTime, Length
Here the . operator is used to run the scriptblock immediately, without creating a new scope. If you want to create a new scope (e. g. to define temporary variables that exist only within the scriptblock), you could use the call operator & instead.

How to solve the "'IndexOf'." error in PowerShell script

While running the below script I am getting an error:
"Method invocation failed because [System.Management.Automation.PSCustomObject] doesn't contain a method named 'IndexOf'".
Please help me to find out a solution to avoid the above error while running the below script.
Code:
$serverlist_csv1 = Import-Csv -Path $file1
$serverlist_temp1 = $serverlist_csv1
$exclude_serverlist_csv = Import-Csv -Path $file2
foreach ($server in $exclude_serverlist_csv) {
$servers1 = ($serverlist_csv1.'SourceHostName' | Select-Object -ExcludeProperty 'SourceHostName')
if ($servers1 -contains $server.'Exclude Server') {
$server_object1 = ($serverlist_csv1 | Where-Object {$_.SourceHostName -eq $server.'Exclude Server'})
$serverindex1 = $serverlist_csv1.IndexOf($server_object1)
$dataResizable1 = {$serverlist_csv1}.Invoke()
$dataResizable1.RemoveAt($serverindex1)
$serverlist_csv1 = $dataResizable1
}
}
You are getting that error because you used select-object on the pipeline invocation of $serverlist_csv1, which creates a layer over the object effectively creating a new object a pscustomobject and that makes it lose the indexOf() method.
if you avoid this step and instead try for instance to exclude that on the import of the csv or modify the member to nothing if that property isn't necessary to you. The point is like people before me said that does not seem like the better way to solve whatever problem this is.
Build a list of the server names from the second file:
$exclude = Import-Csv $file2 | Select-Object -Expand 'Exclude Server'
Then filter the first file for rows whose SourceHostName column isn't one of those names and write the result back to a file:
Import-Csv $file1 | Where-Object {
$exclude -notcontains $_.SourceHostName
} | Export-Csv 'C:\output.csv' -NoType

Edit an object non-destructively in PowerShell

I am trying to format the resulting object without destroying it. But all my efforts and research has failed me. Any tips are welcome.
My code looks like this:
Set-Location 'C:\Temp'
$Files = Get-ChildItem -File | Select-Object FullName, Length
And what I get, is this:
FullName Length
-------- ------
C:\Temp\CleanupScript.txt 10600
C:\Temp\Columns.csv 4214
C:\Temp\Content.html 271034
C:\Temp\Content.txt 271034
C:\Temp\DirSizes.csv 78
What I want is this:
FullName Length
-------- ------
Temp\CleanupScript.txt 10600
Temp\Columns.csv 4214
Temp\Content.html 271034
Temp\Content.txt 271034
Temp\DirSizes.csv 78
When I tried this:
$Files = Get-ChildItem -File | Select-Object FullName, Length | % { $_.FullName.Remove(0, 3) }
I got the right result, but I lost the Length column.
PS C:\Temp> $Files
Temp\CleanupScript.txt
Temp\Columns.csv
Temp\Content.html
Temp\Content.txt
Temp\DirSizes.csv
Please help.
Big thanks
Patrik
The easiest way to do this is to construct the property you want in the Select command, such as:
$Files = Get-ChildItem -File | Select #{l='FullName';e={$_.FullName.Substring(3)}},Length
The format for this is a hashtable with two entries. The keys are lable (or name), and expression. You can shorten them to l (or n), and e. The label entry defines the name of the property you are constructing, and the expression defines the value.
If you want to retain all of the original methods and properties of the objects you should add a property to them rather than using calculated properties. You can do that with Add-Member as such:
$Files = GCI -File | %{Add-Member -inputobject $_ -notepropertyname 'ShortPath' -notepropertyvalue $_.FullName.Substring(3) -PassThru}
Then you can use that property by name like $Files | FT ShortPath,Length -Auto, while still retaining the ability to use the file's methods like Copy() and what not.
I would recommend using a calculated property and Split-Path -NoQualifier; e.g.:
Get-ChildItem -File | Select-Object `
#{Name = "NameNoQualifier"; Expression = {Split-Path $_.FullName -NoQualifier}},
Length
For help on calculated properties, see the help for Select-Object.
(Aside: To correct your terminology a bit, this is not modifying objects non-destructively but rather outputting new objects containing the properties you want formatted how you want them.)

powershell find string in csv get associated cell

Alright I have a csv that i import into variable $csv
name description system redundant
---- ----------- ------ ---------
hi don't settle sight dumb
hello why not settle settle
this just fails why? settle
I want to find a specific string in either $csv.description or $csv.system. If that string is found, i want to return the associated cell value under $csv.name
I can't have the select-string look for anything in $csv.redundant
this is what i have so far:
$csv = import-csv -path c:\hi
$find = $csv | select-string "settle"
output: $find
#{name=hi; description=don't settle; system=sight; redundant=dumb }
#{name=hello; description=why not; system=settle; redundant=settle}
#{name=this; description=just fails; system=why?; redundant=settle}
however - nothing returns if i do a $find.name, even though the $find.gettype() shows that this is an array. Also i don't know how to get the select-string to avoid $csv.redundant
I need the output to only be the $find.name of only the first 2 objects from the array.
thanks
Don't use Select-String, use Where-Object instead:
$searchTerm = 'settle'
$csv |Where-Object {$_.description -match $searchTerm -or $_.system -match $searchTerm} |Select-Object -Expand Name
ipcsv C:\temp\test.csv | ? {$_.description, $_.system -like "*settle*"} | select Name

Powershell - Strange output when using Get-ChildItem to search within files

I have a problem I am hoping someone could help with....
I have a powershell script containing the lines shown below:
$output = Get-ChildItem -path $target -recurse | Select-String -pattern hello | group path | select name
Write-Output "Output from the string match is $output"
The error I am getting:
Output from the string match Microsoft.Powershell.Commands.GroupInfo Microsoft.Powershell.Commands.GroupInfo
When I run this command on it's own (ie not within a script) it works perfectly and returns the two files in that location that contains the word "hello".
It appears that it knows there are two things it has found because it prints the "Microsoft.Powershell.Commands.GroupInfo" text twice (as shown above in the error). But why is it printing this and not the path to the files as it should do?
There must be something obvious I am overlooking but I dont know what.
Your help is much appreciated, thanks
The reason you're seeing this is because $output is an array of Selected.Microsoft.PowerShell.Commands.GroupInfo objects -- the objects returned by Group-Object when passed to Select-Object (without Select-Object they would just be Microsoft.PowerShell.Commands.GroupInfo objects instead). You can confirm the type of objects in $ouput by running:
$output | Get-Member
Check the TypeName that is displayed at the top of the output.
When you run these commands interactively in the console, you are seeing the paths because PowerShell knows how to display GroupInfo objects in the console so that they are human-readable. Note that when you just call $output in the console, you see a "Name" header underlined with dash characters -- this is PowerShell interpreting the GroupInfo object you gave it and displaying the Name property for you in the console.
The problem occurs when you try to output the $output array inside a string. Then PowerShell is not able to use its more advanced formatting logic and instead merely tries to convert the object to a string to insert into your string. When it does that, it doesn't have enough logic to know that what you really want to appear in your string is the Name property of these GroupInfo objects, so instead if just prints out a string with the type name of each of the objects in the $output array. So that's why you see the type name twice.
The simple solution to this problem is the -ExpandProperty parameter for Select-Object. This does what it says -- it expands the property you asked for with Select-Object and returns just that property, not the parent object. So the Name property of a GroupInfo object is a string. If you call Select-Object Name, you get a GroupInfo object with the Name property. If you call Select-Object -ExpandProperty Name, you get just the Name property as a String object. Which is what I expect that you want in this case.
So try this instead:
$output = Get-ChildItem -path $target -recurse | Select-String -pattern hello | group path | select -ExpandProperty name
A foreach would be appropriate here I believe. Try this:
$output = Get-ChildItem -path $target -recurse | where {$_.name -like "*hello*"} | select name
foreach ($file in $output) {
write-host $file.name
}
Or this:
$output = Get-ChildItem -path $target -recurse | select-string -pattern "hello" | select name
foreach ($file in $output) {
write-output $file.name
}