Generate a pdf from powershell - powershell

I'm trying to generate a PDF with powershell but I don't know how to proceed. I already tried to use Itext 7 but I don't know how to make it work.
When i try to install Itext7 on powershell i have this error message :
No match found for the specified search criteria and the itext7 package name. Use
Get-PackageSource to display for all available registered package sources.
Could I have some help?
Thanks in advance

The combination of PowerShell dependencies can be problematic as they need to be of a known working group in time and 7.1.14 was touted as a light solution so see later TL;DR edits or others comments below, [Later EDIT for more recent heavier list of 7.2.# dependencies see answer by #paul-oneill ] (https://stackoverflow.com/a/75280860/10802527) and run as Admin perhaps different to a normal user. So follow these steps carefully as some may downgrade your current settings.
MOST IMPORTANT use a project directory and watch that your prompt is located in that folder to ensure you are not running in the default PowerShell directory. I use a shortcut where the target directory is "blank/empty" thus defaults to the current working folder.
1st Check:-
project folder>[Net.ServicePointManager]::SecurityProtocol
should return either Tls12 or Tls13 we need it to be 1.2 so keep a note if yours is set to Tls13 and run this line.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
we may need to possibly change package provider so first check if nuget includes https://www.nuget.org/api/v2/:-
> Get-PackageSource
Name ProviderName IsTrusted Location
---- ------------ --------- --------
nuget.org NuGet False https://www.nuget.org/api/v2/
PSGallery PowerShellGet False https://www.powershellgallery.com/api/v2
If not you can add it as
Register-PackageSource nuget.org https://www.nuget.org/api/v2/ -ProviderName NuGet
now you should be able to install the dlls as follows
Install-Package -Name "itext7" -ProviderName NuGet -RequiredVersion 7.1.14 -Destination . -SkipDependencies
Install-Package -Name Portable.BouncyCastle -ProviderName NuGet -RequiredVersion 1.8.9.0 -Destination . -SkipDependencies
Install-Package -Name Common.Logging -ProviderName NuGet -RequiredVersion 3.4.1.0 -Destination . -SkipDependencies
Install-Package -Name Common.Logging.Core -ProviderName NuGet -RequiredVersion 3.4.1.0 -Destination . -SkipDependencies
Double check your folder has the correct structure
Note the order and location of the script is critical for correct loading
Add-Type -Path (Join-Path $PSScriptRoot ".\Common.Logging.Core.3.4.1\lib\net40\Common.Logging.Core.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\Common.Logging.3.4.1\lib\net40\Common.Logging.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\Portable.BouncyCastle.1.8.9\lib\net40\BouncyCastle.Crypto.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\itext7.7.1.14\lib\net40\itext.io.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\itext7.7.1.14\lib\net40\itext.layout.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\itext7.7.1.14\lib\net40\itext.kernel.dll")
$pdfDocuFilename = (join-path $PSScriptRoot "My1st.pdf")
$pdfWriter = [iText.Kernel.Pdf.PdfWriter]::new($pdfDocuFilename)
$pdfdocument = [iText.Kernel.Pdf.PdfDocument]::new($pdfWriter)
$pdfdocument.AddNewPage()
$pdfdocument.Close()
This will produce an empty file but proves all is well, and you can start running other examples such as the one suggested by S_G, so after the loading Add-Type block replace my blank example with
[string] $DEST = "HelloWorld.pdf"
$pdfWriter = [iText.Kernel.Pdf.PdfWriter]::new($DEST)
$pdf = [iText.Kernel.Pdf.PdfDocument]::new($pdfWriter)
$document = [iText.Layout.Document]::new($pdf)
$document.Add([iText.Layout.Element.Paragraph]::new("Hello World! from Powershell"))
$pdf.Close()
... Good Luck.
The versions above were for a fixed point in time when user blogs had verified that 7.1 mixes worked without much conflict, the aim is to produce a group of standalone files working within Net40 environment, but time moves on and you should ensure you are using a newer mix. HOWEVER everything changed in 7.1.15 as a phenomenally greater list of dependencies is now required for Net 4.5 and now 4.6.1 although, packages/itext7/7.2.1 itself still works with
packages/Portable.BouncyCastle/1.8.9 + and common logging is still 3.4.1

Below is the code for a PowerShell Script which outputs a PDF with "Hello World!" written on it. It mirrors the functionality of iText 7 basic Hello World example. You can change it as per your requirement.
Add-Type -Path "C:\temp\Common.Logging.Core.dll"
Add-Type -Path "C:\temp\Common.Logging.dll"
Add-Type -Path "C:\temp\BouncyCastle.Crypto.dll"
Add-Type -Path "C:\temp\itext.io.dll"
Add-Type -Path "C:\temp\itext.layout.dll"
Add-Type -Path "C:\temp\itext.kernel.dll"
[string] $DEST = "C:\files\HelloWorldPowerShell.pdf"
$pdfWriter = [iText.Kernel.Pdf.PdfWriter]::new($DEST)
$pdf = [iText.Kernel.Pdf.PdfDocument]::new($pdfWriter)
$document = [iText.Layout.Document]::new($pdf)
$document.Add([iText.Layout.Element.Paragraph]::new("Hello World!"))
$pdf.Close()

I found some good info here what DLLs need to be loaded via add-type ... https://renenyffenegger.ch/notes/design/graphic/pdf/tools/iText/index
Through trial & error I found loading the below works for itext7 versions 7.2.0, 7.2.4 & 7.2.5.
# DLL list - https://www.nuget.org/packages/itext7/
$dll_list = #(
"$my_ScriptDir\DLL_7.2.4\BouncyCastle.Crypto.dll"
"$my_ScriptDir\DLL_7.2.4\Common.Logging.Core.dll"
"$my_ScriptDir\DLL_7.2.4\Common.Logging.dll"
"$my_ScriptDir\DLL_7.2.4\itext.commons.dll"
"$my_ScriptDir\DLL_7.2.4\itext.forms.dll"
"$my_ScriptDir\DLL_7.2.4\itext.io.dll"
"$my_ScriptDir\DLL_7.2.4\itext.kernel.dll"
"$my_ScriptDir\DLL_7.2.4\itext.layout.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Bcl.AsyncInterfaces.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.DependencyInjection.Abstractions.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.DependencyInjection.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.Logging.Abstractions.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.Logging.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.Options.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.Primitives.dll"
"$my_ScriptDir\DLL_7.2.4\System.Diagnostics.DiagnosticSource.dll"
"$my_ScriptDir\DLL_7.2.4\System.Memory.dll"
"$my_ScriptDir\DLL_7.2.4\System.Runtime.CompilerServices.Unsafe.dll"
"$my_ScriptDir\DLL_7.2.4\System.Threading.Tasks.Extensions.dll"
"$my_ScriptDir\DLL_7.2.4\System.ValueTuple.dll"
"$my_ScriptDir\DLL_7.2.4\Newtonsoft.Json.dll"
)
# Loop & load DLLs
foreach ($dll in $dll_list)
{
Write-Host "Loading $dll" -ForegroundColor Green
try { Add-Type -Path "$dll"}
catch { $dll.Exception.LoaderExceptions }
}

