Download file from SharePoint through Powershell - powershell

I am trying to download a file from a SharePoint site through PowerShell. The objective of this script is to take the SharePoint file and apply it to Outlook for employee signatures. We already have created the employee signatures that we want, we just need to deploy those .htm files to the employee devices. I am running this script through Office 365 Endpoint Manager (no longer Intune) to deploy to my end users. The Script will create the .htm files locally on a machine, however when opening the .htm file it takes me to the site url, not providing me with the actual email signature - almost like the command is only copying and not actually downloading. Any thoughts on how to add onto this script to download the respective file from the SharePoint site, where the email signatures are stored? Or is there another, easier option that I am not thinking about that could work better? Still a little new to some SharePoint functions and getting Powershell to communicate with Sharepoint, so please bear with me. Thank you for your help.
Used this code to help build the script: https://github.com/marcusburst/scripts/blob/master/Powershell/Exchange/AutomaticOutlookSignature.ps1
Made adjustments to help fit my needs.
# Checks if outlook profile exists - we only want it to run on people who have a profile so they don't get an annoying profile popup #
$OutlookProfileExists = Test-Path
"C:\Users\$env:Username\AppData\Local\Microsoft\Outlook"
if ($OutlookProfileExists -eq $true) {
Write-Host "User Outlook profile exists.. continuing.." -ForegroundColor Yellow
# Signature Variables #
$ExternalSignatureName = 'External-Signature.htm'
$SigSource = 'https://SharePointSiteURLL'
$RepliesForwardsSignatureName = 'Replies-Forwards-Signature.htm'
$SigSource = 'https://SharePointSiteURL'
# Environment variables #
$AppData = $env:appdata
$SigPath = '\Microsoft\Signatures'
$LocalSignaturePath = $AppData + $SigPath
# Copy file #
If (!(Test-Path -Path $LocalSignaturePath)) {
New-Item -Path $LocalSignaturePath -Type Directory
}
# Check signature path #
if (!(Test-Path -path $LocalSignaturePath)) {
New-Item $LocalSignaturePath -Type Directory
}
# Copy signature templates from domain to local Signature-folder #
Write-Host "Copying Signatures" -ForegroundColor Green
Invoke-WebRequest -URI $Sigsource -Outfile "$LocalSignaturePath\$ExternalSignatureName"
Invoke-WebRequest -URI $SigSource -OutFile "$LocalSignaturePath\$RepliesForwardsSignatureName"
# Set as Default Signature #
If (Test-Path HKCU:'\Software\Microsoft\Office\16.0') {
Write-host "Setting signature for Office 2019"-ForegroundColor Green
Write-host "Setting signature for Office 2019 as available" -ForegroundColor Green
If ((Get-ItemProperty -Name 'First-Run' -Path HKCU:'\Software\Microsoft\Office\16.0\Outlook\Setup' -ErrorAction SilentlyContinue))
{
Remove-ItemProperty -Path HKCU:'\Software\Microsoft\Office\16.0\Outlook\Setup' -Name 'First-Run' -Force
}
If (!(Get-ItemProperty -Name 'External-Signature' -Path HKCU:'\Software\Microsoft\Office\16.0\Common\MailSettings' -ErrorAction SilentlyContinue))
{
New-ItemProperty -Path HKCU:'\Software\Microsoft\Office\16.0\Common\MailSettings' -Name 'Ext-Signature' -Value $ExternalSignatureName -PropertyType 'String' -Force
}
If (!(Get-ItemProperty -Name 'Replies-Forwards-Signature' -Path HKCU:'\Software\Microsoft\Office\16.0\Common\MailSettings' -ErrorAction SilentlyContinue))
{
New-ItemProperty -Path HKCU:'\Software\Microsoft\Office\16.0\Common\MailSettings' -Name 'Replies-Forwards-Signature' -Value $RepliesForwardsSignatureName -PropertyType 'String' -Force
}
}
# Removes files from recent items in file explorer #
Write-host "Cleaning up recent files list in File Explorer.." -ForegroundColor Yellow
Get-ChildItem -Path "$env:APPDATA\Microsoft\Windows\Recent" -File | Sort-Object LastWriteTime -Descending | Remove-Item
Get-ChildItem -Path "$env:APPDATA\Microsoft\Windows\Recent\AutomaticDestinations" -File | Sort-Object LastWriteTime -Descending | Remove-Item
}

