move contents not fully completed - list

I have a source folder called "aa" directly on c:\
It contains 3 subfolders A1, A2, A3, with everyone a file t1, t2, t3 (respectively)
I have a file called "mylist.txt" which contain list of folders I would like to move (in my case A1 & A3)
I would like to move each folders listed in mylist, from source to dest, including their contents
when I try this code below :
"A3" folder is correctly moved with its "T3" file,
"A2" folder stay in source folder because not asked in mylist file
but "A1" folder disappear and "T1" file is moved directly to "dest" folder...
#
$Sce = "C:\aa"
$Dest = "c:\zz"
$files = "c:\mylist.txt"
Clear-Host
foreach($line in [System.IO.File]::ReadLines($files))
{
$fullline = $sce + "\" + $line
Move-Item -Path $fullline -Destination $Dest
}
#
Can someone help me?

I am auto replying to help any one
in fact we have to check if "dest" exist prior to move content, or create it
in this case all sub folder and content are move correctly
hope this can help
have a nice day
# PARAM
$Sce = "C:\aa"
$Dest = "c:\zz"
$list = "c:\mylist.txt"
$line = ""
$fullSce = ""
Clear-Host
# --- DO NOT MODIFY BELOW THIS LINE ---
# verifie que le repertoire dest existe, le cree sinon
If(!(test-path -PathType container $Dest))
{
New-Item $Dest -ItemType Directory
}
# deplace tous les sous-repertoires et contenus de la source vers la dest,
# selon les criteres du fichier $list
foreach($line in [System.IO.File]::ReadLines($list))
{
$fullSce = $sce + "\" + $line
Move-Item -Path $fullSce -Destination $Dest
}

Related

partial extraction of urls due to bad handling of accented and punctuation characters

