I am trying to delete an image based on the dimensions of said image, but I've run into a problem.
I am trying to delete images whose length or width are less than 490 pixels. However, the code I have tried throws an error for every item. This is the error:
Remove-Item : Cannot remove item (file path): The process cannot access the file
'(file path)' because it is being used by another process.
At line:6 char:9
+ Remove-Item $_
+ ~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: ((file path):FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Here is my code:
[Void][Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$(Get-ChildItem -Filter *.jpg).FullName | ForEach-Object {
$img = [Drawing.Image]::FromFile($_);
If (($img.Width -lt 490) -or ($img.Height -lt 490)) {
Remove-Item $_
}
}
I am not running any apparent processes that would be using the images. When using Handle64, it says that powershell.exe is using the files. Any help would be appreciated!
The $img object is keeping the file in use, so you need to dispose of that before you can delete the file:
Add-Type -AssemblyName System.Drawing
(Get-ChildItem -Filter '*.jpg' -File).FullName | ForEach-Object {
$img = [System.Drawing.Image]::FromFile($_)
$w = $img.Width
$h = $img.Height
# get rid of the Image object and release the lock on the file
$img.Dispose()
If (($w -lt 490) -or ($h -lt 490)) {
Remove-Item -Path $_
}
}
Related
I am trying to get a script working to audit folder permissions on a Windows server, among other data, and export this data to a CSV file for analysis after a ransomware attack.
I ripped the script from a forum, but it did not run correctly as is. Below is a slightly modified version during my troubleshooting.
I am well versed in batch scripting, and have a decent understanding of loops and pipelining, but this Powershell script has me scratching my head.
It seems like the array is not making it to the nested loop.
I am testing in Windows 10 Pro 21H1, using Powershell version 5.1.19041.1320, build 10.0.19041.1320
##The script:
$ErrorActionPreference = "Continue"
$strComputer = $env:ComputerName
$colDrives = Get-PSDrive -PSProvider Filesystem
ForEach ($DriveLetter in $colDrives) {
$StartPath = "$DriveLetter`:\"
Get-ChildItem -LiteralPath $StartPath -Recurse | ?{ $_.PSIsContainer } |
ForEach ($FullPath = Get-Item -LiteralPath{Get-Item -LiteralPath $_.PSPath}{Get-Item -
LiteralPath $FullPath}.Directoryinfo.GetAccessControl())}
Select #{N='Server Name';E={$strComputer}}
#{N='Full Path';E={$FullPath}}
#{N='Type';E={If($FullPath.PSIsContainer -eq $True) {'D'} Else {'F'}}}
#{N='Owner';E={$_.Owner}}
#{N='Trustee';E={$_.IdentityReference}}
#{N='Inherited';E={$_.IsInherited}}
#{N='Inheritance Flags';E={$_.InheritanceFlags}}
#{N='Ace Flags';E={$_.PropagationFlags}}
#{N='Ace Type';E={$_.AccessControlType}}
#{N='Access Masks';E={$_.FileSystemRights}}
Export-CSV -NoTypeInformation -Delimiter "|" -Path "$strComputer`_$DriveLetter.csv"
##The error I am getting:
You cannot call a method on a null-valued expression.
At C:\Users\user\Documents\fileaudit2.ps1:8 char:13
ForEach ($FullPath = Get-Item -LiteralPath{Get-Item -LiteralPath $ ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidOperation: (:) [], RuntimeException
FullyQualifiedErrorId : InvokeMethodOnNull
##when I modify the nested loop as follows:
ForEach ($FullPath = Get-Item -LiteralPath{Get-Item -LiteralPath $_.PSPath}{Get-Item -LiteralPath $FullPath}).Directoryinfo.GetAccessControl()}
##I get the error:
Get-Item : Cannot evaluate parameter 'LiteralPath' because its argument is specified as a script block and there is no input. A script block cannot be evaluated without
input.
At C:\Users\user\Documents\fileaudit2.ps1:8 char:46
... Path = Get-Item -LiteralPath{Get-Item -LiteralPath $_.PSPath}{Get-Ite ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : MetadataError: (:) [Get-Item], ParameterBindingException
FullyQualifiedErrorId : ScriptBlockArgumentNoInput,Microsoft.PowerShell.Commands.GetItemCommand
##I'm just wholly struggling to understand what is not working in this loop.
You are mixing a lot of unneeded Get-Item calls in there.
I also would not use Get-PSDrive for this because I assume you don't want to get results for CD drives, USB devices etc in the report.
Try:
# this returns drives WITH a trailing backslash like C:\
$colDrives = ([System.IO.DriveInfo]::GetDrives() | Where-Object { $_.DriveType -eq 'Fixed' }).Name
# or use:
# this returns drives WITHOUT trailing backslash like C:
# $colDrives = (Get-CimInstance -ClassName win32_logicaldisk | Where-Object { $_.DriveType -eq 3 }).DeviceID
$result = foreach ($drive in $colDrives) {
Get-ChildItem -LiteralPath $drive -Directory -Recurse -ErrorAction SilentlyContinue |
ForEach-Object {
$path = $_.FullName
$acl = Get-Acl -Path $path
foreach ($access in $acl.Access) {
[PsCustomObject]#{
Server = $env:COMPUTERNAME
Drive = $drive[0] # just the first character of the drive
Directory = $path
Owner = $acl.Owner
Trustee = $access.IdentityReference
Inherited = $access.IsInherited
InheritanceFlags = $access.InheritanceFlags -join ', '
'Ace Flags' = $access.PropagationFlags -join ', '
'Ace Type' = $access.AccessControlType
'Access Masks' = $access.FileSystemRights -join ', '
}
}
}
}
# now you can save your result as CSV file for instance you can double-click to open in Excel:
$result | Export-Csv -Path 'X:\WhereEver\audit.csv' -NoTypeInformation -UseCulture
To do this on several remote machines, wrap it inside Invoke-Command
# set the credentials for admin access on the servers
$cred = Get-Credential 'Please enter your admin credentials'
# create an array of the servers you need to probe
$servers = 'Server01', 'Server02'
$result = Invoke-Command -ComputerName $servers -Credential $cred -ScriptBlock {
$colDrives = ([System.IO.DriveInfo]::GetDrives() | Where-Object { $_.DriveType -eq 'Fixed' }).Name
foreach ($drive in $colDrives) {
# code inside this loop unchanged as above
}
}
# remove the extra properties PowerShell added
$result = $result | Select-Object * -ExcludeProperty PS*, RunspaceId
# output to csv file
$result | Export-Csv -Path 'X:\WhereEver\audit.csv' -NoTypeInformation -UseCulture
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 am trying to understand what this error actually means. I am new to PowerShell and cannot
figure this one out. I have searched for similar questions but the content differs to my
requirement.
In a nut shell the script is queering a data historian system for a batch/lot number and the
start time of that batch.
This script will run every minute using task scheduler. This has not been set up yet as I am
still in the testing phase.
I have set up a service account is order for the script to run. The details of which are
stored in a cred file.
The script creates a folder using this batch/lot number.
The script creates a log file with the batch number and the start date and time of the batch.
Then the script searches a source folder on the server when a file is uploaded from the
factory floor into the source folder the script moves the file into the already created folder
with the correct batch number.
If files that are outside of the batch start and end time then the files are moved to no batch
folder where they will be reviewed manually.
I have done tests whereby I manually added files to the source folder on the server and
everything worked and did not get the "a positional parameter cannot be found that accepts
argument "+" from the script.
I am looking into the server configuration and permission levels but to my knowledge, nothing
has changed. I cannot see what is wrong with the script but hopefully, someone can give me
some pointers.
Error Code below
`PS C:\Users\a-graydx2> E:\Kistler Script\Batch ID with log 2021-11-29.ps1
An error occurred:
Key not valid for use in specified state.
Add-Content : A positional parameter cannot be found that accepts argument '+'.
At E:\Kistler Script\Batch ID with log 2021-11-29.ps1:186 char:11
+ Add-Content -Path $ErrorFileName -Value (Get-Date -Format " ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Add-Content], ParameterBindingException
+ FullyQualifiedErrorId :
PositionalParameterNotFound,Microsoft.PowerShell.Commands.AddContentCommand
An error occurred:
Key not valid for use in specified state.
Add-Content : A positional parameter cannot be found that accepts argument '+'.
At E:\Kistler Script\Batch ID with log 2021-11-29.ps1:186 char:11
+ Add-Content -Path $ErrorFileName -Value (Get-Date -Format " ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Add-Content], ParameterBindingException
+ FullyQualifiedErrorId :
PositionalParameterNotFound,Microsoft.PowerShell.Commands.AddContentCommand`
Script is below
Thanks for your help
`# Declare global variables
$fmSourcePath = "E:\Kistler\CoMo Services\Data\5336_L1.4345277\"
$shSourcePath = "E:\Kistler\CoMo Services\Data\5338_L1.5338_L1\"
$fmDesinationPath = "E:\Kistler XML Files\FM\"
$shDesinationPath = "E:\Kistler XML Files\SH\"
$fmWebAPI = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$shWebAPI = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# the path to stored credential
$credPath = "E:\Kistler Script\Cred.xml"
$logFileName = "BatchLog.txt"
#Path to the error log file
$ErrorFileName = "E:\Kistler Script\errorlog.txt"
function Move_Kistler_Files {
param (
[string]$url,
[string]$SourcePath,
[string]$DestinationPath
)
try {
# check for stored credential
if ( Test-Path $credPath ) {
#crendetial is stored, load it
$cred = Import-CliXml -Path $credPath
} else {
# no stored credential then: create store, get credential and save it
$parent = split-path $credpath -parent
if ( -not ( test-Path $parent ) ) {
New-Item -ItemType Directory -Force -Path $parent
}
$cred = get-credential
$cred | Export-CliXml -Path $credPath
}
# Get the current batch id using the Web-API call
$result = Invoke-RestMethod -Uri $url -Credential $Cred
$BatchID = $result.Value
$BatchFolder = $DestinationPath + $BatchID
Write-Host $BatchFolder
# Create a new folder in the destination path based on the Batch ID
If(!(test-path $BatchFolder))
{
New-Item -ItemType Directory -Force -Path $BatchFolder | Out-Null
# Add the current date/time to the log file
$LogFile = $DestinationPath + $logFileName
# if file exist Update the last record with the batch end date
If((test-path $LogFile)){
$txt = get-content $LogFile
$txt[$txt.length - 1 ] = $txt[$txt.length - 1 ] + ", " + (Get-Date)
$txt | set-content $LogFile
}else{
#add a header row in the file
Add-Content -Path $LogFile -Value "BatchID, StartDate, EndDate"
}
# create a new record in the log file with current Batch Id and date as start of
batch indicator
$msg = $BatchID + ", " + (Get-Date)
Add-Content -Path $LogFile -Value $msg
}
##############################################################################
# Copy the Kistler XML files from the source to the destination
##############################################################################
# get al the Kistler XML files in the source folder
$Files = get-childitem -path $SourcePath -Recurse | Where-Object {$_.Extension -eq ".XML"}
| Sort-Object LastWriteTime -Descending
# If we have files to process do it
if ($Files.Length -gt 0) {
# read back the batch start and end dates from the log table
$LogFile = $DestinationPath + $logFileName
$txt = get-content $LogFile
# Get the latest Batch Id and it's start date
$FileMoveCount = 0
$FileNotMoveCount = 0
$ptr = 1
$batchArray =$txt[$txt.length - $ptr ].Split(",")
$MoveToPath = $DestinationPath + $batchArray[0]
$batchStartDate = $batchArray[1]
#Process each XML file
Foreach ($File in $Files ) {
$FileTime = $File.LastWriteTime
#write-host $File.FullName $File.Name $FileTime $MoveToPath $batchStartDate
#if the XML file's date-time is older than the batch start time, skip to the
previus Batch Id and start time
while ( ([DateTime]$FileTime -lt [DateTime]$batchStartDate) -and ($ptr -lt
($txt.length)-1) ) {
#Write a log for the number of files copied
if ($FileMoveCount -gt 0){
Add-Content -Path $ErrorFileName -Value ((Get-Date -Format "dd/MM/yyyy
HH:mm") + ": " + $FileMoveCount + " XML files moved to " + $MoveToPath)
$FileMoveCount = 0
}
$ptr++
$batchArray =$txt[$txt.length - $ptr ].Split(",")
$MoveToPath = $DestinationPath + $batchArray[0]
$batchStartDate = $batchArray[1]
#write-host $MoveToPath $batchStartDate
}
#Copy the XML file to the destination folder
if ([DateTime]$FileTime -ge [DateTime]$batchStartDate){
Move-Item $File.FullName -Destination ($MoveToPath + "\" + $File.Name)
$FileMoveCount++
}else{
Move-Item $File.FullName -Destination ($DestinationPath + "\NoBatch\" +
$File.Name)
$FileNotMoveCount++
}
}
#Write a log for the number of files copied
if ($FileMoveCount -gt 0){
Add-Content -Path $ErrorFileName -Value ((Get-Date -Format "dd/MM/yyyy HH:mm") + ": "
+ $FileMoveCount + " XML files moved to " + $MoveToPath)
}
if ($FileNotMoveCount -gt 0){
Add-Content -Path $ErrorFileName -Value ((Get-Date -Format "dd/MM/yyyy HH:mm") + ":
Could not find batch ID for " + $FileNotMoveCount + " XML files " )
}
}
}catch{
#Write the error
Write-Host "An error occurred:" -ForegroundColor red
Write-Host $_ -ForegroundColor red
Add-Content -Path $ErrorFileName -Value (Get-Date -Format "dd/MM/yyyy HH:mm") + ": " +
$_
}
}
### Process the FM Kistler files
Move_Kistler_Files $fmWebAPI $fmSourcePath $fmDesinationPath
### Process the SH Kistler files
Move_Kistler_Files $shWebAPI $shSourcePath $shDesinationPath`
all.
I'm stuck. I have a PowerShell script which looks to a specific folder for files which are older than 30 days from the last modified date (additionally, it'll create the folder if it doesn't exist). It creates the folder, it gives me the total files, it'll list all of the files in a test query, but it won't actually count the number of 30+ day old files. I've tried several methods to get this count (some deriving from other solutions to delete old files from this site), but PowerShell just doesn't want to do it.
Here's my code so far...
$HomePath = $env:USERPROFILE
$CompanyFolder = "\Company"
$TimeSensativeFolder = "\TimeSensative"
$TimeSensativePath = $HomePath+$CompanyFolder+$TimeSensativeFolder
$OldFilesAmount = 0
$TotalFilesAmount = 0
$TimeLimit = (Get-Date).AddDays(-30)
$StatusOK = "No old files were found in the time sensative folder."
$StatusCreated = "The time sensative folder was created."
$StatusError1 = "There were old files found in the time sensative folder!"
$StatusError2 = "Unable to create the time sensative folder!"
function MakeTimeSensativeFolder ($TimeSensativePath) {
try {
md $TimeSensativePath -Force -ErrorAction Stop
Write-Host $StatusCreated
}
catch {
Write-Host $StatusError2
}
}
function CountOldFiles () {
$OldFilesAmount = $OldFilesAmount + 1
}
if(!(Test-Path $TimeSensativePath -PathType Container)) {
MakePHIFolder $TimeSensativePath
}
else {
}
try {
$TotalFilesAmount = (Get-ChildItem $PHIPath -Recurse -File | Measure-Object).Count
# I've tried this...
Get-Item $PHIPath | Foreach {$_.LastWriteTime} -ErrorAction Stop
if (Get-Content $_.LastWriteTime | Where-Object {$_ -gt $TimeLimit}) {
CountOldFiles
}
# And I've tried this...
Get-ChildItem -Path $PHIPath -Recurse -File | Foreach-Object {
if (Get-Content $_.LastWriteTime | Where-Object {$_ -gt $TimeLimit}) {
CountOldFiles
}
}
# I've even tried this...
Get-ChildItem $PHIPath -Recurse -File | ? {
-not $_.PSIsContainer -and $_.LastWriteTime -lt $TimeLimit
} | CountOldFiles
# And this, as well...
Get-ChildItem -Path $PHIPath -Recurse -File | Where-Object {$_.LastWriteTime -gt $TimeLimit} | CountOldFiles
}
catch {
MakeTimeSensativeFolder $TimeSensativePath
}
# Used for testing.
<#
Get-ChildItem $TimeSensativePath -Recurse -File
Write-Host "TimeSensative folder exists:" $TimeSensativePathExists
Write-Host "Home TimeSensative path:" $TimeSensativePath
Write-Host "Old files found:" $OldFilesAmount
Write-Host "Total files found:" $TotalFilesAmount
Exit
#>
# Determining proper grammar for status message based on old file count.
if ($OldFilesAmount -eq 1) {
$StatusError1 = "There was "+$OldFilesAmount+" old file of "+$TotalFilesAmount+" total found in the PHI folder!"
}
if ($OldFilesAmount -gt 1) {
$StatusError1 = "There were "+$OldFilesAmount+" old files of "+$TotalFilesAmount+" total found in the PHI folder!"
}
# Give statuses.
if ($OldFilesAmount -gt 0) {
Write-Host $StatusError1
}
else {
Write-Host $StatusOK
}
Depending on which I tried, I would get no result or I'd get something like this:
Get-Content : Cannot find drive. A drive with the name '12/22/2016 17' does not exist.
At C:\Users\nobody\Scripts\PS1\ts_file_age.ps1:54 char:14
+ if (Get-Content $_.LastWriteTime | Where-Object {$_ -gt $Tim ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (12/22/2016 17:String) [Get-Content], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetContentCommand
In any instance, there's no old file count as I'm endeavoring to demand.
It's been a bit of a head scratcher. Any advice?
Thanks so much in advance!
Filtering files with last write time is easy enough. Like so,
$allFiles = gci
$d = (Get-Date).adddays(-30)
$newFiles = #()
$oldFiles = #()
$allFiles | % { if ($_.lastwritetime -ge $d) { $newFiles +=$_ } else { $oldFiles += $_ } }
What's done here is that first all the files are set in a collection. This isn't mandatory, but one can browse the collection to check that it's been populated properly. This is useful in cases one has complex paths or exclusion filters.
The second step is just to get a DateTime that is used later to divide files into old and new ones. Just like the sample did, so nothing interesting here. Actually, there's one little thing. The date is -30 days, but hours, minutes and seconds are based on current time. So if there's really tight limit, consider using midnight time ([datetime]::Today).AddDays(-30)
The third step is to declare two empty collections for new and old files.
The last step is to iterate through the $allFiles and check the last write time. If it's greater or equal to the cutpoint, add it into $newFiles, othervise $OldFiles.
After the last step, further processing should be simple enough.
This is what I do to get (delete in this case) files older than X days:
$Days = 5
$limit = (Get-Date).AddDays(-$Days)
$CurrentDate = Get-Date
#This will delete all files older than 5 days
Get-ChildItem -Path $Workdir -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.LastWriteTime -lt $limit } | Remove-Item -Force
# ---------------------------------------------------------
# ScriptingGamesBeginnerEvent8_PS1.ps1
# ed wilson, msft 8/21/2009
# PS1 version of HSG-08-19-09 http://bit.ly/1d8Rww
#
# ---------------------------------------------------------
Param(
[string]$path = 'C:\',
[int]$first = 50
)# end param
# *** Function Here ***
function Get-DirSize ($path){
BEGIN {}
PROCESS{
$size = 0
$folders = #()
foreach ($file in (Get-ChildItem $path -Force -ea SilentlyContinue)) {
if ($file.PSIsContainer) {
$subfolders = #(Get-DirSize $file.FullName)
$size += $subfolders[-1].Size
$folders += $subfolders
} else {
$size += $file.Length
}
}
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name Folder -Value (Get-Item $path).fullname
$object | Add-Member -MemberType NoteProperty -Name Size -Value $size
$folders += $object
Write-Output $folders
}
END {}
} # end function Get-DirSize
Function Get-FormattedNumber($size)
{
IF($size -ge 1GB)
{
"{0:n2}" -f ($size / 1GB) + " GigaBytes"
}
ELSEIF($size -ge 1MB)
{
"{0:n2}" -f ($size / 1MB) + " MegaBytes"
}
ELSE
{
"{0:n2}" -f ($size / 1KB) + " KiloBytes"
}
} #end function Get-FormattedNumber
# *** Entry Point to Script ***
if(-not(Test-Path -Path $path))
{
Write-Host -ForegroundColor red "Unable to locate $path"
Help $MyInvocation.InvocationName -full
exit
}
Get-DirSize -path $path |
Sort-Object -Property size -Descending |
Select-Object -Property folder, size -First $first |
Format-Table -Property Folder,
#{ Label="Size of Folder" ; Expression = {Get-FormattedNumber($_.size)} }
So I have this script which I got from
http://gallery.technet.microsoft.com/scriptcenter/36bf0988-867f-45be-92c0-f9b24bd766fb#content
I've been playing around with it and created a batch file to help handle the log output of this file and such. However, I'm noticing that paths with spaces in them don't get read. For example ..Documents\My Music
Get-Item : Could not find item C:\Users\MyUser\Documents\My Music.
At C:\test.ps1:32 char:80
+ $object | Add-Member -MemberType NoteProperty -Name Folder -Value (Get-It
em <<<< $path).fullname
+ CategoryInfo : ObjectNotFound: (C:\Users\MyUser\Documents\My
Music:String) [Get-Item], IOException
+ FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetIt
emCommand
On the TechNet page for the code, someone brings the issue up but no solution is given. I'm not sure how to fix it here. I've played with the $path argument, surrounding it in " " or ' ' and such.
Here is part of the batch file to execute it:
C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -noe -command "& 'C:\test.ps1' -path "'C:\Users\MyUser\'""
Might be a bit late for answer here, but, as Aaron mentioned, this is not due to spaces in the path.
If you read the documentation for Get-Item cmdlet, there is a -Force switch, which allows the cmdlet to get items that cannot otherwise be accessed, such as hidden items.
Moreover, it seems from your code that you are not expecting to pass a wildcard pattern to the cmdlet, so instead of (Get-Item $path).FullName you should use
(Get-Item -force -LiteralPath $path).FullName
That should resolve this issue.
It's not the spaces in the path. If it was, the error would say path C:\Users\MyUser\Documents\My couldn't be found. Get-ChildItem and Get-Item behave... strangely... with certain files/directories, returning errors like you're seeing. That's why Get-ChildItem has an -ErrorAction SilentlyContinue parameter on it. I would add the same to the call to Get-Item, i.e. change
(Get-Item $path).FullName
to
(Get-Item $path -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName
or even forgo the call to Get-Item completely:
$path
As suggested by TheTrowser in a comment above: The problem may be resolved if you replace the double-quotes with single quotes surrounding the file directory with spaces. This is what solved it for me.
Using the command below didn't work for me.
get-item 'some path with two spaces.txt'
Enclosing the filename in double quotes within the single quotes, forces Powershell to use the filename as written.
get-item '"some path with two spaces.txt"'
Note: I'm totally cringing at my origal message (cleaned up a bit above). Below is a better example of what I was seeing.
$exampleA = "c:\temp\weird path\blah.txt"
$exampleB = "c:\temp\normal path\blah.txt"
# Works
get-item '$exampleA'
get-item $exampleB
# Fails
get-item $exampleA