Powershell Select-Object how to get array of values - powershell

I am trying to delete contents of few folders.
What I have:
$Config = #{
InstallPath = 'C:\Program Files\App'
SubPaths = #('www\app1', 'www\app2', 'www\app3')
}
And here is the code to get contents:
$Config.SubPaths | Select-Object { Join-Path $Config.InstallPath $_ } | Get-ChildItem
But it doesn't work, because Get-ChildItem receives object like below:
#{ Join-Path $Config.InstallPath $_ =C:\Program Files\App\www\app1}
Error:
Get-ChildItem : Cannot find drive. A drive with the name '#{ Join-Path $Config.InstallPath $_ =C' does not exist.
At line:1 char:85
+ ... elect-Object { Join-Path $Config.InstallPath $_ } | Get-ChildItem
+ ~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (#{ Join-Path $C...stallPath $_ =D:String) [Get-ChildItem], DriveNotFoun
dException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
How can I convert result of Select-Object to simple array of strings? Or any other approach to make code better?

The results you are getting are because you made a new object with the the literal property Join-Path $Config.InstallPath $_. Instead...
$Config.SubPaths | ForEach-Object { Join-Path $Config.InstallPath $_ } | Get-ChildItem
You are not trying to select a property of a single subpath but generate a string from each of the SubPaths. Using Foreach-object instead to iterate over the collection should get you the results you are looking for.
While you could create custom objects and properties using calculated properties I figure this is not the direction you are going for. But to answer the question in the title you could have done this:
$Config.SubPaths |
Select-Object #{Name="Path";Expression={Join-Path $Config.InstallPath $_}} |
Get-ChildItem
Get-ChildItem should bind to the path property of the new object were are making

Related

storing filename and path in variable to use with Copy-Item

I'm trying to write a script to find the most recent .bak in a certain directory and copy the file to another location. When I use Get-ChildItem the file name isn't enlcosed in single quotes so when i try to copy it Copy-Item cant find it. ( I think)
$dir = 'E:\Backups\'
$dest = 'F:\'
$filename = Get-ChildItem -path $dir -filter *.bak | Sort-Object CreationTime -Descending | Select-Object -First 1 | select FullName | Format-Table -HideTableHeaders
echo #filename
copy-Item -path #filename -destination #dest
echo #filename returns E:\Backups\company.bak but i think need 'E:\Backups\company.bak' for it to work?
PS C:\Users\prodadmin> copy-Item -path #filename -destination #dest
Copy-Item : A positional parameter cannot be found that accepts argument 'Microsoft.PowerShell.Commands.Internal.Format.GroupStartData'.
At line:1 char:1
+ copy-Item -path #filename -destination #dest
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Copy-Item], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
As above, typed it all in one go.
Get-ChildItem returns FileInfo (and also DirectoryInfo) objects.
By using select FullName you tell PowerShell to return an new object with one property called FullName and you lose the Name property.
Format-Table is a cmdlet used for display purposes only, so never use that on data you want to process further.
Lastly, you prefix the variables you have with # instead of $
Try
$dir = 'E:\Backups\'
$dest = 'F:\'
$file = Get-ChildItem -Path $dir -Filter '*.bak' -File | # do not return directories
Sort-Object CreationTime -Descending | # or did you mean LastWriteTime (=> last modified date) ?
Select-Object -First 1 # return just 1 FileInfo object
Write-Host "Found $($file.Name)" # write to console
Copy-Item -Path $file.FullName -Destination $dest

Powershell: how to replace a value within format-table

