Can somebody tell me the best way to delete a series of files between April 1, 2014 and April 17, 2014 on Windows server 2003 command line
This PowerShell oneliner will do the trick. You can remove the back-ticks and put the code all on one line if you want.
Get-ChildItem C:\data\*.* | `
Where-Object {$_.lastwritetime -gt '4/1/14' -AND $_.lastwritetime -lt '4/17/14'} | `
Remove-Item
I found a shorter version of the script here. I prefer to use the full Powershell cmdlet names though.
Related
I am trying to come up with a Powershell script to dynamically do 'Restore Database' in SQL Server 2019 with multiple TRN (or BAK in my case) files that are located in one folder on a daily basis.
I will manually do the full backup first, and this task will be scheduled to run after (once on a daily basis).
So, a Python script will grab only yesterday's files from another folder into this folder, and this Powershell script will execute to run to restore a database using these TRN / BAK files (located in this folder).
The plan is go thru each TRN files (located in the same folder) sequentially (not with the time files were created, but by file name).
For example, it will start from "..04" --> "..12" in this case.
I found some examples from this site, but I was not sure how to code where it recognize the sequence ("..04" --> "..12") to run.
PS C:\> $File = Get-ChildItem c:\backups, \\server1\backups -recurse
PS C:\> $File | Restore-DbaDatabase -SqlInstance Server1\Instance -UseDestinationDefaultDirectories
So, by default, I think Get-ChildItem should be already displaying the files starting from lowest to highest but if you want to make sure you could try something like this and see if the output fits your case.
For starting the test I'll create files using the same names as yours:
$i=1;1..12|foreach{
$null > "LOG_us_bcan_multi_replica_20210427$($i.ToString('0#')).bak"
$null > "LOG_us_bcan_multi_replica_20200327$($i.ToString('0#')).bak"
$i++
}
This creates 24 files with the same naming convention you have.
From ...multi_replica_2021042701.bak to ...multi_replica_2021042712.bak
From ...multi_replica_2020042701.bak to ...multi_replica_2020042712.bak
We know sorting by DateTime is possible so we can use string manipulation to get the date of your FileNames and use the ParseExact method on them.
Example:
# Assuming your current directory is the directory where the .bak files are
$expression={
[datetime]::ParseExact(
$_.BaseName.split('replica_')[1],'yyyyMMddHH',[cultureinfo]::InvariantCulture
)
}
Get-ChildItem | Select-Object BaseName,#{n='DateFromFileName';e=$expression}
# This will return a side by side FileName with their Dates from FileName
BaseName DateFromFileName
-------- ----------------
LOG_us_bcan_multi_replica_2020032701 3/27/2020 1:00:00 AM
LOG_us_bcan_multi_replica_2020032702 3/27/2020 2:00:00 AM
LOG_us_bcan_multi_replica_2020032703 3/27/2020 3:00:00 AM
LOG_us_bcan_multi_replica_2020032704 3/27/2020 4:00:00 AM
LOG_us_bcan_multi_replica_2020032705 3/27/2020 5:00:00 AM
LOG_us_bcan_multi_replica_2020032706 3/27/2020 6:00:00 AM
.....
Now we can use the same $expression with Sort-Object instead of Select-Object
Get-ChildItem | Sort-Object $expression
I have 2x mini scripts which are fairly similar.
The first backs up our SQL Jobs and runs fine:
Import-Module "SQLPS" Get-ChildItem -Path SQLSERVER:\SQL\MYSERVERNAME\Default\JobServer\Jobs\ | %{$_.script()} | out-file -Filepath "MYFILEPATH_$(get-date -f yyyyMMdd).sql"
The second is meant to back up our SQL Stored Procedures, and does not produce results in the output file:
Import-Module "SQLPS" Get-ChildItem -Path SQLSERVER:\SQL\MYSERVERNAME\Default\Databases\MYDBNAME\StoredProcedures\ | %{$_.script()} | out-file -Filepath "MYFILEPATH_$(get-date -f yyyyMMdd).sql"
This problematic second script gives the below error:
Get-ChildItem : Cannot find path 'SQLSERVER:\SQL\MYSERVERNAME\Default\Databases\MYDBNAME\StoredProcedures\' because it does not exist.
It used to run successfully until around the time I upgraded to Windows10. Any suggestions on how to correct this second script?
I have a xxx.ppt file. I need to identify if this file is in 2003 format or 97 format or 95 format or a version older than that. I tried checking file properties, it simply says Microsoft Powerpoint. No version mentioned. I tried with Apache POI and got the version number something like this "ppt version[50334156]". I couldn't find any specification documents for pre 97 format files either. Working with these binary files is such a pain.
I have no idea why you need to do this but I found it extreamly interesting (Can it be done?) So I wrote this very ugly powershell hack.
$shell = new-object -com shell.application
Rename-Item C:\Temp\Presentation1.ppt C:\Temp\Presentation1.zip
$zip = $shell.NameSpace(“C:\Temp\Presentation1.zip”)
mkdir C:\temp\ziptest
foreach($item in $zip.items())
{
$shell.Namespace(“C:\temp\ziptest”).copyhere($item)
}
$file = Get-Content C:\temp\ziptest\docprops\app.xml | Select-String -Pattern ("<AppVersion>([\s\S]*?)</AppVersion>")
Remove-Item -Recurse -Force C:\temp\ziptest\
clear
echo $file.Matches[0].Groups[1].Value
To use it you will have to add a function that reads your ppt files into a variable and then loops through this snippet, the snippet will rename them to .zip (and by this enable us to read the xml files from the ppt) get the app.xml and give you the version number (Office95 = 7.0, Office 97 (8.0), Office 97 Powered by Word 98 (8.5), Office 2000 (9.0), Office XP (10.0),Office 2003 (11.0),Office 2007 (12.0), Office 2010 (14.0), Office 2013 (15.0))
UPDATE: Modified the script to work within the bounds of PS1 as required by SQLPS.
Changed:
IF($property.Value -match $regex){
$currentBadLine = (ConvertTo-Csv $_ -NoTypeInformation -Delimiter $delimiter);
$badLines += $currentBadLine[1,2]
};
To:
IF($property.Value -match $regex){
$badLines += $_ | Select-Object | ft -autoSize;
};
Prints a new header for each bad line, but it's not the end of the world and not worth the effort to prevent.
I have a Powershell script that pre-processes CSV files before they have a chance to screw up my data imports.
On two servers in a row now I have confirmed that the PS Major Version at least 2, and that the following code snippet runs fine in Powershell ISE. The purpose of the code is to read in each line of the CSV, and then loop through the columns looking for the regex pattern in the $regex variable. When it finds one I want it to keep track of the error before fixing it so I can write an error log later before outputting a cleaned up file ready for import.
%{
Foreach($Property in $_.PSObject.Properties){
IF($property.Value -match $regex){
$currentBadLine = (ConvertTo-Csv $_ -NoTypeInformation -Delimiter $delimiter);
$badLines += $currentBadLine[1,2]
};
$property.Value = $property.Value -replace $regex;
}
$_
}
But once I put that code into an agent job the agent complains:
'The term 'ConvertTo-Csv' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and
try again. '
The question then is this: Is the Agents Powershell subsystem using a different version of Powershell than the rest of the system? If so, how do I find out which version the Subsystem is using and if possible upgrade it so I can fix this.
The server is running:
Windows Server 2008 R2 Enterprise
PS Major version 2, Minor 0 Build -1 revision -1
SQL Server 2008 R2 SP1 10.5.2500.0 64 bit
Thanks!
Yes, proper PowerShell support isn't really implemented until SQL Server 2012 (an even that is a bit flakey as to what cmdlets it supports)
In 2008 and R2 the agent's powershell implementation is actually a minishell, created by the now (thankfully) deprecated make-shell.exe utility, which only allows v1 cmdlets to run, and disallows the use of Add-PSSnapin so you can't add anymore cmdlets.
To get proper powershell support, you either need to shell out and call an external script, or run the job as a windows scheduled task rather than an agent job.
The following article explains a lot about why powershell support in 2008 R2 doesn't work like you think it should:
The Truth about SQLPS and PowerShell V2
One work-around: Export-CSV to a file, then Get-Content from the file.
$rows = ,(New-Object PSObject -prop #{a=7; b='stuff';});
$rows +=,(New-Object PSObject -prop #{a=77; b='more';});
#To run from SQL Job, change from this:
$csvrows = $rows | ConvertTo-CSV -NoType | % {$_.Replace('"','')};
write-output $csvrows;
#to this:
$rows | Export-CSV -NoType "C:\Temp\T.csv"
$csvrows = (Get-Content "C:\Temp\T.csv") | % {$_.Replace('"','')};
write-output $csvrows;
I need a PowerShell script that can access a file's properties and discover the LastWriteTime property and compare it with the current date and return the date difference.
I have something like this...
$writedate = Get-ItemProperty -Path $source -Name LastWriteTime
...but I can not cast the LastWriteTime to a "DateTime" datatype. It says, "Cannot convert "#{LastWriteTime=...date...}" to "System.DateTime".
Try the following.
$d = [datetime](Get-ItemProperty -Path $source -Name LastWriteTime).lastwritetime
This is part of the item property weirdness. When you run Get-ItemProperty it does not return the value but instead the property. You have to use one more level of indirection to get to the value.
(ls $source).LastWriteTime
("ls", "dir", or "gci" are the default aliases for Get-ChildItem.)
I have an example I would like to share
$File = "C:\Foo.txt"
#retrieves the Systems current Date and Time in a DateTime Format
$today = Get-Date
#subtracts 12 hours from the date to ensure the file has been written to recently
$today = $today.AddHours(-12)
#gets the last time the $file was written in a DateTime Format
$lastWriteTime = (Get-Item $File).LastWriteTime
#If $File doesn't exist we will loop indefinetely until it does exist.
# also loops until the $File that exists was written to in the last twelve hours
while((!(Test-Path $File)) -or ($lastWriteTime -lt $today))
{
#if a file exists then the write time is wrong so update it
if (Test-Path $File)
{
$lastWriteTime = (Get-Item $File).LastWriteTime
}
#Sleep for 5 minutes
$time = Get-Date
Write-Host "Sleep" $time
Start-Sleep -s 300;
}
(Get-Item $source).LastWriteTime is my preferred way to do it.
I can't fault any of the answers here for the OP accepted one of them as resolving their problem. However, I found them flawed in one respect. When you output the result of the assignment to the variable, it contains numerous blank lines, not just the sought after answer. Example:
PS C:\brh> [datetime](Get-ItemProperty -Path .\deploy.ps1 -Name LastWriteTime).LastWriteTime
Friday, December 12, 2014 2:33:09 PM
PS C:\brh>
I'm a fan of two things in code, succinctness and correctness. brianary has the right of it for succinctness with a tip of the hat to Roger Lipscombe but both miss correctness due to the extra lines in the result. Here's what I think the OP was looking for since it's what got me over the finish line.
PS C:\brh> (ls .\deploy.ps1).LastWriteTime.DateTime
Friday, December 12, 2014 2:33:09 PM
PS C:\brh>
Note the lack of extra lines, only the one that PowerShell uses to separate prompts. Now this can be assigned to a variable for comparison or, as in my case, stored in a file for reading and comparison in a later session.
Slightly easier - use the new-timespan cmdlet, which creates a time interval from the current time.
ls | where-object {(new-timespan $_.LastWriteTime).days -ge 1}
shows all files not written to today.
Use
ls | % {(get-date) - $_.LastWriteTime }
It can work to retrieve the diff. You can replace ls with a single file.