There are 2 issues with your code, the first issue is in your PowerShell function Protect-File
, you’re overwriting the first 16 bytes on $FileStreamWriter.Write($Crypto.IV, 0, $Crypto.IV.Length)
. You should first write the IV
and then $FileStreamReader.CopyTo($CryptoStream)
.
In summary, how your PowerShell function should look:
function Protect-File {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[string] $FileName,
[Parameter(Mandatory = $true, Position = 1)]
[string] $KeyAsPlainText
)
# these 3 could be parameters
$Algorithm = 'AES'
$CipherMode = 'CBC'
$PaddingMode = 'PKCS7'
try {
$Crypto = [System.Security.Cryptography.SymmetricAlgorithm]::Create($Algorithm)
$Crypto.Key = [System.Convert]::FromBase64String($KeyAsPlainText)
$Crypto.GenerateIV()
$Crypto.Mode = $CipherMode
$Crypto.Padding = $PaddingMode
$DestinationFile = $FileName + '.encrypted'
# Write the IV first
$FileStreamWriter = [System.IO.File]::OpenWrite($DestinationFile)
$FileStreamWriter.Write($Crypto.IV, 0, $Crypto.IV.Length)
$FileStreamWriter.Flush()
# No need to re-open the stream, can be passed in as argument
$Transform = $Crypto.CreateEncryptor()
$CryptoStream = [System.Security.Cryptography.CryptoStream]::new(
$FileStreamWriter,
$Transform,
[System.Security.Cryptography.CryptoStreamMode]::Write)
$FileStreamReader = [System.IO.File]::OpenRead($FileName)
$FileStreamReader.CopyTo($CryptoStream)
Write-Output "File encrypted successfully: $DestinationFile"
}
finally {
if ($FileStreamReader) {
$FileStreamReader.Dispose()
}
if ($CryptoStream) {
$CryptoStream.Dispose()
}
if ($FileStreamWriter) {
$FileStreamWriter.Dispose()
}
}
}
Then for your C# method, which as you have it will work for unprotecting the file, however the first 16 bytes should be skipped. Skipping the first 16 bytes is done when fileStream.Read(iv, 0, iv.Length);
so, you should re-use this stream instead of opening a new one: using (FileStream fileStreamReader = File.OpenRead(sourceFile))
.
public static bool UnprotectFile(
string sourceFile,
string destinationFile,
string keyAsPlainText)
{
try
{
byte[] encryptionKey = Convert.FromBase64String(keyAsPlainText);
// Read IV from the beginning of the encrypted file
using (Aes crypto = Aes.Create())
using (FileStream sourceStream = File.OpenRead(sourceFile))
using (FileStream destinationStream = File.OpenWrite(destinationFile))
{
byte[] iv = new byte[16];
sourceStream.Read(iv, 0, iv.Length);
// Configure encryption algorithm
crypto.Key = encryptionKey;
crypto.IV = iv;
crypto.Mode = CipherMode.CBC;
crypto.Padding = PaddingMode.PKCS7;
// Decrypt the file
using (CryptoStream cryptoStream = new CryptoStream(
destinationStream,
crypto.CreateDecryptor(),
CryptoStreamMode.Write))
{
sourceStream.CopyTo(cryptoStream);
}
}
return true;
}
catch
{
// handling...
return false;
}
}

