Mirth Property File Corrupted on Editing using powershell - powershell

I am trying to edit the Mirth property file to add microsoft sql server driver url and class name using powershell. I am able to edit and save . When I start the Mirth services after editing, the Mirth property file is corrupted. But I reviewed both the original and the edited content. Everything is the same except the added changes and the file size is increased from 5kb to 10 kb. Can anyone help me out? Here is the powershell script.
$server="Localhost"
$PropertyfilePath = "C:\Program Files\Mirth Connect\conf\mirth.properties"
$connectionString = "jdbc:sqlserver://$($server):1433;instanceName=$($server);databaseName=Mydb;integratedSecurity=true"
$driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"
$data= #()
Copy-Item $PropertyfilePath "D:\Mirthbackup" -force
$newstreamreader = New-Object System.IO.StreamReader($PropertyfilePath)
[int]$eachlinenumber = 1
while (($readeachline = $newstreamreader.ReadLine()) -ne $null)
{
if($readeachline.Contains("= derby")){
$readeachline.Remove(0)
$update= "database = sqlserver"
$data +=$update
$eachlinenumber++
}
elseif($readeachline.Contains("database.url"))
{
$update=$readeachline.Substring(0,12)+" = "+$connectionString
$data +=$update
$eachlinenumber++
}
elseif($readeachline.Contains(".driver"))
{
$readeachline.Remove(0)
$update ="database.driver = "+$driverName
$data +=$update
$eachlinenumber++
}
else{
$data +=$readeachline
$eachlinenumber++
}
}
$newstreamreader.Dispose()
$data | Out-File -FilePath $PropertyfilePath

Your properties file should be ISO-8859-1 (latin1) encoded.
Try to change your code to:
$server="Localhost"
$PropertyfilePath = "C:\Program Files\Mirth Connect\conf\mirth.properties"
$connectionString = "jdbc:sqlserver://$($server):1433;instanceName=$($server);databaseName=Mydb;integratedSecurity=true"
$driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"
$data= #()
Copy-Item $PropertyfilePath "D:\Mirthbackup" -force
$encoding = [System.Text.Encoding]::GetEncoding('iso-8859-1'))
$newstreamreader = New-Object System.IO.StreamReader($PropertyfilePath, $encoding)
[int]$eachlinenumber = 1
while (($readeachline = $newstreamreader.ReadLine()) -ne $null)
{
# if statements left out
}
$newstreamreader.Dispose()
[System.IO.File]::WriteAllLines($PropertyfilePath,$data, $encoding)

Related

How to handle create a file and write it using Powershell?

