I want to create a powershell script that will edit a config file (apache httpd.conf) and if I find
#keyword
some data
#keyword
the I replace the data between the #keyword else I add the #keywords with the data.
Can someone give me some help
Thank you
$fileName = "..\..\apache\conf\extra\httpd-vhosts.conf"
$found = $false
$contains = $false
$kw = "##xceed.localhost"
$text = "A
BBBB
C"
(Get-Content ( $fileName )) |
Foreach-Object{
if($_ -match $kw)
{
if($found -eq $false)
{
$found=$true
}else
{
$found=$false
}
if($found -eq $true)
{
$contains=$true
#Add Lines after the selected pattern
$kw
$text
}
}
if($found -ne $true)
{
$_
}
} | Set-Content( $fileName )
if($contains -eq $false)
{
$value=($kw+"`r`n"+$text+"`r`n"+$kw)
Add-Content $fileName $value
}
Related
Both commands work when running inside Visual Studio Code but if I execute the ps1 file directly in pwsh 7 the file is blank. Same if I right-click and select Open With pwsh.
Tried both commands, out-file first but moved to [system.io.file]::WriteAllText to remove blank rows. Both successfully create and populate a csv file as expected when I execute it from within Visual Studio Code.
try {
$files = #()
$files = Get-ChildItem -Path "\\networkShare\ps1files"
#$files = $files + (get-childitem -Path "\\networkShare\ps1files2")
$results = foreach ($file in $files) {
if ($file.FullName.substring($file.FullName.length - 3, 3) -eq "ps1") {
#Write-Host $file
$scriptblock = [scriptblock]::Create((Get-Content -Raw -Path $file.FullName))
$ast = $scriptblock.Ast
$commands = $ast.FindAll( { $args[0] -is [System.Management.Automation.Language.CommandAst] }, $true)
$commandText = foreach ($command in $commands) {
$command.CommandElements[0].Extent.Text
}
$commandText |
Select-Object -Unique |
Sort-Object |
Select-Object #{
Label = "Module"
Expression = { (Get-Command $_).Source.Substring(0, (Get-Command $_).Source.Length) }
}
$value = ""
foreach ($result in $results) {
if ($result.Module -inotlike "C:*") {
if ($value -inotlike "*" + $result.Module + "*") {
$value = $value + $result.Module + "`n"
}
}
}
}
}
$ModulesInUse = #()
$NewModules = #()
$NewestMod = #()
#$NewestMod = ""
$ModulesInUse = Import-Csv \\networkShare\PSModulesUsed.csv -Header "Module"
$NewModules = $results.Where({ $_.module -notin $ModulesInUse.Module -and $_.Module.Length -gt 0 -and $_.Module -inotlike "C:*" })
if ($NewModules.count -gt 0) {
Write-Host "New Modules found `n"
# Create unique array of new modules found
foreach ( $mod in $NewModules ) {
if ($mod.Module -notin $NewestMod.Module) {
$NewestMod = $NewestMod + $mod
}
}
$NewestMod.module
Write-Host `n
$Prompt = 'Do you want to update the Modules Used csv file now? Y/N'
$UpdateFile = Read-Host -Prompt $Prompt
if ($UpdateFile -eq 'y') {
#$value | Out-File "\\networkShare\PSModulesUsed.csv"
[system.io.file]::WriteAllText(“\\networkShare\PSModulesUsed.csv”, $value)
}
}
else {
Read-Host "No new Modules found. Press any key to exit"
}
Big thanks to mklement0!!!
Making that change to Code revealed the $value I was sending was not correct, even though it was working before. When running outside of Code it was blank.
I moved the code below to outside the $Results block of code and it works now.
$value = ""
foreach ($result in $results) {
if ($result.Module -inotlike "C:*") {
if ($value -inotlike "*" + $result.Module + "*") {
$value = $value + $result.Module + "`n"
}
}
}
I'm trying to find a string and add the string needed for a program.
I need the code to look to see if the action = run fast already exists and if so do nothing.
$Input = GetContent "${Env:ProgramFiles}\myprogram\file.conf"
$replace = #"
[MyAction_Log]
action = run fast
"#
$Input -replace ('action = run fast') -replace ('\[MyAction_Log\]',$replace) | set-content "${Env:ProgramFiles}\myprogram\file.conf"
I would check before wantonly replacing things you think exist. Also, never use $Input as a variable name; it's an automatic variable and won't do what you think it will (treat it as read-only).
$path = "$Env:ProgramFiles\prog\file.conf"
$file = Get-Content -Path $path
$replacementString = #'
[MyAction_Log]
action = run fast
'#
if ($file -notmatch 'action\s=\srun\sfast')
{
$file -replace '\[MyAction_Log\]', $replacementString |
Set-Content -Path $path
}
An alternative that's able to cope with the action key being located anywhere in the [MyAction_Log] section
$Inside = $False
$Modified = $False
$Path = "$( $env:ProgramFiles )\prog\file.conf"
$NewLines = Get-Content $Path |
ForEach-Object {
if( $_.Trim() -like "[*]" ) { $Inside = $False }
if( $_.Trim() -like "*[MyAction_Log]*" ) { $Inside = $True }
If( $Inside -and $_ -like "action = *" -and $_ -notlike "*run fast*" ) { $Modified = $True; "action = run fast" } else { $_ }
}
If( $Modified ) { $NewLines | Set-Content $Path }
Sorry if you have seen this code but I did make some tweaks after I accepted the answer and got some interesting results and wasn't able to reopen previous thread for continuance.
My powershell seems to be running but the function calls are producing no result after $filestore in function execute. What is going on? Are my functions not reading the inputs due to lack of global variables?
$filestore = Import-Excel 'C:\594 Sample of Filestore.xlsx'
function Import-Excel
{
param (
[string]$FileName,
[string]$WorksheetName,
[bool]$DisplayProgress = $true
)
if ($FileName -eq "") {
throw "Please provide path to the Excel file"
Exit
}
if (-not (Test-Path $FileName)) {
throw "Path '$FileName' does not exist."
exit
}
$FileName = Resolve-Path $FileName
$excel = New-Object -com "Excel.Application"
$excel.Visible = $false
$workbook = $excel.workbooks.open($FileName)
if (-not $WorksheetName) {
Write-Warning "Defaulting to the first worksheet in workbook."
$sheet = $workbook.ActiveSheet
} else {
$sheet = $workbook.Sheets.Item($WorksheetName)
}
if (-not $sheet)
{
throw "Unable to open worksheet $WorksheetName"
exit
}
$sheetName = $sheet.Name
$columns = $sheet.UsedRange.Columns.Count
$lines = $sheet.UsedRange.Rows.Count
Write-Warning "Worksheet $sheetName contains $columns columns and $lines lines of data"
$fields = #()
for ($column = 1; $column -le $columns; $column ++) {
$fieldName = $sheet.Cells.Item.Invoke(1, $column).Value2
if ($fieldName -eq $null) {
$fieldName = "Column" + $column.ToString()
}
$fields += $fieldName
}
$line = 2
for ($line = 2; $line -le $lines; $line ++) {
$values = New-Object object[] $columns
for ($column = 1; $column -le $columns; $column++) {
$values[$column - 1] = $sheet.Cells.Item.Invoke($line, $column).Value2
}
$row = New-Object psobject
$fields | foreach-object -begin {$i = 0} -process {
$row | Add-Member -MemberType noteproperty -Name $fields[$i] -Value $values[$i]; $i++
}
$row
$percents = [math]::round((($line/$lines) * 100), 0)
if ($DisplayProgress) {
Write-Progress -Activity:"Importing from Excel file $FileName" -Status:"Imported $line of total $lines lines ($percents%)" -PercentComplete:$percents
}
}
$workbook.Close()
$excel.Quit()
}
function FindFiles {
param(
[string]$filestore
)
$length = $filestore.Length
$GuidArray = #()
for($line=0;$line -le $filestore.Count;$line++){
$check = $filestore[$line]
echo $check
$length2 = $check.Length
$fileGuid = $check | ForEach-Object{$_.FileGuid}
$GuidArray = $GuidArray + $fileGuid
}
write-host "-------------------------------------------------------------" -ForegroundColor Yellow
$filepath = Read-Host " Please Enter File Path to Search"
for ($counter=0;$counter -lt $GuidArray.Count;$counter++){
$fileArray = #()
$guidcheck = $GuidArray[$counter]
$file = Get-ChildItem -Recurse -Force $filePath -ErrorAction SilentlyContinue | Where-Object { ($_.PSIsContainer -eq $false) -and ( $_.Name -like "*$guidcheck*") } | Select-Object Directory,Name| Format-Table -AutoSize
$fileArray += $file
}
Write-Output $fileArray
}
function CopyFiles {
param(
[string]$fileArray
)
for ($counter = 0;$counter -lt $fileArrray.Count;$counter++){
echo $fileArray[$counter]
#Copy-Item
}
}
function execute {
$filestore = Import-Excel 'C:\594 Sample of Filestore.xlsx'
echo $filestore
$fileArray = #(FindFiles($fileArray))
echo "test"
echo $fileArray
#CopyFiles($fileArray)
}
At the end of FindFiles add this line:
Write-Output $GuidArray
This returns that variable to the standard output stream (the pipeline).
Similarily at the end of FindFiles2 you need to do:
Write-Output $fileArray
In the below code I am having trouble understanding why when I return FileArray why my other function is returning it as being empty?
I am looking to use copyfiles with FileArray. Am I just supposed to put all the steps into one huge function?
function Import-Excel
{
param (
[string]$FileName,
[string]$WorksheetName,
[bool]$DisplayProgress = $true
)
if ($FileName -eq "") {
throw "Please provide path to the Excel file"
Exit
}
if (-not (Test-Path $FileName)) {
throw "Path '$FileName' does not exist."
exit
}
$FileName = Resolve-Path $FileName
$excel = New-Object -com "Excel.Application"
$excel.Visible = $false
$workbook = $excel.workbooks.open($FileName)
if (-not $WorksheetName) {
Write-Warning "Defaulting to the first worksheet in workbook."
$sheet = $workbook.ActiveSheet
} else {
$sheet = $workbook.Sheets.Item($WorksheetName)
}
if (-not $sheet)
{
throw "Unable to open worksheet $WorksheetName"
exit
}
$sheetName = $sheet.Name
$columns = $sheet.UsedRange.Columns.Count
$lines = $sheet.UsedRange.Rows.Count
Write-Warning "Worksheet $sheetName contains $columns columns and $lines lines of data"
$fields = #()
for ($column = 1; $column -le $columns; $column ++) {
$fieldName = $sheet.Cells.Item.Invoke(1, $column).Value2
if ($fieldName -eq $null) {
$fieldName = "Column" + $column.ToString()
}
$fields += $fieldName
}
$line = 2
for ($line = 2; $line -le $lines; $line ++) {
$values = New-Object object[] $columns
for ($column = 1; $column -le $columns; $column++) {
$values[$column - 1] = $sheet.Cells.Item.Invoke($line, $column).Value2
}
$row = New-Object psobject
$fields | foreach-object -begin {$i = 0} -process {
$row | Add-Member -MemberType noteproperty -Name $fields[$i] -Value $values[$i]; $i++
}
$row
$percents = [math]::round((($line/$lines) * 100), 0)
if ($DisplayProgress) {
Write-Progress -Activity:"Importing from Excel file $FileName" -Status:"Imported $line of total $lines lines ($percents%)" -PercentComplete:$percents
}
}
$workbook.Close()
$excel.Quit()
}
function FindFiles {
param(
[string]$fiestore
)
$length = $filestore.Length
$GuidArray = #()
for($line=0;$line -le $filestore.Count;$line++){
$check = $filestore[$line]
$length2 = $check.Length
echo $check
$fileGuid = $check | ForEach-Object{$_.FileGuid}
$GuidArray = $GuidArray + $fileGuid
}
write-host "-------------------------------------------------------------" -ForegroundColor Yellow
$filepath = Read-Host " Please Enter File Path to Search"
for ($counter=0;$counter -lt $GuidArray.Count;$counter++){
$fileArray = #()
$guidcheck = $GuidArray[$counter]
echo $guidcheck
$file = Get-ChildItem -Recurse -Force $filePath -ErrorAction SilentlyContinue | Where-Object { ($_.PSIsContainer -eq $false) -and ( $_.Name -like "*$guidcheck*") } | Select-Object Directory,Name| Format-Table -AutoSize
$fileArray += $file
}
echo $fileArray
return $fileArray
}
function CopyFiles {
param(
[string]$filearray
)
echo $fileArray
for($counter = 0;$counter -lt $filearrray.Count;$counter++){
echo $filearray[$counter]
#Copy-Item
}
}
function execute {
$filestore = Import-Excel 'C:\594 Sample of Filestore.xlsx'
$fileArray = #()
FindFiles($filestore)
echo $fileArray
CopyFiles($fileArray)
}
$fileArray doesn't become available outside of the Function by doing Return, but you could make it accessible outside of the function by defining it with a Global scope (although this is not best practice): Return $Global:fileArray.
Instead, it becomes the value of the Function call itself, so in Execute you could do:
$filestore = Import-Excel 'C:\594 Sample of Filestore.xlsx'
$fileArray = #(FindFiles($filestore))
echo $fileArray
CopyFiles($fileArray)
However I think you also need to remove any echo statements from within the FindFiles function or they may be returned as well.
Note: This is untested code.
i have the following script but it does never end executing.
what could be the issue ? I tried to debug it but apparently it works correctly with a single file, but when I throw it against a folder full of content fails.
$path = split-path -parent $MyInvocation.MyCommand.Definition
$files = Get-ChildItem "$path\CodeForCertification\5_SourceCode\*" -Include *.c,*.h -Recurse | where{
! $_.PSIsContainer
}#$PSScriptRoot
ForEach ($file in $files){
$data = Get-Content -Path $file.FullName
$feature = Get-Content "$path\Disabled_Features.txt"
#[System.ArrayList]$Modifier
$nl=[Environment]::NewLine
$Modifier=#()
$flag=0
$data = $data | ForEach-Object -Begin {
$ignore = $false; $levels = 0
} -Process {
for($counter=0; $counter -lt $feature.Count; $counter++){
$parse = $feature[$counter]
if($_ -match "^#ifdef $parse" -And $flag -eq '0') {
$ignore = $true
$flag = 1;
}
}
if($ignore) {
if ($_ -match "^#ifdef") {
$levels++
}elseif ($_ -match "#endif") {
if($levels -ge 1) {
$levels--
if($levels -eq '0'){
$ignore = $false
}
}
}
}else {
$flag=0
$temp=$_
$_
$Modifier+="$temp"
}
}
$data | Out-File $file.FullName
}
OK, Jackson, let's solve your problem before you enter some kind of question spam filter ;-)
Consider this (just put it somewhere at the start of your script):
function RemoveUndesiredFeatures([string[]]$lines,[string[]]$undesiredFeatures)
{
$inIgnoreBlock = $false
$nestingLevel = 0
foreach ($line in $lines)
{
if ($inIgnoreBlock)
{
# Only search for nested blocks and end of block
if ($line -like "#ifdef*")
{
$nestingLevel++
}
elseif ($line -like "#endif*")
{
$nestingLevel--
}
if ($nestingLevel -eq 0)
{
$inIgnoreBlock = $false
}
}
else
{
# Search for undesired feature
$isIfdefMatch = $line -match "#ifdef (?<feature>\w+)"
if ($isIfdefMatch -and ($Matches.feature -in $undesiredFeatures))
{
# Ignore Feature
$inIgnoreBlock = $true
$nestingLevel++
}
else
{
# Output line
$line
}
}
}
}
Here is my example to use it:
$undesiredFeatures = #("F1","F2") # Just as example. Get-Content on a file with features is also fine
$files = Get-ChildItem *.c,*.h -Recurse # Again, just as example
foreach ($file in $files)
{
$lines = Get-Content $file.FullName
$changedLines = RemoveUndesiredFeatures $lines $undesiredFeatures
if ($changedLines.Count -ne $lines.Count)
{
# Features were removed. Write out changed file (to a different file to preserve my test files)
Set-Content -Value $changedLines -Path "$($file.FullName).changed"
}
}