Powershell Remove-Item item is Null when using get-childitem - powershell

I am having trouble with the following script, which liberally makes use of pipelines:
$date = Get-Date -date "12/31/2010 00:00 AM" -format MM-dd-yyyy
$TDrive = "C:\Users\xxxx\Desktop"
(get-childitem -path $Tdrive -recurse -force -ErrorAction SilentlyContinue) |
?{ $_.fullname -notmatch "\\Alina_NEW\\?" } |
?{ $_.fullname -notmatch "\\!macros\\?" } |
?{ $_.fullname -notmatch "\\DO_NOT_DELETE\\?" } |
Where-Object {$_.LastAccessTime -lt $date} |
Remove-Item $_
I am getting the following error when I run this, meaning that the $_ is null:
Remove-Item : Cannot bind argument to parameter 'Path' because it is null.
At line:13 char:13
+ Remove-Item $_
+ ~~
+ CategoryInfo : InvalidData: (:) [Remove-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.R
emoveItemCommand
What I am not understanding is, why would the path ever be null? This is all one fluid pipeline, and the value of $_ should persist through the entire pipeline, should it not?
My only thought is that when the where-object finds a file that is not less than that date, it returns null through the rest of the pipeline. I believe this error happens pre-execution, however, so there is a more fundamental problem here.
The point of this script is to delete all files not in the directories listed, that are older than 12/31/2010.

Two things. First, you'll want to Remove-Item Foreach of the files gci finds. Second, Remove-Item takes a path. Try something like this:
$date = Get-Date -date "12/31/2010 00:00 AM" -format MM-dd-yyyy
$TDrive = "C:\Users\xxxx\Desktop"
(get-childitem -path $Tdrive -recurse -force -ErrorAction SilentlyContinue) |
?{ $_.fullname -notmatch "\\Alina_NEW\\?" } |
?{ $_.fullname -notmatch "\\!macros\\?" } |
?{ $_.fullname -notmatch "\\DO_NOT_DELETE\\?" } |
Where-Object {$_.LastAccessTime -lt $date} |
% {Remove-Item $_.FullName -WhatIf}

Related

Powershell error when deleting old files and folders

I'm trying to delete some old files in an archive folder and my script works fine until it gets to the last section where it removes the empty folders (testing using -whatif initially). I get the following error:
Remove-Item : Cannot bind argument to parameter 'Path' because it is null.
At C:\ArchiveDelete.ps1:13 char:39
+ $dirs | Foreach-Object { Remove-Item <<<< $_.fullname -whatif }
+ CategoryInfo : InvalidData: (:) [Remove-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.RemoveItemCommand
Tried to find a suitable answer on here but can't find a solution (I know I may be using an older version of Powershell)
#Days older than
$HowOld = -900
#Path to the root folder
$Path = "C:\SharedWorkspace\ArchiveDSAgile"
#Deletion files task
get-childitem $Path -recurse | where {$_.lastwritetime -lt (get-date).adddays($HowOld) -and -not $_.psiscontainer} |% {remove-item $_.fullname -force -whatif}
#Deletion empty folders task
do {
$dirs = gci $Path -recurse | Where { (gci $_.fullName -Force).count -eq 0 -and $_.PSIsContainer } | select -expandproperty FullName
$dirs | Foreach-Object { Remove-Item $_ -whatif }
} while ($dirs.count -gt 0)
None of your loops are necessary.
You can feed the output of Where-Object right into Remove-Item
$AgeCap = (Get-Date).AddDays(-900)
$Path = "C:\SharedWorkspace\ArchiveDSAgile"
Get-ChildItem $Path -Recurse -File | Where-Object LastWriteTime -lt $AgeCap | Remove-Item -WhatIf
The -File parameter for Get-ChildItem available in PowerShell 3.0 (I believe) and higher. The Workaround for PowerShell 2.0 would be checking against $_.PSIsContainer in Where-Object, as you did in your sample code.
Finally got it working:
#Days older than
$HowOld = -900
#Path to the root folder
$Path = "C:\SharedWorkspace\ArchiveDSAgile"
#Deletion files task
get-childitem $Path -recurse | where {$_.lastwritetime -lt (get-date).adddays($HowOld) -and -not $_.psiscontainer} |% {remove-item $_.fullname -force -whatif}
#Deletion empty folders task
Get-ChildItem $Path -Recurse | Where-Object {$_.lastwritetime -lt (get-date).adddays($HowOld) -and -not !$_.psiscontainer} | Remove-Item -recurse -WhatIf
Thanks for your help

One-liner to find a registry key and delete parent works but returns an error

I am using a one liner to find a registry key based on a value then delete it's parent. The one liner produces an error but if I separate the search result into a variable and run remove-item there is no error. I'd like to find out what causes this and if I should I be worried?
Produces an error:
Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurse -ErrorAction Stop | Get-ItemProperty -Name "PackageName" -ErrorAction SilentlyContinue| where { $_.PackageName -cmatch "BigFixAgent\.msi" } | Select-Object -ExpandProperty PSParentPath | Remove-Item -Recurse -confirm
Get-ChildItem : The registry key at the specified path does not exist.
At line:1 char:1
+ Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurs ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (HKEY_LOCAL_MACH...4D34\SourceList:String) [Get-ChildItem],
ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.GetChildItemCommand
Produces No Errors:
$offending_key= Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurse -ErrorAction Stop | Get-ItemProperty -Name "PackageName" -ErrorAction SilentlyContinue| where { $_.PackageName -cmatch "BigFixAgent\.msi" } | Select-Object -ExpandProperty PSParentPath
Remove-Item -Recurse $offending_key -confirm
That's because it is iterating recursively through the registry tree, and you deleted part of that tree in the middle of the iteration. You could put parenthesis around everything but the last part, so that it finishes iteration first, or you could put the last part in a ForEach-Object loop, and add a break after it so once that key is found it removes it and stops looking.
Complete Get-ChildItem iteration before deleting:
(Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurse -ErrorAction Stop | Get-ItemProperty -Name "PackageName" -ErrorAction SilentlyContinue| where { $_.PackageName -cmatch "BigFixAgent\.msi" } | Select-Object -ExpandProperty PSParentPath) | Remove-Item -Recurse -confirm
Stop after finding the first matching key:
Get-ChildItem -path HKLM:\SOFTWARE\Classes\Installer\Products -Recurse -ErrorAction Stop | Get-ItemProperty -Name "PackageName" -ErrorAction SilentlyContinue| where { $_.PackageName -cmatch "BigFixAgent\.msi" } | Select-Object -ExpandProperty PSParentPath | ForEach-Object {$_ | Remove-Item -Recurse -confirm; break}

Rename Folders After Copy

I'm having problems after a folder is copied to a different location, I need to rename the folders in the directory to remove ".deploy" from the end, but I get the following error below. I have Googled around for PowerShell admin permissions, but cannot seem to find a 'catch-all' for my scenario.
Get-Content : Access to the path 'C:\OldUserBackup\a.deploy' is denied.
At C:\PSScripts\DesktopSwap\TestMergeDir.ps1:28 char:14
+ (Get-Content $file.PSPath) |
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (C:\OldUserBackup\a.deploy:String) [Get-Content], UnauthorizedAccessException
+ FullyQualifiedErrorId : GetContentReaderUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetContentCommand
Here is what I have:
$UserName = [Environment]::UserName
$CurrUser = [Environment]::UserName + '.deploy'
$OldUserDir = 'C:\OldUserBackup'
$CurrDate = Get-Date -format G
$PathExist = Test-Path $OldUserDir
if ($PathExist -eq $true) {
#Copy Desktop, Downloads, Favorites, Documents, Music, Pictures, Videos
Copy-Item -Path $OldUserDir -Destination C:\Users\$UserName\Desktop\CopyTest -Recurse -Force
$configFiles = Get-ChildItem $OldUserDir *.deploy -rec
foreach ($file in $configFiles) {
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace ".deploy", "" } |
Set-Content $file.PSPath
}
}
You should use the -Directory switch on the Get-ChildItem cmdlet to only get directories. Then use the Rename-Item cmdlet to rename the folders. I use the -replace function with a simple regex to get the new folder name:
$deployFolders = Get-ChildItem $OldUserDir *.deploy -rec -Directory
$deployFolders | Foreach {
$_ | Rename-Item -NewName ($_.Name -replace ('\.deploy$') )
}
You don't even have to use the Foreach-Object cmdlet (Thanks to AnsgarWiechers):
Get-ChildItem $OldUserDir *.deploy -rec -Directory |
Rename-Item -NewName { $_.Name -replace ('\.deploy$') }

Parameter Binding

I'm trying to create a PowerShell script that will move XML files of a certain age to a network drive to be archived. The script thus far:
$qaprocessedpath = "Y:\SFTPSHARE\SFTPYMSQ\YS42C1Processed"
$qabackup = “\\servername\S$\xmlbackup\qa"
$max_age_qa = "-1"
$curr_date = Get-Date
$del_date_q = $curr_date.AddDays($max_age_qa)
Get-ChildItem -include *.xml $qaprocessedpath | Where-Object {$_.LastWriteTime -lt $del_date_q } | Foreach-Object {Copy-Item -Path $_.FullName -Destination $qabackup} {Remove-Item $_.FullName}
This code leads to the following error:
Copy-Item : Cannot bind argument to parameter 'Path' because it is null.
At Y:\SFTPSHARE\SFTPYMSP\XMLBackup.ps1:52 char:132
+ Get-ChildItem -include *.xml $qaprocessedpath | Where-Object { $_.LastWriteTime -lt $del_date_q } | Foreach-Object {Copy-Item -Path <<<< $_.FullName -Destination $qabackup} {Remove-Item $_.FullName}
+ CategoryInfo : InvalidData: (:) [Copy-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CopyItemCommand
Not sure where the issue is. I'm a novice scripter, so I'm sure it's something obvious...
In this line
Get-ChildItem -include *.xml $qaprocessedpath | Where-Object {$_.LastWriteTime -lt $del_date_q } | Foreach-Object {Copy-Item -Path $_.FullName -Destination $qabackup} {Remove-Item $_.FullName}
Why do you have two scriptblocks following the Foreach-Object?
Try separating the copy-item and remove-item with semicolons (in the same scriptblock) if you want them both to run. As you wrote it, the two scriptblocks are getting bound to the -Process parameter (as usual) and the -Begin parameter.

Recursively renaming files in Powershell

Calling this powershell command and getting an error. Driving me nuts.
Prompt> get-childitem -recurse ./ *NYCSCA* | where-object { $_.Name -like
"*NYCSCA*" } | rename-item $_ -newname $_.Name.Replace(" ","_") -whatif
Here is the response:
You cannot call a method on a null-valued expression.
At line:1 char:140
+ get-childitem -recurse ./ *NYCSCA* | where-object { $_.Name -like "*NYCSCA*" } | select FullName | rename-item $_ -n
ewname $_.Name.Replace <<<< (" ","_") -whatif
+ CategoryInfo : InvalidOperation: (Replace:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
If I remove the last part, I get a list of files. Any clues? I have not grocked powershell yet, obviously.
Note: I tried to post this to superuser, but the site is consistently failing now - won't let me add this exact question.
Here it is greatly simplified. I cannot even get this classic example to work.
gci *NYCSCA* | ren $_ ($_.Name).Replace("foo","bar")
Thank you #JNK, the % did it. The solution I needed is this, in case you're interested:
gci -recurse | where-object{ $_.Name -like "*NYCSCA*"} | %{rename-item $_.FullName $_.FullName.Replace("NYCSCA","SDUSD") }
I think you need foreach-object:
get-childitem -recurse ./ *NYCSCA* | where-object { $_.Name -like
"*NYCSCA*" } | % {rename-item $_ -newname $_.Name.Replace(" ","_") -whatif}
The piped array can't be renamed as a set.
Here's a simplified version to rename files only
Get-ChildItem -Filter *NYCSCA* -Recurse |
Where-Object {!$_.PSIsContainer} |
Rename-Item -NewName { $_.Name.Replace(' ','_') } -WhatIf
(Edit: line breaks added for clarity)