I want to create a file and write content to the file.
The new file will create based on the total SWPO file exist. I tried this scirpt, I can create new file. But when I put only 1 $PO_Path file, it will create 2 new file. Actually those 2 file are the same but one of the file without $c. Like this
ID_ABC18XXR3CT123_.job
ID_ABC18XXR3CT123_AE.job
BUt if I put $PO_Path file more than 1, it works well.
Anyone can help me please. Thanks.
Function Create_OriJob
{
$BID = "18XXR3CT123"
$Job_Path = $Config_File.Automation_Config.Path.OriJob
$PO_Path = $Config_File.Automation_Config.Path.POfiles
if(Test-Path -Path "$PO_Path\*$BID*")
{
Write-Output "SWPO File Found"
# Start-Sleep -s 3
$PO_Content = Get-Content -path "$PO_Path\*$BID*"
$POfile = Get-ChildItem -Name "$PO_Path\*$BID*"
$Get_CRM = $PO_Content | Where-Object {$_ -like "*;CRM*"}
$CRM = $Get_CRM.Substring(5,2)
$CRM = $CRM.split()
$POCountry = Get-ChildItem -Name "$PO_Path"
$GetCountry = $POCountry.Substring(15,3)
$GetCountry = $GetCountry.split()
For($i = 0; $i -lt $POfile.Length; $i++){
try{
$po = $POfile[$i]
$c = $CRM[$i]
$cc = $GetCountry[$i]
New-Item -ItemType File -Path "$Job_Path\$JobType`_$Prefix$BID`_$c.job" -Force
$Title = $Config_File.Automation_Config.Out_Job.Title
$Auto = $Config_File.Automation_Config.Out_Job.Auto
$Proc = $Config_File.Automation_Config.Out_Job.Process
$Auto = $Config_File.Automation_Config.Out_Job.Auto
$PO_Conf = $Config_File.Automation_Config.Out_Job.PO
$BIDINFO = $Config_File.Automation_Config.Out_Job.BIDINFO
$BuildID = $Config_File.Automation_Config.Out_Job.BID
$PFX = $Config_File.Automation_Config.Out_Job.PFX
$CRM_Conf = $Config_File.Automation_Config.Out_Job.CRM
$CountryConf = $Config_File.Automation_Config.Out_Job.Country
$Platform = $Config_File.Automation_Config.Out_Job.Platform
$TSJobcreate = Get-Date
$Output_JOB = #"
<?xml version="1.0" encoding="UTF-8"?>
<$Title>
<$Auto>
<$Proc>$Auto</$Proc>
<$PO_Conf>$po</$PO_Conf>
</$Auto>
<$BIDINFO>
<$BuildID>$BID</$BuildID>
<$PFX>$Prefix</$PFX>
<$CRM_Conf>$c</$CRM_Conf>
<$CountryConf>$cc</$CountryConf>
</$BIDINFO>
<$Platform>
$All_SSID
</$Platform>
<Timestamp>
<JobCreate>$TSJobcreate</JobCreate>
</Timestamp>
</$Title>
"#
$Output_JOB | Out-File "$Job_Path\$JobType`_$Prefix$BID`_$c.job" -NoNewline
Write-Host "Output"
}
catch{
Write-Output "Something wrong!"
}
}
Write-Output "Continue to create operational job"
Create_OpJob
}
else{
Write-Host "SWPO Not Found, Do Error checking file"
Error_Monitoring
}
#Error_Monitoring
}

Windows Power Shell rename files