Just my 2 cents but the above code does NOT work with Itext7 7.2.1 (after modifying for proper paths).
Wish I'd seen this post last week - wasted most of several days pulling hair out over 7.2.1 not behaving itself. :(

Related

Powershell copy all folders and files with certain extension

I have one package on my Windows machine and another package on a remote server.
The first one is -> C:\Users\One. It contains the following files:
adapter.jsx
result.js
system.jsx
moment.js
readme.txt
package called info that contains two files -> logger.jsx and date.js.
Another one is a remote target directory -> /mnt/media/Two. It is currently empty. The user and host for it are: $userAndHost = "user#foo.bar"
I want to copy all the packages and files of extensions .jsx and .js from package One to package Two. It's required to use scp here since this is a copy between two different platforms.
What I tried:
get all the items within the package:
Get-ChildItem -Path "C:\Users\One" -Recurse
filter items by certain extension, in my case they are .jsx and .js:
Get-ChildItem -Path "C:\Users\One" -Recurse | Where-Object {$_.extension -in ".js",".jsx"}
do the secure copy (scp) - I didn't come up with the script here.
Please, help me finish the script.
Hi i think you need something like this.
I write a code for you, tested working.
#Set execution policy to bypass
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
#install Posh-SSH from powershell gallery
#https://www.powershellgallery.com/packages/Posh-SSH/2.0.2
Install-Module -Name Posh-SSH -RequiredVersion 2.0.2
#import module
Import-Module Posh-SSH
#get all the items within the package in the path:
$path = 'C:\Users\One'
$items = (Get-ChildItem -Path $path -Name -File -Include ( '*.jsx', '*.js') -Recurse)
#Need destination credential
$credential = Get-Credential
#copy selected items to destination via scp
$items | ForEach-Object {
Set-SCPFile -ComputerName 'SCP-SERVER-HOST-HERE' -Credential $credential -RemotePath '/mnt/media/Two' -LocalFile "$path\$_"
}
Hope this helps you