Inside film_disponibili.txt I have these lines
La forza dell'amore
La forza della volontà
La fuga - Girl in Flight
Inside html_di_test.txt I have this html code
La forza dell’amore [B/N] (1936)
La forza della volontà [HD] (1988)
La fuga – Girl in Flight [HD] (2016)
Lo studente (1982)
I try to writes into a file called urls_estratti.txt only these urls extracted from html_di_test.txt
https://cb01.clinic/la-forza-dellamore-b-n-1936/
https://cb01.clinic/la-forza-della-volonta-hd-1988/
https://cb01.clinic/la-fuga-girl-in-flight-hd-2016/
but I get only this url
https://cb01.clinic/la-forza-della-volonta-hd-1988/
these urls are missing and I don't understand why
https://cb01.clinic/la-forza-dellamore-b-n-1936/
https://cb01.clinic/la-fuga-girl-in-flight-hd-2016/
This is the code that I'm trying to set
$films = Get-Content .\film_disponibili.txt
$html = Get-Content .\html_di_test.txt -Raw
$urls = foreach ($film in $films) {
$film_decoded = [System.Web.HttpUtility]::HtmlDecode($film)
$regex = '.*<a href="(https://cb01.clinic/.*)">' + [regex]::Escape($film_decoded) + '.*'
$match = [regex]::Match($html, $regex)
if ($match.Success) { $match.Groups[1].Value }
}
$urls | Set-Content .\urls_estratti.txt
Condition is this: if there is a string like La fuga - Girl in Flight into
La fuga – Girl in Flight [HD] (2016) `
script should be write this url: https://cb01.clinic/la-fuga-girl-in-flight-hd-2016/
But this doesn't totally happen, I saw that there is a problem with the accented characters, the apostrophe and the dash in the middle of the name, but I can't handle them completely
As stated in comments ’ is a smart quote and – is a en dash which don't match ' or - respectively hence your problem.
You could change your film_disponibili.txt file to the following:
La forza dell\p{P}amore
La forza della volontà
La fuga \p{P} Girl in Flight
Using \p{P} you can match any kind of punctuation character.
Then another take on solving this problem is using Htmlfile to parse html_di_test.txt.
Code would look as follows:
$toMatch = Get-Content .\film_disponibili.txt
$content = Get-Content .\html_di_test.txt -Raw
$html = New-Object -ComObject htmlfile
$html.write([System.Text.Encoding]::Unicode.GetBytes($content))
$predicate = [Func[object, bool]]{ $_.textContent -match $args[0] }
$html.getElementsByTagName('a') |
Where-Object { [Linq.Enumerable]::Any($toMatch, $predicate) } |
ForEach-Object href
And output would be:
https://cb01.clinic/la-forza-dellamore-b-n-1936/
https://cb01.clinic/la-forza-della-volonta-hd-1988/
https://cb01.clinic/la-fuga-girl-in-flight-hd-2016/

Automate a search for members of the local 'Administators' group

I have a PowerShell script named script1.ps1 that work perfectly. Here is the script:
Write-Host Script to display members of the local -ForegroundColor Green
Write-Host Administators group of a remote server. -ForegroundColor Green
Write-Host "`n"
$strComputer = Read-Host "Please enter the computer name"
$computer = [ADSI]("WinNT://" + $strComputer + ",computer")
$group = $computer.PSBase.Children.Find("administrators")
Write-Host ""
Write-Host "Computer Name : "$computer.Name
Write-Host "_____________________________________"
Write-Host ""
Write-Host "Group Name : "$Group.Name
Write-Host "_____________________________________"
$domain = $group.Path.Split("/")[2]
$string1 = "WinNT://" + $domain + "/" + $strComputer + "/"
$string2 = $strComputer + "/"
$string3 = "WinNT://"
$members = ($group.PSBase.Invoke("Members") | Foreach-Object {$_.GetType().InvokeMember("Adspath", 'GetProperty', $null, $_, $null)}) -replace ($string1,$string2) -replace ($string3,"")
Write-Host ""
Write-Host "Members : "
Write-Host ""
$members
But as you can see, I'm obliged to write each time the name of computer I want.
I ask myself if there is a function or other things which take automatically the computers names from a text or CSV file?
Like this at the beginning of the script, it automatically take all the computers names & give me the members of the local 'Administators' group which then gonna be exported in one text file or CSV file too?
Updated script according to the answer given.
Write-Host Script to display members of the local -ForegroundColor Green
Write-Host Administators group of a remote server. -ForegroundColor Green
Write-Host "`n"
Get-Content 'C:\Users\herbautr\Desktop\List1.txt' | ForEach-Object {
Write-Host "-$_-"
$computer = [ADSI]("WinNT://" + $_ + ",computer")
$group = $computer.PSBase.Children.Find("administrators")
Write-Host ""
Write-Host "Computer Name : "$computer.Name
Write-Host "_____________________________________"
Write-Host ""
Write-Host "Group Name : "$Group.Name
Write-Host "_____________________________________"
$domain = $group.Path.Split("/")[2]
$string1 = "WinNT://" + $domain + "/" + $_ + "/"
$string2 = $_ + "/"
$string3 = "WinNT://"
$members = ($group.PSBase.Invoke("Members") | Foreach-Object {$_.GetType().InvokeMember("Adspath", 'GetProperty', $null, $_, $null)}) -replace ($string1,$string2) -replace ($string3,"")
Write-Host ""
Write-Host "Members : "
Write-Host ""
$members
} | Set-Content 'C:\Users\herbautr\Desktop\administrators.txt'
I have add 1 computer name to the List1.txt:
01SPEAI-TEST1
01SPEAI-TEST2
02SPHPV-TEST1
01SLCPTAAP-PROD
And it works (not) perfectly (Unreadable layout)
01SPEAI-PROD1/Administrator
VNF-PRINCIPAL/Admins du domaine
VNF-PRINCIPAL/svceri
01SPEAI-PROD2/Administrator
VNF-PRINCIPAL/Admins du domaine
VNF-PRINCIPAL/svceri
02SPHPV-PROD1/Administrator
VNF-PRINCIPAL/Admins du domaine
01SLCPTAAP-PROD/Administrator
VNF-PRINCIPAL/Admins du domaine
01SLCPTAAP-PROD/maint
VNF-PRINCIPAL/svcoraas
VNF-PRINCIPAL/svcvisionit
VNF-PRINCIPAL/GopOAS
VNF-PRINCIPAL/svcdigora
Note (15:18pm): I have tried with 5 names, it continue to work.
Why when adding just 1 name it "works"?
You're looking for Get-Content and Set-Content.
Get-Content 'C:\path\to\computers.txt' | ForEach-Object {
$computer = [ADSI]("WinNT://" + $_ + ",computer")
...
} | Set-Content 'C:\path\to\administrators.txt'
Note that you need to replace all occurrences of $strComputer inside the ForEach-Object loop with the current object automatic variable ($_).
If you want to use CSVs for input and output use the Import-Csv and Export-Csv cmdlets.
Import-Csv 'C:\path\to\computers.csv' | ForEach-Object {
$computer = [ADSI]("WinNT://" + $_.ComputerName + ",computer")
...
$members | ForEach-Object {
New-Object -Type PSObject -Property #{
Member = $_
}
}
} | Export-Csv 'C:\path\to\administrators.csv' -NoType
Note that CSVs have some advantages when you need to handle items with multiple properties, but they require somewhat more elaborate handling than simple strings (as you can see in my example above).