I am sort of new to scripting and here's my task:
A folder with X files. Each file contains some Word documents, Excel sheets, etc. In these files, there is a client name and I need to assign an ID number.
This change will affect all the files in this folder that contain this client's name.
How can do this using Windows Power Shell?
$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace " JOHN ", "123" } |
Set-Content $file.PSPath
}
Is this the right approach ?
As #lee_Daily pointed out you would need to have different code to perform a find and replace in different file types. Here is an example of how you could go about doing that:
$objWord = New-Object -comobject Word.Application
$objWord.Visible = $false
foreach ( $file in (Get-ChildItem . -r ) ) {
Switch ( $file.Extension ) {
".config" {
(Get-Content $file.FullName) |
Foreach-Object { $_ -replace " JOHN ", "123" } |
Set-Content $file.FullName
}
{('.doc') -or ('.docx')} {
### Replace in word document using $file.fullname as the target
}
{'.xlsx'} {
### Replace in spreadsheet using $file.fullname as the target
}
}
}
For the actual code to perform the find and replace, i would suggest com objects for both.
Example of word find and replace https://codereview.stackexchange.com/questions/174455/powershell-script-to-find-and-replace-in-word-document-including-header-footer
Example of excel find and replace Search & Replace in Excel without looping?
I would suggest learning the ImportExcel module too, it is a great tool which i use a lot.
For Word Document : This is what I'm using. Just can't figure out how this script could also change Header and Footer in a Word Document
$objWord = New-Object -comobject Word.Application
$objWord.Visible = $false
$list = Get-ChildItem "C:\Users\*.*" -Include *.doc*
foreach($item in $list){
$objDoc = $objWord.Documents.Open($item.FullName,$true)
$objSelection = $objWord.Selection
$wdFindContinue = 1
$FindText = " BLAH "
$MatchCase = $False
$MatchWholeWord = $true
$MatchWildcards = $False
$MatchSoundsLike = $False
$MatchAllWordForms = $False
$Forward = $True
$Wrap = $wdFindContinue
$Format = $False
$wdReplaceNone = 0
$ReplaceWith = "help "
$wdFindContinue = 1
$ReplaceAll = 2
$a = $objSelection.Find.Execute($FindText,$MatchCase,$MatchWholeWord, `
$MatchWildcards,$MatchSoundsLike,$MatchAllWordForms,$Forward,`
$Wrap,$Format,$ReplaceWith,$ReplaceAll)
$objDoc.Save()
$objDoc.Close()
}
$objWord.Quit()
What If I try to run on C# ? Is anything else missing?
}
string rootfolder = #"C:\Temp";
string[] files = Directory.GetFiles(rootfolder, "*.*",SearchOption.AllDirectories);
foreach (string file in files)
{ try
{ string contents = File.ReadAllText(file);
contents = contents.Replace(#"Text to find", #"Replacement text");
// Make files writable
File.SetAttributes(file, FileAttributes.Normal);
File.WriteAllText(file, contents);
}
catch (Exception ex)
{ Console.WriteLine(ex.Message);
}
}

SharePoint 2013 Powershell - Copy File From One Site Collection To Another

Please can someone assist in helping with the above subject?
I would like to copy one file from a specific folder in a sharepoint site collection to another library (of the same name) in a different sharepoint site collection (but still within the same Web Application).
I have very little Powershell experience and have tried a number of Google searches but cannot seem to find anything that works.
Below is an example of what i have tried to do (lots of Write-Host to try and figure out what is going on) with the error message at the bottom.
Add-PSSnapIn "Microsoft.SharePoint.PowerShell"
##
#Set Static Variables
##
$SourceWebURL = "http://WebAppURL/sites/Area/Master"
$SourceLibraryTitle = "Web"
$DestinationWebURL = "http://WebAppURL/sites/OtherSiteName"
$DestinationLibraryTitle = "Web"
$FileName = "Resources.aspx"
##
#Begin Script
##
$sWeb = Get-SPWeb $SourceWebURL
$sList = $sWeb.Lists | ? {$_.Title -eq $SourceLibraryTitle}
$dWeb = Get-SPWeb $DestinationWebURL
$dList = $dWeb.Lists | ? {$_.title -like $DestinationLibraryTitle}
$DestFolder = $dList.Files
$RootFolder = $sList.RootFolder
Write-Host " line 25 -- " $RootFolder
$collfiles1 = $RootFolder.Files
Write-Host " line 27 -- "$collfiles1
Write-Host " line 28 -- "$DestFolder
Write-Host " line 30 -- "$str = $DestinationWebURL"/"$DestinationLibraryTitle"/"$FileName
Write-Host " line 31 -- "$collfiles1.Count
for($i = 0 ; $i -lt $collfiles1.Count ; $i++)
{
Write-Host " line 34 -- "$collfiles1[$i].Name
##Write-Host $FileName
if($collfiles1[$i].Name -eq $FileName)
{
## $str = $DestinationWebURL.Url + $DestinationLibraryTitle + "/" + $FileName
$str = $DestinationWebURL+"/" +$DestinationLibraryTitle+"/"
Write-Host " line 40 -- "$str
Write-Host " line 41 -- "$collfiles1[$i]
$FiletoCopy = $collfiles1[$i].Name
Write-Host " line 43 -- " $FiletoCopy
$FiletoCopy.CopyTo($str,$true)
}
}
Write-Host "Script Completed"
The below example gives the error
Cannot find an overload for "CopyTo" and the argument count: "2".
At line:44 char:3
+ $FiletoCopy.CopyTo($str,$true)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
If someone could point me in the right direction that would be very helpful.
Thanks in advance,
Ian.
The following PowerShell for your reference, copy a file from one library in site collection to another library in another site collection with fields.
Add-PSSnapIn "Microsoft.SharePoint.PowerShell"
##
#Set Static Variables
##
$SourceWebURL = "http://WebAppURL/sites/Area/Master"
$SourceLibraryTitle = "Web"
$DestinationWebURL = "http://WebAppURL/sites/OtherSiteName"
$DestinationLibraryTitle = "Web"
$FileName = "Resources.aspx"
##
#Begin Script
##
$sWeb = Get-SPWeb $SourceWebURL
#$sList = $sWeb.Lists | ? {$_.Title -eq $SourceLibraryTitle}
$dWeb = Get-SPWeb $DestinationWebURL
#$dList = $dWeb.Lists | ? {$_.title -like $DestinationLibraryTitle}
$SourceFile=$sWeb.GetFile($SourceWebURL+"/"+$SourceLibraryTitle+"/"+$FileName)
$TargetFolder = $dWeb.GetFolder($DestinationLibraryTitle)
#Copy File from the Source
$NewFile = $TargetFolder.Files.Add($SourceFile.Name, $SourceFile.OpenBinary(),$True)
#Copy Meta-Data from Source
Foreach($Field in $SourceFile.Item.Fields)
{
If(!$Field.ReadOnlyField)
{
if($NewFile.Item.Fields.ContainsField($Field.InternalName))
{
$NewFile.Item[$Field.InternalName] = $SourceFile.Item[$Field.InternalName]
}
}
}
#Update
$NewFile.Item.UpdateOverwriteVersion()
Write-host "Copied File:"$SourceFile.Name
Reference: Copy Files Between Document Libraries in SharePoint using PowerShell
So in case of large files where file size is greater than 50MB. This script mentioned by #LZ_MSFT will never be able to copy that file may be. In that aspect, you need to chunk the file into small pieces.Here is the PS to copy from source to destination with chunking if file size is greater than 50MB. Plus point for this one script is, it is using Client so it can be used with SP online and on-prem.
Add-Type –Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type –Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
Function UploadFileInSlice ($DestinationCtx, $SourceCtx, $SourceFileUrl, $DestinationFolderUrl, $fileName, $fileChunkSizeInMB) {
# Each sliced upload requires a unique ID.
$UploadId = [GUID]::NewGuid()
# Get File by Server Relative URL
$File = $SourceCtx.Web.GetFileByServerRelativeUrl($SourceFileUrl)
$SourceCtx.Load($File)
# Get file Steam with OpenBinarySteam
$StreamToUpload = $File.OpenBinaryStream()
$SourceCtx.ExecuteQuery()
# File size in bytes
$FileSize = ($File).length
# Get Destination Folder by Server Relative URL
$DestinationFolder =
$DestinationContext.Web.GetFolderByServerRelativeUrl($DestinationFolderUrl)
$DestinationCtx.Load($DestinationFolder)
$DestinationCtx.ExecuteQuery()
# Set Complete Destination URL with Destination Folder + FileName
$destUrl = $DestinationFolderUrl + "/" + $fileName
# File object.
[Microsoft.SharePoint.Client.File] $upload
# Calculate block size in bytes.
$BlockSize = $fileChunkSizeInMB * 1000 * 1000
Write-Host "File Size is: $FileSize bytes and Chunking Size is:$BlockSize bytes"
if ($FileSize -le $BlockSize)
{
# Use regular approach if file size less than BlockSize
Write-Host "File uploading with out chunking"
$upload =[Microsoft.SharePoint.Client.File]::SaveBinaryDirect($DestinationCtx, $destUrl, $StreamToUpload.Value, $true)
return $upload
}
else
{
# Use large file upload approach.
$BytesUploaded = $null
$Fs = $null
Try {
$br = New-Object System.IO.BinaryReader($StreamToUpload.Value)
#$br = New-Object System.IO.BinaryReader($Fs)
$buffer = New-Object System.Byte[]($BlockSize)
$lastBuffer = $null
$fileoffset = 0
$totalBytesRead = 0
$bytesRead
$first = $true
$last = $false
# Read data from file system in blocks.
while(($bytesRead = $br.Read($buffer, 0, $buffer.Length)) -gt 0) {
$totalBytesRead = $totalBytesRead + $bytesRead
# You've reached the end of the file.
if($totalBytesRead -eq $FileSize) {
$last = $true
# Copy to a new buffer that has the correct size.
$lastBuffer = New-Object System.Byte[]($bytesRead)
[array]::Copy($buffer, 0, $lastBuffer, 0, $bytesRead)
}
If($first)
{
$ContentStream = New-Object System.IO.MemoryStream
# Add an empty file.
$fileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$fileCreationInfo.ContentStream = $ContentStream
$fileCreationInfo.Url = $fileName
$fileCreationInfo.Overwrite = $true
#Add file to Destination Folder with file creation info
$Upload = $DestinationFolder.Files.Add($fileCreationInfo)
$DestinationCtx.Load($Upload)
# Start upload by uploading the first slice.
$s = New-Object System.IO.MemoryStream(,$Buffer)
Write-Host "Uploading id is:"+$UploadId
# Call the start upload method on the first slice.
$BytesUploaded = $Upload.StartUpload($UploadId, $s)
$DestinationCtx.ExecuteQuery()
# fileoffset is the pointer where the next slice will be added.
$fileoffset = $BytesUploaded.Value
Write-Host "First patch of file with bytes"+ $fileoffset
# You can only start the upload once.
$first = $false
}
Else
{
# Get a reference to your file.
$Upload = $DestinationCtx.Web.GetFileByServerRelativeUrl($destUrl);
If($last) {
# Is this the last slice of data?
$s = New-Object System.IO.MemoryStream(,$lastBuffer)
# End sliced upload by calling FinishUpload.
$Upload = $Upload.FinishUpload($UploadId, $fileoffset, $s)
$DestinationCtx.ExecuteQuery()
Write-Host "File Upload Completed Successfully!"
# Return the file object for the uploaded file.
return $Upload
}
else {
$s = New-Object System.IO.MemoryStream(,$buffer)
# Continue sliced upload.
$BytesUploaded = $Upload.ContinueUpload($UploadId, $fileoffset, $s)
$DestinationCtx.ExecuteQuery()
# Update fileoffset for the next slice.
$fileoffset = $BytesUploaded.Value
Write-Host "File uploading is in progress with bytes: "+ $fileoffset
}
}
} #// while ((bytesRead = br.Read(buffer, 0, buffer.Length)) > 0)
}
Catch {
Write-Host $_.Exception.Message -ForegroundColor Red
}
Finally {
if ($Fs -ne $null)
{
$Fs.Dispose()
}
}
}
return $null
}
#URL to Configure, in this case Destination is SP Online site URL
#Adding up credentials hard-code, you can use Get-Credentails PS command too
$DestnationSiteUrl = "https://your-domain.sharepoint.com/sites/xyz"
$DestinationRelativeURL = "/sites/xyz/TestLibrary" #server relative URL here with library Name and Folder name
$DestinationUserName = "xyz#your-domain.com"
$DestinationPassword = Read-Host "Enter Password for Destination User:
$DestinationUserName" -AsSecureString
#URL to Configure, in this case Source is On-Prem site URL
#Adding up credentials hard-code, you can use Get-Credentails PS command too
$SourceSiteUrl = "http://intranet/sites/xyz"
$SourceRelativeURL = "/sites/xyz/TestLibrary/myfile.pptx" #server relative URL here with library Name and file name with extension
$SourceUsername = "domain\xyz"
$SourcePassword = Read-Host "Enter Password for Source User: $SourceUsername" -AsSecureString
#Set a file name with extension
$FileNameWithExt = "myfile.pptx"
#Get Source Client Context with credentials
$SourceContext = New-Object Microsoft.SharePoint.Client.ClientContext($SourceSiteUrl)
#Using NetworkCredentials in case of On-Prem
$SourceCtxcredentials = New-Object System.Net.NetworkCredential($SourceUsername, $SourcePassword)
$SourceContext.RequestTimeout = [System.Threading.Timeout]::Infinite
$SourceContext.ExecuteQuery();
#Get Destination Client Context with credentials
$DestinationContext = New-Object Microsoft.SharePoint.Client.ClientContext($DestnationSiteUrl)
#Using SharePointOnlineCredentials in case of SP-Online
$DestinationContext.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($DestinationUserName, $DestinationPassword)
$DestinationContext.RequestTimeout = [System.Threading.Timeout]::Infinite
$DestinationContext.ExecuteQuery();
#All Set up, now just call the UploadFileInSlice with parameters
$UpFile = UploadFileInSlice -DestinationCtx $DestinationContext -SourceCtx $SourceContext -DestinationFolderUrl $DestinationRelativeURL -SourceFileUrl $SourceRelativeURL -fileName $FileNameWithExt -fileChunkSizeInMB 10

Unable to convert .xlsx to .csv through Power shell in windows server 2012

I have created below function in Powershell to convert an .xlsx file into .csv ,the script is running in windows server 2012 machine.The script is getting complete without any error but it not doing the conversion.When same script I have tried in win 10 machine its working perfectly.Can you please confirm how to fix this issue.Is it due to server OS as excel is not installed in it ?
function xlsx_to_csv($xlinput,$csvout) {
$excel = New-Object -ComObject excel.application
$excel.DisplayAlerts = $false
$Workbook = $excel.Workbooks.Open("$xlinput")
$Workbook.SaveAs("$csvout",6)
$excel.Quit()
}
xlsx_to_csv $yest_xl_in $yest_csv_in
$yest_xl_in and $yest_csv_in are the xlsx and csv file locations.
Here is a more elegant function to convert an XLSX file into a csv. I have been using it for quite some time now and it has never let me down, yet! :)
function Get-ExcelData {
[CmdletBinding(DefaultParameterSetName='Worksheet')]
Param(
[Parameter(Mandatory=$true, Position=0)]
[String] $Path,
[Parameter(Position=1, ParameterSetName='Worksheet')]
[String] $WorksheetName = 'Sheet1',
[Parameter(Position=1, ParameterSetName='Query')]
[String] $Query = 'SELECT * FROM [Sheet1$]'
)
switch ($pscmdlet.ParameterSetName) {
'Worksheet' {
$Query = 'SELECT * FROM [{0}$]' -f $WorksheetName
break
}
'Query' {
# Make sure the query is in the correct syntax (e.g. 'SELECT * FROM [SheetName$]')
$Pattern = '.*from\b\s*(?<Table>\w+).*'
if($Query -match $Pattern) {
$Query = $Query -replace $Matches.Table, ('[{0}$]' -f $Matches.Table)
}
}
}
# Create the scriptblock to run in a job
$JobCode = {
Param($Path, $Query)
# Check if the file is XLS or XLSX
if ((Get-Item -Path $Path).Extension -eq 'xls') {
$Provider = 'Microsoft.Jet.OLEDB.4.0'
$ExtendedProperties = 'Excel 8.0;HDR=YES;IMEX=1'
} else {
$Provider = 'Microsoft.ACE.OLEDB.12.0'
$ExtendedProperties = 'Excel 12.0;HDR=YES'
}
# Build the connection string and connection object
$ConnectionString = 'Provider={0};Data Source={1};Extended Properties="{2}"' -f $Provider, $Path, $ExtendedProperties
$Connection = New-Object System.Data.OleDb.OleDbConnection $ConnectionString
try {
# Open the connection to the file, and fill the datatable
$Connection.Open()
$Adapter = New-Object -TypeName System.Data.OleDb.OleDbDataAdapter $Query, $Connection
$DataTable = New-Object System.Data.DataTable
$Adapter.Fill($DataTable) | Out-Null
}
catch {
# something went wrong ??
Write-Error $_.Exception.Message
}
finally {
# Close the connection
if ($Connection.State -eq 'Open') {
$Connection.Close()
}
}
# Return the results as an array
return ,$DataTable
}
# Run the code in a 32bit job, since the provider is 32bit only
$job = Start-Job $JobCode -RunAs32 -ArgumentList $Path, $Query
$job | Wait-Job | Receive-Job
Remove-Job $job
}
Now to get your csv file, you can simply do -
$csvfile = Get-ExcelData -Path 'PathToYourExcelFile\YourExcelFile.xlsx'
$csvfile | Export-Csv -path $env:USERPROFILE\Desktop\CsvFileName.csv -NoTypeInformation #Save the csv file on your Desktop