You will learn how to:
- Copy a single file to another location
- Use wildcards to copy multiple files
- Copy all files from one folder to another
- Copy and rename files
- Handle errors and skip overwrite, etc.
Whether you need to back up configuration files, deploy scripts to multiple servers, or sync changes to a directory, PowerShell has the copy commands you need.
Table of contents
- Introduction to Copy-Item cmdlet in PowerShell
- Copy File without Overwriting Existing in PowerShell
- PowerShell to Copy and Rename a File
- Ensure the Destination Folder Before Copying the Files
- Copy Multiple Files in PowerShell
- Copy All Files and Folders Recursively
- Copy files from multiple folders to one Folder
- PowerShell to Include or Exclude Files to Copy
- Filter and Copy Files
- Copy Contents between Folders with the Progress Bar
- Copying Files to and from Remote Servers with PowerShell
- How do you copy a file if it is newer?
- Wrapping up
Introduction to Copy-Item cmdlet in PowerShell
In PowerShell, you can copy a file from one location to another using the Copy-Item cmdlet. At its core, the Copy-Item cmdlet is designed to copy files from one location to another within the same namespace. It can handle file system operations, such as copying files, directories, registry keys from registry drive, and entries. The Copy-Item cmdlet can copy files between folders, drives, and remote machines.
PowerShell Copy-Item Syntax
Copy-Item -Path <string[]> -Destination <string[]> [-Container] [-Credential <pscredential>] [-Exclude <string[]>] [-Filter <string>] [-Include <string[]>] [-Force] [-PassThru] [-Recurse] [-FromSession <PSSession[]>] [-ToSession <PSSession>] [-WhatIf] [-Confirm] [<CommonParameters>]
The important parameters list:
Parameter | Description |
---|---|
-Path | Specifies the path to the item to copy. |
-Destination | The destination parameter specifies the path to the location where the items are copied. |
-Container | Indicates that this cmdlet preserves the container when it copies the items. Default is $True. |
-Exclude | Specifies, as a string array, an item or items that this cmdlet excludes from the operation. |
-Filter | Specifies a filter to qualify the Path parameter. |
-Include | Specifies, as a string array, an item or items that this cmdlet includes in the operation. |
-Force | Forces the cmdlet to copy items that cannot otherwise be changed, such as read-only files or hidden items. |
-Recurse | Copies items in subdirectories, not the subdirectories themselves. Use this parameter with the Container parameter. |
-PassThru | When you use the PassThru parameter, it returns an object representing the copied item |
PowerShell Copy File Example
Here’s a simple example of how to use the Copy-Item cmdlet:
Copy-Item -Path <source> -Destination <destination>
This cmdlet takes two parameters: the file’s source location and the destination location. The -Path
specifies the path of the file you want to copy. This can be a local or a remote file path, and the -Destination
specifies the location where you want to copy the file to. This can also be a local or a remote path. You can also use its aliases: Copy, CP, or CPI.
Examples:
Let’s take a look at some examples to understand better the basic syntax and parameters for copying files with PowerShell:
Example | Example |
---|---|
Copy-Item -Path "C:\file.txt" -Destination "D:\newfile.txt" | Copies the file “file.txt” from the C: drive to the D: drive, renaming it as “newfile.txt” in the destination folder. |
Copy-Item -Path "C:\folder" -Destination "D:\" -Recurse | Copies the entire contents of a folder from the C: drive to the D: drive, preserving the directory structure. |
Copy-Item -Path "C:\file.txt" -Destination "\\Server\Share\" | Copies the file “file.txt” from the local machine to a remote server specified by the UNC path “\\Server\Share\”. |
By mastering the basic syntax and parameters of the Copy-Item command, you’ll have the foundation to efficiently copy files with PowerShell and streamline your file management tasks.
Copy-Item -Path "C:\Source\AppLog.txt" -Destination "C:\Destination"
If you want to copy the entire folder structure, including all the files and subfolders, use:
Copy-Item -Path "C:\Source\*" -Destination "C:\Destination" -Recurse
Copy File without Overwriting Existing in PowerShell
#Parameters $SourceFile = "C:\Temp\AppLog.txt" $DestinationFile = "C:\Temp\Archive\AppLog.txt" #Check if the Target file exists If (-not (Test-Path -Path $DestinationFile)) { Copy-Item -Path $sourceFile -Destination $DestinationFile } Else { Write-Host -f Yellow "The Destination File Already Exists!" }
PowerShell to Copy and Rename a File
You can copy a file to the same path or a different folder to rename it. E.g.,
Copy-Item -Path "C:\Source\example.txt" -Destination "C:\Destination\NewExample.log"
Also works: Copy-Item -Path “C:\Source\example.txt” -Destination “C:\Source\example-v2.txt”
Ensure the Destination Folder Before Copying the Files
If the destination folder does not exist, the cmdlet will throw an error “Copy-Item : Could not find a part of the path <Path>”. To avoid this, you have to use the combination of Test-Item, New-Item, and Copy-Item cmdlet, to create the entire destination folder tree if it does not exist.
#Function to copy a File to given path Function Copy-File { [CmdletBinding()] Param ( # The path to the Source File location [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,Position=0)] [string] $SourceFilePath, # The destionaion Folder where the file to be copied [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=1)] [string] $DestinationFolderPath ) #Check if the Destination Folder exists If (-not (Test-Path $DestinationFolderPath)) { New-Item -ItemType Directory -Path $DestinationFolderPath | Out-Null Write-Host "Ensured the $DestinationFolderPath!" -f Yellow } #Copy the File to Destination Folder Copy-Item -Path $SourceFilePath -Destination $DestinationFolderPath Write-Host "File $SourceFilePath Has been Copied to $DestinationFolderPath!" -f Green } #Call the function Copy-File -SourceFilePath "C:\Temp\AppLog.zip" -DestinationFolderPath "C:\Temp2\Logs"

