Category Archives: Powershell

Exception calling “Update” with “0” argument(s): “Invalid look-up value

Had this error when trying to update SharePoint SPFieldLookupValueCollection using PowerShell.

Just to share a small part of my PowerShell that DID NOT Work

$valueCol = New-Object Microsoft.SharePoint.SPFieldLookupValueCollection;
 
 $groupValue.Split(",") | % {
 $lookupTitle = $_;
 $lookupItem = $lookupItems| ? {$_.Title -eq $lookupTitle};
 if($lookupItem -eq $null)
 {
 Write-Host -f Yellow "Unable to locate Lookup Item $lookupTitle."
 }
 else
 {
$val = New-Object Microsoft.SharePoint.SPFieldLookupValue($lookupItem.ID, $lookupTitle);
 Write-Host "`t`tLookup:" $val.LookupId " LookupValue:" $val.LookupValue
 $valueCol.Add($val);
 }
 }
 
 Write-Host "`tAdding Value" $valueCol;
 $existingItem["MultipleLookupColumnName"] = $valueCol;
 $existingItem.Update();

I thought it was easy. Turned out that this script WILL ONLY store the last value of the loop that you updated. That means, if you were to have Multiple Value of “A,B,C”, it stores only the C !

Resolution

It turns out that you just need to include the Type of the object before intializing a PowerShell Variable and it works perfectly fine.

[Microsoft.SharePoint.SPFieldLookupValueCollection]$valueCol = New-Object Microsoft.SharePoint.SPFieldLookupValueCollection;

$groupValue.Split(",") | % {
$lookupTitle = $_;
$lookupItem = $lookupItems| ? {$_.Title -eq $lookupTitle};
if($lookupItem -eq $null)
{
Write-Host -f Yellow "Unable to locate Lookup Item $lookupTitle."
}
else
{
[Microsoft.SharePoint.SPFieldLookupValue]$val = New-Object Microsoft.SharePoint.SPFieldLookupValue($lookupItem.ID, $lookupTitle);
Write-Host "`t`tLookup:" $val.LookupId " LookupValue:" $val.LookupValue
$valueCol.Add($val);
}
}

Write-Host "`tAdding Value" $valueCol;
$existingItem["MultipleLookupColumnName"] = $valueCol;
$existingItem.Update();

So please dont forget to do that!

 

PowerShell script to disable Limited Access Lock Down mode for all Site Collections

I always like to make use of PowerShell to do stuff. When dealing with a lot of Site Collection, it is advisable to script your task than going through UI one by one to configure.

I have a requirement to take out the Limited Access Lock Down mode introduced in SharePoint 2013. A bit introduction for this feature, this feature actually BLOCK users from browsing a file (via Browser) or check-in/check-out a file (via Office Client such as Word).

limited access user permission lockdown mode

If you activate this lock down mode, SharePoint does not allow browsing of its parent and hence you will receive error when trying to edit a file via Office Client (even if you have contribute permission to the file itself!). If you are only allowing your users (usually external or someone who does not have permission to the entire web or document library) to read the file, you do not need to Deactivate this.

In my environment, its much more complicated where some users are only editable to file from other Sub Site or Site. And Content Owners always assign Individual file for other site’s user to edit. In this case, in order to allow seamless experience, I would need to make sure that this feature is Deactivated at all site collections.

I came out with this PowerShell, Short and Sweet one, to help me. Hope it helps!


Get-SPSite | % {
  Get-SPFeature -Site $_ | ? { $_.DisplayName -eq "ViewFormPagesLockDown"} | Disable-SPFeature -Url $_.Url -Confirm:$false
}

P.S. Run it via SharePoint Management PowerShell. Or else you need to add in “Add-PSSnapIn Microsoft.SharePoint.PowerShell” at the start of this script.

PowerShell script to Open or Close SharePoint Web Parts

If you ever need to make changes to your SharePoint Web Parts such as hiding/showing, this post will help you to cut down unnecessary time.

Run the PowerShell script below via SharePoint Management Shell.

Change the Parameter accordingly base on your environment.


$web = Get-SPWeb [URL]
$f = $web.GetFile("Pages/Default.aspx");