Unable to read an open file with binary reader

I have this function to read the SQL Server errorlog but the problem is that I'm not able to read the errorlog that the server is using at the time. I have been google-ing and it seems that the Fileshare flag isn't working for powershell. Is there some way to set the the Fileshare flag when I try to open the file?
function check_logs{
param($logs)
$pos
foreach($log in $logpos){
if($log.host -eq $logs.host){
$currentLog = $log
break
}
}
if($currentLog -eq $null){
$currentLog = #{}
$logpos.Add($currentLog)
$currentLog.host = $logs.host
$currentLog.event = $logs.type
$currentLog.lastpos = 0
}
$path = $logs.file
if($currentLog.lastpos -ne $null){$pos = $currentLog.lastpos}
else{$pos = 0}
if($logs.enc -eq $null){$br = New-Object System.IO.BinaryReader([System.IO.File]::Open($path, [System.IO.FileMode]::Open))}
else{
$encoding = $logs.enc.toUpper().Replace('-','')
if($encoding -eq 'UTF16'){$encoding = 'Unicode'}
$br = New-Object System.IO.BinaryReader([System.IO.File]::Open($path, [System.IO.FileMode]::Open), [System.Text.Encoding]::$encoding)
}
$required = $br.BaseStream.Length - $pos
if($required -lt 0){
$pos = 0
$required = $br.BaseStream.Length
}
if($required -eq 0){$br.close(); return $null}
$br.BaseStream.Seek($pos, [System.IO.SeekOrigin]::Begin)|Out-Null
$bytes = $br.ReadBytes($required)
$result = [System.Text.Encoding]::Unicode.GetString($bytes)
$split = $result.Split("`n")
foreach($s in $split)
{
if($s.contains(" Error:"))
{
$errorLine = [regex]::Split($s, "\s\s+")
$err = [regex]::Split($errorLine[1], "\s+")
if(log_filter $currentLog.event $err[1..$err.length]){$Script:events = $events+ [string]$s + "`n" }
}
}
$currentLog.lastpos = $br.BaseStream.Position
$br.close()
}
To be clear the error comes when I try to open the file. The error message is:
Exception calling "Open" with "2" argument(s): "The process cannot access the file
'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Log\ERRORLOG'
because it is being used by another process."
Gísli
So I found the answer and it was pretty simple.
The binary reader constructor takes as input a stream. I didn't define the stream seperately and that's why I didn't notice that you set the FileShare flag in the stream's constructor.
What I had to do was to change this:
{$br = New-Object System.IO.BinaryReader([System.IO.File]::Open($path, [System.IO.FileMode]::Open))}
To this:
{$br = New-Object System.IO.BinaryReader([System.IO.File]::Open($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite))}
And then it worked like a charm.
Gísli