Powershell log tailer issues

I have written a log tailer with Powershell, the tailer loads in an xml file which contains configuration information regarding when to report on a word match in the log tail (basically if certain patterns occur X amount of times in the tail).
At the moment the tailer is not returning matches for many of the lines that contain matches.
For example we are retrieving a log file with many INFO lines, if I check for the word INFO nothing is detected, however if I look for the work shutdown it returns matches (the line with shutdown also contains INFO on the line).
The really strange thing is that using the same log file and same Powershell script seems to produce perfectly accurate results on my own machine but behaves strangely on the server.
I suspect that this might be an issue with the version of Powershell that is running on the server, so I was hoping someone here might know of issues that can come up with different versions. I have also noticed that when I print out the number of matches, if nothing is found the output is blank, perhaps this should be 0 and is causing some weird issue to trigger?
function Main()
{
#### GLOBAL SETTINGS
$DebugPreference = "Continue"
$serverName = $env:COMPUTERNAME
$scriptPath = Split-Path $script:MyInvocation.MyCommand.Path
$logConfigPath = "$scriptPath/config.xml"
#### VARIABLES RELATING TO THE LOG FILE
#contains the log path and log file mask
$logPaths = #()
$logFileMasks = #()
# the total number of lines grabbed from the end of the log file for evaluation
$numLinesToTail = 1000
# key value pair for the strings to match and the max count of matches before they are considered an issue
$keywords = #()
$maxCounts = #()
#### VARIABLES RELATING TO THE EMAIL SETTINGS
$smtpServer = "mail server"
$emailSubject = "$serverName log report"
$toEmailAddress = "email accounts"
$fromEmailAddress = ""
# any initial content you want in the email body should go here (e.g. the name of the server that this is on)
$htmlBodyContent = "<p><h3>SERVER $serverName : </h3></p><p>Items that appear in red have exceeded their match threshold and should be investigated.<br/>Tail Lines: $numLinesToTail</p>"
#### FUNCTION CALLS
LoadLogTailerConfig $logConfigPath ([ref]$logPaths) ([ref]$logFileMasks) ([ref]$keywords) ([ref]$maxCounts)
for ($i = 0; $i -lt $logPaths.Count; $i++)
{
$tail = GetLogTail $numLinesToTail $logPaths[$i] $logFileMasks[$i]
$tailIssueTable = CheckForKeywords $tail $keywords[$i] $maxCounts[$i]
if ($tailIssueTable -ne "")
{
$htmlBodyContent += "<br/>Logs scanned: " + (GetLatestLogFileFullName $logPaths[$i] $logFileMasks[$i]) + "<br/><br/>" + $tailIssueTable
SendIssueEmail $smtpServer $emailSubject $toEmailAddress $ccEmailAddress $fromEmailAddress $htmlBodyContent
}
}
}
# Loads in configuration data for the utility to use
function LoadLogTailerConfig($logConfigPath, [ref]$logPaths, [ref]$logFileMasks, [ref]$keywords, [ref]$maxCounts)
{
Write-Debug "Loading config file data from $logConfigPath"
[xml]$configData = Get-Content $logConfigPath
foreach ($log in $configData.Logs.Log) {
$logPaths.Value += $log.FilePath
$logFileMasks.Value += $log.FileMask
$kwp = #()
$kwc = #()
foreach ($keywordSet in $log.Keywords.Keyword)
{
$kwp += $keywordSet.Pattern
$kwc += $keywordSet.MaxMatches
}
$keywords.Value += #(,$kwp)
$maxCounts.Value += #(,$kwc)
}
}
# Gets a string containing the last X lines of the most recent log file
function GetLogTail($numLinesToTail, $logPath, $logFileMask)
{
$logFile = GetLatestLogFileFullName $logPath $logFileMask #Get-ChildItem $logPath -Filter $logFileMask | sort LastWriteTime | select -Last 1
Write-Debug "Getting $numLinesToTail line tail of $logFile"
$tail = Get-Content "$logFile" | select -Last $numLinesToTail
return $tail
}
function GetLatestLogFileFullName($logPath, $logFileMask)
{
$logFile = Get-ChildItem $logPath -Filter $logFileMask | sort LastWriteTime | select -Last 1
return "$logPath$logFile"
}
# Returns body text for email containing details on keywords in the log file and their frequency
function CheckForKeywords($tail, $keywords, $maxCounts)
{
$issuesFound = 0
$htmlBodyContent += "<table><tr><th style=""text-align : left;"">Keyword</th><th>Max Count Value</th><th>Count Total<th></tr>"
for ($i = 0; $i -lt $keywords.Count; $i++)
{
$keywordCount = ($tail | Select-String $keywords[$i] -AllMatches).Matches.Count
Write-Debug (("Match count for {0} : {1}" -f $keywords[$i], $keywordCount))
if ($keywordCount -gt $maxCounts[$i])
{
# style red if the count threshold has been exceeded
$htmlBodyContent += "<tr style=""color : red;""><td>" + $keywords[$i] + "</td><td>" + $maxCounts[$i] + "</td><td>" + $keywordCount + "</td></tr>"
$issuesFound = 1
}
else
{
# style green if the count threshold has not been exceeded
$htmlBodyContent += "<tr style=""color : green;""><td>" + $keywords[$i] + "</td><td>" + $maxCounts[$i] + "</td><td>" + $keywordCount + "</td></tr>"
}
}
$htmlBodyContent += "</table>"
if ($issuesFound -eq 1)
{
return $htmlBodyContent
}
return ""
}
# Sends out an email to the specified email address
function SendIssueEmail($smtpServer, $subject, $toAddress, $ccAddress, $fromAddress, $bodyContent)
{
Write-Debug "Sending email with subject: $subject, To: $toAddress, via SMTP ($smtpServer)"
Send-MailMessage -SmtpServer $smtpServer -Subject $subject -To $toAddress -From $fromAddress -BodyAsHtml $bodyContent
}
cls
Main
And a XML config example:
<Logs>
<Log>
<FilePath>C:/Some/Path</FilePath>
<FileMask>log.*</FileMask>
<Keywords>
<Keyword>
<Pattern>NullReferenceException</Pattern>
<MaxMatches>10</MaxMatches>
</Keyword>
<Keyword>
<Pattern>Exception</Pattern>
<MaxMatches>10</MaxMatches>
</Keyword>
</Keywords>
</Log>
<Log>
<FilePath>C:/Some/Path</FilePath>
<FileMask>test.*</FileMask>
<Keywords>
<Keyword>
<Pattern>NullReferenceException</Pattern>
<MaxMatches>100</MaxMatches>
</Keyword>
</Keywords>
</Log>
</Logs>
EDIT : The server that is having the issues is running Powershell V 1.0, however the test servers are also running the same version perfectly fine...
Your function GetLatestLogFileFullName is one problem. It can and will generate invalid paths.
function GetLatestLogFileFullName($logPath, $logFileMask)
{
$logFile = Get-ChildItem $logPath -Filter $logFileMask | sort LastWriteTime | select -Last 1
return "$logPath$logFile"
}
Use this instead:
return $logfile.FullName
And you should also check for cases where there is no valid log file:
if ($logfile) {
return $logfile.FullName
} else {
return $null
}
The second problem will be your Select-String usage.
$keywordCount = ($tail | Select-String $keywords[$i] -AllMatches).Matches.Count
In PowerShell v1 Select-String does not have -AllMatches parameter.
PS> Get-Help Select-String
NAME
Select-String
SYNOPSIS
Identifies patterns in strings.
SYNTAX
Select-String [-pattern] <string[]> -inputObject <psobject>[-include <string[]>] [-exclude <string[]>] [-simpleMatch] [-caseSensitive] [-quiet] [-list] [<CommonParameters>]
Select-String [-pattern] <string[]> [-path] <string[]> [-include<string[]>] [-exclude <string[]>] [-simpleMatch] [-caseSensitive] [-quiet] [-list] [<CommonParameters>]
Check the PowerShell versions on your servers using the $PSVersionTable variable. Do not rely on the version displayed in the title bar!
If the variable does not exist you have Version 1.

