we have windows 2012 servers and we have powershell version 3. I'm trying to zip log files individually in a folder based on date condition.
Compress-Archive is not available in version 3.
we do not have any 3rd party zip utilities like WinZip, 7z..etc
I tried using [System.IO.Compression.ZipFile] class but it has no flexibility to zip individual files.
My requirement is, to capture the log files based on date and send them through loop to zip each file and delete original file. Your help in this regard is much appreciated.
Thanks in advance.
This answer works fine - it's using COM rather than pure .NET methods:
https://serverfault.com/a/456496/204875
Although, to be honest, I highly recommend downloading the portable version of 7zip and using that. No installation required, a lot more efficient and faster. If you can distribute a script, you can usually distribute an exe with it (although, yes, some environments are highly regulated).
Example:
$srcdir = "C:\tmp\in"
$zipFilepath = "C:\tmp\out"
$files = Get-ChildItem -Path $srcdir | where{! $_.PSIsContainer}
foreach($file in $files) {
$zipFilename = $file.name -replace '\.\w+$','.zip'
$zipFile = "$zipFilepath\$zipFilename"
#Prepare zip file
if(-not (test-path($zipFile))) {
set-content $zipFile ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
(dir $zipFile).IsReadOnly = $false
}
else {
# exit loop if zipfile with same name exists
write-warning "$zipfile exists"
Continue
}
# create new COM object
$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipFile)
$zipPackage.CopyHere($file.FullName)
#using this method, sometimes files can be 'skipped'
#this 'while' loop checks each file is added before moving to the next
while($zipPackage.Items().Item($file.name) -eq $null){
Start-sleep -milliseconds 250
}
}
write-host "zipfiles created"
Result:
> dir -Recurse
Directory: C:\tmp\in
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 30/12/2021 4:12 pm 5157 txt1.txt
-a---- 30/12/2021 4:12 pm 5157 txt2.txt
-a---- 30/12/2021 4:12 pm 5157 txt3.txt
-a---- 30/12/2021 4:12 pm 5157 txt4.txt
Directory: C:\tmp\out
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 30/12/2021 4:13 pm 1997 txt1.zip
-a---- 30/12/2021 4:14 pm 1997 txt2.zip
-a---- 30/12/2021 4:14 pm 1997 txt3.zip
-a---- 30/12/2021 4:14 pm 1997 txt4.zip
This solution has been thoroughly tested on Windows Server 2012 and doesn't require the shell COM object. Consequently it can run unattended. I have scheduled it to run daily via Windows Task Scheduler.
Related
I am trying to remove files I generated using powershell and del, but I get this message
del : Cannot remove item C:\Users\stefano.borini\<redacted>\.tox\py36\Include\fakepq.h: You do not have sufficient access rights to perform this operation.
At line:1 char:1
+ del .\.tox\
+ ~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (fakepq.h:FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemUnAuthorizedAccess,Microsoft.PowerShell.Commands.RemoveItemCommand
del : Cannot remove item C:\Users\stefano.borini\<redacted>\.tox\py36\Include\fakesql.h: You do not have sufficient access rights to perform this operation.
However, I can right click the items and delete them from the windows explorer without any problem. Why?
Did you run Powershell as Administrator rights?
If so, you can try to add "-force" to your command.
I have found the solution to this issue. This is specifically referring to the files that are created with Windows 10 FileHistory where users are posting issues with it all over.
When you look at your files in PowerShell doing a "dir" command on them, you'll see something like this.
Directory: D:\FileHistory\XXX\BT-XX\Data\C\Users\XXXX\Documents
dir Out*
Mode LastWriteTime Length Name
d----- 2022-09-30 12:11 OUTLOOK.BACKUP.20220910
d----- 2022-09-30 12:46 Outlook Rules
d----- 2022-09-30 12:46 Outlook Personal Folders
d----- 2022-09-30 13:25 Outlook Files
-ar--- 2016-03-13 13:08 19673 Outlook Rules 20160313 (2022_09_30 13_30_15 UTC).rwz
-ar--- 2012-09-13 13:39 28488 Outlook Rules 20120913 (2022_09_30 13_30_15 UTC).rwz
-ar--- 2022-09-30 15:27 33919878144 Outlook (2022_09_30 19_44_57 UTC).pst
-ar--- 2022-10-03 18:31 33940448256 Outlook (2022_10_03 22_32_14 UTC).pst
-ar--- 2022-10-04 02:41 33940448256 Outlook (2022_10_04 06_54_55 UTC).pst
-ar--- 2022-10-04 12:50 33940448256 Outlook (2022_10_04 16_50_50 UTC).pst
The -ar---- is the problem. The 'a' is for archive, and the 'r' is for READ-ONLY!!!!!!!!! WHY DO THEY DO THIS TO US?!?!?
If you try to delete one of these files from PowerShell with the rm command, it will not allow it and give you this message:
… Cannot remove item ……………… You do not have sufficient access rights to perform this operation.
At line:1 char:1
rm '.\Outlook (2022_10_03 22_32_14 UTC).pst ...
+ CategoryInfo : PermissionDenied: (D:\FileHistory\...35_35 UTC.ost :FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemUnAuthorizedAccess,Microsoft.PowerShell.Commands.RemoveItemCommand
You can add the -force to your rm command and it WILL delete it immediately.
In Windows Explorer, look at the properties of the "FileHistory" folder. It will have [X] READ-ONLY checked. If you un-check it, it'll say:
You have chosen to make the following attribute changes:
unset read-only
Do you want to apply this change to this folder only, or do you want to apply it to all subfolders and files as well?
When I select the default "Apply changes to this folder, subfolders and files", it will go through the entire structure and turn off read-only on the files.
When you go back to that directory in PowerShell, they will now look like this:
Mode LastWriteTime Length Name
d----- 2022-09-30 12:11 OUTLOOK.BACKUP.20220910
d----- 2022-09-30 12:46 Outlook Rules
d----- 2022-09-30 12:46 Outlook Personal Folders
d----- 2022-09-30 13:25 Outlook Files
-a---- 2016-03-13 13:08 19673 Outlook Rules 20160313 (2022_09_30 13_30_15 UTC).rwz
-a---- 2012-09-13 13:39 28488 Outlook Rules 20120913 (2022_09_30 13_30_15 UTC).rwz
-a---- 2022-09-30 15:27 33919878144 Outlook (2022_09_30 19_44_57 UTC).pst
-a---- 2022-10-03 18:31 33940448256 Outlook (2022_10_03 22_32_14 UTC).pst
-a---- 2022-10-04 02:41 33940448256 Outlook (2022_10_04 06_54_55 UTC).pst
-a---- 2022-10-04 12:50 33940448256 Outlook (2022_10_04 16_50_50 UTC).pst
Now you can run the FileHistory "Clean up versions", select whatever parameter under "Delete files:" (Older than 1 year… etc…)
This should work. But why do we have to do this extra step?
Why doesn't Windows know that if we can create the file, we should be able to delete it.
Let me know if anyone finds anything else out.
ATB,
Josef
Is it possible to make git print back slashes instead of forward slashes when it prints out paths in a Windows console? I'd like to be able to copy the paths that it outputs and paste it into my future console commands.
Example output:
C:\vna>git status
On branch herpderp
Your branch is up-to-date with 'origin/herpyderp'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
Java/HerpDerp/src
Java/HerpDerp/src/main/java/com/derp/messaging/
Java/HerpDerp/src/main/java/com/derp/controller/event/
Java/HerpDerp/src/main/java/com/derp/controller/domain/
Java/HerpDerp/src/main/java/com/derp/controller/monitor/
nothing added to commit but untracked files present (use "git add" to track)
Instead of
Java/HerpDerp/src/main/java/com/derp/messaging/
I'd like to see
Java\HerpDerp\src\main\java\com\derp\messaging\
or even
Java\\HerpDerp\\src\\main\\java\\com\\derp\\messaging\\
Edit: I should have clarified that this was for working with git in a Windows console. Also, it seems the correct answer for my case is to use Git Bash.
I know it's a little old, but you can use environment variable substitution to replace the / with \ or \\:
C:\> SET FILE=Java/HerpDerp/src
C:\> ECHO %FILE:/=\%
Java\HerpDerp\src
C:\> ECHO %FILE:/=\\%
Java\\HerpDerp\\src
C:\>
To take it a step further, you can write a batch file that does it for a command that outputs a bunch of paths: (git diff --name-only HEAD~1 in the following example)
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "usebackq delims=" %%i IN (`git diff --name-only HEAD~1`) DO (
SET FILE=%%i
ECHO !FILE:/=\!
)
ENDLOCAL
git status will be execute through a git bash session, so it would not ever use \ in path (as seen in "Git Bash for Windows showing/expecting file paths with forward-slashes, no drive colon").
See also "Why Windows Uses Backslashes and Everything Else Uses Forward Slashes"
As mentioned, you would have to post-process the output of the command in order to get the correct path format, as in "Bash converting path names for sed so they escape".
st=$(git status)
echo "${st////\\}"
or
echo "${st////\\\\}"
with:
// / / \\\\}"
^ ^ ^ ^
| | | |
| | | replacement, backslash needs to be backslashed
| | delimiter
| string
global
substitution
Thank you Lance Clark and VonC. I've been using Git with Windows, Unix/Linux, and Mac for several years, but I never understood how Git works through the Windows Command Shell. I came across this question because I was having trouble with forward slashes in the DOS command shell (the Windows Command Prompt).
In the DOS command shell, I was calling the delete command ("del") to delete a file using the file path returned by "git status", which of course had forward slashes in it. As a result, the error "Invalid switch" was returned or if I wrapped the path in quotes the error was "The system cannot find the path specified." That is when I did a web search and came across this stack overflow question.
The answer led me to learn about Git Bash and how Git really works in Windows. As a result, I'm switching to using Git Bash with Windows whenever possible rather than the DOS command shell. That is also making life easier going back and forth between Windows, Linux, and Mac. My forward slash and backward slash nightmares are mostly better now and I can sleep at night. :)
Here are some links to concise information about Git Bash that helped me understand how it works:
Atlassian: Git Bash
superuser: What is Git Bash for Windows anyway?
This is a little old, but I want to add this for people who find it via Google as I did (I was looking for something else).
#aspoon mentioned that you can change \ to / fairly easily in PowerShell. However, the OP mentioned that their goal was to use the output in subsequent commands. That makes this a bit of an XY question: the OP asked how to get git to output Windows-style paths, but then said that their actual goal was this:
I'd like to be able to copy the paths that it outputs and paste them into my future console commands.
If that's the case, another solution is that if you can use PowerShell as your console, or at least make your "future console commands" be PowerShell commands, then your commands will work.
One of the improvements that PowerShell has over previous Windows shells is that it accepts either folder delimiter as input. Note that in the following Get-ChildItem commands, the input paths can use either / or \ as folder delimiters.
This is not meant as a correction to other answers but merely an additional option that I want people to be aware of.
PS> dir \Users\Public\Desktop\ -Force
Directory: C:\Users\Public\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 7/3/2022 11:17 PM 2043 CloudBerry Backup.lnk
-a--- 7/29/2022 5:04 PM 1422 EditPad Pro 8.lnk
-a--- 8/31/2022 11:11 AM 993 Firefox.lnk
-a--- 6/17/2022 8:56 AM 1070 GET Help Live Chat.lnk
-a--- 6/17/2022 8:56 AM 1986 GET Help Phone Support.lnk
-a--- 9/16/2022 8:38 PM 2260 Google Chrome.lnk
-a--- 9/27/2022 4:32 PM 2276 Microsoft Edge.lnk
-a--- 7/28/2022 12:47 PM 1363 PowerGREP 5.lnk
-a--- 7/1/2022 4:41 PM 1453 RegexBuddy 4.lnk
-a--- 6/17/2022 1:32 PM 877 TeamViewer.lnk
-a--- 6/30/2022 6:30 PM 993 Visual Studio Code.lnk
-a--- 9/14/2022 9:20 AM 1917 Zoom.lnk
PS> dir /Users/Public/Desktop/ -Force
Directory: C:\Users\Public\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 7/3/2022 11:17 PM 2043 CloudBerry Backup.lnk
-a--- 7/29/2022 5:04 PM 1422 EditPad Pro 8.lnk
-a--- 8/31/2022 11:11 AM 993 Firefox.lnk
-a--- 6/17/2022 8:56 AM 1070 GET Help Live Chat.lnk
-a--- 6/17/2022 8:56 AM 1986 GET Help Phone Support.lnk
-a--- 9/16/2022 8:38 PM 2260 Google Chrome.lnk
-a--- 9/27/2022 4:32 PM 2276 Microsoft Edge.lnk
-a--- 7/28/2022 12:47 PM 1363 PowerGREP 5.lnk
-a--- 7/1/2022 4:41 PM 1453 RegexBuddy 4.lnk
-a--- 6/17/2022 1:32 PM 877 TeamViewer.lnk
-a--- 6/30/2022 6:30 PM 993 Visual Studio Code.lnk
-a--- 9/14/2022 9:20 AM 1917 Zoom.lnk
Trying to figure out how to get Powershell to display header details on subsequent requests to the same directory path.
Here is a simplified example of what I am trying to do, note that the second call to Get-ChildItem does not display the header details (presumably because it knows its already been called previously within the same scriptblock):
PS C:\TEMP\foo> $path="c:\temp\foo";Get-ChildItem -Path $path;Write-Output "Delete something and display directory contents again...";del $path\*5*;Get-ChildItem -Path $path
Directory: C:\temp\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 9/21/2016 9:54 PM 16 File1.txt
-a--- 9/21/2016 9:54 PM 16 File2.txt
-a--- 9/21/2016 9:54 PM 16 File3.txt
-a--- 9/21/2016 9:54 PM 16 File4.txt
-a--- 9/21/2016 9:54 PM 16 File5.txt
Delete something and display directory contents again...
-a--- 9/21/2016 9:54 PM 16 File1.txt
-a--- 9/21/2016 9:54 PM 16 File2.txt
-a--- 9/21/2016 9:54 PM 16 File3.txt
-a--- 9/21/2016 9:54 PM 16 File4.txt
This appears to be the default behavior if the same path is referenced more than once. I have found that a second header will be generated whenever a different path is provided in the second Get-ChildItem call, but never when the same path is used more than once.
Any ideas on how to force the second header to display like the first while still keeping both of these calls within the same scriptblock?
Thanks!
$path="c:\temp\data";
Get-ChildItem -Path $path
Write-host "Delete something and display directory contents again..."
del $path\*5* -Recurse
Get-ChildItem -Path $path
Add format-table after get-childitem,it will always display the result in table format with headers
Get-childitem $path | format-table
How can I read name of source file and send it as archive name in 7zip using cmd archive option.
Now I use:
7z a -t7z V:\archive.7z V:\Backup\*.bak
I want to check bak namefile in V:\Backup (there is always only 1 file) and send it as archive.7z - for example if in V:\Backup is 1 file named "20131028_1100.bak" I want to name archive "20131028_1100.7z"
I found this to work:
Get-ChildItem *txt | ForEach-Object {.\7zr.exe a -t7z $($_.Name).replace('.txt','.7z') $_.FullName}
Example:
PS C:\tools> ls
Directory: C:\tools
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2022/08/01 11:00 578048 7zr.exe
-a---- 2022/08/01 11:02 7 hello.txt
PS C:\tools> Get-ChildItem *txt | ForEach-Object {.\7zr.exe a -t7z $($_.Name).replace('.txt','.7z') $_.FullName}
7-Zip (r) 22.01 (x86) : Igor Pavlov : Public domain : 2022-07-15
Scanning the drive:
1 file, 7 bytes (1 KiB)
Creating archive: hello.7z
Add new data to archive: 1 file, 7 bytes (1 KiB)
Files read from disk: 1
Archive size: 133 bytes (1 KiB)
Everything is Ok
PS C:\tools> ls
Directory: C:\tools
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2022/08/01 11:00 578048 7zr.exe
-a---- 2022/08/01 11:20 133 hello.7z
-a---- 2022/08/01 11:02 7 hello.txt
PS C:\tools> ls
you need a .bat script that execute a FOR command like this:
for %%X in (*) do "7zip\App\7-Zip\7z.exe" a "%%~nX.zip" "%%X"
%%X will catch the file name of every file contained in the folder where you will execute the script (in this case V:\Backup\ and only 1 file would be processed), so %%~nX.zip will take that file name
7zip keep source file name to archive
As "capa" said, it is necessary to use shell commands, because 7zip does not provide a command for this case.
The following edited command is available in order to operate with *.bak files and it is working for "7z" compression extension. It is more efficient than "zip" format in compression rate.
7z Format
FOR %%I IN (.bak) DO "c:\Program Files\7-Zip\7z.exe" a -t7z %%~nI.7z %%~nI.
zip Format
FOR %%I IN (.bak) DO "c:\Program Files\7-Zip\7z.exe" a -tZip %%~nI.zip %%~nI.
In the above commands the " * " symbol before .bak is not appeared. Please add it!
Also add the " * " to the end of each command.
*Create a "bat" file for example "compressbak.bat" on *.bak files directory, copy and paste the preferred command(7z or zip), "Save" the content on "compressbak.bat"! This will create named archives of *.bak files in the same folder that *.bak files saved. Also if you running on Windows x64 and you have a x86 version of 7-Zip you have to follow the right path in order to call the 7z.exe file. "c:\Program Files (x86)\7-Zip\7z.exe"
Folder and bat file content!
I hope that it helps you!!!
FindFirst/FindNext is slow. I see program like Defraggler can gather this list quickly. What Windows API they use ?
You are saying "FindFirst/FindNext" is slow. I think in terms of execution, _findfirst(), _findnext(), _findclose() #include <io.h> is as fast as it gets.
If you need very long path names, you need to use the Windows API version.
The Windows API is FindFirstFile(), FindNextFile(), and FindClose(), and the header file is #include <windows.h>.
The documentation for the Windows API tells you how to prepend "\?\" to the directory strings and get the maximum possible path length.
If you need more information than the C Library functions give you, then you need to use the Windows API FindFirstFileEx(), FindNextFileEx(), FindClose().
I have to refer you to the documentation for the details.
Simplest, C Library, _findfirst(): https://msdn.microsoft.com/en-us/library/zyzxfzac.aspx
More Info returned, Maximum path lengths, Windows API FindFirstFile(): https://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx
Maximum Info returned, Maximum path lengths, Windows API FindFirstFileEx():
https://msdn.microsoft.com/en-us/library/windows/desktop/aa364419(v=vs.85).aspx
If the links are no longer valid, you probably can search something like "C Language _findfirst()", etc.
Not sure about Defraggler; however you could use powershell
If you are on a windows xp system you will have to download and install it
with powershell you can preform a simple query
for example:
$foo = Get-childItem -Path "c:\windows"
in powershell this will put all of the file names in the windows directory into an array called $foo
you can then go further and take the array and pipe it into a file
$foo >> c:\temp\test.txt
Example output:
Mode LastWrite Time Length Name
---- ------------- ------ ----
d---- 7/14/2009 1:32 AM Web
d---- 5/9/2012 3:20 AM winsxs
-a--- 2/3/2012 1:01 PM 16896 AsTaskSched.dll
-a--- 4/6/2011 12:46 AM 32200 atiogl.xml
-a--- 2/3/2012 12:35 PM 0 ativpsrm.bin
-a--- 11/20/2010 10:24 PM 71168 bfsvc.exe
-a--s 5/24/2012 10:17 PM 67584 bootstat.dat
-a--- 3/21/2012 11:58 PM 1908 diagerr.xml
-a--- 3/21/2012 11:58 PM 1908 diagwrn.xml
-a--- 5/4/2012 6:19 PM 28406 DirectX.log
For more info on powershell checkout
http://technet.microsoft.com/en-us/library/bb978526.aspx