I want to shorten Directory with relative path:
$Dir = get-childitem C:\temp -recurse
$List = $Dir | where {$_.extension -eq ".txt"}
$List | format-table name, Directory -replace "C:\temp", ""
I get this error:
Format-Table : A parameter cannot be found that matches parameter name 'replace'.
At line:3 char:38
+ $List | format-table name, Directory -replace "C:\temp", ""
+ ~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Format-Table], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.FormatTableCommand
What's the right syntax ?
You can use a calculated property. Example:
$List | Format-Table name,
#{Name = "Directory"; $Expression = {$_.FullName -replace "C:\\temp", ""}}
A calculated property is simply a hashtable that dictates the content of the property. Calculated properties are available with formatting cmdlets that select properties and output a new custom object (e.g, Select-Object, Format-List, etc.).
(As an aside: The -replace operator uses a regular expression, so you would need to write C:\\temp instead of just C:\temp.)
If your goal is to output file system item directory names: Directory is not a property of all file system objects. Is this what you mean?
Get-ChildItem C:\Temp\*.txt -Recurse | Format-Table Name,
#{Name = "Directory"; Expression = {$_.FullName -replace 'C:\\temp', ''}}
Note how this command takes advantage of the pipeline (no need for the intermediate $List or $Dir variables).
To add to #Bill_Stewart's Answer.
$Dir = get-childitem C:\temp -recurse
$List = $Dir | where {$_.extension -eq ".txt"}
$List | format-table name, #{Label="Directory"; Expression={$_.Directory -replace "C:\\temp", ""}}

Powershell - Find Files by Searching for String and Find/Replace Text

I'm learning powershell and trying to write a script that can find files in a directory by a string, and then do a find and replace on the files that are found. I want to store the file list as a variable and then loop through the files and replace specific strings. Here's my script and error, if you have any ideas it would be much appreciated. Thanks!
$GetFiles = Select-String -path "C:\temp\*.xml" -pattern "<cmn:BusinessName>ABC INC</cmn:BusinessName>"|Select-Object filename
foreach ($file in $GetFiles)
{
(Get-Content $Files.PSPath) |Foreach-Object {
$_ -replace "<cmn:FileNumber>0001234</cmn:FileReceiverNumber>", "<cmn:FileReceiverNumber>12345678</cmn:FileReceiverNumber>" `
-replace "<cmn:DropIndicator>DROP</cmn:Indicator>", "<cmn:DropIndicator>DONTDROP</cmn:DropIndicator>"
} |Set-Content $Files.PSPath
}
ERROR
Get-Content : Cannot bind argument to parameter 'Path' because it is
null. At C:\scripts\script.ps1:5 char:18
+ (Get-Content $Files.PSPath) |Foreach-Object {
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-Content], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetContentCommand
$GetFiles = Select-String -Path "C:\temp\*.xml" -Pattern "<cmn:BusinessName>ABC INC</cmn:BusinessName>"
foreach ($File in $GetFiles)
{
$NewContent = Get-Content $File.Path | Foreach-Object {
$_ -replace "<cmn:FileNumber>0001234</cmn:FileReceiverNumber>", "<cmn:FileReceiverNumber>12345678</cmn:FileReceiverNumber>" `
-replace "<cmn:DropIndicator>DROP</cmn:Indicator>", "<cmn:DropIndicator>DONTDROP</cmn:DropIndicator>"
}
$NewContent | Set-Content $File.Path
}
In foreach, you have defined variable named $File but in inside your foreach statement, you are $Files instead of $File
In Line 1, by using Select-Object Filename in the end, $GetFiles has object with only one property Filename. So PSPath property doesn't exist. that is why you getting the null error. BTW the output of Select-String command doesn't have PSPath property.

Powershell getting full path information