if( $f.CheckOutStatus -eq "None" )
{
  $f.CheckOut();
}
$wpm = $f.GetLimitedWebPartManager("Shared")
$webParts = $wpm.WebParts | ? {$_.GetType().Name -eq "ContentEditorWebPart"} //Change for your own web part type
if($webParts.GetType().Name -eq "Object[]")
{
  $webParts | % {
    #$wpm.CloseWebPart($_);
    $wpm.OpenWebPart($_);
    $wpm.SaveChanges($_);
  }
}
else
{
  #$wpm.CloseWebPart($webParts)
  $wpm.OpenWebPart($webParts)
  $wpm.SaveChanges($webParts)
}

$f.CheckIn("");
$f.Publish("");

The example above will check if the page is check out before making any changes to the web parts. Subsequently, it closes/opens all content editor web parts within it and check in and publish the page. You can additional perform more tasks such as DeleteWebPart or AddWebPart, MoveWebPart or only make changes to only certain type of web part by changing PowerShell rules

 

How to check my CPU Temperature using PowerShell Remotely

Thought it would be helpful to share how to remotely check your Computer temperature especially when you have a computer at home and you want to track if it is HOT. Just in case you don’t want to burn your computer etc etc, for whatsoever reason.

Well. Steps below show you how to do that! Make sure your client machine (the one that you are using) has PowerShell version 2.0 and above (well most of the Windows nowadays has it already). Just do a Search in your program menu and you should see it

  1. First of all, ensure your target computer (the one sitting at home that you want to check) has Firewall Turn off (not recommended). Alternatively, set Exception rules for WMI rules.
    Very briefly, go to “wf.msc” – Windows Firewall of the target computer and enable Inbound Rules for “Windows Management Instrumentation (WMI-In)” – Profile: Domain.
    remotely check cpu temperature - 1
    See detail steps here 
  2. Once firewall is cleared, make sure you have local administrator rights account that can query the CPU temperature in the target computer. (this one is simple) Fire “lusrmgr.msc” in the Run command.
    Check the “Administrators” group and make sure your account is the member.
  3. In order for you to be able to remotely check your computer temperature, you must have connectivity to your target computer. I believe there could have many way you can have connectivity to your target computer. Of what I know, the below three should be enough to fulfill the task
    1. One that I always like to use is Teamviewer. With this, you can easily establish VPN or remotely login to run the script mention in Step 4. (without specifying the -Computer and -Credential).
      Make sure when you install the Teamviewer, you have the VPN Driver installation option ticked.
    2. Allowing RDP to your target computer from public IP. In this option, you need to configure your Home Router to allow port 3389 to hit your target computer. Please go to your router admin page (usually ends of 192.168.0.1 or  192.168.1.1 depending on which is your subnet) and configure port forwarding to your private IP.
      In this way, you will be doing the same steps as option 1 where the only difference is you remotely accessing your home computer and run the script directly onto the target computer. Again, without specifying the -Computer and -Credential parameter in step 4)
    3. Option 3 is kinda most complete one and if you want to learn a little bit deeper for WMI. In this option, you will be granting DCOM port (135) and a fixed port (24158) port forwarding to your remote compute (which is accessible via public IP like what you’ve done in option 2). Refer here for how to fix WMI port.Screen shot example on how I configured the WMI to fixed port. (please pardon the typo)
      configure WMI to fixed port
      At the end of the day, your target computer but be accessible via DCOM port and WMI port from public IP.
  4. Open PowerShell via Administrator rights and run the following PS command

    Get-WmiObject MSAcpi_ThermalZoneTemperature -Namespace “root/wmi” -ComputerName “<IP of your target computer>” -Credential (Get-Credential)

    You will be prompted to specify the credential, use the account that you have administrator rights mentioned in step 2 above.
  5. You should be expecting response like screen below
    remotely check cpu temperature - 3
  6. Look for “CurrentTemperature” and the value is in Celsius

SharePoint Permission Back Up and Restore in PowerShell

Hi SharePoint Admins! I’ve recently worked on a module to enhance SharePoint Backup experience. If you haven’t known SharePoint Native Backup enough, please read this.  SharePoint Native backup supports Backup-SPFarm, Backup-SPSite, Backup-SPFarm, Export-SPWeb.

All these approaches backup the actual content of the file and at times requires the entire Site or List to be restored entirely. If you are using Version History feature, recovering file can be made easier by restoring only the mis-updated files. In additional, the introduction of Recycle Bin since SharePoint 2010 has helped many SharePoint Admins (at least for myself) to recover accidentally deleted files without burning much of your time.

