Tips for collecting of YSoft SafeQ log files
In various cases YSoft SafeQ log files are necessary for analysis. This article provides the PowerShell script that can effectively help you to collect them. You can copy the script body and save it as a file with .ps1 extension.
When editing the script it is good to use "PowerShell ISE" tool.
Kindly follow instructions from the .DESCRIPTION section of the script when using it.
Script body
Click here to expand...
<#.SYNOPSISThe script helps collecting log files, configuration files, Windows Event Logs of YSoft SafeQ 6..DESCRIPTIONThe script identifies YSoft SafeQ installation and collects all possible log files and configuration.The script collects information from Windows Event Viewer.The script collects information from Windows System InformationThe script collects data for defined period of time (see $LogAge parameter). E.g. if the issue happened 3 hours ago, you would collect data from the last 4-5 hours to ensure that all data for analysis are available.The script collects only data from the server where the command was triggered for the past X hours (see $LogAge parameter). In case other servers may be involved (Management Server, CBPR Client, Authentication against SPOC group, etc.) data from all affected servers has to be provided.- for instance an authentication issue on an MFD managed by a SPOC group hidden behind a virtual IP address of load balancer occurs; log files from all servers in the SPOC group as well as from the Management servers has to be provided.- log files must cover the date and time of the occurrence.PowerShell 3.0 or higher is required, current version can be listed by command: $PSVersionTable.PSVersion.MajorThe script must be launched using PowerShell as an Administrator.Additional data such as "Support information" (YSoft SafeQ management interface > Dashboard > Click "Support information" > Click "Download support information"), screenshots and other relevant information must be collected manually and provided along with the log files..PARAMETER LogAgeDefines the period for how how many hours the log files will be collected from now to the past (default configuration is past 24 hours)..PARAMETER RootCollectionPathDefines the folder where on the server would you like to store the data (by default a new folder will be created on the desktop)..PARAMETER GetLogDetermine if logs are collected ($true / $false)..PARAMETER GetConfDetermine if the configuration files are collected ($true / $false)..PARAMETER GetCertDetermine if certificates and private keys are collected ($true / $false)..PARAMETER GetMiscDetermine if Windows Event Logs, System Information, list of Windows services, list of Memory Dumps are collected ($true / $false)..NOTESVersion: 1.30Last Modified: 02/Sep/2021.EXAMPLEDefine required values in $LogAge and $RootCollectionPath parameter.Run Windows PowerShell as an administrator and launch the command as follows:C:\Users\Administrator\Downloads> .\SQ_Collect_Logs.ps1#>#-----------------------------------------------------------[Parameters]-----------------------------------------------------------# Set the log age to gather in hours (Default: $LogAge = 24)$LogAge = 24# Log collection folder (Default: $RootCollectionPath = "$($env:USERPROFILE)\Desktop")# Example : $RootCollectionPath = "C:\Temp"$RootCollectionPath = "$($env:USERPROFILE)\Desktop"# Get logs ($true / $false)$GetLog = $true# Get configuration files ($true / $false)$GetConf = $true# Get certificates and private keys ($true / $false)$GetCert = $false# Get Windows Event Logs, System Information, Memory Dumps ($true / $false)$GetMisc = $true#-----------------------------------------------------------[Execution]------------------------------------------------------------# Input value checkIf (($GetConf -eq $false) -and ($GetLog -eq $false) -and ($GetMisc -eq $false) -and ($GetCert -eq $false)) {Write-Warning 'Nothing to collect. Please review the configuration and re-run the script.''Press any key to exit the script.' | Out-HostRead-Hostexit}# Admin rights checkIf (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(([System.Security.Principal.SecurityIdentifier]'S-1-5-32-544'))) {Write-Warning 'Administrative rights are missing. Please re-run the script as an Administrator.''Press any key to exit the script.' | Out-HostRead-Hostexit}# Create function for data copyingfunction copydata($FileToCopy) {ForEach ($tmp in $FileToCopy) {$DirectoryName = $tmp.DirectoryName -replace ("\w:\\","")$Destination = "$DataDest\$DirectoryName"If (!(Test-Path $Destination)) {New-Item -Path $Destination -ItemType Directory | Out-Null}Copy-Item $tmp.FullName -Destination $Destination}}# Create functions for data extractionfunction Expand-ZIP($file, $destination) {Add-Type -AssemblyName System.IO.Compression.FileSystem[System.IO.Compression.ZipFile]::ExtractToDirectory($file, $destination)}# Create functions for data archivation# Using .NET function is better than native Compress-Archive (PS5), native Compress-Archive may consume all the OS memoryfunction Compress-ZIP($directory, $destination) {Try {Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction SilentlyContinue} Catch {"File compression failed, kindly pack the files manually and provide them to CSS." | Out-Host"Files are available at: $DataDest" | Out-Host"" | Out-Host'Press any key to exit the script.' | Out-HostRead-Hostexit} Finally {[System.IO.Compression.ZipFile]::CreateFromDirectory($directory, $destination, "optimal", $true)}}# Prepare the log collection folder$IPaddress = (Get-WmiObject -Class Win32_NetworkAdapterConfiguration | Where-Object {$_.DefaultIPGateway -ne $null}).IPAddress | Select-Object -First 1$FolderName = "$($env:COMPUTERNAME)_$($IPaddress)"$DataDest = "$($RootCollectionPath)\$($FolderName)"'Locating the installation directories'# Define the services$ServiceList = Get-ChildItem -Path HKLM:\SYSTEM\CurrentControlSet\Services | Get-ItemProperty | `? {($_.PSChildName -match 'YSoft.*|YSQ.*' -or $_.DisplayName -match 'YSoft.*|YSQ.*')} | `? {$_.PSPath -notmatch 'YSoftEtcd|YSoftSQ-LDAP|YSoftSafeQLDAPReplicator|YSoftSafeQCMLDBS|YSoftWeb|YSoftPGSQL|YSoftIms'}# Find the root directory for each serviceForEach ($Service in $ServiceList) {$tmp = $Service.ImagePath.Split()[0].Trim('`"')$tmp = $tmp.Substring(0,$tmp.LastIndexOf('\')) -Replace ('\\?bin\\?','') -Replace ('\\?tomcat\\?','') -Replace ('\\Service\\?','') -Replace ('PGSQL','PGSQL-data') -replace ('\\procrun','')$Service | Add-Member -MemberType NoteProperty -Name Path -Value $tmp}# Add location of customization located in rootdir, the ones deployed in different locations and not having YSoft* in the service name will be omitted from data collection.$findcustom = $ServiceList | ? {$_.PSChildName -in "YSoftSQ-Management",'YSoftSQ-SPOC'}if ($findcustom) {$findcustom = $findcustom[0].Path -replace '\\\w+$',''$findcustom = Get-ChildItem -Path $findcustom -Directory | ? {$_.FullName -notin $ServiceList.Path} | foreach { $ServiceList += New-Object -TypeName PSObject -Property @{Path = $_.FullName} }}# Temporary workaround for YSoftSQ-SPOOLER v3 client deployed by MSI package (key path in registry is not complete)$v3clientmsi = $ServiceList | ? {$_.DisplayName -eq "YSoft SafeQ Spooler"}if ($v3clientmsi -and $v3clientmsi.Path -match "\w:$") {$v3clientmsi.Path = $v3clientmsi.ImagePath -replace '\\\d+\.\d+\.\d+\.\d+\\..\\latest\\YSoft\.Spooler\.Host\.exe"\s--run-as-service','\latest' -replace '"',''}# General list of directories to exclude from all searches to speed up processing$DirExclude = '\\.*backup.*|\\PGSQL\\|PGSQL-data\\(base|pg_wal)|\\spoolcache|\\cache|\\missioncontrol|java\\(demo|sample|lib|legal)\\|web-inf\\(views|classes|libs)|\\assets\\|\\catalina\\localhost|FSP\\universal-pcl-driver|Client\\resources\\app|\\AccountedJobs|\\ims\\\.vertx'if ($GetConf -eq $true) {'Copying the configuration files' | Out-Host# Obtaining all the configuration files$FileExtension = '.conf','.config','.properties','.xml','.json','.drl','.ini'$FileExclude = '\.dll\.config'$DirExcludeConf = $DirExclude + '|\\terminalserver|MobilePrint\\Service'$ConfToCopy = @()ForEach ($Service in $ServiceList) {if ($Service.PSChildName -match 'YSoftSQ-TS*'){$ConfToCopy += Get-ChildItem -Path $Service.Path -File -Recurse -Include 'TerminalServer.exe.config'} elseif ($Service.PSChildName -match 'YSoftSQ-MPS|YSoftMobilePrintServer') {$ConfToCopy += Get-ChildItem -Path $Service.Path -File -Recurse -Include '*.config'} else {$LookupDir = @()$LookupDir += Get-ChildItem -Path $Service.Path -Directory -Recurse | ? { $_.FullName -notmatch $DirExcludeConf }$LookupDir += Get-Item $Service.Path$ConfToCopy += $LookupDir | Get-ChildItem -File | ? {$_.Extension -in $FileExtension -and $_.FullName -notmatch $FileExclude }}}$ConfToCopy = $ConfToCopy | Sort FullName -Uniquecopydata $ConfToCopy}if ($GetCert -eq $true) {'Copying the certificates and private keys' | Out-Host# Obtaining all the certificate and private key files based on the predefined list$CertList = '\.(cer|crt|key|pfx|jks|p12|pem)|\\.*keystore|\\.*truststore'$CertToCopy = @()ForEach ($Service in $ServiceList) {$LookupDir = @()$LookupDir += Get-ChildItem -Path $Service.Path -Directory -Recurse | ? { $_.FullName -notmatch $DirExclude }$LookupDir += Get-Item $Service.Path$CertToCopy += $LookupDir | Get-ChildItem -File | ? { $_.FullName -match $CertList }}$CertToCopy = $CertToCopy | Sort FullName -Uniquecopydata $CertToCopy}if ($GetLog -eq $true) {'Copying the log files' | Out-Host# Obtaining all the files modified in the defined period plus the two last files of each filename pattern$LogToCopy = @()ForEach ($Service in $ServiceList) {$LogList = @()$LookupDir = @()$LookupDir += Get-ChildItem -Path $Service.Path -Directory -Recurse | ? { $_.FullName -notmatch $DirExclude }$LookupDir += Get-Item $Service.Path$LogList += $LookupDir | Get-ChildItem -File | ? { (($_.Length -gt 0) -and ($_.extension -eq ".log")) -or ($_.DirectoryName -match "\\(pg_log|log|logs)$") }# Additional location for global install log$LogList += (Get-Item $Service.Path).parent.FullName | Get-ChildItem -File | ? {$_.extension -eq ".log"}# Additional location for YSoftSQ-SPOOLER install.log and client v3 logif ($Service.Path -match 'versions\\latest'){$LogList += Get-ChildItem -Path $($Service.Path -replace 'versions\\latest','logs') -File -ErrorAction Ignore$LogList += Get-ChildItem -Path $(($env:USERPROFILE -replace "[^\\]*(?:)?$") + '*\AppData\Roaming\YSoft SafeQ Client\logs') -Recurse}# Code to pick the last two logs for each name pattern$Patterns = @()ForEach ($Log in $LogList) {If ($Log.BaseName -match "\.") {$Patterns += ($Log.BaseName -Split ('\.'))[0]} Elseif ($Log.BaseName -match "postgresql") {$Patterns += ($Log.BaseName -Split ('\-'))[0]} Else {$Patterns += $Log.BaseName}}$Patterns = $Patterns | Select-Object -Unique$LastLogs = @()ForEach ($Pattern in $Patterns) {$LastLogs += $LogList | ? {$_.BaseName -match "$Pattern"} | Sort-Object LastWriteTime -Descending | Select-Object -First 2}$LogToCopy += $LogList | ? {$_.LastWriteTime -gt (Get-Date).AddHours(-$LogAge) -or $_ -in $LastLogs}}$LogToCopy = $LogToCopy | Sort FullName -Uniquecopydata $LogToCopy'Extracting archived logs' | Out-Host$ZipFiles = Get-ChildItem -Path $DataDest -Recurse | Where-Object {$_.Name -match '.zip'}If ($ZipFiles) {$progresstrack = 0$command = [scriptblock]::Create('Expand-ZIP -File $($ZipFile.FullName) -Destination $($ZipFile.Directory.FullName)')ForEach ($ZipFile in $ZipFiles) {Try {Write-Progress -Activity "Extracting archived logs" -CurrentOperation "" -PercentComplete ($progresstrack/$zipfiles.Count*100)$progresstrack = $progresstrack + 1& $commandRemove-Item -Path $ZipFile.FullName} Catch {<#"File extraction failed, keeping an archive: $ZipFile"#>}}Write-Progress -Activity "Extracting archived logs" -Status "Ready" -Complete}}if ($GetMisc -eq $true) {If (!(Test-Path $DataDest)) {New-Item -Path $DataDest -ItemType Directory | Out-Null}'Getting the Windows Event Logs' | Out-HostGet-EventLog Application -After (Get-Date).AddHours(-$LogAge) | Format-Table -Property TimeWritten, Source, EventID, EntryType, Message -wrap -auto | Out-File $DataDest\EventLog_Application.txt -Width 250Get-EventLog System -After (Get-Date).AddHours(-$LogAge) | Format-Table -Property TimeWritten, Source, EventID, EntryType, Message -wrap -auto | Out-File $DataDest\EventLog_System.txt -Width 250'Getting the System Info' | Out-Host$sysinfo = @()If ([System.Version]$PSVersionTable.PSVersion -ge [System.Version]"5.1") {$sysinfo += 'Accurate CPU information obtained by PowerShell 5.1 or higher:'$sysinfo += (Get-ComputerInfo -Property CsNumberOfLogicalProcessors, CsNumberOfProcessors, CsProcessors | Format-List | Out-String).Trim()$sysinfo += ''}$sysinfo += 'Generic system information:'$sysinfo += 'WARNING: The number of CPU cores listed below is incorrect, because command "sysinfo" provides inaccurate data.'$sysinfo += systeminfo$sysinfo | Out-File $DataDest\SystemInfo.txt'Getting details about services' | Out-Host$OSservicelist = Get-WmiObject win32_serviceforeach ($OSservice in $OSservicelist) {$OSr = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\$($OSservice.Name)"If ( $OSr.DelayedAutostart -eq 1 -and $OSr.Start -eq 2 ) { $OSservice.StartMode = $OSservice.StartMode + ' (Delayed)' }}$OSservicelist | Sort DisplayName | format-table -Property DisplayName, Name, StartName, StartMode, State | Out-File $DataDest\Services.txt -Width 250'Getting details about available memory dumps' | Out-Host$dmp = Get-ChildItem -Path ([regex]::split($ServiceList.Path, '(\w:\\\w+\s?\w\\)')[1]) -Include *.hprof,*.mdmp,*.dmp -RecurseIf (![string]::IsNullOrEmpty($dmp)) {$dmp | Format-Table -Property FullName, Length, LastWriteTime -AutoSize | Out-File $DataDest\Dump_List.txt} Else {'No hprof/mdmp/dmp file found.' | Out-File $DataDest\Dump_List.txt}}'Compressing the files' | Out-Host$FileName = "$($RootCollectionPath)\$((Get-Date).ToString('yyyyMMddHHmm'))_$($FolderName)_YSoftDiagData"Compress-ZIP -Directory $DataDest -Destination "$($FileName).zip"'Removing temporary files' | Out-HostRemove-Item -Path $DataDest -Recurse -ForceWrite-Output ""Write-Output "Work done, the output is in $($FileName).zip"Write-Output 'Feel free to close the script'Read-Host