The above script preserves the directory structure between the source directory and the destination.
Copy Multiple Files in PowerShell
Copy-Item -Path "C:\Source\*.txt" -Destination "C:\Destination"
Copy-Item -Path "C:\Source\*.*" -Destination "C:\Destination"
Copy All Files and Folders Recursively
The Copy-Item cmdlet can also be used to copy an entire directory with its contents. To do this, you would use the -Recurse
parameter, which tells PowerShell to copy the contents of the directory along with its files and subdirectories.
Copy-Item -Path "C:\Source" -Destination "C:\Destination" -Recurse -Force
Please note, that you have to use the -Force
switch merge with the destination folder if it exists already! The above cmdlet will merge the source with destination folders, and overwrite any files with the same name. Otherwise, You’ll get “Copy-Item : An item with the specified name C:\Temp2\Logs already exists.” error.
What if you want to copy the contents of a folder without the Root folder? Use:
Copy-Item -Path "C:\Temp\Logs\*" -Recurse -Force -Destination "C:\Logs"
Copy files from multiple folders to one Folder
Here’s a PowerShell script that you can use to copy multiple files from a source folder to a destination folder:
Copy-Item -Path C:\Logs\Log-1.txt,C:\temp\log-2.txt -Destination C:\LogsV2
Similarly, you can copy all files from multiple folders and merge them with PowerShell, as:
Copy-Item -Path "C:\Temp\Logs V2\*","C:\Temp\Logs V3\*" -Destination "C:\Logs"-Recurse -force
PowerShell to Include or Exclude Files to Copy
You can also use the -Include or -Exclude switch, along with wildcard characters, to filter the files you want to copy. For example, you can use -Include to copy only the files with specific extensions:
Copy-Item -Path "C:\Temp\*" -Destination "C:\Logs" -Include "*.log"
This script will copy only the files with the extension log. You can also use -Exclude to exclude certain files or folders from the copy process:
Copy-Item -Path "C:\Temp\*" -Destination "C:\Logs" -Exclude "*.bak","*.tmp"
This script will copy all files and folders except the ones with the .bak extension and the folder named ‘temp’.
Filter and Copy Files
Get-ChildItem "C:\Source" -File | Where { $_.LastWriteTime -gt (Get-Date).AddDays(-7)} | ForEach-Object { Copy-Item -Path $_.FullName -Destination "C:\Destination"}
This command will copy all files modified in the last seven days to the destination folder. It uses the pipeline input from the Get-ChildItem cmdlet.
Copy Contents between Folders with the Progress Bar
This script will display a progress bar in the PowerShell console, updating as each file is copied from the source to the destination folder.
# Set the source and destination folder paths $SourcePath = "C:\Source" $DestinationPath = "C:\Destination" # Get all files and Folders in the source folder $SourceItems = Get-ChildItem -Path $SourcePath -Recurse # Initialize progress bar variables $TotalItems = $SourceItems.Count $CurrentIndex = 0 # Copy files with progress bar ForEach ($Item in $SourceItems) { $currentIndex++ $ProgressPercent = ($CurrentIndex / $TotalItems) * 100 # Update the progress bar Write-Progress -Activity "Copying Files" -Status "$Item ($currentIndex of $TotalItems)" -PercentComplete $ProgressPercent $SourceItemPath = $Item.FullName $DestinationItemPath = $SourceItemPath.Replace($SourcePath, $DestinationPath) # Ensure destination directory exists $DestinationDir = [System.IO.Path]::GetDirectoryName($DestinationItemPath) if (!(Test-Path -Path $DestinationDir)) { New-Item -ItemType Directory -Path $DestinationDir } # Copy the file Copy-Item -Path $SourceItemPath -Destination $DestinationItemPath -Force Write-host "Copied:"$Item.FullName # Optional: Pause between files for demonstration # Start-Sleep -Milliseconds 100 } # Complete the progress bar Write-Progress -Activity "Copying Files" -Completed