Unable to find [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory] even though dll is already in GAC

I am trying to write a PowerShell script, but I'm running into an error.
When my script gets to the line
$tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($server)
I get the error:
Unable to find type [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]...
InvalidOperation: (Microsoft.TeamF...onServerFactory:TypeName) [], RuntimeException
Though my question is very similar to this question, I already know that the Microsoft.TeamFoundation.Client.dll file and its dependencies are in the GAC. The other question never clarifies that, and I think that might affect the answers I will get.
Before the line where the error occurs, I have a number of Add-Type statements to make sure the references I need are there. Among these statements is an Add-Type statement pointing to the Microsoft.TeamFoundation.Client.dll. I have verified that it's looking in the right location.
I've also included a try-catch statement that prints the loader exceptions if anything goes wrong there. Currently, the script is successfully making it through those statements without hitting the catch block.
Given that I know that the relevant dll is already in the GAC, what could cause this error, and how would I fix it?
I’d suggest you to load assemblies from directory directly, for example:
$TfsAssembliesPath="C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer"
Add-Type -Path "$TfsAssembliesPath\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.ServiceBus.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.VisualStudio.Services.Common.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.VisualStudio.Services.WebApi.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.VisualStudio.Services.Client.Interactive.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.Core.WebApi.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.Common.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.Client.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.TestManagement.Common.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.ProjectManagement.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.Build.Client.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.Build.Common.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.Git.Client.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.SourceControl.WebApi.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.WorkItemTracking.Client.QueryLanguage.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.WorkItemTracking.Client.DataStoreLoader.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.WorkItemTracking.Common.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.WorkItemTracking.WebApi.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.WorkItemTracking.Client.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.TestManagement.Client.dll"
Function CreateWorkItem{
[string]$tfsCollectionUrl="TFS collection URL"
[string]$tfsTeamProjectName="team project"
$teamProjectCollection=[Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($tfsCollectionUrl)
$ws = $teamProjectCollection.GetService([type]"Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore")
$proj = $ws.Projects[$tfsTeamProjectName]
$wit = $proj.WorkItemTypes["Task"]
#Create a new work item of that type
$workitem = $wit.NewWorkItem()
$workItem.Title = "Sample Task Title 3"
$workItem.Description = "Sample Description"
$workitem.AreaPath = $tfsTeamProjectName
$workitem.IterationPath = $tfsTeamProjectName
$workItem.Save()
Write-Host "The TFS work item number is: " $workItem.Id
}
You also could copy assemblies to a special folder (e.g. Lib folder in current project)
$TfsAssembliesPath="$PSScriptRoot\Libs"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.Client.dll"
Add-Type -Path "$TfsAssembliesPath\Microsoft.TeamFoundation.Common.dll"
...
I've never used this, but I believe this would work. At least I didn't get a type not found error.
using assembly Microsoft.TeamFoundation.Client
using namespace Microsoft.TeamFoundation.Client
$tfs = [TeamFoundationServerFactory]::GetServer($server)
Not that in PS 6, there's no GAC. so you'd have to put the full path to the dll for using assembly.

Powershell: Setting SASS_BINARY_PATH

I need to set SASS_BINARY_PATH environment variable with the local file I've downloaded to be able to install node-sass behind a corporate firewall. So on windows cmd, I just do:
SET SASS_BINARY_PATH=C:\Source\Repos\SRT\Srt.Web\sass-binary\v4.7.2\win32-x64-48_binding.node
And the installation works fine since it successfully sets the variable. But when I try doing it via Powershell, it doesn't work:
$env:SASS_BINARY_PATH="C:\Source\Repos\SRT\Srt.Web\sass-binary\v4.7.2\win32-x64-48_binding.node"
I've also tried another way on Powershell:
[Environment]::SetEnvironmentVariable("SASS_BINARY_PATH", "C:\Source\Repos\SRT\Srt.Web\sass-binary\v4.7.2\win32-x64-48_binding.node", "Machine")
Upon checking it on the control panel, it successfully added a "SASS_BINARY_PATH" system variable. But upon trying to reinstall node-sass, it fails again.
One of my observations is when I'm doing it the windows cmd way then check it by using the command line set, the variable shows up along with others. But when I use both the Powershell methods, it does not show up. Any ideas on this?
The error encountered when trying to npm-install node-sass over a corporate firewall is:
Downloading binary from
https://github.com/sass/node-sass/releases/download/v4.7
.2/win32-x64-48_binding.node Cannot download
"https://github.com/sass/node-sass/releases/download/v4.7.2/win3
2-x64-48_binding.node":
HTTP error 401 Unauthorized
Download win32-x64-48_binding.node manually
Put it in C:\Users\<user>\AppData\Roaming\npm-cache\node-sass\4.7.2 folder.
Then try to run npm install node-sass
here is the PowerShell command #jengfad used based on above solution which is commented in the discussion
$cacheSassPath = $env:APPDATA + '\npm-cache\node-sass'
if( -Not (Test-Path -Path $cacheSassPath ) )
{
Write-Host "cacheSassPath not exists"
New-Item -ItemType directory -Path $cacheSassPath
Write-Host "cacheSassPath CREATED"
}
<# Ensure has no content #>
Get-ChildItem -Path $cacheSassPath -Recurse| Foreach-object {Remove-item -Recurse -path $_.FullName }
<# Copy local sass binary (~Srt.Web\sass-binary\4.7.2) file to cache folder #>
$sassBinaryPath = split-path -parent $MyInvocation.MyCommand.Definition
$sassBinaryPath = $sassBinaryPath + "\sass-binary\4.7.2"
Copy-Item -Path $sassBinaryPath -Recurse -Destination $npmcachedir -Container
Write-Host "node-sass binary file successfully copied!"

Power shell script - can we set dll Product Version when we build it?

I am new to Powershell.
I am using power shell script to build VB6 dlls.
$compiler = "C:\Program Files (x86)\Microsoft Visual Studio\VB98\VB6.EXE".
$vbpPath= "C:\...\Desktop\ProjectFile\ProjectName.vbp"
$Outputpath = "C:\...\Desktop\Destination\ProjectName.dll"
Start-Process -FilePath "`"$compiler `"" -ArgumentList "/out
error.txt /make `"$vbpPath`" `"$Outputpath `"" -PassThru -Wait
Can we set its product version by our self when we build it?
Let's say set product version to "Mysoftware 5.1 Beta 6".
Thanks in advance.
Hi to anyone who faced similar issues,
After referencing this link:
How do I set the version information for an existing .exe, .dll?
I was able to change dlls and exes' product version under a specific folder. This step is done after all the dlls and exes were built.
Use Resource Hacker to Extract the *.RC file from exes/ dlls :
$ResourceHackerPath = "C:\Tools\resource_hacker\ResourceHacker.EXE"
$Dllpath = "...\MySoftware\Mydll.dll"
$RCpath = "...\MySoftware\Mydll.RC"
Start-Process -FilePath "`"$ResourceHackerPath`"" -ArgumentList "-extract `"$ProductPath`",`"$RCpath`",versioninfo,," -wait
Edit product version in *.RC file :
$OriProVer = (Get-Item -literalpath $Dllpath ).VersionInfo.ProductVersion
$NewProVer = "Mysoftware 5.1 Beta 6"
(Get-Content $Dllpath).Replace($OriProVer, $NewProVer ) | Set-Content $Dllpath
Use GoRC to change *.RC file format to *.RES file:
Start-Process -FilePath "`"$GoRCPath`"" -ArgumentList "/r `"$RCpath`"" -wait
Use Resource Hacker again to add the *.RES file to the dlls or exes
$RESpath = "...\MySoftware\Mydll.RES"
Start-Process -FilePath "`"$ResourceHackerPath`"" -ArgumentList "-addoverwrite `"$Dllpath `",`"$Dllpath `",`"$RESpath`", , ," -wait
Your dlls' product version should be updated to any string that you want.
Extra tips, if you wish to update a lot of dlls and exes product version:
You can try this:
Search all the dlls and exes under a specific folder:
$directory = "...\Desktop\New Folder"
$FileNameList = Get-ChildItem -literalpath $directory -Include *.dll, *.exe -recurse | foreach-object { "{0}" -f [System.Diagnostics.FileVersionInfo]::GetVersionInfo($_).FileName}
Doing the all 4 steps above in a for loop:
for ($i = 0;$i -lt $FileNameList.count;$i++){...}
Thanks & have a nice day :)

Unable to find type [System.IO.Compression.CompressionLevel]: make sure that the assembly containing this type is loaded

I wrote this PowerShell script to archive all log files created during a certain date range.
$currentDate = Get-Date;
$currentDate | Get-Member -Membertype Method Add;
$daysBefore = -1;
$archiveTillDate = $currentDate.AddDays($daysBefore);
$sourcePath = 'C:\LOGS';
$destPath='C:\LogArchieve\_'+$archiveTillDate.Day+$archiveTillDate.Month+$archiveTillDate.Year+'.zip';
foreach( $item in (Get-ChildItem $sourcePath | Where-Object { $_.CreationTime -le $archiveTillDate }) )
{
[Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem");
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal;
[System.IO.Compression.ZipFile]::CreateFromDirectory($sourcePath,$destPath, $compressionLevel, $false);
}
It works until the foreach loop, but once in the loop it gives these errors:
Unable to find type [System.IO.Compression.CompressionLevel]: make sure that the assembly containing this type is loaded.
At line:4 char:65
+ $compressionLevel = [System.IO.Compression.CompressionLevel] <<<< ::Optimal;
+ CategoryInfo : InvalidOperation: (System.IO.Compression.CompressionLevel:String) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
As System.IO.Compression is part of .NET 4.5, I have it installed on the system, but I still get these errors. I am on Windows Server 2008 R2 and using PowerShell v2.0
How can I make this work?
Try using Add-Type -AssemblyName System.IO.Compression.FileSystem instead. It is cleaner and does not have a dependency on the reference assemblies which need an installation of Visual Studio.
You can manually add a .NET class to your PowerShell session.
Remove [Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem"); from your script and add the following at the very top:
Add-Type -Path "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.IO.Compression.FileSystem.dll"
Or on a 32-bit box:
Add-Type -Path "C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.IO.Compression.FileSystem.dll"
This presumes .NET 4.5 installed OK on your system and System.IO.Compression.FileSystem.dll actually exists.
Also, make sure to check your $pshome exe.config file. I had an issue once where Powershell ISE refused to load a .NET assembly, because the config file had .NET 2.0 listed instead of 4.