Powershell: how to replace a value within format-table - powershell

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", ""}}

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: A drive with the name '#{Path=C' does not exist

I'm trying to search through a directory of files and pull out all the file paths that have the pattern. Then loop through each file and search for another pattern of text. It works if I manually do:
Select-String -Path "C:\inetpub\mailroot\Badmail-Archive\003c908531613052021000000A2.BAD" -Pattern ('Final-Recipient') | Select -ExpandProperty line
It does not if I do it in the loop:
$FileList = Get-ChildItem "C:\inetpub\mailroot\Badmail-Archive" -Filter *.BAD | Select-String -Pattern 'Diagnostic-Code: smtp;550 5.1.1' | Select-Object Path
$FileList += Get-ChildItem "C:\inetpub\mailroot\Badmail-Archive" -Filter *.BAD | Select-String -Pattern 'Diagnostic-Code: smtp;550 5.1.2' | Select-Object Path
$FileList += Get-ChildItem "C:\inetpub\mailroot\Badmail-Archive" -Filter *.BAD | Select-String -Pattern 'Diagnostic-Code: smtp;550 5.2.1' | Select-Object Path
foreach($filepath in $FileList) {
$BADSearch = Select-String -Path $filepath -Pattern ('Final-Recipient') | Select -ExpandProperty line
$eMailAddress = $BADSearch.Split(";")[1]
echo "File Path: $filepath"
echo $eMailAddress
}
File Path: C:\inetpub\mailroot\Badmail-Archive\003c908531613052021000000A2.BAD
Select-String : Cannot find drive. A drive with the name '#{Path=C' does not exist.
At C:\Scripts\BadEmails-SQLGenerator.ps1:46 char:14
+ ... BADSearch = Select-String -Path $filepath -Pattern ('Final-Recipient' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (#{Path=C:String) [Select-String], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.SelectStringCommand
Your problem is with treating any arbitrary object as if it's a string. Select-String expects a string instance for the Path parameter, but you're passing it the resulting MatchInfo object returned from the previous Select-String call.
You'll need to tease out the path by selecting the .Path member from the previous command output:
Select-String -Path $filepath.Path # ...

Powershell Set Content Replaced string

So, i need to save a string that was replaced on files.
I'm doing something wrong, but i`m not be able to figure it out, what!
My code:
Get-ChildItem -Path C:\Users\user\Documents -Recurse -Include "*.txt" -File | Select-String -Pattern \b192\.168\.10\.2\b , \b192\.168\.10\.11\b -AllMatches -List | Foreach-Object { $_ -replace '\b192\.168\.10\.2\b', "DEV" -and $_ -replace '\b192\.168\.10\.11\b', "QUAL" | Set-Content $_}
And gives-me the following error:
Set-Content : Could not open the alternate data stream '1:192.168.10.11' of the file 'C:\Users\user\Documents\result.txt'.
At line:1 char:323
+ ... place '\b192\.168\.10\.11\b', "QUAL" | Set-Content $_}
+
+ CategoryInfo : ObjectNotFound: (C:\Users\paulo....ents\result.txt:String) [Set-Content], FileNotFoundException
+ FullyQualifiedErrorId : GetContentWriterFileNotFoundError,Microsoft.PowerShell.Commands.SetContentCommand
Set-Content : Could not open the alternate data stream '1:192.168.10.11' of the file
'C:\Users\user\Documents\test.txt'
At line:1 char:323 ... place '\b192\.168\.10\.11\b', "QUAL" | Set-Content $_}
CategoryInfo : ObjectNotFound: (C:\Users\user\test.txt:String) [Set-Content], FileNotFoundException
FullyQualifiedErrorId : GetContentWriterFileNotFoundError,Microsoft.PowerShell.Commands.SetContentCommand
Thanks for any Help!
Inside the ForEach-Object block, $_ will refer to the current match result as returned by Select-String - to get the file path, reference the Path property:
... | ForEach-Object { ... |Set-Content -LiteralPath $_.Path}
The -and operator is used inside if tests like if(this -and that).
You should change the double replace actions from
$_ -replace '\b192\.168\.10\.2\b', "DEV" -and $_ -replace '\b192\.168\.10\.11\b', "QUAL"
into
$_ -replace '\b192\.168\.10\.2\b', "DEV" -replace '\b192\.168\.10\.11\b', "QUAL"
Also, if I understand the question properly, you want to find all string replacements in the file, and to get all, you need to remove the -List switch from Select-String.
Next, as Mathias explains in his answer, you need to use the Path property from the current match to get the file FullName.
However, if you pipe this through to Set-Content straight away, you will get an exception because the file then is in use and you cannot write to the same file.
Below creates a new file in the same path, with _replacements appended to the filename
# use '-Include' instead of '-Filter' if you need more file extensions to filter on
Get-ChildItem -Path 'C:\Users\user\Documents' -Recurse -Filter "*.txt" -File |
Select-String -Pattern '\b192\.168\.10\.2\b', '\b192\.168\.10\.11\b' -AllMatches |
Foreach-Object {
$file = '{0}_replacements{1}' -f [System.IO.Path]::GetFileNameWithoutExtension($_.Path),
[System.IO.Path]::GetExtension($_.Path)
$target = Join-Path -Path ([System.IO.Path]::GetDirectoryName($_.Path)) -ChildPath $file
$_ -replace '\b192\.168\.10\.2\b', "DEV" -replace '\b192\.168\.10\.11\b', "QUAL" |
Add-Content -Path $target
}
This results in a file called 'C:\Users\user\Documents\test_replacements.txt'
C:\Users\user\Documents\test.txt:4:DEV
C:\Users\user\Documents\test.txt:7:QUAL
The original file 'C:\Users\user\Documents\test.txt' will not be altered.

Powershell Select-Object how to get array of values

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

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.