However, there is no Version History for Permission. Whatever permission changes that you have made onto a document, library or site do not keep a backup copy for you to restore in the later time. You can tap on third party product to help you on this, downside is, you have to pay for the service. Some 3rd party products that you can find in the markets are like Lightning Tools and AvePoint . (Personally never tried that but I’m more of a Self Fulfilling kind, where everything can be done by my left hand and my right hand. But please don’t get me wrong, paying more for premier service sometimes can be good as it comes with support and service level assurance)

So much for the introduction, now let’s go into the script!

I uploaded my script to CodePlex – PowerShell to backup/restore SharePoint Webs, Libraries, Folders and Files and inside the source code, you can find two powershell script, namely BackupPermission.ps1 and RestorePermission.ps1.

You would first run the BackupPermission.ps1. This backuppermission.ps1 generates a Permission.xml file that you gonna need it for the RestorePermission.ps1 later.

What this Backuppermission.ps1 does is to loop through your entire SharePoint Farm for Site Collections. Subsequently, for each of the site collection, it back up its Root Web permissions and Sub Web permissions. After backing up the web level permission, it goes to back up all document libraries permission, folder permission within each library and optionally (turn on by default) files permission.

Why do I need to care about backing up the permission? Well, there may have many reasons for that but below are just some for myself…

  1. You screw up the permission and can’t afford to restore the SharePoint Site Collection (cause only Backup-SPFarm was running DAILY)
  2. You do not want to inform the user for backup recovery cause the user will scream at you if the data that you going to restore has been modified by the user.
  3. You do have full confidence to run SharePoint Native Restore-SPSite as you all know, some times it doesn’t Work. Some how.. (MS, no offense on this, well, it does work most of the time but reason 1 superseded this)
  4. You accidentally RESET or Hit the “Delete Unique Permission” button when trying to change a WEB permission. Refer to my previous post on why this will kill your document permission.

 

Here I’m gonna talk about the Permissions.xml that is generated by my BackupPermission.ps1. You can always change the XML to suit your backup needs. Things like Restoring only partial of your Site Collection, restoring only a document library and even up to only a folder or file. By default, if a entity does not contains <RoleAssignments> node, the RestorePermission.ps1 script will bypass updating the permission and it will remains as its current stage (could be Inherting its parent permission or already broken permission. no changes will be done).


<?xml version="1.0" encoding="UTF-8"?>
<SharePoint>
 <Sites>
  <Site>
   <Url>https://mysharepoint.com</Url>
   <RootWeb>
    <Title>SharePoint Portal</Title>
    <Url>https://mysharepoint.com</Url>
    <RoleAssignments>
     <RoleAssignment User="i:0#.w|contoso\appadmin">
      <RoleDefinitionBindings>
       <RoleDefinition Name="Full Control"/>
      </RoleDefinitionBindings>
     </RoleAssignment>
     <RoleAssignment Group="SharePoint Portal Owners">
      <RoleDefinitionBindings>
       <RoleDefinition Name="Full Control"/>
      </RoleDefinitionBindings>
     </RoleAssignment>
     <RoleAssignment Group="SharePoint Portal Visitors">
      <RoleDefinitionBindings>
       <RoleDefinition Name="Read"/>
      </RoleDefinitionBindings>
     </RoleAssignment>
    </RoleAssignments>
    <Lists>
     <List>
      <Title>Documents</Title>
      <RootFolder>
       <Name>Documents</Name>
       <Url>Documents</Url>
       <SubFolders>
        <Folder>
         <Name>Folder A</Name>
         <Url>Documents/Folder A</Url>
         <RoleAssignments>
          <RoleAssignment Group="SharePoint Portal Owners">
           <RoleDefinitionBindings>
            <RoleDefinition Name="Full Control"/>
           </RoleDefinitionBindings>
          </RoleAssignment>
          <RoleAssignment Group="SharePoint Portal Visitors">
           <RoleDefinitionBindings>
            <RoleDefinition Name="Read"/>
           </RoleDefinitionBindings>
          </RoleAssignment>
          <RoleAssignment Group="SharePoint Portal Members">
           <RoleDefinitionBindings>
            <RoleDefinition Name="Contribute"/>
           </RoleDefinitionBindings>
          </RoleAssignment>
         </RoleAssignments>
        </Folder>
        <Folder>
         <Name>Folder B</Name>
         <Url>Documents/Folder A - Copy (8)</Url>
        </Folder>
       </SubFolders>
       <Files>
       </Files>
      </RootFolder>
     </List>
    </Lists>
    <Webs>
    </Webs>
   </RootWeb>
  </Site>
 </Sites>
