WecEventlog.ps1
<#
.EXAMPLE New-EventLogProvider -ProviderName WEC-Workstations-Sysmon,WEC-DomainControllers-Sysmon,WEC-Servers-Sysmon .EXAMPLE New-EventLogProvider -ProviderName WEC-DomainControllers-Test -ChannelName Test,Test1,Test2 -LogSize 32mb .EXAMPLE New-EventLogProvider -ManFile c:\ManFile.man .NOTES Author: SAGSA https://github.com/SAGSA/WecEventlog Requires: Powershell 2.0 #> function New-EventLogProvider { [cmdletbinding()] param( [ValidateNotNullOrEmpty()] [string[]]$ProviderName, [string[]]$ChannelName, [ValidateSet("Admin","Operational")] $ChannelType="Operational", [string[]]$ImportChannel=@("Application","System"), [int64]$LogSize=10485760, [ValidateNotNullOrEmpty()] [ValidateScript({test-path $_})] [string]$ManFile ) $NameSpaceName="CustomChannelsNamespace" [String]$RootFolder="$env:SystemRoot\CustomProviders" $BaseName="CustomProvider" #$CheckFileSignature=$True if (!((New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator))) { Write-Error "Run powershell as administrator" -ErrorAction Stop } if ($PSBoundParameters["ProviderName"] -and $PSBoundParameters["ManFile"]) { Write-Error "Only one parameter is possible from ProviderName,Manfile" -ErrorAction Stop } $TmpRes=Join-Path -Path $RootFolder -ChildPath Tmp if (!(Test-Path $TmpRes)) { Write-Verbose "Create Folder $TmpRes" New-Item -ItemType Directory -Path $TmpRes -ErrorAction Stop | Out-Null } if ($PSBoundParameters["ManFile"]) { Write-Verbose "Copy-item $ManFile $TmpRes\$BaseName.man" [xml]$ManConfigXml=Get-Content $ManFile -ErrorAction Stop [array]$ProviderName=$ManConfigXml.instrumentationManifest.instrumentation.events.provider | foreach { $_.name } if ($ProviderName.count -eq 0) { Write-Error "Incorrect man file $ManFile" -ErrorAction Stop } Copy-Item $ManFile -Destination "$TmpRes\$BaseName.man" } $ProviderName | foreach { if (Get-WinEvent -ListProvider $_ -ErrorAction SilentlyContinue) { Write-Error "Provider $_ already exists" -ErrorAction Stop } } $FolderName=[guid]::NewGuid() $CustomEventsDLLFullPath = $RootFolder + "\"+$FolderName+"\"+ $BaseName + ".dll" $TmpManFileFullPath=$TmpRes+"\$BaseName"+".man" if (!(Test-Path $RootFolder)) { Write-Verbose "Create Folder $RootFolder" New-Item -ItemType Directory -Path $RootFolder -ErrorAction Stop | Out-Null } #Write-Verbose $CustomEventsDLLFullPath function CreateManFile { [cmdletbinding()] param( [string[]]$ProviderName, [ValidateSet("Admin","Operational","Analytic","Debug")] $ChannelType="Operational", [string[]]$ImportChannel, [xml]$ManConfigXml, [string[]]$Channel, [parameter(Mandatory=$true)] [ValidateScript({$_ -match ":\\.+\\.+\.dll$"})] [string]$DllPath, [parameter(Mandatory=$true)] [ValidateScript({$_ -match ":\\.+\\.+\.man$"})] [string]$OutManFilePath ) if ($PSBoundParameters["ManConfigXml"]) { $ManConfigXml.instrumentationManifest.instrumentation.events.provider | foreach { Write-Verbose "$($_.name) Set Attribute resourceFileName $DllPath" $_.SetAttribute("resourceFileName",$DllPath) Write-Verbose "$($_.name) Set Attribute messageFileName $DllPath" $_.SetAttribute("messageFileName",$DllPath) Write-Verbose "$($_.name) Set Attribute parameterFileName $DllPath" $_.SetAttribute("parameterFileName",$DllPath) } $ManConfigXml.Save($OutManFilePath) } elseif($PSBoundParameters["ProviderName"]) { $ProviderName=$ProviderName | Select-Object -Unique #$CustomEvents = Import-CSV $ConfigFile #$Providers = $CustomEvents | Select-Object -Property ProviderSymbol,ProviderName,ProviderGuid -Unique $XmlWriter = New-Object System.XMl.XmlTextWriter($OutManFilePath,$null) $xmlWriter.Formatting = "Indented" $xmlWriter.Indentation = "4" $xmlWriter.WriteStartDocument() $xmlWriter.WriteStartElement("instrumentationManifest") $xmlWriter.WriteAttributeString("xsi:schemaLocation","http://schemas.microsoft.com/win/2004/08/events eventman.xsd") $xmlWriter.WriteAttributeString("xmlns","http://schemas.microsoft.com/win/2004/08/events") $xmlWriter.WriteAttributeString("xmlns:win","http://manifests.microsoft.com/win/2004/08/windows/events") $xmlWriter.WriteAttributeString("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance") $xmlWriter.WriteAttributeString("xmlns:xs","http://www.w3.org/2001/XMLSchema") $xmlWriter.WriteAttributeString("xmlns:trace","http://schemas.microsoft.com/win/2004/08/events/trace") $xmlWriter.WriteStartElement("instrumentation") $xmlWriter.WriteStartElement("events") foreach ($Pname in $ProviderName) { $ProviderSymbol=$Pname -replace "-","_" if (!($PSBoundParameters['Channel'])) { $Channel=$ChannelType } $ProviderGuid="{$([guid]::NewGuid())}" $xmlWriter.WriteStartElement("provider") $xmlWriter.WriteAttributeString("name",$PName) $xmlWriter.WriteAttributeString("guid", $ProviderGuid) $xmlWriter.WriteAttributeString("symbol",$ProviderSymbol) $xmlWriter.WriteAttributeString("resourceFileName",$DllPath) $xmlWriter.WriteAttributeString("messageFileName",$DllPath) $xmlWriter.WriteAttributeString("parameterFileName",$DllPath) $xmlWriter.WriteStartElement("channels") if ($PSBoundParameters["ImportChannel"]) { $Count=0 $ImportChannel | foreach { $Count++ $xmlWriter.WriteStartElement("importChannel") $xmlWriter.WriteAttributeString("name",$_) $xmlWriter.WriteAttributeString("chid","C$Count") $xmlWriter.WriteEndElement() } } $Channel | foreach { $xmlWriter.WriteStartElement("channel") $ChannelName=$Pname+"/$_" $ChannelSymbol=($ChannelName -replace "-","_") -replace "/","_" $xmlWriter.WriteAttributeString("name",$ChannelName) $xmlWriter.WriteAttributeString("chid",($ChannelName).Replace(' ','')) $xmlWriter.WriteAttributeString("symbol",$ChannelSymbol) $xmlWriter.WriteAttributeString("type",$ChannelType) $xmlWriter.WriteAttributeString("enabled","true") $xmlWriter.WriteEndElement() } $xmlWriter.WriteEndElement() $xmlWriter.WriteEndElement() } $xmlWriter.WriteEndElement() $xmlWriter.WriteEndElement() $xmlWriter.WriteEndElement() $xmlWriter.WriteEndDocument() $xmlWriter.Finalize $xmlWriter.Flush() $xmlWriter.Close() } else { Write-Error "Parameter ProviderName or ManConfigXml is empty" -ErrorAction Stop } Write-Verbose "Man file created successfully $OutManFilePath" return 0 } if ($PSBoundParameters["ProviderName"]) { Write-Verbose "Create ManFile $ProviderName" $res=CreateManFile -ProviderName $ProviderName -ChannelType $ChannelType -DllPath $CustomEventsDLLFullPath -OutManFilePath $TmpManFileFullPath -Channel $ChannelName -ImportChannel $ImportChannel if ($res -ne 0) { Write-Error "Man file not created" -ErrorAction Stop } } elseif($PSBoundParameters["ManFile"]) { Write-Verbose "Create Provider Use ManFile $ManFile" $res=CreateManFile -ManConfigXml $ManConfigXml -DllPath $CustomEventsDLLFullPath -OutManFilePath $TmpManFileFullPath if ($res -ne 0) { Write-Error "Man file not created" -ErrorAction Stop } } else { Write-Error "Parameter ProviderName or ManFile is empty" -ErrorAction Stop } $Osarch="x32" $FrameworkFolderName="Framework" if (${env:ProgramFiles(x86)}) { $Osarch="x64" $FrameworkFolderName="Framework64" } $UtilPath=$PSScriptRoot+"\util\$Osarch" $McFullPath=join-path $UtilPath "mc.exe" -Resolve -ErrorAction Stop $RcFullfPath=join-path $UtilPath "rc.exe" -Resolve -ErrorAction Stop $RcDllfullPath=join-path $UtilPath "rcdll.dll" -Resolve -ErrorAction Stop $CscFullPath= join-path $env:SystemRoot "Microsoft.NET\$FrameworkFolderName\v4.0.30319\csc.exe" -Resolve -ErrorAction Stop $Res=InvokeExe -ExeFile $McFullPath -Args $TmpManFileFullPath,"-h",$TmpRes,"-r",$TmpRes -CheckSignature $CheckFileSignature -ErrorAction Stop $Res=InvokeExe -ExeFile $McFullPath -Args "-css",$NameSpaceName,$TmpManFileFullPath,"-h",$TmpRes,"-r",$TmpRes -ErrorAction Stop $RcFileFullPath=Join-Path $TmpRes $($BaseName+".rc") -Resolve -ErrorAction Stop $Res=InvokeExe -ExeFile $RcFullfPath -Args $RcFileFullPath -CheckSignature $CheckFileSignature -ErrorAction Stop $Res=InvokeExe -ExeFile $CscFullPath "/win32res:$TmpRes\$BaseName.res","/unsafe","/target:library","/out:$TmpRes\$BaseName.dll","$TmpRes\$BaseName.cs" -ErrorAction Stop if (Test-Path "$RootFolder\$BaseName.dll") { Write-Error "file $RootFolder\$BaseName.dll already exists" -ErrorAction Stop } if (Test-Path "$RootFolder\$BaseName.man") { Write-Error "file $RootFolder\$BaseName.man already exists" -ErrorAction Stop } Write-Verbose "New-Item -Path $RootFolder\$FolderName" New-Item -ItemType Directory -Path $RootFolder\$FolderName -ErrorAction Stop | Out-Null Write-Verbose "Copy-Item $TmpRes\$BaseName.dll $RootFolder\$FolderName" Copy-Item -Path "$TmpRes\$BaseName.dll" -Destination $RootFolder\$FolderName -ErrorAction Stop Write-Verbose "Copy-Item $TmpRes\$BaseName.man $RootFolder\$FolderName" Copy-Item -Path "$TmpRes\$BaseName.man" -Destination $RootFolder\$FolderName -ErrorAction Stop $WevtUtilFullPath=Join-Path $env:SystemRoot "system32\wevtutil.exe" -Resolve -ErrorAction Stop $res=InvokeExe -ExeFile $WevtUtilFullPath -Args "im","$TmpRes\$BaseName.man" -ErrorAction Stop Write-Verbose "Remove $TmpRes" Remove-Item $TmpRes -Recurse -Force Get-WinEvent -ListProvider $ProviderName | Select-Object -Property Name,LogLinks,MessageFilePath | foreach { $Provider=$_ $Provider.Loglinks | foreach { $LogName=$_.Logname if (!($_.IsImported)) { InvokeExe -ExeFile $WevtUtilFullPath -Args "sl",$LogName,"/ms:$LogSize" | Out-Null Get-WinEvent -ListLog $LogName | Select-Object -Property OwningProviderName,LogName,LogType,MaximumSizeInBytes,LogMode } } } } <# .EXAMPLE Remove-EventLogProvider -ProviderName WEC-Workstations-Sysmon,WEC-DomainControllers-Sysmon,WEC-Servers-Sysmon .EXAMPLE Get-WinEvent -ListProvider WEC* | Remove-EventLogProvider .NOTES Author: SAGSA https://github.com/SAGSA/WecEventlog Requires: Powershell 2.0 #> function Remove-EventLogProvider { [cmdletbinding()] param( [parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0)] [string[]]$ProviderName, [switch]$Force ) begin { if (!((New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator))) { Write-Error "Run powershell as administrator" -ErrorAction Stop } Function RemoveProvider { param( [parameter(Mandatory=$true)] [string]$ManFile, [parameter(Mandatory=$true)] [string]$FolderPath ) if (!(Test-Path $Manfile)) { Write-Error "File $Manfile not found" -ErrorAction Stop } $WevtUtilFullPath=Join-Path $env:SystemRoot "system32\wevtutil.exe" -Resolve -ErrorAction Stop $res=InvokeExe -ExeFile $WevtUtilFullPath -Args "um",$Manfile -ErrorAction Stop Write-Verbose "Remove-Item -Path $FolderPath" Remove-Item -Path $FolderPath -Recurse -Force } $AllProviderInfo=Get-WinEvent -ListProvider * -ErrorAction SilentlyContinue $RemovedProvider=@() $ProviderNames=@() } Process { if ($ProviderName -ne $null) { $ProviderNames+=$ProviderName } } End { foreach($ProviderName in $ProviderNames) { if ($RemovedProvider -eq $ProviderName) { Write-Verbose "$ProviderName has been removed" } else { $ProviderInfo=$AllProviderInfo | Where-Object {$_.providername -eq $ProviderName} if (!$ProviderInfo) { Write-Error "$ProviderName provider does not exist" } else { if ($ProviderInfo.MessageFilePath -ne $null) { if ($ProviderInfo.MessageFilePath -match ".+\\(.+-.+-.+-.+-.+)\\") { $ManFilePath=$ProviderInfo.MessageFilePath -replace "\.dll$",".man" $FolderGuid=$matches[1] $FolderFullPath=Split-Path $ProviderInfo.MessageFilePath -Parent [array]$ProviderList=$AllProviderInfo | Where-Object {$_.MessageFilePath -match $FolderGuid} if ($ProviderList.count -eq 1) { RemoveProvider -ManFile $ManFilePath -FolderPath $FolderFullPath Write-Host "$ProviderName removed succesfully" -ForegroundColor Green } elseif($ProviderList.count -gt 1) { if($PSBoundParameters["Force"].ispresent) { RemoveProvider -ManFile $ManFilePath -FolderPath $FolderFullPath Write-Host "$($ProviderList.ProviderName) removed successfully" -ForegroundColor Green $RemovedProvider+=$ProviderList.ProviderName } else { Write-Error "Multiple providers refer to a file $($ProviderInfo[0].MessageFilePath) Use parameter Force to remove $($ProviderList.ProviderName)" -ErrorAction Stop } } else { Write-Error "Impossible to delete $ProviderName" } } else { Write-Verbose "Unknown provider $ProviderName" -Verbose } } else { Write-Error "$ProviderName MessageFilePath is Null" } } } } if ($FolderFullPath) { $RootFolder=Split-Path $FolderFullPath -Parent if (Test-Path $RootFolder) { if(!(Get-ChildItem $RootFolder -Force)) { Write-Verbose "Remove-Item $RootFolder" Remove-Item $RootFolder -ErrorAction SilentlyContinue } } } } } Function New-EventlogManifest { [CmdletBinding()] param() if(!(Test-Path -Path "$PSScriptRoot\util\ecmangen.exe")) { Write-Error "$PSScriptRoot\util\ecmangen.exe Not Found" -ErrorAction Stop } Copy-Item "$PSScriptRoot\util\ecmangen.exe" $env:TEMP -Force | Out-Null if ($CheckFileSignature) { if((Get-AuthenticodeSignature -FilePath "$env:TEMP\ecmangen.exe").Status -ne "Valid") { Write-Error "CheckSignature failed" -ErrorAction Stop } } Write-Verbose "Start-Process $env:TEMP\ecmangen.exe" Start-Process -FilePath "$env:TEMP\ecmangen.exe" } function InvokeExe { [cmdletbinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [String]$ExeFile, [Parameter(Mandatory=$false)] [String[]]$Args, [Parameter(Mandatory=$false)] [String]$Verb, [bool]$CheckSignature=$false ) $oPsi = New-Object -TypeName System.Diagnostics.ProcessStartInfo $oPsi.CreateNoWindow = $true $oPsi.UseShellExecute = $false $oPsi.RedirectStandardOutput = $true $oPsi.RedirectStandardError = $true $oPsi.FileName = $ExeFile if (! [String]::IsNullOrEmpty($Args)) { $oPsi.Arguments = $Args } if (! [String]::IsNullOrEmpty($Verb)) { $oPsi.Verb = $Verb } $oProcess = New-Object -TypeName System.Diagnostics.Process $oProcess.StartInfo = $oPsi $oStdOutBuilder = New-Object -TypeName System.Text.StringBuilder $oStdErrBuilder = New-Object -TypeName System.Text.StringBuilder $sScripBlock = { if (! [String]::IsNullOrEmpty($EventArgs.Data)) { $Event.MessageData.AppendLine($EventArgs.Data) } } $oStdOutEvent = Register-ObjectEvent -InputObject $oProcess -Action $sScripBlock -EventName 'OutputDataReceived' -MessageData $oStdOutBuilder $oStdErrEvent = Register-ObjectEvent -InputObject $oProcess -Action $sScripBlock -EventName 'ErrorDataReceived' -MessageData $oStdErrBuilder Write-Verbose "$ExeFile $Args" if ($CheckSignature) { Write-Verbose "CheckSignature $ExeFile" if((Get-AuthenticodeSignature -FilePath $ExeFile).Status -ne "Valid") { Write-Error "CheckSignature failed" -ErrorAction Stop } } [Void]$oProcess.Start() $oProcess.BeginOutputReadLine() $oProcess.BeginErrorReadLine() [Void]$oProcess.WaitForExit() Unregister-Event -SourceIdentifier $oStdOutEvent.Name Unregister-Event -SourceIdentifier $oStdErrEvent.Name $oResult = New-Object -TypeName PSObject -Property (@{ "ExeFile" = $ExeFile; "Args" = $Args -join " "; "ExitCode" = $oProcess.ExitCode; "StdOut" = $oStdOutBuilder.ToString().Trim(); "StdErr" = $oStdErrBuilder.ToString().Trim() }) if ($oResult.ExitCode -ne 0) { if (($oResult.StdErr).length -ne 0) { Write-Error "$($oResult.StdErr)" } elseif ($Res.StdOut -match "(error.+)") { Write-Error $Matches[1] } else { Write-Error "Unknown error" } } return $oResult } |