I have a directory called Videos. Inside this directory, are a bunch of sub directories of various cameras. I have a script that will check each of the various cameras, and delete recordings older than a certain date.
I am having a bit of trouble getting the full directory information for the cameras. I am using the following to get it:
#Get all of the paths for each camera
$paths = Get-ChildItem -Path "C:\Videos\" | Select-Object FullName
And then I loop through each path in $paths and delete whatever I need to:
foreach ($pa in $paths) {
# Delete files older than the $limit.
$file = Get-ChildItem -Path $pa -Recurse -Force | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $limit }
$file | Remove-Item -Recurse -Force
$file | Select -Expand FullName | Out-File $logFile -append
}
When I run the script, I am getting errors such as:
#{FullName=C:\Videos\PC1-CAM1}
Get-ChildItem : Cannot find drive. A drive with the name '#{FullName=C' does not exist.
At C:\scripts\BodyCamDelete.ps1:34 char:13
+ $file = Get-ChildItem -Path $pa -Recurse -Force | Where-Object { $_.PSIsCont ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (#{FullName=C:String) [Get-ChildItem], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Is there a way to strip that #{FullName= off of the Path? I think that may be what the issue is.
In your case $pa is an object with a FullName property. The way you would access that would be this.
$file = Get-ChildItem -Path $pa.FullName -Recurse -Force | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $limit }
However it would just be simpler to change only this line and leave
$paths = Get-ChildItem -Path "C:\Videos\" | Select-Object -ExpandProperty FullName
-ExpandProperty will just return the string instead of the object that Select-Object was returning.
You are nearly there. What you want is the -ExpandProperty argument for Select-Object. This will return the value of that property, instead of a FileInfo object with one property, that property being FullName. This should resolve it for you:
$paths = Get-ChildItem -Path "C:\Videos\" | Select-Object -ExpandProperty FullName
Edit: Looks like Matt beat me to it by a minute.

Powershell - Export Multiple CSV's into unique folders

I have been working on a PowerShell script for the better part of well a week or two. I've been able to get some parts of it working however I'm unable to fully get this automated.
I deal with a lot of CSV files on a daily basis, I have been tasked with uploading them into our software however sometimes they're too large to handle so I break them down based upon their "type" (it's a column in the CSV) and I export it to a single CSV per "type". I've been able to accomplish this with the following:
$file = gci -Filter "*.csv";
Import-Csv $file `
| Group-Object –Property “type” `
| Foreach-Object `
{
$path=$_.name+”.csv” ; $_.group `
| Export-Csv –Path $path –NoTypeInformation
}
So this works wonderfully, for each individual CSV. Unfortunately I don't have the time to do this for each individual CSV. Now I come to my other PowerShell script:
get-childitem -Filter "*.csv" `
| select-object basename `
| foreach-object{ $path=$_.basename+".csv" #iterate through files.
if(!(Test-Path -path $_.basename)) #If the folder of the file can't be found then it will attempt to create it.
{
New-Item $_.basename -type directory; $file=$_.basename+".csv";
Import-Csv $file `
| Group-Object -Property "Type" `
| Foreach-Object {
$path=$_.name+".csv"; $_.group `
| `
if(!(Test-Path -path $path2))
{
New-Item $path2 -type directory
Export-Csv -Path $path2 + "\" + $path -NoTypeInformation
}
else
{
"Failed on: " + $_.basename
#Export-Csv -Path $_.basename + "\" + $path -NoTypeInformation
}
}
}
else
{
Import-Csv $path `
| Group-Object -Property "Type" `
| Foreach-Object {$path=$_.basename+".csv" ; $_.group
if(Test-Path -path $._)
{
New-Item $path2 -type directory
Export-Csv -Path $path2 + "\" + $path -NoTypeInformation
}
#else
#{
Write-Host "Failed on: $_.basename"
#Export-Csv -Path $_.basename + "\" + $path -NoTypeInformation
#}
}
}
}
I just can't wrap my head around "why" this isn't working effectively. I have two conditionals. Is there a folder for the CSV? If no create one. I have to have another one because one of the "types" contains a \ which errors out if I don't have the folder, so I automatically try to create it. When I run the script I get the Path is null.
The Error is:
The term ' ' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or
if a path was included, verify that the path is correct and try again.
At C:\Users\c.burkinshaw\foldermake.ps1:11 char:26
+ | ` <<<<
+ CategoryInfo : ObjectNotFound: ( :String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Test-Path : Cannot bind argument to parameter 'Path' because it is null.
At C:\Users\c.burkinshaw\foldermake.ps1:12 char:45
+ if(!(Test-Path -path <<<< $path2))
+ CategoryInfo : InvalidData: (:) [Test-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.TestPathCommand
Any help would be greatly appreciated, if you have questions please don't hesitate to ask.
You have not defined $path2 anywhere, so something like test-path -path $path2 will say path is null. And in one place you are using $._ which will again give errors.
Edit after question updated with error message:
Your error message also says the same
Test-Path : Cannot bind argument to parameter 'Path' because it is
null. At C:\Users\c.burkinshaw\foldermake.ps1:12 char:45
+ if(!(Test-Path -path <<<< $path2))
Also the other error is in:
$path=$_.name+".csv"; $_.group `
| `
what are you trying to do here with the $_.group?
It is not proper. You cannot do $_.group | and provide some if statement.
Other comments:
Why are using $_.basename and then appending .csv? You could have just used $_.name. Try to not use the select-object basename - I don't see the value.
Extract the common import-csv and export-csv part into a function.