Copying Files to and from Remote Servers with PowerShell
PowerShell’s copy-item cmdlet can copy files across different machines. To copy files from one server to another, you can create a PowerShell session to the remote server using the New-PSSession
cmdlet. This establishes a connection that enables file copying between the local and remote servers.
Once the session is established, you can use the Copy-Item
command to copy files from the source path to the destination path on the remote server. The Copy-Item
command supports various parameters, such as -Force
to overwrite existing files and -Recurse
to copy directories and their contents recursively.
Here is the PowerShell script demonstrating how to copy files between different computers:
#Establish a session with remote computer $Session = New-PSSession -ComputerName "FileServer" -Credential (Get-Credential) # Copy All files from local computer to remote computer Copy-Item -Path C:\Backup\* -Destination C:\BackupArchive\ -ToSession $Session -Recurse #Copy Files from Remote Computer to Local Computer Copy-Item -Path C:\Updates\* -Destination C:\temp\ -FromSession $Session -Recurse
In the above example, the $Session is a session variable storing the remote session information.
Copy-Item "\\Server01\Share\Updates.zip" -Destination "\\Server12\Temp\Updates.zip"
How do you copy a file if it is newer?
To copy a file in PowerShell only if it is newer than the version in the destination directory, you can compare the LastWriteTime property of the source and destination files. Here’s how to do it:
# Define source and destination paths $SourcePath = "C:\Source" $DestinationPath = "C:\Destination" # Function to copy items if newer function Copy-IfNewer { param ( [string]$sourceItem, [string]$destinationItem ) if (Test-Path -Path $destinationItem) { $sourceLastWrite = (Get-Item -Path $sourceItem).LastWriteTime $destinationLastWrite = (Get-Item -Path $destinationItem).LastWriteTime if ($sourceLastWrite -gt $destinationLastWrite) { Copy-Item -Path $sourceItem -Destination $destinationItem -Force Write-Output "Source is newer, File copied: $SourceItem" } } else { Copy-Item -Path $sourceItem -Destination $destinationItem -Force Write-Output "No existing file in destination, File copied: $SourceItem" } } # Enumerate all files and folders in the source directory Get-ChildItem -Path $SourcePath -Recurse | ForEach-Object { $SourceItemPath = $_.FullName $DestinationItemPath = $SourceItemPath.Replace($SourcePath, $DestinationPath) # Ensure destination directory exists $DestinationDir = [System.IO.Path]::GetDirectoryName($DestinationItemPath) if (!(Test-Path -Path $DestinationDir)) { New-Item -ItemType Directory -Path $DestinationDir } # Copy the item if it is newer Copy-IfNewer -sourceItem $SourceItemPath -destinationItem $DestinationItemPath }
Handle Errors and Logging
When performing file copying operations with PowerShell, it’s important to handle errors gracefully and implement robust logging mechanisms. This will help you identify any issues and troubleshoot them effectively.
try { Copy-Item -Path 'C:\Source\file.txt' -Destination 'D:\Destination' } catch { Write-Host "An error occurred: $_" # Additional error handling or logging code here }
In this example, any errors that occur during the file copying process will be caught and logged, allowing for further analysis and troubleshooting.
Wrapping up
How do I copy files using PowerShell?
Can I rename files while copying them with PowerShell?
How can I copy files to a remote server using PowerShell?
You can copy files to a remote server by creating a PowerShell session to the server and using the Copy-Item command with the appropriate source and destination paths. E.g.
#Define the source file or directory and the destination path on the remote server$SourcePath = "C:\local\Source"
$DestinationPath = "C:\remote\destination"
#Specify the remote server's name or IP address
$RemoteServer = "remote-server-name-or-ip"
#Establish a session with the remote server
$session = New-PSSession -ComputerName $remoteServer -Credential (Get-Credential)
#Copy the file or folder to the remote server
Copy-Item -Path $sourcePath -Destination $destinationPath -ToSession $session
This allows you to copy files over a network securely.
Can I copy multiple files and folders at once with PowerShell?
Yes, you can copy multiple files and folders by using wildcards, filters, and the -Recurse parameter with the Copy-Item command. This allows you to select specific files or copy entire directories and their contents.Copy-Item -Path "C:\Source\file1.txt", "C:\Source\file2.txt" -Destination "C:\Destination\"
How do I copy only today’s files in PowerShell?
How do I copy a file into a folder in PowerShell?
To copy a file into a folder in PowerShell, you can use the Copy-Item cmdlet. Here’s an example of how to achieve this:Copy-Item -Path "C:\Source\file.txt" -Destination "C:\Destination\"
Can I use xcopy in PowerShell?
Yes, you can use xcopy in PowerShell. PowerShell provides a way to run external commands and utilities so that you can use xcopy within a PowerShell script or directly on the PowerShell command line.xcopy "C:\Source" "C:\Destination"/E /I
Can I copy files over the network?
A little python script I use in conjunction with git so you can easily copy (config) files located outside of a git repository to one (or to wherever you want to). Useful for configuration files.
Available on with pip/pipx: https://pypi.org/project/copy-to/
Depends on argcomplete, GitPython, prompt_toolkit
Install it with
sudo apt install pipx / sudo pacman -S python-pipx
pipx install copy-to
winget install python3
python -m pip install --user pipx
python -m pipx ensurepath
python -m pipx install copy-to
Then, restart you shell.
For autocompletion on Windows Powershell v5.1, first run:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted
Then, for Powershell autocompletion in general, run:
mkdir -p $HOME\Documents\WindowsPowerShell\Modules
python ((where.exe register-python-argcomplete).Split([Environment]::NewLine) | Select -First 1) --shell powershell copy-to.exe > $HOME\Documents\WindowsPowerShell\Modules/copy-to.psm1
Import-Module $HOME\Documents\WindowsPowerShell\Modules/copy-to.psm1
For Linux / MacOs, try running it once if autocompletions aren’t working
You can also run:
sudo activate-global-python-argcomplete
How to use it
Add a pairset of destination folder – source files and/or directories with
copy-to add myname destination_folder sourcefile1 (sourcefolder1 sourcefile2 sourcefile3 sourcefolder2/*) ...
Copy the files to their destination by running
copy-to run myname1 (myname2)
Or copy the files back to source by running
copy-to run-reverse myname1 (myname2)
When the destination is missing, a prompt will ask you if you want to create the destination folder.
Run and run-reverse can also run without arguments when git is installed and present in a git local repository that has configured copy-to. This is so it can be hooked to a git macro more easily, f.ex. with an alias/function
Windows Powershell: (put in your profile – notepad $PSHOME\Profile.ps1
)
function git-status { copy-to.exe run && git.exe status }
Linux bash (put in your .bashrc – nano ~/.bashrc
):
alias git-status="copy-to run && git status"
or for those who use it, on startup of Lazygit:
function lazygit { copy-to.exe run && lazygit.exe }
alias lazygit="copy-to run && lazygit"
Local git config:
[copy-to]
run = myname1 myname2
file = myconf.json
This can be setup with copy-to add myname
and copy-to set-git myname
or
copy-to add myname
and copy-to run
/copy-to run-reverse
after wich a prompt will ask if you want to set it up with git. Both copy-to run
and copy-to run-reverse
will run using the same run
arguments possibly given in a local gitconfig. A custom conf.json can be also be setup and will always take precedence over other file options when set up.
Quick setup for firefox dotfiles
This will setup a git repository for your firefox configuration files using copy-to on Windows.
Install git, initialize git repository and setup copy-to
We start with installing git if it’s not installed already.
winget install Git.Git
(Optional: get latest version of PowerShell)
winget install Microsoft.PowerShell
First we create a local git repository and cd into it.
We can make this repostitory for firefox only firefox
, or make it for all our dotfiles dotfiles
git init dotfiles
cd dotfiles
Now, we could just start and copy-to will put all your configurations in the default location ($HOME/.config/copy-to/confs.json
), or we could set it up so our configuration file is also in our git repository.
Since we’re in a git repostitory, we could accomplish this using copy-to set-git file confs.json
and copy-to will make the config file confs.json
in our current folder while also using this specific file to read files and folders from when we cd
into this git repository. You can see this whether or not this is done by running git config -e
.
We could change the confs.json file from the default path by setting the environment variable COPY_TO
or by using the --file
parameter.
Then we add everything in the firefox ‘profile’ folder programmatically using copy-to:
– First we open the profile folder by opening firefox-> Help-> More Troubleshooting Information-> Open ‘Profile’ Folder and copy the folder path.
– Then we run copy-to add firefox firefox
to add a the target folder but without the source files. This will also create a subfolder firefox
in our git repository wich will be our destination.
copy-to add-source firefox "C:\Users\username\AppData\Roaming\Mozilla\Firefox\Profiles\random_release\places.sqlite" "C:\Users\username\AppData\Roaming\Mozilla\Firefox\Profiles\random_release\bookmarksbackups/" "C:\Users\username\AppData\Roaming\Mozilla\Firefox\Profiles\random_release\favicons.sqlite"
Folders added to source will automatically copy recursively.
On the other hand, we could also iterate over each file in our profile folder (dont forget to replace the path with the path you copied earlier):
Get-ChildItem "C:\Users\username\AppData\Roaming\Mozilla\Firefox\Profiles\random_release" -Filter * |
ForEach-Object {copy-to add-source firefox "C:\Users\username\AppData\Roaming\Mozilla\Firefox\Profiles\random_release\$_" }
For Linux (and presumably MacOs), this would be:
copy-to add-source firefox /home/username/.mozilla/firefox/random_release/*
Then we run copy-to run firefox
to copy the files to the target folder.
Now that everything we want related to firefox is inside our local git repository, we can start setting up our remote repository.
Setup ssh for github
Get-Service -Name ssh-agent | Set-Service -StartupType Manual
Start-Service ssh-agent
Setup remote repository
First we make sure we’ve made our first commit adding every new change:
git add --all
git commit -m "Initial commit"
Now, if we ever need to freshly install firefox, we have a backup ready to go that we can use by running copy-to run-reverse
.
Or, if we ever decide to use a different operating system, we clone our repository after installing firefox and relocate the firefox profile folder.
If we made a private repository we use:
git clone git@github.com:<username>/dotfiles
because otherwise we run into authentication problems.
Then we run:
copy-to set-git file confs.json
copy-to reset-destination firefox "new-profile-folder"
copy-to run-reverse firefox
We have reconfigure our file because git doesn’t upload the local .git/ files.
As an alternative for backing up application configurationfiles accross operating systems, you could add multiple configuration names for each os. (copy-to add firefox-windows ..
/ copy-to add firefox-linux ..
)
Other commands
List configured paths and files with
copy-to list myname/mygroupname/all/all-no-group/groups/all-groups/names/groupnames/all-names
or as a flag
copy-to --list othercommand
‘all-no-group’ and ‘groups’ to list all regular configs and groups respectively
‘names’ and ‘groupnames’ to list just the regular names and groupnames respectively
You can also use ‘all’ to list/run all known configurations
Delete set of dest/src by name with
copy-to delete myname1 (myname2)
Add sources with
copy-to add-source myname folder1 file1
Delete source by index with
copy-to delete-source myname 1 4 7
Reset source and destination folders
copy-to reset-source myname
copy-to reset-destination myname newDest
Set the path of source files/folders by index with
copy-to set-source-path myname1 /home/user/ 1 2-4
Groups are based on names. For copying to multiple directories in one go.
Groupnames ‘group’/’all’ cannot be used.
copy-to add-group mygroupname myname1 myname2
copy-to delete-group mygroupname
Add name to group
copy-to add-to-group mygroupname myname1 myname2
Delete name from group
copy-to delete-from-group mygroupname myname1 myname2
At default the configuration file is located at ~/.config/copy-to/confs.json
, but you can set a environment variable COPY_TO
to change this, or pass a -f, --file
flag.
Mac not tested
I have an XMl which I’d like to expand.
- I want to select the 2. “Step” Node- > copy -> Change -Number- | -Name- and some inner-Text strings
- I want to select the 2. “Transition” Node -> copy -> Change -Number- | -Name- and some inner-Text strings
- I want to select the 2. “Connection” Node -> copy -> Change some inner-Text strings
- I want to select the penultimate “Connection” copy -> Change some inner-Text strings
Here are my XML (without the end-tags):
Here are the Code that work fine in an other job:
$OPN_in ='C:\OPN\OPNOUT.xml'
$OPN_Out='C:\OPN\imp\OPNIMP.xml'
# xml Objekt erstellen
$xml = New-Object XML
# xml laden
$xml.Load($OPN_in)
# Abfrage des ersten 'SW.Blocks.CompileUnit' Knotens
$Bsp_NW = $xml.SelectSingleNode("//SW.Blocks.CompileUnit")
# abbrechen wenn kein Knoten gefunden wurde.
if (!$Bsp_NW){
throw "Error, 'SW.Blocks.CompileUnit' Node not found!"
exit 1
}
# erstelle eine Kopie des Knotens im Speicher
$NEU_NW = $Bsp_NW.Clone()
$NEU_NW.innerxml = $NEU_NW.innerxml -replace ("'Start'" -replace "'"),("'NEXT'" -replace "'")
# id anpassen
$NEU_NW.Id = (100*$z).ToString()
# hänge den kopierten Knoten im selben Parent wie vom Original wieder ins XML ein
$Bsp_NW.ParentNode.InsertAfter($NEU_NW,$Bsp_NW)
#Basisdatenändern
$xml.Document.'SW.Blocks.FC'.AttributeList.Name ='OPN_NEW'
$xml.Document.'SW.Blocks.FC'.AttributeList.Number = [String]($xml.Document.'SW.Blocks.FC'.AttributeList.Number+'00')
# speichere das geänderte xml unter neuem Namen
$xml.Save($OPN_Out)
#>
What not work is:
$Bsp_NW = $xml.SelectSingleNode("//Steps")
thanks for support.
asked Sep 28, 2023 at 7:37
Now It’s working with:
# Abfrage des ersten 'SW.Blocks.CompileUnit' Knotens
$Bsp_NW = $xml.SelectSingleNode("//SW.Blocks.CompileUnit")
$Bsp_NW = $xml.SelectSingleNode("//Steps")
$NEW_Step = $Bsp_NW.step[1].Clone()
$NEW_Step.Number
But Maybe you can give me a tipp How to select a step by using die “number” attribute ?
answered Sep 28, 2023 at 10:19
Windows PowerShell — программа, который объединяет в себе командную оболочку и среду для написания сценариев. Она базируется на .NET и предоставляет средства для управления компьютером и автоматизации рутинных задач. Платформа обладает функциональностью полноценного объектно-ориентированного языка, включая поддержку переменных, функций, классов и объектов.
В отличие от многих других командных оболочек, PowerShell при работе оперирует не строками, а объектами. Это позволяет разрабатывать и применять сложные логические конструкции. Важно отметить, что интерпретатор PowerShell полностью совместим со стандартными командами cmd.exe и способен выполнять их функции без ограничений.
Взаимодействие с командами осуществляется в интерактивном режиме внутри терминала. Однако, если требуется сохранить используемый скрипт, более удобным вариантом станет использование среды ISE.
Windows PowerShell ISE представляет собой интегрированное средство разработки сценариев для языка PowerShell. Здесь можно создавать, сохранять и запускать скрипты с выделением синтаксиса, автоматическим дополнением, справочником команд и инструментами отладки. PowerShell ISE является легаси-инструментом, специфичным для версий языка до 5.1 включительно. В более поздних версиях предпочтение отдается универсальным интегрированным средам разработки с плагинами.
С начала 2016 года язык получил кросс-платформенную поддержку. Теперь его можно применять не только в операционных системах Windows 7, 8, 10, и 11, но и на macOS (начиная с версии 10.13), а также на различных популярных дистрибутивах Linux (подробная информация о совместимых дистрибутивах доступна в официальной документации).
Как открыть PowerShell в Windows
Как правило, PowerShell уже установлен на вашем компьютере по умолчанию. Однако, если по какой-то причине его нет, вы можете воспользоваться инструкциями, предоставленными Microsoft. В дополнение, в официальной документации имеются подробные руководства по установке на macOS и Linux.
PowerShell является независимым от версии операционной системы инструментом и работает одинаково стабильно как на Windows 10, так и на Windows Server.
Существует два основных метода для запуска PowerShell или PowerShell ISE в системе Windows: через меню «Пуск» и с помощью приложения «Выполнить».
- Для того чтобы открыть PowerShell через меню «Пуск», пройдите к папке Windows PowerShell, откройте её и выберите необходимое приложение. В этой директории доступны как 32-разрядные версии (отмечены как x86 в скобках), так и 64-разрядные версии терминала и ISE.

- Чтобы запустить PowerShell через приложение «Выполнить», используйте комбинацию клавиш Win + R. Когда появится окно, введите
powershell
илиpowershell ise
(в зависимости от того, какое приложение вам нужно) и нажмите кнопку ОК.

Команды (командлеты) PowerShell
В языке программы PowerShell команды носят название командлеты (от английского «cmdlet»). Все они формируются с использованием шаблона «Глагол-Существительное», или «Действие-Объект». Например, Get-Services
и Start-Process
. Благодаря такой структуре, можно легко понять предназначение команды, даже если вы с ней ещё не работали ранее.
Синтаксис командлетов
После имени самого командлета следует указание параметров и их значений. Между всеми частями команды следует проставлять пробелы. Вот пример синтаксиса командлета, который позволяет перейти в директорию C:\
:
Set-Location -LiteralPath C:\ -PassThru
Разберем его на составные части:
Set-Location
— буквально «вызвать команду». Этот командлет позволяет выполнять указанный блок сценария.-LiteralPath C:\
— здесь передаем блок сценария, в котором используется командаSet-Location
для перехода в каталогC:\
.-PassThru
— по умолчанию командлетInvoke-Command
не возвращает результат выполнения. Этот параметр указывает на необходимость вывода информации о местоположении, в которое был выполнен переход с помощью командыSet-Location
.

Важно отметить, что регистр букв в командах PowerShell не имеет значения. Таким образом, данную команду можно записать в виде заглавных букв, строчных букв или даже смешанного регистра, и она все равно будет выполняться:
sEt-loCATion -PATH c:\ -passthru
Когда в одной строке объединены несколько команд, они разделяются точкой с запятой
.;
Иногда команда может быть слишком длинной. Для разделения на несколько строк можно использовать символ обратного апострофа `
в месте переноса. Новую строку можно создать, нажав Shift + Enter (для переноса строки ниже текущей) или Ctrl + Enter (для переноса строки выше текущей).
Разделим предыдущую команду:
Set-Location ` -LiteralPath C:\ ` -PassThru

Алиасы
В процессе работы с терминалом иногда может быть неудобно постоянно вводить полные названия командлетов. Именно поэтому у наиболее часто используемых командлетов существуют псевдонимы (алиасы) — их сокращенные варианты.
Чтобы получить список доступных алиасов, вы можете воспользоваться командой Get-Alias
. Кроме того, данной команде также доступен псевдоним gal
.

Чтобы получить список алиасов для конкретного командлета, вы можете использовать параметр -Definition
. Пример:
Get-Alias -Definition Set-Location

Если вам нужно узнать полное название командлета по его алиасу, используйте параметр -Name
. Этот параметр необязателен, так как он является аргументом по умолчанию.
# Оба следующих варианта эквивалентны: Get-Alias -Name clear Get-Alias clear

Особенности обработки путей к каталогам
Для многих командлетов необходимо предоставить путь к файлу или каталогу. Это делается с использованием строки, например: C:\Windows\System32
.
Однако, если в пути встречается пробел или другой специальный символ, PowerShell будет рассматривать его как разделитель. Например:
# Следующая команда не будет выполнена корректно Set-Location C:\Program Files

PowerShell «воспринимает» пробел и интерпретирует его так, будто путь к папке закончился на слове Program
, а files
— это уже значение другого параметра.
Чтобы избежать подобных ситуаций, существует два метода:
- Экранировать символы с помощью обратного апострофа
`
:C:\Program` Files
. Однако это может быть неудобным, если путь длинный. - Поместить весь путь в одинарные или двойные кавычки:
'C:\Program Files'
или"C:\Program Files"
(желательнее использовать одинарные кавычки).
Кроме того, в PowerShell существуют сокращения для быстрого доступа к ближайшим директориям:
- Точка
.
указывает на текущий каталог. Например,Get-ChildItem .
позволяет просмотреть содержимое текущего местоположения. - Две точки
..
указывают на родительский каталог. Например,Set-Location ..
позволяет перейти к родительскому каталогу. Это может быть полезно, если вы находитесь в глубоко вложенной директории.
Большинство командлетов имеют параметры -Path
и -LiteralPath
, позволяющие указать путь к файлу или папке. Разница между ними заключается в том, что в -Path
можно включать переменные, в то время как —LiteralPath
интерпретирует символы буквально, даже если они содержат имя переменной.
Get-Help: как изучать новые командлеты
Для получения подробной информации о конкретном командлете воспользуйтесь командой Get-Help Название-Командлета
. Пример:
Get-Help Get-Childitem

У команды Get-Help
имеется несколько полезных параметров:
-Detailed
предоставляет более подробную справку по командлету.-Full
предоставляет полную справку.-Examples
демонстрирует примеры использования командлета.-Online
перенаправляет пользователя на веб-страницу с соответствующей документацией.
Объекты и конвейеры (пайплайны) в PowerShell
Когда вы работаете с командлетами в PowerShell, они возвращают не просто строки, а объекты — структуры данных, содержащие набор свойств и методов.
То, что отображается в терминале после выполнения команды в виде строки, на самом деле является визуальным представлением объекта. Программа PowerShell отображает определенные свойства объектов в виде таблицы, но далеко не все свойства могут быть отображены таким образом.
Аналогично тому, как командлеты могут возвращать объекты, они также могут принимать и обрабатывать их. Вы можете создать команду, которая возвращает объект, передать этот объект другому командлету, получить объект из него и так далее — этот процесс и называется конвейерами или пайплайнами.
Пример работы конвейера в PowerShell
Команда Get-Process
возвращает список запущенных процессов на компьютере. При передаче ей имени процесса (или шаблона, созданного с помощью регулярных выражений), команда выведет только соответствующие элементы списка.
Рассмотрим пример, где вызываем запущенный процесс PowerShell
:
Get-Process powershell

Мы получаем объект и таблицу, отображающую некоторые его свойства. Чтобы узнать все свойства и методы, давайте передадим этот объект командлету Get-Member
. Для этого используется конвейер:
Get-Process powershell | Get-Member

Команда Get-Member
получает объект от команды Get-Process
и выводит таблицу со всеми его свойствами и методами. Результат работы Get-Member
также представляет собой объект (точнее, список объектов), который можно передать по конвейеру дальше.
Допустим, нужно вывести только те строки, в которых MemberType
равно Property
. Для этого используем команду Where-Object
:
Get-Process powershell | Get-Member | Where-Object {$_.MemberType -eq 'Property'}

Команда Where-Object
последовательно обходит каждый объект, полученный от команды Get-Member
. Выражение в фигурных скобках — логическое:
$_
ссылается на текущий объект (то есть на отдельную строку в таблице);.MemberType
обращается к значению свойстваMemberType
в этом объекте;-eq
выполняет сравнение между выражением слева и выражением справа от него;'Property'
представляет значение, которое ожидаем увидеть у свойстваMemberType
.
Более подробно о логических выражениях рассказано ниже.
Форматирование таблиц с помощью конвейеров
Командлет Format-Table
в PowerShell предоставляет возможность настроить вывод таблицы в терминале: выбирать нужные свойства и методы, устанавливать ширину столбцов, группировать данные по нескольким таблицам и т. д.
Форматируем таблицу, полученную с помощью командлета Get-Member
. Следует использовать следующий синтаксис:
Get-Process powershell | Get-Member | Format-Table -AutoSize -Wrap -GroupBy MemberType -Property Name, Definition

Разберем параметры командлета Format-Table
:
-AutoSize
выравнивает ширину столбцов в соответствии с размерами их содержимого. Это позволяет оптимально использовать ширину экрана.-Wrap
переносит содержимое ячейки на новую строку, если оно не помещается в текущих размерах экрана. По умолчанию, если текст не помещается, он обрезается.-GroupBy
позволяет разделить одну таблицу на несколько, сгруппированных по значению определенного свойства. В данном случае, для каждого значенияMemberType
будет создана отдельная таблица.-Property
определяет, какие свойства объекта будут отображены в таблице в качестве столбцов. В данном примере, мы указали свойстваName
иDefinition
.
Эти параметры позволяют настраивать внешний вид таблицы, сделать вывод более читабельным и структурированным.
Сортировка таблиц с помощью конвейеров
Командлет Sort-Object
в PowerShell позволяет сортировать список объектов (таблицу) по значениям их свойств (столбцов). Давайте отсортируем результат, полученный с помощью командлета Get-Member
, по столбцу Name
в алфавитном порядке. Для этого воспользуемся параметром -Property
, который действует аналогично параметру у командлета Format-Table
:
Get-Process powershell | Get-Member | Sort-Object -Property Name

Командлет Sort-Object в PowerShell имеет также другие полезные параметры:
-Descending
сортирует объекты в порядке убывания. Например:
Get-Process powershell | Get-Member | Sort-Object -Property Name -Descending
-Unique
удаляет дубликаты и возвращает только уникальные объекты. Например:
Get-Process powershell | Get-Member | Sort-Object -Property Name -Unique
- Параметр
-Top
получает число N и отображает первые N объектов в таблице. Например:
Get-Process | Sort-Object -Property CPU -Top 10
- Параметр
-Bottom
получает число N и отображает последние N объектов в таблице. Например:
Get-Process | Sort-Object -Property Memory -Descending -Bottom 5
Эти параметры позволяют более гибко настраивать сортировку и отображение объектов в выводе.
Фоновое выполнение команд
Определенные задачи могут требовать значительного времени на выполнение. Примеры таких задач включают установку и обновление программного обеспечения или поиск файлов в обширной директории. Важно помнить, что во время выполнения одной команды в PowerShell нельзя вводить другие команды.
Рассмотрим пример: предположим, нужно найти файл powershell.exe
на всем диске C. Для этой цели воспользуемся командлетом Get-ChildItem
с параметром -Recurse
. Это позволит ему искать файл не только в текущем каталоге, но и во всех его подкаталогах.
Следует учитывать, что PowerShell может столкнуться с папками, к которым у него нет доступа. Чтобы обойти возможные ошибки, добавим параметр -ErrorAction SilentlyContinue
. Это означает, что в случае ошибки команда не будет генерировать уведомления, а просто продолжит выполнение.
Таким образом, данная ситуация выглядит следующим образом:
Get-ChildItem -Path C:\ -Name powershell.exe -Recurse -ErrorAction SilentlyContinue

Очевидно, что во время выполнения задачи, командная строка становится недоступной. Для принудительного прерывания выполнения задачи можно воспользоваться сочетанием клавиш Ctrl + C. Важно убедиться, что при этом ничего не выделено, чтобы избежать возможного восприятия компьютером как команды «Копировать».
Start-Job {Get-ChildItem -Path C:\ -Name powershell.exe -Recurse -ErrorAction SilentlyContinue}

Параллельно возможно выполнение любого числа фоновых задач. В дополнение к командлету Start-Job
, предназначенному для управления фоновыми задачами, существуют и другие командлеты:
Get-Job
предоставляет отчет о состоянии фоновых задач.Wait-Job
блокирует консоль до завершения фоновой задачи.Stop-Job
прекращает выполнение фоновой задачи.Receive-Job
выводит результаты выполнения фоновой задачи и очищает их из памяти. Для сохранения результатов в памяти используйте параметр-Keep
.
Опции Wait-Job
, Stop-Job
и Receive-Job
требуют указания имени Name
или идентификатора Id
конкретной задачи или задач (в случае нескольких). Это можно сделать непосредственно или в связке с командлетом Get-Job
.
Get-Job Job1

Работа с файлами
PowerShell предоставляет удобные средства для работы с файлами. Вот некоторые ключевые методы:
Для создания файла используйте командлет New-Item
с указанием пути к файлу:
New-Item -Path "C:\путь\к\файлу\новыйфайл.txt" -ItemType File
Чтобы записать данные в файл, используйте Out-File
или Set-Content
:
"Содержимое файла" | Out-File -FilePath "C:\путь\к\файлу\новыйфайл.txt" Set-Content -Path "C:\путь\к\файлу\новыйфайл.txt" -Value "Новое содержимое файла"
Для чтения содержимого файла в массив используйте Get-Content
:
$содержимое = Get-Content -Path "C:\путь\к\файлу\новыйфайл.txt"
Для получения информации о файле (размер, дата создания и др.) используйте Get-Item
:
$информацияОФайле = Get-Item -Path "C:\путь\к\файлу\новыйфайл.txt"
Для копирования файла в другое место используйте Copy-Item
:
Copy-Item -Path "C:\путь\к\файлу\новыйфайл.txt" -Destination "C:\путь\к\копия\новыйфайл.txt"
Для удаления файла воспользуйтесь командлетом Remove-Item
:
Remove-Item -Path "C:\путь\к\файлу\новыйфайл.txt" -Force
Помните, что операции удаления файлов необратимы, поэтому будьте осторожны при их использовании.