I'm trying to create a powershell script that searches a users C drive for a certain file extension, and then writes a file to a network share if it finds one. The script is launched from the last line of a logon script that reads like this:
powershell.exe -ExecutionPolicy Bypass -windowstyle hidden -file "\\servername\Path\To\File.ps1"
And my powershell script looks like this:
$hostname = HostName
Get-ChildItem -Path C:\*.* -Filter $file -Recurse -Force -ErrorAction
SilentlyContinue | Out-File \\servername\Path\To\Results\$hostname\file.txt
If ((Get-Content "\\servername\Path\To\Results\$hostname\file.txt") -eq $Null) {
Remove-Item \\servername\Path\To\Results\$hostname\file.txt
}
Exit
The script runs perfectly fine on my machine even when I load it from the network share but whenever another computer runs it, it never produces an Out File. And I don't think it is even searching.
What am I doing wrong? I thought it was execution policy, but I've set the logon script to bypass it. I don't understand why it isn't working.
[edit]
I've now got the script working sometimes on Windows 10 machines. But it doesn't work at all on Windows 7. I've even tried running
Get-ChildItem C:\*.pst -Recurse
directly from a powershell command prompt, and it just fails silently and doesn't search for anything. Isn't Get-ChildItem a powershell 1 command?
Hello. If you do like this: Get-ChildItem -Path C:*.* -Filter $file
-Recurse -Force the text file output will be enough to weigh.
You can try to check the access to the network folder for the current
user:if access explicitly set, and write access exists, then you can
record a file with the content. Otherwise, it can create folder test
on the local machine which will create the file, indicating that there
is no access. How is this way:
Set-ExecutionPolicy remotesigned -Scope CurrentUser -Force| Out-Null
$user = [System.Environment]::UserName
$hostname = [System.Environment]::MachineName
try {
$accs = Get-ACL -Path "\\server\sharedfolder\Results\"
foreach ($access in $accs) {
$obj = New-Object -TypeName PSObject -Property #{
Access = $accs.Access
}
$obj1 = $obj | select -ExpandProperty Access
for ($i = 0 ; $i -le $obj1.Count ; $i ++ )
{
if (!($obj1[$i].IdentityReference -like "*Users*" -or $obj1[$i].IdentityReference -like "*$user*")) {
if (!(Test-Path "c:\test")) {
md c:\test
$s = "user access from group"
$s | out-file C:\test\ErrInfo.csv
}
else {
$s = "user access from group"
$s | out-file C:\test\ErrInfo.csv
}
}
if ($obj1[$i].IdentityReference -like "*Users*" -or $obj1[$i].IdentityReference -like "*$user*") {
if ($obj1[$i].FileSystemRights -like "*ReadAndExecute*")
{
if (!(Test-Path "c:\test")) {
md c:\test
$s = "Premission only ReadAndExecute"
$s | out-file C:\test\ErrInfo_rex.csv
}
else {
$s = "Premission only ReadAndExecute"
$s | out-file C:\test\ErrInfo_rex.csv
}
}
if ($obj1[$i].FileSystemRights -like "*FullControl*" -and $obj1[$i].AccessControlType -like "*Allow*" -or $obj1[$i].FileSystemRights -like "*Modify*" -and $obj1[$i].AccessControlType -like "*Allow*")
{
if (!(Test-Path "\\server\sharedfolder\Results\$hostname"))
{
md "\\server\sharedfolder\Results\$hostname"
Get-ChildItem -Path C:\testpatch\*.* -Filter $file -Recurse -Force -ErrorAction SilentlyContinue | Out-File "\\server\sharedfolder\Results\$hostname\file.txt"
}
else {
Get-ChildItem -Path C:\testpatch\*.* -Filter $file -Recurse -Force -ErrorAction SilentlyContinue | Out-File "\\server\sharedfolder\Results\$hostname\file.txt"
}
}
}
}
}
}
catch {
if (!(Test-Path "c:\test")) {
md c:\test
$s = "--NoAccess--"
$s | out-file C:\test\ErrInfo_noaccess.csv
}
else {
$s = "--NoAccess--"
$s | out-file C:\test\ErrInfo_noaccess.csv
}
}
Or you can do something like this (whiteout EXIT):
Set-ExecutionPolicy remotesigned -Scope CurrentUser -Force| Out-Null
$hostname = [System.Environment]::MachineName
if (!(Test-Path "\\server\sharedfolder\Results\$hostname")) {
md "\\server\sharedfolder\Results\$hostname" | Out-Null
If ((Get-ChildItem -Path C:\test\*.* -Filter $file -Recurse -Force -ErrorAction SilentlyContinue).Count -ne "0") {
Get-ChildItem -Path C:\test\*.* -Filter $file -Recurse -Force -ErrorAction SilentlyContinue | Out-File "\\server\sharedfolder\Results\$hostname\file.txt"
}
}
elseif (Test-Path "\\server\sharedfolder\Results\$hostname") {
If ((Get-ChildItem -Path C:\test\*.* -Filter $file -Recurse -Force -ErrorAction SilentlyContinue).Count -ne "0") {
Get-ChildItem -Path C:\test\*.* -Filter $file -Recurse -Force -ErrorAction SilentlyContinue | Out-File "\\server\sharedfolder\Results\$hostname\file.txt"
}
}
Related
I use the following script to clear the cache of—and start—Teams.
It worked as expected for some time. Now I get some strange behaviours like:
When I close powershell, Teams closes too
Before I close PS there appear some errors
# start Teams
# Start-Process -File "C:\Program Files (x86)\Microsoft\Teams\current\Teams.exe" -ArgumentList '--processStart "Teams.exe"'
# Write-Host "Teams Process Sucessfully Started"
# Start-Sleep -Seconds 5
#Stop Teams process
Get-Process -ProcessName Teams -ErrorAction SilentlyContinue | Stop-Process -Force
Start-Sleep -Seconds 3
Write-Host "Teams Process Sucessfully Stopped"
#Clear Team Cache
try{
# Get-ChildItem -Path $env:APPDATA\"Microsoft\Teams" | Remove-Item -Recurse -ErrorAction SilentlyContinue # Clear.all
Get-ChildItem -Path $env:APPDATA\"Microsoft\Teams\blob_storage" | Remove-Item -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $env:APPDATA\"Microsoft\Teams\databases" | Remove-Item -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $env:APPDATA\"Microsoft\Teams\cache" | Remove-Item -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $env:APPDATA\"Microsoft\Teams\gpucache" | Remove-Item -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $env:APPDATA\"Microsoft\Teams\Indexeddb" | Remove-Item -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $env:APPDATA\"Microsoft\Teams\Local Storage" | Remove-Item -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $env:APPDATA\"Microsoft\Teams\tmp" | Remove-Item -Recurse -ErrorAction SilentlyContinue
Write-Host "Teams Cache Cleaned"
}catch{
echo $_
}
#Remove Credential from Credential manager
$credential = cmdkey /list | ForEach-Object{if($_ -like "*Target:*" -and $_ -like "*msTeams*"){cmdkey /del:($_ -replace " ","" -replace "Target:","")}}
#Remove Reg.Key
$Regkeypath= "HKCU:\Software\Microsoft\Office\Teams"
$value = (Get-ItemProperty $Regkeypath).HomeUserUpn -eq $null
If ($value -eq $False)
{
Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Office\Teams" -Name "HomeUserUpn"
Write-Host "The registry value Sucessfully removed"
}
Else { Write-Host "The registry value does not exist"}
#Get Desktop-config.json
$TeamsFolders = "$env:APPDATA\Microsoft\Teams"
try{
$SourceDesktopConfigFile = "$TeamsFolders\desktop-config.json"
$desktopConfig = (Get-Content -Path $SourceDesktopConfigFile | ConvertFrom-Json)
}
catch{ Write-Host "Failed to open Desktop-config.json" }
#Overwrite the desktop-config.json
Write-Host "Modify desktop-Config.Json"
try{
$desktopConfig.isLoggedOut = $true
$desktopConfig.upnWindowUserUpn =""; #The email used to sign in | also: whoami /upn
$desktopConfig.userUpn ="";
$desktopConfig.userOid ="";
$desktopConfig.userTid = "";
$desktopConfig.homeTenantId ="";
$desktopConfig.webAccountId="";
$desktopConfig | ConvertTo-Json -Compress | Set-Content -Path $SourceDesktopConfigFile -Force
}
catch{ Write-Host "Failed to overwrite desktop-config.json" }
Write-Host "Modify desktop-Config.Json - Finished"
#Delete the Cookies file. This is a fix for when the joining as anonymous, and prevents the last used guest name from being reused.
Get-ChildItem "$TeamsFolders\Cookies" | Remove-Item
#Lastly delete the storage.json, this corrects some error that MSTeams otherwise would have when logging in again.
Get-ChildItem "$TeamsFolders\storage.json" | Remove-Item
#Try to remove the Link School/Work account if there was one. It can be created if the first time you sign in, the user all
# $LocalPackagesFolder ="$env:LOCALAPPDATA\Packages"
# $AADBrokerFolder = Get-ChildItem -Path $LocalPackagesFolder -Recurse -Include "Microsoft.AAD.BrokerPlugin_*";
# $AADBrokerFolder = $AADBrokerFolder[0];
# Get-ChildItem "$AADBrokerFolder\AC\TokenBroker\Accounts" | Remove-Item -Recurse -Force
# Start-Sleep -Seconds 5
# start Teams
Start-Process -File "C:\Program Files (x86)\Microsoft\Teams\current\Teams.exe" -ArgumentList '--processStart "Teams.exe"'
# "$($env:USERProfile)\AppData\Local\Microsoft\Teams\Update.exe"
Start-Sleep -Seconds 3
Write-Host "Teams Process Sucessfully Started"
# Stop for testpurposes
pause
SIDENOTE
Teams is installed as per Microsoft recommendation for VDI setups.
(Citrix VDI/VDA, HDX Optimized)
It worked as expected for some time. Now I get some strange behaviours like:
When I close powershell, Teams closes too
Before I close PS there appear some errors
Screenshot of errors
I am trying to get files from servers in a list using the below
$server = Get-Content server.txt
$server| ForEach-Object {
$session=new-pssession -computername $server -credential (Import-Clixml "mycredentials.xml")
Invoke-Command -Session $session -ScriptBlock ${function:getfiles}
Copy-Item -path "C:\some\folder\*" -Destination "C:\localfolder" -recurse -FromSession $session
}
If I supply explicitly a name in -computername, works like a charm.
When there are several names in the list, the execution stops after the first one. I suspect that the session closes after the first execution.
Is there a way to make it like this:
get-content -> for each line execute the copy-item -> close session -> open new session to new server -> .....etc, meaning that $session will be only for the current server.
$function:getfiles
function getfiles {
New-Item -Force -Path C:\path\trace.txt
$remoteserver=$env:computername
$trace='C:\path\trace.txt'
$Include = #('*.keystore', '*.cer', '*.crt', '*.pfx', '*.jks', '*.ks')
$exclude = '^C:\\(Windows|Program Files|Documents and Settings|Users|ProgramData)|\bBackup\b|\breleases?\b|\bRECYCLE.BIN\b|\bPerfLogs\b|\bold\b|\bBackups\b|\brelease?\b|'
Get-ChildItem -Path 'C:\','D:\' -file -Include $include -Recurse -EA 0|
Where-Object { $_.DirectoryName -notmatch $exclude } |
Select-Object -ExpandProperty FullName |
Set-Content -Path $trace
$des = "C:\some\folder\$remoteserver"
$safe = Get-Content $trace
$safe | ForEach-Object{
#find drive-delimeter
$first=$_.IndexOf(":\");
if($first -eq 1){
#stripe it
$newdes=Join-Path -Path $des -ChildPath #($_.Substring(0,1)+$_.Substring(2))[0]
}
else{
$newdes=Join-Path -Path $des -ChildPath $_
}
$folder=Split-Path -Path $newdes -Parent
$err=0
#check if folder exists"
$void=Get-Item $folder -ErrorVariable err -ErrorAction SilentlyContinue
if($err.Count -ne 0){
#create when it doesn't
$void=New-Item -Path $folder -ItemType Directory -Force -Verbose
}
$void=Copy-Item -Path $_ -destination $newdes -Recurse -Container -Verbose
}
}
UPDATE
So I have found out that the file where the lines should be be redirected from the script is not populated, which explains why the next step for copy-item fails. I have tried redirecting in different ways, still cant get it populated. The file is created without issues.
Made a workaround - placed the function in a script which is copied to the remote server / execute it \ clean afterwards.
New to PowerShell.
Some experience with Linux, bash, and programming (Java, C, HTML/CSS/JS). I just started an internship.
I was given a PowerShell script in order to do basic disk clean-up. Part of it pasted below. It writes to both console and a logfile. Some of the servers that I am cleaning having hundreds of thousands of files. I want to increase the performance of the script by only writing to the logfile. It usually starts out pretty strong, but once the console output gets large enough, things start to slow down drastically.
I attempted to simply remove the -verbose tags, but then it doesn't write to either. Then my understanding was that 'SilentlyContinue' would allow print to log, but not console. But the code already has SilentlyContinue flags? I then tried adding-Verbose to some of the for-each statements and that didn't work either.
I'm just kind of running in circles now.
Any ideas or pointers?
function global:Write-Verbose
(
[string]$Message
)
{ # check $VerbosePreference variable
if ( $VerbosePreference -ne 'SilentlyContinue' )
{ Write-Host " $Message" -ForegroundColor 'Yellow' }
}
Write-Verbose
$DaysToDelete = 7
$LogDate = get-date -format "MM-d-yy-HH"
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace(0xA)
Start-Transcript -Path C:\Windows\Temp\$LogDate.log
#Cleans all code off of the screen.
Clear-Host
$Before = Get-WmiObject Win32_LogicalDisk | Where-Object { $_.DriveType -eq "3" } | Select-Object SystemName,
#{ Name = "Drive" ; Expression = { ( $_.DeviceID ) } },
#{ Name = "Size (GB)" ; Expression = { "{0:N1}" -f ( $_.Size / 1gb) } },
#{ Name = "FreeSpace (GB)" ; Expression = { "{0:N1}" -f ( $_.Freespace / 1gb ) } },
#{ Name = "PercentFree" ; Expression = { "{0:P1}" -f ( $_.FreeSpace / $_.Size ) } } |
Format-Table -AutoSize | Out-String
## Stops the windows update service.
Get-Service -Name wuauserv | Stop-Service -Force -Verbose -ErrorAction SilentlyContinue
## Windows Update Service has been stopped successfully!
## Deletes the contents of windows software distribution.
Get-ChildItem "C:\Windows\SoftwareDistribution\*" -Recurse -Force -Verbose -ErrorAction SilentlyContinue |
Where-Object { ($_.CreationTime -lt $(Get-Date).AddDays(-$DaysToDelete)) } |
remove-item -force -Verbose -recurse -ErrorAction SilentlyContinue
## The Contents of Windows SoftwareDistribution have been removed successfully!
## Deletes the contents of the Windows Temp folder.
Get-ChildItem "C:\Windows\Temp\*" -Recurse -Force -Verbose -ErrorAction SilentlyContinue |
Where-Object { ($_.CreationTime -lt $(Get-Date).AddDays(-$DaysToDelete)) } |
remove-item -force -Verbose -recurse -ErrorAction SilentlyContinue
## The Contents of Windows Temp have been removed successfully!
## Deletes all files and folders in user's Temp folder.
Get-ChildItem "C:\users\$env:USERNAME\AppData\Local\Temp\*" -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { ($_.CreationTime -lt $(Get-Date).AddDays(-$DaysToDelete)) } |
remove-item -force -Verbose -recurse -ErrorAction SilentlyContinue
## The contents of C:\users\$env:USERNAME\AppData\Local\Temp\ have been removed successfully!
## Remove all files and folders in user's Temporary Internet Files.
Get-ChildItem "C:\users\$env:USERNAME\AppData\Local\Microsoft\Windows\Temporary Internet Files\*" -Recurse -Force -Verbose -ErrorAction SilentlyContinue |
Where-Object { ($_.CreationTime -le $(Get-Date).AddDays(-$DaysToDelete)) } |
remove-item -force -recurse -ErrorAction SilentlyContinue
## All Temporary Internet Files have been removed successfully!
## Cleans IIS Logs if applicable.
Get-ChildItem "C:\inetpub\logs\LogFiles\*" -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { ($_.CreationTime -le $(Get-Date).AddDays(-60)) } |
Remove-Item -Force -Verbose -Recurse -ErrorAction SilentlyContinue
## All IIS Logfiles over x days old have been removed Successfully!
## deletes the contents of the recycling Bin.
$objFolder.items() | ForEach-Object { Remove-Item $_.path -ErrorAction Ignore -Force -Verbose -Recurse }
## The Recycling Bin has been emptied!
## Starts the Windows Update Service
Get-Service -Name wuauserv | Start-Service -Verbose
$After = Get-WmiObject Win32_LogicalDisk | Where-Object { $_.DriveType -eq "3" } | Select-Object SystemName,
#{ Name = "Drive" ; Expression = { ( $_.DeviceID ) } },
#{ Name = "Size (GB)" ; Expression = { "{0:N1}" -f ( $_.Size / 1gb) } },
#{ Name = "FreeSpace (GB)" ; Expression = { "{0:N1}" -f ( $_.Freespace / 1gb ) } },
#{ Name = "PercentFree" ; Expression = { "{0:P1}" -f ( $_.FreeSpace / $_.Size ) } } |
Format-Table -AutoSize | Out-String
## Sends some before and after info for ticketing purposes
Hostname ; Get-Date | Select-Object DateTime
Write-Host "Before: $Before"
Write-Host "After: $After"
Write-Verbose ( Get-ChildItem -Path C:\* -Include *.iso, *.vhd, *.vhdx -Recurse -ErrorAction SilentlyContinue |
Sort Length -Descending | Select-Object Name, Directory,
#{Name = "Size (GB)"; Expression = { "{0:N2}" -f ($_.Length / 1GB) } } | Format-Table |
Out-String )
## Completed Successfully!
Stop-Transcript
You want to look into Redirection: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_redirection?view=powershell-7.1
It's useful for logging your Catch output, wrapping it in ${} and specifying your stream output. Ex: ${ Write-Verbose ... } 4>&1 3>&1 2>&1 >> $logFile
Most of what you have though looks like you're trying to log data for reference. Like your Before:After & final Get-ChildItem statements. If you're doing it as you go, you can pipe to Out-File -Append to a log file. But since you have it in a block towards the end, you can simply wrap & redirect:
&{
Write-Host "Before: " $Before
Write-Host "After: " $After"
Get-ChildItem -Path C:\* -Include *.iso, *.vhd, *.vhdx -Recurse -ErrorAction SilentlyContinue |
Sort Length -Descending | Select-Object Name, Directory,
#{Name = "Size (GB)"; Expression = { "{0:N2}" -f ($_.Length / 1GB) } } | Format-Table |
Out-String
} *> C:\FilePath\File.txt
Notice you don't even need to wrap your Get-ChildItem in a Write-Verbose statement. Get cmdlets that spit out to console, will just write the output to the file when using redirection. The only time you should need to issue a Write statement is if you are adding a string of text / interpolating data.
On an unrelated note, I see a DRY opportunity. Your before & after statements are identical. Put a function towards the top of your file that returns the statement, that way you can just assign your $Before & $After vars to the return output.
I have written the following script using a post on this forum. The script deletes the files which are older than 15 days:
cls
$servers = Get-Content server.txt
$limit = (Get-Date).AddDays(-15)
$path = "E:\CheckDBOutput"
ForEach ($line in $servers)
{
Invoke-Command -cn $line -ScriptBlock {
Get-ChildItem -Path $path -Recurse -Force | Where-Object {
!$_.PSIsContainer -and $_.CreationTime -lt $limit
} | Remove-Item -Force
}
}
The script is executing fine, but no files are getting deleted.
As already mentioned in the comments, you need to pass the parameters to use inside the scriptblock as arguments to the -ArgumentList parameter:
$RemoveOldFiles = {
param(
[string]$path,
[datetime]$limit
)
Get-ChildItem -Path $path -Recurse -Force | Where-Object {
!$_.PSIsContainer -and $_.CreationTime -lt $limit
} | Remove-Item -Force
}
$servers = Get-Content server.txt
$limit = (Get-Date).AddDays(-15)
$path = "E:\CheckDBOutput"
ForEach ($line in $servers)
{
Invoke-Command -cn $line -ScriptBlock $RemoveOldFiles -ArgumentList $path,$limit
}
Remove-Item does not exist in PowerShell version 1.0 - make sure your destination servers have v2.0 or better installed.
I'm trying to feed my function with some variables and when no variable is given it should use a default value of 30 for OlderThanDays. For one reason or another this is not working out as I'd expected.
I fixed my problem in the ForEach loop by using if($_.B -ne $null) {$OlderThanDays=$_.B} else {$OlderThanDays="30"} But I don't think this is best practice. Can anyone tell me why [Int]$OlderThanDays=30 isn't working?
Problem: When adding a line in my csv-file without defining the OlderThanDaysvariable, the default of 30 days is not used and the files are just deleted...
Thank you for your help.
CSV file:
# Correct input formats are:
#
# ServerName, LocalPath, OlderThanDays
# Ex: server, E:\SHARE\Target, 10
# Ex: server, E:\CBR\SHARE\Target
#
# UNC-Path, OlderThanDays
# Ex: \\domain\SHARE\Target, 20
# Ex: \\domain\Target
#
# If no 'OlderThanDays' is provided, a default of 30 days will be used
# Commenting out can be done with '#'
# ______________________________________________________________________
SERVER1, E:\SHARE\Target
\\domain\SHARE\Target2
Full script:
#__________________________________________________________________________________________________________________________________
$ImportFile = "S:\Input\Scheduled Task\Auto_Clean.csv"
$Password = cat "S:\Input\pwd.txt" | ConvertTo-SecureString -Force
$UserName = "domain\me"
#__________________________________________________________________________________________________________________________________
# Scriptblock for running the function in a job
$JobCall = {
# Function that removes files older than x days in all subfolders
Function Delete-OldFiles {
[CmdletBinding(SupportsShouldProcess=$True)]
Param(
[Parameter(Mandatory=$True,Position=1)]
[ValidateScript({Test-Path $_})]
[String]$Target,
[Parameter(Mandatory=$False,Position=2)]
[Int]$OlderThanDays=30,
[Parameter(Mandatory=$False,Position=3)]
[String]$Server,
[switch]$CleanFolders
)
#__________________________________________________________________________________________________________________________________
# Create logfile
$TempDate = (get-date).ToString("dd-MM-yyyy")
$TempFolderPath = $Target -replace '\\','_'
$TempFolderPath = $TempFolderPath -replace ':',''
$TempFolderPath = $TempFolderPath -replace ' ',''
$script:LogFile = "\\DEUSTHEIDIT02\Log\Scheduled Task\Auto_Clean\$Server - $TempFolderPath - $TempDate.log"
#__________________________________________________________________________________________________________________________________
# Check the version of PowerShell
if ($PSVersionTable.PSVersion.Major -ge "3") {
# PowerShell 3+ Remove files older than (FASTER)
Get-ChildItem -Path $Target -Recurse -File |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
"$Timestamp | REMOVED: $Server $Item"
}
} | Tee-Object $LogFile -Append -Verbose}
Else {
# PowerShell 2 Remove files older than
Get-ChildItem -Path $Target -Recurse |
Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
Write-Host "$Timestamp | FAILLED: $Server $Item (IN USE)"
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
Write-Host "$Timestamp | REMOVED: $Server $Item"
"$Timestamp | REMOVED: $Server $Item"
}
} | Out-File $LogFile -Append }
#__________________________________________________________________________________________________________________________________
# Switch -CleanFolders deletes empty folders older than x days
if ($CleanFolders) {
# Check the version of PowerShell
if ($PSVersionTable.PSVersion.Major -ge "3") {
# PowerShell 3+ Remove empty folders older than (FASTER)
Get-ChildItem -Path $Target -Recurse -Force -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
Where-Object { (Get-ChildItem -Path $_.FullName -Recurse -Force -File) -eq $null } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
"$Timestamp | REMOVED: $Server $Item"
}
} | Tee-Object $LogFile -Append
}
else {
# PowerShell 2 Remove empty folders older than
Get-ChildItem -Path $Target -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$OlderThanDays) } |
ForEach {
$Item = $_.FullName
Remove-Item $Item -Recurse -Force -ErrorAction SilentlyContinue
# Log succes/failure
$Timestamp = (Get-Date).ToShortDateString()+" | "+(Get-Date).ToLongTimeString()
if (Test-Path $Item) {
Write-Host "$Timestamp | FAILLED: $Server $Item (IN USE)"
"$Timestamp | FAILLED: $Server $Item (IN USE)"
}
else {
Write-Host "$Timestamp | REMOVED: $Server $Item"
"$Timestamp | REMOVED: $Server $Item"
}
} | Out-File $LogFile -Append
}
}
}
# Lact command of the ScriptBlock: Call the magic to happen
Delete-OldFiles $args[0] $args[1] $args[2] -CleanFolders:$args[3]
}
#__________________________________________________________________________________________________________________________________
# Read input file and ignore all lines starting with #
$File = (Import-Csv -Path $ImportFile -Header "A", "B", "C", "D" | Where { $_.A -NotLike "#*" } )
#__________________________________________________________________________________________________________________________________
# If the UNC Path is provided we will run the script locally else it wil be run on the remote server as a job
Foreach ($_ in $File) {
# Define input format & default values
if ($_.A -like "\\*") {
$Server="UNC"
$Target=$_.A
$OlderThanDays=$_.B
$CleanFolders=$_.C
}
else {
$Server=$_.A
$Target=$_.B
$OlderThanDays=$_.C
$CleanFolders=$_.D
}
# Call the scriptblock with the function to run locally or on the remote server
if ($Server -eq "UNC")
{
Write-Host "UNC Path detected: $Target, $OlderThanDays" -ForegroundColor Yellow
Start-Job -ScriptBlock $JobCall -ArgumentList ($Target, $OlderThanDays, $Server) -Name DelFiles
}
else
{
Write-Host "Local path detected: $Server, $Target, $OlderThanDays" -ForegroundColor Cyan
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName,$Password
Invoke-Command -ScriptBlock $JobCall -ArgumentList ($Target, $OlderThanDays, $Server) -ComputerName "$Server.domain" -Authentication Credssp -Credential $Credentials -AsJob -JobName DelFiles
# Delete empty folders: Invoke-Command -ScriptBlock $JobCall -ArgumentList ($Target, $OlderThanDays, $Server, $true) -ComputerName "$Server.domain" -Authentication Credssp -Credential $Credentials -AsJob -JobName DelFiles
}
}
The parameter can't be both Mandatory and have default value. Former is checked first, and if it's set to $true, than default value is simply ignored. If you want to make sure that users can't specify empty value, just use [ValidateNotNullorEmpty()] validation, and make parameter optional.
So I had a similar problem. After months keeping a module with personal functions for day-to-day activities making extensive use of default values and, in many cases, mandatory parameters with initialized default values, suddenly my functions stopped working.
After writing a new one, calling it with explicit parameters would result in the parameters values being empty in the function execution context.
After restarting powershell console for some times I decided to reboot the machine, and everything went back to normal. Go figure.