PowerShell GUI脚本获取子文件夹报错及远程删SQL dump文件求助
解决PowerShell GUI远程删除SQL Dump文件的报错问题
需求目标
- 远程删除大型SQL dump文件
- 启动脚本后选中父文件夹点击OK
- 再次点击OK进入其子文件夹
- 选择文件后点击OK完成删除
- 待删文件位于子文件夹的下一级子目录
报错信息
Get-ChildItem : Cannot find path 'C:\Users\Ujjwal Mandal\@{name=All Documents; Size=6.18 GB}' because it does not exist. At D:\project\test.ps1:30 char:20 + $child1= $output | Get-ChildItem | Out-GridView -Title "Select server ...
现有代码
Add-Type -AssemblyName PresentationFramework Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $TempFile = [io.path]::GetTempFileName() $form = New-Object System.Windows.Forms.Form $form.Text = "Fix low space issue" $form.size = New-Object System.Drawing.Size(900,400) $remdmp = New-Object System.Windows.Forms.Button $remdmp.Location = New-Object System.Drawing.Size(300,35) $remdmp.Size = New-Object System.Drawing.Size(300,45) $remdmp.Text = "Remove dump Files" $remdmp.Font = [System.Drawing.Font]::new('Microsoft Sans Serif', 10, [System.Drawing.FontStyle]::Bold) $remdmp.Add_Click({ Remove-Item $TempFile -ErrorAction SilentlyContinue [void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') $svrs ="TM-ND0276" $path = "\\TM-ND0276\d$\" $size = 0 $decimalPlaces = 2 $output = @() $data=Get-ChildItem -Directory $path | ForEach-Object { $size += (Get-ChildItem -Recurse $_.FullName | Measure-Object -Property Length -Sum).Sum $output += New-Object PSObject -Property @{ name = $_.Name Size = "{0:N$decimalPlaces} GB" -f ((Get-ChildItem -Recurse $_.FullName | Measure-Object -Property Length -Sum).Sum / 1GB) } } $output | Sort-Object -Descending -Property Size | Out-GridView -Title "select" -PassThru $child1= $output | Get-ChildItem | Out-GridView -Title "Select server name folder you want to delete the dump files from" -PassThru $child2= $child1 | Get-ChildItem | Out-GridView -Title "Select files you want to delete" -PassThru if($child2) { $child2 | Remove-Item -Recurse -Force $msgbox=[System.Windows.MessageBox]::Show('Dump files have been deleted. Check notepad for available free space in D drive') $dskspce=Invoke-Command -ComputerName $svrs -ScriptBlock {Get-WmiObject -Class win32_logicaldisk | Format-Table DeviceId, MediaType, @{n="Size";e={[math]::Round($_.Size/1GB,2)}},@{n="FreeSpace";e={[math]::Round($_.FreeSpace/1GB,2)}} } $dskspce | Format-Table > $TempFile | Notepad $TempFile } else{ $msgbox=[System.Windows.MessageBox]::Show('Action has been cancelled. Script will stop here!') } }) $Form.Controls.Add($remdmp) $QUIT = New-Object 'System.Windows.Forms.Button' $QUIT.DialogResult = 'OK' $QUIT.Location = '300, 200' $QUIT.Margin = '5, 5, 5, 5' $QUIT.Name = 'buttonOK' $QUIT.Size = '300, 50' $QUIT.BackColor ="LightGray" $QUIT.ForeColor ="black" $QUIT.Text = '&CLOSE' $QUIT.Font = [System.Drawing.Font]::new('Microsoft Sans Serif', 10, [System.Drawing.FontStyle]::Bold) $QUIT.UseCompatibleTextRendering = $True $QUIT.UseVisualStyleBackColor = $False $QUIT.Add_Click({$form.Add_FormClosing({$_.Cancel=$false});$form.Close()}) $QUIT.Show()#$QUIT.Hide() $form.Controls.Add($QUIT) $form.showdialog()
问题根源
你说得没错,$output是自定义的PSCustomObject而非System.IO.DirectoryInfo对象,这就是报错的核心原因:
Get-ChildItem需要接收路径字符串或DirectoryInfo对象,但你传递的自定义对象会被转换成@{name=...; Size=...}格式的字符串,PowerShell会把这个字符串当成本地路径去查找,自然找不到对应的目录。- 代码没有捕获
Out-GridView -PassThru的选择结果,直接用原始的$output遍历,导致无法进入用户选中的子文件夹。
修复后的代码
核心修改是保留原始DirectoryInfo对象并附加Size属性,同时每一步都捕获用户的选择结果:
Add-Type -AssemblyName PresentationFramework Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $TempFile = [io.path]::GetTempFileName() $form = New-Object System.Windows.Forms.Form $form.Text = "Fix low space issue" $form.size = New-Object System.Drawing.Size(900,400) $remdmp = New-Object System.Windows.Forms.Button $remdmp.Location = New-Object System.Drawing.Size(300,35) $remdmp.Size = New-Object System.Drawing.Size(300,45) $remdmp.Text = "Remove dump Files" $remdmp.Font = [System.Drawing.Font]::new('Microsoft Sans Serif', 10, [System.Drawing.FontStyle]::Bold) $remdmp.Add_Click({ Remove-Item $TempFile -ErrorAction SilentlyContinue $svrs = "TM-ND0276" $path = "\\TM-ND0276\d$\" $decimalPlaces = 2 # 保留原始DirectoryInfo对象,添加Size属性用于显示 $foldersWithSize = Get-ChildItem -Directory $path | ForEach-Object { $totalSize = (Get-ChildItem -Recurse $_.FullName -File | Measure-Object -Property Length -Sum).Sum $_ | Add-Member -MemberType NoteProperty -Name "Size" -Value ("{0:N$decimalPlaces} GB" -f ($totalSize / 1GB)) -PassThru } # 第一步:选择父文件夹 $selectedParent = $foldersWithSize | Sort-Object -Descending -Property Size | Out-GridView -Title "Select parent folder" -PassThru if (-not $selectedParent) { [System.Windows.MessageBox]::Show('Action has been cancelled. Script will stop here!') return } # 第二步:进入子文件夹(父文件夹的直接子目录) $childFolders = Get-ChildItem -Directory $selectedParent.FullName $selectedChild = $childFolders | Out-GridView -Title "Select child folder containing dump files" -PassThru if (-not $selectedChild) { [System.Windows.MessageBox]::Show('Action has been cancelled. Script will stop here!') return } # 第三步:选择要删除的dump文件(子文件夹下一级的文件) $dumpFiles = Get-ChildItem -File $selectedChild.FullName $selectedFiles = $dumpFiles | Out-GridView -Title "Select dump files to delete" -PassThru if (-not $selectedFiles) { [System.Windows.MessageBox]::Show('Action has been cancelled. Script will stop here!') return } # 执行删除并处理结果 try { $selectedFiles | Remove-Item -Force -ErrorAction Stop [System.Windows.MessageBox]::Show('Dump files have been deleted. Check notepad for available free space in D drive') # 获取磁盘空间信息(用Get-CimInstance替代已过时的Get-WmiObject) $dskspce = Invoke-Command -ComputerName $svrs -ScriptBlock { Get-CimInstance -Class win32_logicaldisk | Format-Table DeviceId, MediaType, @{n="Size";e={[math]::Round($_.Size/1GB,2)}}, @{n="FreeSpace";e={[math]::Round($_.FreeSpace/1GB,2)}} -AutoSize } $dskspce | Out-File -FilePath $TempFile Notepad $TempFile } catch { [System.Windows.MessageBox]::Show("Error deleting files: $_") } }) $Form.Controls.Add($remdmp) $QUIT = New-Object 'System.Windows.Forms.Button' $QUIT.DialogResult = 'OK' $QUIT.Location = '300, 200' $QUIT.Margin = '5, 5, 5, 5' $QUIT.Name = 'buttonOK' $QUIT.Size = '300, 50' $QUIT.BackColor ="LightGray" $QUIT.ForeColor ="black" $QUIT.Text = '&CLOSE' $QUIT.Font = [System.Drawing.Font]::new('Microsoft Sans Serif', 10, [System.Drawing.FontStyle]::Bold) $QUIT.UseCompatibleTextRendering = $True $QUIT.UseVisualStyleBackColor = $False $QUIT.Add_Click({$form.Add_FormClosing({$_.Cancel=$false});$form.Close()}) $QUIT.Show() $form.Controls.Add($QUIT) $form.showdialog()
关键优化点
- 保留DirectoryInfo对象:用
Add-Member给原始文件夹对象添加Size属性,既保留了路径信息,又能在GridView中显示大小 - 捕获用户选择:每一步都获取
Out-GridView -PassThru的结果,只有用户选中后才继续流程 - 性能优化:避免重复遍历文件夹计算大小,一次计算完成后复用结果
- 现代API替代:用
Get-CimInstance取代已过时的Get-WmiObject - 错误处理:添加try-catch块捕获删除时的异常,提升脚本稳定性
内容的提问来源于stack exchange,提问作者Ujjawal Mandal
相关产品推荐
相关产品推荐