I think i ran into this issue a while back. I think your script it fine, you just have to make sure there's a valid token in your blob storage.

Related

Powershell script searching files on domain

Very new to powershell and AD, so apologies if this post has an obvious answer. I have done some research and I am still not finding the answers I am looking for. My script is below for reference.
I have created a simple powershell script that will run on an admin vm i have setup on my domain. I have a separate SQL vm running a backup script that consume a lot of storage over time. I am trying to run this very simple script. My question is, do I need to modify this script in order to store it on my admin vm but have it run on my sql vm? Or can i leave the path as is and just set up in AD task scheduler. I have tried targeting the FQDN and the IP, but it doesn't seem to be working either way.
$backups_file = 'E:\blahBlahBla\SQL\Backups' or
$backups_file = '<IP_ADDRESS>\E:\blahBlahBla\SQL\Backups' or
$backups_file = '<FQDN>E:\blahBlahBla\SQL\Backups'
$backup_file_exist = (Test-Path -Path $backups_file)
if ($backup_file_exist){
# Verifies the folder exists
Write-Output -InputObject "This folder exists"
# returns all the files in the folder.
Get-ChildItem -Path $backups_file
# Deletes all files in the folder that are older that 7 days.
Get-ChildItem -Path $backups_file -Recurse | Where-Object {($_.LastWriteTime -lt (Get-
Date).AddDays(-7))} | Remove-Item
}
else
{
Write-Output -InputObject "Unable to access this directory."
}
Thanks.
well all your $backups_file solutions seems wrong to me.
If you want excess a directory on a Remote system, it has to be at least a fileshare or a administrative share like \\computer\e$\folder\folder\
But why using file shares or something like that when you just simple can connect to a Powershell Session on the Remote Host? here is a example.:
$mySQLServer = "Server1.domain.name", "server2.domain.name"
$backupFolder = "E:\blahBlahBla\SQL\Backups"
foreach ($server in $mySQLServer)
{
$session = New-PSSession -ComputerName $server #maybe -cred if needed
Invoke-Command -Session $session -ArgumentList $backupFolder -ScriptBlock {
param(
$directoy
)
if ($backup_file_exist)
{
# Verifies the folder exists
Write-Output -InputObject "This folder exists"
# returns all the files in the folder.
Get-ChildItem -Path $directoy
# Deletes all files in the folder that are older that 7 days.
Get-ChildItem -Path $directoy -Recurse | Where-Object { ($_.LastWriteTime -lt (Get-Date).AddDays(-7))
} | Remove-Item
}
}
Remove-PSSession
}
Good Luck!

Create a powershell script to place a custom word template in the templates folder