</SharePoint>

What you are seeing above basically showing a backup xml that if you restore using this, only 1 site “https://mysharepoint.com” will be processed.  The permission of this site will have the following permission

  • appadmin (SPUser) – Full Control
  • SharePoint Portal Owners (SPGroup) – Full Control
  • SharePoint Portal Visitors (SPGroup) – Read

Subsequently, the script will continue to loop and restore List (in my backup script, this node stores only document libraries.) with Title “Documents” which is inheriting parent permission.

Folder “Folder A” within this document library will have unique permission while “Folder B” will inherit library permission which follows the Web permissions.

 

Well if you don’t really care at all, simply running BackupPermission.ps1 and RestorePermission.ps1 should be able to help you recovering you web permission.

To complete the entire process, set a Task Scheduler job to backup your farm permission regularly!

SharePoint Limited Access Permission – Careful when using BreakInheritance

This post is for SharePoint Developer or Admin who deals with SharePoint APIs (PowerShell or C#)

I have recently discovered a killing command from SharePoint that could kill your SharePoint Day. At times, you will need to configure a Unique permission to document/file for Content Sharing purposes. Typical feature which your end user will ask is to Share a certain document or folder to only certain group of people. Although it is recommend to Share using SharePoint Group which more manageable when it comes to a big Content management system, sometime you prefer to make a easier way out by just assigning to the Individual Users. (Less group to manage and you CAN Afford to loss the permission when things go wrong… and yes, this post will tell you why and how it goes wrong)

With much user friendly SharePoint “Share With” feature, you could break inheritance, grant new user permission so on and so forth. You can’t stop user from doing it, cause it is so apparent nowadays in SharePoint 2013

break and grant permission

Or you can run PowerShell script to Get the ListItem (or to be precise, SPSecurableObject Base Type object), subsequently execute  $object.BreakInheritance($false) and start adding SPRoleAssignment object.

If you have noticed this API

void ISecurableObject.BreakRoleInheritance(bool copyRoleAssignments)

 

This command allows you to quickly remove all existing RoleAssignment (from inheriting parent object permission) and so you can start adding Custom permission that you desired.

Important! This is Extremely Dangerous. Why? Because if you carefully loop into the $object.RoleAssignments (SPRoleAssignmentCollection) property, you will discover that some role definition bindings are named “Limited Access”. In SharePoint 2010, you can easily notice this definition through the permission setting page whereas in SharePoint 2013, it is hidden by default (which is more scarier cause you didn’t even know its existence).

Why is this Limited Access permission? There are many articles out there telling you why and why. I’m not gonna cover that here.

But if you really intend to so-called Cleanse the messy permission list that you have already added, the advice is Don’t.

Let me give you an example of how this BreakInheritance way of breaking parent permission can cause you problem.

By executing BreakInheritance(False), you are technically removing ALL Role Assignments from this object, which include the Limited Access permission granted automatically by SharePoint. You will usually see a lot of limited access for Document library and Web, cause the children within it are likely to be requested (by user) to have unique custom permission.

reset and break with false

 

For Example

  • Web 1 
    • Document Library A
      • Folder a (Break inheritance)
        • File
      • Folder b 

Assuming you have a “Folder a” with broken inheritance permission for UniqueUserA. Upon granting this unique permission, SharePoint automatically creates a Role Assignment for UniqueUserA with “Limited Access” permission to Web1 because Document Library A is inheriting permission from Web1 and hence it is added into Web1 instead.

Somehow or other, you need to change/script to change the permission for Web 1 object up there (the one with Limited Access), by purging the limited access granted to UniqueUserA. the permission that you granted previously to “Folder a” will be DELETED automatically! Yes, Automatically, seamlessly, without-your-knowingly.

And what is going to happen after that? Your lovely user UniqueUserA will send email you, telling you that he has no permission to access files or folder a. Not to mention if you have many Unique permission granted for sub folders within that document library.

Now, the Task you need to ask yourself is – How to still be able to remove existing permission while preserving the Unique configured child permission.

I came out with a simple PowerShell script that allows me to clear the permission. I think it can be easily translated into C# for code behind implementation.


#############################################################################
# Clearing Permission while keeping Limited Access user - Important #
#############################################################################
function ClearPermission
{
 Param([Microsoft.SharePoint.SPSecurableObject]$obj)

 $roleAssignments = $obj.RoleAssignments;
 $count = $roleAssignments.Count;
 for($i = 0; $i -lt $count ; $i++)
 {
  $roleAssignment = $roleAssignments[$i];
  $bindingCount = $roleAssignment.RoleDefinitionBindings.Count
  $clearCounter = 0;
  for($j = 0; $j -lt $bindingCount ; $j++)
  {
   $roleBinding = $roleAssignment.RoleDefinitionBindings[$clearCounter];
   if($roleBinding.Name -ne "Limited Access")
   {
    $roleAssignment.RoleDefinitionBindings.Remove($clearCounter);
   }
   else
   {
    $clearCounter++;
   }
  }
 }
 $obj.Update();
}

What it simply does is to loop through the Role Assignment Collection and delete only Binding with definition of Limited Access. Note that I do not loop via ForEach loop as when you looping the collection, you cannot delete the object within the collection. You can try and you will end up seeing error.

How to use:


Add-PSSnapin Microsoft.SharePoint.PowerShell

$w = Get-SPWeb https://yoursite

ClearPermission $w;

#add your unique permission here.

#additional code to add role assignement (permission)

$user = $w.EnsureUser("domainX\LoginNameY");

$roleAssignment = New-Object Microsoft.SharePoint.SPRoleAssignment($user);

$roleDefinition = $w.RoleDefinitions["Full Control"]

$roleAssignment.RoleDefinitionBindings.Add($roleDefinition)

$w.Update();

Hope it helps

Scripting your SharePoint Farm Backup with PowerShell in Task Scheduler

Hi guys,

Today, I would like to share one of the SharePoint admin must-do deployment steps which is to configure a task scheduler and to backup your SharePoint Farm. Note that this is working for both 2010 and 2013 environment.

Also, I’m leveraging this SP Farm Backup script created by good people (thanks for making this powerful and useful script). Please ensure that you have downloaded them and configure the params.xml file base on your corporate needs.

For the interest of those who want to just reference my configuration, below are the xml I used for my SharePoint Farm


<?xml version="1.0" encoding="utf-8"?>
<backup version="2.3">
 <params>
 <backupserver>SERVER_HOST_NAME</backupserver> <!-- Name of server if backup share is on remote server -->
 <sendemail>TRUE</sendemail> <!-- Option: TRUE/FALSE -->
 <smtpserver>SMTP_IP</smtpserver>
 <environment>My SharePoint (Staging)</environment>
 <emailfrom>yihaa_5@hotmail.com</emailfrom>
 <emailto>yihaa_5@hotmail.com</emailto> <!-- Multiple recipients must be comma separated -->
 <emailcc></emailcc> <!-- Multiple recipients must be comma separated -->
 <backupwebconfigonly>FALSE</backupwebconfigonly> <!-- IMPORTANT: If set to TRUE then web.config is backed up and NOT Virtual Directories -->
 <exportsolutions>TRUE</exportsolutions> <!-- Option: TRUE/FALSE -->
 <backupiis>TRUE</backupiis> <!-- Option: TRUE/FALSE -->
 <backupgac>TRUE</backupgac> <!-- Option: TRUE/FALSE -->
 <backupulslogs>TRUE</backupulslogs> <!-- Option: TRUE/FALSE -->
 <backup14hive>FALSE</backup14hive> <!-- Option: TRUE/FALSE -->
 <backupfulldays>Sunday</backupfulldays> <!-- Used in conjunction with option 1 of backupoption - Days must be comma separated -->
 <backupthreads>1</backupthreads> <!-- Option: 1 to 10 -->
 <backupsites>TRUE</backupsites> <!-- Option: TRUE/FALSE -->
 <includemysites>FALSE</includemysites> <!-- Option: TRUE/FALSE -->
 <backupconfigonly>FALSE</backupconfigonly> <!-- Option: TRUE/FALSE -->
 <backupshare>FarmBackup</backupshare>
 <backupoption>0</backupoption> <!-- Option: 0/1/2 -->
 <daystoretain>30</daystoretain> <!-- No. of days backups to retain (Must be greater than 1 day. Default: 7 days)-->
 </params>
</backup>

The key consideration of the above configuration is on the number of days to retain (daystoretain). You would need to really consult your technical manager in order to craft out the backup data retention period.

Once you have the SP Farm Backup script ready,  create a text file name “CreateTaskSchedulerForSPBackup” and subsequently change the extension to “.ps1” file (PowerShell extension).

Copy the below PowerShell script into the newly created CreateTaskSchedulerForSPBackup PowerShell


$A = New-ScheduledTaskAction -Execute "F:\TaskScheduler\Farm-Backup.bat" -WorkingDirectory "F:\TaskScheduler\"
$T = New-ScheduledTaskTrigger -Daily -DaysInterval 1 -At (Get-Date).Date
$S = New-ScheduledTaskSettingsSet

Register-ScheduledTask -Action $A -User "$($env:USERDOMAIN)\spfarmadmin" -Trigger $T -Settings $S -Force -TaskName "SharePoint Farm Backup" -RunLevel 1 -Password "xxxxxxxx"

For above PowerShell, there are certain things that you need to change based on your environment.

Farm-Backup.bat Path

It is assuming that you have copied all the SP Farm Backup downloaded script (together with your params.xml) into F:\TaskScheduler\ Folder of the server running the task scheduler. You only need to configure Task Scheduler in 1 of your SharePoint server only.

Task User Account

For most of the environment, your SP Farm Admin account is not always the local admin account where you access the server and create the task schedule. You will have to explicitly specify the Farm Admin account in the PowerShell as well as the Password of this account so that when the task is running, it takes in the Farm Admin account to perform Backup.

You need to use Farm Admin account to execute the backup script. Else you will hit access denied during the backup job.

Note that your password is entered in plain text. If you wish not to dispose the Password in Script. You can refer to last section on how to do it.

Backup Directory

It is also assume that you have created a Shared Folder in the server where you want to store the backup files. It must be a Network Shared Folder. In my example, it will be in “\\SERVER_HOST_NAME\FarmBackup” . 

Few things you need to consider when creating this shared folder:

  • Central Admin app pool account must have read/write access to the location of the backups.
  • SQL Service account must have read/write access to the location of the backups.
  • When running a farm backup from STSADM or Windows PowerShell, the account you’re running it as must have read/write access the location of the backups.
  • The location must be accessible from the SharePoint machine the backup is running on.
  • The location must be accessible from the SQL instance that SharePoint is trying to back up.

automated task scheduler for SharePoint Backup

Now that you have the script, kindly open PowerShell with Administrator rights in the server where you want to create the Task Scheduler.

Run the CreateTaskSchedulerForSPBackup.ps1

To double check if the task is created successfully, you go to Task Scheduler (taskschd) and check. The task “SharePoint Farm Backup” will be created.

automated task scheduler for SharePoint Backup output

How to avoid storing password into PowerShell Script.

As mentioned just now, you may want to avoid storing your password into the PowerShell Script.

In order to do that, you can use the PowerShell Script below to archive that.


$password = Read-Host -AsSecureString "Enter your password and hit Enter"
$bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
$plainPassword = [RunTime.InteropServices.Marshal]::PtrToStringAuto($bstr)

Register-ScheduledTask -Action $A -User "$($env:USERDOMAIN)\spfarmadmin" -Trigger $T -Settings $S -Force -TaskName "SharePoint Farm Backup" -RunLevel 1 -Password $plainPassword

Save the CreateTaskSchedulerForSPBackup.ps1 and reruns it via PowerShell.

I hope the script to create task schedule can save you some time. It happens to me that manually creating Task Scheduler can be very error prone as there are many clicking in the Task Scheduler UI, repeating the same creation steps in difference farm environment can be very tedious too.

PowerShell script to test SharePoint Send Mail

Thought it would be good to share some of my script to the public

Copy the below script and save as .ps1 file. Run it in SharePoint Management Shell with Admin Rights.


$webUrl = Read-Host "Enter SharePoint Web Url, e.g. https://sharepoint.com"

$web = Get-SPWeb $webUrl;

if($web)
 {
 $header = New-Object System.Collections.Specialized.StringDictionary
 $to = Read-Host "Enter Email TO address (e.g. abc@def.com) "
 $header.Add("To",$to);
 $header.Add("From","ahcheng@ahcheng.com")
 $subject = Read-Host "Enter Email Subject "
 $header.Add("Subject",$subject);
 $header.Add("content-type","text/html");

$body = Read-Host "Enter Email Body Content "
 $sent = [Microsoft.SharePoint.Utilities.SPUtility]::SendEmail($web,$header,$body);
 if($sent)
 {
 Write-Host -f Green "Email ($to) Sent successfully"
 }
 else
 {
 Write-Host -f Red "Email failed to send"
 }
 }