I want to write all paths stored in quick access to a text file. With a normal folder this would not be a problem. But "quick access" is not a folder and I don't know how to read what is inside.
You can use COM for this:
$shell = New-Object -ComObject Shell.Application
$paths = $shell.Namespace("shell:::{679f85cb-0220-4080-b29b-5540cc05aab6}").Items() | ForEach-Object { $_.Path }
# view on screen
$paths
# write to text file
$paths | Set-Content -Path 'X:\MyQuickAccessPaths.txt'
# don't forget to remove the used COM object from memory when done
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Related
I want to move all images in a directory, including subdirectories, to a new location while maintaining the existing folder structure.
Following the example, here, I put the objects into a variable, like so:
$picMetadata = Get-FileMetaData -folder (Get-childitem K:\myImages -Recurse -Directory).FullName
The move must be based on the results of a logical expression, such as the following for example.
foreach ($test01 in $picMetadata) {
if ($test01.Height -match "^[0-9]?[0-9] ") {
Write-Host "Test01.Height:" $test01.Height
}
}
Still at an early testing phase So far, I'm having no success even testing for the desired files. In the example above, I thought this simple regex test might provide for anything from "1 pixels" to "99 pixels", which would at least slim down my pictures collection (e.g. an expression without the caret, like "[0-9][0-9] " will return "NN pixels" as well as "NNN Pixels", "NNNNNN pixels", etc.)
Once I figure out how to find my desired images based on a logical, image object dimensions test, I will then need to create a script to move the files. Robocopy /MOV would be nice, but i'm probably in over my head already.
I was going to try to base it on this example (which was provided to a User attempting to COPY (not move / copy/delete) *.extension files). Unfortunately, such a simple operation will not benefit me, as I wish to move .jpg,.png,.gif, etc, based on dimensions not file extension:
$sourceDir = 'K:\myImages\'
$targetDir = ' K:\myImages_psMoveTest\'
Get-ChildItem $sourceDir -filter "*" -recurse | `
foreach{
$targetFile = $targetDir + $_.FullName.SubString($sourceDir.Length);
New-Item -ItemType File -Path $targetFile -Force;
Copy-Item $_.FullName -destination $targetFile
}
Perhaps you have a powershell script that could be used for my intended purpose? I'm just trying to move smaller images out of my collection, without having to overwrite same name images, and lose folder structure, etc.
Thank you very much for reading, and any advisory!
(Edit: Never opposed to improving Powershell skill, if you are aware of a freeware software which would perform this operation, please advise.)
If I understand your question correctly, you want to move image files with a pixel height of 1 up to 99 pixels to a new destination folder, while leaving the subfolder structure intact.
If that is true, you can do:
# needed to use System.Drawing.Image
Add-Type -AssemblyName System.Drawing
$sourceDir = 'K:\myImages'
$targetDir = 'K:\myImages_psMoveTest'
Get-ChildItem $sourceDir -File -Recurse | ForEach-Object {
$file = $_.FullName # need this for when we hit the catch block
try {
# Open image file to determine the pixelheight
$img = [System.Drawing.Image]::FromFile($_.FullName)
$height = $img.Height
# dispose of the image to remove the reference to the file
$img.Dispose()
$img = $null
if ($height -ge 1 -and $height -le 99) {
$targetFolder = Join-Path -Path $targetDir -ChildPath $_.DirectoryName.Substring($sourceDir.Length)
# create the target (sub) folder if it does not already exist
$null = New-Item -Path $targetFolder -ItemType Directory -Force
# next move the file
$_ | Move-Item -Destination $targetFolder -ErrorAction Stop
}
}
catch {
Write-Warning "Error moving file '$file': $($_.Exception.Message)"
}
}
I need to periodically scan a folder for new fontfiles to install and delete them afterwards using a powershell script.
During processing I want to skip already installed files and to achieve that I need to resolve the "real" fontname of the provided file.
I figured out everything and it seems to work everything but the file deletion.
The deletion did work until I added the font name resolution using this GlythTypeInterface Object. It seems like the invoked object does "file lock" the fontfile resulting in an UnauthorizedAccessException.
Thats why I tried some garbage collection stuff I found but I can't make it work.
My code so far:
Add-Type -AssemblyName PresentationCore
$FONTS = 0x14
$Path="C:\_fonts_to_install"
$FontItem = Get-Item -Path $Path
$FontList = Get-ChildItem -Path "$FontItem\*" -Include ('*.fon','*.otf','*.ttc','*.ttf')
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace($FONTS)
$Fontdir = dir $Path
$username = $env:UserName
foreach($File in $FontList) {
$try = $true
$installedFonts = #(Get-ChildItem C:\Users\$username\AppData\Local\Microsoft\Windows\Fonts | Where-Object {$_.PSIsContainer -eq $false} | Select-Object basename)
$fontObject = New-Object -TypeName Windows.Media.GlyphTypeface -ArgumentList $File.fullname
$fontName = $fontObject.Win32FamilyNames.Values
Write-Host $fontName
$fontObject = $null
Remove-Variable fontObject
foreach($font in $installedFonts)
{
if ($font -match $fontName)
{
$try = $false
}
}
if ($try)
{
$objFolder.CopyHere($File.fullname)
}
Write-Host $File
Remove-Item $File -Force -Verbose
}
I want to read the Body of the email file (.msg) in a powershell script, however I can only open it once because the file is "locked" or already opened, so there is an error the 2nd time.
My Code:
Get-ChildItem $scriptPath -Filter *.msg |
ForEach-Object {
$outlook = New-Object -comobject outlook.application
$msg = $outlook.Session.OpenSharedItem($_.FullName)
$msg | Select-Object -ExpandProperty Body
$outlook.Quit()
}
Error is: The file XXX cant be opened. Maybe it is already opened....
Thanks in advance
I know it's an old thread, but its the top when searching for this issue. This is what worked for me:
Get-ChildItem $scriptPath -Filter *.msg |
ForEach-Object {
$outlook = New-Object -comobject outlook.application
$msg = $outlook.Session.OpenSharedItem($_.FullName)
$msg | Select-Object -ExpandProperty Body
$msg.Close(1) # oldispose
$msg = $null
}
Which Outlook version do you use?
There's a bug in Outlook and a workaround is to mark the .msg files with readonly attribute.
I need to convert batches of TIFF images to JPEGs. Can it be done with plain vanilla PowerShell, without installing ImageMagick?
After a little research here and here, it seems it can be done. First, by loading a .NET Framework assembly:
[Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”);
But since I'm saving the converted image in a different directory, removing the first four characters of the filename, and changing the extension to jpg, I'm stuck with the syntax:
Get-ChildItem *.tif | %{ $file = new-object System.Drawing.Bitmap($_.FullName); $file.Save({ Join-Path "C:\Users\oscar\Downloads\" ($_.Name -replace '^.{4}(.*?)', '$1.jpg') },"JPEG") }
I get an "invalid characters in path name" error.
I'm not sure if your problem is situated in conversion or creating the new file name. If file name creation is the problem you can try following. Example:
PS C:\temp> "test.txt" -replace "txt", "somethingOther"
In your case:
Get-ChildItem -Include *.tif | %{ $file = new-object System.Drawing.Bitmap($_.FullName); $file.Save(( Join-Path "C:\Users\oscar\Downloads\" ($_.Name -replace "tif", 'jpg') ),"JPEG") }
I also replaced the curly brackets through normal one (at Join-Path).
Hope that helps
I don't like one liners while explaining things.
This script includes the needed .substring(4) for the new file name:
[void] [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$DestDir = "C:\Users\oscar\Downloads\"
$SrcDir = "X:\test\path"
PushD $SrcDir
Get-ChildItem *.tif |
ForEach-Object{
$NewFileName = ( Join-Path $DestDir ($_.BaseName.SubString(4)+'.jpg' ))
$Picture = new-object System.Drawing.Bitmap($_.FullName)
$Picture.Save($NewFileName ,"JPEG")
}
PopD
i am trying to loop through all files no matter the type, in a folder, and change a string with one that is input by the user..
i can do this now, with the code below, but only with one type of file extension..
This is my code:
$NewString = Read-Host -Prompt 'Input New Name Please'
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$InputFiles = Get-Item "$scriptPath\*.md"
$OldString = 'SolutionName'
$InputFiles | ForEach {
(Get-Content -Path $_.FullName).Replace($OldString,$NewString) | Set-Content -Path $_.FullName
}
echo 'Complete'
How do i loop through the files, no matter the extension ?
so no matter if it is a md, txt or cshtml or some other, it will replace the string as instructed.
To get all the files in a folder you can get use Get-ChildItem. Add the -Recurse switch to also include files inside of sub-folders.
E.g. you could rewrite your script like this
$path = 'c:\tmp\test'
$NewString = Read-Host -Prompt 'Input New Name Please'
$OldString = 'SolutionName'
Get-ChildItem -Path $path | where {!$_.PsIsContainer} | foreach { (Get-Content $_).Replace($OldString,$NewString) | Set-Content -Path $_.FullName }
this will first get all the files from inside the folder defined in $path, then replace the value given in $OldString with what the user entered in when prompted and finally save the files.
Note: the scripts doesn't make any difference regarding if the content of the files changed or not. This will cause all files modified date to get updated. If this information is important to you then you need to add a check to see if the files contains the $OldString before changing them and saving.