Powershell output formatting? - powershell

I have a script that scans for a specific folder in users AppData folder. If it finds the folder, it then returns the path to a txt file. So we can see the computer name and username where it was found.
I would like to be able to format the what is actually written to the text file, so it removes everything from the path except the Computer and User names.
Script:
foreach($computer in $computers){
$BetterNet = "\\$computer\c$\users\*\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm"
Get-ChildItem $BetterNet | ForEach-Object {
$count++
$betternetCount++
write-host BetterNet found on: $computer
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" $_`n
write-host
}
}
The text files contain information like this
\\computer-11-1004S10\c$\users\turtle\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-24S\c$\users\camel\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm
\\computer-1004-23S\c$\users\rabbit\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm

If you have each line in a form of the string $string_containing_path then it is easy to split using split method and then add index(1) and (4) that you need:
$afterSplit = $string_containing_path.Split('\')
$stringThatYouNeed = $afterSplit[1] + " " + $afterSplit[4]
You can also use simple script that will fix your current logs:
$path_in = "C:\temp\list.txt"
$path_out= "C:\temp\output.txt"
$reader = [System.IO.File]::OpenText($path_in)
try {
while($true){
$line = $reader.ReadLine()
if ($line -eq $null) { break }
$line_after_split_method = $line.Split('\')
$stringToOutput = $line_after_split_method[1] + " " + $line_after_split_method[4] + "`r`n"
add-content $path_out $stringToOutput
}
add-content $path_out "End"
}
finally {
$reader.Close()
}

If you split your loop into two foreach loops, one for computer and user directory it would be easier to output the name of the user directory.
$output = foreach($computer in $computers){
$UserDirectories = Get-ChildItem "\\$computer\c$\users\" -Directory
foreach ($Directory in $UserDirectories) {
$BetterNet = Get-ChildItem (Join-Path $Directory.fullname "\AppData\Local\Google\Chrome\User Data\Default\Extensions\gjknjjomckknofjidppipffbpoekiipm")
Add-Content "\\SERVERNAME\PowershellScans\$date\$time\BetterNet.txt" "$computer $($Directory.name)`r`n"
write-host BetterNet found on: $computer
$BetterNet
}
}
$output.count

Related

Monitor Azure Files in Storage Account for event : file creation

I know I could use System.IO.FileSystemWatcher in a Powershell script to detect when a file is created in Azure files (in my storage account). Is there a better way to detect a file being created than this method ?
I can't seem to find any logs that I could perhaps parse ?
Thanks
This could do you if you really didn't want to use the FileSystemWatch
$Files = Get-ChildItem -file -Recurse "C:\Temp"
$IfOlderThan = 60
$NewlyCreated = #()
$OldCreated = #()
$Count = 0
Foreach ($file in $files){
if($file.CreationTime -gt (Get-Date).AddMinutes(-$IfOlderThan)){
$NewlyCreated += $file
} Else {
$OldCreated += $file
}
}
Write-Host "Found " -NoNewline;Write-host $($NewlyCreated.Count) -NoNewline -ForegroundColor Green; Write-Host " file\s that have been created in the last $IfOlderThan minutes"
$NewlyCreated | select Name, Fullname, CreationTime

Powershell script suddenly failing

We have a script running daily on two separate servers, there have been no changes made to either copy of the script all year. Last weekend, there was a server outage that interrupted the script running on one of the servers, and ever since the script on that server partially fails each day.
Here is the code which continues to fail, I have broken it out and ran it locally without issue.
$rawlineCountFile ="C:\temp\files\test\linecount"
$rawlineCountFile = $rawlineCountFile +'RawlineCount' + 'test' + '.csv'
$filePath = "C:\temp\files\test"
# do line count in files
$bak = Get-ChildItem $filePath | Where-Object { $_.Extension -eq ".dat" }
Try
{
Write-Output "line_count , file_name"
foreach ($file in $bak) {
$name = $file.name
$measure =(Get-Content $filePath\$file | Measure-Object)
$lines = $measure.Count
Write-Output "$lines , $name"
Write-Output "$lines , $name" >> $rawlineCountFile
}
} catch [Exception] {
Write-Output $_.Exception.GetType().FullName
Write-Output $_.Exception.Message
}
This script above looks at a folder with .dat files and FOR EACH one, it writes the $lines within each file ($measure.count) and the $file.name into a rawlinecountfile.csv.
i.e.
123 , file1.dat
234 , file2.dat
987 , file3.dat
567 , file4.dat
etc. etc.
Each day there are 7 files moved into this folder, then this script runs, so there should be 7 rows added to the rawlinecountfile each day also, then later, after the rest of the process finishes, all the files are cleared out to prepare for the next day.
However, since the outage last week, it only writes 0-2 out of 7 rows onto the csv file each day, not FOR EACH file (still 7).
We are stumped as to why the For Each doesn't seem to be working anymore, while the script has not been changed and the same exact script still runs as expected on the sister server, and on my local machine.
Any thoughts?
When you were calling Get-Content, I believe you are trying to get the file from C:\Temp\Files\Test\C:\Temp\Files\Test\Filename.dat. You can use $file.FullName to get the full path. I suspect it was probably throwing an error and not adding the content to the file. This worked in PS 5.1.
$rawlineCountFile ="C:\temp\files\test\linecount"
$rawlineCountFile = $rawlineCountFile +'RawlineCount' + 'test' + '.csv'
$filePath = "C:\temp\files\test"
# do line count in files
$bak = Get-ChildItem $filePath | Where-Object { $_.Extension -eq ".dat" }
Try
{
Write-Output "line_count , file_name"
foreach ($file in $bak)
{
$name = $file.name
$lines = #(Get-Content -Path $File.FullName).Count
Write-Output "$lines , $name"
"$lines , $name" | Add-Content $rawlineCountFile
}
}
catch [Exception]
{
Write-Output $_.Exception.GetType().FullName
Write-Output $_.Exception.Message
}
Replacing just the single line I mentioned that could be an issue:
$rawlineCountFile ="C:\temp\files\test\linecount"
$rawlineCountFile = $rawlineCountFile +'RawlineCount' + 'test' + '.csv'
$filePath = "C:\temp\files\test"
# do line count in files
$bak = Get-ChildItem $filePath | Where-Object { $_.Extension -eq ".dat" }
Try
{
Write-Output "line_count , file_name"
foreach ($file in $bak) {
$name = $file.name
$measure =(Get-Content $file.FullName | Measure-Object)
$lines = $measure.Count
Write-Output "$lines , $name"
Write-Output "$lines , $name" >> $rawlineCountFile
}
} catch [Exception] {
Write-Output $_.Exception.GetType().FullName
Write-Output $_.Exception.Message
}

Search through a list of computers to find a string in a file with ForEach- Powershell

I am trying to find a string in the hosts files of computers in a text file. I want to check each machine in the text file for the change in the hosts file.
For security purposes, I cannot put the actual string I am searching for. I am very new to PowerShell, and I tried to do this in CMD, but I could not get the output I wanted.
$sys = Get-Content .\Systems.txt
$Loc = "\\$sys\c$\Windows\System32\Drivers\etc\hosts"
$SearchStr = "string"
$sel = Select-String -pattern $SearchStr -path $Loc
ForEach ($System in $sys) {
If ($sel -eq $null)
{
write-host $sys NotFound
}
Else
{
write-host $sys Found
}
}
You weren't too far off, you just needed to re-think your ForEach loop a little. Move your $Loc = line within the loop so that it updates for each system, then skip the $sel = line and just put that in your If check and you're all set:
$sys = Get-Content .\Systems.txt
$SearchStr = "string"
ForEach ($System in $sys) {
$Loc = "\\$system\c`$\Windows\System32\Drivers\etc\hosts"
If (Select-String -pattern $SearchStr -path $Loc -Quiet)
{
write-host "$system Found"
}
Else
{
write-host "$system Not Found"
}
}
I also escaped the dollar sign in the path for c$. I don't think it's needed in this case, but it's good practice in general when using dollar signs that you want to actually be used as such in strings like that.

In powershell $x.FullName not returning full path

I have a powershell script below which takes a config file and deletes files older than x days matching a regular expression.
Config File:
path,pattern,days,testrun
C:\logs\,^data_access_listener.log,7,false
However here is what is output:
Would have deleted 000a19f6-a982-4f77-88be-ca9cc51a2bcbuu_data_access_listener.log
Would have deleted 00189746-2d46-4cdd-a5bb-6fed4bee25a7uu_data_access_listener.log
I'm expecting the output to include the full file path since I'm using the .FullName attribute so I'd expect output as such:
Would have deleted C:\logs\000a19f6-a982-4f77-88be-ca9cc51a2bcbuu_data_access_listener.log
Would have deleted C:\logs\00189746-2d46-4cdd-a5bb-6fed4bee25a7uu_data_access_listener.log
If I am using $x.FullName why am I not getting the full name with path (C:\logs)?
Thanks
Brad
$LogFile = "C:\deletefiles.log"
$Config = import-csv -path C:\config.txt
function DeleteFiles ([string]$path, [string]$pattern, [int]$days, [string]$testrun){
$a = Get-ChildItem $path -recurse | where-object {$_.Name -notmatch $pattern}
foreach($x in $a) {
$y = ((Get-Date) - $x.LastWriteTime).Days
if ($y -gt $days -and $x.PsISContainer -ne $True) {
if ($testrun -eq "false") {
write-output “Deleted" $x.FullName >>$LogFile
} else {
write-output “Would have deleted $x” >>$LogFile
}
}
}
}
foreach ($line in $Config) {
$path = $line.path
$pattern = $line.pattern
$days = $line.days
$testrun = $line.testrun
DeleteFiles $path $pattern $days
}
Looks like a typo. You are not using FullName in the condition that leads to "Would have Deleted". Change:
write-output “Would have deleted $x” >>$LogFile
to:
write-output “Would have deleted " $x.FullName >>$LogFile
To answer your comment, if you want to call a property on a variable that is expanded in the string, you have to surround it in $(), so that the parser knows to invoke the whole expression. Like this:
write-output “Would have deleted $($x.FullName)" >>$LogFile

PowerShell Wildcard Not Returning All Files

I'm new to PowerShell and been trying to get this script to work.
If ((Get-Date -UFormat %a) -eq "Mon") {$intSubtract = -3}
Else {$intSubtract = -1}
$datDate = (Get-Date).AddDays($intSubtract)
Write-Output "Find expected file --------------"
$strDate = ($datDate).ToString('yyyyMMdd')
Write-Host "strDate: $strDate"
$arrGetFile = Get-ChildItem -Path "\\Computer\Data\States\NorthDakota\Cities\*_Bismark_$strDate*.txt"
$strLocalFileName = $arrGetFile
If ($arrGetFile.count -ne 2)
{
Throw "No file or more than two files with today's date exists!"
}
Else {$strLocalFileName = $arrGetFile[0].Name}
Write-Output "Found file $strLocalFileName --------------"
#Encrypt each file
foreach ($arrGetFile in $strPath)
{
Write-Output "Start Encrypt --------------"
$strPath = "\\Computer\Data\States\NorthDakota\Cities\"
$FileAndPath = Join-Path $strPath $strLocalFileName
$Recipient = "0xA49B4B5D"
Import-Module \\JAMS\C$\PSM_PGP.psm1
Get-Module Encrypt
Encrypt $FileAndPath $Recipient
$strLocalFileNamePGP = $strLocalFileName + ".pgp"
Write-Output "End Encrypt --------------"
}
#Archive files
Write-Output "Archiving --------------"
move-item -path \\Computer\Data\States\NorthDakota\Cities\*_Bismark_$strDate*.txt -destination \\Computer\Data\States\NorthDakota\Cities\Archive
The Cities folder will contain two files. Example 2015_Bismark_20150626_183121.txt and 2015_Bismark_20150626_183121_Control.txt
I am trying to get both files encrypted however it is only finding and encrypting the file without _Control. It is archiving both files correctly.
Not sure what I am missing to also find the control file.
Your for loop is incorrect. You have foreach ($arrGetFile in $strPath), but $strPath doesn't seem to contain anything at that point.
Your for loop should be:
foreach ($LocalFile in $arrGetFile)
And you need to remove the following line:
$strLocalFileName = $arrGetFile
This is making $strLocalFileName an array of file objects, but later in the script you are treating it like a string. You may have more logical errors--you need to walk through the script very carefully and identify each variable and make sure it contains what you expect it to contain.
In general you seem to be treating arrays of non-string objects as if they are strings. Note that I changed your $strLocalFileName variable to $LocalFile. This is because it is a file object, not a string object.
Following is a sample that just shows that the for loop iterates through the both files.
If ((Get-Date -UFormat %a) -eq "Mon") {$intSubtract = -3}
Else {$intSubtract = -1}
$datDate = (Get-Date).AddDays($intSubtract)
Write-Output "Find expected file --------------"
$strDate = ($datDate).ToString('yyyyMMdd')
Write-Host "strDate: $strDate"
$arrGetFile = Get-ChildItem -Path "\\Computer\Data\States\NorthDakota\Cities\*_Bismark_$strDate*.txt"
If ($arrGetFile.count -ne 2)
{
Throw "No file or more than two files with today's date exists!"
}
Write-Output "Found files " ($arrGetFile | select Name | fl) "--------------"
#Process each file
foreach ($LocalFile in $arrGetFile)
{
$FileAndPath = Join-Path $LocalFile.DirectoryName $LocalFile
$FileAndPath
}
Start with this and then carefully add your encryption processing back into the loop.
Also, The line that assigns $FileAndPath could be removed. You can just use $LocalFile.FullName wherever you need the full path and filename.