Move-Item Counter

I have amended this to a more simpler explanation below and removed my previous version
Good Afternoon
i was wondering if anyone could advise
Each day we have alogfile which bears the current date, eg 22012013.txt, 23012013.txt etc
I have a move item cmdlet in my script, i would like to record how many files have been moved to 3 specific folders each day and writing the counter to the dated text log mentioned above
Pretend this is my folder structure
folder1
folder2
folder3
As an example, here is how my move-item would work
my move item moves file1.txt to folder1
file2 to folder3
file3 to folder1
file4 to folder3
file5 to folder2
file6 to folder1
In the log file, i would like to see
Items moved to Folder1 = 3
Items moved to Folder2 = 1
Items moved to Folder3 = 2
And that is it as the next day, that days file moves will be recorded in the new log file for that day, i would like the increment to go up for each move item if this is possible
Hope this makes sense
Regards
Barrie
Here is an example implementation of a function which moves a file and then updates a log.
No doubt it could be more concise, but it gets the job done and is reasonably readable.
The first argument is the file to be moved, the second is the name of the destination folder (it must not contain whitespace).
Basically, after moving the file to the specified folder, the last line of the log file is grabbed and checked to see if it contains today's date. If it does, the line is split on whitespace and the resulting array is iterated to find the folder name. If found, the next item of the array, which will be the number of moves made to that folder, is incremented by one. If not found, the folder name is appended to the line. The amended line then replaces the last line in the file. If the last line of the log file does not contain today's date a line is appended to the file with today's date and the folder name etc.
#() is used to ensure that the enclosed expression returns an array - it makes it easier to add content to the file as proper lines.
function Log-Move() {
$logfile = 'O:\AutoScan\log.txt'
$destination = 'O:\AutoScan\'
$folder = $args[1]
Move-Item -ErrorAction Stop $args[0] ( $destination + $folder )
$content = #( get-content -path $logfile )
$line = $content[-1]
$date = Get-Date -format 'd'
if ( $line ) {
if ( $line.Contains( $date ) ) {
$items = $line.split()
$count = $items.count
for ( $i = 0; $i -lt $count; $i++ ) {
if ( $items[$i] -eq $folder ) {
$items[$i + 1] = 1 + $items[$i + 1]
break
}
}
if ( $i -eq $count ) {
$items += #( $folder, '1' )
}
$line = $items -join ' '
if ( $content.length -gt 1 ) {
$content = #( $content[0..$($content.length-2)] ) + $line
} else {
$content = #( $line )
}
} else {
$content += $date + ' ' + $folder + ' 1'
}
} else {
$content = #( $date + ' ' + $folder + ' 1' )
}
$content | Set-Content -path $logfile
}
Example usage
Log-Move $newLongFilename Multiples
# log.txt:
# 22/01/2013 Multiples 1
Log-Move $anotherfile Multiples
Log-Move $anotherfile Autosorting
# 22/01/2013 Multiples 2 Autosorting 1

