To create a robust PowerShell script that accepts multiple parameters, we'll use the param
block. Here's how to declare all the required parameters with proper data types:
param (
[Parameter(Mandatory=$true)]
[string]$SourceFolder,
[Parameter(Mandatory=$true)]
[string[]]$Extensions,
[Parameter(Mandatory=$true)]
[string]$DestinationFolder,
[Parameter(Mandatory=$true)]
[bool]$RestartIIS,
[Parameter(Mandatory=$false)]
[PSCredential]$Credential
)
For copying files to a remote server, we'll use Copy-Item
with credentials. The New-PSDrive
cmdlet helps establish a temporary connection:
$driveParams = @{
Name = "TempRemoteDrive"
PSProvider = "FileSystem"
Root = "\\$($DestinationFolder.Split('\')[2])\$($DestinationFolder.Split('\')[3])"
Credential = $Credential
Persistent = $false
}
$remoteDrive = New-PSDrive @driveParams
try {
foreach ($ext in $Extensions) {
Get-ChildItem -Path $SourceFolder -Filter "*.$ext" | ForEach-Object {
$destPath = $_.FullName.Replace($SourceFolder, $remoteDrive.Root)
Copy-Item -Path $_.FullName -Destination $destPath -Force
}
}
}
finally {
Remove-PSDrive -Name $remoteDrive.Name
}
To handle IIS restart when required, we'll use the Import-Module WebAdministration
and appropriate cmdlets:
if ($RestartIIS) {
try {
Import-Module WebAdministration
Restart-WebAppPool -Name "*"
Write-Host "All application pools have been restarted successfully."
}
catch {
Write-Error "Failed to restart IIS: $_"
}
}
For handling multiple folder copies, create a controller script that calls your main script:
$folders = @(
@{
Source = "C:\Folder1"
Extensions = @("txt","log")
Destination = "\\server1\share1"
RestartIIS = $false
},
@{
Source = "D:\Folder2"
Extensions = @("csv","xml")
Destination = "\\server2\share2"
RestartIIS = $true
}
)
$cred = Get-Credential
foreach ($folder in $folders) {
& ".\Copy-FilesWithExtensions.ps1"
-SourceFolder $folder.Source
-Extensions $folder.Extensions
-DestinationFolder $folder.Destination
-RestartIIS $folder.RestartIIS
-Credential $cred
}
Add comprehensive error handling and logging to make the script production-ready:
Start-Transcript -Path "C:\Logs\FileCopy_$(Get-Date -Format 'yyyyMMddHHmmss').log"
try {
# Main script logic here
}
catch {
Write-Error "Script failed: $_"
if ($_.Exception.InnerException) {
Write-Error "Inner exception: $($_.Exception.InnerException.Message)"
}
}
finally {
Stop-Transcript
}
html
When automating file deployment in Windows environments, we often need to:
- Filter files by specific extensions
- Handle remote server transfers
- Optionally restart IIS services
- Support multiple source folders
For remote file operations, these are essential:
Copy-Item
New-PSSession
Invoke-Command
Restart-WebAppPool
Get-ChildItem
Test-Path
Here's how to structure the parameter block:
param (
[Parameter(Mandatory=$true)]
[string[]]$SourceFolders,
[Parameter(Mandatory=$true)]
[string[]]$Extensions,
[Parameter(Mandatory=$true)]
[string]$Destination,
[Parameter()]
[switch]$RestartIIS,
[Parameter()]
[pscredential]$Credential
)
# FileCopyWithIIS.ps1
param (
[Parameter(Mandatory=$true)]
[string[]]$SourceFolders,
[Parameter(Mandatory=$true)]
[string[]]$Extensions = @("*.dll","*.config"),
[Parameter(Mandatory=$true)]
[string]$Destination = "\\server\share\destination",
[Parameter()]
[switch]$RestartIIS,
[Parameter()]
[pscredential]$Credential
)
try {
# Create remote session if credentials provided
if ($Credential) {
$session = New-PSSession -ComputerName ($Destination -split '\\')[2] -Credential $Credential
}
foreach ($folder in $SourceFolders) {
if (-not (Test-Path $folder)) {
Write-Warning "Source folder $folder not found"
continue
}
$files = Get-ChildItem -Path $folder -Include $Extensions -Recurse -File
foreach ($file in $files) {
$destPath = $Destination + $file.FullName.Substring($folder.Length)
$destDir = [System.IO.Path]::GetDirectoryName($destPath)
if (-not (Test-Path $destDir)) {
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
}
Copy-Item -Path $file.FullName -Destination $destPath -Force
}
}
if ($RestartIIS) {
if ($session) {
Invoke-Command -Session $session -ScriptBlock {
Import-Module WebAdministration
Restart-WebAppPool -Name "DefaultAppPool"
}
}
else {
Import-Module WebAdministration
Restart-WebAppPool -Name "DefaultAppPool"
}
}
}
catch {
Write-Error "Error occurred: $_"
}
finally {
if ($session) { Remove-PSSession $session }
}
For batch processing:
$params = @{
SourceFolders = @("C:\App1\Bin","D:\App2\Assets")
Extensions = @("*.dll","*.pdb","*.config")
Destination = "\\prod-server\deploy"
RestartIIS = $true
Credential = Get-Credential
}
.\FileCopyWithIIS.ps1 @params
- Always use encrypted credentials
- Validate destination paths
- Implement proper error handling
- Consider using JEA for constrained endpoints
For large deployments:
# Use robocopy for bulk operations
foreach ($folder in $SourceFolders) {
robocopy $folder $Destination $Extensions /S /Z /MT:16 /R:1 /W:1
}