What I wanna do: design a command for the Windows Powershell that lets a user input a path to a file they want to have the checksum of as well as their preferred checksum algorithm. The result should then be saved in a file of the same name as that file, in the same directory, but with the checksum algorithm as its extension.
Example: C:\path\to\file.pdf is written into the command and the user will find C:\path\to\file.sha256 that contains the SHA-256 checksum as text.
What I have so far:
Set-Variable -Name "pfad" -Value "C:\path\to\file.pdf"; Set-Variable -Name "algorithmus" -Value SHA256; certutil -hashfile $pfad $algorithmus > $pfad + "." + $algorithmus
If this worked, it would return a file.pdf.SHA256 which would be fine. However, it overwrites the original file with a file of the same name containing an error message.
Unfortunately, some kind of bash script is not viable for me. It has to be one command that the users will be able to copy with their desired values into one place of the command.
I have looked into several functions like SplitPath etc but I feel like there should be a fairly simple way of doing what I want. This is my first time dealing with the Windows Powershell so I'm very ignorant of my possibilities.
I think this will do what you want.
Instead of setting the variables you can just declare them and set them equal to Read-Host which will get the user input.
Then you can just pipe the data into a format list and then into a csv file named what you wanted.
$filePath = Read-Host "Please enter your filepath (e.g. C:\path\to\documents)"
$fileName = Read-Host "Please enter your filename (e.g. file.pdf)"
$algorithmus = Read-Host "Please enter your Algorithm format (e.g. SHA256, SHA1, MD5)"
Get-FileHash -Path "$filePath\$fileName" -Algorithm "$algorithmus" | Export-csv "$filePath\$fileName.$algorithmus" -NoTypeInformation
Get-FileHash Docs
Edit: This will create the file.pdf.sha256 in the same directory as the original file.
Related
I'm trying to create a file listing of a folder for a secure file transfer tool. This is what I do:
Get-ChildItem c:\files | % {$_.FullName} > c:\temp\list1.csv
$csv = Import-Csv C:\TEMP\list1.csv -Header Path
The output holds every file in a new line, but I need it in one line.
Required output
"C:\files\Alpha" "C:\files\Beta" "C:\files\Gamma" "C:\files\Delta"
Actual output
C:\files\Alpha
C:\files\Beta
C:\files\Gamma
C:\files\Delta
The csv file is just what came to my mind first. A variable containing the files formatted like mentioned above would be sufficient. Do you have an idea?
Edit: Thank you #Matthias R. Jessen and #WaitingForGuacamole, you gave me exactly what I wanted.
(Get-ChildItem C:\scripts -File).ForEach({'"{0}"' -f $_.FullName.Replace('"','\"')}) -join " "
However, somehow my tool (written in java) is interpreting the output as one file instead of multiple files in a line.
Below the error message:
Java : Error: The file 'C:\files\Alpha C:\files\Beta C:\files\Delta C:\files\Gamma' was not found and is excluded from the transfer.
I know, that I have to handover the paths differently when using a properties file instead of entering the command manually in PowerShell.
Is there a way on letting the output look like:
"C:\\files\Alpha" "C:\\files\Beta" "C:\\files\Gamma" "C:\\files\Delta"
To pass the file paths of all children of a specific folder to a command line program as separate arguments, just pass the results of
(Get-ChildItem -File).FullName
to the program. Example:
$files = (Get-ChildItem C:\MyFolder -File).FullName
# Expected: myprogram.exe -arg1 -arg2 C:\MyFolder\file1.txt C:\MyFolder\file2.txt ...
myprogram.exe -arg1 -arg2 $files
I wrote a powershell script to get a list of all installed software and version information for each of our servers. I'd like to be able to export it to a .csv file and name it after the $server name that was entered.
Export-CSV -path "C:\Scripts\Server_Audit\$server_Software_List.csv"
When I find that file in the folder, it just says .csv.
Do I need to declare that in another fashion so that it works?
An underscore is a valid part of a variable name, so it's trying to add $server_Software_List to the file path. One solution is to use $() in your string:
Export-CSV -path "C:\Scripts\Server_Audit\$($server)_Software_List.csv"
My dirctory is D:\\Main. I want to create a file named file.js in the directory only i.e. D:\\Main. I use the code
type nul > file.js. It creates the file but also displayes an error message saying that nul folder wasn't found. Am I doing something wrong? How do I improve the code to stop the error message?
What you attempted to use is valid for CMD.EXE, but in PowerShell, type is an alias for Get-Content, which expects a valid device or file. However, the null device is not available in PowerShell, although a variable $null will return the desired value. You should instead use
New-Item -Path . -Name "file.js" -Value $null
or
Set-Content -Path .\file.js -Value $null
to create an empty file.
I didn't get a satisfactory answer so I searched the command list for PowerShell on Microsoft's website.
Use
Set-Content -path D:\\Main\file.js
Then it will ask for values *(e.g. [-Value0], [-Value1], ...)." Values are what what you want to type in the file e.g. [-Value0] will contain what will be in the first line of the code of file.js. Pressing enter will move to next line i.e. [-Value1]. Pressing enter without typing anything in a value will exit taking values and save the file.
The above command can be shortened like:
sc for Set-Content & . for D:\\Main because it is your default directory. You can also skip the -path term. So the new shortened command will be:
sc .\file.js
REASONS WHY THIS IS NOT A DUPLICATE
Since 3 people have already voted to close, I guess I should explain why this question is not a duplicate:
I cannot use cat or >> as these mess up the encoding of the files, which are UTF8 on input and need to be UTF8-BOM on output.
The linked question does not show how to loop through all files that match a given pattern in a directory, and concatenate a single file to each of the matching files on output, plus give the new file a different extension.
Using Set-Content is not Powershell 6 future-proof, since Set-Content will NOT add a BOM marker. In Powershell 5 and below, it sometimes adds a BOM marker and sometimes not, depending on the configuration settings of the executing user. See 'quick note on encoding' at the end of this article.
So in conclusion I am looking for a solution that uses copy (hence the question title) and does NOT use Cat or Set-Content.
I need to loop through certain files in a given directory and run the following on each file:
copy /b BOMMarker.txt+InputFile.dat OutputFile.txt
This inserts the contents of the BOMMarker.txt file at the start of the InputFile.dat and writes the output to OutputFile.txt
I found this question which explains how I can loop through the folder to load each file into Powershell, but how do I apply the "copy /b" command so that I can get the BOM marker at the start of each file?
EDIT
The comment from Jeroen indicates I can just do Set-Content on the output file, as Powershell will automatically add the BOM at the start.
But I also need to change the extension. So the output filename needs to be the same as the input filename, just with a changed extension (from .dat to .txt) and including the BOM.
I am guessing I can use Path.ChangeExtension somehow to do this, but not sure how to combine that with also adding the BOM.
EDIT - for Bounty
The example answer I posted does not work in all environments I tested it, and I do not know why (possibly different default Powershell setttings) but also, it is not future proof since Powershell 6 will not output BOM by default.
From the given directory, I need to process all files that match the filter (DIL_BG_TXN*.dat).
For each of those files, I need to copy it with a BOM at the start but the resultant new file needs to be the same name but with the extension .txt instead of .dat.
This solutions uses streams, that reliably read and write as-is:
$bomStream = [IO.File]::OpenRead('BOMMarker.txt')
$location = "" # set this to the folder location
$items = Get-ChildItem -Path $location -Filter DIL_BG_TXN*.dat
foreach ($item in $items) {
$sourceStream = [IO.File]::OpenRead($item.FullName)
$targetStream = [IO.File]::OpenWrite([IO.Path]::ChangeExtension($item.FullName, '.txt'))
$bomStream.CopyTo($targetStream)
$sourceStream.CopyTo($targetStream)
$targetStream.Flush()
$targetStream.Close()
$sourceStream.Close()
$bomStream.Position = 0
}
$bomStream.Close()
Of course please write the absolute path of BOMMarker.txt (1st line) according to its location.
This finally worked:
$Location = "C:\Code\Bulgaria_Test"
$items = Get-ChildItem -Path $Location -Filter DIL_BG_TXN*.dat
ForEach ($item in $items) {
Write-Host "Processing file - " $item
cmd /c copy /b BOMMarker.txt+$item ($item.BaseName + '.txt')
}
Description:
Set the directory location where all the .dat files are.
Load only those files that match the filter into the array $items.
Loop through each $item in the array.
With each $item, call cmd shell with the copy /b command and concatenate the bom marker file with the $item file and write the result to the basename of $item plus the new extension.
I'm trying to write a script in powershell to batch convert video files.
The way I intend to use it is to go to some folder full of video files and run it. It uses a conversion program that can be run in "command-line mode" (named handbrake) and saves the converted files with "-android" appended to them before the file extension. For example, if I have a file named video1.avi in the folder, after running the script the folder has 2 files: video1.avi and video1-android.avi
The reason I want to do this this way is so that I can check if, for each video file, there is a converted version of it (with -android appended to the name). And if so, skip the conversion for that file.
And this is where I'm having touble. The problem is the Test-Path's behavior (the cmdlet I'm using to test if a file exists).
What happens is, if the video file has an "unusual" name (for example in my case it's video[long].avi) Test-Path always returns False if you try to check if that file exists.
An easy way for you to test this is for example to do this:
Go to an empty folder,
run notepad to create a file with "[" in its name:
¬epad test[x].txt
Save the file
then do this:
Get-ChildItem | ForEach-Object {Test-Path $_.FullName}
It does not return true! It should right? Well it doesn't if the file has "[" in its name (I didn't check for any other special characters)
I've realized that if you escape the "[" and "]" it works
Test-Path 'test`[x`].txt'
returns true.
How can I go around this issue? I want to be able to: given a BaseName of a file, append it "-android.avi" and check if a file with that name exists.
Thanks,
Rui
Many PowerShell cmdlets have Path parameters that support wildcarding. As you have observed, in PowerShell not only is * a wildcard but [ and ] are also considered wildcard characters. You can read more about this in the help topic about_Wildcards.
For your issue, if you don't need wildcarding then I would recommend using the -LiteralPath parameter. This parameter doesn't support wildcarding and accepts [ and ] as literal path characters e.g.:
Get-ChildItem | ForEach {Test-Path -LiteralPath `
"$([io.path]::ChangeExtension($_.FullName,'avi'))"}
FYI, the reason piping the output of Get-ChildItem directly into Test-Path works is because the LiteralPath parameter has an alias "PSPath" that maps to the PSPath property on the FileInfo object output by Get-ChildItem. That property gets bound to the LiteralPath (er PSPath) parameter "by property name".
dir | % {test-path "$($_.Name)-android.avi"}