Powershell advanced regex to select from file

I would like to search for a pattern in a file which I can do easily with something like:
gc $filename | select-string $pattern
However once I have found this first pattern, using the location (line) of the first match as a starting point I would then like to start searching for a second pattern. Once the second pattern has been matched I would then like to return all lines between the first and second matches, discarding the matched lines themselves.
Let's say your first pattern is pattern1 and the second pattern is pattern2
then expression would be (?<=pattern1)(.*?)(?=pattern2)
(?<=pattern1) - this will match prefix pattern but exclude it from capture
(?=pattern2) - this will match suffix pattern but exclude it from capture
There may be a more elegant way but this will work
function ParseFile
{
param([string] $FileName)
$s = gc $FileName;
for($x = 0 ; $X -lt $s.count; $x++)
{
if(-not $first ){
if($s[$x] -match "1000"){
$first =$x
}
}
else{
if($s[$x] -match "1075"){
$second = $x ;
break;
}
}
}
(($first +1) .. ($second -1))|%{
$ret += $s[$_]
}
return $ret;
}
I've used foreach with $foreach.Movenext():
foreach ($line in (Get-Content $file))
{
if ($line -match $firstTag)
{
do {
$line
$foreach.MoveNext()
} until ($foreach.current -match $secondTag)
continue
}
}
This will simply return each line one by one, but you can do what you like within the do-loop if you need to process the result in some way
Here is my one (a french bricolage ;o) ), imagine the file c:\temp\gorille.txt :
C'est à travers de larges grilles,
Que les femelles du canton,
Contemplaient un puissant gorille,
Sans souci du qu'en-dira-t-on.
Avec impudeur, ces commères
Lorgnaient même un endroit précis
Que, rigoureusement ma mère
M'a défendu de nommer ici...
Gare au gorille !...
Here is the text between "canton" and "endroit"
PS > (((Get-Content -Path C:\temp\gorille.txt) -join "£" | Select-String -Pattern "(?=canton)(.*)(?<=endroit)").matches[0].groups[0].value) -split "£"
canton,
Contemplaient un puissant gorille,
Sans souci du qu'en-dira-t-on.
Avec impudeur, ces commères
Lorgnaient même un endroit
I join all the lines with a special character "£" (choose onather one if used) then use #Alex Aza pattern in CmdLet Select-String then split again.
$start = select-string -Path $path -pattern $pattern1 -list |
select -expand linenumber
$end = select-string -path $path -pattern $pattern2 |
where-object {$_.linenumber -gt $start} |
sort linenumber -desc |
select -first 1 -expand linenumber
(get-content $path)[$start..($end -2)]