I want to place a word template, template.dotm into the Word custom templates folder.
Using Office 365, latest version of Word. Windows 10. Apologies if my terminology is incorrect, still a powershell/programming novice.
This folder doesn't exist by default, and the directory Word looks for default templates in doesn't exist by default either. If a user has created a template, then it will create an expanding string named PersonalTemplates at the following registry key: HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Word\Options, with the value being the directory they've elected as their default custom templates directory.
I want to make a script which:
Checks for presence of PersonalTemplates. If present, and value is not null, store as $regvalue.
If not present, or value is null, create expanding string with the following value $newreg at HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Word\Options.
Then copy template.dotm into the $regvalue or $newreg. Powershell will be run from the same directory as the template.dotm is stored in.
I've got a bunch of snippets which do some of the principle operations, though I can't work out how to tie them together, and am missing some bits which I just can't work out:
Copy the template to the destination
ForEach ($user in (Get-ChildItem "C:\Users" -Exclude Public)) {
New-Item -ItemType Directory -Force -Path "C:\Users$($user.Name)\Documents\Custom Office Templates"
Copy-Item template.dotm -Destination "C:\Users$($user.Name)\Documents\Custom Office Templates"
Create registry key with value
Set-Location -Path
'HKCU:\SOFTWARE\Microsoft\Office\16.0\Word\Options'
New-ItemProperty -Path
'HKCU:\SOFTWARE\Microsoft\Office\16.0\Word\Options' -Name
'PersonalTemplates' -Value "C:\Users$($user.Name)\Documents\Custom
Office Templates" -PropertyType ExpandString -Force }
Get regvalue
$regvalue = (Get-ItemPropertyValue
'HKCU:\SOFTWARE\Microsoft\Office\16.0\Word\Options'
'PersonalTemplates')
I have put together your code snippets in order, also corrected the logic for checking if the Registry key is present or not.
ForEach ($user in (Get-ChildItem "C:\Users" -Exclude Public))
{
$location = "C:\Users\$($user.Name)\Documents\Custom Office Templates"
$IsPresent = Get-ItemProperty 'HKCU:\SOFTWARE\Microsoft\Office\16.0\Word\Options' | ForEach-Object {If($_ -like '*PersonalTemplates*'){ Return 'True' }}
if(-Not($IsPresent -eq 'True'))
{
New-ItemProperty -Path 'HKCU:\SOFTWARE\Microsoft\Office\16.0\Word\Options' -Name 'PersonalTemplates' -Value $location -PropertyType ExpandString -Force \\Not tested
New-Item -ItemType Directory -Force -Path $location
}
$existingValue= Get-ItemPropertyValue -Path 'HKCU:\SOFTWARE\Microsoft\Office\16.0\Word\Options' -Name 'PersonalTemplates'
if([string]::IsNullOrWhiteSpace($existingValue)){
Set-ItemProperty -Path 'HKCU:\SOFTWARE\Microsoft\Office\16.0\Word\Options' -Name 'PersonalTemplates' -Value $location
}
else{
$location=$existingValue
if(!(test-path $existingValue))
{
New-Item -ItemType Directory -Force -Path $existingValue
}
}
Copy-Item template.dotm -Destination $location
}
I have not tested the creation of registry key as I am on my work laptop, so assuming that line of code works.
Also, question for you: With this approach wouldn't the registry entry have the single value that of the first user folder, you may have to look into the logic? I feel you may have to run this script for each user after they login using $env:Username instead of looping through the user folder. But I could be wrong, there may be other who could suggest better.

unblock-file can get rid of prompt warning when try to run ps1 file from internet machine

i want to rename photos based on exif data on my remote machine, the code is as follows:
Unblock-File -path ..\exif-datetaken.ps1
Get-ChildItem *.jpg | foreach {
#Write-Host "$_`t->`t" -ForegroundColor Cyan -NoNewLine
$date = (..\exif-datetaken.ps1 $_.FullName)
if ($date -eq $null) {
Write-Host '{ No ''Date Taken'' in Exif }' -ForegroundColor Cyan
return
}
$newName = $date.ToString('yyyy-MM-dd HH-mm-ss') + $_.extension
$newName = (Join-Path $_.DirectoryName $newName)
Write-Host $newName -ForegroundColor Cyan
mv $_ $newName
}
i use unblock-file to get rid of warning, as i need to click on button to confirm for each photo manually,
but i found unblock-file do not work, i still get that warning prompt,
is it the wrong way to do to resolve this problem ?
Almost any file you download from the web will have ADS (alternate date stream) attached which indicates that it came form the web, and should not be trusted.
You have to use Unblock-File to get rid of that ADS.
If you are doing this for lots of downloaded files, then you have to do that to all of them before take any other actions on them.
ForEach ($TargetPath in $TargetPaths)
{
$TargetPath
Get-ChildItem -Path $TargetPath -Recurse | Unblock-File
Start-Sleep -Seconds 1
}
# Your rename code here
If you are running into prompts, after any downloaded file, then you may need to implement the -Confirm or -Force switch as where prudent.
Unblock-File -Confirm:$false
Rename-Item -Confirm:$false
Unblock is really only needed for downloaded files.
If you are getting other prompts the some lock is on the file or a permission issue. Yet, since you are not showing the error, we are left to guess.

Powershell script to install a specific program. Script works but is there a better way to do everything?

Okay so the script below is originally made using Batch and i converted it to PS. It works at the moment but is there better way to do this?
First we want to check is operating system 32 or 64 bit so we'll get the right installation path. Then we want to check is there old installation folder or not and if there is, the script should stop.
If there isn't that old installation folder, we'll create one and then import the registry file.
After that, we want to change drive H: to C:\Temp and then we'll install the msi-file. When the msi-file is installed, we want to check the installation path is the "program.exe" in the right place.
If everything is ok, we want to create folder for the GCTI files and then copy all the necessary files.
At the end of the script there's couple more file copying left and then we are done.
At the moment this script is in the same folder as the necessary installation files and when we use this to install the program, we need to copy the folder to the remote computer. I am planning to change this script a bit so that at first it asks on which computer we want to install this and then it copies all the files to the specific remote computer and then runs this script in remote computer.
#Let's check is OS 32 or 64 bit
$bit = "C:\Windows\syswow64\."
$isit64bit = Test-Path $bit
If ($isit64bit -eq $True) {$installpath = "C:\Program Files (x86)"}
Else {$installpath = "C:\Program Files"}
#Let's check is there old installation folder
$Program = $installpath+"\Program\"
$Programtest = Test-Path $Program
If ($Programtest -eq $false ) {Write-Host "None found, let's continue the installation"}
Else {Write-Host "Old installation folder found, remove files and try again" Exit}
# Create ODBC-connection in registry
Start-Process -FilePath Reg -ArgumentList import, ".\Progserver_ODBC.reg" -Wait -WindowStyle Minimized
#Let's check if previous action is ok
$registry = "HKLM:\SOFTWARE\WOW6432Node\ODBC\ODBC.INI\Progserver\"
$registrycheck = Test-Path $registry
If ($registrycheck -eq $True) {Write-Host "Registrychange is ok"}
Else {Write-Host "Registrychange failed" Exit}
# Rename Drive "H:" C:\temp
New-PSDrive -Name "H" -PSProvider 'FileSystem' -Root C:\temp
# Install the msi
Start-Process -FilePath msiexec -ArgumentList /i, "Program-4.3.32.msi", /quiet -Wait
$install = "C:\Program Files (x86)\PathtoProgram.exe"
$installcheck = Test-Path $install
If ($installcheck -eq $True) {Write-Host "Installation succeeded"}
Else {Write-Host "Installation failed." Exit}
# Create GCTI's
$GCTI = "$installpath\PathToGCTI\"
If (Test-Path $GCTI) {Write-Host "GCTI folder already exists"}
Else {Write-Host "Create GCTI folder"} New-Item -ItemType Directory -Path $GCTI -Force
Copy-Item .\PathtoGCTI\* -Destination $GCTI -Recurse -Force
Write-Host "Copied GCTI-files"
# Copy program.ini ja vec.ini
Write-Host "Copying program.ini ja vec.ini"
Copy-Item .\PathToProgram.ini $installpath\PathToProgram.ini
Copy-Item .\PathToVec.ini $installpath\PathToVec.ini
# Change folder rights for the installation folder
cacls.exe $installpath\Program /T /E /G "All Users:C"
# Copy files from version 4.3.26
Copy-Item .\PathToProgram.exe $installpath\PathToProgram -Force
# Copy files
Copy-Item .\PathToFiles\* $installpath\PathToProgram\ -Force -Recurse
Set-ItemProperty $installpath\PathToProgram\graph\* -Name isreadonly $true
#Remove PSDrive
Remove-PSDrive -Name "H"
This is by no means exhaustive; just a selection of comments. You might be better submitting this to the Code Review StackExchange site.
General rules:
always used named parameters in PS functions
Your code formatting is important (carriage returns, tabbing/spacing, etc.)
e.g.
### Don't do this
Get-ChildItem "C:\temp"
### Instead do this
Get-ChildItem -Path "C:\temp"
Test if we're running a 64 bit OS and pick the appropriate Program Files folder
if ([environment]::Is64BitOperatingSystem) {
$installationPath = $env:ProgramFiles
}
else {
$installationPath = ${env:ProgramFiles(x86)}
}
When joining file paths, use Join-Path:
### So don't do this
$Program = $installpath+"\Program\"
### Instead do this
$Program = Join-Path -Path $installpath -ChildPath "Program"
When mapping your drive; be careful about scoping.
And probably best ensure you clean up after yourself, too! I have fallen foul of this in the past and it was a nightmare to clean up :-S
try {
if (Test-Path -Path "H:\") {
Remove-PSDrive -Name "H"
}
New-PSDrive -Name "H" -Root "C:\temp" -PSProvider FileSystem -Scope Script
### do your other stuff
catch {
throw $_.Exception
}
finally {
if (Test-Path -Path "H:\") {
Remove-PSDrive -Name "H"
}
}
Note the defensive programming (check if the drive exists already and remove it if it does!).
For bonus points you could pull the mapping code in to a separate function to avoid repetition (D.R.Y.)
Phew... I think that will do for now!
Good work :-)

Octopus Deploy - Deploy.ps1 script for setting up SSL bindings on IIS

Using the octopus deploy script for creating websites found here
I am trying to setup up a website that uses SSL. I have changed the http -> https and the variable is set to this $MyWebAppIisBindings = "*:433:"
This script does everything to create the new site and deploy my app except set a certificate.
I have one certificate called 'webserver' that can be selected from the combo box in the edit site bindings dialog in the IIS 7 Manager. selecting this manually makes the SSL work as expected.
What Powershell cmdlet do I need to add to the deploy script in order to associate my certificate with my binding on IIS?
(I'm a complete Powershell noob, please don't assume that I know anything about it in your answer)
EDIT: I have progressed a little but I'm still lost
# think I need to do something like this to get the certificate
# Get-Item cert:\LocalMachine\My\$siteCertThumb
# but I have no idea how to assign it to the 443 binding
To expand on Jared's answer, here is a complete script from a recent project that uses both HTTP and HTTPS:
#
# Settings
#---------------
$appPoolName = ("Kraken-Pool-" + $OctopusEnvironmentName)
$siteName = ("Kraken - " + $OctopusEnvironmentName)
$siteBindings = ":80:octopushq.com"
$siteBindingsSecure = ":443:octopushq.com"
$siteCertificate = "CERT:\LocalMachine\WebHosting\A347FC4B77A2C176E451D8CE4973C7D0FB3E19AA"
$appPoolFrameworkVersion = "v4.0"
$webRoot = (resolve-path .)
# Installation
#---------------
Import-Module WebAdministration
cd IIS:\
$appPoolPath = ("IIS:\AppPools\" + $appPoolName)
$pool = Get-Item $appPoolPath -ErrorAction SilentlyContinue
if (!$pool) {
Write-Host "App pool does not exist, creating..."
new-item $appPoolPath
$pool = Get-Item $appPoolPath
} else {
Write-Host "App pool exists."
}
Write-Host "Set .NET framework version:" $appPoolFrameworkVersion
Set-ItemProperty $appPoolPath managedRuntimeVersion $appPoolFrameworkVersion
Write-Host "Set identity..."
Set-ItemProperty $appPoolPath -name processModel -value #{identitytype="NetworkService"}
Write-Host "Checking site..."
$sitePath = ("IIS:\Sites\" + $siteName)
$site = Get-Item $sitePath -ErrorAction SilentlyContinue
if (!$site) {
Write-Host "Site does not exist, creating..."
$id = (dir iis:\sites | foreach {$_.id} | sort -Descending | select -first 1) + 1
new-item $sitePath -bindings #{protocol="http";bindingInformation=$siteBindings} -id $id -physicalPath $webRoot
} else {
Write-Host "Site exists. Complete"
}
Write-Host "Set app pool..."
Set-ItemProperty $sitePath -name applicationPool -value $appPoolName
Write-Host "Set bindings..."
Set-ItemProperty $sitePath -name bindings -value #{protocol="http";bindingInformation=$siteBindings}
New-ItemProperty $sitePath -name bindings -value #{protocol="https";bindingInformation=$siteBindingsSecure}
Get-Item $siteCertificate | Set-Item IIS://SslBindings/0.0.0.0!443
Write-Host "Set path..."
Set-ItemProperty $sitePath -name physicalPath -value "$webRoot"
Write-Host "IIS configuration complete!"
At 15below we use octopus and have built an open source octopus helper.
One of the functions in the helper powershells include installing into IIS and adding an SSL cert.
the project itself can be found here: https://github.com/15below/Ensconce
with regard to how to use the helper, firstly reference the createWebSite.ps1. - this works out if you are using IIS6 or 7.
Then create the app pool, website and add the ssl cert.
here is a small example
$deployTools = "D:\DeployTools\"
. $deployTools\createWebSite.ps1
CreateAppPool "MyAppPool"
CreateWebsite "MyWebsite" "D:\WebsiteDir" "MyAppPool" "MyAppName" "myWebsite.com" "D:\Logs\MyWebsite"
AddSslCertificate "MyWebsite" "CertificateName" "myWebsite.com"
You can also use the ensconce tool to deploy your application and update any config data. - more info on this can be found on the GitHub wiki.
Along with the two changes you have already made, http -> https and 80 -> 443.
Add the following to the end of the deployment script. Where $siteCertThumb is the thumbprint of the certificate stored in the LocalMachine\My store.
Write-Host "Add certificate to binding..."
Get-Item CERT:\LocalMachine\MY\$siteCertThumb | New-Item IIS://SslBindings/$siteBindings