bat to ps [SOLVED]

by supergirl at 2013-03-21 03:19:36

hi there

I configured log4j with the DailyRollingFileAppender so i get my logfiles like this: D:\log\app1\logfile.log.2013-03-20.txt, D:\log\app2\logfile.log.2013-03-20.txt

Now i wrote a batch script that move old logfiles in to a archive directory and compact them:



for /R d:\log %%x in (.log.2) do move /Y %%x %%~dpxarchive<br>for /R d:\log %%x in (.log.2) do compact /C %%x
for /R d:\log %%x in (_20.log) do move /Y %%x %%~dpxarchive<br>for /R d:\log %%x in (_20.log) do compact /C %%x


I want to write this code in powershell, any idea how to?

thaks
supergirl
by poshoholic at 2013-03-21 11:58:08
Hello Supergirl,

This might seem like an easy question to answer, but it’s not as easy as it should be. You must use CIM/WMI to compress files because PowerShell and .NET do not natively support this.

With that in mind, your PowerShell script would look something like this script that requires PowerShell 3 or later:
# Identify the location where the log files are being pulled from
$sourceFolder = ‘D:\log’
# Identify the location where the log files will be archived and compressed
$destinationFolder = ‘C:\dpxarchive’
# For each possible pattern that matches the log files we want to move and compress
foreach ($wildcardPattern in @(’.log.2’,’_20.log’)) {
# Get all of the log files, including hidden files, that match the path
foreach ($logfile in Get-ChildItem -Recurse -LiteralPath $sourceFolder -File -Force -Filter $wildcardPattern) {
# Move the log file to the destination folder
$destinationLogfile = Move-Item -LiteralPath $logfile.FullName -Destination $destinationFolder -PassThru
# Set the compression attribute on the log file in its new location
$cimResult = Get-CimInstance -ClassName CIM_DataFile -Filter “name=’$($destinationLogfile.FullName -replace ‘\’,’\’)’” | Invoke-CimMethod -MethodName Compress
# If we were unable to compress the file, report an error to the console
if ($cimResult.ReturnValue -ne 0) {
Write-Error “Failed to compress $($logFile.FullName)!”
}
}
}
by supergirl at 2013-03-22 04:41:22
Hello poshoholic

Thanks a lot for your feedback. Your script works really great, except the move part. My logfile tree looks like this:

D:\Log\App1
D:\Log\App2
D:\Log\App3

In each folder there is an archive directory. So for example logfiles from app1 should move to D:\Log\App1\Archive. I don’t know how to get this in Powershell

supergirl
by poshoholic at 2013-03-22 05:26:15
Hi Supergirl,

I follow what you’re after. This modified version of the script above should do the trick. It moves log files into an archive subfolder if they are not compressed already and if they are not already in an archive subfolder (i.e. since you’re doing a recursive search and moving from parent into child, it is necessary to exclude log files that are already archived).

Here’s the updated script:
# Identify the location where the log files are being pulled from
$sourceFolder = ‘D:\log’
# Identify the location where the log files will be archived and compressed
$archiveSubfolder = ‘dpxarchive’
# For each possible pattern that matches the log files we want to move and compress
foreach ($wildcardPattern in @(’.log.2’,’_20.log’)) {
# Get all of the uncompressed log files, including hidden files, that match the pattern
foreach ($logfile in Get-ChildItem -Recurse -LiteralPath $sourceFolder -File -Force -Filter $wildcardPattern -Attributes !Compressed) {
# If the log file is from an archive folder, continue to the next log file (no need to archive files that are already archived)
if ($logfile.Directory.Name -eq $archiveSubfolder) {
# This shouldn’t happen, so we should report it if/when it does
Write-Warning “Uncompressed logfile $($logfile.FullName) was found in the archive folder!”
# Now continue our loop with the next log file
continue
}
# Identify the destination folder
$destinationFolder = Join-Path -Path $logfile.DirectoryName -ChildPath $archiveSubfolder
# Move the log file to the destination folder
$destinationLogfile = Move-Item -LiteralPath $logfile.FullName -Destination $destinationFolder -PassThru
# Set the compression attribute on the log file in its new location
$cimResult = Get-CimInstance -ClassName CIM_DataFile -Filter “name=’$($destinationLogfile.FullName -replace ‘\’,’\’)’” | Invoke-CimMethod -MethodName Compress
# If we were unable to compress the file, report an error to the console
if ($cimResult.ReturnValue -ne 0) {
Write-Error “Failed to compress $($logFile.FullName)!”
}
}
}
by DexterPOSH at 2013-03-22 15:49:11
Hello Kirk Sir,

It’s a sheer pleasure to read your answers, so much to learn…I tried something similar to below in PowerShell v2 to set the compress attrib for a file
[quote=“poshoholic”]# Set the compression attribute on the log file in its new location
$cimResult = Get-CimInstance -ClassName CIM_DataFile -Filter “name=’$($destinationLogfile.FullName -replace ‘\’,’\’)’” | Invoke-CimMethod -MethodName Compress[/quote]

and learned a few things – I didn’t knew that Get-WMIObject can be used with CIM_* classes and the path passed as a filter needs to backslashes.
by poshoholic at 2013-03-22 19:00:57
Hi Dexter,

I’m glad you like my answers. Thanks for letting me know. :slight_smile:

WMI is actually loaded with CIM classes, and many WMI classes you use every day are derived from CIM classes. Take Win32_Process for example:
PS C:&gt; gwmi -list -Class win32_process | ft Name,__SUPERCLASS

Name __SUPERCLASS
---- ------------
Win32_Process CIM_Process

Also, WMI filters are interesting and quite different from PowerShell filters. You caught onto the double-backslash that is required if you want to use a string with a backslash already. That is required because backslash is the escape character in WMI filters/queries. If you want to do a wildcard search using a filter in WMI, instead of an asterisk you would use a percent sign, and instead of a question mark you would use an underscore. To be honest, I wish PowerShell supported one consistent method of filtering or using wildcards, whether you are working with WMI, CIM, or PowerShell. That would make things a lot easier, and I have often used a ConvertTo-WmiFilter function in my scripts that automatically handles these descrepancies so that I could just use regular wildcards regardless of what sort of filter I am creating.
by supergirl at 2013-03-25 05:02:08
Hi Poshoholic

Now this works really great. Thanks a lot!
by DexterPOSH at 2013-03-26 15:25:12
[quote=“poshoholic”]WMI is actually loaded with CIM classes, and many WMI classes you use every day are derived from CIM classes[/quote]
I understand this a lot better after going through MVP Richard Siddaway’s “PowerShell and WMI”…so WMI is implementation of CIM by Microsoft ,still reading it and it looks a lot promising.
BTW idea of using a function like ConvertTo-WmiFilter is something I will start using :slight_smile:

Thanks again for your time